2 * (C) Copyright 2008-2010 Freescale Semiconductor, Inc.
5 * Copyright 2007, Freescale Semiconductor, Inc
8 * Based vaguely on the pxa mmc code:
10 * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
12 * Adapted for U-Boot version 2012-04-01 by Lothar Waßmann <LW@KARO-electronics.de>
14 * See file CREDITS for list of people who contributed to this
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License as
19 * published by the Free Software Foundation; either version 2 of
20 * the License, or (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
35 #include <linux/types.h>
37 #include <asm/arch/imx-regs.h>
38 #include <asm/arch/imx_iim.h>
40 static struct iim_regs *imx_iim = (void *)IMX_IIM_BASE;
42 /* slen - string length, e.g.: 23 -> slen=2; abcd -> slen=4 */
43 /* only convert hex value as string input. so "12" is 0x12. */
44 static u32 quick_atoi(char *a, u32 slen)
46 u32 i, num = 0, digit;
48 for (i = 0; i < slen; i++) {
49 if (a[i] >= '0' && a[i] <= '9') {
51 } else if (a[i] >= 'a' && a[i] <= 'f') {
52 digit = a[i] - 'a' + 10;
53 } else if (a[i] >= 'A' && a[i] <= 'F') {
54 digit = a[i] - 'A' + 10;
56 printf("ERROR: %c\n", a[i]);
59 num = (num * 16) + digit;
65 static void fuse_op_start(void)
67 /* Do not generate interrupt */
68 writel(0, &imx_iim->statm);
69 /* clear the status bits and error bits */
70 writel(0x3, &imx_iim->stat);
71 writel(0xfe, &imx_iim->err);
75 * The action should be either:
80 static s32 poll_fuse_op_done(s32 action)
84 if (action != POLL_FUSE_PRGD && action != POLL_FUSE_SNSD) {
85 printf("%s(%d) invalid operation\n", __func__, action);
89 /* Poll busy bit till it is NOT set */
90 while ((readl(&imx_iim->stat) & IIM_STAT_BUSY) != 0)
93 /* Test for successful write */
94 status = readl(&imx_iim->stat);
95 error = readl(&imx_iim->err);
97 if ((status & action) != 0 && \
98 (error & (action >> IIM_ERR_SHIFT)) == 0) {
100 printf("Even though the operation"
101 "seems successful...\n");
102 printf("There are some error(s) "
103 "at addr=%p: 0x%x\n",
104 &imx_iim->err, error);
108 printf("%s(%d) failed\n", __func__, action);
109 printf("status address=%p, value=0x%x\n",
110 &imx_iim->stat, status);
111 printf("There are some error(s) at addr=%p: 0x%x\n",
112 &imx_iim->err, error);
116 static u32 sense_fuse(s32 bank, s32 row, s32 bit)
118 s32 addr, addr_l, addr_h;
123 addr = ((bank << 11) | (row << 3) | (bit & 0x7));
124 /* Set IIM Program Upper Address */
125 addr_h = (addr >> 8) & 0x000000FF;
126 /* Set IIM Program Lower Address */
127 addr_l = (addr & 0x000000FF);
129 #ifdef IIM_FUSE_DEBUG
130 printf("%s: addr_h=0x%x, addr_l=0x%x\n",
131 __func__, addr_h, addr_l);
133 writel(addr_h, &imx_iim->ua);
134 writel(addr_l, &imx_iim->la);
137 writel(0x8, &imx_iim->fctl);
138 if (poll_fuse_op_done(POLL_FUSE_SNSD) != 0) {
139 printf("%s(bank: %d, row: %d, bit: %d failed\n",
140 __func__, bank, row, bit);
142 reg_addr = &imx_iim->sdat;
144 return readl(reg_addr);
147 int iim_read(int bank, char row)
152 printf("Read fuse at bank:%d row:%d\n", bank, row);
153 fuse_val = sense_fuse(bank, row, 0);
154 printf("fuses at (bank:%d, row:%d) = 0x%x\n", bank, row, fuse_val);
159 /* Blow fuses based on the bank, row and bit positions (all 0-based)
161 static s32 fuse_blow_bit(s32 bank, s32 row, s32 bit)
163 int addr, addr_l, addr_h, ret = -1;
167 /* Disable IIM Program Protect */
168 writel(0xaa, &imx_iim->preg_p);
170 addr = ((bank << 11) | (row << 3) | (bit & 0x7));
171 /* Set IIM Program Upper Address */
172 addr_h = (addr >> 8) & 0x000000FF;
173 /* Set IIM Program Lower Address */
174 addr_l = (addr & 0x000000FF);
176 #ifdef IIM_FUSE_DEBUG
177 printf("blowing addr_h=0x%x, addr_l=0x%x\n", addr_h, addr_l);
180 writel(addr_h, &imx_iim->ua);
181 writel(addr_l, &imx_iim->la);
183 /* Start Programming */
184 writel(0x31, &imx_iim->fctl);
185 if (poll_fuse_op_done(POLL_FUSE_PRGD) == 0)
188 /* Enable IIM Program Protect */
189 writel(0x0, &imx_iim->preg_p);
194 static void fuse_blow_row(s32 bank, s32 row, s32 value)
198 /* enable fuse blown */
199 reg = readl(CCM_BASE_ADDR + 0x64);
201 writel(reg, CCM_BASE_ADDR + 0x64);
203 for (i = 0; i < 8; i++) {
204 if (((value >> i) & 0x1) == 0)
206 if (fuse_blow_bit(bank, row, i) != 0) {
207 printf("fuse_blow_bit(bank: %d, row: %d, "
213 writel(reg, CCM_BASE_ADDR + 0x64);
216 int iim_blow(int bank, int row, int val)
218 u32 fuse_val, err = 0;
220 printf("Blowing fuse at bank:%d row:%d value:%d\n",
222 fuse_blow_row(bank, row, val);
223 fuse_val = sense_fuse(bank, row, 0);
224 printf("fuses at (bank:%d, row:%d) = 0x%x\n", bank, row, fuse_val);
229 int iim_blow_func(char *func_name, char *func_val)
236 if (strcmp(func_name, "scc") == 0) {
238 C3D153EDFD2EA9982226EF5047D3B9A0B9C7138EA87C028401D28C2C2C0B9AA2 */
239 printf("Ready to burn SCC fuses\n");
244 value = quick_atoi(val, 2);
245 /* printf("fuse_blow_row(2, %d, value=0x%x)\n",
247 fuse_blow_row(2, i, value);
249 if (*(++s) == '\0') {
250 printf("ERROR: Odd string input\n");
254 if (*(++s) == '\0') {
255 printf("Successful\n");
259 } else if (strcmp(func_name, "srk") == 0) {
261 418bccd09b53bee1ab59e2662b3c7877bc0094caee201052add49be8780dff95 */
262 printf("Ready to burn SRK key fuses\n");
267 value = quick_atoi(val, 2);
269 /* 0x41 goes to SRK_HASH[255:248],
271 fuse_blow_row(1, 1, value);
273 /* 0x8b in SRK_HASH[247:240] bank 3, row 1 */
274 /* 0xcc in SRK_HASH[239:232] bank 3, row 2 */
276 fuse_blow_row(3, i, value);
278 if (*(++s) == '\0') {
279 printf("ERROR: Odd string input\n");
283 if (*(++s) == '\0') {
284 printf("Successful\n");
289 } else if (strcmp(func_name, "fecmac") == 0) {
292 if (func_val == NULL) {
293 /* Read the Mac address and print it */
294 imx_get_mac_from_fuse(0, ea);
296 printf("FEC MAC address: ");
297 printf("0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n\n",
298 ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]);
303 eth_parse_enetaddr(func_val, ea);
304 if (!is_valid_ether_addr(ea)) {
305 printf("Error: invalid mac address parameter!\n");
308 for (i = 0; i < 6; ++i)
309 fuse_blow_row(1, i + 9, ea[i]);
312 printf("This command is not supported\n");