aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Roese <sr@denx.de>2007-03-01 21:11:36 +0100
committerStefan Roese <sr@denx.de>2007-03-01 21:11:36 +0100
commitba58e4c9a9a917ce795dd16d4ec8d515f9f7aa35 (patch)
tree1870475942be67d0516fc69095731bee3f925a99
parent6c7cac8c4fce0ea2bf8e15ed8658d87974155b44 (diff)
downloadu-boot-midas-ba58e4c9a9a917ce795dd16d4ec8d515f9f7aa35.tar.gz
u-boot-midas-ba58e4c9a9a917ce795dd16d4ec8d515f9f7aa35.tar.bz2
u-boot-midas-ba58e4c9a9a917ce795dd16d4ec8d515f9f7aa35.zip
[PATCH] Update AMCC Katmai 440SPe eval board support
This patch updates the recently added Katmai board support. The biggest change is the support of ECC DIMM modules in the 440SP(e) SPD DDR2 driver. Please note, that still some problems are left with some memory configurations. See the driver for more details. Signed-off-by: Stefan Roese <sr@denx.de>
-rw-r--r--board/amcc/katmai/katmai.c35
-rw-r--r--board/amcc/katmai/katmai.h65
-rw-r--r--cpu/ppc4xx/44x_spd_ddr2.c375
-rw-r--r--cpu/ppc4xx/start.S43
-rw-r--r--cpu/ppc4xx/tlb.c4
-rw-r--r--include/configs/katmai.h21
-rw-r--r--include/ppc440.h6
7 files changed, 369 insertions, 180 deletions
diff --git a/board/amcc/katmai/katmai.c b/board/amcc/katmai/katmai.c
index 8704925a9c..fbf1a98ab3 100644
--- a/board/amcc/katmai/katmai.c
+++ b/board/amcc/katmai/katmai.c
@@ -28,7 +28,6 @@
#include <i2c.h>
#include <asm-ppc/io.h>
-#include "katmai.h"
#include "../cpu/ppc4xx/440spe_pcie.h"
#undef PCIE_ENDPOINT
@@ -40,7 +39,6 @@ void ppc440spe_setup_pcie(struct pci_controller *hose, int port);
int board_early_init_f (void)
{
unsigned long mfr;
- unsigned long pfc;
/*----------------------------------------------------------------------+
* Interrupt controller setup for the Katmai 440SPe Evaluation board.
@@ -228,15 +226,11 @@ int board_early_init_f (void)
mfr &= ~SDR0_MFR_ECS_MASK;
/* mtsdr(sdr_mfr, mfr); */
- /*
- * Setup GPIO signalling per defines in katmai.h
- */
- pfc = PFC0_KATMAI;
- mtsdr(SDR0_PFC0, pfc);
+ mtsdr(SDR0_PFC0, CFG_PFC0);
- out32(GPIO0_OR_ADDR, GPIO_OR_KATMAI);
- out32(GPIO0_ODR_ADDR, GPIO_ODR_KATMAI);
- out32(GPIO0_TCR_ADDR, GPIO_TCR_KATMAI);
+ out32(GPIO0_OR, CFG_GPIO_OR);
+ out32(GPIO0_ODR, CFG_GPIO_ODR);
+ out32(GPIO0_TCR, CFG_GPIO_TCR);
return 0;
}
@@ -378,6 +372,23 @@ int is_pci_host(struct pci_controller *hose)
return 1;
}
+int katmai_pcie_card_present(int port)
+{
+ u32 val;
+
+ val = in32(GPIO0_IR);
+ switch (port) {
+ case 0:
+ return !(val & GPIO_VAL(CFG_GPIO_PCIE_PRESENT0));
+ case 1:
+ return !(val & GPIO_VAL(CFG_GPIO_PCIE_PRESENT1));
+ case 2:
+ return !(val & GPIO_VAL(CFG_GPIO_PCIE_PRESENT2));
+ default:
+ return 0;
+ }
+}
+
static struct pci_controller pcie_hose[3] = {{0},{0},{0}};
void pcie_setup_hoses(void)
@@ -391,6 +402,10 @@ void pcie_setup_hoses(void)
*/
bus = 1;
for (i = 0; i <= 2; i++) {
+ /* Check for katmai card presence */
+ if (!katmai_pcie_card_present(i))
+ continue;
+
#ifdef PCIE_ENDPOINT
if (ppc440spe_init_pcie_endport(i)) {
#else
diff --git a/board/amcc/katmai/katmai.h b/board/amcc/katmai/katmai.h
deleted file mode 100644
index 9d5b793f13..0000000000
--- a/board/amcc/katmai/katmai.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * (C) Copyright 2007
- * Stefan Roese, DENX Software Engineering, sr@denx.de.
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-#ifndef __KATMAI_H_
-#define __KATMAI_H_
-
-/*----------------------------------------------------------------------------
- * XX
- * XXXX XX XXX XXX XXXX
- * XX XX XX XX XX XX
- * XX XXX XX XX XX XX XX
- * XX XX XXXXX XX XX XX
- * XXXX XX XXXX XXXX
- * XXXX
- *
- * The 440SPe provices 32 bits of GPIO. By default all GPIO pins
- * are disabled, and must be explicitly enabled by setting a
- * bit in the SDR0_PFC0 indirect DCR. Each GPIO maps 1-to-1 with the
- * corresponding bit in the SDR0_PFC0 register (note that bit numbers
- * reflect the PowerPC convention where bit 0 is the most-significant
- * bit).
- *
- * Katmai specific:
- * RS232_RX_EN# is held HIGH during reset by hardware, keeping the
- * RS232_CTS, DSR & DCD signals coming from the MAX3411 (U26) in
- * Hi-Z condition. This prevents contention between the MAX3411 (U26)
- * and 74CBTLV3125PG (U2) during reset.
- *
- * RS232_RX_EN# is connected as GPIO pin 30. Once the processor
- * is released from reset, this pin must be configured as an output and
- * then driven high to enable the receive signals from the UART transciever.
- *----------------------------------------------------------------------------*/
-#define GPIO_ENABLE(gpio) (0x80000000 >> (gpio))
-
-#define PFC0_KATMAI GPIO_ENABLE(30)
-#define GPIO_OR_KATMAI GPIO_ENABLE(30) /* Drive all outputs low except GPIO 30 */
-#define GPIO_TCR_KATMAI GPIO_ENABLE(30)
-#define GPIO_ODR_KATMAI 0 /* Disable open drain for all outputs */
-
-#define GPIO0_OR_ADDR (CFG_PERIPHERAL_BASE + 0x700)
-#define GPIO0_TCR_ADDR (CFG_PERIPHERAL_BASE + 0x704)
-#define GPIO0_ODR_ADDR (CFG_PERIPHERAL_BASE + 0x718)
-#define GPIO0_IR_ADDR (CFG_PERIPHERAL_BASE + 0x71C)
-
-#endif /* __KATMAI_H_ */
diff --git a/cpu/ppc4xx/44x_spd_ddr2.c b/cpu/ppc4xx/44x_spd_ddr2.c
index 6cff3a2e1a..fe0f2b6ea4 100644
--- a/cpu/ppc4xx/44x_spd_ddr2.c
+++ b/cpu/ppc4xx/44x_spd_ddr2.c
@@ -34,6 +34,7 @@
#endif
#include <common.h>
+#include <command.h>
#include <ppc4xx.h>
#include <i2c.h>
#include <asm/io.h>
@@ -43,6 +44,9 @@
#if defined(CONFIG_SPD_EEPROM) && \
(defined(CONFIG_440SP) || defined(CONFIG_440SPE))
+/*-----------------------------------------------------------------------------+
+ * Defines
+ *-----------------------------------------------------------------------------*/
#ifndef TRUE
#define TRUE 1
#endif
@@ -63,17 +67,67 @@
#define MULDIV64(m1, m2, d) (u32)(((u64)(m1) * (u64)(m2)) / (u64)(d))
-#if defined(DEBUG)
-static void ppc440sp_sdram_register_dump(void);
-#endif
+#define CMD_NOP (7 << 19)
+#define CMD_PRECHARGE (2 << 19)
+#define CMD_REFRESH (1 << 19)
+#define CMD_EMR (0 << 19)
+#define CMD_READ (5 << 19)
+#define CMD_WRITE (4 << 19)
+
+#define SELECT_MR (0 << 16)
+#define SELECT_EMR (1 << 16)
+#define SELECT_EMR2 (2 << 16)
+#define SELECT_EMR3 (3 << 16)
+
+/* MR */
+#define DLL_RESET 0x00000100
+
+#define WRITE_RECOV_2 (1 << 9)
+#define WRITE_RECOV_3 (2 << 9)
+#define WRITE_RECOV_4 (3 << 9)
+#define WRITE_RECOV_5 (4 << 9)
+#define WRITE_RECOV_6 (5 << 9)
+
+#define BURST_LEN_4 0x00000002
+
+/* EMR */
+#define ODT_0_OHM 0x00000000
+#define ODT_50_OHM 0x00000044
+#define ODT_75_OHM 0x00000004
+#define ODT_150_OHM 0x00000040
+
+#define ODS_FULL 0x00000000
+#define ODS_REDUCED 0x00000002
+
+/* defines for ODT (On Die Termination) of the 440SP(e) DDR2 controller */
+#define ODT_EB0R (0x80000000 >> 8)
+#define ODT_EB0W (0x80000000 >> 7)
+#define CALC_ODT_R(n) (ODT_EB0R << (n << 1))
+#define CALC_ODT_W(n) (ODT_EB0W << (n << 1))
+#define CALC_ODT_RW(n) (CALC_ODT_R(n) | CALC_ODT_W(n))
-/*-----------------------------------------------------------------------------+
- * Defines
- *-----------------------------------------------------------------------------*/
/* Defines for the Read Cycle Delay test */
#define NUMMEMTESTS 8
#define NUMMEMWORDS 8
+#define CONFIG_ECC_ERROR_RESET /* test-only: see description below, at check_ecc() */
+
+/*
+ * This DDR2 setup code can dynamically setup the TLB entries for the DDR2 memory
+ * region. Right now the cache should still be disabled in U-Boot because of the
+ * EMAC driver, that need it's buffer descriptor to be located in non cached
+ * memory.
+ *
+ * If at some time this restriction doesn't apply anymore, just define
+ * CFG_ENABLE_SDRAM_CACHE in the board config file and this code should setup
+ * everything correctly.
+ */
+#ifdef CFG_ENABLE_SDRAM_CACHE
+#define MY_TLB_WORD2_I_ENABLE 0 /* enable caching on SDRAM */
+#else
+#define MY_TLB_WORD2_I_ENABLE TLB_WORD2_I_ENABLE /* disable caching on SDRAM */
+#endif
+
/* Private Structure Definitions */
/* enum only to ease code for cas latency setting */
@@ -89,7 +143,7 @@ typedef enum ddr_cas_id {
* Prototypes
*-----------------------------------------------------------------------------*/
static unsigned long sdram_memsize(void);
-void program_tlb(u32 start, u32 size);
+void program_tlb(u32 start, u32 size, u32 tlb_word2_i_value);
static void get_spd_info(unsigned long *dimm_populated,
unsigned char *iic0_dimm_addr,
unsigned long num_dimm_banks);
@@ -114,7 +168,8 @@ static void program_codt(unsigned long *dimm_populated,
static void program_mode(unsigned long *dimm_populated,
unsigned char *iic0_dimm_addr,
unsigned long num_dimm_banks,
- ddr_cas_id_t *selected_cas);
+ ddr_cas_id_t *selected_cas,
+ int *write_recovery);
static void program_tr(unsigned long *dimm_populated,
unsigned char *iic0_dimm_addr,
unsigned long num_dimm_banks);
@@ -130,22 +185,30 @@ static void program_copt1(unsigned long *dimm_populated,
static void program_initplr(unsigned long *dimm_populated,
unsigned char *iic0_dimm_addr,
unsigned long num_dimm_banks,
- ddr_cas_id_t selected_cas);
+ ddr_cas_id_t selected_cas,
+ int write_recovery);
static unsigned long is_ecc_enabled(void);
static void program_ecc(unsigned long *dimm_populated,
unsigned char *iic0_dimm_addr,
- unsigned long num_dimm_banks);
+ unsigned long num_dimm_banks,
+ unsigned long tlb_word2_i_value);
static void program_ecc_addr(unsigned long start_address,
- unsigned long num_bytes);
-
+ unsigned long num_bytes,
+ unsigned long tlb_word2_i_value);
+static void program_DQS_calibration(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
#ifdef HARD_CODED_DQS /* calibration test with hardvalues */
static void test(void);
#else
static void DQS_calibration_process(void);
#endif
-static void program_DQS_calibration(unsigned long *dimm_populated,
- unsigned char *iic0_dimm_addr,
- unsigned long num_dimm_banks);
+#if defined(DEBUG)
+static void ppc440sp_sdram_register_dump(void);
+#endif
+int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
+void dcbz_area(u32 start_address, u32 num_bytes);
+void dflush(void);
static u32 mfdcr_any(u32 dcr)
{
@@ -235,7 +298,7 @@ static unsigned long sdram_memsize(void)
&& ((mcopt2 & SDRAM_MCOPT2_SREN_MASK) == SDRAM_MCOPT2_SREN_EXIT)
&& ((mcstat & (SDRAM_MCSTAT_MIC_MASK | SDRAM_MCSTAT_SRMS_MASK))
== (SDRAM_MCSTAT_MIC_COMP | SDRAM_MCSTAT_SRMS_NOT_SF))) {
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < MAXBXCF; i++) {
mfsdram(SDRAM_MB0CF + (i << 2), mb0cf);
/* Banks enabled */
if ((mb0cf & SDRAM_BXCF_M_BE_MASK) == SDRAM_BXCF_M_BE_ENABLE) {
@@ -300,14 +363,15 @@ static unsigned long sdram_memsize(void)
*-----------------------------------------------------------------------------*/
long int initdram(int board_type)
{
+ unsigned char iic0_dimm_addr[] = SPD_EEPROM_ADDRESS;
unsigned char spd0[MAX_SPD_BYTES];
unsigned char spd1[MAX_SPD_BYTES];
unsigned char *dimm_spd[MAXDIMMS];
unsigned long dimm_populated[MAXDIMMS];
- unsigned char iic0_dimm_addr[MAXDIMMS];
unsigned long num_dimm_banks; /* on board dimm banks */
unsigned long val;
ddr_cas_id_t selected_cas;
+ int write_recovery;
unsigned long dram_size = 0;
num_dimm_banks = sizeof(iic0_dimm_addr);
@@ -319,15 +383,9 @@ long int initdram(int board_type)
dimm_spd[1] = spd1;
/*------------------------------------------------------------------
- * Set up an array of iic0 dimm addresses.
- *-----------------------------------------------------------------*/
- iic0_dimm_addr[0] = IIC0_DIMM0_ADDR;
- iic0_dimm_addr[1] = IIC0_DIMM1_ADDR;
-
- /*------------------------------------------------------------------
* Reset the DDR-SDRAM controller.
*-----------------------------------------------------------------*/
- mtsdr(SDR0_SRST, 0x00200000);
+ mtsdr(SDR0_SRST, (0x80000000 >> 10));
mtsdr(SDR0_SRST, 0x00000000);
/*
@@ -399,7 +457,8 @@ long int initdram(int board_type)
/*------------------------------------------------------------------
* Program SDRAM mode register.
*-----------------------------------------------------------------*/
- program_mode(dimm_populated, iic0_dimm_addr, num_dimm_banks, &selected_cas);
+ program_mode(dimm_populated, iic0_dimm_addr, num_dimm_banks,
+ &selected_cas, &write_recovery);
/*------------------------------------------------------------------
* Set the SDRAM Write Data/DM/DQS Clock Timing Reg
@@ -438,7 +497,7 @@ long int initdram(int board_type)
* Program Initialization preload registers.
*-----------------------------------------------------------------*/
program_initplr(dimm_populated, iic0_dimm_addr, num_dimm_banks,
- selected_cas);
+ selected_cas, write_recovery);
/*------------------------------------------------------------------
* Delay to ensure 200usec have elapsed since reset.
@@ -471,19 +530,17 @@ long int initdram(int board_type)
dram_size = sdram_memsize();
/* and program tlb entries for this size (dynamic) */
- program_tlb(0, dram_size);
+ program_tlb(0, dram_size, MY_TLB_WORD2_I_ENABLE);
-#if 1 /* TODO: ECC support will come later */
/*------------------------------------------------------------------
- * If ecc is enabled, initialize the parity bits.
+ * DQS calibration.
*-----------------------------------------------------------------*/
- program_ecc(dimm_populated, iic0_dimm_addr, num_dimm_banks);
-#endif
+ program_DQS_calibration(dimm_populated, iic0_dimm_addr, num_dimm_banks);
/*------------------------------------------------------------------
- * DQS calibration.
+ * If ecc is enabled, initialize the parity bits.
*-----------------------------------------------------------------*/
- program_DQS_calibration(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+ program_ecc(dimm_populated, iic0_dimm_addr, num_dimm_banks, MY_TLB_WORD2_I_ENABLE);
#ifdef DEBUG
ppc440sp_sdram_register_dump();
@@ -996,8 +1053,8 @@ static void program_codt(unsigned long *dimm_populated,
dimm_type = SDRAM_DDR1;
}
- total_rank += dimm_rank;
- total_dimm ++;
+ total_rank += dimm_rank;
+ total_dimm++;
if ((dimm_num == 0) && (total_dimm == 1))
firstSlot = TRUE;
else
@@ -1008,49 +1065,49 @@ static void program_codt(unsigned long *dimm_populated,
codt |= SDRAM_CODT_DQS_1_8_V_DDR2;
if ((total_dimm == 1) && (firstSlot == TRUE)) {
if (total_rank == 1) {
- codt |= 0x00800000;
- modt0 = 0x01000000;
+ codt |= CALC_ODT_R(0);
+ modt0 = CALC_ODT_W(0);
modt1 = 0x00000000;
modt2 = 0x00000000;
modt3 = 0x00000000;
}
if (total_rank == 2) {
- codt |= 0x02800000;
- modt0 = 0x06000000;
- modt1 = 0x01800000;
+ codt |= CALC_ODT_R(0) | CALC_ODT_R(1);
+ modt0 = CALC_ODT_W(0);
+ modt1 = CALC_ODT_W(0);
modt2 = 0x00000000;
modt3 = 0x00000000;
}
- } else {
+ } else if ((total_dimm == 1) && (firstSlot != TRUE)) {
if (total_rank == 1) {
- codt |= 0x00800000;
- modt0 = 0x01000000;
+ codt |= CALC_ODT_R(2);
+ modt0 = 0x00000000;
modt1 = 0x00000000;
- modt2 = 0x00000000;
+ modt2 = CALC_ODT_W(2);
modt3 = 0x00000000;
}
if (total_rank == 2) {
- codt |= 0x02800000;
- modt0 = 0x06000000;
- modt1 = 0x01800000;
- modt2 = 0x00000000;
- modt3 = 0x00000000;
+ codt |= CALC_ODT_R(2) | CALC_ODT_R(3);
+ modt0 = 0x00000000;
+ modt1 = 0x00000000;
+ modt2 = CALC_ODT_W(2);
+ modt3 = CALC_ODT_W(2);
}
}
if (total_dimm == 2) {
if (total_rank == 2) {
- codt |= 0x08800000;
- modt0 = 0x18000000;
+ codt |= CALC_ODT_R(0) | CALC_ODT_R(2);
+ modt0 = CALC_ODT_RW(2);
modt1 = 0x00000000;
- modt2 = 0x01800000;
+ modt2 = CALC_ODT_RW(0);
modt3 = 0x00000000;
}
if (total_rank == 4) {
- codt |= 0x2a800000;
- modt0 = 0x18000000;
- modt1 = 0x18000000;
- modt2 = 0x01800000;
- modt3 = 0x01800000;
+ codt |= CALC_ODT_R(0) | CALC_ODT_R(1) | CALC_ODT_R(2) | CALC_ODT_R(3);
+ modt0 = CALC_ODT_RW(2);
+ modt1 = 0x00000000;
+ modt2 = CALC_ODT_RW(0);
+ modt3 = 0x00000000;
}
}
} else {
@@ -1092,9 +1149,19 @@ static void program_codt(unsigned long *dimm_populated,
static void program_initplr(unsigned long *dimm_populated,
unsigned char *iic0_dimm_addr,
unsigned long num_dimm_banks,
- ddr_cas_id_t selected_cas)
+ ddr_cas_id_t selected_cas,
+ int write_recovery)
{
- unsigned long MR_CAS_value = 0;
+ u32 cas = 0;
+ u32 odt = 0;
+ u32 ods = 0;
+ u32 mr;
+ u32 wr;
+ u32 emr;
+ u32 emr2;
+ u32 emr3;
+ int dimm_num;
+ int total_dimm = 0;
/******************************************************
** Assumption: if more than one DIMM, all DIMMs are the same
@@ -1112,41 +1179,90 @@ static void program_initplr(unsigned long *dimm_populated,
mtsdram(SDRAM_INITPLR7, 0x81000062);
} else if ((dimm_populated[0] == SDRAM_DDR2) || (dimm_populated[1] == SDRAM_DDR2)) {
switch (selected_cas) {
- /*
- * The CAS latency is a field of the Mode Reg
- * that need to be set from caller input.
- * CAS bits in Mode Reg are starting at bit 4 at least for the Micron DDR2
- * this is the reason of the shift.
- */
case DDR_CAS_3:
- MR_CAS_value = 3 << 4;
+ cas = 3 << 4;
break;
case DDR_CAS_4:
- MR_CAS_value = 4 << 4;
+ cas = 4 << 4;
break;
case DDR_CAS_5:
- MR_CAS_value = 5 << 4;
+ cas = 5 << 4;
break;
default:
- printf("ERROR: ucode error on selected_cas value %d", (unsigned char)selected_cas);
+ printf("ERROR: ucode error on selected_cas value %d", selected_cas);
hang();
break;
}
- mtsdram(SDRAM_INITPLR0, 0xB5380000); /* NOP */
- mtsdram(SDRAM_INITPLR1, 0x82100400); /* precharge 8 DDR clock cycle */
- mtsdram(SDRAM_INITPLR2, 0x80820000); /* EMR2 */
- mtsdram(SDRAM_INITPLR3, 0x80830000); /* EMR3 */
- mtsdram(SDRAM_INITPLR4, 0x80810000); /* EMR DLL ENABLE */
- mtsdram(SDRAM_INITPLR5, 0x80800502 | MR_CAS_value); /* MR w/ DLL reset */
- mtsdram(SDRAM_INITPLR6, 0x82100400); /* precharge 8 DDR clock cycle */
- mtsdram(SDRAM_INITPLR7, 0x8a080000); /* Refresh 50 DDR clock cycle */
- mtsdram(SDRAM_INITPLR8, 0x8a080000); /* Refresh 50 DDR clock cycle */
- mtsdram(SDRAM_INITPLR9, 0x8a080000); /* Refresh 50 DDR clock cycle */
- mtsdram(SDRAM_INITPLR10, 0x8a080000); /* Refresh 50 DDR clock cycle */
- mtsdram(SDRAM_INITPLR11, 0x80800402 | MR_CAS_value); /* MR w/o DLL reset */
- mtsdram(SDRAM_INITPLR12, 0x80810380); /* EMR OCD Default */
- mtsdram(SDRAM_INITPLR13, 0x80810000); /* EMR OCD Exit */
+#if 0
+ /*
+ * ToDo - Still a problem with the write recovery:
+ * On the Corsair CM2X512-5400C4 module, setting write recovery
+ * in the INITPLR reg to the value calculated in program_mode()
+ * results in not correctly working DDR2 memory (crash after
+ * relocation).
+ *
+ * So for now, set the write recovery to 3. This seems to work
+ * on the Corair module too.
+ *
+ * 2007-03-01, sr
+ */
+ switch (write_recovery) {
+ case 3:
+ wr = WRITE_RECOV_3;
+ break;
+ case 4:
+ wr = WRITE_RECOV_4;
+ break;
+ case 5:
+ wr = WRITE_RECOV_5;
+ break;
+ case 6:
+ wr = WRITE_RECOV_6;
+ break;
+ default:
+ printf("ERROR: write recovery not support (%d)", write_recovery);
+ hang();
+ break;
+ }
+#else
+ wr = WRITE_RECOV_3; /* test-only, see description above */
+#endif
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++)
+ if (dimm_populated[dimm_num] != SDRAM_NONE)
+ total_dimm++;
+ if (total_dimm == 1) {
+ odt = ODT_150_OHM;
+ ods = ODS_FULL;
+ } else if (total_dimm == 2) {
+ odt = ODT_75_OHM;
+ ods = ODS_REDUCED;
+ } else {
+ printf("ERROR: Unsupported number of DIMM's (%d)", total_dimm);
+ hang();
+ }
+
+ mr = CMD_EMR | SELECT_MR | BURST_LEN_4 | wr | cas;
+ emr = CMD_EMR | SELECT_EMR | odt | ods;
+ emr2 = CMD_EMR | SELECT_EMR2;
+ emr3 = CMD_EMR | SELECT_EMR3;
+ mtsdram(SDRAM_INITPLR0, 0xB5000000 | CMD_NOP); /* NOP */
+ udelay(1000);
+ mtsdram(SDRAM_INITPLR1, 0x82000400 | CMD_PRECHARGE); /* precharge 8 DDR clock cycle */
+ mtsdram(SDRAM_INITPLR2, 0x80800000 | emr2); /* EMR2 */
+ mtsdram(SDRAM_INITPLR3, 0x80800000 | emr3); /* EMR3 */
+ mtsdram(SDRAM_INITPLR4, 0x80800000 | emr); /* EMR DLL ENABLE */
+ mtsdram(SDRAM_INITPLR5, 0x80800000 | mr | DLL_RESET); /* MR w/ DLL reset */
+ udelay(1000);
+ mtsdram(SDRAM_INITPLR6, 0x82000400 | CMD_PRECHARGE); /* precharge 8 DDR clock cycle */
+ mtsdram(SDRAM_INITPLR7, 0x8a000000 | CMD_REFRESH); /* Refresh 50 DDR clock cycle */
+ mtsdram(SDRAM_INITPLR8, 0x8a000000 | CMD_REFRESH); /* Refresh 50 DDR clock cycle */
+ mtsdram(SDRAM_INITPLR9, 0x8a000000 | CMD_REFRESH); /* Refresh 50 DDR clock cycle */
+ mtsdram(SDRAM_INITPLR10, 0x8a000000 | CMD_REFRESH); /* Refresh 50 DDR clock cycle */
+ mtsdram(SDRAM_INITPLR11, 0x80000000 | mr); /* MR w/o DLL reset */
+ mtsdram(SDRAM_INITPLR12, 0x80800380 | emr); /* EMR OCD Default */
+ mtsdram(SDRAM_INITPLR13, 0x80800000 | emr); /* EMR OCD Exit */
} else {
printf("ERROR: ucode error as unknown DDR type in program_initplr");
hang();
@@ -1161,7 +1277,8 @@ static void program_initplr(unsigned long *dimm_populated,
static void program_mode(unsigned long *dimm_populated,
unsigned char *iic0_dimm_addr,
unsigned long num_dimm_banks,
- ddr_cas_id_t *selected_cas)
+ ddr_cas_id_t *selected_cas,
+ int *write_recovery)
{
unsigned long dimm_num;
unsigned long sdram_ddr1;
@@ -1424,8 +1541,12 @@ static void program_mode(unsigned long *dimm_populated,
mmode |= SDRAM_MMODE_WR_DDR2_6_CYC;
break;
}
+ *write_recovery = t_wr_clk;
}
+ debug("CAS latency = %d\n", *selected_cas);
+ debug("Write recovery = %d\n", *write_recovery);
+
mtsdram(SDRAM_MMODE, mmode);
}
@@ -2017,7 +2138,8 @@ static unsigned long is_ecc_enabled(void)
*-----------------------------------------------------------------------------*/
static void program_ecc(unsigned long *dimm_populated,
unsigned char *iic0_dimm_addr,
- unsigned long num_dimm_banks)
+ unsigned long num_dimm_banks,
+ unsigned long tlb_word2_i_value)
{
unsigned long mcopt1;
unsigned long mcopt2;
@@ -2046,23 +2168,59 @@ static void program_ecc(unsigned long *dimm_populated,
&& ((mcstat & (SDRAM_MCSTAT_MIC_MASK | SDRAM_MCSTAT_SRMS_MASK))
== (SDRAM_MCSTAT_MIC_COMP | SDRAM_MCSTAT_SRMS_NOT_SF))) {
- program_ecc_addr(0, sdram_memsize());
+ program_ecc_addr(0, sdram_memsize(), tlb_word2_i_value);
}
}
return;
}
+#ifdef CONFIG_ECC_ERROR_RESET
+/*
+ * Check for ECC errors and reset board upon any error here
+ *
+ * On the Katmai 440SPe eval board, from time to time, the first
+ * lword write access after DDR2 initializazion with ECC checking
+ * enabled, leads to an ECC error. I couldn't find a configuration
+ * without this happening. On my board with the current setup it
+ * happens about 1 from 10 times.
+ *
+ * The ECC modules used for testing are:
+ * - Kingston ValueRAM KVR667D2E5/512 (tested with 1 and 2 DIMM's)
+ *
+ * This has to get fixed for the Katmai and tested for the other
+ * board (440SP/440SPe) that will eventually use this code in the
+ * future.
+ *
+ * 2007-03-01, sr
+ */
+static void check_ecc(void)
+{
+ u32 val;
+
+ mfsdram(SDRAM_ECCCR, val);
+ if (val != 0) {
+ printf("\nECC error: MCIF0_ECCES=%08lx MQ0_ESL=%08lx address=%08lx\n",
+ val, mfdcr(0x4c), mfdcr(0x4e));
+ printf("ECC error occured, resetting board...\n");
+ do_reset(NULL, 0, 0, NULL);
+ }
+}
+#endif
+
/*-----------------------------------------------------------------------------+
* program_ecc_addr.
*-----------------------------------------------------------------------------*/
static void program_ecc_addr(unsigned long start_address,
- unsigned long num_bytes)
+ unsigned long num_bytes,
+ unsigned long tlb_word2_i_value)
{
unsigned long current_address;
unsigned long end_address;
unsigned long address_increment;
unsigned long mcopt1;
+ char str[] = "ECC generation...";
+ int i;
current_address = start_address;
mfsdram(SDRAM_MCOPT1, mcopt1);
@@ -2073,26 +2231,49 @@ static void program_ecc_addr(unsigned long start_address,
eieio();
wait_ddr_idle();
- /* ECC bit set method for non-cached memory */
- if ((mcopt1 & SDRAM_MCOPT1_DMWD_MASK) == SDRAM_MCOPT1_DMWD_32)
- address_increment = 4;
- else
- address_increment = 8;
- end_address = current_address + num_bytes;
+ puts(str);
+ if (tlb_word2_i_value == TLB_WORD2_I_ENABLE) {
+ /* ECC bit set method for non-cached memory */
+ if ((mcopt1 & SDRAM_MCOPT1_DMWD_MASK) == SDRAM_MCOPT1_DMWD_32)
+ address_increment = 4;
+ else
+ address_increment = 8;
+ end_address = current_address + num_bytes;
- while (current_address < end_address) {
- *((unsigned long *)current_address) = 0x00000000;
- current_address += address_increment;
+ while (current_address < end_address) {
+ *((unsigned long *)current_address) = 0x00000000;
+ current_address += address_increment;
+ }
+ } else {
+ /* ECC bit set method for cached memory */
+ dcbz_area(start_address, num_bytes);
+ dflush();
}
+ for (i=0; i<strlen(str); i++)
+ putc('\b');
+
sync();
eieio();
wait_ddr_idle();
+ /* clear ECC error repoting registers */
+ mtsdram(SDRAM_ECCCR, 0xffffffff);
+ mtdcr(0x4c, 0xffffffff);
+
mtsdram(SDRAM_MCOPT1,
- (mcopt1 & ~SDRAM_MCOPT1_MCHK_MASK) | SDRAM_MCOPT1_MCHK_CHK);
+ (mcopt1 & ~SDRAM_MCOPT1_MCHK_MASK) | SDRAM_MCOPT1_MCHK_CHK_REP);
sync();
eieio();
wait_ddr_idle();
+
+#ifdef CONFIG_ECC_ERROR_RESET
+ /*
+ * One write to 0 is enough to trigger this ECC error
+ * (see description above)
+ */
+ out_be32(0, 0x12345678);
+ check_ecc();
+#endif
}
}
diff --git a/cpu/ppc4xx/start.S b/cpu/ppc4xx/start.S
index a3db93ffbb..cd2cceced9 100644
--- a/cpu/ppc4xx/start.S
+++ b/cpu/ppc4xx/start.S
@@ -1912,4 +1912,47 @@ pll_wait:
TLBRE(3,3,0)
blr
function_epilog(mftlb1)
+
+/*----------------------------------------------------------------------------+
+| dcbz_area.
++----------------------------------------------------------------------------*/
+ function_prolog(dcbz_area)
+ rlwinm. r5,r4,0,27,31
+ rlwinm r5,r4,27,5,31
+ beq ..d_ra2
+ addi r5,r5,0x0001
+..d_ra2:mtctr r5
+..d_ag2:dcbz r0,r3
+ addi r3,r3,32
+ bdnz ..d_ag2
+ sync
+ blr
+ function_epilog(dcbz_area)
+
+/*----------------------------------------------------------------------------+
+| dflush. Assume 32K at vector address is cachable.
++----------------------------------------------------------------------------*/
+ function_prolog(dflush)
+ mfmsr r9
+ rlwinm r8,r9,0,15,13
+ rlwinm r8,r8,0,17,15
+ mtmsr r8
+ addi r3,r0,0x0000
+ mtspr dvlim,r3
+ mfspr r3,ivpr
+ addi r4,r0,1024
+ mtctr r4
+..dflush_loop:
+ lwz r6,0x0(r3)
+ addi r3,r3,32
+ bdnz ..dflush_loop
+ addi r3,r3,-32
+ mtctr r4
+..ag: dcbf r0,r3
+ addi r3,r3,-32
+ bdnz ..ag
+ sync
+ mtmsr r9
+ blr
+ function_epilog(dflush)
#endif /* CONFIG_440 */
diff --git a/cpu/ppc4xx/tlb.c b/cpu/ppc4xx/tlb.c
index 8c605591b8..08ae76c3f4 100644
--- a/cpu/ppc4xx/tlb.c
+++ b/cpu/ppc4xx/tlb.c
@@ -166,13 +166,13 @@ static void program_tlb_addr(unsigned long base_addr, unsigned long mem_size,
* Common usage for boards with SDRAM DIMM modules to dynamically
* configure the TLB's for the SDRAM
*/
-void program_tlb(u32 start, u32 size)
+void program_tlb(u32 start, u32 size, u32 tlb_word2_i_value)
{
region_t region_array;
region_array.base = start;
region_array.size = size;
- region_array.tlb_word2_i_value = TLB_WORD2_I_ENABLE; /* disable cache (for now) */
+ region_array.tlb_word2_i_value = tlb_word2_i_value; /* en-/disable cache */
/* Call the routine to add in the tlb entries for the memory regions */
program_tlb_addr(region_array.base, region_array.size,
diff --git a/include/configs/katmai.h b/include/configs/katmai.h
index c750e14656..f350155c83 100644
--- a/include/configs/katmai.h
+++ b/include/configs/katmai.h
@@ -107,11 +107,8 @@
* DDR SDRAM
*----------------------------------------------------------------------*/
#define CONFIG_SPD_EEPROM 1 /* Use SPD EEPROM for setup */
-#define SPD_EEPROM_ADDRESS {0x51, 0x52} /* SPD i2c spd addresses */
-#define IIC0_DIMM0_ADDR 0x51
-#define IIC0_DIMM1_ADDR 0x52
+#define SPD_EEPROM_ADDRESS {0x51, 0x52} /* SPD i2c spd addresses*/
#undef CONFIG_STRESS
-#undef ENABLE_ECC
/*-----------------------------------------------------------------------
* I2C
@@ -384,6 +381,22 @@
EBC_CFG_PME_DISABLE | \
EBC_CFG_PR_16)
+/*-----------------------------------------------------------------------
+ * GPIO Setup
+ *----------------------------------------------------------------------*/
+#define CFG_GPIO_PCIE_PRESENT0 17
+#define CFG_GPIO_PCIE_PRESENT1 21
+#define CFG_GPIO_PCIE_PRESENT2 23
+#define CFG_GPIO_RS232_FORCEOFF 30
+
+#define CFG_PFC0 (GPIO_VAL(CFG_GPIO_PCIE_PRESENT0) | \
+ GPIO_VAL(CFG_GPIO_PCIE_PRESENT1) | \
+ GPIO_VAL(CFG_GPIO_PCIE_PRESENT2) | \
+ GPIO_VAL(CFG_GPIO_RS232_FORCEOFF))
+#define CFG_GPIO_OR GPIO_VAL(CFG_GPIO_RS232_FORCEOFF)
+#define CFG_GPIO_TCR GPIO_VAL(CFG_GPIO_RS232_FORCEOFF)
+#define CFG_GPIO_ODR 0
+
/*
* For booting Linux, the board info and command line data
* have to be in the first 8 MB of memory, since this is
diff --git a/include/ppc440.h b/include/ppc440.h
index c24f5b7ab1..1c7f11c488 100644
--- a/include/ppc440.h
+++ b/include/ppc440.h
@@ -3190,7 +3190,8 @@
#define GPIO0 0
#define GPIO1 1
-#if defined(CONFIG_440GP) || defined(CONFIG_440GX)
+#if defined(CONFIG_440GP) || defined(CONFIG_440GX) || \
+ defined(CONFIG_440SP) || defined(CONFIG_440SPE)
#define GPIO0_BASE (CFG_PERIPHERAL_BASE+0x00000700)
#define GPIO0_OR (GPIO0_BASE+0x0)
@@ -3275,6 +3276,8 @@
#define GPIO_IN_SEL 0x40000000 /* GPIO_IN value put in GPIO_ISx for the GPIO nb 0 */
/* For the other GPIO number, you must shift */
+#define GPIO_VAL(gpio) (0x80000000 >> (gpio))
+
#ifndef __ASSEMBLY__
typedef enum gpio_select { GPIO_SEL, GPIO_ALT1, GPIO_ALT2, GPIO_ALT3 } gpio_select_t;
@@ -3285,7 +3288,6 @@ typedef struct { unsigned long add; /* gpio core base address */
gpio_select_t alt_nb; /* Selected Alternate */
} gpio_param_s;
-
#endif /* __ASSEMBLY__ */
/*