1 /* 2 * (C) Copyright 2013 ADVANSEE 3 * Benoît Thébaudeau <benoit.thebaudeau@advansee.com> 4 * 5 * Based on Dirk Behme's 6 * https://github.com/dirkbehme/u-boot-imx6/blob/28b17e9/drivers/misc/imx_otp.c, 7 * which is based on Freescale's 8 * http://git.freescale.com/git/cgit.cgi/imx/uboot-imx.git/tree/drivers/misc/imx_otp.c?h=imx_v2009.08_1.1.0&id=9aa74e6, 9 * which is: 10 * Copyright (C) 2011 Freescale Semiconductor, Inc. 11 * 12 * SPDX-License-Identifier: GPL-2.0+ 13 */ 14 15 #include <common.h> 16 #include <fuse.h> 17 #include <asm/errno.h> 18 #include <asm/io.h> 19 #include <asm/arch/clock.h> 20 #include <asm/arch/imx-regs.h> 21 22 #define BO_CTRL_WR_UNLOCK 16 23 #define BM_CTRL_WR_UNLOCK 0xffff0000 24 #define BV_CTRL_WR_UNLOCK_KEY 0x3e77 25 #define BM_CTRL_ERROR 0x00000200 26 #define BM_CTRL_BUSY 0x00000100 27 #define BO_CTRL_ADDR 0 28 #ifdef CONFIG_MX7 29 #define BM_CTRL_ADDR 0x0000000f 30 #define BM_CTRL_RELOAD 0x00000400 31 #else 32 #define BM_CTRL_ADDR 0x0000007f 33 #endif 34 35 #ifdef CONFIG_MX7 36 #define BO_TIMING_FSOURCE 12 37 #define BM_TIMING_FSOURCE 0x0007f000 38 #define BV_TIMING_FSOURCE_NS 1001 39 #define BO_TIMING_PROG 0 40 #define BM_TIMING_PROG 0x00000fff 41 #define BV_TIMING_PROG_US 10 42 #else 43 #define BO_TIMING_STROBE_READ 16 44 #define BM_TIMING_STROBE_READ 0x003f0000 45 #define BV_TIMING_STROBE_READ_NS 37 46 #define BO_TIMING_RELAX 12 47 #define BM_TIMING_RELAX 0x0000f000 48 #define BV_TIMING_RELAX_NS 17 49 #define BO_TIMING_STROBE_PROG 0 50 #define BM_TIMING_STROBE_PROG 0x00000fff 51 #define BV_TIMING_STROBE_PROG_US 10 52 #endif 53 54 #define BM_READ_CTRL_READ_FUSE 0x00000001 55 56 #define BF(value, field) (((value) << BO_##field) & BM_##field) 57 58 #define WRITE_POSTAMBLE_US 2 59 60 #if defined(CONFIG_MX6) || defined(CONFIG_VF610) 61 #define FUSE_BANK_SIZE 0x80 62 #ifdef CONFIG_MX6SL 63 #define FUSE_BANKS 8 64 #else 65 #define FUSE_BANKS 16 66 #endif 67 #elif defined CONFIG_MX7 68 #define FUSE_BANK_SIZE 0x40 69 #define FUSE_BANKS 16 70 #else 71 #error "Unsupported architecture\n" 72 #endif 73 74 #if defined(CONFIG_MX6) 75 #include <asm/arch/sys_proto.h> 76 77 /* 78 * There is a hole in shadow registers address map of size 0x100 79 * between bank 5 and bank 6 on iMX6QP, iMX6DQ, iMX6SDL, iMX6SX and iMX6UL. 80 * Bank 5 ends at 0x6F0 and Bank 6 starts at 0x800. When reading the fuses, 81 * we should account for this hole in address space. 82 * 83 * Similar hole exists between bank 14 and bank 15 of size 84 * 0x80 on iMX6QP, iMX6DQ, iMX6SDL and iMX6SX. 85 * Note: iMX6SL has only 0-7 banks and there is no hole. 86 * Note: iMX6UL doesn't have this one. 87 * 88 * This function is to covert user input to physical bank index. 89 * Only needed when read fuse, because we use register offset, so 90 * need to calculate real register offset. 91 * When write, no need to consider hole, always use the bank/word 92 * index from fuse map. 93 */ 94 u32 fuse_bank_physical(int index) 95 { 96 u32 phy_index; 97 98 if (is_cpu_type(MXC_CPU_MX6SL)) { 99 phy_index = index; 100 } else if (is_cpu_type(MXC_CPU_MX6UL)) { 101 if (index >= 6) 102 phy_index = fuse_bank_physical(5) + (index - 6) + 3; 103 else 104 phy_index = index; 105 } else { 106 if (index >= 15) 107 phy_index = fuse_bank_physical(14) + (index - 15) + 2; 108 else if (index >= 6) 109 phy_index = fuse_bank_physical(5) + (index - 6) + 3; 110 else 111 phy_index = index; 112 } 113 return phy_index; 114 } 115 #else 116 u32 fuse_bank_physical(int index) 117 { 118 return index; 119 } 120 #endif 121 122 static void wait_busy(struct ocotp_regs *regs, unsigned int delay_us) 123 { 124 while (readl(®s->ctrl) & BM_CTRL_BUSY) 125 udelay(delay_us); 126 } 127 128 static void clear_error(struct ocotp_regs *regs) 129 { 130 writel(BM_CTRL_ERROR, ®s->ctrl_clr); 131 } 132 133 static int prepare_access(struct ocotp_regs **regs, u32 bank, u32 word, 134 int assert, const char *caller) 135 { 136 *regs = (struct ocotp_regs *)OCOTP_BASE_ADDR; 137 138 if (bank >= FUSE_BANKS || 139 word >= ARRAY_SIZE((*regs)->bank[0].fuse_regs) >> 2 || 140 !assert) { 141 printf("mxc_ocotp %s(): Invalid argument\n", caller); 142 return -EINVAL; 143 } 144 145 enable_ocotp_clk(1); 146 147 wait_busy(*regs, 1); 148 clear_error(*regs); 149 150 return 0; 151 } 152 153 static int finish_access(struct ocotp_regs *regs, const char *caller) 154 { 155 u32 err; 156 157 err = !!(readl(®s->ctrl) & BM_CTRL_ERROR); 158 clear_error(regs); 159 160 if (err) { 161 printf("mxc_ocotp %s(): Access protect error\n", caller); 162 return -EIO; 163 } 164 165 return 0; 166 } 167 168 static int prepare_read(struct ocotp_regs **regs, u32 bank, u32 word, u32 *val, 169 const char *caller) 170 { 171 return prepare_access(regs, bank, word, val != NULL, caller); 172 } 173 174 int fuse_read(u32 bank, u32 word, u32 *val) 175 { 176 struct ocotp_regs *regs; 177 int ret; 178 u32 phy_bank; 179 180 ret = prepare_read(®s, bank, word, val, __func__); 181 if (ret) 182 return ret; 183 184 phy_bank = fuse_bank_physical(bank); 185 186 *val = readl(®s->bank[phy_bank].fuse_regs[word << 2]); 187 188 return finish_access(regs, __func__); 189 } 190 191 #ifdef CONFIG_MX7 192 static void set_timing(struct ocotp_regs *regs) 193 { 194 u32 ipg_clk; 195 u32 fsource, prog; 196 u32 timing; 197 198 ipg_clk = mxc_get_clock(MXC_IPG_CLK); 199 200 fsource = DIV_ROUND_UP((ipg_clk / 1000) * BV_TIMING_FSOURCE_NS, 201 + 1000000) + 1; 202 prog = DIV_ROUND_CLOSEST(ipg_clk * BV_TIMING_PROG_US, 1000000) + 1; 203 204 timing = BF(fsource, TIMING_FSOURCE) | BF(prog, TIMING_PROG); 205 206 clrsetbits_le32(®s->timing, BM_TIMING_FSOURCE | BM_TIMING_PROG, 207 timing); 208 } 209 #else 210 static void set_timing(struct ocotp_regs *regs) 211 { 212 u32 ipg_clk; 213 u32 relax, strobe_read, strobe_prog; 214 u32 timing; 215 216 ipg_clk = mxc_get_clock(MXC_IPG_CLK); 217 218 relax = DIV_ROUND_UP(ipg_clk * BV_TIMING_RELAX_NS, 1000000000) - 1; 219 strobe_read = DIV_ROUND_UP(ipg_clk * BV_TIMING_STROBE_READ_NS, 220 1000000000) + 2 * (relax + 1) - 1; 221 strobe_prog = DIV_ROUND_CLOSEST(ipg_clk * BV_TIMING_STROBE_PROG_US, 222 1000000) + 2 * (relax + 1) - 1; 223 224 timing = BF(strobe_read, TIMING_STROBE_READ) | 225 BF(relax, TIMING_RELAX) | 226 BF(strobe_prog, TIMING_STROBE_PROG); 227 228 clrsetbits_le32(®s->timing, BM_TIMING_STROBE_READ | BM_TIMING_RELAX | 229 BM_TIMING_STROBE_PROG, timing); 230 } 231 #endif 232 233 static void setup_direct_access(struct ocotp_regs *regs, u32 bank, u32 word, 234 int write) 235 { 236 u32 wr_unlock = write ? BV_CTRL_WR_UNLOCK_KEY : 0; 237 #ifdef CONFIG_MX7 238 u32 addr = bank; 239 #else 240 u32 addr = bank << 3 | word; 241 #endif 242 243 set_timing(regs); 244 clrsetbits_le32(®s->ctrl, BM_CTRL_WR_UNLOCK | BM_CTRL_ADDR, 245 BF(wr_unlock, CTRL_WR_UNLOCK) | 246 BF(addr, CTRL_ADDR)); 247 } 248 249 int fuse_sense(u32 bank, u32 word, u32 *val) 250 { 251 struct ocotp_regs *regs; 252 int ret; 253 254 ret = prepare_read(®s, bank, word, val, __func__); 255 if (ret) 256 return ret; 257 258 setup_direct_access(regs, bank, word, false); 259 writel(BM_READ_CTRL_READ_FUSE, ®s->read_ctrl); 260 wait_busy(regs, 1); 261 #ifdef CONFIG_MX7 262 *val = readl((®s->read_fuse_data0) + (word << 2)); 263 #else 264 *val = readl(®s->read_fuse_data); 265 #endif 266 267 return finish_access(regs, __func__); 268 } 269 270 static int prepare_write(struct ocotp_regs **regs, u32 bank, u32 word, 271 const char *caller) 272 { 273 return prepare_access(regs, bank, word, true, caller); 274 } 275 276 int fuse_prog(u32 bank, u32 word, u32 val) 277 { 278 struct ocotp_regs *regs; 279 int ret; 280 281 ret = prepare_write(®s, bank, word, __func__); 282 if (ret) 283 return ret; 284 285 setup_direct_access(regs, bank, word, true); 286 #ifdef CONFIG_MX7 287 switch (word) { 288 case 0: 289 writel(0, ®s->data1); 290 writel(0, ®s->data2); 291 writel(0, ®s->data3); 292 writel(val, ®s->data0); 293 break; 294 case 1: 295 writel(val, ®s->data1); 296 writel(0, ®s->data2); 297 writel(0, ®s->data3); 298 writel(0, ®s->data0); 299 break; 300 case 2: 301 writel(0, ®s->data1); 302 writel(val, ®s->data2); 303 writel(0, ®s->data3); 304 writel(0, ®s->data0); 305 break; 306 case 3: 307 writel(0, ®s->data1); 308 writel(0, ®s->data2); 309 writel(val, ®s->data3); 310 writel(0, ®s->data0); 311 break; 312 } 313 wait_busy(regs, BV_TIMING_PROG_US); 314 #else 315 writel(val, ®s->data); 316 wait_busy(regs, BV_TIMING_STROBE_PROG_US); 317 #endif 318 udelay(WRITE_POSTAMBLE_US); 319 320 return finish_access(regs, __func__); 321 } 322 323 int fuse_override(u32 bank, u32 word, u32 val) 324 { 325 struct ocotp_regs *regs; 326 int ret; 327 u32 phy_bank; 328 329 ret = prepare_write(®s, bank, word, __func__); 330 if (ret) 331 return ret; 332 333 phy_bank = fuse_bank_physical(bank); 334 335 writel(val, ®s->bank[phy_bank].fuse_regs[word << 2]); 336 337 return finish_access(regs, __func__); 338 } 339