zynqmp_nvmem.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2019 Xilinx, Inc.
  4. * Copyright (C) 2022 - 2023, Advanced Micro Devices, Inc.
  5. */
  6. #include <linux/dma-mapping.h>
  7. #include <linux/module.h>
  8. #include <linux/nvmem-provider.h>
  9. #include <linux/of.h>
  10. #include <linux/platform_device.h>
  11. #include <linux/firmware/xlnx-zynqmp.h>
  12. #define SILICON_REVISION_MASK 0xF
  13. #define P_USER_0_64_UPPER_MASK GENMASK(31, 16)
  14. #define P_USER_127_LOWER_4_BIT_MASK GENMASK(3, 0)
  15. #define WORD_INBYTES 4
  16. #define SOC_VER_SIZE 0x4
  17. #define EFUSE_MEMORY_SIZE 0x177
  18. #define UNUSED_SPACE 0x8
  19. #define ZYNQMP_NVMEM_SIZE (SOC_VER_SIZE + UNUSED_SPACE + \
  20. EFUSE_MEMORY_SIZE)
  21. #define SOC_VERSION_OFFSET 0x0
  22. #define EFUSE_START_OFFSET 0xC
  23. #define EFUSE_END_OFFSET 0xFC
  24. #define EFUSE_PUF_START_OFFSET 0x100
  25. #define EFUSE_PUF_MID_OFFSET 0x140
  26. #define EFUSE_PUF_END_OFFSET 0x17F
  27. #define EFUSE_NOT_ENABLED 29
  28. /*
  29. * efuse access type
  30. */
  31. enum efuse_access {
  32. EFUSE_READ = 0,
  33. EFUSE_WRITE
  34. };
  35. /**
  36. * struct xilinx_efuse - the basic structure
  37. * @src: address of the buffer to store the data to be write/read
  38. * @size: read/write word count
  39. * @offset: read/write offset
  40. * @flag: 0 - represents efuse read and 1- represents efuse write
  41. * @pufuserfuse:0 - represents non-puf efuses, offset is used for read/write
  42. * 1 - represents puf user fuse row number.
  43. *
  44. * this structure stores all the required details to
  45. * read/write efuse memory.
  46. */
  47. struct xilinx_efuse {
  48. u64 src;
  49. u32 size;
  50. u32 offset;
  51. enum efuse_access flag;
  52. u32 pufuserfuse;
  53. };
  54. static int zynqmp_efuse_access(void *context, unsigned int offset,
  55. void *val, size_t bytes, enum efuse_access flag,
  56. unsigned int pufflag)
  57. {
  58. struct device *dev = context;
  59. struct xilinx_efuse *efuse;
  60. dma_addr_t dma_addr;
  61. dma_addr_t dma_buf;
  62. size_t words = bytes / WORD_INBYTES;
  63. int ret;
  64. int value;
  65. char *data;
  66. if (bytes % WORD_INBYTES != 0) {
  67. dev_err(dev, "Bytes requested should be word aligned\n");
  68. return -EOPNOTSUPP;
  69. }
  70. if (pufflag == 0 && offset % WORD_INBYTES) {
  71. dev_err(dev, "Offset requested should be word aligned\n");
  72. return -EOPNOTSUPP;
  73. }
  74. if (pufflag == 1 && flag == EFUSE_WRITE) {
  75. memcpy(&value, val, bytes);
  76. if ((offset == EFUSE_PUF_START_OFFSET ||
  77. offset == EFUSE_PUF_MID_OFFSET) &&
  78. value & P_USER_0_64_UPPER_MASK) {
  79. dev_err(dev, "Only lower 4 bytes are allowed to be programmed in P_USER_0 & P_USER_64\n");
  80. return -EOPNOTSUPP;
  81. }
  82. if (offset == EFUSE_PUF_END_OFFSET &&
  83. (value & P_USER_127_LOWER_4_BIT_MASK)) {
  84. dev_err(dev, "Only MSB 28 bits are allowed to be programmed for P_USER_127\n");
  85. return -EOPNOTSUPP;
  86. }
  87. }
  88. efuse = dma_alloc_coherent(dev, sizeof(struct xilinx_efuse),
  89. &dma_addr, GFP_KERNEL);
  90. if (!efuse)
  91. return -ENOMEM;
  92. data = dma_alloc_coherent(dev, sizeof(bytes),
  93. &dma_buf, GFP_KERNEL);
  94. if (!data) {
  95. ret = -ENOMEM;
  96. goto efuse_data_fail;
  97. }
  98. if (flag == EFUSE_WRITE) {
  99. memcpy(data, val, bytes);
  100. efuse->flag = EFUSE_WRITE;
  101. } else {
  102. efuse->flag = EFUSE_READ;
  103. }
  104. efuse->src = dma_buf;
  105. efuse->size = words;
  106. efuse->offset = offset;
  107. efuse->pufuserfuse = pufflag;
  108. zynqmp_pm_efuse_access(dma_addr, (u32 *)&ret);
  109. if (ret != 0) {
  110. if (ret == EFUSE_NOT_ENABLED) {
  111. dev_err(dev, "efuse access is not enabled\n");
  112. ret = -EOPNOTSUPP;
  113. } else {
  114. dev_err(dev, "Error in efuse read %x\n", ret);
  115. ret = -EPERM;
  116. }
  117. goto efuse_access_err;
  118. }
  119. if (flag == EFUSE_READ)
  120. memcpy(val, data, bytes);
  121. efuse_access_err:
  122. dma_free_coherent(dev, sizeof(bytes),
  123. data, dma_buf);
  124. efuse_data_fail:
  125. dma_free_coherent(dev, sizeof(struct xilinx_efuse),
  126. efuse, dma_addr);
  127. return ret;
  128. }
  129. static int zynqmp_nvmem_read(void *context, unsigned int offset, void *val, size_t bytes)
  130. {
  131. struct device *dev = context;
  132. int ret;
  133. int pufflag = 0;
  134. int idcode;
  135. int version;
  136. if (offset >= EFUSE_PUF_START_OFFSET && offset <= EFUSE_PUF_END_OFFSET)
  137. pufflag = 1;
  138. switch (offset) {
  139. /* Soc version offset is zero */
  140. case SOC_VERSION_OFFSET:
  141. if (bytes != SOC_VER_SIZE)
  142. return -EOPNOTSUPP;
  143. ret = zynqmp_pm_get_chipid((u32 *)&idcode, (u32 *)&version);
  144. if (ret < 0)
  145. return ret;
  146. dev_dbg(dev, "Read chipid val %x %x\n", idcode, version);
  147. *(int *)val = version & SILICON_REVISION_MASK;
  148. break;
  149. /* Efuse offset starts from 0xc */
  150. case EFUSE_START_OFFSET ... EFUSE_END_OFFSET:
  151. case EFUSE_PUF_START_OFFSET ... EFUSE_PUF_END_OFFSET:
  152. ret = zynqmp_efuse_access(context, offset, val,
  153. bytes, EFUSE_READ, pufflag);
  154. break;
  155. default:
  156. *(u32 *)val = 0xDEADBEEF;
  157. ret = 0;
  158. break;
  159. }
  160. return ret;
  161. }
  162. static int zynqmp_nvmem_write(void *context,
  163. unsigned int offset, void *val, size_t bytes)
  164. {
  165. int pufflag = 0;
  166. if (offset < EFUSE_START_OFFSET || offset > EFUSE_PUF_END_OFFSET)
  167. return -EOPNOTSUPP;
  168. if (offset >= EFUSE_PUF_START_OFFSET && offset <= EFUSE_PUF_END_OFFSET)
  169. pufflag = 1;
  170. return zynqmp_efuse_access(context, offset,
  171. val, bytes, EFUSE_WRITE, pufflag);
  172. }
  173. static const struct of_device_id zynqmp_nvmem_match[] = {
  174. { .compatible = "xlnx,zynqmp-nvmem-fw", },
  175. { /* sentinel */ },
  176. };
  177. MODULE_DEVICE_TABLE(of, zynqmp_nvmem_match);
  178. static int zynqmp_nvmem_probe(struct platform_device *pdev)
  179. {
  180. struct device *dev = &pdev->dev;
  181. struct nvmem_config econfig = {};
  182. econfig.name = "zynqmp-nvmem";
  183. econfig.owner = THIS_MODULE;
  184. econfig.word_size = 1;
  185. econfig.size = ZYNQMP_NVMEM_SIZE;
  186. econfig.dev = dev;
  187. econfig.add_legacy_fixed_of_cells = true;
  188. econfig.reg_read = zynqmp_nvmem_read;
  189. econfig.reg_write = zynqmp_nvmem_write;
  190. return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &econfig));
  191. }
  192. static struct platform_driver zynqmp_nvmem_driver = {
  193. .probe = zynqmp_nvmem_probe,
  194. .driver = {
  195. .name = "zynqmp-nvmem",
  196. .of_match_table = zynqmp_nvmem_match,
  197. },
  198. };
  199. module_platform_driver(zynqmp_nvmem_driver);
  200. MODULE_AUTHOR("Michal Simek <michal.simek@amd.com>, Nava kishore Manne <nava.kishore.manne@amd.com>");
  201. MODULE_DESCRIPTION("ZynqMP NVMEM driver");
  202. MODULE_LICENSE("GPL");