0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/bitfield.h>
0009 #include <linux/bitops.h>
0010 #include <linux/clk.h>
0011 #include <linux/delay.h>
0012 #include <linux/io.h>
0013 #include <linux/iopoll.h>
0014 #include <linux/module.h>
0015 #include <linux/nvmem-provider.h>
0016 #include <linux/of.h>
0017 #include <linux/of_device.h>
0018 #include <linux/platform_device.h>
0019 #include <linux/sizes.h>
0020 #include <linux/slab.h>
0021
0022 #define MESON_MX_EFUSE_CNTL1 0x04
0023 #define MESON_MX_EFUSE_CNTL1_PD_ENABLE BIT(27)
0024 #define MESON_MX_EFUSE_CNTL1_AUTO_RD_BUSY BIT(26)
0025 #define MESON_MX_EFUSE_CNTL1_AUTO_RD_START BIT(25)
0026 #define MESON_MX_EFUSE_CNTL1_AUTO_RD_ENABLE BIT(24)
0027 #define MESON_MX_EFUSE_CNTL1_BYTE_WR_DATA GENMASK(23, 16)
0028 #define MESON_MX_EFUSE_CNTL1_AUTO_WR_BUSY BIT(14)
0029 #define MESON_MX_EFUSE_CNTL1_AUTO_WR_START BIT(13)
0030 #define MESON_MX_EFUSE_CNTL1_AUTO_WR_ENABLE BIT(12)
0031 #define MESON_MX_EFUSE_CNTL1_BYTE_ADDR_SET BIT(11)
0032 #define MESON_MX_EFUSE_CNTL1_BYTE_ADDR_MASK GENMASK(10, 0)
0033
0034 #define MESON_MX_EFUSE_CNTL2 0x08
0035
0036 #define MESON_MX_EFUSE_CNTL4 0x10
0037 #define MESON_MX_EFUSE_CNTL4_ENCRYPT_ENABLE BIT(10)
0038
0039 struct meson_mx_efuse_platform_data {
0040 const char *name;
0041 unsigned int word_size;
0042 };
0043
0044 struct meson_mx_efuse {
0045 void __iomem *base;
0046 struct clk *core_clk;
0047 struct nvmem_device *nvmem;
0048 struct nvmem_config config;
0049 };
0050
0051 static void meson_mx_efuse_mask_bits(struct meson_mx_efuse *efuse, u32 reg,
0052 u32 mask, u32 set)
0053 {
0054 u32 data;
0055
0056 data = readl(efuse->base + reg);
0057 data &= ~mask;
0058 data |= (set & mask);
0059
0060 writel(data, efuse->base + reg);
0061 }
0062
0063 static int meson_mx_efuse_hw_enable(struct meson_mx_efuse *efuse)
0064 {
0065 int err;
0066
0067 err = clk_prepare_enable(efuse->core_clk);
0068 if (err)
0069 return err;
0070
0071
0072 meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL1,
0073 MESON_MX_EFUSE_CNTL1_PD_ENABLE, 0);
0074
0075 meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL4,
0076 MESON_MX_EFUSE_CNTL4_ENCRYPT_ENABLE, 0);
0077
0078 return 0;
0079 }
0080
0081 static void meson_mx_efuse_hw_disable(struct meson_mx_efuse *efuse)
0082 {
0083 meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL1,
0084 MESON_MX_EFUSE_CNTL1_PD_ENABLE,
0085 MESON_MX_EFUSE_CNTL1_PD_ENABLE);
0086
0087 clk_disable_unprepare(efuse->core_clk);
0088 }
0089
0090 static int meson_mx_efuse_read_addr(struct meson_mx_efuse *efuse,
0091 unsigned int addr, u32 *value)
0092 {
0093 int err;
0094 u32 regval;
0095
0096
0097 regval = FIELD_PREP(MESON_MX_EFUSE_CNTL1_BYTE_ADDR_MASK, addr);
0098 meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL1,
0099 MESON_MX_EFUSE_CNTL1_BYTE_ADDR_MASK, regval);
0100
0101
0102 meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL1,
0103 MESON_MX_EFUSE_CNTL1_BYTE_ADDR_SET,
0104 MESON_MX_EFUSE_CNTL1_BYTE_ADDR_SET);
0105 meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL1,
0106 MESON_MX_EFUSE_CNTL1_BYTE_ADDR_SET, 0);
0107
0108
0109 meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL1,
0110 MESON_MX_EFUSE_CNTL1_AUTO_RD_START,
0111 MESON_MX_EFUSE_CNTL1_AUTO_RD_START);
0112 meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL1,
0113 MESON_MX_EFUSE_CNTL1_AUTO_RD_START, 0);
0114
0115
0116
0117
0118
0119 readl(efuse->base + MESON_MX_EFUSE_CNTL1);
0120
0121 err = readl_poll_timeout_atomic(efuse->base + MESON_MX_EFUSE_CNTL1,
0122 regval,
0123 (!(regval & MESON_MX_EFUSE_CNTL1_AUTO_RD_BUSY)),
0124 1, 1000);
0125 if (err) {
0126 dev_err(efuse->config.dev,
0127 "Timeout while reading efuse address %u\n", addr);
0128 return err;
0129 }
0130
0131 *value = readl(efuse->base + MESON_MX_EFUSE_CNTL2);
0132
0133 return 0;
0134 }
0135
0136 static int meson_mx_efuse_read(void *context, unsigned int offset,
0137 void *buf, size_t bytes)
0138 {
0139 struct meson_mx_efuse *efuse = context;
0140 u32 tmp;
0141 int err, i, addr;
0142
0143 err = meson_mx_efuse_hw_enable(efuse);
0144 if (err)
0145 return err;
0146
0147 meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL1,
0148 MESON_MX_EFUSE_CNTL1_AUTO_RD_ENABLE,
0149 MESON_MX_EFUSE_CNTL1_AUTO_RD_ENABLE);
0150
0151 for (i = 0; i < bytes; i += efuse->config.word_size) {
0152 addr = (offset + i) / efuse->config.word_size;
0153
0154 err = meson_mx_efuse_read_addr(efuse, addr, &tmp);
0155 if (err)
0156 break;
0157
0158 memcpy(buf + i, &tmp,
0159 min_t(size_t, bytes - i, efuse->config.word_size));
0160 }
0161
0162 meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL1,
0163 MESON_MX_EFUSE_CNTL1_AUTO_RD_ENABLE, 0);
0164
0165 meson_mx_efuse_hw_disable(efuse);
0166
0167 return err;
0168 }
0169
0170 static const struct meson_mx_efuse_platform_data meson6_efuse_data = {
0171 .name = "meson6-efuse",
0172 .word_size = 1,
0173 };
0174
0175 static const struct meson_mx_efuse_platform_data meson8_efuse_data = {
0176 .name = "meson8-efuse",
0177 .word_size = 4,
0178 };
0179
0180 static const struct meson_mx_efuse_platform_data meson8b_efuse_data = {
0181 .name = "meson8b-efuse",
0182 .word_size = 4,
0183 };
0184
0185 static const struct of_device_id meson_mx_efuse_match[] = {
0186 { .compatible = "amlogic,meson6-efuse", .data = &meson6_efuse_data },
0187 { .compatible = "amlogic,meson8-efuse", .data = &meson8_efuse_data },
0188 { .compatible = "amlogic,meson8b-efuse", .data = &meson8b_efuse_data },
0189 { },
0190 };
0191 MODULE_DEVICE_TABLE(of, meson_mx_efuse_match);
0192
0193 static int meson_mx_efuse_probe(struct platform_device *pdev)
0194 {
0195 const struct meson_mx_efuse_platform_data *drvdata;
0196 struct meson_mx_efuse *efuse;
0197 struct resource *res;
0198
0199 drvdata = of_device_get_match_data(&pdev->dev);
0200 if (!drvdata)
0201 return -EINVAL;
0202
0203 efuse = devm_kzalloc(&pdev->dev, sizeof(*efuse), GFP_KERNEL);
0204 if (!efuse)
0205 return -ENOMEM;
0206
0207 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0208 efuse->base = devm_ioremap_resource(&pdev->dev, res);
0209 if (IS_ERR(efuse->base))
0210 return PTR_ERR(efuse->base);
0211
0212 efuse->config.name = drvdata->name;
0213 efuse->config.owner = THIS_MODULE;
0214 efuse->config.dev = &pdev->dev;
0215 efuse->config.priv = efuse;
0216 efuse->config.stride = drvdata->word_size;
0217 efuse->config.word_size = drvdata->word_size;
0218 efuse->config.size = SZ_512;
0219 efuse->config.read_only = true;
0220 efuse->config.reg_read = meson_mx_efuse_read;
0221
0222 efuse->core_clk = devm_clk_get(&pdev->dev, "core");
0223 if (IS_ERR(efuse->core_clk)) {
0224 dev_err(&pdev->dev, "Failed to get core clock\n");
0225 return PTR_ERR(efuse->core_clk);
0226 }
0227
0228 efuse->nvmem = devm_nvmem_register(&pdev->dev, &efuse->config);
0229
0230 return PTR_ERR_OR_ZERO(efuse->nvmem);
0231 }
0232
0233 static struct platform_driver meson_mx_efuse_driver = {
0234 .probe = meson_mx_efuse_probe,
0235 .driver = {
0236 .name = "meson-mx-efuse",
0237 .of_match_table = meson_mx_efuse_match,
0238 },
0239 };
0240
0241 module_platform_driver(meson_mx_efuse_driver);
0242
0243 MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
0244 MODULE_DESCRIPTION("Amlogic Meson MX eFuse NVMEM driver");
0245 MODULE_LICENSE("GPL v2");