Skip to content

Commit 1530b92

Browse files
geertugregkh
authored andcommitted
nvmem: Add R-Car E-FUSE driver
R-Car Gen4 SoCs contain fuses indicating hardware support or hardware (e.g. tuning) parameters. Add a driver to access the state of the fuses. This supports two types of hardware fuse providers: 1. E-FUSE non-volatile memory accessible through the Pin Function Controller on R-Car V3U and S4-8, 2. E-FUSE non-volatile memory accessible through OTP_MEM on R-Car V4H and V4M. The state of the cells can be read using the NVMEM framework, either from kernel space (e.g. by the Renesas UFSHCD driver), or from userspace. Signed-off-by: Geert Uytterhoeven <[email protected]> Reviewed-by: Yoshihiro Shimoda <[email protected]> Acked-by: Arnd Bergmann <[email protected]> Signed-off-by: Srinivas Kandagatla <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 2aea0d1 commit 1530b92

File tree

4 files changed

+156
-0
lines changed

4 files changed

+156
-0
lines changed

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2930,6 +2930,7 @@ F: arch/arm/include/debug/renesas-scif.S
29302930
F: arch/arm/mach-shmobile/
29312931
F: arch/arm64/boot/dts/renesas/
29322932
F: arch/riscv/boot/dts/renesas/
2933+
F: drivers/nvmem/rcar-efuse.c
29332934
F: drivers/pmdomain/renesas/
29342935
F: drivers/soc/renesas/
29352936
F: include/linux/soc/renesas/

drivers/nvmem/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,17 @@ config NVMEM_RAVE_SP_EEPROM
246246
help
247247
Say y here to enable Rave SP EEPROM support.
248248

249+
config NVMEM_RCAR_EFUSE
250+
tristate "Renesas R-Car Gen4 E-FUSE support"
251+
depends on (ARCH_RENESAS && ARM64) || COMPILE_TEST
252+
depends on NVMEM
253+
help
254+
Enable support for reading the fuses in the E-FUSE or OTP
255+
non-volatile memory block on Renesas R-Car Gen4 SoCs.
256+
257+
This driver can also be built as a module. If so, the module
258+
will be called nvmem-rcar-efuse.
259+
249260
config NVMEM_RMEM
250261
tristate "Reserved Memory Based Driver Support"
251262
depends on HAS_IOMEM

drivers/nvmem/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ obj-$(CONFIG_NVMEM_QCOM_SEC_QFPROM) += nvmem_sec_qfprom.o
5252
nvmem_sec_qfprom-y := sec-qfprom.o
5353
obj-$(CONFIG_NVMEM_RAVE_SP_EEPROM) += nvmem-rave-sp-eeprom.o
5454
nvmem-rave-sp-eeprom-y := rave-sp-eeprom.o
55+
obj-$(CONFIG_NVMEM_RCAR_EFUSE) += nvmem-rcar-efuse.o
56+
nvmem-rcar-efuse-y := rcar-efuse.o
5557
obj-$(CONFIG_NVMEM_RMEM) += nvmem-rmem.o
5658
nvmem-rmem-y := rmem.o
5759
obj-$(CONFIG_NVMEM_ROCKCHIP_EFUSE) += nvmem_rockchip_efuse.o

