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