]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/misc/imx_iim.c
applied patches from Freescale and Ka-Ro
[karo-tx-uboot.git] / drivers / misc / imx_iim.c
1 /*
2  * (C) Copyright 2008-2010 Freescale Semiconductor, Inc.
3  * Terry Lv
4  *
5  * Copyright 2007, Freescale Semiconductor, Inc
6  * Andy Fleming
7  *
8  * Based vaguely on the pxa mmc code:
9  * (C) Copyright 2003
10  * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
11  *
12  * See file CREDITS for list of people who contributed to this
13  * project.
14  *
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.
19  *
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.
24  *
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,
28  * MA 02111-1307 USA
29  */
30
31 #include <linux/types.h>
32 #include <asm/io.h>
33 #include <asm/imx_iim.h>
34 #include <common.h>
35 #include <net.h>
36
37 static const struct iim_regs *imx_iim =
38                 (struct iim_regs *)IMX_IIM_BASE;
39
40 static void quick_itoa(u32 num, char *a)
41 {
42         int i, j, k;
43         for (i = 0; i <= 7; i++) {
44                 j = (num >> (4 * i)) & 0xf;
45                 k = (j < 10) ? '0' : ('a' - 0xa);
46                 a[i] = j + k;
47         }
48 }
49
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)
53 {
54         u32 i, num = 0, digit;
55
56         for (i = 0; i < slen; i++) {
57                 if (a[i] >= '0' && a[i] <= '9') {
58                         digit = a[i] - '0';
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;
63                 } else {
64                         printf("ERROR: %c\n", a[i]);
65                         return -1;
66                 }
67                 num = (num * 16) + digit;
68         }
69
70     return num;
71 }
72
73 static void fuse_op_start(void)
74 {
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));
80 }
81
82 /*
83  * The action should be either:
84  *          POLL_FUSE_PRGD
85  * or:
86  *          POLL_FUSE_SNSD
87  */
88 static s32 poll_fuse_op_done(s32 action)
89 {
90         u32 status, error;
91
92         if (action != POLL_FUSE_PRGD && action != POLL_FUSE_SNSD) {
93                 printf("%s(%d) invalid operation\n", __func__, action);
94                 return -1;
95         }
96
97         /* Poll busy bit till it is NOT set */
98         while ((readl(&(imx_iim->stat)) & IIM_STAT_BUSY) != 0)
99                 ;
100
101         /* Test for successful write */
102         status = readl(&(imx_iim->stat));
103         error = readl(&(imx_iim->err));
104
105         if ((status & action) != 0 && \
106                         (error & (action >> IIM_ERR_SHIFT)) == 0) {
107                 if (error) {
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);
113                 }
114                 return 0;
115         }
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);
121         return -1;
122 }
123
124 static u32 sense_fuse(s32 bank, s32 row, s32 bit)
125 {
126         s32 addr, addr_l, addr_h, reg_addr;
127
128         fuse_op_start();
129
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);
135
136 #ifdef IIM_FUSE_DEBUG
137         printf("%s: addr_h=0x%x, addr_l=0x%x\n",
138                         __func__, addr_h, addr_l);
139 #endif
140         writel(addr_h, &(imx_iim->ua));
141         writel(addr_l, &(imx_iim->la));
142
143         /* Start sensing */
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);
148         }
149         reg_addr = &(imx_iim->sdat);
150
151         return readl(reg_addr);
152 }
153
154 int iim_read(int bank, char row)
155 {
156         u32 fuse_val;
157         s32 err = 0;
158
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);
162
163         return err;
164 }
165
166 /* Blow fuses based on the bank, row and bit positions (all 0-based)
167 */
168 static s32 fuse_blow_bit(s32 bank, s32 row, s32 bit)
169 {
170         int addr, addr_l, addr_h, ret = -1;
171
172         fuse_op_start();
173
174         /* Disable IIM Program Protect */
175         writel(0xaa, &(imx_iim->preg_p));
176
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);
182
183 #ifdef IIM_FUSE_DEBUG
184         printf("blowing addr_h=0x%x, addr_l=0x%x\n", addr_h, addr_l);
185 #endif
186
187         writel(addr_h, &(imx_iim->ua));
188         writel(addr_l, &(imx_iim->la));
189
190         /* Start Programming */
191         writel(0x31, &(imx_iim->fctl));
192         if (poll_fuse_op_done(POLL_FUSE_PRGD) == 0)
193                 ret = 0;
194
195         /* Enable IIM Program Protect */
196         writel(0x0, &(imx_iim->preg_p));
197
198         return ret;
199 }
200
201 static void fuse_blow_row(s32 bank, s32 row, s32 value)
202 {
203         u32 reg, i;
204
205         /* enable fuse blown */
206         reg = readl(CCM_BASE_ADDR + 0x64);
207         reg |= 0x10;
208         writel(reg, CCM_BASE_ADDR + 0x64);
209
210         for (i = 0; i < 8; i++) {
211                 if (((value >> i) & 0x1) == 0)
212                         continue;
213         if (fuse_blow_bit(bank, row, i) != 0) {
214                         printf("fuse_blow_bit(bank: %d, row: %d, "
215                                 "bit: %d failed\n",
216                                 bank, row, i);
217                 }
218     }
219     reg &= ~0x10;
220     writel(reg, CCM_BASE_ADDR + 0x64);
221 }
222
223 int iim_blow(int bank, int row, int val)
224 {
225         u32 fuse_val, err = 0;
226
227         printf("Blowing fuse at bank:%d row:%d value:%d\n",
228                         bank, row, val);
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);
232
233         return err;
234 }
235
236 static int iim_read_mac_addr(u8 *data)
237 {
238         s32 bank = CONFIG_IIM_MAC_BANK;
239         s32 row  = CONFIG_IIM_MAC_ROW;
240
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) ;
247
248         if (!memcmp(data, "\0\0\0\0\0\0", 6))
249                 return 0;
250         else
251                 return 1;
252 }
253
254 int iim_blow_func(char *func_name, char *func_val)
255 {
256         u32 value, i;
257         char *s;
258         char val[3];
259         s32 err = 0;
260
261         if (0 == strcmp(func_name, "scc")) {
262                 /* fuse_blow scc
263         C3D153EDFD2EA9982226EF5047D3B9A0B9C7138EA87C028401D28C2C2C0B9AA2 */
264                 printf("Ready to burn SCC fuses\n");
265                 s = func_val;
266                 for (i = 0; ; ++i) {
267                         memcpy(val, s, 2);
268                         val[2] = '\0';
269                         value = quick_atoi(val, 2);
270                         /* printf("fuse_blow_row(2, %d, value=0x%x)\n",
271                                         i, value); */
272                         fuse_blow_row(2, i, value);
273
274                         if ((++s)[0] == '\0') {
275                                 printf("ERROR: Odd string input\n");
276                                 err = -1;
277                                 break;
278                         }
279                         if ((++s)[0] == '\0') {
280                                 printf("Successful\n");
281                                 break;
282                         }
283                 }
284         } else if (0 == strcmp(func_name, "srk")) {
285                 /* fuse_blow srk
286         418bccd09b53bee1ab59e2662b3c7877bc0094caee201052add49be8780dff95 */
287                 printf("Ready to burn SRK key fuses\n");
288                 s = func_val;
289                 for (i = 0; ; ++i) {
290                         memcpy(val, s, 2);
291                         val[2] = '\0';
292                         value = quick_atoi(val, 2);
293                         if (i == 0) {
294                                 /* 0x41 goes to SRK_HASH[255:248],
295                                  * bank 1, row 1 */
296                                 fuse_blow_row(1, 1, value);
297                         } else {
298                                 /* 0x8b in SRK_HASH[247:240] bank 3, row 1 */
299                                 /* 0xcc in SRK_HASH[239:232] bank 3, row 2 */
300                                 /* ... */
301                                 fuse_blow_row(3, i, value);
302
303                                 if ((++s)[0] == '\0') {
304                                         printf("ERROR: Odd string input\n");
305                                         err = -1;
306                                         break;
307                                 }
308                                 if ((++s)[0] == '\0') {
309                                         printf("Successful\n");
310                                         break;
311                                 }
312                         }
313                 }
314         } else if (0 == strcmp(func_name, "fecmac")) {
315                 u8 ea[6] = { 0 };
316
317                 if (NULL == func_val) {
318                         /* Read the Mac address and print it */
319                         iim_read_mac_addr(ea);
320
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]);
324
325                         return 0;
326                 }
327
328                 eth_parse_enetaddr(func_val, ea);
329                 if (!is_valid_ether_addr(ea)) {
330                         printf("Error: invalid mac address parameter!\n");
331                         err = -1;
332                 } else {
333                         for (i = 0; i < 6; ++i)
334                                 fuse_blow_row(1, i + 9, ea[i]);
335                 }
336         } else {
337                 printf("This command is not supported\n");
338         }
339
340         return err;
341 }
342
343