804-v5.18-0009-nvmem-Add-driver-for-OCOTP-in-Sunplus-SP7021.patch 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. From 8747ec2e9762ed9ae53b3a590938f454b6a1abdf Mon Sep 17 00:00:00 2001
  2. From: Vincent Shih <[email protected]>
  3. Date: Wed, 23 Feb 2022 22:35:01 +0000
  4. Subject: [PATCH] nvmem: Add driver for OCOTP in Sunplus SP7021
  5. Add driver for OCOTP in Sunplus SP7021
  6. Signed-off-by: Vincent Shih <[email protected]>
  7. Signed-off-by: Srinivas Kandagatla <[email protected]>
  8. Link: https://lore.kernel.org/r/[email protected]
  9. Signed-off-by: Greg Kroah-Hartman <[email protected]>
  10. ---
  11. MAINTAINERS | 5 +
  12. drivers/nvmem/Kconfig | 12 ++
  13. drivers/nvmem/Makefile | 2 +
  14. drivers/nvmem/sunplus-ocotp.c | 228 ++++++++++++++++++++++++++++++++++
  15. 4 files changed, 247 insertions(+)
  16. create mode 100644 drivers/nvmem/sunplus-ocotp.c
  17. --- a/MAINTAINERS
  18. +++ b/MAINTAINERS
  19. @@ -17954,6 +17954,11 @@ L: [email protected]
  20. S: Maintained
  21. F: drivers/net/ethernet/dlink/sundance.c
  22. +SUNPLUS OCOTP DRIVER
  23. +M: Vincent Shih <[email protected]>
  24. +S: Maintained
  25. +F: drivers/nvmem/sunplus-ocotp.c
  26. +
  27. SUPERH
  28. M: Yoshinori Sato <[email protected]>
  29. M: Rich Felker <[email protected]>
  30. --- a/drivers/nvmem/Kconfig
  31. +++ b/drivers/nvmem/Kconfig
  32. @@ -312,4 +312,16 @@ config NVMEM_LAYERSCAPE_SFP
  33. This driver can also be built as a module. If so, the module
  34. will be called layerscape-sfp.
  35. +config NVMEM_SUNPLUS_OCOTP
  36. + tristate "Sunplus SoC OTP support"
  37. + depends on SOC_SP7021 || COMPILE_TEST
  38. + depends on HAS_IOMEM
  39. + help
  40. + This is a driver for the On-chip OTP controller (OCOTP) available
  41. + on Sunplus SoCs. It provides access to 128 bytes of one-time
  42. + programmable eFuse.
  43. +
  44. + This driver can also be built as a module. If so, the module
  45. + will be called nvmem-sunplus-ocotp.
  46. +
  47. endif
  48. --- a/drivers/nvmem/Makefile
  49. +++ b/drivers/nvmem/Makefile
  50. @@ -63,3 +63,5 @@ obj-$(CONFIG_NVMEM_BRCM_NVRAM) += nvmem_
  51. nvmem_brcm_nvram-y := brcm_nvram.o
  52. obj-$(CONFIG_NVMEM_LAYERSCAPE_SFP) += nvmem-layerscape-sfp.o
  53. nvmem-layerscape-sfp-y := layerscape-sfp.o
  54. +obj-$(CONFIG_NVMEM_SUNPLUS_OCOTP) += nvmem_sunplus_ocotp.o
  55. +nvmem_sunplus_ocotp-y := sunplus-ocotp.o
  56. --- /dev/null
  57. +++ b/drivers/nvmem/sunplus-ocotp.c
  58. @@ -0,0 +1,228 @@
  59. +// SPDX-License-Identifier: GPL-2.0
  60. +
  61. +/*
  62. + * The OCOTP driver for Sunplus SP7021
  63. + *
  64. + * Copyright (C) 2019 Sunplus Technology Inc., All rights reserved.
  65. + */
  66. +
  67. +#include <linux/bitfield.h>
  68. +#include <linux/clk.h>
  69. +#include <linux/delay.h>
  70. +#include <linux/device.h>
  71. +#include <linux/io.h>
  72. +#include <linux/iopoll.h>
  73. +#include <linux/module.h>
  74. +#include <linux/nvmem-provider.h>
  75. +#include <linux/of_device.h>
  76. +#include <linux/platform_device.h>
  77. +
  78. +/*
  79. + * OTP memory
  80. + * Each bank contains 4 words (32 bits).
  81. + * Bank 0 starts at offset 0 from the base.
  82. + */
  83. +
  84. +#define OTP_WORDS_PER_BANK 4
  85. +#define OTP_WORD_SIZE sizeof(u32)
  86. +#define OTP_BIT_ADDR_OF_BANK (8 * OTP_WORD_SIZE * OTP_WORDS_PER_BANK)
  87. +#define QAC628_OTP_NUM_BANKS 8
  88. +#define QAC628_OTP_SIZE (QAC628_OTP_NUM_BANKS * OTP_WORDS_PER_BANK * OTP_WORD_SIZE)
  89. +#define OTP_READ_TIMEOUT_US 200000
  90. +
  91. +/* HB_GPIO */
  92. +#define ADDRESS_8_DATA 0x20
  93. +
  94. +/* OTP_RX */
  95. +#define OTP_CONTROL_2 0x48
  96. +#define OTP_RD_PERIOD GENMASK(15, 8)
  97. +#define OTP_RD_PERIOD_MASK ~GENMASK(15, 8)
  98. +#define CPU_CLOCK FIELD_PREP(OTP_RD_PERIOD, 30)
  99. +#define SEL_BAK_KEY2 BIT(5)
  100. +#define SEL_BAK_KEY2_MASK ~BIT(5)
  101. +#define SW_TRIM_EN BIT(4)
  102. +#define SW_TRIM_EN_MASK ~BIT(4)
  103. +#define SEL_BAK_KEY BIT(3)
  104. +#define SEL_BAK_KEY_MASK ~BIT(3)
  105. +#define OTP_READ BIT(2)
  106. +#define OTP_LOAD_SECURE_DATA BIT(1)
  107. +#define OTP_LOAD_SECURE_DATA_MASK ~BIT(1)
  108. +#define OTP_DO_CRC BIT(0)
  109. +#define OTP_DO_CRC_MASK ~BIT(0)
  110. +#define OTP_STATUS 0x4c
  111. +#define OTP_READ_DONE BIT(4)
  112. +#define OTP_READ_DONE_MASK ~BIT(4)
  113. +#define OTP_LOAD_SECURE_DONE_MASK ~BIT(2)
  114. +#define OTP_READ_ADDRESS 0x50
  115. +
  116. +enum base_type {
  117. + HB_GPIO,
  118. + OTPRX,
  119. + BASEMAX,
  120. +};
  121. +
  122. +struct sp_ocotp_priv {
  123. + struct device *dev;
  124. + void __iomem *base[BASEMAX];
  125. + struct clk *clk;
  126. +};
  127. +
  128. +struct sp_ocotp_data {
  129. + int size;
  130. +};
  131. +
  132. +const struct sp_ocotp_data sp_otp_v0 = {
  133. + .size = QAC628_OTP_SIZE,
  134. +};
  135. +
  136. +static int sp_otp_read_real(struct sp_ocotp_priv *otp, int addr, char *value)
  137. +{
  138. + unsigned int addr_data;
  139. + unsigned int byte_shift;
  140. + unsigned int status;
  141. + int ret;
  142. +
  143. + addr_data = addr % (OTP_WORD_SIZE * OTP_WORDS_PER_BANK);
  144. + addr_data = addr_data / OTP_WORD_SIZE;
  145. +
  146. + byte_shift = addr % (OTP_WORD_SIZE * OTP_WORDS_PER_BANK);
  147. + byte_shift = byte_shift % OTP_WORD_SIZE;
  148. +
  149. + addr = addr / (OTP_WORD_SIZE * OTP_WORDS_PER_BANK);
  150. + addr = addr * OTP_BIT_ADDR_OF_BANK;
  151. +
  152. + writel(readl(otp->base[OTPRX] + OTP_STATUS) & OTP_READ_DONE_MASK &
  153. + OTP_LOAD_SECURE_DONE_MASK, otp->base[OTPRX] + OTP_STATUS);
  154. + writel(addr, otp->base[OTPRX] + OTP_READ_ADDRESS);
  155. + writel(readl(otp->base[OTPRX] + OTP_CONTROL_2) | OTP_READ,
  156. + otp->base[OTPRX] + OTP_CONTROL_2);
  157. + writel(readl(otp->base[OTPRX] + OTP_CONTROL_2) & SEL_BAK_KEY2_MASK & SW_TRIM_EN_MASK
  158. + & SEL_BAK_KEY_MASK & OTP_LOAD_SECURE_DATA_MASK & OTP_DO_CRC_MASK,
  159. + otp->base[OTPRX] + OTP_CONTROL_2);
  160. + writel((readl(otp->base[OTPRX] + OTP_CONTROL_2) & OTP_RD_PERIOD_MASK) | CPU_CLOCK,
  161. + otp->base[OTPRX] + OTP_CONTROL_2);
  162. +
  163. + ret = readl_poll_timeout(otp->base[OTPRX] + OTP_STATUS, status,
  164. + status & OTP_READ_DONE, 10, OTP_READ_TIMEOUT_US);
  165. +
  166. + if (ret < 0)
  167. + return ret;
  168. +
  169. + *value = (readl(otp->base[HB_GPIO] + ADDRESS_8_DATA + addr_data * OTP_WORD_SIZE)
  170. + >> (8 * byte_shift)) & 0xff;
  171. +
  172. + return ret;
  173. +}
  174. +
  175. +static int sp_ocotp_read(void *priv, unsigned int offset, void *value, size_t bytes)
  176. +{
  177. + struct sp_ocotp_priv *otp = priv;
  178. + unsigned int addr;
  179. + char *buf = value;
  180. + char val[4];
  181. + int ret;
  182. +
  183. + ret = clk_enable(otp->clk);
  184. + if (ret)
  185. + return ret;
  186. +
  187. + *buf = 0;
  188. + for (addr = offset; addr < (offset + bytes); addr++) {
  189. + ret = sp_otp_read_real(otp, addr, val);
  190. + if (ret < 0) {
  191. + dev_err(otp->dev, "OTP read fail:%d at %d", ret, addr);
  192. + goto disable_clk;
  193. + }
  194. +
  195. + *buf++ = *val;
  196. + }
  197. +
  198. +disable_clk:
  199. + clk_disable(otp->clk);
  200. +
  201. + return ret;
  202. +}
  203. +
  204. +static struct nvmem_config sp_ocotp_nvmem_config = {
  205. + .name = "sp-ocotp",
  206. + .read_only = true,
  207. + .word_size = 1,
  208. + .size = QAC628_OTP_SIZE,
  209. + .stride = 1,
  210. + .reg_read = sp_ocotp_read,
  211. + .owner = THIS_MODULE,
  212. +};
  213. +
  214. +static int sp_ocotp_probe(struct platform_device *pdev)
  215. +{
  216. + struct device *dev = &pdev->dev;
  217. + struct nvmem_device *nvmem;
  218. + struct sp_ocotp_priv *otp;
  219. + struct resource *res;
  220. + int ret;
  221. +
  222. + otp = devm_kzalloc(dev, sizeof(*otp), GFP_KERNEL);
  223. + if (!otp)
  224. + return -ENOMEM;
  225. +
  226. + otp->dev = dev;
  227. +
  228. + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hb_gpio");
  229. + otp->base[HB_GPIO] = devm_ioremap_resource(dev, res);
  230. + if (IS_ERR(otp->base[HB_GPIO]))
  231. + return PTR_ERR(otp->base[HB_GPIO]);
  232. +
  233. + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "otprx");
  234. + otp->base[OTPRX] = devm_ioremap_resource(dev, res);
  235. + if (IS_ERR(otp->base[OTPRX]))
  236. + return PTR_ERR(otp->base[OTPRX]);
  237. +
  238. + otp->clk = devm_clk_get(&pdev->dev, NULL);
  239. + if (IS_ERR(otp->clk))
  240. + return dev_err_probe(&pdev->dev, PTR_ERR(otp->clk),
  241. + "devm_clk_get fail\n");
  242. +
  243. + ret = clk_prepare(otp->clk);
  244. + if (ret < 0) {
  245. + dev_err(dev, "failed to prepare clk: %d\n", ret);
  246. + return ret;
  247. + }
  248. +
  249. + sp_ocotp_nvmem_config.priv = otp;
  250. + sp_ocotp_nvmem_config.dev = dev;
  251. +
  252. + nvmem = devm_nvmem_register(dev, &sp_ocotp_nvmem_config);
  253. + if (IS_ERR(nvmem))
  254. + return dev_err_probe(&pdev->dev, PTR_ERR(nvmem),
  255. + "register nvmem device fail\n");
  256. +
  257. + platform_set_drvdata(pdev, nvmem);
  258. +
  259. + dev_dbg(dev, "banks:%d x wpb:%d x wsize:%d = %d",
  260. + (int)QAC628_OTP_NUM_BANKS, (int)OTP_WORDS_PER_BANK,
  261. + (int)OTP_WORD_SIZE, (int)QAC628_OTP_SIZE);
  262. +
  263. + dev_info(dev, "by Sunplus (C) 2020");
  264. +
  265. + return 0;
  266. +}
  267. +
  268. +static const struct of_device_id sp_ocotp_dt_ids[] = {
  269. + { .compatible = "sunplus,sp7021-ocotp", .data = &sp_otp_v0 },
  270. + { }
  271. +};
  272. +MODULE_DEVICE_TABLE(of, sp_ocotp_dt_ids);
  273. +
  274. +static struct platform_driver sp_otp_driver = {
  275. + .probe = sp_ocotp_probe,
  276. + .driver = {
  277. + .name = "sunplus,sp7021-ocotp",
  278. + .of_match_table = sp_ocotp_dt_ids,
  279. + }
  280. +};
  281. +module_platform_driver(sp_otp_driver);
  282. +
  283. +MODULE_AUTHOR("Vincent Shih <[email protected]>");
  284. +MODULE_DESCRIPTION("Sunplus On-Chip OTP driver");
  285. +MODULE_LICENSE("GPL");
  286. +