imx-ocotp-scu.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * i.MX8 OCOTP fusebox driver
  4. *
  5. * Copyright 2019 NXP
  6. *
  7. * Peng Fan <peng.fan@nxp.com>
  8. */
  9. #include <linux/arm-smccc.h>
  10. #include <linux/firmware/imx/sci.h>
  11. #include <linux/module.h>
  12. #include <linux/nvmem-provider.h>
  13. #include <linux/of_device.h>
  14. #include <linux/platform_device.h>
  15. #include <linux/slab.h>
  16. #define IMX_SIP_OTP_WRITE 0xc200000B
  17. enum ocotp_devtype {
  18. IMX8QXP,
  19. IMX8QM,
  20. };
  21. #define ECC_REGION BIT(0)
  22. #define HOLE_REGION BIT(1)
  23. struct ocotp_region {
  24. u32 start;
  25. u32 end;
  26. u32 flag;
  27. };
  28. struct ocotp_devtype_data {
  29. int devtype;
  30. int nregs;
  31. u32 num_region;
  32. struct ocotp_region region[];
  33. };
  34. struct ocotp_priv {
  35. struct device *dev;
  36. const struct ocotp_devtype_data *data;
  37. struct imx_sc_ipc *nvmem_ipc;
  38. };
  39. struct imx_sc_msg_misc_fuse_read {
  40. struct imx_sc_rpc_msg hdr;
  41. u32 word;
  42. } __packed;
  43. static DEFINE_MUTEX(scu_ocotp_mutex);
  44. static struct ocotp_devtype_data imx8qxp_data = {
  45. .devtype = IMX8QXP,
  46. .nregs = 800,
  47. .num_region = 3,
  48. .region = {
  49. {0x10, 0x10f, ECC_REGION},
  50. {0x110, 0x21F, HOLE_REGION},
  51. {0x220, 0x31F, ECC_REGION},
  52. },
  53. };
  54. static struct ocotp_devtype_data imx8qm_data = {
  55. .devtype = IMX8QM,
  56. .nregs = 800,
  57. .num_region = 2,
  58. .region = {
  59. {0x10, 0x10f, ECC_REGION},
  60. {0x1a0, 0x1ff, ECC_REGION},
  61. },
  62. };
  63. static bool in_hole(void *context, u32 index)
  64. {
  65. struct ocotp_priv *priv = context;
  66. const struct ocotp_devtype_data *data = priv->data;
  67. int i;
  68. for (i = 0; i < data->num_region; i++) {
  69. if (data->region[i].flag & HOLE_REGION) {
  70. if ((index >= data->region[i].start) &&
  71. (index <= data->region[i].end))
  72. return true;
  73. }
  74. }
  75. return false;
  76. }
  77. static bool in_ecc(void *context, u32 index)
  78. {
  79. struct ocotp_priv *priv = context;
  80. const struct ocotp_devtype_data *data = priv->data;
  81. int i;
  82. for (i = 0; i < data->num_region; i++) {
  83. if (data->region[i].flag & ECC_REGION) {
  84. if ((index >= data->region[i].start) &&
  85. (index <= data->region[i].end))
  86. return true;
  87. }
  88. }
  89. return false;
  90. }
  91. static int imx_sc_misc_otp_fuse_read(struct imx_sc_ipc *ipc, u32 word,
  92. u32 *val)
  93. {
  94. struct imx_sc_msg_misc_fuse_read msg;
  95. struct imx_sc_rpc_msg *hdr = &msg.hdr;
  96. int ret;
  97. hdr->ver = IMX_SC_RPC_VERSION;
  98. hdr->svc = IMX_SC_RPC_SVC_MISC;
  99. hdr->func = IMX_SC_MISC_FUNC_OTP_FUSE_READ;
  100. hdr->size = 2;
  101. msg.word = word;
  102. ret = imx_scu_call_rpc(ipc, &msg, true);
  103. if (ret)
  104. return ret;
  105. *val = msg.word;
  106. return 0;
  107. }
  108. static int imx_scu_ocotp_read(void *context, unsigned int offset,
  109. void *val, size_t bytes)
  110. {
  111. struct ocotp_priv *priv = context;
  112. u32 count, index, num_bytes;
  113. u32 *buf;
  114. void *p;
  115. int i, ret;
  116. index = offset;
  117. num_bytes = round_up(bytes, 4);
  118. count = num_bytes >> 2;
  119. if (count > (priv->data->nregs - index))
  120. count = priv->data->nregs - index;
  121. p = kzalloc(num_bytes, GFP_KERNEL);
  122. if (!p)
  123. return -ENOMEM;
  124. mutex_lock(&scu_ocotp_mutex);
  125. buf = p;
  126. for (i = index; i < (index + count); i++) {
  127. if (in_hole(context, i)) {
  128. *buf++ = 0;
  129. continue;
  130. }
  131. ret = imx_sc_misc_otp_fuse_read(priv->nvmem_ipc, i, buf);
  132. if (ret) {
  133. mutex_unlock(&scu_ocotp_mutex);
  134. kfree(p);
  135. return ret;
  136. }
  137. buf++;
  138. }
  139. memcpy(val, (u8 *)p, bytes);
  140. mutex_unlock(&scu_ocotp_mutex);
  141. kfree(p);
  142. return 0;
  143. }
  144. static int imx_scu_ocotp_write(void *context, unsigned int offset,
  145. void *val, size_t bytes)
  146. {
  147. struct ocotp_priv *priv = context;
  148. struct arm_smccc_res res;
  149. u32 *buf = val;
  150. u32 tmp;
  151. u32 index;
  152. int ret;
  153. /* allow only writing one complete OTP word at a time */
  154. if (bytes != 4)
  155. return -EINVAL;
  156. index = offset;
  157. if (in_hole(context, index))
  158. return -EINVAL;
  159. if (in_ecc(context, index)) {
  160. pr_warn("ECC region, only program once\n");
  161. mutex_lock(&scu_ocotp_mutex);
  162. ret = imx_sc_misc_otp_fuse_read(priv->nvmem_ipc, index, &tmp);
  163. mutex_unlock(&scu_ocotp_mutex);
  164. if (ret)
  165. return ret;
  166. if (tmp) {
  167. pr_warn("ECC region, already has value: %x\n", tmp);
  168. return -EIO;
  169. }
  170. }
  171. mutex_lock(&scu_ocotp_mutex);
  172. arm_smccc_smc(IMX_SIP_OTP_WRITE, index, *buf, 0, 0, 0, 0, 0, &res);
  173. mutex_unlock(&scu_ocotp_mutex);
  174. return res.a0;
  175. }
  176. static struct nvmem_config imx_scu_ocotp_nvmem_config = {
  177. .name = "imx-scu-ocotp",
  178. .read_only = false,
  179. .word_size = 4,
  180. .stride = 1,
  181. .owner = THIS_MODULE,
  182. .reg_read = imx_scu_ocotp_read,
  183. .reg_write = imx_scu_ocotp_write,
  184. };
  185. static const struct of_device_id imx_scu_ocotp_dt_ids[] = {
  186. { .compatible = "fsl,imx8qxp-scu-ocotp", (void *)&imx8qxp_data },
  187. { .compatible = "fsl,imx8qm-scu-ocotp", (void *)&imx8qm_data },
  188. { },
  189. };
  190. MODULE_DEVICE_TABLE(of, imx_scu_ocotp_dt_ids);
  191. static int imx_scu_ocotp_probe(struct platform_device *pdev)
  192. {
  193. struct device *dev = &pdev->dev;
  194. struct ocotp_priv *priv;
  195. struct nvmem_device *nvmem;
  196. int ret;
  197. priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  198. if (!priv)
  199. return -ENOMEM;
  200. ret = imx_scu_get_handle(&priv->nvmem_ipc);
  201. if (ret)
  202. return ret;
  203. priv->data = of_device_get_match_data(dev);
  204. priv->dev = dev;
  205. imx_scu_ocotp_nvmem_config.size = 4 * priv->data->nregs;
  206. imx_scu_ocotp_nvmem_config.dev = dev;
  207. imx_scu_ocotp_nvmem_config.priv = priv;
  208. nvmem = devm_nvmem_register(dev, &imx_scu_ocotp_nvmem_config);
  209. return PTR_ERR_OR_ZERO(nvmem);
  210. }
  211. static struct platform_driver imx_scu_ocotp_driver = {
  212. .probe = imx_scu_ocotp_probe,
  213. .driver = {
  214. .name = "imx_scu_ocotp",
  215. .of_match_table = imx_scu_ocotp_dt_ids,
  216. },
  217. };
  218. module_platform_driver(imx_scu_ocotp_driver);
  219. MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
  220. MODULE_DESCRIPTION("i.MX8 SCU OCOTP fuse box driver");
  221. MODULE_LICENSE("GPL v2");