drivers/nvmem/rcar-efuse.c

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Renesas R-Car E-FUSE/OTP Driver
4+
*
5+
* Copyright (C) 2024 Glider bv
6+
*/
7+
8+
#include <linux/device.h>
9+
#include <linux/export.h>
10+
#include <linux/io.h>
11+
#include <linux/mod_devicetable.h>
12+
#include <linux/nvmem-provider.h>
13+
#include <linux/platform_device.h>
14+
#include <linux/pm_runtime.h>
15+
#include <linux/property.h>
16+
17+
struct rcar_fuse {
18+
struct nvmem_keepout keepouts[2];
19+
struct nvmem_device *nvmem;
20+
struct device *dev;
21+
void __iomem *base;
22+
};
23+
24+
struct rcar_fuse_data {
25+
unsigned int bank; /* 0: PFC + E-FUSE, 1: OPT_MEM + E-FUSE */
26+
unsigned int start; /* inclusive */
27+
unsigned int end; /* exclusive */
28+
};
29+
30+
static int rcar_fuse_reg_read(void *priv, unsigned int offset, void *val,
31+
size_t bytes)
32+
{
33+
struct rcar_fuse *fuse = priv;
34+
int ret;
35+
36+
ret = pm_runtime_resume_and_get(fuse->dev);
37+
if (ret < 0)
38+
return ret;
39+
40+
__ioread32_copy(val, fuse->base + offset, bytes / 4);
41+
42+
pm_runtime_put(fuse->dev);
43+
44+
return 0;
45+
}
46+
47+
static int rcar_fuse_probe(struct platform_device *pdev)
48+
{
49+
struct device *dev = &pdev->dev;
50+
const struct rcar_fuse_data *data = device_get_match_data(dev);
51+
struct nvmem_config config = {
52+
.dev = dev,
53+
.name = "rcar-fuse",
54+
.id = NVMEM_DEVID_NONE,
55+
.owner = THIS_MODULE,
56+
.type = NVMEM_TYPE_OTP,
57+
.read_only = true,
58+
.root_only = true,
59+
.reg_read = rcar_fuse_reg_read,
60+
.word_size = 4,
61+
.stride = 4,
62+
};
63+
struct rcar_fuse *fuse;
64+
struct resource *res;
65+
int ret;
66+
67+
ret = devm_pm_runtime_enable(dev);
68+
if (ret < 0)
69+
return ret;
70+
71+
fuse = devm_kzalloc(dev, sizeof(*fuse), GFP_KERNEL);
72+
if (!fuse)
73+
return -ENOMEM;
74+
75+
fuse->base = devm_platform_get_and_ioremap_resource(pdev, data->bank,
76+
&res);
77+
if (IS_ERR(fuse->base))
78+
return PTR_ERR(fuse->base);
79+
80+
fuse->dev = dev;
81+
fuse->keepouts[0].start = 0;
82+
fuse->keepouts[0].end = data->start;
83+
fuse->keepouts[1].start = data->end;
84+
fuse->keepouts[1].end = resource_size(res);
85+
86+
config.keepout = fuse->keepouts;
87+
config.nkeepout = ARRAY_SIZE(fuse->keepouts);
88+
config.size = resource_size(res);
89+
config.priv = fuse;
90+
91+
fuse->nvmem = devm_nvmem_register(dev, &config);
92+
if (IS_ERR(fuse->nvmem))
93+
return dev_err_probe(dev, PTR_ERR(fuse->nvmem),
94+
"Failed to register NVMEM device\n");
95+
96+
return 0;
97+
}
98+
99+
static const struct rcar_fuse_data rcar_fuse_v3u = {
100+
.bank = 0,
101+
.start = 0x0c0,
102+
.end = 0x0e8,
103+
};
104+
105+
static const struct rcar_fuse_data rcar_fuse_s4 = {
106+
.bank = 0,
107+
.start = 0x0c0,
108+
.end = 0x14c,
109+
};
110+
111+
static const struct rcar_fuse_data rcar_fuse_v4h = {
112+
.bank = 1,
113+
.start = 0x100,
114+
.end = 0x1a0,
115+
};
116+
117+
static const struct rcar_fuse_data rcar_fuse_v4m = {
118+
.bank = 1,
119+
.start = 0x100,
120+
.end = 0x110,
121+
};
122+
123+
static const struct of_device_id rcar_fuse_match[] = {
124+
{ .compatible = "renesas,r8a779a0-efuse", .data = &rcar_fuse_v3u },
125+
{ .compatible = "renesas,r8a779f0-efuse", .data = &rcar_fuse_s4 },
126+
{ .compatible = "renesas,r8a779g0-otp", .data = &rcar_fuse_v4h },
127+
{ .compatible = "renesas,r8a779h0-otp", .data = &rcar_fuse_v4m },
128+
{ /* sentinel */ }
129+
};
130+
131+
static struct platform_driver rcar_fuse_driver = {
132+
.probe = rcar_fuse_probe,
133+
.driver = {
134+
.name = "rcar_fuse",
135+
.of_match_table = rcar_fuse_match,
136+
},
137+
};
138+
module_platform_driver(rcar_fuse_driver);
139+
140+
MODULE_DESCRIPTION("Renesas R-Car E-FUSE/OTP driver");
141+
MODULE_LICENSE("GPL");
142+
MODULE_AUTHOR("Geert Uytterhoeven");

0 commit comments

Comments
 (0)