2 * Copyright (C) 2017 Xilinx, Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
15 #include <linux/dma-mapping.h>
16 #include <linux/module.h>
17 #include <linux/nvmem-provider.h>
19 #include <linux/platform_device.h>
20 #include <linux/firmware/xilinx/zynqmp/firmware.h>
22 #define SILICON_REVISION_MASK 0xF
23 #define WORD_INBYTES (4)
24 #define SOC_VER_SIZE (0x4)
25 #define EFUSE_MEMORY_SIZE (0xF4)
26 #define UNUSED_SPACE (0x8)
27 #define ZYNQMP_NVMEM_SIZE (SOC_VER_SIZE + UNUSED_SPACE + \
29 #define SOC_VERSION_OFFSET (0x0)
30 #define EFUSE_START_OFFSET (0xC)
31 #define EFUSE_END_OFFSET (0xFC)
32 #define EFUSE_NOT_ENABLED (29)
33 #define EFUSE_READ (0)
34 #define EFUSE_WRITE (1)
37 * struct xilinx_efuse - the basic structure
38 * @src: address of the buffer to store the data to be write/read
39 * @size: no of words to be read/write
40 * @offset: offset to be read/write`
41 * @flag: 0 - represents efuse read and 1- represents efuse write
43 * this structure stores all the required details to
44 * read/write efuse memory.
54 static int zynqmp_efuse_access(void *context, unsigned int offset,
55 void *val, size_t bytes, unsigned int flag)
57 const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
58 size_t words = bytes / WORD_INBYTES;
59 struct device *dev = context;
60 dma_addr_t dma_addr, dma_buf;
61 struct xilinx_efuse *efuse;
65 if (!eemi_ops || !eemi_ops->efuse_access)
68 if (bytes % WORD_INBYTES != 0) {
70 "ERROR: Bytes requested should be word aligned\n\r");
73 if (offset % WORD_INBYTES != 0) {
75 "ERROR: offset requested should be word aligned\n\r");
79 efuse = dma_alloc_coherent(dev, sizeof(struct xilinx_efuse),
80 &dma_addr, GFP_KERNEL);
84 data = dma_alloc_coherent(dev, sizeof(bytes),
85 &dma_buf, GFP_KERNEL);
87 dma_free_coherent(dev, sizeof(struct xilinx_efuse),
92 if (flag == EFUSE_WRITE) {
93 memcpy(data, val, bytes);
94 efuse->flag = EFUSE_WRITE;
96 efuse->flag = EFUSE_READ;
101 efuse->offset = offset;
103 eemi_ops->efuse_access(dma_addr, &ret);
105 if (ret == EFUSE_NOT_ENABLED) {
106 dev_err(dev, "ERROR: efuse access is not enabled\n\r");
110 dev_err(dev, "ERROR: in efuse read %x\n\r", ret);
115 if (flag == EFUSE_READ)
116 memcpy(val, data, bytes);
119 dma_free_coherent(dev, sizeof(struct xilinx_efuse),
121 dma_free_coherent(dev, sizeof(bytes),
127 static int zynqmp_nvmem_read(void *context, unsigned int offset,
128 void *val, size_t bytes)
132 const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
134 if (!eemi_ops || !eemi_ops->get_chipid)
138 /* Soc version offset is zero */
139 case SOC_VERSION_OFFSET:
140 if (bytes != SOC_VER_SIZE)
143 ret = eemi_ops->get_chipid(&idcode, &version);
147 pr_debug("Read chipid val %x %x\n", idcode, version);
148 *(int *)val = version & SILICON_REVISION_MASK;
150 /* Efuse offset starts from 0xc */
151 case EFUSE_START_OFFSET ... EFUSE_END_OFFSET:
152 ret = zynqmp_efuse_access(context, offset, val,
156 *(u32 *)val = 0xDEADBEEF;
164 static int zynqmp_nvmem_write(void *context,
165 unsigned int offset, void *val, size_t bytes)
167 /* Efuse offset starts from 0xc */
168 if (offset < EFUSE_START_OFFSET)
171 return(zynqmp_efuse_access(context, offset,
172 val, bytes, EFUSE_WRITE));
175 static struct nvmem_config econfig = {
176 .name = "zynqmp-nvmem",
177 .owner = THIS_MODULE,
179 .size = ZYNQMP_NVMEM_SIZE,
182 static const struct of_device_id zynqmp_nvmem_match[] = {
183 { .compatible = "xlnx,zynqmp-nvmem-fw", },
186 MODULE_DEVICE_TABLE(of, zynqmp_nvmem_match);
188 static int zynqmp_nvmem_probe(struct platform_device *pdev)
190 struct nvmem_device *nvmem;
192 econfig.dev = &pdev->dev;
193 econfig.priv = &pdev->dev;
194 econfig.reg_read = zynqmp_nvmem_read;
195 econfig.reg_write = zynqmp_nvmem_write;
197 nvmem = nvmem_register(&econfig);
199 return PTR_ERR(nvmem);
201 platform_set_drvdata(pdev, nvmem);
206 static int zynqmp_nvmem_remove(struct platform_device *pdev)
208 struct nvmem_device *nvmem = platform_get_drvdata(pdev);
210 return nvmem_unregister(nvmem);
213 static struct platform_driver zynqmp_nvmem_driver = {
214 .probe = zynqmp_nvmem_probe,
215 .remove = zynqmp_nvmem_remove,
217 .name = "zynqmp-nvmem",
218 .of_match_table = zynqmp_nvmem_match,
222 module_platform_driver(zynqmp_nvmem_driver);
224 MODULE_AUTHOR("Michal Simek <michal.simek@xilinx.com>, Nava kishore Manne <navam@xilinx.com>");
225 MODULE_DESCRIPTION("ZynqMP NVMEM driver");
226 MODULE_LICENSE("GPL");