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 static void wait_busy(struct ocotp_regs *regs, unsigned int delay_us) 61 { 62 while (readl(®s->ctrl) & BM_CTRL_BUSY) 63 udelay(delay_us); 64 } 65 66 static void clear_error(struct ocotp_regs *regs) 67 { 68 writel(BM_CTRL_ERROR, ®s->ctrl_clr); 69 } 70 71 static int prepare_access(struct ocotp_regs **regs, u32 bank, u32 word, 72 int assert, const char *caller) 73 { 74 *regs = (struct ocotp_regs *)OCOTP_BASE_ADDR; 75 76 if (bank >= ARRAY_SIZE((*regs)->bank) || 77 word >= ARRAY_SIZE((*regs)->bank[0].fuse_regs) >> 2 || 78 !assert) { 79 printf("mxc_ocotp %s(): Invalid argument\n", caller); 80 return -EINVAL; 81 } 82 83 enable_ocotp_clk(1); 84 85 wait_busy(*regs, 1); 86 clear_error(*regs); 87 88 return 0; 89 } 90 91 static int finish_access(struct ocotp_regs *regs, const char *caller) 92 { 93 u32 err; 94 95 err = !!(readl(®s->ctrl) & BM_CTRL_ERROR); 96 clear_error(regs); 97 98 if (err) { 99 printf("mxc_ocotp %s(): Access protect error\n", caller); 100 return -EIO; 101 } 102 103 return 0; 104 } 105 106 static int prepare_read(struct ocotp_regs **regs, u32 bank, u32 word, u32 *val, 107 const char *caller) 108 { 109 return prepare_access(regs, bank, word, val != NULL, caller); 110 } 111 112 int fuse_read(u32 bank, u32 word, u32 *val) 113 { 114 struct ocotp_regs *regs; 115 int ret; 116 117 ret = prepare_read(®s, bank, word, val, __func__); 118 if (ret) 119 return ret; 120 121 *val = readl(®s->bank[bank].fuse_regs[word << 2]); 122 123 return finish_access(regs, __func__); 124 } 125 126 #ifdef CONFIG_MX7 127 static void set_timing(struct ocotp_regs *regs) 128 { 129 u32 ipg_clk; 130 u32 fsource, prog; 131 u32 timing; 132 133 ipg_clk = mxc_get_clock(MXC_IPG_CLK); 134 135 fsource = DIV_ROUND_UP((ipg_clk / 1000) * BV_TIMING_FSOURCE_NS, 136 + 1000000) + 1; 137 prog = DIV_ROUND_CLOSEST(ipg_clk * BV_TIMING_PROG_US, 1000000) + 1; 138 139 timing = BF(fsource, TIMING_FSOURCE) | BF(prog, TIMING_PROG); 140 141 clrsetbits_le32(®s->timing, BM_TIMING_FSOURCE | BM_TIMING_PROG, 142 timing); 143 } 144 #else 145 static void set_timing(struct ocotp_regs *regs) 146 { 147 u32 ipg_clk; 148 u32 relax, strobe_read, strobe_prog; 149 u32 timing; 150 151 ipg_clk = mxc_get_clock(MXC_IPG_CLK); 152 153 relax = DIV_ROUND_UP(ipg_clk * BV_TIMING_RELAX_NS, 1000000000) - 1; 154 strobe_read = DIV_ROUND_UP(ipg_clk * BV_TIMING_STROBE_READ_NS, 155 1000000000) + 2 * (relax + 1) - 1; 156 strobe_prog = DIV_ROUND_CLOSEST(ipg_clk * BV_TIMING_STROBE_PROG_US, 157 1000000) + 2 * (relax + 1) - 1; 158 159 timing = BF(strobe_read, TIMING_STROBE_READ) | 160 BF(relax, TIMING_RELAX) | 161 BF(strobe_prog, TIMING_STROBE_PROG); 162 163 clrsetbits_le32(®s->timing, BM_TIMING_STROBE_READ | BM_TIMING_RELAX | 164 BM_TIMING_STROBE_PROG, timing); 165 } 166 #endif 167 168 static void setup_direct_access(struct ocotp_regs *regs, u32 bank, u32 word, 169 int write) 170 { 171 u32 wr_unlock = write ? BV_CTRL_WR_UNLOCK_KEY : 0; 172 #ifdef CONFIG_MX7 173 u32 addr = bank; 174 #else 175 u32 addr = bank << 3 | word; 176 #endif 177 178 set_timing(regs); 179 clrsetbits_le32(®s->ctrl, BM_CTRL_WR_UNLOCK | BM_CTRL_ADDR, 180 BF(wr_unlock, CTRL_WR_UNLOCK) | 181 BF(addr, CTRL_ADDR)); 182 } 183 184 int fuse_sense(u32 bank, u32 word, u32 *val) 185 { 186 struct ocotp_regs *regs; 187 int ret; 188 189 ret = prepare_read(®s, bank, word, val, __func__); 190 if (ret) 191 return ret; 192 193 setup_direct_access(regs, bank, word, false); 194 writel(BM_READ_CTRL_READ_FUSE, ®s->read_ctrl); 195 wait_busy(regs, 1); 196 #ifdef CONFIG_MX7 197 *val = readl((®s->read_fuse_data0) + (word << 2)); 198 #else 199 *val = readl(®s->read_fuse_data); 200 #endif 201 202 return finish_access(regs, __func__); 203 } 204 205 static int prepare_write(struct ocotp_regs **regs, u32 bank, u32 word, 206 const char *caller) 207 { 208 return prepare_access(regs, bank, word, true, caller); 209 } 210 211 int fuse_prog(u32 bank, u32 word, u32 val) 212 { 213 struct ocotp_regs *regs; 214 int ret; 215 216 ret = prepare_write(®s, bank, word, __func__); 217 if (ret) 218 return ret; 219 220 setup_direct_access(regs, bank, word, true); 221 #ifdef CONFIG_MX7 222 switch (word) { 223 case 0: 224 writel(0, ®s->data1); 225 writel(0, ®s->data2); 226 writel(0, ®s->data3); 227 writel(val, ®s->data0); 228 break; 229 case 1: 230 writel(val, ®s->data1); 231 writel(0, ®s->data2); 232 writel(0, ®s->data3); 233 writel(0, ®s->data0); 234 break; 235 case 2: 236 writel(0, ®s->data1); 237 writel(val, ®s->data2); 238 writel(0, ®s->data3); 239 writel(0, ®s->data0); 240 break; 241 case 3: 242 writel(0, ®s->data1); 243 writel(0, ®s->data2); 244 writel(val, ®s->data3); 245 writel(0, ®s->data0); 246 break; 247 } 248 wait_busy(regs, BV_TIMING_PROG_US); 249 #else 250 writel(val, ®s->data); 251 wait_busy(regs, BV_TIMING_STROBE_PROG_US); 252 #endif 253 udelay(WRITE_POSTAMBLE_US); 254 255 return finish_access(regs, __func__); 256 } 257 258 int fuse_override(u32 bank, u32 word, u32 val) 259 { 260 struct ocotp_regs *regs; 261 int ret; 262 263 ret = prepare_write(®s, bank, word, __func__); 264 if (ret) 265 return ret; 266 267 writel(val, ®s->bank[bank].fuse_regs[word << 2]); 268 269 return finish_access(regs, __func__); 270 } 271