Home | History | Annotate | Download | only in mpc83xx
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * (C) Copyright 2010
      4  * Eastman Kodak Company, <www.kodak.com>
      5  * Michael Zaidman, <michael.zaidman (at) kodak.com>
      6  *
      7  * The code is based on the cpu/mpc83xx/ecc.c written by
      8  * Dave Liu <daveliu (at) freescale.com>
      9  */
     10 
     11 #include <common.h>
     12 #include <mpc83xx.h>
     13 #include <watchdog.h>
     14 #include <asm/io.h>
     15 #include <post.h>
     16 
     17 #if CONFIG_POST & CONFIG_SYS_POST_ECC
     18 /*
     19  * We use the RAW I/O accessors where possible in order to
     20  * achieve performance goal, since the test's execution time
     21  * affects the board start up time.
     22  */
     23 static inline void ecc_clear(ddr83xx_t *ddr)
     24 {
     25 	/* Clear capture registers */
     26 	__raw_writel(0, &ddr->capture_address);
     27 	__raw_writel(0, &ddr->capture_data_hi);
     28 	__raw_writel(0, &ddr->capture_data_lo);
     29 	__raw_writel(0, &ddr->capture_ecc);
     30 	__raw_writel(0, &ddr->capture_attributes);
     31 
     32 	/* Clear SBEC and set SBET to 1 */
     33 	out_be32(&ddr->err_sbe, 1 << ECC_ERROR_MAN_SBET_SHIFT);
     34 
     35 	/* Clear Error Detect register */
     36 	out_be32(&ddr->err_detect, ECC_ERROR_DETECT_MME |\
     37 			ECC_ERROR_DETECT_MBE |\
     38 			ECC_ERROR_DETECT_SBE |\
     39 			ECC_ERROR_DETECT_MSE);
     40 
     41 	isync();
     42 }
     43 
     44 int ecc_post_test(int flags)
     45 {
     46 	int ret = 0;
     47 	int int_state;
     48 	int errbit;
     49 	u32 pattern[2], writeback[2], retval[2];
     50 	ddr83xx_t *ddr = &((immap_t *)CONFIG_SYS_IMMR)->ddr;
     51 	volatile u64 *addr = (u64 *)CONFIG_SYS_POST_ECC_START_ADDR;
     52 
     53 	/* The pattern is written into memory to generate error */
     54 	pattern[0] = 0xfedcba98UL;
     55 	pattern[1] = 0x76543210UL;
     56 
     57 	/* After injecting error, re-initialize the memory with the value */
     58 	writeback[0] = ~pattern[0];
     59 	writeback[1] = ~pattern[1];
     60 
     61 	/* Check if ECC is enabled */
     62 	if (__raw_readl(&ddr->err_disable) & ECC_ERROR_ENABLE) {
     63 		debug("DDR's ECC is not enabled, skipping the ECC POST.\n");
     64 		return 0;
     65 	}
     66 
     67 	int_state = disable_interrupts();
     68 	icache_enable();
     69 
     70 #ifdef CONFIG_DDR_32BIT
     71 	/* It seems like no one really uses the CONFIG_DDR_32BIT mode */
     72 #error "Add ECC POST support for CONFIG_DDR_32BIT here!"
     73 #else
     74 	for (addr = (u64*)CONFIG_SYS_POST_ECC_START_ADDR, errbit=0;
     75 	     addr < (u64*)CONFIG_SYS_POST_ECC_STOP_ADDR; addr++, errbit++ ) {
     76 
     77 		WATCHDOG_RESET();
     78 
     79 		ecc_clear(ddr);
     80 
     81 		/* Enable error injection */
     82 		setbits_be32(&ddr->ecc_err_inject, ECC_ERR_INJECT_EIEN);
     83 		sync();
     84 		isync();
     85 
     86 		/* Set bit to be injected */
     87 		if (errbit < 32) {
     88 			__raw_writel(1 << errbit, &ddr->data_err_inject_lo);
     89 			__raw_writel(0, &ddr->data_err_inject_hi);
     90 		} else {
     91 			__raw_writel(0, &ddr->data_err_inject_lo);
     92 			__raw_writel(1<<(errbit-32), &ddr->data_err_inject_hi);
     93 		}
     94 		sync();
     95 		isync();
     96 
     97 		/* Write memory location injecting SBE */
     98 		ppcDWstore((u32*)addr, pattern);
     99 		sync();
    100 
    101 		/* Disable error injection */
    102 		clrbits_be32(&ddr->ecc_err_inject, ECC_ERR_INJECT_EIEN);
    103 		sync();
    104 		isync();
    105 
    106 		/* Data read should generate SBE */
    107 		ppcDWload((u32*)addr, retval);
    108 		sync();
    109 
    110 		if (!(__raw_readl(&ddr->err_detect) & ECC_ERROR_DETECT_SBE) ||
    111 			(__raw_readl(&ddr->data_err_inject_hi) !=
    112 			(__raw_readl(&ddr->capture_data_hi) ^ pattern[0])) ||
    113 			(__raw_readl(&ddr->data_err_inject_lo) !=
    114 			(__raw_readl(&ddr->capture_data_lo) ^ pattern[1]))) {
    115 
    116 			post_log("ECC failed to detect SBE error at %08x, "
    117 				"SBE injection mask %08x-%08x, wrote "
    118 				"%08x-%08x, read %08x-%08x\n", addr,
    119 				ddr->data_err_inject_hi,
    120 				ddr->data_err_inject_lo,
    121 				pattern[0], pattern[1],
    122 				retval[0], retval[1]);
    123 
    124 			printf("ERR_DETECT Reg: %08x\n", ddr->err_detect);
    125 			printf("ECC CAPTURE_DATA Reg: %08x-%08x\n",
    126 				ddr->capture_data_hi, ddr->capture_data_lo);
    127 			ret = 1;
    128 			break;
    129 		}
    130 
    131 		/* Re-initialize the ECC memory */
    132 		ppcDWstore((u32*)addr, writeback);
    133 		sync();
    134 		isync();
    135 
    136 		errbit %= 63;
    137 	}
    138 #endif /* !CONFIG_DDR_32BIT */
    139 
    140 	ecc_clear(ddr);
    141 
    142 	icache_disable();
    143 
    144 	if (int_state)
    145 		enable_interrupts();
    146 
    147 	return ret;
    148 }
    149 #endif
    150