1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd 4 */ 5 6 #include <common.h> 7 #include <asm/io.h> 8 #include <command.h> 9 #include <dm.h> 10 #include <linux/bitops.h> 11 #include <linux/delay.h> 12 #include <misc.h> 13 #include <rockchip-otp.h> 14 15 static int rockchip_otp_wait_status(struct rockchip_otp_platdata *otp, 16 u32 flag) 17 { 18 int delay = OTPC_TIMEOUT; 19 20 while (!(readl(otp->base + OTPC_INT_STATUS) & flag)) { 21 udelay(1); 22 delay--; 23 if (delay <= 0) { 24 printf("%s: wait init status timeout\n", __func__); 25 return -ETIMEDOUT; 26 } 27 } 28 29 /* clean int status */ 30 writel(flag, otp->base + OTPC_INT_STATUS); 31 32 return 0; 33 } 34 35 static int rockchip_otp_ecc_enable(struct rockchip_otp_platdata *otp, 36 bool enable) 37 { 38 int ret = 0; 39 40 writel(SBPI_DAP_ADDR_MASK | (SBPI_DAP_ADDR << SBPI_DAP_ADDR_SHIFT), 41 otp->base + OTPC_SBPI_CTRL); 42 43 writel(SBPI_CMD_VALID_MASK | 0x1, otp->base + OTPC_SBPI_CMD_VALID_PRE); 44 writel(SBPI_DAP_CMD_WRF | SBPI_DAP_REG_ECC, 45 otp->base + OTPC_SBPI_CMD0_OFFSET); 46 if (enable) 47 writel(SBPI_ECC_ENABLE, otp->base + OTPC_SBPI_CMD1_OFFSET); 48 else 49 writel(SBPI_ECC_DISABLE, otp->base + OTPC_SBPI_CMD1_OFFSET); 50 51 writel(SBPI_ENABLE_MASK | SBPI_ENABLE, otp->base + OTPC_SBPI_CTRL); 52 53 ret = rockchip_otp_wait_status(otp, OTPC_SBPI_DONE); 54 if (ret < 0) 55 printf("%s timeout during ecc_enable\n", __func__); 56 57 return ret; 58 } 59 60 static int rockchip_px30_otp_read(struct udevice *dev, int offset, 61 void *buf, int size) 62 { 63 struct rockchip_otp_platdata *otp = dev_get_platdata(dev); 64 u8 *buffer = buf; 65 int ret = 0; 66 67 ret = rockchip_otp_ecc_enable(otp, false); 68 if (ret < 0) { 69 printf("%s rockchip_otp_ecc_enable err\n", __func__); 70 return ret; 71 } 72 73 writel(OTPC_USE_USER | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL); 74 udelay(5); 75 while (size--) { 76 writel(offset++ | OTPC_USER_ADDR_MASK, 77 otp->base + OTPC_USER_ADDR); 78 writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK, 79 otp->base + OTPC_USER_ENABLE); 80 ret = rockchip_otp_wait_status(otp, OTPC_USER_DONE); 81 if (ret < 0) { 82 printf("%s timeout during read setup\n", __func__); 83 goto read_end; 84 } 85 *buffer++ = readb(otp->base + OTPC_USER_Q); 86 } 87 88 read_end: 89 writel(0x0 | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL); 90 91 return ret; 92 } 93 94 static int rockchip_otp_read(struct udevice *dev, int offset, 95 void *buf, int size) 96 { 97 OTP_READ otp_read = NULL; 98 99 otp_read = (OTP_READ)dev_get_driver_data(dev); 100 if (!otp_read) 101 return -ENOSYS; 102 103 return (*otp_read)(dev, offset, buf, size); 104 } 105 106 static const struct misc_ops rockchip_otp_ops = { 107 .read = rockchip_otp_read, 108 }; 109 110 static int rockchip_otp_ofdata_to_platdata(struct udevice *dev) 111 { 112 struct rockchip_otp_platdata *otp = dev_get_platdata(dev); 113 114 otp->base = dev_read_addr_ptr(dev); 115 116 return 0; 117 } 118 119 static const struct udevice_id rockchip_otp_ids[] = { 120 { 121 .compatible = "rockchip,px30-otp", 122 .data = (ulong)&rockchip_px30_otp_read, 123 }, 124 { 125 .compatible = "rockchip,rk3308-otp", 126 .data = (ulong)&rockchip_px30_otp_read, 127 }, 128 {} 129 }; 130 131 U_BOOT_DRIVER(rockchip_otp) = { 132 .name = "rockchip_otp", 133 .id = UCLASS_MISC, 134 .of_match = rockchip_otp_ids, 135 .ops = &rockchip_otp_ops, 136 .ofdata_to_platdata = rockchip_otp_ofdata_to_platdata, 137 .platdata_auto_alloc_size = sizeof(struct rockchip_otp_platdata), 138 }; 139