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 * See file CREDITS for list of people who contributed to this
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License as
17 * published by the Free Software Foundation; either version 2 of
18 * the License, or (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
31 #include <linux/types.h>
33 #include <asm/imx_iim.h>
37 static const struct iim_regs *imx_iim =
38 (struct iim_regs *)IMX_IIM_BASE;
40 static void quick_itoa(u32 num, char *a)
43 for (i = 0; i <= 7; i++) {
44 j = (num >> (4 * i)) & 0xf;
45 k = (j < 10) ? '0' : ('a' - 0xa);
50 /* slen - streng length, e.g.: 23 -> slen=2; abcd -> slen=4 */
51 /* only convert hex value as string input. so "12" is 0x12. */
52 static u32 quick_atoi(char *a, u32 slen)
54 u32 i, num = 0, digit;
56 for (i = 0; i < slen; i++) {
57 if (a[i] >= '0' && a[i] <= '9') {
59 } else if (a[i] >= 'a' && a[i] <= 'f') {
60 digit = a[i] - 'a' + 10;
61 } else if (a[i] >= 'A' && a[i] <= 'F') {
62 digit = a[i] - 'A' + 10;
64 printf("ERROR: %c\n", a[i]);
67 num = (num * 16) + digit;
73 static void fuse_op_start(void)
75 /* Do not generate interrupt */
76 writel(0, &(imx_iim->statm));
77 /* clear the status bits and error bits */
78 writel(0x3, &(imx_iim->stat));
79 writel(0xfe, &(imx_iim->err));
83 * The action should be either:
88 static s32 poll_fuse_op_done(s32 action)
92 if (action != POLL_FUSE_PRGD && action != POLL_FUSE_SNSD) {
93 printf("%s(%d) invalid operation\n", __func__, action);
97 /* Poll busy bit till it is NOT set */
98 while ((readl(&(imx_iim->stat)) & IIM_STAT_BUSY) != 0)
101 /* Test for successful write */
102 status = readl(&(imx_iim->stat));
103 error = readl(&(imx_iim->err));
105 if ((status & action) != 0 && \
106 (error & (action >> IIM_ERR_SHIFT)) == 0) {
108 printf("Even though the operation"
109 "seems successful...\n");
110 printf("There are some error(s) "
111 "at addr=0x%x: 0x%x\n",
112 (u32)&(imx_iim->err), error);
116 printf("%s(%d) failed\n", __func__, action);
117 printf("status address=0x%x, value=0x%x\n",
118 (u32)&(imx_iim->stat), status);
119 printf("There are some error(s) at addr=0x%x: 0x%x\n",
120 (u32)&(imx_iim->err), error);
124 static u32 sense_fuse(s32 bank, s32 row, s32 bit)
126 s32 addr, addr_l, addr_h, reg_addr;
130 addr = ((bank << 11) | (row << 3) | (bit & 0x7));
131 /* Set IIM Program Upper Address */
132 addr_h = (addr >> 8) & 0x000000FF;
133 /* Set IIM Program Lower Address */
134 addr_l = (addr & 0x000000FF);
136 #ifdef IIM_FUSE_DEBUG
137 printf("%s: addr_h=0x%x, addr_l=0x%x\n",
138 __func__, addr_h, addr_l);
140 writel(addr_h, &(imx_iim->ua));
141 writel(addr_l, &(imx_iim->la));
144 writel(0x8, &(imx_iim->fctl));
145 if (poll_fuse_op_done(POLL_FUSE_SNSD) != 0) {
146 printf("%s(bank: %d, row: %d, bit: %d failed\n",
147 __func__, bank, row, bit);
149 reg_addr = &(imx_iim->sdat);
151 return readl(reg_addr);
154 int iim_read(int bank, char row)
159 printf("Read fuse at bank:%d row:%d\n", bank, row);
160 fuse_val = sense_fuse(bank, row, 0);
161 printf("fuses at (bank:%d, row:%d) = 0x%x\n", bank, row, fuse_val);
166 /* Blow fuses based on the bank, row and bit positions (all 0-based)
168 static s32 fuse_blow_bit(s32 bank, s32 row, s32 bit)
170 int addr, addr_l, addr_h, ret = -1;
174 /* Disable IIM Program Protect */
175 writel(0xaa, &(imx_iim->preg_p));
177 addr = ((bank << 11) | (row << 3) | (bit & 0x7));
178 /* Set IIM Program Upper Address */
179 addr_h = (addr >> 8) & 0x000000FF;
180 /* Set IIM Program Lower Address */
181 addr_l = (addr & 0x000000FF);
183 #ifdef IIM_FUSE_DEBUG
184 printf("blowing addr_h=0x%x, addr_l=0x%x\n", addr_h, addr_l);
187 writel(addr_h, &(imx_iim->ua));
188 writel(addr_l, &(imx_iim->la));
190 /* Start Programming */
191 writel(0x31, &(imx_iim->fctl));
192 if (poll_fuse_op_done(POLL_FUSE_PRGD) == 0)
195 /* Enable IIM Program Protect */
196 writel(0x0, &(imx_iim->preg_p));
201 static void fuse_blow_row(s32 bank, s32 row, s32 value)
205 /* enable fuse blown */
206 reg = readl(CCM_BASE_ADDR + 0x64);
208 writel(reg, CCM_BASE_ADDR + 0x64);
210 for (i = 0; i < 8; i++) {
211 if (((value >> i) & 0x1) == 0)
213 if (fuse_blow_bit(bank, row, i) != 0) {
214 printf("fuse_blow_bit(bank: %d, row: %d, "
220 writel(reg, CCM_BASE_ADDR + 0x64);
223 int iim_blow(int bank, int row, int val)
225 u32 fuse_val, err = 0;
227 printf("Blowing fuse at bank:%d row:%d value:%d\n",
229 fuse_blow_row(bank, row, val);
230 fuse_val = sense_fuse(bank, row, 0);
231 printf("fuses at (bank:%d, row:%d) = 0x%x\n", bank, row, fuse_val);
236 static int iim_read_mac_addr(u8 *data)
238 s32 bank = CONFIG_IIM_MAC_BANK;
239 s32 row = CONFIG_IIM_MAC_ROW;
241 data[0] = sense_fuse(bank, row, 0) ;
242 data[1] = sense_fuse(bank, row + 1, 0) ;
243 data[2] = sense_fuse(bank, row + 2, 0) ;
244 data[3] = sense_fuse(bank, row + 3, 0) ;
245 data[4] = sense_fuse(bank, row + 4, 0) ;
246 data[5] = sense_fuse(bank, row + 5, 0) ;
248 if (!memcmp(data, "\0\0\0\0\0\0", 6))
254 int iim_blow_func(char *func_name, char *func_val)
261 if (0 == strcmp(func_name, "scc")) {
263 C3D153EDFD2EA9982226EF5047D3B9A0B9C7138EA87C028401D28C2C2C0B9AA2 */
264 printf("Ready to burn SCC fuses\n");
269 value = quick_atoi(val, 2);
270 /* printf("fuse_blow_row(2, %d, value=0x%x)\n",
272 fuse_blow_row(2, i, value);
274 if ((++s)[0] == '\0') {
275 printf("ERROR: Odd string input\n");
279 if ((++s)[0] == '\0') {
280 printf("Successful\n");
284 } else if (0 == strcmp(func_name, "srk")) {
286 418bccd09b53bee1ab59e2662b3c7877bc0094caee201052add49be8780dff95 */
287 printf("Ready to burn SRK key fuses\n");
292 value = quick_atoi(val, 2);
294 /* 0x41 goes to SRK_HASH[255:248],
296 fuse_blow_row(1, 1, value);
298 /* 0x8b in SRK_HASH[247:240] bank 3, row 1 */
299 /* 0xcc in SRK_HASH[239:232] bank 3, row 2 */
301 fuse_blow_row(3, i, value);
303 if ((++s)[0] == '\0') {
304 printf("ERROR: Odd string input\n");
308 if ((++s)[0] == '\0') {
309 printf("Successful\n");
314 } else if (0 == strcmp(func_name, "fecmac")) {
317 if (NULL == func_val) {
318 /* Read the Mac address and print it */
319 iim_read_mac_addr(ea);
321 printf("FEC MAC address: ");
322 printf("0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n\n",
323 ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]);
328 eth_parse_enetaddr(func_val, ea);
329 if (!is_valid_ether_addr(ea)) {
330 printf("Error: invalid mac address parameter!\n");
333 for (i = 0; i < 6; ++i)
334 fuse_blow_row(1, i + 9, ea[i]);
337 printf("This command is not supported\n");