drivers/nvmem/zynqmp_nvmem.c

Source file repositories/reference/linux-study-clean/drivers/nvmem/zynqmp_nvmem.c

File Facts

System
Linux kernel
Corpus path
drivers/nvmem/zynqmp_nvmem.c
Extension
.c
Size
5995 bytes
Lines
237
Domain
Driver Families
Bucket
drivers/nvmem
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct xilinx_efuse {
	u64 src;
	u32 size;
	u32 offset;
	enum efuse_access flag;
	u32 pufuserfuse;
};

static int zynqmp_efuse_access(void *context, unsigned int offset,
			       void *val, size_t bytes, enum efuse_access flag,
			       unsigned int pufflag)
{
	struct device *dev = context;
	struct xilinx_efuse *efuse;
	dma_addr_t dma_addr;
	dma_addr_t dma_buf;
	size_t words = bytes / WORD_INBYTES;
	int ret;
	unsigned int value;
	char *data;

	if (bytes % WORD_INBYTES != 0) {
		dev_err(dev, "Bytes requested should be word aligned\n");
		return -EOPNOTSUPP;
	}

	if (pufflag == 0 && offset % WORD_INBYTES) {
		dev_err(dev, "Offset requested should be word aligned\n");
		return -EOPNOTSUPP;
	}

	if (pufflag == 1 && flag == EFUSE_WRITE) {
		memcpy(&value, val, sizeof(value));
		if ((offset == EFUSE_PUF_START_OFFSET ||
		     offset == EFUSE_PUF_MID_OFFSET) &&
		    value & P_USER_0_64_UPPER_MASK) {
			dev_err(dev, "Only lower 4 bytes are allowed to be programmed in P_USER_0 & P_USER_64\n");
			return -EOPNOTSUPP;
		}

		if (offset == EFUSE_PUF_END_OFFSET &&
		    (value & P_USER_127_LOWER_4_BIT_MASK)) {
			dev_err(dev, "Only MSB 28 bits are allowed to be programmed for P_USER_127\n");
			return -EOPNOTSUPP;
		}
	}

	efuse = dma_alloc_coherent(dev, sizeof(struct xilinx_efuse),
				   &dma_addr, GFP_KERNEL);
	if (!efuse)
		return -ENOMEM;

	data = dma_alloc_coherent(dev, bytes,
				  &dma_buf, GFP_KERNEL);
	if (!data) {
		ret = -ENOMEM;
		goto efuse_data_fail;
	}

	if (flag == EFUSE_WRITE) {
		memcpy(data, val, bytes);
		efuse->flag = EFUSE_WRITE;
	} else {
		efuse->flag = EFUSE_READ;
	}

	efuse->src = dma_buf;
	efuse->size = words;
	efuse->offset = offset;
	efuse->pufuserfuse = pufflag;

	zynqmp_pm_efuse_access(dma_addr, (u32 *)&ret);
	if (ret != 0) {
		if (ret == EFUSE_NOT_ENABLED) {
			dev_err(dev, "efuse access is not enabled\n");
			ret = -EOPNOTSUPP;
		} else {
			dev_err(dev, "Error in efuse read %x\n", ret);
			ret = -EPERM;
		}
		goto efuse_access_err;
	}

	if (flag == EFUSE_READ)
		memcpy(val, data, bytes);
efuse_access_err:
	dma_free_coherent(dev, bytes,
			  data, dma_buf);
efuse_data_fail:
	dma_free_coherent(dev, sizeof(struct xilinx_efuse),

Annotation

Implementation Notes