blob: de8733938df1fad1b901b07ee09f6993cac1a664 [file] [log] [blame]
Michael Zaidman4228f8b2010-04-07 18:30:08 +03001/*
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 */
40static 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
61int 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