rockchip-otp.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
  4. */
  5. #include <common.h>
  6. #include <asm/io.h>
  7. #include <command.h>
  8. #include <display_options.h>
  9. #include <dm.h>
  10. #include <linux/bitops.h>
  11. #include <linux/delay.h>
  12. #include <linux/iopoll.h>
  13. #include <malloc.h>
  14. #include <misc.h>
  15. /* OTP Register Offsets */
  16. #define OTPC_SBPI_CTRL 0x0020
  17. #define OTPC_SBPI_CMD_VALID_PRE 0x0024
  18. #define OTPC_SBPI_CS_VALID_PRE 0x0028
  19. #define OTPC_SBPI_STATUS 0x002C
  20. #define OTPC_USER_CTRL 0x0100
  21. #define OTPC_USER_ADDR 0x0104
  22. #define OTPC_USER_ENABLE 0x0108
  23. #define OTPC_USER_QP 0x0120
  24. #define OTPC_USER_Q 0x0124
  25. #define OTPC_INT_STATUS 0x0304
  26. #define OTPC_SBPI_CMD0_OFFSET 0x1000
  27. #define OTPC_SBPI_CMD1_OFFSET 0x1004
  28. /* OTP Register bits and masks */
  29. #define OTPC_USER_ADDR_MASK GENMASK(31, 16)
  30. #define OTPC_USE_USER BIT(0)
  31. #define OTPC_USE_USER_MASK GENMASK(16, 16)
  32. #define OTPC_USER_FSM_ENABLE BIT(0)
  33. #define OTPC_USER_FSM_ENABLE_MASK GENMASK(16, 16)
  34. #define OTPC_SBPI_DONE BIT(1)
  35. #define OTPC_USER_DONE BIT(2)
  36. #define SBPI_DAP_ADDR 0x02
  37. #define SBPI_DAP_ADDR_SHIFT 8
  38. #define SBPI_DAP_ADDR_MASK GENMASK(31, 24)
  39. #define SBPI_CMD_VALID_MASK GENMASK(31, 16)
  40. #define SBPI_DAP_CMD_WRF 0xC0
  41. #define SBPI_DAP_REG_ECC 0x3A
  42. #define SBPI_ECC_ENABLE 0x00
  43. #define SBPI_ECC_DISABLE 0x09
  44. #define SBPI_ENABLE BIT(0)
  45. #define SBPI_ENABLE_MASK GENMASK(16, 16)
  46. #define OTPC_TIMEOUT 10000
  47. #define RK3588_OTPC_AUTO_CTRL 0x0004
  48. #define RK3588_ADDR_SHIFT 16
  49. #define RK3588_ADDR(n) ((n) << RK3588_ADDR_SHIFT)
  50. #define RK3588_BURST_SHIFT 8
  51. #define RK3588_BURST(n) ((n) << RK3588_BURST_SHIFT)
  52. #define RK3588_OTPC_AUTO_EN 0x0008
  53. #define RK3588_AUTO_EN BIT(0)
  54. #define RK3588_OTPC_DOUT0 0x0020
  55. #define RK3588_OTPC_INT_ST 0x0084
  56. #define RK3588_RD_DONE BIT(1)
  57. struct rockchip_otp_plat {
  58. void __iomem *base;
  59. };
  60. struct rockchip_otp_data {
  61. int (*read)(struct udevice *dev, int offset, void *buf, int size);
  62. int offset;
  63. int size;
  64. int block_size;
  65. };
  66. #if defined(DEBUG)
  67. static int dump_otp(struct cmd_tbl *cmdtp, int flag,
  68. int argc, char *const argv[])
  69. {
  70. struct udevice *dev;
  71. u8 data[4];
  72. int ret, i;
  73. ret = uclass_get_device_by_driver(UCLASS_MISC,
  74. DM_DRIVER_GET(rockchip_otp), &dev);
  75. if (ret) {
  76. printf("%s: no misc-device found\n", __func__);
  77. return 0;
  78. }
  79. for (i = 0; true; i += sizeof(data)) {
  80. ret = misc_read(dev, i, &data, sizeof(data));
  81. if (ret <= 0)
  82. return 0;
  83. print_buffer(i, data, 1, sizeof(data), sizeof(data));
  84. }
  85. return 0;
  86. }
  87. U_BOOT_CMD(
  88. dump_otp, 1, 1, dump_otp,
  89. "Dump the content of the otp",
  90. ""
  91. );
  92. #endif
  93. static int rockchip_otp_poll_timeout(struct rockchip_otp_plat *otp,
  94. u32 flag, u32 reg)
  95. {
  96. u32 status;
  97. int ret;
  98. ret = readl_poll_sleep_timeout(otp->base + reg, status,
  99. (status & flag), 1, OTPC_TIMEOUT);
  100. if (ret)
  101. return ret;
  102. /* Clear int flag */
  103. writel(flag, otp->base + reg);
  104. return 0;
  105. }
  106. static int rockchip_otp_ecc_enable(struct rockchip_otp_plat *otp, bool enable)
  107. {
  108. writel(SBPI_DAP_ADDR_MASK | (SBPI_DAP_ADDR << SBPI_DAP_ADDR_SHIFT),
  109. otp->base + OTPC_SBPI_CTRL);
  110. writel(SBPI_CMD_VALID_MASK | 0x1, otp->base + OTPC_SBPI_CMD_VALID_PRE);
  111. writel(SBPI_DAP_CMD_WRF | SBPI_DAP_REG_ECC,
  112. otp->base + OTPC_SBPI_CMD0_OFFSET);
  113. if (enable)
  114. writel(SBPI_ECC_ENABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
  115. else
  116. writel(SBPI_ECC_DISABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
  117. writel(SBPI_ENABLE_MASK | SBPI_ENABLE, otp->base + OTPC_SBPI_CTRL);
  118. return rockchip_otp_poll_timeout(otp, OTPC_SBPI_DONE, OTPC_INT_STATUS);
  119. }
  120. static int rockchip_px30_otp_read(struct udevice *dev, int offset,
  121. void *buf, int size)
  122. {
  123. struct rockchip_otp_plat *otp = dev_get_plat(dev);
  124. u8 *buffer = buf;
  125. int ret;
  126. ret = rockchip_otp_ecc_enable(otp, false);
  127. if (ret)
  128. return ret;
  129. writel(OTPC_USE_USER | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
  130. udelay(5);
  131. while (size--) {
  132. writel(offset++ | OTPC_USER_ADDR_MASK,
  133. otp->base + OTPC_USER_ADDR);
  134. writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK,
  135. otp->base + OTPC_USER_ENABLE);
  136. ret = rockchip_otp_poll_timeout(otp, OTPC_USER_DONE,
  137. OTPC_INT_STATUS);
  138. if (ret)
  139. goto read_end;
  140. *buffer++ = (u8)(readl(otp->base + OTPC_USER_Q) & 0xFF);
  141. }
  142. read_end:
  143. writel(0x0 | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
  144. return ret;
  145. }
  146. static int rockchip_rk3568_otp_read(struct udevice *dev, int offset,
  147. void *buf, int size)
  148. {
  149. struct rockchip_otp_plat *otp = dev_get_plat(dev);
  150. u16 *buffer = buf;
  151. int ret;
  152. ret = rockchip_otp_ecc_enable(otp, false);
  153. if (ret)
  154. return ret;
  155. writel(OTPC_USE_USER | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
  156. udelay(5);
  157. while (size--) {
  158. writel(offset++ | OTPC_USER_ADDR_MASK,
  159. otp->base + OTPC_USER_ADDR);
  160. writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK,
  161. otp->base + OTPC_USER_ENABLE);
  162. ret = rockchip_otp_poll_timeout(otp, OTPC_USER_DONE,
  163. OTPC_INT_STATUS);
  164. if (ret)
  165. goto read_end;
  166. *buffer++ = (u16)(readl(otp->base + OTPC_USER_Q) & 0xFFFF);
  167. }
  168. read_end:
  169. writel(0x0 | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
  170. return ret;
  171. }
  172. static int rockchip_rk3588_otp_read(struct udevice *dev, int offset,
  173. void *buf, int size)
  174. {
  175. struct rockchip_otp_plat *otp = dev_get_plat(dev);
  176. u32 *buffer = buf;
  177. int ret;
  178. while (size--) {
  179. writel(RK3588_ADDR(offset++) | RK3588_BURST(1),
  180. otp->base + RK3588_OTPC_AUTO_CTRL);
  181. writel(RK3588_AUTO_EN, otp->base + RK3588_OTPC_AUTO_EN);
  182. ret = rockchip_otp_poll_timeout(otp, RK3588_RD_DONE,
  183. RK3588_OTPC_INT_ST);
  184. if (ret)
  185. return ret;
  186. *buffer++ = readl(otp->base + RK3588_OTPC_DOUT0);
  187. }
  188. return 0;
  189. }
  190. static int rockchip_otp_read(struct udevice *dev, int offset,
  191. void *buf, int size)
  192. {
  193. const struct rockchip_otp_data *data =
  194. (void *)dev_get_driver_data(dev);
  195. u32 block_start, block_end, block_offset, blocks;
  196. u8 *buffer;
  197. int ret;
  198. if (offset < 0 || !buf || size <= 0 || offset + size > data->size)
  199. return -EINVAL;
  200. if (!data->read)
  201. return -ENOSYS;
  202. offset += data->offset;
  203. if (data->block_size <= 1) {
  204. ret = data->read(dev, offset, buf, size);
  205. goto done;
  206. }
  207. block_start = offset / data->block_size;
  208. block_offset = offset % data->block_size;
  209. block_end = DIV_ROUND_UP(offset + size, data->block_size);
  210. blocks = block_end - block_start;
  211. buffer = calloc(blocks, data->block_size);
  212. if (!buffer)
  213. return -ENOMEM;
  214. ret = data->read(dev, block_start, buffer, blocks);
  215. if (!ret)
  216. memcpy(buf, buffer + block_offset, size);
  217. free(buffer);
  218. done:
  219. return ret < 0 ? ret : size;
  220. }
  221. static const struct misc_ops rockchip_otp_ops = {
  222. .read = rockchip_otp_read,
  223. };
  224. static int rockchip_otp_of_to_plat(struct udevice *dev)
  225. {
  226. struct rockchip_otp_plat *plat = dev_get_plat(dev);
  227. plat->base = dev_read_addr_ptr(dev);
  228. return 0;
  229. }
  230. static const struct rockchip_otp_data px30_data = {
  231. .read = rockchip_px30_otp_read,
  232. .size = 0x40,
  233. };
  234. static const struct rockchip_otp_data rk3568_data = {
  235. .read = rockchip_rk3568_otp_read,
  236. .size = 0x80,
  237. .block_size = 2,
  238. };
  239. static const struct rockchip_otp_data rk3588_data = {
  240. .read = rockchip_rk3588_otp_read,
  241. .offset = 0xC00,
  242. .size = 0x400,
  243. .block_size = 4,
  244. };
  245. static const struct udevice_id rockchip_otp_ids[] = {
  246. {
  247. .compatible = "rockchip,px30-otp",
  248. .data = (ulong)&px30_data,
  249. },
  250. {
  251. .compatible = "rockchip,rk3308-otp",
  252. .data = (ulong)&px30_data,
  253. },
  254. {
  255. .compatible = "rockchip,rk3568-otp",
  256. .data = (ulong)&rk3568_data,
  257. },
  258. {
  259. .compatible = "rockchip,rk3588-otp",
  260. .data = (ulong)&rk3588_data,
  261. },
  262. {}
  263. };
  264. U_BOOT_DRIVER(rockchip_otp) = {
  265. .name = "rockchip_otp",
  266. .id = UCLASS_MISC,
  267. .of_match = rockchip_otp_ids,
  268. .of_to_plat = rockchip_otp_of_to_plat,
  269. .plat_auto = sizeof(struct rockchip_otp_plat),
  270. .ops = &rockchip_otp_ops,
  271. };