0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/clk.h>
0010 #include <linux/delay.h>
0011 #include <linux/device.h>
0012 #include <linux/io.h>
0013 #include <linux/module.h>
0014 #include <linux/nvmem-provider.h>
0015 #include <linux/slab.h>
0016 #include <linux/of.h>
0017 #include <linux/of_platform.h>
0018 #include <linux/platform_device.h>
0019
0020 #define RK3288_A_SHIFT 6
0021 #define RK3288_A_MASK 0x3ff
0022 #define RK3288_PGENB BIT(3)
0023 #define RK3288_LOAD BIT(2)
0024 #define RK3288_STROBE BIT(1)
0025 #define RK3288_CSB BIT(0)
0026
0027 #define RK3328_SECURE_SIZES 96
0028 #define RK3328_INT_STATUS 0x0018
0029 #define RK3328_DOUT 0x0020
0030 #define RK3328_AUTO_CTRL 0x0024
0031 #define RK3328_INT_FINISH BIT(0)
0032 #define RK3328_AUTO_ENB BIT(0)
0033 #define RK3328_AUTO_RD BIT(1)
0034
0035 #define RK3399_A_SHIFT 16
0036 #define RK3399_A_MASK 0x3ff
0037 #define RK3399_NBYTES 4
0038 #define RK3399_STROBSFTSEL BIT(9)
0039 #define RK3399_RSB BIT(7)
0040 #define RK3399_PD BIT(5)
0041 #define RK3399_PGENB BIT(3)
0042 #define RK3399_LOAD BIT(2)
0043 #define RK3399_STROBE BIT(1)
0044 #define RK3399_CSB BIT(0)
0045
0046 #define REG_EFUSE_CTRL 0x0000
0047 #define REG_EFUSE_DOUT 0x0004
0048
0049 struct rockchip_efuse_chip {
0050 struct device *dev;
0051 void __iomem *base;
0052 struct clk *clk;
0053 };
0054
0055 static int rockchip_rk3288_efuse_read(void *context, unsigned int offset,
0056 void *val, size_t bytes)
0057 {
0058 struct rockchip_efuse_chip *efuse = context;
0059 u8 *buf = val;
0060 int ret;
0061
0062 ret = clk_prepare_enable(efuse->clk);
0063 if (ret < 0) {
0064 dev_err(efuse->dev, "failed to prepare/enable efuse clk\n");
0065 return ret;
0066 }
0067
0068 writel(RK3288_LOAD | RK3288_PGENB, efuse->base + REG_EFUSE_CTRL);
0069 udelay(1);
0070 while (bytes--) {
0071 writel(readl(efuse->base + REG_EFUSE_CTRL) &
0072 (~(RK3288_A_MASK << RK3288_A_SHIFT)),
0073 efuse->base + REG_EFUSE_CTRL);
0074 writel(readl(efuse->base + REG_EFUSE_CTRL) |
0075 ((offset++ & RK3288_A_MASK) << RK3288_A_SHIFT),
0076 efuse->base + REG_EFUSE_CTRL);
0077 udelay(1);
0078 writel(readl(efuse->base + REG_EFUSE_CTRL) |
0079 RK3288_STROBE, efuse->base + REG_EFUSE_CTRL);
0080 udelay(1);
0081 *buf++ = readb(efuse->base + REG_EFUSE_DOUT);
0082 writel(readl(efuse->base + REG_EFUSE_CTRL) &
0083 (~RK3288_STROBE), efuse->base + REG_EFUSE_CTRL);
0084 udelay(1);
0085 }
0086
0087
0088 writel(RK3288_PGENB | RK3288_CSB, efuse->base + REG_EFUSE_CTRL);
0089
0090 clk_disable_unprepare(efuse->clk);
0091
0092 return 0;
0093 }
0094
0095 static int rockchip_rk3328_efuse_read(void *context, unsigned int offset,
0096 void *val, size_t bytes)
0097 {
0098 struct rockchip_efuse_chip *efuse = context;
0099 unsigned int addr_start, addr_end, addr_offset, addr_len;
0100 u32 out_value, status;
0101 u8 *buf;
0102 int ret, i = 0;
0103
0104 ret = clk_prepare_enable(efuse->clk);
0105 if (ret < 0) {
0106 dev_err(efuse->dev, "failed to prepare/enable efuse clk\n");
0107 return ret;
0108 }
0109
0110
0111 offset += RK3328_SECURE_SIZES;
0112 addr_start = rounddown(offset, RK3399_NBYTES) / RK3399_NBYTES;
0113 addr_end = roundup(offset + bytes, RK3399_NBYTES) / RK3399_NBYTES;
0114 addr_offset = offset % RK3399_NBYTES;
0115 addr_len = addr_end - addr_start;
0116
0117 buf = kzalloc(array3_size(addr_len, RK3399_NBYTES, sizeof(*buf)),
0118 GFP_KERNEL);
0119 if (!buf) {
0120 ret = -ENOMEM;
0121 goto nomem;
0122 }
0123
0124 while (addr_len--) {
0125 writel(RK3328_AUTO_RD | RK3328_AUTO_ENB |
0126 ((addr_start++ & RK3399_A_MASK) << RK3399_A_SHIFT),
0127 efuse->base + RK3328_AUTO_CTRL);
0128 udelay(4);
0129 status = readl(efuse->base + RK3328_INT_STATUS);
0130 if (!(status & RK3328_INT_FINISH)) {
0131 ret = -EIO;
0132 goto err;
0133 }
0134 out_value = readl(efuse->base + RK3328_DOUT);
0135 writel(RK3328_INT_FINISH, efuse->base + RK3328_INT_STATUS);
0136
0137 memcpy(&buf[i], &out_value, RK3399_NBYTES);
0138 i += RK3399_NBYTES;
0139 }
0140
0141 memcpy(val, buf + addr_offset, bytes);
0142 err:
0143 kfree(buf);
0144 nomem:
0145 clk_disable_unprepare(efuse->clk);
0146
0147 return ret;
0148 }
0149
0150 static int rockchip_rk3399_efuse_read(void *context, unsigned int offset,
0151 void *val, size_t bytes)
0152 {
0153 struct rockchip_efuse_chip *efuse = context;
0154 unsigned int addr_start, addr_end, addr_offset, addr_len;
0155 u32 out_value;
0156 u8 *buf;
0157 int ret, i = 0;
0158
0159 ret = clk_prepare_enable(efuse->clk);
0160 if (ret < 0) {
0161 dev_err(efuse->dev, "failed to prepare/enable efuse clk\n");
0162 return ret;
0163 }
0164
0165 addr_start = rounddown(offset, RK3399_NBYTES) / RK3399_NBYTES;
0166 addr_end = roundup(offset + bytes, RK3399_NBYTES) / RK3399_NBYTES;
0167 addr_offset = offset % RK3399_NBYTES;
0168 addr_len = addr_end - addr_start;
0169
0170 buf = kzalloc(array3_size(addr_len, RK3399_NBYTES, sizeof(*buf)),
0171 GFP_KERNEL);
0172 if (!buf) {
0173 clk_disable_unprepare(efuse->clk);
0174 return -ENOMEM;
0175 }
0176
0177 writel(RK3399_LOAD | RK3399_PGENB | RK3399_STROBSFTSEL | RK3399_RSB,
0178 efuse->base + REG_EFUSE_CTRL);
0179 udelay(1);
0180 while (addr_len--) {
0181 writel(readl(efuse->base + REG_EFUSE_CTRL) | RK3399_STROBE |
0182 ((addr_start++ & RK3399_A_MASK) << RK3399_A_SHIFT),
0183 efuse->base + REG_EFUSE_CTRL);
0184 udelay(1);
0185 out_value = readl(efuse->base + REG_EFUSE_DOUT);
0186 writel(readl(efuse->base + REG_EFUSE_CTRL) & (~RK3399_STROBE),
0187 efuse->base + REG_EFUSE_CTRL);
0188 udelay(1);
0189
0190 memcpy(&buf[i], &out_value, RK3399_NBYTES);
0191 i += RK3399_NBYTES;
0192 }
0193
0194
0195 writel(RK3399_PD | RK3399_CSB, efuse->base + REG_EFUSE_CTRL);
0196
0197 memcpy(val, buf + addr_offset, bytes);
0198
0199 kfree(buf);
0200
0201 clk_disable_unprepare(efuse->clk);
0202
0203 return 0;
0204 }
0205
0206 static struct nvmem_config econfig = {
0207 .name = "rockchip-efuse",
0208 .stride = 1,
0209 .word_size = 1,
0210 .read_only = true,
0211 };
0212
0213 static const struct of_device_id rockchip_efuse_match[] = {
0214
0215 {
0216 .compatible = "rockchip,rockchip-efuse",
0217 .data = (void *)&rockchip_rk3288_efuse_read,
0218 },
0219 {
0220 .compatible = "rockchip,rk3066a-efuse",
0221 .data = (void *)&rockchip_rk3288_efuse_read,
0222 },
0223 {
0224 .compatible = "rockchip,rk3188-efuse",
0225 .data = (void *)&rockchip_rk3288_efuse_read,
0226 },
0227 {
0228 .compatible = "rockchip,rk3228-efuse",
0229 .data = (void *)&rockchip_rk3288_efuse_read,
0230 },
0231 {
0232 .compatible = "rockchip,rk3288-efuse",
0233 .data = (void *)&rockchip_rk3288_efuse_read,
0234 },
0235 {
0236 .compatible = "rockchip,rk3368-efuse",
0237 .data = (void *)&rockchip_rk3288_efuse_read,
0238 },
0239 {
0240 .compatible = "rockchip,rk3328-efuse",
0241 .data = (void *)&rockchip_rk3328_efuse_read,
0242 },
0243 {
0244 .compatible = "rockchip,rk3399-efuse",
0245 .data = (void *)&rockchip_rk3399_efuse_read,
0246 },
0247 { },
0248 };
0249 MODULE_DEVICE_TABLE(of, rockchip_efuse_match);
0250
0251 static int rockchip_efuse_probe(struct platform_device *pdev)
0252 {
0253 struct resource *res;
0254 struct nvmem_device *nvmem;
0255 struct rockchip_efuse_chip *efuse;
0256 const void *data;
0257 struct device *dev = &pdev->dev;
0258
0259 data = of_device_get_match_data(dev);
0260 if (!data) {
0261 dev_err(dev, "failed to get match data\n");
0262 return -EINVAL;
0263 }
0264
0265 efuse = devm_kzalloc(dev, sizeof(struct rockchip_efuse_chip),
0266 GFP_KERNEL);
0267 if (!efuse)
0268 return -ENOMEM;
0269
0270 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0271 efuse->base = devm_ioremap_resource(dev, res);
0272 if (IS_ERR(efuse->base))
0273 return PTR_ERR(efuse->base);
0274
0275 efuse->clk = devm_clk_get(dev, "pclk_efuse");
0276 if (IS_ERR(efuse->clk))
0277 return PTR_ERR(efuse->clk);
0278
0279 efuse->dev = dev;
0280 if (of_property_read_u32(dev->of_node, "rockchip,efuse-size",
0281 &econfig.size))
0282 econfig.size = resource_size(res);
0283 econfig.reg_read = data;
0284 econfig.priv = efuse;
0285 econfig.dev = efuse->dev;
0286 nvmem = devm_nvmem_register(dev, &econfig);
0287
0288 return PTR_ERR_OR_ZERO(nvmem);
0289 }
0290
0291 static struct platform_driver rockchip_efuse_driver = {
0292 .probe = rockchip_efuse_probe,
0293 .driver = {
0294 .name = "rockchip-efuse",
0295 .of_match_table = rockchip_efuse_match,
0296 },
0297 };
0298
0299 module_platform_driver(rockchip_efuse_driver);
0300 MODULE_DESCRIPTION("rockchip_efuse driver");
0301 MODULE_LICENSE("GPL v2");