1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2019 Xilinx, Inc.
4 * Copyright (C) 2022 - 2023, Advanced Micro Devices, Inc.
7 #include <linux/dma-mapping.h>
8 #include <linux/module.h>
9 #include <linux/nvmem-provider.h>
11 #include <linux/platform_device.h>
12 #include <linux/firmware/xlnx-zynqmp.h>
14 #define SILICON_REVISION_MASK 0xF
15 #define P_USER_0_64_UPPER_MASK GENMASK(31, 16)
16 #define P_USER_127_LOWER_4_BIT_MASK GENMASK(3, 0)
17 #define WORD_INBYTES 4
18 #define SOC_VER_SIZE 0x4
19 #define EFUSE_MEMORY_SIZE 0x177
20 #define UNUSED_SPACE 0x8
21 #define ZYNQMP_NVMEM_SIZE (SOC_VER_SIZE + UNUSED_SPACE + \
23 #define SOC_VERSION_OFFSET 0x0
24 #define EFUSE_START_OFFSET 0xC
25 #define EFUSE_END_OFFSET 0xFC
26 #define EFUSE_PUF_START_OFFSET 0x100
27 #define EFUSE_PUF_MID_OFFSET 0x140
28 #define EFUSE_PUF_END_OFFSET 0x17F
29 #define EFUSE_NOT_ENABLED 29
40 * struct xilinx_efuse - the basic structure
41 * @src: address of the buffer to store the data to be write/read
42 * @size: read/write word count
43 * @offset: read/write offset
44 * @flag: 0 - represents efuse read and 1- represents efuse write
45 * @pufuserfuse:0 - represents non-puf efuses, offset is used for read/write
46 * 1 - represents puf user fuse row number.
48 * this structure stores all the required details to
49 * read/write efuse memory.
55 enum efuse_access flag
;
59 static int zynqmp_efuse_access(void *context
, unsigned int offset
,
60 void *val
, size_t bytes
, enum efuse_access flag
,
63 struct device
*dev
= context
;
64 struct xilinx_efuse
*efuse
;
67 size_t words
= bytes
/ WORD_INBYTES
;
72 if (bytes
% WORD_INBYTES
!= 0) {
73 dev_err(dev
, "Bytes requested should be word aligned\n");
77 if (pufflag
== 0 && offset
% WORD_INBYTES
) {
78 dev_err(dev
, "Offset requested should be word aligned\n");
82 if (pufflag
== 1 && flag
== EFUSE_WRITE
) {
83 memcpy(&value
, val
, bytes
);
84 if ((offset
== EFUSE_PUF_START_OFFSET
||
85 offset
== EFUSE_PUF_MID_OFFSET
) &&
86 value
& P_USER_0_64_UPPER_MASK
) {
87 dev_err(dev
, "Only lower 4 bytes are allowed to be programmed in P_USER_0 & P_USER_64\n");
91 if (offset
== EFUSE_PUF_END_OFFSET
&&
92 (value
& P_USER_127_LOWER_4_BIT_MASK
)) {
93 dev_err(dev
, "Only MSB 28 bits are allowed to be programmed for P_USER_127\n");
98 efuse
= dma_alloc_coherent(dev
, sizeof(struct xilinx_efuse
),
99 &dma_addr
, GFP_KERNEL
);
103 data
= dma_alloc_coherent(dev
, sizeof(bytes
),
104 &dma_buf
, GFP_KERNEL
);
107 goto efuse_data_fail
;
110 if (flag
== EFUSE_WRITE
) {
111 memcpy(data
, val
, bytes
);
112 efuse
->flag
= EFUSE_WRITE
;
114 efuse
->flag
= EFUSE_READ
;
117 efuse
->src
= dma_buf
;
119 efuse
->offset
= offset
;
120 efuse
->pufuserfuse
= pufflag
;
122 zynqmp_pm_efuse_access(dma_addr
, (u32
*)&ret
);
124 if (ret
== EFUSE_NOT_ENABLED
) {
125 dev_err(dev
, "efuse access is not enabled\n");
128 dev_err(dev
, "Error in efuse read %x\n", ret
);
131 goto efuse_access_err
;
134 if (flag
== EFUSE_READ
)
135 memcpy(val
, data
, bytes
);
137 dma_free_coherent(dev
, sizeof(bytes
),
140 dma_free_coherent(dev
, sizeof(struct xilinx_efuse
),
146 static int zynqmp_nvmem_read(void *context
, unsigned int offset
, void *val
, size_t bytes
)
148 struct device
*dev
= context
;
154 if (offset
>= EFUSE_PUF_START_OFFSET
&& offset
<= EFUSE_PUF_END_OFFSET
)
158 /* Soc version offset is zero */
159 case SOC_VERSION_OFFSET
:
160 if (bytes
!= SOC_VER_SIZE
)
163 ret
= zynqmp_pm_get_chipid((u32
*)&idcode
, (u32
*)&version
);
167 dev_dbg(dev
, "Read chipid val %x %x\n", idcode
, version
);
168 *(int *)val
= version
& SILICON_REVISION_MASK
;
170 /* Efuse offset starts from 0xc */
171 case EFUSE_START_OFFSET
... EFUSE_END_OFFSET
:
172 case EFUSE_PUF_START_OFFSET
... EFUSE_PUF_END_OFFSET
:
173 ret
= zynqmp_efuse_access(context
, offset
, val
,
174 bytes
, EFUSE_READ
, pufflag
);
177 *(u32
*)val
= 0xDEADBEEF;
185 static int zynqmp_nvmem_write(void *context
,
186 unsigned int offset
, void *val
, size_t bytes
)
190 if (offset
< EFUSE_START_OFFSET
|| offset
> EFUSE_PUF_END_OFFSET
)
193 if (offset
>= EFUSE_PUF_START_OFFSET
&& offset
<= EFUSE_PUF_END_OFFSET
)
196 return zynqmp_efuse_access(context
, offset
,
197 val
, bytes
, EFUSE_WRITE
, pufflag
);
200 static const struct of_device_id zynqmp_nvmem_match
[] = {
201 { .compatible
= "xlnx,zynqmp-nvmem-fw", },
204 MODULE_DEVICE_TABLE(of
, zynqmp_nvmem_match
);
206 static int zynqmp_nvmem_probe(struct platform_device
*pdev
)
208 struct device
*dev
= &pdev
->dev
;
209 struct nvmem_config econfig
= {};
211 econfig
.name
= "zynqmp-nvmem";
212 econfig
.owner
= THIS_MODULE
;
213 econfig
.word_size
= 1;
214 econfig
.size
= ZYNQMP_NVMEM_SIZE
;
216 econfig
.add_legacy_fixed_of_cells
= true;
217 econfig
.reg_read
= zynqmp_nvmem_read
;
218 econfig
.reg_write
= zynqmp_nvmem_write
;
220 return PTR_ERR_OR_ZERO(devm_nvmem_register(dev
, &econfig
));
223 static struct platform_driver zynqmp_nvmem_driver
= {
224 .probe
= zynqmp_nvmem_probe
,
226 .name
= "zynqmp-nvmem",
227 .of_match_table
= zynqmp_nvmem_match
,
231 module_platform_driver(zynqmp_nvmem_driver
);
233 MODULE_AUTHOR("Michal Simek <michal.simek@amd.com>, Nava kishore Manne <nava.kishore.manne@amd.com>");
234 MODULE_DESCRIPTION("ZynqMP NVMEM driver");
235 MODULE_LICENSE("GPL");