File Index
Files and directories
Sign in
FILE

mchp_pci1xxxx_otpe2p.c

File preview with syntax highlighting.

linux-6.19.14/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_otpe2p.c C
  1// SPDX-License-Identifier: GPL-2.0
  2// Copyright (C) 2022-2023 Microchip Technology Inc.
  3// PCI1xxxx OTP/EEPROM driver
  4
  5#include <linux/auxiliary_bus.h>
  6#include <linux/device.h>
  7#include <linux/iopoll.h>
  8#include <linux/module.h>
  9#include <linux/nvmem-provider.h>
 10
 11#include "mchp_pci1xxxx_gp.h"
 12
 13#define AUX_DRIVER_NAME			"PCI1xxxxOTPE2P"
 14#define EEPROM_NAME			"pci1xxxx_eeprom"
 15#define OTP_NAME			"pci1xxxx_otp"
 16
 17#define PERI_PF3_SYSTEM_REG_ADDR_BASE	0x2000
 18#define PERI_PF3_SYSTEM_REG_LENGTH	0x4000
 19
 20#define EEPROM_SIZE_BYTES		8192
 21#define OTP_SIZE_BYTES			8192
 22
 23#define CONFIG_REG_ADDR_BASE		0
 24#define EEPROM_REG_ADDR_BASE		0x0E00
 25#define OTP_REG_ADDR_BASE		0x1000
 26
 27#define MMAP_OTP_OFFSET(x)		(OTP_REG_ADDR_BASE + (x))
 28#define MMAP_EEPROM_OFFSET(x)		(EEPROM_REG_ADDR_BASE + (x))
 29#define MMAP_CFG_OFFSET(x)		(CONFIG_REG_ADDR_BASE + (x))
 30
 31#define EEPROM_CMD_REG			0x00
 32#define EEPROM_DATA_REG			0x04
 33
 34#define EEPROM_CMD_EPC_WRITE		(BIT(29) | BIT(28))
 35#define EEPROM_CMD_EPC_TIMEOUT_BIT	BIT(17)
 36#define EEPROM_CMD_EPC_BUSY_BIT		BIT(31)
 37
 38#define STATUS_READ_DELAY_US		1
 39#define STATUS_READ_TIMEOUT_US		20000
 40
 41#define OTP_ADDR_HIGH_OFFSET		0x04
 42#define OTP_ADDR_LOW_OFFSET		0x08
 43#define OTP_PRGM_DATA_OFFSET		0x10
 44#define OTP_PRGM_MODE_OFFSET		0x14
 45#define OTP_RD_DATA_OFFSET		0x18
 46#define OTP_FUNC_CMD_OFFSET		0x20
 47#define OTP_CMD_GO_OFFSET		0x28
 48#define OTP_PASS_FAIL_OFFSET		0x2C
 49#define OTP_STATUS_OFFSET		0x30
 50
 51#define OTP_FUNC_RD_BIT			BIT(0)
 52#define OTP_FUNC_PGM_BIT		BIT(1)
 53#define OTP_CMD_GO_BIT			BIT(0)
 54#define OTP_STATUS_BUSY_BIT		BIT(0)
 55#define OTP_PGM_MODE_BYTE_BIT		BIT(0)
 56#define OTP_FAIL_BIT			BIT(0)
 57
 58#define OTP_PWR_DN_BIT			BIT(0)
 59#define OTP_PWR_DN_OFFSET		0x00
 60
 61#define CFG_SYS_LOCK_OFFSET		0xA0
 62#define CFG_SYS_LOCK_PF3		BIT(5)
 63
 64#define BYTE_LOW			(GENMASK(7, 0))
 65#define BYTE_HIGH			(GENMASK(12, 8))
 66
 67struct pci1xxxx_otp_eeprom_device {
 68	struct auxiliary_device *pdev;
 69	void __iomem *reg_base;
 70	struct nvmem_config nvmem_config_eeprom;
 71	struct nvmem_device *nvmem_eeprom;
 72	struct nvmem_config nvmem_config_otp;
 73	struct nvmem_device *nvmem_otp;
 74};
 75
 76static int set_sys_lock(struct pci1xxxx_otp_eeprom_device *priv)
 77{
 78	void __iomem *sys_lock = priv->reg_base +
 79				 MMAP_CFG_OFFSET(CFG_SYS_LOCK_OFFSET);
 80	u8 data;
 81
 82	writel(CFG_SYS_LOCK_PF3, sys_lock);
 83	data = readl(sys_lock);
 84	if (data != CFG_SYS_LOCK_PF3)
 85		return -EPERM;
 86
 87	return 0;
 88}
 89
 90static void release_sys_lock(struct pci1xxxx_otp_eeprom_device *priv)
 91{
 92	void __iomem *sys_lock = priv->reg_base +
 93				 MMAP_CFG_OFFSET(CFG_SYS_LOCK_OFFSET);
 94	writel(0, sys_lock);
 95}
 96
 97static bool is_eeprom_responsive(struct pci1xxxx_otp_eeprom_device *priv)
 98{
 99	void __iomem *rb = priv->reg_base;
100	u32 regval;
101	int ret;
102
103	writel(EEPROM_CMD_EPC_TIMEOUT_BIT,
104	       rb + MMAP_EEPROM_OFFSET(EEPROM_CMD_REG));
105	writel(EEPROM_CMD_EPC_BUSY_BIT,
106	       rb + MMAP_EEPROM_OFFSET(EEPROM_CMD_REG));
107
108	/* Wait for the EPC_BUSY bit to get cleared or timeout bit to get set*/
109	ret = read_poll_timeout(readl, regval, !(regval & EEPROM_CMD_EPC_BUSY_BIT),
110				STATUS_READ_DELAY_US, STATUS_READ_TIMEOUT_US,
111				true, rb + MMAP_EEPROM_OFFSET(EEPROM_CMD_REG));
112
113	/* Return failure if either of software or hardware timeouts happen */
114	if (ret < 0 || (!ret && (regval & EEPROM_CMD_EPC_TIMEOUT_BIT)))
115		return false;
116
117	return true;
118}
119
120static int pci1xxxx_eeprom_read(void *priv_t, unsigned int off,
121				void *buf_t, size_t count)
122{
123	struct pci1xxxx_otp_eeprom_device *priv = priv_t;
124	void __iomem *rb = priv->reg_base;
125	char *buf = buf_t;
126	u32 regval;
127	u32 byte;
128	int ret;
129
130	if (off >= priv->nvmem_config_eeprom.size)
131		return -EFAULT;
132
133	if ((off + count) > priv->nvmem_config_eeprom.size)
134		count = priv->nvmem_config_eeprom.size - off;
135
136	ret = set_sys_lock(priv);
137	if (ret)
138		return ret;
139
140	for (byte = 0; byte < count; byte++) {
141		writel(EEPROM_CMD_EPC_BUSY_BIT | (off + byte), rb +
142		       MMAP_EEPROM_OFFSET(EEPROM_CMD_REG));
143
144		ret = read_poll_timeout(readl, regval,
145					!(regval & EEPROM_CMD_EPC_BUSY_BIT),
146					STATUS_READ_DELAY_US,
147					STATUS_READ_TIMEOUT_US, true,
148					rb + MMAP_EEPROM_OFFSET(EEPROM_CMD_REG));
149		if (ret < 0 || (!ret && (regval & EEPROM_CMD_EPC_TIMEOUT_BIT))) {
150			ret = -EIO;
151			goto error;
152		}
153
154		buf[byte] = readl(rb + MMAP_EEPROM_OFFSET(EEPROM_DATA_REG));
155	}
156error:
157	release_sys_lock(priv);
158	return ret;
159}
160
161static int pci1xxxx_eeprom_write(void *priv_t, unsigned int off,
162				 void *value_t, size_t count)
163{
164	struct pci1xxxx_otp_eeprom_device *priv = priv_t;
165	void __iomem *rb = priv->reg_base;
166	char *value = value_t;
167	u32 regval;
168	u32 byte;
169	int ret;
170
171	if (off >= priv->nvmem_config_eeprom.size)
172		return -EFAULT;
173
174	if ((off + count) > priv->nvmem_config_eeprom.size)
175		count = priv->nvmem_config_eeprom.size - off;
176
177	ret = set_sys_lock(priv);
178	if (ret)
179		return ret;
180
181	for (byte = 0; byte < count; byte++) {
182		writel(*(value + byte), rb + MMAP_EEPROM_OFFSET(EEPROM_DATA_REG));
183		regval = EEPROM_CMD_EPC_TIMEOUT_BIT | EEPROM_CMD_EPC_WRITE |
184			 (off + byte);
185		writel(regval, rb + MMAP_EEPROM_OFFSET(EEPROM_CMD_REG));
186		writel(EEPROM_CMD_EPC_BUSY_BIT | regval,
187		       rb + MMAP_EEPROM_OFFSET(EEPROM_CMD_REG));
188
189		ret = read_poll_timeout(readl, regval,
190					!(regval & EEPROM_CMD_EPC_BUSY_BIT),
191					STATUS_READ_DELAY_US,
192					STATUS_READ_TIMEOUT_US, true,
193					rb + MMAP_EEPROM_OFFSET(EEPROM_CMD_REG));
194		if (ret < 0 || (!ret && (regval & EEPROM_CMD_EPC_TIMEOUT_BIT))) {
195			ret = -EIO;
196			goto error;
197		}
198	}
199error:
200	release_sys_lock(priv);
201	return ret;
202}
203
204static void otp_device_set_address(struct pci1xxxx_otp_eeprom_device *priv,
205				   u16 address)
206{
207	u16 lo, hi;
208
209	lo = address & BYTE_LOW;
210	hi = (address & BYTE_HIGH) >> 8;
211	writew(lo, priv->reg_base + MMAP_OTP_OFFSET(OTP_ADDR_LOW_OFFSET));
212	writew(hi, priv->reg_base + MMAP_OTP_OFFSET(OTP_ADDR_HIGH_OFFSET));
213}
214
215static int pci1xxxx_otp_read(void *priv_t, unsigned int off,
216			     void *buf_t, size_t count)
217{
218	struct pci1xxxx_otp_eeprom_device *priv = priv_t;
219	void __iomem *rb = priv->reg_base;
220	char *buf = buf_t;
221	u32 regval;
222	u32 byte;
223	int ret;
224	u8 data;
225
226	if (off >= priv->nvmem_config_otp.size)
227		return -EFAULT;
228
229	if ((off + count) > priv->nvmem_config_otp.size)
230		count = priv->nvmem_config_otp.size - off;
231
232	ret = set_sys_lock(priv);
233	if (ret)
234		return ret;
235
236	for (byte = 0; byte < count; byte++) {
237		otp_device_set_address(priv, (u16)(off + byte));
238		data = readl(rb + MMAP_OTP_OFFSET(OTP_FUNC_CMD_OFFSET));
239		writel(data | OTP_FUNC_RD_BIT,
240		       rb + MMAP_OTP_OFFSET(OTP_FUNC_CMD_OFFSET));
241		data = readl(rb + MMAP_OTP_OFFSET(OTP_CMD_GO_OFFSET));
242		writel(data | OTP_CMD_GO_BIT,
243		       rb + MMAP_OTP_OFFSET(OTP_CMD_GO_OFFSET));
244
245		ret = read_poll_timeout(readl, regval,
246					!(regval & OTP_STATUS_BUSY_BIT),
247					STATUS_READ_DELAY_US,
248					STATUS_READ_TIMEOUT_US, true,
249					rb + MMAP_OTP_OFFSET(OTP_STATUS_OFFSET));
250
251		data = readl(rb + MMAP_OTP_OFFSET(OTP_PASS_FAIL_OFFSET));
252		if (ret < 0 || data & OTP_FAIL_BIT) {
253			ret = -EIO;
254			goto error;
255		}
256
257		buf[byte] = readl(rb + MMAP_OTP_OFFSET(OTP_RD_DATA_OFFSET));
258	}
259error:
260	release_sys_lock(priv);
261	return ret;
262}
263
264static int pci1xxxx_otp_write(void *priv_t, unsigned int off,
265			      void *value_t, size_t count)
266{
267	struct pci1xxxx_otp_eeprom_device *priv = priv_t;
268	void __iomem *rb = priv->reg_base;
269	char *value = value_t;
270	u32 regval;
271	u32 byte;
272	int ret;
273	u8 data;
274
275	if (off >= priv->nvmem_config_otp.size)
276		return -EFAULT;
277
278	if ((off + count) > priv->nvmem_config_otp.size)
279		count = priv->nvmem_config_otp.size - off;
280
281	ret = set_sys_lock(priv);
282	if (ret)
283		return ret;
284
285	for (byte = 0; byte < count; byte++) {
286		otp_device_set_address(priv, (u16)(off + byte));
287
288		/*
289		 * Set OTP_PGM_MODE_BYTE command bit in OTP_PRGM_MODE register
290		 * to enable Byte programming
291		 */
292		data = readl(rb + MMAP_OTP_OFFSET(OTP_PRGM_MODE_OFFSET));
293		writel(data | OTP_PGM_MODE_BYTE_BIT,
294		       rb + MMAP_OTP_OFFSET(OTP_PRGM_MODE_OFFSET));
295		writel(*(value + byte), rb + MMAP_OTP_OFFSET(OTP_PRGM_DATA_OFFSET));
296		data = readl(rb + MMAP_OTP_OFFSET(OTP_FUNC_CMD_OFFSET));
297		writel(data | OTP_FUNC_PGM_BIT,
298		       rb + MMAP_OTP_OFFSET(OTP_FUNC_CMD_OFFSET));
299		data = readl(rb + MMAP_OTP_OFFSET(OTP_CMD_GO_OFFSET));
300		writel(data | OTP_CMD_GO_BIT,
301		       rb + MMAP_OTP_OFFSET(OTP_CMD_GO_OFFSET));
302
303		ret = read_poll_timeout(readl, regval,
304					!(regval & OTP_STATUS_BUSY_BIT),
305					STATUS_READ_DELAY_US,
306					STATUS_READ_TIMEOUT_US, true,
307					rb + MMAP_OTP_OFFSET(OTP_STATUS_OFFSET));
308
309		data = readl(rb + MMAP_OTP_OFFSET(OTP_PASS_FAIL_OFFSET));
310		if (ret < 0 || data & OTP_FAIL_BIT) {
311			ret = -EIO;
312			goto error;
313		}
314	}
315error:
316	release_sys_lock(priv);
317	return ret;
318}
319
320static int pci1xxxx_otp_eeprom_probe(struct auxiliary_device *aux_dev,
321				     const struct auxiliary_device_id *id)
322{
323	struct auxiliary_device_wrapper *aux_dev_wrapper;
324	struct pci1xxxx_otp_eeprom_device *priv;
325	struct gp_aux_data_type *pdata;
326	int ret;
327	u8 data;
328
329	aux_dev_wrapper = container_of(aux_dev, struct auxiliary_device_wrapper,
330				       aux_dev);
331	pdata = &aux_dev_wrapper->gp_aux_data;
332	if (!pdata)
333		return -EINVAL;
334
335	priv = devm_kzalloc(&aux_dev->dev, sizeof(*priv), GFP_KERNEL);
336	if (!priv)
337		return -ENOMEM;
338
339	priv->pdev = aux_dev;
340
341	if (!devm_request_mem_region(&aux_dev->dev, pdata->region_start +
342				     PERI_PF3_SYSTEM_REG_ADDR_BASE,
343				     PERI_PF3_SYSTEM_REG_LENGTH,
344				     aux_dev->name))
345		return -ENOMEM;
346
347	priv->reg_base = devm_ioremap(&aux_dev->dev, pdata->region_start +
348				      PERI_PF3_SYSTEM_REG_ADDR_BASE,
349				      PERI_PF3_SYSTEM_REG_LENGTH);
350	if (!priv->reg_base)
351		return -ENOMEM;
352
353	ret = set_sys_lock(priv);
354	if (ret)
355		return ret;
356
357	/* Set OTP_PWR_DN to 0 to make OTP Operational */
358	data = readl(priv->reg_base + MMAP_OTP_OFFSET(OTP_PWR_DN_OFFSET));
359	writel(data & ~OTP_PWR_DN_BIT,
360	       priv->reg_base + MMAP_OTP_OFFSET(OTP_PWR_DN_OFFSET));
361
362	dev_set_drvdata(&aux_dev->dev, priv);
363
364	if (is_eeprom_responsive(priv)) {
365		priv->nvmem_config_eeprom.type = NVMEM_TYPE_EEPROM;
366		priv->nvmem_config_eeprom.name = EEPROM_NAME;
367		priv->nvmem_config_eeprom.id = NVMEM_DEVID_AUTO;
368		priv->nvmem_config_eeprom.dev = &aux_dev->dev;
369		priv->nvmem_config_eeprom.owner = THIS_MODULE;
370		priv->nvmem_config_eeprom.reg_read = pci1xxxx_eeprom_read;
371		priv->nvmem_config_eeprom.reg_write = pci1xxxx_eeprom_write;
372		priv->nvmem_config_eeprom.priv = priv;
373		priv->nvmem_config_eeprom.stride = 1;
374		priv->nvmem_config_eeprom.word_size = 1;
375		priv->nvmem_config_eeprom.size = EEPROM_SIZE_BYTES;
376
377		priv->nvmem_eeprom = devm_nvmem_register(&aux_dev->dev,
378							 &priv->nvmem_config_eeprom);
379		if (IS_ERR(priv->nvmem_eeprom))
380			return PTR_ERR(priv->nvmem_eeprom);
381	}
382
383	release_sys_lock(priv);
384
385	priv->nvmem_config_otp.type = NVMEM_TYPE_OTP;
386	priv->nvmem_config_otp.name = OTP_NAME;
387	priv->nvmem_config_otp.id = NVMEM_DEVID_AUTO;
388	priv->nvmem_config_otp.dev = &aux_dev->dev;
389	priv->nvmem_config_otp.owner = THIS_MODULE;
390	priv->nvmem_config_otp.reg_read = pci1xxxx_otp_read;
391	priv->nvmem_config_otp.reg_write = pci1xxxx_otp_write;
392	priv->nvmem_config_otp.priv = priv;
393	priv->nvmem_config_otp.stride = 1;
394	priv->nvmem_config_otp.word_size = 1;
395	priv->nvmem_config_otp.size = OTP_SIZE_BYTES;
396
397	priv->nvmem_otp = devm_nvmem_register(&aux_dev->dev,
398					      &priv->nvmem_config_otp);
399	if (IS_ERR(priv->nvmem_otp))
400		return PTR_ERR(priv->nvmem_otp);
401
402	return ret;
403}
404
405static void pci1xxxx_otp_eeprom_remove(struct auxiliary_device *aux_dev)
406{
407	struct pci1xxxx_otp_eeprom_device *priv;
408	void __iomem *sys_lock;
409
410	priv = dev_get_drvdata(&aux_dev->dev);
411	sys_lock = priv->reg_base + MMAP_CFG_OFFSET(CFG_SYS_LOCK_OFFSET);
412	writel(CFG_SYS_LOCK_PF3, sys_lock);
413
414	/* Shut down OTP */
415	writel(OTP_PWR_DN_BIT,
416	       priv->reg_base + MMAP_OTP_OFFSET(OTP_PWR_DN_OFFSET));
417
418	writel(0, sys_lock);
419}
420
421static const struct auxiliary_device_id pci1xxxx_otp_eeprom_auxiliary_id_table[] = {
422	{.name = "mchp_pci1xxxx_gp.gp_otp_e2p"},
423	{},
424};
425MODULE_DEVICE_TABLE(auxiliary, pci1xxxx_otp_eeprom_auxiliary_id_table);
426
427static struct auxiliary_driver pci1xxxx_otp_eeprom_driver = {
428	.driver = {
429		.name = AUX_DRIVER_NAME,
430	},
431	.probe = pci1xxxx_otp_eeprom_probe,
432	.remove = pci1xxxx_otp_eeprom_remove,
433	.id_table = pci1xxxx_otp_eeprom_auxiliary_id_table
434};
435module_auxiliary_driver(pci1xxxx_otp_eeprom_driver);
436
437MODULE_LICENSE("GPL");
438MODULE_AUTHOR("Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com>");
439MODULE_AUTHOR("Tharun Kumar P <tharunkumar.pasumarthi@microchip.com>");
440MODULE_AUTHOR("Vaibhaav Ram T.L <vaibhaavram.tl@microchip.com>");
441MODULE_DESCRIPTION("Microchip Technology Inc. PCI1xxxx OTP EEPROM Programmer");
~/ Read-only file preview.