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 <linux/iopoll.h> 13 #include <misc.h> 14 #include <rockchip-otp.h> 15 16 struct otp_data { 17 int (*init)(struct udevice *dev); 18 int (*read)(struct udevice *dev, int offset, void *buf, int size); 19 }; 20 21 static int rockchip_otp_wait_status(struct rockchip_otp_platdata *otp, 22 u32 flag) 23 { 24 int delay = OTPC_TIMEOUT; 25 26 while (!(readl(otp->base + OTPC_INT_STATUS) & flag)) { 27 udelay(1); 28 delay--; 29 if (delay <= 0) { 30 printf("%s: wait init status timeout\n", __func__); 31 return -ETIMEDOUT; 32 } 33 } 34 35 /* clean int status */ 36 writel(flag, otp->base + OTPC_INT_STATUS); 37 38 return 0; 39 } 40 41 static int rockchip_otp_ecc_enable(struct rockchip_otp_platdata *otp, 42 bool enable) 43 { 44 int ret = 0; 45 46 writel(SBPI_DAP_ADDR_MASK | (SBPI_DAP_ADDR << SBPI_DAP_ADDR_SHIFT), 47 otp->base + OTPC_SBPI_CTRL); 48 49 writel(SBPI_CMD_VALID_MASK | 0x1, otp->base + OTPC_SBPI_CMD_VALID_PRE); 50 writel(SBPI_DAP_CMD_WRF | SBPI_DAP_REG_ECC, 51 otp->base + OTPC_SBPI_CMD0_OFFSET); 52 if (enable) 53 writel(SBPI_ECC_ENABLE, otp->base + OTPC_SBPI_CMD1_OFFSET); 54 else 55 writel(SBPI_ECC_DISABLE, otp->base + OTPC_SBPI_CMD1_OFFSET); 56 57 writel(SBPI_ENABLE_MASK | SBPI_ENABLE, otp->base + OTPC_SBPI_CTRL); 58 59 ret = rockchip_otp_wait_status(otp, OTPC_SBPI_DONE); 60 if (ret < 0) 61 printf("%s timeout during ecc_enable\n", __func__); 62 63 return ret; 64 } 65 66 static int rockchip_px30_otp_read(struct udevice *dev, int offset, 67 void *buf, int size) 68 { 69 struct rockchip_otp_platdata *otp = dev_get_platdata(dev); 70 u8 *buffer = buf; 71 int ret = 0; 72 73 ret = rockchip_otp_ecc_enable(otp, false); 74 if (ret < 0) { 75 printf("%s rockchip_otp_ecc_enable err\n", __func__); 76 return ret; 77 } 78 79 writel(OTPC_USE_USER | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL); 80 udelay(5); 81 while (size--) { 82 writel(offset++ | OTPC_USER_ADDR_MASK, 83 otp->base + OTPC_USER_ADDR); 84 writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK, 85 otp->base + OTPC_USER_ENABLE); 86 ret = rockchip_otp_wait_status(otp, OTPC_USER_DONE); 87 if (ret < 0) { 88 printf("%s timeout during read setup\n", __func__); 89 goto read_end; 90 } 91 *buffer++ = readb(otp->base + OTPC_USER_Q); 92 } 93 94 read_end: 95 writel(0x0 | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL); 96 97 return ret; 98 } 99 100 static int rockchip_rv1126_otp_init(struct udevice *dev) 101 { 102 struct rockchip_otp_platdata *otp = dev_get_platdata(dev); 103 u32 status = 0; 104 int ret; 105 106 writel(0x0, otp->base + RV1126_OTP_NVM_CEB); 107 ret = readl_poll_timeout(otp->base + RV1126_OTP_NVM_ST, status, 108 status & 0x1, OTPC_TIMEOUT); 109 if (ret < 0) { 110 printf("%s timeout during set ceb\n", __func__); 111 return ret; 112 } 113 114 writel(0x1, otp->base + RV1126_OTP_NVM_RSTB); 115 ret = readl_poll_timeout(otp->base + RV1126_OTP_NVM_ST, status, 116 status & 0x4, OTPC_TIMEOUT); 117 if (ret < 0) { 118 printf("%s timeout during set rstb\n", __func__); 119 return ret; 120 } 121 122 return 0; 123 } 124 125 static int rockchip_rv1126_otp_read(struct udevice *dev, int offset, void *buf, 126 int size) 127 { 128 struct rockchip_otp_platdata *otp = dev_get_platdata(dev); 129 u32 status = 0; 130 u8 *buffer = buf; 131 int ret = 0; 132 133 while (size--) { 134 writel(offset++, otp->base + RV1126_OTP_NVM_RADDR); 135 writel(0x1, otp->base + RV1126_OTP_NVM_RSTART); 136 ret = readl_poll_timeout(otp->base + RV1126_OTP_READ_ST, 137 status, status == 0, OTPC_TIMEOUT); 138 if (ret < 0) { 139 printf("%s timeout during read setup\n", __func__); 140 return ret; 141 } 142 143 *buffer++ = readb(otp->base + RV1126_OTP_NVM_RDATA); 144 } 145 146 return 0; 147 } 148 149 static int rockchip_otp_read(struct udevice *dev, int offset, 150 void *buf, int size) 151 { 152 struct otp_data *data; 153 154 data = (struct otp_data *)dev_get_driver_data(dev); 155 if (!data) 156 return -ENOSYS; 157 158 return data->read(dev, offset, buf, size); 159 } 160 161 static const struct misc_ops rockchip_otp_ops = { 162 .read = rockchip_otp_read, 163 }; 164 165 static int rockchip_otp_ofdata_to_platdata(struct udevice *dev) 166 { 167 struct rockchip_otp_platdata *otp = dev_get_platdata(dev); 168 169 otp->base = dev_read_addr_ptr(dev); 170 171 return 0; 172 } 173 174 static int rockchip_otp_probe(struct udevice *dev) 175 { 176 struct otp_data *data; 177 178 data = (struct otp_data *)dev_get_driver_data(dev); 179 if (!data) 180 return -EINVAL; 181 182 if (data->init) 183 return data->init(dev); 184 185 return 0; 186 } 187 188 static const struct otp_data px30_data = { 189 .read = rockchip_px30_otp_read, 190 }; 191 192 static const struct otp_data rv1126_data = { 193 .init = rockchip_rv1126_otp_init, 194 .read = rockchip_rv1126_otp_read, 195 }; 196 197 static const struct udevice_id rockchip_otp_ids[] = { 198 { 199 .compatible = "rockchip,px30-otp", 200 .data = (ulong)&px30_data, 201 }, 202 { 203 .compatible = "rockchip,rk3308-otp", 204 .data = (ulong)&px30_data, 205 }, 206 { 207 .compatible = "rockchip,rv1126-otp", 208 .data = (ulong)&rv1126_data, 209 }, 210 {} 211 }; 212 213 U_BOOT_DRIVER(rockchip_otp) = { 214 .name = "rockchip_otp", 215 .id = UCLASS_MISC, 216 .of_match = rockchip_otp_ids, 217 .ops = &rockchip_otp_ops, 218 .ofdata_to_platdata = rockchip_otp_ofdata_to_platdata, 219 .platdata_auto_alloc_size = sizeof(struct rockchip_otp_platdata), 220 .probe = rockchip_otp_probe, 221 }; 222