1 /* 2 * Copyright (C) 2015 Toradex AG. 3 * 4 * Author: Sanchayan Maity <sanchayan.maity@toradex.com> 5 * 6 * Based on the barebox ocotp driver, 7 * Copyright (c) 2010 Baruch Siach <baruch@tkos.co.il> 8 * Orex Computed Radiography 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 and 12 * only version 2 as published by the Free Software Foundation. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 */ 19 20 #include <linux/clk.h> 21 #include <linux/delay.h> 22 #include <linux/device.h> 23 #include <linux/io.h> 24 #include <linux/module.h> 25 #include <linux/nvmem-provider.h> 26 #include <linux/of.h> 27 #include <linux/platform_device.h> 28 #include <linux/regmap.h> 29 #include <linux/slab.h> 30 31 /* OCOTP Register Offsets */ 32 #define OCOTP_CTRL_REG 0x00 33 #define OCOTP_CTRL_SET 0x04 34 #define OCOTP_CTRL_CLR 0x08 35 #define OCOTP_TIMING 0x10 36 #define OCOTP_DATA 0x20 37 #define OCOTP_READ_CTRL_REG 0x30 38 #define OCOTP_READ_FUSE_DATA 0x40 39 40 /* OCOTP Register bits and masks */ 41 #define OCOTP_CTRL_WR_UNLOCK 16 42 #define OCOTP_CTRL_WR_UNLOCK_KEY 0x3E77 43 #define OCOTP_CTRL_WR_UNLOCK_MASK GENMASK(31, 16) 44 #define OCOTP_CTRL_ADDR 0 45 #define OCOTP_CTRL_ADDR_MASK GENMASK(6, 0) 46 #define OCOTP_CTRL_RELOAD_SHADOWS BIT(10) 47 #define OCOTP_CTRL_ERR BIT(9) 48 #define OCOTP_CTRL_BUSY BIT(8) 49 50 #define OCOTP_TIMING_STROBE_READ 16 51 #define OCOTP_TIMING_STROBE_READ_MASK GENMASK(21, 16) 52 #define OCOTP_TIMING_RELAX 12 53 #define OCOTP_TIMING_RELAX_MASK GENMASK(15, 12) 54 #define OCOTP_TIMING_STROBE_PROG 0 55 #define OCOTP_TIMING_STROBE_PROG_MASK GENMASK(11, 0) 56 57 #define OCOTP_READ_CTRL_READ_FUSE 0x1 58 59 #define VF610_OCOTP_TIMEOUT 100000 60 61 #define BF(value, field) (((value) << field) & field##_MASK) 62 63 #define DEF_RELAX 20 64 65 static const int base_to_fuse_addr_mappings[][2] = { 66 {0x400, 0x00}, 67 {0x410, 0x01}, 68 {0x420, 0x02}, 69 {0x450, 0x05}, 70 {0x4F0, 0x0F}, 71 {0x600, 0x20}, 72 {0x610, 0x21}, 73 {0x620, 0x22}, 74 {0x630, 0x23}, 75 {0x640, 0x24}, 76 {0x650, 0x25}, 77 {0x660, 0x26}, 78 {0x670, 0x27}, 79 {0x6F0, 0x2F}, 80 {0x880, 0x38}, 81 {0x890, 0x39}, 82 {0x8A0, 0x3A}, 83 {0x8B0, 0x3B}, 84 {0x8C0, 0x3C}, 85 {0x8D0, 0x3D}, 86 {0x8E0, 0x3E}, 87 {0x8F0, 0x3F}, 88 {0xC80, 0x78}, 89 {0xC90, 0x79}, 90 {0xCA0, 0x7A}, 91 {0xCB0, 0x7B}, 92 {0xCC0, 0x7C}, 93 {0xCD0, 0x7D}, 94 {0xCE0, 0x7E}, 95 {0xCF0, 0x7F}, 96 }; 97 98 struct vf610_ocotp { 99 void __iomem *base; 100 struct clk *clk; 101 struct device *dev; 102 struct nvmem_device *nvmem; 103 int timing; 104 }; 105 106 static int vf610_ocotp_wait_busy(void __iomem *base) 107 { 108 int timeout = VF610_OCOTP_TIMEOUT; 109 110 while ((readl(base) & OCOTP_CTRL_BUSY) && --timeout) 111 udelay(10); 112 113 if (!timeout) { 114 writel(OCOTP_CTRL_ERR, base + OCOTP_CTRL_CLR); 115 return -ETIMEDOUT; 116 } 117 118 udelay(10); 119 120 return 0; 121 } 122 123 static int vf610_ocotp_calculate_timing(struct vf610_ocotp *ocotp_dev) 124 { 125 u32 clk_rate; 126 u32 relax, strobe_read, strobe_prog; 127 u32 timing; 128 129 clk_rate = clk_get_rate(ocotp_dev->clk); 130 131 /* Refer section OTP read/write timing parameters in TRM */ 132 relax = clk_rate / (1000000000 / DEF_RELAX) - 1; 133 strobe_prog = clk_rate / (1000000000 / 10000) + 2 * (DEF_RELAX + 1) - 1; 134 strobe_read = clk_rate / (1000000000 / 40) + 2 * (DEF_RELAX + 1) - 1; 135 136 timing = BF(relax, OCOTP_TIMING_RELAX); 137 timing |= BF(strobe_read, OCOTP_TIMING_STROBE_READ); 138 timing |= BF(strobe_prog, OCOTP_TIMING_STROBE_PROG); 139 140 return timing; 141 } 142 143 static int vf610_get_fuse_address(int base_addr_offset) 144 { 145 int i; 146 147 for (i = 0; i < ARRAY_SIZE(base_to_fuse_addr_mappings); i++) { 148 if (base_to_fuse_addr_mappings[i][0] == base_addr_offset) 149 return base_to_fuse_addr_mappings[i][1]; 150 } 151 152 return -EINVAL; 153 } 154 155 static int vf610_ocotp_write(void *context, const void *data, size_t count) 156 { 157 return 0; 158 } 159 160 static int vf610_ocotp_read(void *context, 161 const void *off, size_t reg_size, 162 void *val, size_t val_size) 163 { 164 struct vf610_ocotp *ocotp = context; 165 void __iomem *base = ocotp->base; 166 unsigned int offset = *(u32 *)off; 167 u32 reg, *buf = val; 168 int fuse_addr; 169 int ret; 170 171 while (val_size > 0) { 172 fuse_addr = vf610_get_fuse_address(offset); 173 if (fuse_addr > 0) { 174 writel(ocotp->timing, base + OCOTP_TIMING); 175 ret = vf610_ocotp_wait_busy(base + OCOTP_CTRL_REG); 176 if (ret) 177 return ret; 178 179 reg = readl(base + OCOTP_CTRL_REG); 180 reg &= ~OCOTP_CTRL_ADDR_MASK; 181 reg &= ~OCOTP_CTRL_WR_UNLOCK_MASK; 182 reg |= BF(fuse_addr, OCOTP_CTRL_ADDR); 183 writel(reg, base + OCOTP_CTRL_REG); 184 185 writel(OCOTP_READ_CTRL_READ_FUSE, 186 base + OCOTP_READ_CTRL_REG); 187 ret = vf610_ocotp_wait_busy(base + OCOTP_CTRL_REG); 188 if (ret) 189 return ret; 190 191 if (readl(base) & OCOTP_CTRL_ERR) { 192 dev_dbg(ocotp->dev, "Error reading from fuse address %x\n", 193 fuse_addr); 194 writel(OCOTP_CTRL_ERR, base + OCOTP_CTRL_CLR); 195 } 196 197 /* 198 * In case of error, we do not abort and expect to read 199 * 0xBADABADA as mentioned by the TRM. We just read this 200 * value and return. 201 */ 202 *buf = readl(base + OCOTP_READ_FUSE_DATA); 203 } else { 204 *buf = 0; 205 } 206 207 buf++; 208 val_size--; 209 offset += reg_size; 210 } 211 212 return 0; 213 } 214 215 static struct regmap_bus vf610_ocotp_bus = { 216 .read = vf610_ocotp_read, 217 .write = vf610_ocotp_write, 218 .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, 219 .val_format_endian_default = REGMAP_ENDIAN_NATIVE, 220 }; 221 222 static struct regmap_config ocotp_regmap_config = { 223 .reg_bits = 32, 224 .val_bits = 32, 225 .reg_stride = 4, 226 }; 227 228 static struct nvmem_config ocotp_config = { 229 .name = "ocotp", 230 .owner = THIS_MODULE, 231 }; 232 233 static const struct of_device_id ocotp_of_match[] = { 234 { .compatible = "fsl,vf610-ocotp", }, 235 {/* sentinel */}, 236 }; 237 MODULE_DEVICE_TABLE(of, ocotp_of_match); 238 239 static int vf610_ocotp_remove(struct platform_device *pdev) 240 { 241 struct vf610_ocotp *ocotp_dev = platform_get_drvdata(pdev); 242 243 return nvmem_unregister(ocotp_dev->nvmem); 244 } 245 246 static int vf610_ocotp_probe(struct platform_device *pdev) 247 { 248 struct device *dev = &pdev->dev; 249 struct resource *res; 250 struct regmap *regmap; 251 struct vf610_ocotp *ocotp_dev; 252 253 ocotp_dev = devm_kzalloc(&pdev->dev, 254 sizeof(struct vf610_ocotp), GFP_KERNEL); 255 if (!ocotp_dev) 256 return -ENOMEM; 257 258 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 259 ocotp_dev->base = devm_ioremap_resource(dev, res); 260 if (IS_ERR(ocotp_dev->base)) 261 return PTR_ERR(ocotp_dev->base); 262 263 ocotp_dev->clk = devm_clk_get(dev, NULL); 264 if (IS_ERR(ocotp_dev->clk)) { 265 dev_err(dev, "failed getting clock, err = %ld\n", 266 PTR_ERR(ocotp_dev->clk)); 267 return PTR_ERR(ocotp_dev->clk); 268 } 269 270 ocotp_regmap_config.max_register = resource_size(res); 271 regmap = devm_regmap_init(dev, 272 &vf610_ocotp_bus, ocotp_dev, &ocotp_regmap_config); 273 if (IS_ERR(regmap)) { 274 dev_err(dev, "regmap init failed\n"); 275 return PTR_ERR(regmap); 276 } 277 ocotp_config.dev = dev; 278 279 ocotp_dev->nvmem = nvmem_register(&ocotp_config); 280 if (IS_ERR(ocotp_dev->nvmem)) 281 return PTR_ERR(ocotp_dev->nvmem); 282 283 ocotp_dev->dev = dev; 284 platform_set_drvdata(pdev, ocotp_dev); 285 286 ocotp_dev->timing = vf610_ocotp_calculate_timing(ocotp_dev); 287 288 return 0; 289 } 290 291 static struct platform_driver vf610_ocotp_driver = { 292 .probe = vf610_ocotp_probe, 293 .remove = vf610_ocotp_remove, 294 .driver = { 295 .name = "vf610-ocotp", 296 .of_match_table = ocotp_of_match, 297 }, 298 }; 299 module_platform_driver(vf610_ocotp_driver); 300 MODULE_AUTHOR("Sanchayan Maity <sanchayan.maity@toradex.com>"); 301 MODULE_DESCRIPTION("Vybrid OCOTP driver"); 302 MODULE_LICENSE("GPL v2"); 303