tizen 2.4 release
[kernel/u-boot-tm1.git] / post / cpu / mpc83xx / ecc.c
1 /*
2  * (C) Copyright 2010
3  * Eastman Kodak Company, <www.kodak.com>
4  * Michael Zaidman, <michael.zaidman@kodak.com>
5  *
6  * The code is based on the cpu/mpc83xx/ecc.c written by
7  * Dave Liu <daveliu@freescale.com>
8  *
9  * See file CREDITS for list of people who contributed to this
10  * project.
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License as
14  * published by the Free Software Foundation; either version 2 of
15  * the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25  * MA 02111-1307 USA
26  */
27
28 #include <common.h>
29 #include <mpc83xx.h>
30 #include <watchdog.h>
31 #include <asm/io.h>
32 #include <post.h>
33
34 #if CONFIG_POST & CONFIG_SYS_POST_ECC
35 /*
36  * We use the RAW I/O accessors where possible in order to
37  * achieve performance goal, since the test's execution time
38  * affects the board start up time.
39  */
40 static inline void ecc_clear(ddr83xx_t *ddr)
41 {
42         /* Clear capture registers */
43         __raw_writel(0, &ddr->capture_address);
44         __raw_writel(0, &ddr->capture_data_hi);
45         __raw_writel(0, &ddr->capture_data_lo);
46         __raw_writel(0, &ddr->capture_ecc);
47         __raw_writel(0, &ddr->capture_attributes);
48
49         /* Clear SBEC and set SBET to 1 */
50         out_be32(&ddr->err_sbe, 1 << ECC_ERROR_MAN_SBET_SHIFT);
51
52         /* Clear Error Detect register */
53         out_be32(&ddr->err_detect, ECC_ERROR_DETECT_MME |\
54                         ECC_ERROR_DETECT_MBE |\
55                         ECC_ERROR_DETECT_SBE |\
56                         ECC_ERROR_DETECT_MSE);
57
58         isync();
59 }
60
61 int ecc_post_test(int flags)
62 {
63         int ret = 0;
64         int int_state;
65         int errbit;
66         u32 pattern[2], writeback[2], retval[2];
67         ddr83xx_t *ddr = &((immap_t *)CONFIG_SYS_IMMR)->ddr;
68         volatile u64 *addr = (u64 *)CONFIG_SYS_POST_ECC_START_ADDR;
69
70         /* The pattern is written into memory to generate error */
71         pattern[0] = 0xfedcba98UL;
72         pattern[1] = 0x76543210UL;
73
74         /* After injecting error, re-initialize the memory with the value */
75         writeback[0] = ~pattern[0];
76         writeback[1] = ~pattern[1];
77
78         /* Check if ECC is enabled */
79         if (__raw_readl(&ddr->err_disable) & ECC_ERROR_ENABLE) {
80                 debug("DDR's ECC is not enabled, skipping the ECC POST.\n");
81                 return 0;
82         }
83
84         int_state = disable_interrupts();
85         icache_enable();
86
87 #ifdef CONFIG_DDR_32BIT
88         /* It seems like no one really uses the CONFIG_DDR_32BIT mode */
89 #error "Add ECC POST support for CONFIG_DDR_32BIT here!"
90 #else
91         for (addr = (u64*)CONFIG_SYS_POST_ECC_START_ADDR, errbit=0;
92              addr < (u64*)CONFIG_SYS_POST_ECC_STOP_ADDR; addr++, errbit++ ) {
93
94                 WATCHDOG_RESET();
95
96                 ecc_clear(ddr);
97
98                 /* Enable error injection */
99                 setbits_be32(&ddr->ecc_err_inject, ECC_ERR_INJECT_EIEN);
100                 sync();
101                 isync();
102
103                 /* Set bit to be injected */
104                 if (errbit < 32) {
105                         __raw_writel(1 << errbit, &ddr->data_err_inject_lo);
106                         __raw_writel(0, &ddr->data_err_inject_hi);
107                 } else {
108                         __raw_writel(0, &ddr->data_err_inject_lo);
109                         __raw_writel(1<<(errbit-32), &ddr->data_err_inject_hi);
110                 }
111                 sync();
112                 isync();
113
114                 /* Write memory location injecting SBE */
115                 ppcDWstore((u32*)addr, pattern);
116                 sync();
117
118                 /* Disable error injection */
119                 clrbits_be32(&ddr->ecc_err_inject, ECC_ERR_INJECT_EIEN);
120                 sync();
121                 isync();
122
123                 /* Data read should generate SBE */
124                 ppcDWload((u32*)addr, retval);
125                 sync();
126
127                 if (!(__raw_readl(&ddr->err_detect) & ECC_ERROR_DETECT_SBE) ||
128                         (__raw_readl(&ddr->data_err_inject_hi) !=
129                         (__raw_readl(&ddr->capture_data_hi) ^ pattern[0])) ||
130                         (__raw_readl(&ddr->data_err_inject_lo) !=
131                         (__raw_readl(&ddr->capture_data_lo) ^ pattern[1]))) {
132
133                         post_log("ECC failed to detect SBE error at %08x, "
134                                 "SBE injection mask %08x-%08x, wrote "
135                                 "%08x-%08x, read %08x-%08x\n", addr,
136                                 ddr->data_err_inject_hi,
137                                 ddr->data_err_inject_lo,
138                                 pattern[0], pattern[1],
139                                 retval[0], retval[1]);
140
141                         printf("ERR_DETECT Reg: %08x\n", ddr->err_detect);
142                         printf("ECC CAPTURE_DATA Reg: %08x-%08x\n",
143                                 ddr->capture_data_hi, ddr->capture_data_lo);
144                         ret = 1;
145                         break;
146                 }
147
148                 /* Re-initialize the ECC memory */
149                 ppcDWstore((u32*)addr, writeback);
150                 sync();
151                 isync();
152
153                 errbit %= 63;
154         }
155 #endif /* !CONFIG_DDR_32BIT */
156
157         ecc_clear(ddr);
158
159         icache_disable();
160
161         if (int_state)
162                 enable_interrupts();
163
164         return ret;
165 }
166 #endif