1 From 3de15e03d89eeda18e665d270c6e3abf65c94d1d Mon Sep 17 00:00:00 2001
2 From: Terry Lv <r65388@freescale.com>
3 Date: Tue, 26 Jan 2010 20:18:22 +0800
4 Subject: [PATCH] ENGR00120476: Add fuse support for mx51
6 Add fuse support for mx51.
8 Signed-off-by: Terry Lv <r65388@freescale.com>
10 cpu/arm_cortexa8/mx51/Makefile | 3 +
11 cpu/arm_cortexa8/mx51/cmd_fuse.c | 92 ++++++++++
12 cpu/arm_cortexa8/mx51/imx_fuse.c | 333 ++++++++++++++++++++++++++++++++++
13 drivers/net/mxc_fec.c | 4 +
14 include/asm-arm/arch-mx51/imx_fuse.h | 33 ++++
15 include/asm-arm/arch-mx51/mx51.h | 35 ++++-
16 include/configs/mx51_3stack.h | 6 +
17 include/configs/mx51_bbg.h | 6 +
18 8 files changed, 511 insertions(+), 1 deletions(-)
20 diff --git a/cpu/arm_cortexa8/mx51/Makefile b/cpu/arm_cortexa8/mx51/Makefile
21 index 435f26f..79f697d 100644
22 --- a/cpu/arm_cortexa8/mx51/Makefile
23 +++ b/cpu/arm_cortexa8/mx51/Makefile
24 @@ -28,6 +28,9 @@ include $(TOPDIR)/config.mk
25 LIB = $(obj)lib$(SOC).a
27 COBJS = interrupts.o serial.o generic.o iomux.o timer.o cache.o
28 +COBJS-$(CONFIG_CMD_FUSE) += cmd_fuse.o
29 +COBJS-$(CONFIG_IMX_FUSE) += imx_fuse.o
31 SOBJS = mxc_nand_load.o
33 SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
34 diff --git a/cpu/arm_cortexa8/mx51/cmd_fuse.c b/cpu/arm_cortexa8/mx51/cmd_fuse.c
36 index 0000000..1d32e3a
38 +++ b/cpu/arm_cortexa8/mx51/cmd_fuse.c
41 + * (C) Copyright 2008-2010 Freescale Semiconductor, Inc.
44 + * Copyright 2007, Freescale Semiconductor, Inc
47 + * Based vaguely on the pxa mmc code:
48 + * (C) Copyright 2003
49 + * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
51 + * See file CREDITS for list of people who contributed to this
54 + * This program is free software; you can redistribute it and/or
55 + * modify it under the terms of the GNU General Public License as
56 + * published by the Free Software Foundation; either version 2 of
57 + * the License, or (at your option) any later version.
59 + * This program is distributed in the hope that it will be useful,
60 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
61 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
62 + * GNU General Public License for more details.
64 + * You should have received a copy of the GNU General Public License
65 + * along with this program; if not, write to the Free Software
66 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
70 +#include <linux/types.h>
72 +#include <asm/arch/mx51.h>
75 +#include <asm/arch/imx_fuse.h>
77 +int do_fuseops(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
86 + if (strcmp(argv[1], "read") == 0) {
87 + bank = simple_strtoul(argv[2], NULL, 16);
88 + row = simple_strtoul(argv[3], NULL, 16);
90 + fuse_read(bank, row);
91 + } else if (strcmp(argv[1], "blow") == 0) {
92 + fuse_blow_func(argv[2], argv[3]);
94 + printf("It is too dangeous for you to use fuse command.\n");
95 + printf("Usage:\n%s\n", cmdtp->usage);
100 + if (strcmp(argv[1], "blow") == 0) {
101 + bank = simple_strtoul(argv[2], NULL, 16);
102 + row = simple_strtoul(argv[3], NULL, 16);
103 + val = simple_strtoul(argv[4], NULL, 16);
105 + fuse_blow(bank, row, val);
107 + printf("It is too dangeous for you to use fuse command.\n");
108 + printf("Usage:\n%s\n", cmdtp->usage);
114 + printf("It is too dangeous for you to use fuse command.\n");
115 + printf("Usage:\n%s\n", cmdtp->usage);
123 + fuse, 5, 1, do_fuseops,
125 + "read <bank> <row> - Read some fuses\n"
126 + "blow <bank> <row> <value> - Blow some fuses\n"
127 + "blow scc <value> - Blow scc value\n"
128 + "blow srk <value> - Blow srk value\n"
129 + "blow fecmac <0x##:0x##:0x##:0x##:0x##:0x##>"
130 + "- Blow FEC Mac address\n");
132 diff --git a/cpu/arm_cortexa8/mx51/imx_fuse.c b/cpu/arm_cortexa8/mx51/imx_fuse.c
134 index 0000000..3901a25
136 +++ b/cpu/arm_cortexa8/mx51/imx_fuse.c
139 + * (C) Copyright 2008-2010 Freescale Semiconductor, Inc.
142 + * Copyright 2007, Freescale Semiconductor, Inc
145 + * Based vaguely on the pxa mmc code:
146 + * (C) Copyright 2003
147 + * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
149 + * See file CREDITS for list of people who contributed to this
152 + * This program is free software; you can redistribute it and/or
153 + * modify it under the terms of the GNU General Public License as
154 + * published by the Free Software Foundation; either version 2 of
155 + * the License, or (at your option) any later version.
157 + * This program is distributed in the hope that it will be useful,
158 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
159 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
160 + * GNU General Public License for more details.
162 + * You should have received a copy of the GNU General Public License
163 + * along with this program; if not, write to the Free Software
164 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
165 + * MA 02111-1307 USA
168 +#include <linux/types.h>
170 +#include <asm/arch/mx51.h>
171 +#include <asm/arch/imx_fuse.h>
175 +static void quick_itoa(u32 num, char *a)
178 + for (i = 0; i <= 7; i++) {
179 + j = (num >> (4 * i)) & 0xF;
180 + k = (j < 10) ? '0' : ('a' - 0xa);
185 +/* slen - streng length, e.g.: 23 -> slen=2; abcd -> slen=4 */
186 +/* only convert hex value as string input. so "12" is 0x12. */
187 +static u32 quick_atoi(char *a, u32 slen)
189 + u32 i, num = 0, digit;
191 + for (i = 0; i < slen; i++) {
192 + if (a[i] >= '0' && a[i] <= '9') {
193 + digit = a[i] - '0';
194 + } else if (a[i] >= 'a' && a[i] <= 'f') {
195 + digit = a[i] - 'a' + 10;
196 + } else if (a[i] >= 'A' && a[i] <= 'F') {
197 + digit = a[i] - 'A' + 10;
199 + printf("ERROR: %c\n", a[i]);
202 + num = (num * 16) + digit;
208 +static void fuse_op_start(void)
210 + /* Do not generate interrupt */
211 + writel(0, IIM_BASE_ADDR + IIM_STATM_OFF);
212 + /* clear the status bits and error bits */
213 + writel(0x3, IIM_BASE_ADDR + IIM_STAT_OFF);
214 + writel(0xFE, IIM_BASE_ADDR + IIM_ERR_OFF);
218 + * The action should be either:
223 +static s32 poll_fuse_op_done(s32 action)
227 + if (action != POLL_FUSE_PRGD && action != POLL_FUSE_SNSD) {
228 + printf("%s(%d) invalid operation\n", __func__, action);
232 + /* Poll busy bit till it is NOT set */
233 + while ((readl(IIM_BASE_ADDR + IIM_STAT_OFF) & IIM_STAT_BUSY) != 0)
236 + /* Test for successful write */
237 + status = readl(IIM_BASE_ADDR + IIM_STAT_OFF);
238 + error = readl(IIM_BASE_ADDR + IIM_ERR_OFF);
240 + if ((status & action) != 0 && \
241 + (error & (action >> IIM_ERR_SHIFT)) == 0) {
243 + printf("Even though the operation seems successful...\n");
244 + printf("There are some error(s) at addr=0x%x: 0x%x\n",
245 + (IIM_BASE_ADDR + IIM_ERR_OFF), error);
249 + printf("%s(%d) failed\n", __func__, action);
250 + printf("status address=0x%x, value=0x%x\n",
251 + (IIM_BASE_ADDR + IIM_STAT_OFF), status);
252 + printf("There are some error(s) at addr=0x%x: 0x%x\n",
253 + (IIM_BASE_ADDR + IIM_ERR_OFF), error);
257 +static u32 sense_fuse(s32 bank, s32 row, s32 bit)
259 + s32 addr, addr_l, addr_h, reg_addr;
263 + addr = ((bank << 11) | (row << 3) | (bit & 0x7));
264 + /* Set IIM Program Upper Address */
265 + addr_h = (addr >> 8) & 0x000000FF;
266 + /* Set IIM Program Lower Address */
267 + addr_l = (addr & 0x000000FF);
269 +#ifdef IIM_FUSE_DEBUG
270 + printf("%s: addr_h=0x%x, addr_l=0x%x\n",
271 + __func__, addr_h, addr_l);
273 + writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
274 + writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
276 + /* Start sensing */
277 + writel(0x8, IIM_BASE_ADDR + IIM_FCTL_OFF);
278 + if (poll_fuse_op_done(POLL_FUSE_SNSD) != 0) {
279 + printf("%s(bank: %d, row: %d, bit: %d failed\n",
280 + __func__, bank, row, bit);
282 + reg_addr = IIM_BASE_ADDR + IIM_SDAT_OFF;
284 + return readl(reg_addr);
287 +int fuse_read(int bank, char row)
292 + printf("Read fuse at bank:%d row:%d\n", bank, row);
293 + fuse_val = sense_fuse(bank, row, 0);
294 + printf("fuses at (bank:%d, row:%d) = 0x%x\n", bank, row, fuse_val);
299 +/* Blow fuses based on the bank, row and bit positions (all 0-based)
301 +static s32 fuse_blow_bit(s32 bank, s32 row, s32 bit)
303 + int addr, addr_l, addr_h, ret = -1;
307 + /* Disable IIM Program Protect */
308 + writel(0xAA, IIM_BASE_ADDR + IIM_PREG_P_OFF);
310 + addr = ((bank << 11) | (row << 3) | (bit & 0x7));
311 + /* Set IIM Program Upper Address */
312 + addr_h = (addr >> 8) & 0x000000FF;
313 + /* Set IIM Program Lower Address */
314 + addr_l = (addr & 0x000000FF);
316 +#ifdef IIM_FUSE_DEBUG
317 + printf("blowing addr_h=0x%x, addr_l=0x%x\n", addr_h, addr_l);
320 + writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
321 + writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
323 + /* Start Programming */
324 + writel(0x31, IIM_BASE_ADDR + IIM_FCTL_OFF);
325 + if (poll_fuse_op_done(POLL_FUSE_PRGD) == 0)
328 + /* Enable IIM Program Protect */
329 + writel(0x0, IIM_BASE_ADDR + IIM_PREG_P_OFF);
334 +static void fuse_blow_row(s32 bank, s32 row, s32 value)
338 + /* enable fuse blown */
339 + reg = readl(CCM_BASE_ADDR + 0x64);
341 + writel(reg, CCM_BASE_ADDR + 0x64);
343 + for (i = 0; i < 8; i++) {
344 + if (((value >> i) & 0x1) == 0)
346 + if (fuse_blow_bit(bank, row, i) != 0) {
347 + printf("fuse_blow_bit(bank: %d, row: %d, bit: %d failed\n",
352 + writel(reg, CCM_BASE_ADDR + 0x64);
355 +int fuse_blow(int bank, int row, int val)
357 + u32 fuse_val, err = 0;
359 + printf("Blowing fuse at bank:%d row:%d value:%d\n",
361 + fuse_blow_row(bank, row, val);
362 + fuse_val = sense_fuse(bank, row, 0);
363 + printf("fuses at (bank:%d, row:%d) = 0x%x\n", bank, row, fuse_val);
368 +static int fuse_read_mac_addr(u8 *data)
370 + data[0] = sense_fuse(1, 9, 0) ;
371 + data[1] = sense_fuse(1, 10, 0) ;
372 + data[2] = sense_fuse(1, 11, 0) ;
373 + data[3] = sense_fuse(1, 12, 0) ;
374 + data[4] = sense_fuse(1, 13, 0) ;
375 + data[5] = sense_fuse(1, 14, 0) ;
377 + if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
378 + (data[3] == 0) && (data[4] == 0) && (data[5] == 0)) {
385 +int fuse_blow_func(char *func_name, char *func_val)
392 + if (0 == strcmp(func_name, "scc")) {
393 + /* fuse_blow scc C3D153EDFD2EA9982226EF5047D3B9A0B9C7138EA87C028401D28C2C2C0B9AA2 */
394 + printf("Ready to burn SCC fuses\n");
396 + for (i = 0; ; ++i) {
399 + value = quick_atoi(val, 2);
400 + /* printf("fuse_blow_row(2, %d, value=0x%x)\n", i, value); */
401 + fuse_blow_row(2, i, value);
403 + if ((++s)[0] == '\0') {
404 + printf("ERROR: Odd string input\n");
408 + if ((++s)[0] == '\0') {
409 + printf("Successful\n");
413 + } else if (0 == strcmp(func_name, "srk")) {
414 + /* fuse_blow srk 418bccd09b53bee1ab59e2662b3c7877bc0094caee201052add49be8780dff95 */
415 + printf("Ready to burn SRK key fuses\n");
417 + for (i = 0; ; ++i) {
420 + value = quick_atoi(val, 2);
422 + /* 0x41 goes to SRK_HASH[255:248], bank 1, row 1 */
423 + fuse_blow_row(1, 1, value);
425 + /* 0x8b in SRK_HASH[247:240] bank 3, row 1 */
426 + /* 0xcc in SRK_HASH[239:232] bank 3, row 2 */
428 + fuse_blow_row(3, i, value);
430 + if ((++s)[0] == '\0') {
431 + printf("ERROR: Odd string input\n");
435 + if ((++s)[0] == '\0') {
436 + printf("Successful\n");
441 + } else if (0 == strcmp(func_name, "fecmac")) {
444 + if (NULL == func_val) {
445 + /* Read the Mac address and print it */
446 + fuse_read_mac_addr(ea);
448 + printf("FEC MAC address: ");
449 + printf("0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n\n",
450 + ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]);
455 + eth_parse_enetaddr(func_val, ea);
456 + if (!is_valid_ether_addr(ea)) {
457 + printf("Error: invalid mac address parameter!\n");
460 + for (i = 0; i < 6; ++i)
461 + fuse_blow_row(1, i + 9, ea[i]);
464 + printf("This command is not supported\n");
471 diff --git a/drivers/net/mxc_fec.c b/drivers/net/mxc_fec.c
472 index 8aa32c7..c3e813d 100644
473 --- a/drivers/net/mxc_fec.c
474 +++ b/drivers/net/mxc_fec.c
475 @@ -729,6 +729,10 @@ void mxc_fec_set_mac_from_env(char *mac_addr)
478 eth_parse_enetaddr(mac_addr, ea);
479 + if (!is_valid_ether_addr(ea)) {
480 + printf("Error: invalid FEC MAC address!\n");
484 for (i = 0; i < sizeof(fec_info) / sizeof(fec_info[0]); i++) {
485 fecp = (fec_t *)(fec_info[i].iobase);
486 diff --git a/include/asm-arm/arch-mx51/imx_fuse.h b/include/asm-arm/arch-mx51/imx_fuse.h
488 index 0000000..8a65613
490 +++ b/include/asm-arm/arch-mx51/imx_fuse.h
493 + * (C) Copyright 2009-2010 Freescale Semiconductor, Inc.
495 + * Configuration settings for the MX51-3Stack Freescale board.
497 + * This program is free software; you can redistribute it and/or
498 + * modify it under the terms of the GNU General Public License as
499 + * published by the Free Software Foundation; either version 2 of
500 + * the License, or (at your option) any later version.
502 + * This program is distributed in the hope that it will be useful,
503 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
504 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
505 + * GNU General Public License for more details.
507 + * You should have received a copy of the GNU General Public License
508 + * along with this program; if not, write to the Free Software
509 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
510 + * MA 02111-1307 USA
513 +#ifndef _IMX_FUSE_H_
514 +#define _IMX_FUSE_H_
516 +#define IIM_ERR_SHIFT 8
517 +#define POLL_FUSE_PRGD (IIM_STAT_PRGD | (IIM_ERR_PRGE << IIM_ERR_SHIFT))
518 +#define POLL_FUSE_SNSD (IIM_STAT_SNSD | (IIM_ERR_SNSE << IIM_ERR_SHIFT))
520 +int fuse_read(int bank, char row);
521 +int fuse_blow(int bank, int row, int val);
522 +int fuse_blow_func(char *func_name, char *func_val);
525 diff --git a/include/asm-arm/arch-mx51/mx51.h b/include/asm-arm/arch-mx51/mx51.h
526 index 00e50cf..5fc57bb 100644
527 --- a/include/asm-arm/arch-mx51/mx51.h
528 +++ b/include/asm-arm/arch-mx51/mx51.h
531 - * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
532 + * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
537 #define DP_MFD_216 (4 - 1)
541 +#define IIM_STAT_OFF 0x00
542 +#define IIM_STAT_BUSY (1 << 7)
543 +#define IIM_STAT_PRGD (1 << 1)
544 +#define IIM_STAT_SNSD (1 << 0)
545 +#define IIM_STATM_OFF 0x04
546 +#define IIM_ERR_OFF 0x08
547 +#define IIM_ERR_PRGE (1 << 7)
548 +#define IIM_ERR_WPE (1 << 6)
549 +#define IIM_ERR_OPE (1 << 5)
550 +#define IIM_ERR_RPE (1 << 4)
551 +#define IIM_ERR_WLRE (1 << 3)
552 +#define IIM_ERR_SNSE (1 << 2)
553 +#define IIM_ERR_PARITYE (1 << 1)
554 +#define IIM_EMASK_OFF 0x0C
555 +#define IIM_FCTL_OFF 0x10
556 +#define IIM_UA_OFF 0x14
557 +#define IIM_LA_OFF 0x18
558 +#define IIM_SDAT_OFF 0x1C
559 +#define IIM_PREV_OFF 0x20
560 +#define IIM_SREV_OFF 0x24
561 +#define IIM_PREG_P_OFF 0x28
562 +#define IIM_SCS0_OFF 0x2C
563 +#define IIM_SCS1_P_OFF 0x30
564 +#define IIM_SCS2_OFF 0x34
565 +#define IIM_SCS3_P_OFF 0x38
567 +#define IIM_PROD_REV_SH 3
568 +#define IIM_PROD_REV_LEN 5
569 +#define IIM_SREV_REV_SH 4
570 +#define IIM_SREV_REV_LEN 4
571 +#define PROD_SIGNATURE_MX51 0x1
573 #define CHIP_REV_1_0 0x10
574 #define CHIP_REV_1_1 0x11
575 #define CHIP_REV_2_0 0x20
576 diff --git a/include/configs/mx51_3stack.h b/include/configs/mx51_3stack.h
577 index 292e2cc..f6083c5 100644
578 --- a/include/configs/mx51_3stack.h
579 +++ b/include/configs/mx51_3stack.h
581 #define CONFIG_CMD_MII
582 #define CONFIG_CMD_NET
583 #define CONFIG_CMD_MMC
584 +#define CONFIG_CMD_FUSE
589 +#define CONFIG_IMX_FUSE
593 diff --git a/include/configs/mx51_bbg.h b/include/configs/mx51_bbg.h
594 index aee33ba..f773563 100644
595 --- a/include/configs/mx51_bbg.h
596 +++ b/include/configs/mx51_bbg.h
598 #define CONFIG_CMD_SPI
599 #define CONFIG_CMD_SF
600 #define CONFIG_CMD_MMC
601 +#define CONFIG_CMD_FUSE
606 +#define CONFIG_IMX_FUSE