1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2015-2016 Reinhard Pfau <reinhard.pfau@gdsys.cc> 4 */ 5 6#include <config.h> 7#include <common.h> 8#include <errno.h> 9#include <asm/io.h> 10#include <asm/arch/cpu.h> 11#include <asm/arch/efuse.h> 12#include <asm/arch/soc.h> 13#include <asm/gpio.h> 14#include <linux/bitops.h> 15#include <linux/delay.h> 16#include <linux/mbus.h> 17 18#if defined(CONFIG_MVEBU_EFUSE_FAKE) 19#define DRY_RUN 20#else 21#undef DRY_RUN 22#endif 23 24#define MBUS_EFUSE_BASE 0xF6000000 25#define MBUS_EFUSE_SIZE BIT(20) 26 27#define MVEBU_EFUSE_CONTROL (MVEBU_REGISTER(0xE4008)) 28 29enum { 30 MVEBU_EFUSE_CTRL_PROGRAM_ENABLE = (1 << 31), 31 MVEBU_EFUSE_LD1_SELECT = (1 << 6), 32}; 33 34struct mvebu_hd_efuse { 35 u32 bits_31_0; 36 u32 bits_63_32; 37 u32 bit64; 38 u32 reserved0; 39}; 40 41#ifndef DRY_RUN 42static struct mvebu_hd_efuse *efuses = 43 (struct mvebu_hd_efuse *)(MBUS_EFUSE_BASE + 0xF9000); 44static u32 *ld_efuses = (void *)MBUS_EFUSE_BASE + 0xF8F00; 45#else 46static struct mvebu_hd_efuse efuses[EFUSE_LINE_MAX + 1]; 47static u32 ld_efuses[EFUSE_LD_WORDS]; 48#endif 49 50static int efuse_initialised; 51 52static struct mvebu_hd_efuse *get_efuse_line(int nr) 53{ 54 if (nr < 0 || nr > 63 || !efuse_initialised) 55 return NULL; 56 57 return efuses + nr; 58} 59 60#ifndef DRY_RUN 61static int vhv_gpio; 62#endif 63 64static int enable_efuse_program(void) 65{ 66#ifndef DRY_RUN 67 if (CONFIG_MVEBU_EFUSE_VHV_GPIO[0]) { 68 if (gpio_lookup_name(CONFIG_MVEBU_EFUSE_VHV_GPIO, NULL, NULL, &vhv_gpio)) { 69 printf("Error: VHV gpio lookup failed\n"); 70 return -EOPNOTSUPP; 71 } 72 if (gpio_request(vhv_gpio, CONFIG_MVEBU_EFUSE_VHV_GPIO)) { 73 printf("Error: VHV gpio request failed\n"); 74 return -EOPNOTSUPP; 75 } 76 if (gpio_direction_output(vhv_gpio, 77 IS_ENABLED(CONFIG_MVEBU_EFUSE_VHV_GPIO_ACTIVE_LOW) ? 0 : 1)) { 78 printf("Error: VHV gpio enable failed\n"); 79 return -EINVAL; 80 } 81 mdelay(5); /* Wait for the VHV power to stabilize */ 82 } 83 84 setbits_le32(MVEBU_EFUSE_CONTROL, MVEBU_EFUSE_CTRL_PROGRAM_ENABLE); 85#endif 86 87 return 0; 88} 89 90static void disable_efuse_program(void) 91{ 92#ifndef DRY_RUN 93 clrbits_le32(MVEBU_EFUSE_CONTROL, MVEBU_EFUSE_CTRL_PROGRAM_ENABLE); 94 95 if (CONFIG_MVEBU_EFUSE_VHV_GPIO[0]) { 96 if (gpio_direction_output(vhv_gpio, 97 IS_ENABLED(CONFIG_MVEBU_EFUSE_VHV_GPIO_ACTIVE_LOW) ? 1 : 0)) 98 printf("Error: VHV gpio disable failed\n"); 99 gpio_free(vhv_gpio); 100 vhv_gpio = 0; 101 } 102#endif 103} 104 105static int do_prog_efuse(struct mvebu_hd_efuse *efuse, 106 struct efuse_val *new_val, u32 mask0, u32 mask1) 107{ 108 struct efuse_val val; 109 110 val.dwords.d[0] = readl(&efuse->bits_31_0); 111 val.dwords.d[1] = readl(&efuse->bits_63_32); 112 val.lock = readl(&efuse->bit64); 113 114 if (val.lock & 1) 115 return -EPERM; 116 117 val.dwords.d[0] |= (new_val->dwords.d[0] & mask0); 118 val.dwords.d[1] |= (new_val->dwords.d[1] & mask1); 119 val.lock |= new_val->lock; 120 121 writel(val.dwords.d[0], &efuse->bits_31_0); 122 mdelay(1); 123 writel(val.dwords.d[1], &efuse->bits_63_32); 124 mdelay(1); 125 writel(val.lock, &efuse->bit64); 126 mdelay(5); 127 128 return 0; 129} 130 131static int prog_efuse(int nr, struct efuse_val *new_val, u32 mask0, u32 mask1) 132{ 133 struct mvebu_hd_efuse *efuse; 134 int res = 0; 135 136 res = mvebu_efuse_init_hw(); 137 if (res) 138 return res; 139 140 efuse = get_efuse_line(nr); 141 if (!efuse) 142 return -ENODEV; 143 144 if (!new_val) 145 return -EINVAL; 146 147 /* only write a fuse line with lock bit */ 148 if (!new_val->lock) 149 return -EINVAL; 150 151 /* according to specs ECC protection bits must be 0 on write */ 152 if (new_val->bytes.d[7] & 0xFE) 153 return -EINVAL; 154 155 if (!new_val->dwords.d[0] && !new_val->dwords.d[1] && (mask0 | mask1)) 156 return 0; 157 158 res = enable_efuse_program(); 159 if (res) 160 return res; 161 162 res = do_prog_efuse(efuse, new_val, mask0, mask1); 163 164 disable_efuse_program(); 165 166 return res; 167} 168 169int mvebu_prog_ld_efuse(int ld1, u32 word, u32 val) 170{ 171 int i, res; 172 u32 line[EFUSE_LD_WORDS]; 173 174 res = mvebu_efuse_init_hw(); 175 if (res) 176 return res; 177 178 mvebu_read_ld_efuse(ld1, line); 179 180 /* check if lock bit is already programmed */ 181 if (line[EFUSE_LD_WORDS - 1]) 182 return -EPERM; 183 184 /* check if word is valid */ 185 if (word >= EFUSE_LD_WORDS) 186 return -EINVAL; 187 188 /* check if there is some bit for programming */ 189 if (val == (line[word] & val)) 190 return 0; 191 192 res = enable_efuse_program(); 193 if (res) 194 return res; 195 196 mvebu_read_ld_efuse(ld1, line); 197 line[word] |= val; 198 199 for (i = 0; i < EFUSE_LD_WORDS; i++) { 200 writel(line[i], ld_efuses + i); 201 mdelay(1); 202 } 203 204 mdelay(5); 205 206 disable_efuse_program(); 207 208 return 0; 209} 210 211int mvebu_efuse_init_hw(void) 212{ 213 int ret; 214 215 if (efuse_initialised) 216 return 0; 217 218 ret = mvebu_mbus_add_window_by_id( 219 CPU_TARGET_SATA23_DFX, 0xA, MBUS_EFUSE_BASE, MBUS_EFUSE_SIZE); 220 221 if (ret) 222 return ret; 223 224 efuse_initialised = 1; 225 226 return 0; 227} 228 229int mvebu_read_efuse(int nr, struct efuse_val *val) 230{ 231 struct mvebu_hd_efuse *efuse; 232 int res; 233 234 res = mvebu_efuse_init_hw(); 235 if (res) 236 return res; 237 238 efuse = get_efuse_line(nr); 239 if (!efuse) 240 return -ENODEV; 241 242 if (!val) 243 return -EINVAL; 244 245 val->dwords.d[0] = readl(&efuse->bits_31_0); 246 val->dwords.d[1] = readl(&efuse->bits_63_32); 247 val->lock = readl(&efuse->bit64); 248 return 0; 249} 250 251void mvebu_read_ld_efuse(int ld1, u32 *line) 252{ 253 int i; 254 255#ifndef DRY_RUN 256 if (ld1) 257 setbits_le32(MVEBU_EFUSE_CONTROL, MVEBU_EFUSE_LD1_SELECT); 258 else 259 clrbits_le32(MVEBU_EFUSE_CONTROL, MVEBU_EFUSE_LD1_SELECT); 260#endif 261 262 for (i = 0; i < EFUSE_LD_WORDS; i++) 263 line[i] = readl(ld_efuses + i); 264} 265 266int mvebu_write_efuse(int nr, struct efuse_val *val) 267{ 268 return prog_efuse(nr, val, ~0, ~0); 269} 270 271int mvebu_lock_efuse(int nr) 272{ 273 struct efuse_val val = { 274 .lock = 1, 275 }; 276 277 return prog_efuse(nr, &val, 0, 0); 278} 279 280/* 281 * wrapper funcs providing the fuse API 282 * 283 * we use the following mapping: 284 * "bank" -> eFuse line 285 * "word" -> 0: bits 0-31 286 * 1: bits 32-63 287 * 2: bit 64 (lock) 288 */ 289 290static struct efuse_val prog_val; 291static int valid_prog_words; 292 293int fuse_read(u32 bank, u32 word, u32 *val) 294{ 295 struct efuse_val fuse_line; 296 u32 ld_line[EFUSE_LD_WORDS]; 297 int res; 298 299 if ((bank == EFUSE_LD0_LINE || bank == EFUSE_LD1_LINE) && word < EFUSE_LD_WORDS) { 300 res = mvebu_efuse_init_hw(); 301 if (res) 302 return res; 303 mvebu_read_ld_efuse(bank == EFUSE_LD1_LINE, ld_line); 304 *val = ld_line[word]; 305 return 0; 306 } 307 308 if (bank < EFUSE_LINE_MIN || bank > EFUSE_LINE_MAX || word > 2) 309 return -EINVAL; 310 311 res = mvebu_read_efuse(bank, &fuse_line); 312 if (res) 313 return res; 314 315 if (word < 2) 316 *val = fuse_line.dwords.d[word]; 317 else 318 *val = fuse_line.lock; 319 320 return res; 321} 322 323int fuse_sense(u32 bank, u32 word, u32 *val) 324{ 325 /* not supported */ 326 return -ENOSYS; 327} 328 329int fuse_prog(u32 bank, u32 word, u32 val) 330{ 331 int res = 0; 332 333 if (bank == EFUSE_LD0_LINE || bank == EFUSE_LD1_LINE) 334 return mvebu_prog_ld_efuse(bank == EFUSE_LD1_LINE, word, val); 335 336 /* 337 * NOTE: Fuse line should be written as whole. 338 * So how can we do that with this API? 339 * For now: remember values for word == 0 and word == 1 and write the 340 * whole line when word == 2. 341 * This implies that we always require all 3 fuse prog cmds (one for 342 * for each word) to write a single fuse line. 343 * Exception is a single write to word 2 which will lock the fuse line. 344 * 345 * Hope that will be OK. 346 */ 347 348 if (bank < EFUSE_LINE_MIN || bank > EFUSE_LINE_MAX || word > 2) 349 return -EINVAL; 350 351 if (word < 2) { 352 prog_val.dwords.d[word] = val; 353 valid_prog_words |= (1 << word); 354 } else if ((valid_prog_words & 3) == 0 && val) { 355 res = mvebu_lock_efuse(bank); 356 valid_prog_words = 0; 357 } else if ((valid_prog_words & 3) != 3 || !val) { 358 res = -EINVAL; 359 } else { 360 prog_val.lock = val != 0; 361 res = mvebu_write_efuse(bank, &prog_val); 362 valid_prog_words = 0; 363 } 364 365 return res; 366} 367 368int fuse_override(u32 bank, u32 word, u32 val) 369{ 370 /* not supported */ 371 return -ENOSYS; 372} 373