microchip-otpc.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * OTP Memory controller
  4. *
  5. * Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries
  6. *
  7. * Author: Claudiu Beznea <[email protected]>
  8. */
  9. #include <linux/bitfield.h>
  10. #include <linux/iopoll.h>
  11. #include <linux/module.h>
  12. #include <linux/nvmem-provider.h>
  13. #include <linux/of.h>
  14. #include <linux/platform_device.h>
  15. #define MCHP_OTPC_CR (0x0)
  16. #define MCHP_OTPC_CR_READ BIT(6)
  17. #define MCHP_OTPC_MR (0x4)
  18. #define MCHP_OTPC_MR_ADDR GENMASK(31, 16)
  19. #define MCHP_OTPC_AR (0x8)
  20. #define MCHP_OTPC_SR (0xc)
  21. #define MCHP_OTPC_SR_READ BIT(6)
  22. #define MCHP_OTPC_HR (0x20)
  23. #define MCHP_OTPC_HR_SIZE GENMASK(15, 8)
  24. #define MCHP_OTPC_DR (0x24)
  25. #define MCHP_OTPC_NAME "mchp-otpc"
  26. #define MCHP_OTPC_SIZE (11 * 1024)
  27. /**
  28. * struct mchp_otpc - OTPC private data structure
  29. * @base: base address
  30. * @dev: struct device pointer
  31. * @packets: list of packets in OTP memory
  32. * @npackets: number of packets in OTP memory
  33. */
  34. struct mchp_otpc {
  35. void __iomem *base;
  36. struct device *dev;
  37. struct list_head packets;
  38. u32 npackets;
  39. };
  40. /**
  41. * struct mchp_otpc_packet - OTPC packet data structure
  42. * @list: list head
  43. * @id: packet ID
  44. * @offset: packet offset (in words) in OTP memory
  45. */
  46. struct mchp_otpc_packet {
  47. struct list_head list;
  48. u32 id;
  49. u32 offset;
  50. };
  51. static struct mchp_otpc_packet *mchp_otpc_id_to_packet(struct mchp_otpc *otpc,
  52. u32 id)
  53. {
  54. struct mchp_otpc_packet *packet;
  55. if (id >= otpc->npackets)
  56. return NULL;
  57. list_for_each_entry(packet, &otpc->packets, list) {
  58. if (packet->id == id)
  59. return packet;
  60. }
  61. return NULL;
  62. }
  63. static int mchp_otpc_prepare_read(struct mchp_otpc *otpc,
  64. unsigned int offset)
  65. {
  66. u32 tmp;
  67. /* Set address. */
  68. tmp = readl_relaxed(otpc->base + MCHP_OTPC_MR);
  69. tmp &= ~MCHP_OTPC_MR_ADDR;
  70. tmp |= FIELD_PREP(MCHP_OTPC_MR_ADDR, offset);
  71. writel_relaxed(tmp, otpc->base + MCHP_OTPC_MR);
  72. /* Set read. */
  73. tmp = readl_relaxed(otpc->base + MCHP_OTPC_CR);
  74. tmp |= MCHP_OTPC_CR_READ;
  75. writel_relaxed(tmp, otpc->base + MCHP_OTPC_CR);
  76. /* Wait for packet to be transferred into temporary buffers. */
  77. return read_poll_timeout(readl_relaxed, tmp, !(tmp & MCHP_OTPC_SR_READ),
  78. 10000, 2000, false, otpc->base + MCHP_OTPC_SR);
  79. }
  80. /*
  81. * OTPC memory is organized into packets. Each packets contains a header and
  82. * a payload. Header is 4 bytes long and contains the size of the payload.
  83. * Payload size varies. The memory footprint is something as follows:
  84. *
  85. * Memory offset Memory footprint Packet ID
  86. * ------------- ---------------- ---------
  87. *
  88. * 0x0 +------------+ <-- packet 0
  89. * | header 0 |
  90. * 0x4 +------------+
  91. * | payload 0 |
  92. * . .
  93. * . ... .
  94. * . .
  95. * offset1 +------------+ <-- packet 1
  96. * | header 1 |
  97. * offset1 + 0x4 +------------+
  98. * | payload 1 |
  99. * . .
  100. * . ... .
  101. * . .
  102. * offset2 +------------+ <-- packet 2
  103. * . .
  104. * . ... .
  105. * . .
  106. * offsetN +------------+ <-- packet N
  107. * | header N |
  108. * offsetN + 0x4 +------------+
  109. * | payload N |
  110. * . .
  111. * . ... .
  112. * . .
  113. * +------------+
  114. *
  115. * where offset1, offset2, offsetN depends on the size of payload 0, payload 1,
  116. * payload N-1.
  117. *
  118. * The access to memory is done on a per packet basis: the control registers
  119. * need to be updated with an offset address (within a packet range) and the
  120. * data registers will be update by controller with information contained by
  121. * that packet. E.g. if control registers are updated with any address within
  122. * the range [offset1, offset2) the data registers are updated by controller
  123. * with packet 1. Header data is accessible though MCHP_OTPC_HR register.
  124. * Payload data is accessible though MCHP_OTPC_DR and MCHP_OTPC_AR registers.
  125. * There is no direct mapping b/w the offset requested by software and the
  126. * offset returned by hardware.
  127. *
  128. * For this, the read function will return the first requested bytes in the
  129. * packet. The user will have to be aware of the memory footprint before doing
  130. * the read request.
  131. */
  132. static int mchp_otpc_read(void *priv, unsigned int off, void *val,
  133. size_t bytes)
  134. {
  135. struct mchp_otpc *otpc = priv;
  136. struct mchp_otpc_packet *packet;
  137. u32 *buf = val;
  138. u32 offset;
  139. size_t len = 0;
  140. int ret, payload_size;
  141. /*
  142. * We reach this point with off being multiple of stride = 4 to
  143. * be able to cross the subsystem. Inside the driver we use continuous
  144. * unsigned integer numbers for packet id, thus devide off by 4
  145. * before passing it to mchp_otpc_id_to_packet().
  146. */
  147. packet = mchp_otpc_id_to_packet(otpc, off / 4);
  148. if (!packet)
  149. return -EINVAL;
  150. offset = packet->offset;
  151. while (len < bytes) {
  152. ret = mchp_otpc_prepare_read(otpc, offset);
  153. if (ret)
  154. return ret;
  155. /* Read and save header content. */
  156. *buf++ = readl_relaxed(otpc->base + MCHP_OTPC_HR);
  157. len += sizeof(*buf);
  158. offset++;
  159. if (len >= bytes)
  160. break;
  161. /* Read and save payload content. */
  162. payload_size = FIELD_GET(MCHP_OTPC_HR_SIZE, *(buf - 1));
  163. writel_relaxed(0UL, otpc->base + MCHP_OTPC_AR);
  164. do {
  165. *buf++ = readl_relaxed(otpc->base + MCHP_OTPC_DR);
  166. len += sizeof(*buf);
  167. offset++;
  168. payload_size--;
  169. } while (payload_size >= 0 && len < bytes);
  170. }
  171. return 0;
  172. }
  173. static int mchp_otpc_init_packets_list(struct mchp_otpc *otpc, u32 *size)
  174. {
  175. struct mchp_otpc_packet *packet;
  176. u32 word, word_pos = 0, id = 0, npackets = 0, payload_size;
  177. int ret;
  178. INIT_LIST_HEAD(&otpc->packets);
  179. *size = 0;
  180. while (*size < MCHP_OTPC_SIZE) {
  181. ret = mchp_otpc_prepare_read(otpc, word_pos);
  182. if (ret)
  183. return ret;
  184. word = readl_relaxed(otpc->base + MCHP_OTPC_HR);
  185. payload_size = FIELD_GET(MCHP_OTPC_HR_SIZE, word);
  186. if (!payload_size)
  187. break;
  188. packet = devm_kzalloc(otpc->dev, sizeof(*packet), GFP_KERNEL);
  189. if (!packet)
  190. return -ENOMEM;
  191. packet->id = id++;
  192. packet->offset = word_pos;
  193. INIT_LIST_HEAD(&packet->list);
  194. list_add_tail(&packet->list, &otpc->packets);
  195. /* Count size by adding header and paload sizes. */
  196. *size += 4 * (payload_size + 1);
  197. /* Next word: this packet (header, payload) position + 1. */
  198. word_pos += payload_size + 2;
  199. npackets++;
  200. }
  201. otpc->npackets = npackets;
  202. return 0;
  203. }
  204. static struct nvmem_config mchp_nvmem_config = {
  205. .name = MCHP_OTPC_NAME,
  206. .type = NVMEM_TYPE_OTP,
  207. .read_only = true,
  208. .word_size = 4,
  209. .stride = 4,
  210. .reg_read = mchp_otpc_read,
  211. };
  212. static int mchp_otpc_probe(struct platform_device *pdev)
  213. {
  214. struct nvmem_device *nvmem;
  215. struct mchp_otpc *otpc;
  216. u32 size;
  217. int ret;
  218. otpc = devm_kzalloc(&pdev->dev, sizeof(*otpc), GFP_KERNEL);
  219. if (!otpc)
  220. return -ENOMEM;
  221. otpc->base = devm_platform_ioremap_resource(pdev, 0);
  222. if (IS_ERR(otpc->base))
  223. return PTR_ERR(otpc->base);
  224. otpc->dev = &pdev->dev;
  225. ret = mchp_otpc_init_packets_list(otpc, &size);
  226. if (ret)
  227. return ret;
  228. mchp_nvmem_config.dev = otpc->dev;
  229. mchp_nvmem_config.size = size;
  230. mchp_nvmem_config.priv = otpc;
  231. nvmem = devm_nvmem_register(&pdev->dev, &mchp_nvmem_config);
  232. return PTR_ERR_OR_ZERO(nvmem);
  233. }
  234. static const struct of_device_id __maybe_unused mchp_otpc_ids[] = {
  235. { .compatible = "microchip,sama7g5-otpc", },
  236. { },
  237. };
  238. MODULE_DEVICE_TABLE(of, mchp_otpc_ids);
  239. static struct platform_driver mchp_otpc_driver = {
  240. .probe = mchp_otpc_probe,
  241. .driver = {
  242. .name = MCHP_OTPC_NAME,
  243. .of_match_table = of_match_ptr(mchp_otpc_ids),
  244. },
  245. };
  246. module_platform_driver(mchp_otpc_driver);
  247. MODULE_AUTHOR("Claudiu Beznea <[email protected]>");
  248. MODULE_DESCRIPTION("Microchip SAMA7G5 OTPC driver");
  249. MODULE_LICENSE("GPL");