rockchip-efuse.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * eFuse driver for Rockchip devices
  4. *
  5. * Copyright 2017, Theobroma Systems Design und Consulting GmbH
  6. * Written by Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
  7. */
  8. #include <common.h>
  9. #include <asm/io.h>
  10. #include <command.h>
  11. #include <display_options.h>
  12. #include <dm.h>
  13. #include <linux/bitops.h>
  14. #include <linux/delay.h>
  15. #include <linux/iopoll.h>
  16. #include <malloc.h>
  17. #include <misc.h>
  18. #define EFUSE_CTRL 0x0000
  19. #define RK3036_A_SHIFT 8
  20. #define RK3036_A_MASK GENMASK(15, 8)
  21. #define RK3036_ADDR(n) ((n) << RK3036_A_SHIFT)
  22. #define RK3128_A_SHIFT 7
  23. #define RK3128_A_MASK GENMASK(15, 7)
  24. #define RK3128_ADDR(n) ((n) << RK3128_A_SHIFT)
  25. #define RK3288_A_SHIFT 6
  26. #define RK3288_A_MASK GENMASK(15, 6)
  27. #define RK3288_ADDR(n) ((n) << RK3288_A_SHIFT)
  28. #define RK3399_A_SHIFT 16
  29. #define RK3399_A_MASK GENMASK(25, 16)
  30. #define RK3399_ADDR(n) ((n) << RK3399_A_SHIFT)
  31. #define RK3399_STROBSFTSEL BIT(9)
  32. #define RK3399_RSB BIT(7)
  33. #define RK3399_PD BIT(5)
  34. #define EFUSE_PGENB BIT(3)
  35. #define EFUSE_LOAD BIT(2)
  36. #define EFUSE_STROBE BIT(1)
  37. #define EFUSE_CSB BIT(0)
  38. #define EFUSE_DOUT 0x0004
  39. #define RK3328_INT_STATUS 0x0018
  40. #define RK3328_INT_FINISH BIT(0)
  41. #define RK3328_DOUT 0x0020
  42. #define RK3328_AUTO_CTRL 0x0024
  43. #define RK3328_AUTO_RD BIT(1)
  44. #define RK3328_AUTO_ENB BIT(0)
  45. struct rockchip_efuse_plat {
  46. void __iomem *base;
  47. };
  48. struct rockchip_efuse_data {
  49. int (*read)(struct udevice *dev, int offset, void *buf, int size);
  50. int offset;
  51. int size;
  52. int block_size;
  53. };
  54. #if defined(DEBUG)
  55. static int dump_efuse(struct cmd_tbl *cmdtp, int flag,
  56. int argc, char *const argv[])
  57. {
  58. struct udevice *dev;
  59. u8 data[4];
  60. int ret, i;
  61. ret = uclass_get_device_by_driver(UCLASS_MISC,
  62. DM_DRIVER_GET(rockchip_efuse), &dev);
  63. if (ret) {
  64. printf("%s: no misc-device found\n", __func__);
  65. return 0;
  66. }
  67. for (i = 0; true; i += sizeof(data)) {
  68. ret = misc_read(dev, i, &data, sizeof(data));
  69. if (ret <= 0)
  70. return 0;
  71. print_buffer(i, data, 1, sizeof(data), sizeof(data));
  72. }
  73. return 0;
  74. }
  75. U_BOOT_CMD(
  76. dump_efuse, 1, 1, dump_efuse,
  77. "Dump the content of the efuse",
  78. ""
  79. );
  80. #endif
  81. static int rockchip_rk3036_efuse_read(struct udevice *dev, int offset,
  82. void *buf, int size)
  83. {
  84. struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
  85. u8 *buffer = buf;
  86. /* Switch to read mode */
  87. writel(EFUSE_LOAD, efuse->base + EFUSE_CTRL);
  88. udelay(2);
  89. while (size--) {
  90. clrsetbits_le32(efuse->base + EFUSE_CTRL, RK3036_A_MASK,
  91. RK3036_ADDR(offset++));
  92. udelay(2);
  93. setbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
  94. udelay(2);
  95. *buffer++ = (u8)(readl(efuse->base + EFUSE_DOUT) & 0xFF);
  96. clrbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
  97. udelay(2);
  98. }
  99. /* Switch to inactive mode */
  100. writel(0x0, efuse->base + EFUSE_CTRL);
  101. return 0;
  102. }
  103. static int rockchip_rk3128_efuse_read(struct udevice *dev, int offset,
  104. void *buf, int size)
  105. {
  106. struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
  107. u8 *buffer = buf;
  108. /* Switch to read mode */
  109. writel(EFUSE_LOAD, efuse->base + EFUSE_CTRL);
  110. udelay(2);
  111. while (size--) {
  112. clrsetbits_le32(efuse->base + EFUSE_CTRL, RK3128_A_MASK,
  113. RK3128_ADDR(offset++));
  114. udelay(2);
  115. setbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
  116. udelay(2);
  117. *buffer++ = (u8)(readl(efuse->base + EFUSE_DOUT) & 0xFF);
  118. clrbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
  119. udelay(2);
  120. }
  121. /* Switch to inactive mode */
  122. writel(0x0, efuse->base + EFUSE_CTRL);
  123. return 0;
  124. }
  125. static int rockchip_rk3288_efuse_read(struct udevice *dev, int offset,
  126. void *buf, int size)
  127. {
  128. struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
  129. u8 *buffer = buf;
  130. /* Switch to read mode */
  131. writel(EFUSE_CSB, efuse->base + EFUSE_CTRL);
  132. writel(EFUSE_LOAD | EFUSE_PGENB, efuse->base + EFUSE_CTRL);
  133. udelay(2);
  134. while (size--) {
  135. clrsetbits_le32(efuse->base + EFUSE_CTRL, RK3288_A_MASK,
  136. RK3288_ADDR(offset++));
  137. udelay(2);
  138. setbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
  139. udelay(2);
  140. *buffer++ = (u8)(readl(efuse->base + EFUSE_DOUT) & 0xFF);
  141. clrbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
  142. udelay(2);
  143. }
  144. /* Switch to standby mode */
  145. writel(EFUSE_CSB | EFUSE_PGENB, efuse->base + EFUSE_CTRL);
  146. return 0;
  147. }
  148. static int rockchip_rk3328_efuse_read(struct udevice *dev, int offset,
  149. void *buf, int size)
  150. {
  151. struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
  152. u32 status, *buffer = buf;
  153. int ret;
  154. while (size--) {
  155. writel(RK3328_AUTO_RD | RK3328_AUTO_ENB | RK3399_ADDR(offset++),
  156. efuse->base + RK3328_AUTO_CTRL);
  157. udelay(1);
  158. ret = readl_poll_sleep_timeout(efuse->base + RK3328_INT_STATUS,
  159. status, (status & RK3328_INT_FINISH), 1, 50);
  160. if (ret)
  161. return ret;
  162. *buffer++ = readl(efuse->base + RK3328_DOUT);
  163. writel(RK3328_INT_FINISH, efuse->base + RK3328_INT_STATUS);
  164. }
  165. return 0;
  166. }
  167. static int rockchip_rk3399_efuse_read(struct udevice *dev, int offset,
  168. void *buf, int size)
  169. {
  170. struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
  171. u32 *buffer = buf;
  172. /* Switch to array read mode */
  173. writel(EFUSE_LOAD | EFUSE_PGENB | RK3399_STROBSFTSEL | RK3399_RSB,
  174. efuse->base + EFUSE_CTRL);
  175. udelay(1);
  176. while (size--) {
  177. setbits_le32(efuse->base + EFUSE_CTRL,
  178. EFUSE_STROBE | RK3399_ADDR(offset++));
  179. udelay(1);
  180. *buffer++ = readl(efuse->base + EFUSE_DOUT);
  181. clrbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
  182. udelay(1);
  183. }
  184. /* Switch to power-down mode */
  185. writel(RK3399_PD | EFUSE_CSB, efuse->base + EFUSE_CTRL);
  186. return 0;
  187. }
  188. static int rockchip_efuse_read(struct udevice *dev, int offset,
  189. void *buf, int size)
  190. {
  191. const struct rockchip_efuse_data *data =
  192. (void *)dev_get_driver_data(dev);
  193. u32 block_start, block_end, block_offset, blocks;
  194. u8 *buffer;
  195. int ret;
  196. if (offset < 0 || !buf || size <= 0 || offset + size > data->size)
  197. return -EINVAL;
  198. if (!data->read)
  199. return -ENOSYS;
  200. offset += data->offset;
  201. if (data->block_size <= 1) {
  202. ret = data->read(dev, offset, buf, size);
  203. goto done;
  204. }
  205. block_start = offset / data->block_size;
  206. block_offset = offset % data->block_size;
  207. block_end = DIV_ROUND_UP(offset + size, data->block_size);
  208. blocks = block_end - block_start;
  209. buffer = calloc(blocks, data->block_size);
  210. if (!buffer)
  211. return -ENOMEM;
  212. ret = data->read(dev, block_start, buffer, blocks);
  213. if (!ret)
  214. memcpy(buf, buffer + block_offset, size);
  215. free(buffer);
  216. done:
  217. return ret < 0 ? ret : size;
  218. }
  219. static const struct misc_ops rockchip_efuse_ops = {
  220. .read = rockchip_efuse_read,
  221. };
  222. static int rockchip_efuse_of_to_plat(struct udevice *dev)
  223. {
  224. struct rockchip_efuse_plat *plat = dev_get_plat(dev);
  225. plat->base = dev_read_addr_ptr(dev);
  226. return 0;
  227. }
  228. static const struct rockchip_efuse_data rk3036_data = {
  229. .read = rockchip_rk3036_efuse_read,
  230. .size = 0x20,
  231. };
  232. static const struct rockchip_efuse_data rk3128_data = {
  233. .read = rockchip_rk3128_efuse_read,
  234. .size = 0x40,
  235. };
  236. static const struct rockchip_efuse_data rk3288_data = {
  237. .read = rockchip_rk3288_efuse_read,
  238. .size = 0x20,
  239. };
  240. static const struct rockchip_efuse_data rk3328_data = {
  241. .read = rockchip_rk3328_efuse_read,
  242. .offset = 0x60,
  243. .size = 0x20,
  244. .block_size = 4,
  245. };
  246. static const struct rockchip_efuse_data rk3399_data = {
  247. .read = rockchip_rk3399_efuse_read,
  248. .size = 0x80,
  249. .block_size = 4,
  250. };
  251. static const struct udevice_id rockchip_efuse_ids[] = {
  252. {
  253. .compatible = "rockchip,rk3036-efuse",
  254. .data = (ulong)&rk3036_data,
  255. },
  256. {
  257. .compatible = "rockchip,rk3066a-efuse",
  258. .data = (ulong)&rk3288_data,
  259. },
  260. {
  261. .compatible = "rockchip,rk3128-efuse",
  262. .data = (ulong)&rk3128_data,
  263. },
  264. {
  265. .compatible = "rockchip,rk3188-efuse",
  266. .data = (ulong)&rk3288_data,
  267. },
  268. {
  269. .compatible = "rockchip,rk3228-efuse",
  270. .data = (ulong)&rk3288_data,
  271. },
  272. {
  273. .compatible = "rockchip,rk3288-efuse",
  274. .data = (ulong)&rk3288_data,
  275. },
  276. {
  277. .compatible = "rockchip,rk3328-efuse",
  278. .data = (ulong)&rk3328_data,
  279. },
  280. {
  281. .compatible = "rockchip,rk3399-efuse",
  282. .data = (ulong)&rk3399_data,
  283. },
  284. {}
  285. };
  286. U_BOOT_DRIVER(rockchip_efuse) = {
  287. .name = "rockchip_efuse",
  288. .id = UCLASS_MISC,
  289. .of_match = rockchip_efuse_ids,
  290. .of_to_plat = rockchip_efuse_of_to_plat,
  291. .plat_auto = sizeof(struct rockchip_efuse_plat),
  292. .ops = &rockchip_efuse_ops,
  293. };