1 // SPDX-License-Identifier: GPL-2.0
3 * STM32 Factory-programmed memory read access driver
5 * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
6 * Author: Fabrice Gasnier <fabrice.gasnier@st.com> for STMicroelectronics.
9 #include <linux/arm-smccc.h>
11 #include <linux/module.h>
12 #include <linux/nvmem-provider.h>
13 #include <linux/of_device.h>
15 /* BSEC secure service access from non-secure */
16 #define STM32_SMC_BSEC 0x82001003
17 #define STM32_SMC_READ_SHADOW 0x01
18 #define STM32_SMC_PROG_OTP 0x02
19 #define STM32_SMC_WRITE_SHADOW 0x03
20 #define STM32_SMC_READ_OTP 0x04
22 /* shadow registers offest */
23 #define STM32MP15_BSEC_DATA0 0x200
25 /* 32 (x 32-bits) lower shadow registers */
26 #define STM32MP15_BSEC_NUM_LOWER 32
28 struct stm32_romem_cfg
{
32 struct stm32_romem_priv
{
34 struct nvmem_config cfg
;
37 static int stm32_romem_read(void *context
, unsigned int offset
, void *buf
,
40 struct stm32_romem_priv
*priv
= context
;
44 for (i
= offset
; i
< offset
+ bytes
; i
++)
45 *buf8
++ = readb_relaxed(priv
->base
+ i
);
50 static int stm32_bsec_smc(u8 op
, u32 otp
, u32 data
, u32
*result
)
52 #if IS_ENABLED(CONFIG_HAVE_ARM_SMCCC)
53 struct arm_smccc_res res
;
55 arm_smccc_smc(STM32_SMC_BSEC
, op
, otp
, data
, 0, 0, 0, 0, &res
);
60 *result
= (u32
)res
.a1
;
68 static int stm32_bsec_read(void *context
, unsigned int offset
, void *buf
,
71 struct stm32_romem_priv
*priv
= context
;
72 struct device
*dev
= priv
->cfg
.dev
;
73 u32 roffset
, rbytes
, val
;
74 u8
*buf8
= buf
, *val8
= (u8
*)&val
;
75 int i
, j
= 0, ret
, skip_bytes
, size
;
77 /* Round unaligned access to 32-bits */
78 roffset
= rounddown(offset
, 4);
79 skip_bytes
= offset
& 0x3;
80 rbytes
= roundup(bytes
+ skip_bytes
, 4);
82 if (roffset
+ rbytes
> priv
->cfg
.size
)
85 for (i
= roffset
; (i
< roffset
+ rbytes
); i
+= 4) {
88 if (otp
< STM32MP15_BSEC_NUM_LOWER
) {
89 /* read lower data from shadow registers */
91 priv
->base
+ STM32MP15_BSEC_DATA0
+ i
);
93 ret
= stm32_bsec_smc(STM32_SMC_READ_SHADOW
, otp
, 0,
96 dev_err(dev
, "Can't read data%d (%d)\n", otp
,
101 /* skip first bytes in case of unaligned read */
103 size
= min(bytes
, (size_t)(4 - skip_bytes
));
105 size
= min(bytes
, (size_t)4);
106 memcpy(&buf8
[j
], &val8
[skip_bytes
], size
);
115 static int stm32_bsec_write(void *context
, unsigned int offset
, void *buf
,
118 struct stm32_romem_priv
*priv
= context
;
119 struct device
*dev
= priv
->cfg
.dev
;
123 /* Allow only writing complete 32-bits aligned words */
124 if ((bytes
% 4) || (offset
% 4))
127 for (i
= offset
; i
< offset
+ bytes
; i
+= 4) {
128 ret
= stm32_bsec_smc(STM32_SMC_PROG_OTP
, i
>> 2, *buf32
++,
131 dev_err(dev
, "Can't write data%d (%d)\n", i
>> 2, ret
);
139 static int stm32_romem_probe(struct platform_device
*pdev
)
141 const struct stm32_romem_cfg
*cfg
;
142 struct device
*dev
= &pdev
->dev
;
143 struct stm32_romem_priv
*priv
;
144 struct resource
*res
;
146 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
150 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
151 priv
->base
= devm_ioremap_resource(dev
, res
);
152 if (IS_ERR(priv
->base
))
153 return PTR_ERR(priv
->base
);
155 priv
->cfg
.name
= "stm32-romem";
156 priv
->cfg
.word_size
= 1;
157 priv
->cfg
.stride
= 1;
159 priv
->cfg
.priv
= priv
;
160 priv
->cfg
.owner
= THIS_MODULE
;
162 cfg
= (const struct stm32_romem_cfg
*)
163 of_match_device(dev
->driver
->of_match_table
, dev
)->data
;
165 priv
->cfg
.read_only
= true;
166 priv
->cfg
.size
= resource_size(res
);
167 priv
->cfg
.reg_read
= stm32_romem_read
;
169 priv
->cfg
.size
= cfg
->size
;
170 priv
->cfg
.reg_read
= stm32_bsec_read
;
171 priv
->cfg
.reg_write
= stm32_bsec_write
;
174 return PTR_ERR_OR_ZERO(devm_nvmem_register(dev
, &priv
->cfg
));
177 static const struct stm32_romem_cfg stm32mp15_bsec_cfg
= {
178 .size
= 384, /* 96 x 32-bits data words */
181 static const struct of_device_id stm32_romem_of_match
[] = {
182 { .compatible
= "st,stm32f4-otp", }, {
183 .compatible
= "st,stm32mp15-bsec",
184 .data
= (void *)&stm32mp15_bsec_cfg
,
188 MODULE_DEVICE_TABLE(of
, stm32_romem_of_match
);
190 static struct platform_driver stm32_romem_driver
= {
191 .probe
= stm32_romem_probe
,
193 .name
= "stm32-romem",
194 .of_match_table
= of_match_ptr(stm32_romem_of_match
),
197 module_platform_driver(stm32_romem_driver
);
199 MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>");
200 MODULE_DESCRIPTION("STMicroelectronics STM32 RO-MEM");
201 MODULE_ALIAS("platform:nvmem-stm32-romem");
202 MODULE_LICENSE("GPL v2");