summaryrefslogtreecommitdiff
path: root/cpu/ppc4xx
diff options
context:
space:
mode:
Diffstat (limited to 'cpu/ppc4xx')
-rw-r--r--cpu/ppc4xx/405gp_pci.c6
-rw-r--r--cpu/ppc4xx/40x_spd_sdram.c469
-rw-r--r--cpu/ppc4xx/440spe_pcie.c8
-rw-r--r--cpu/ppc4xx/44x_spd_ddr.c (renamed from cpu/ppc4xx/spd_sdram.c)450
-rw-r--r--cpu/ppc4xx/44x_spd_ddr2.c2954
-rw-r--r--cpu/ppc4xx/4xx_enet.c172
-rw-r--r--cpu/ppc4xx/Makefile4
-rw-r--r--cpu/ppc4xx/cpu.c104
-rw-r--r--cpu/ppc4xx/cpu_init.c20
-rw-r--r--cpu/ppc4xx/i2c.c458
-rw-r--r--cpu/ppc4xx/ndfc.c3
-rw-r--r--cpu/ppc4xx/sdram.c41
-rw-r--r--cpu/ppc4xx/serial.c97
-rw-r--r--cpu/ppc4xx/speed.c127
-rw-r--r--cpu/ppc4xx/start.S179
-rw-r--r--cpu/ppc4xx/tlb.c184
-rw-r--r--cpu/ppc4xx/usb_ohci.c6
-rw-r--r--cpu/ppc4xx/vecnum.h42
18 files changed, 4516 insertions, 808 deletions
diff --git a/cpu/ppc4xx/405gp_pci.c b/cpu/ppc4xx/405gp_pci.c
index 03128d3..7134355 100644
--- a/cpu/ppc4xx/405gp_pci.c
+++ b/cpu/ppc4xx/405gp_pci.c
@@ -380,7 +380,7 @@ void pci_405gp_setup_vga(struct pci_controller *hose, pci_dev_t dev,
pci_hose_write_config_dword(hose, dev, PCI_COMMAND, cmdstat);
}
-#if !(defined(CONFIG_PIP405) || defined (CONFIG_MIP405))
+#if !(defined(CONFIG_PIP405) || defined (CONFIG_MIP405)) && !(defined (CONFIG_SOLIDCARD3))
/*
*As is these functs get called out of flash Not a horrible
@@ -475,7 +475,11 @@ void pci_440_init (struct pci_controller *hose)
pci_set_region(hose->regions + reg_num++,
CFG_PCI_TARGBASE,
CFG_PCI_MEMBASE,
+#ifdef CFG_PCI_MEMSIZE
+ CFG_PCI_MEMSIZE,
+#else
0x10000000,
+#endif
PCI_REGION_MEM );
#if defined(CONFIG_PCI_SYS_MEM_BUS) && defined(CONFIG_PCI_SYS_MEM_PHYS) && \
diff --git a/cpu/ppc4xx/40x_spd_sdram.c b/cpu/ppc4xx/40x_spd_sdram.c
new file mode 100644
index 0000000..19c4f76
--- /dev/null
+++ b/cpu/ppc4xx/40x_spd_sdram.c
@@ -0,0 +1,469 @@
+/*
+ * cpu/ppc4xx/40x_spd_sdram.c
+ * This SPD SDRAM detection code supports IBM/AMCC PPC44x cpu with a
+ * SDRAM controller. Those are all current 405 PPC's.
+ *
+ * (C) Copyright 2001
+ * Bill Hunter, Wave 7 Optics, williamhunter@attbi.com
+ *
+ * Based on code by:
+ *
+ * Kenneth Johansson ,Ericsson AB.
+ * kenneth.johansson@etx.ericsson.se
+ *
+ * hacked up by bill hunter. fixed so we could run before
+ * serial_init and console_init. previous version avoided this by
+ * running out of cache memory during serial/console init, then running
+ * this code later.
+ *
+ * (C) Copyright 2002
+ * Jun Gu, Artesyn Technology, jung@artesyncp.com
+ * Support for AMCC 440 based on OpenBIOS draminit.c from IBM.
+ *
+ * (C) Copyright 2005
+ * 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
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <i2c.h>
+#include <ppc4xx.h>
+
+#if defined(CONFIG_SPD_EEPROM) && !defined(CONFIG_440)
+
+/*
+ * Set default values
+ */
+#ifndef CFG_I2C_SPEED
+#define CFG_I2C_SPEED 50000
+#endif
+
+#ifndef CFG_I2C_SLAVE
+#define CFG_I2C_SLAVE 0xFE
+#endif
+
+#define ONE_BILLION 1000000000
+
+#define SDRAM0_CFG_DCE 0x80000000
+#define SDRAM0_CFG_SRE 0x40000000
+#define SDRAM0_CFG_PME 0x20000000
+#define SDRAM0_CFG_MEMCHK 0x10000000
+#define SDRAM0_CFG_REGEN 0x08000000
+#define SDRAM0_CFG_ECCDD 0x00400000
+#define SDRAM0_CFG_EMDULR 0x00200000
+#define SDRAM0_CFG_DRW_SHIFT (31-6)
+#define SDRAM0_CFG_BRPF_SHIFT (31-8)
+
+#define SDRAM0_TR_CASL_SHIFT (31-8)
+#define SDRAM0_TR_PTA_SHIFT (31-13)
+#define SDRAM0_TR_CTP_SHIFT (31-15)
+#define SDRAM0_TR_LDF_SHIFT (31-17)
+#define SDRAM0_TR_RFTA_SHIFT (31-29)
+#define SDRAM0_TR_RCD_SHIFT (31-31)
+
+#define SDRAM0_RTR_SHIFT (31-15)
+#define SDRAM0_ECCCFG_SHIFT (31-11)
+
+/* SDRAM0_CFG enable macro */
+#define SDRAM0_CFG_BRPF(x) ( ( x & 0x3)<< SDRAM0_CFG_BRPF_SHIFT )
+
+#define SDRAM0_BXCR_SZ_MASK 0x000e0000
+#define SDRAM0_BXCR_AM_MASK 0x0000e000
+
+#define SDRAM0_BXCR_SZ_SHIFT (31-14)
+#define SDRAM0_BXCR_AM_SHIFT (31-18)
+
+#define SDRAM0_BXCR_SZ(x) ( (( x << SDRAM0_BXCR_SZ_SHIFT) & SDRAM0_BXCR_SZ_MASK) )
+#define SDRAM0_BXCR_AM(x) ( (( x << SDRAM0_BXCR_AM_SHIFT) & SDRAM0_BXCR_AM_MASK) )
+
+#ifdef CONFIG_SPDDRAM_SILENT
+# define SPD_ERR(x) do { return 0; } while (0)
+#else
+# define SPD_ERR(x) do { printf(x); return(0); } while (0)
+#endif
+
+#define sdram_HZ_to_ns(hertz) (1000000000/(hertz))
+
+/* function prototypes */
+int spd_read(uint addr);
+
+
+/*
+ * This function is reading data from the DIMM module EEPROM over the SPD bus
+ * and uses that to program the sdram controller.
+ *
+ * This works on boards that has the same schematics that the AMCC walnut has.
+ *
+ * Input: null for default I2C spd functions or a pointer to a custom function
+ * returning spd_data.
+ */
+
+long int spd_sdram(int(read_spd)(uint addr))
+{
+ int tmp,row,col;
+ int total_size,bank_size,bank_code;
+ int ecc_on;
+ int mode;
+ int bank_cnt;
+
+ int sdram0_pmit=0x07c00000;
+#ifndef CONFIG_405EP /* not on PPC405EP */
+ int sdram0_besr0=-1;
+ int sdram0_besr1=-1;
+ int sdram0_eccesr=-1;
+#endif
+ int sdram0_ecccfg;
+
+ int sdram0_rtr=0;
+ int sdram0_tr=0;
+
+ int sdram0_b0cr;
+ int sdram0_b1cr;
+ int sdram0_b2cr;
+ int sdram0_b3cr;
+
+ int sdram0_cfg=0;
+
+ int t_rp;
+ int t_rcd;
+ int t_ras;
+ int t_rc;
+ int min_cas;
+
+ PPC405_SYS_INFO sys_info;
+ unsigned long bus_period_x_10;
+
+ /*
+ * get the board info
+ */
+ get_sys_info(&sys_info);
+ bus_period_x_10 = ONE_BILLION / (sys_info.freqPLB / 10);
+
+ if (read_spd == 0){
+ read_spd=spd_read;
+ /*
+ * Make sure I2C controller is initialized
+ * before continuing.
+ */
+ i2c_init(CFG_I2C_SPEED, CFG_I2C_SLAVE);
+ }
+
+ /* Make shure we are using SDRAM */
+ if (read_spd(2) != 0x04) {
+ SPD_ERR("SDRAM - non SDRAM memory module found\n");
+ }
+
+ /* ------------------------------------------------------------------
+ * configure memory timing register
+ *
+ * data from DIMM:
+ * 27 IN Row Precharge Time ( t RP)
+ * 29 MIN RAS to CAS Delay ( t RCD)
+ * 127 Component and Clock Detail ,clk0-clk3, junction temp, CAS
+ * -------------------------------------------------------------------*/
+
+ /*
+ * first figure out which cas latency mode to use
+ * use the min supported mode
+ */
+
+ tmp = read_spd(127) & 0x6;
+ if (tmp == 0x02) { /* only cas = 2 supported */
+ min_cas = 2;
+/* t_ck = read_spd(9); */
+/* t_ac = read_spd(10); */
+ } else if (tmp == 0x04) { /* only cas = 3 supported */
+ min_cas = 3;
+/* t_ck = read_spd(9); */
+/* t_ac = read_spd(10); */
+ } else if (tmp == 0x06) { /* 2,3 supported, so use 2 */
+ min_cas = 2;
+/* t_ck = read_spd(23); */
+/* t_ac = read_spd(24); */
+ } else {
+ SPD_ERR("SDRAM - unsupported CAS latency \n");
+ }
+
+ /* get some timing values, t_rp,t_rcd,t_ras,t_rc
+ */
+ t_rp = read_spd(27);
+ t_rcd = read_spd(29);
+ t_ras = read_spd(30);
+ t_rc = t_ras + t_rp;
+
+ /* The following timing calcs subtract 1 before deviding.
+ * this has effect of using ceiling instead of floor rounding,
+ * and also subtracting 1 to convert number to reg value
+ */
+ /* set up CASL */
+ sdram0_tr = (min_cas - 1) << SDRAM0_TR_CASL_SHIFT;
+ /* set up PTA */
+ sdram0_tr |= ((((t_rp - 1) * 10)/bus_period_x_10) & 0x3) << SDRAM0_TR_PTA_SHIFT;
+ /* set up CTP */
+ tmp = (((t_rc - t_rcd - t_rp -1) * 10) / bus_period_x_10) & 0x3;
+ if (tmp < 1)
+ tmp = 1;
+ sdram0_tr |= tmp << SDRAM0_TR_CTP_SHIFT;
+ /* set LDF = 2 cycles, reg value = 1 */
+ sdram0_tr |= 1 << SDRAM0_TR_LDF_SHIFT;
+ /* set RFTA = t_rfc/bus_period, use t_rfc = t_rc */
+ tmp = (((t_rc - 1) * 10) / bus_period_x_10) - 3;
+ if (tmp < 0)
+ tmp = 0;
+ if (tmp > 6)
+ tmp = 6;
+ sdram0_tr |= tmp << SDRAM0_TR_RFTA_SHIFT;
+ /* set RCD = t_rcd/bus_period*/
+ sdram0_tr |= ((((t_rcd - 1) * 10) / bus_period_x_10) &0x3) << SDRAM0_TR_RCD_SHIFT ;
+
+
+ /*------------------------------------------------------------------
+ * configure RTR register
+ * -------------------------------------------------------------------*/
+ row = read_spd(3);
+ col = read_spd(4);
+ tmp = read_spd(12) & 0x7f ; /* refresh type less self refresh bit */
+ switch (tmp) {
+ case 0x00:
+ tmp = 15625;
+ break;
+ case 0x01:
+ tmp = 15625 / 4;
+ break;
+ case 0x02:
+ tmp = 15625 / 2;
+ break;
+ case 0x03:
+ tmp = 15625 * 2;
+ break;
+ case 0x04:
+ tmp = 15625 * 4;
+ break;
+ case 0x05:
+ tmp = 15625 * 8;
+ break;
+ default:
+ SPD_ERR("SDRAM - Bad refresh period \n");
+ }
+ /* convert from nsec to bus cycles */
+ tmp = (tmp * 10) / bus_period_x_10;
+ sdram0_rtr = (tmp & 0x3ff8) << SDRAM0_RTR_SHIFT;
+
+ /*------------------------------------------------------------------
+ * determine the number of banks used
+ * -------------------------------------------------------------------*/
+ /* byte 7:6 is module data width */
+ if (read_spd(7) != 0)
+ SPD_ERR("SDRAM - unsupported module width\n");
+ tmp = read_spd(6);
+ if (tmp < 32)
+ SPD_ERR("SDRAM - unsupported module width\n");
+ else if (tmp < 64)
+ bank_cnt = 1; /* one bank per sdram side */
+ else if (tmp < 73)
+ bank_cnt = 2; /* need two banks per side */
+ else if (tmp < 161)
+ bank_cnt = 4; /* need four banks per side */
+ else
+ SPD_ERR("SDRAM - unsupported module width\n");
+
+ /* byte 5 is the module row count (refered to as dimm "sides") */
+ tmp = read_spd(5);
+ if (tmp == 1)
+ ;
+ else if (tmp==2)
+ bank_cnt *= 2;
+ else if (tmp==4)
+ bank_cnt *= 4;
+ else
+ bank_cnt = 8; /* 8 is an error code */
+
+ if (bank_cnt > 4) /* we only have 4 banks to work with */
+ SPD_ERR("SDRAM - unsupported module rows for this width\n");
+
+ /* now check for ECC ability of module. We only support ECC
+ * on 32 bit wide devices with 8 bit ECC.
+ */
+ if ((read_spd(11)==2) && (read_spd(6)==40) && (read_spd(14)==8)) {
+ sdram0_ecccfg = 0xf << SDRAM0_ECCCFG_SHIFT;
+ ecc_on = 1;
+ } else {
+ sdram0_ecccfg = 0;
+ ecc_on = 0;
+ }
+
+ /*------------------------------------------------------------------
+ * calculate total size
+ * -------------------------------------------------------------------*/
+ /* calculate total size and do sanity check */
+ tmp = read_spd(31);
+ total_size = 1 << 22; /* total_size = 4MB */
+ /* now multiply 4M by the smallest device row density */
+ /* note that we don't support asymetric rows */
+ while (((tmp & 0x0001) == 0) && (tmp != 0)) {
+ total_size = total_size << 1;
+ tmp = tmp >> 1;
+ }
+ total_size *= read_spd(5); /* mult by module rows (dimm sides) */
+
+ /*------------------------------------------------------------------
+ * map rows * cols * banks to a mode
+ * -------------------------------------------------------------------*/
+
+ switch (row) {
+ case 11:
+ switch (col) {
+ case 8:
+ mode=4; /* mode 5 */
+ break;
+ case 9:
+ case 10:
+ mode=0; /* mode 1 */
+ break;
+ default:
+ SPD_ERR("SDRAM - unsupported mode\n");
+ }
+ break;
+ case 12:
+ switch (col) {
+ case 8:
+ mode=3; /* mode 4 */
+ break;
+ case 9:
+ case 10:
+ mode=1; /* mode 2 */
+ break;
+ default:
+ SPD_ERR("SDRAM - unsupported mode\n");
+ }
+ break;
+ case 13:
+ switch (col) {
+ case 8:
+ mode=5; /* mode 6 */
+ break;
+ case 9:
+ case 10:
+ if (read_spd(17) == 2)
+ mode = 6; /* mode 7 */
+ else
+ mode = 2; /* mode 3 */
+ break;
+ case 11:
+ mode = 2; /* mode 3 */
+ break;
+ default:
+ SPD_ERR("SDRAM - unsupported mode\n");
+ }
+ break;
+ default:
+ SPD_ERR("SDRAM - unsupported mode\n");
+ }
+
+ /*------------------------------------------------------------------
+ * using the calculated values, compute the bank
+ * config register values.
+ * -------------------------------------------------------------------*/
+ sdram0_b1cr = 0;
+ sdram0_b2cr = 0;
+ sdram0_b3cr = 0;
+
+ /* compute the size of each bank */
+ bank_size = total_size / bank_cnt;
+ /* convert bank size to bank size code for ppc4xx
+ by takeing log2(bank_size) - 22 */
+ tmp = bank_size; /* start with tmp = bank_size */
+ bank_code = 0; /* and bank_code = 0 */
+ while (tmp > 1) { /* this takes log2 of tmp */
+ bank_code++; /* and stores result in bank_code */
+ tmp = tmp >> 1;
+ } /* bank_code is now log2(bank_size) */
+ bank_code -= 22; /* subtract 22 to get the code */
+
+ tmp = SDRAM0_BXCR_SZ(bank_code) | SDRAM0_BXCR_AM(mode) | 1;
+ sdram0_b0cr = (bank_size * 0) | tmp;
+#ifndef CONFIG_405EP /* not on PPC405EP */
+ if (bank_cnt > 1)
+ sdram0_b2cr = (bank_size * 1) | tmp;
+ if (bank_cnt > 2)
+ sdram0_b1cr = (bank_size * 2) | tmp;
+ if (bank_cnt > 3)
+ sdram0_b3cr = (bank_size * 3) | tmp;
+#else
+ /* PPC405EP chip only supports two SDRAM banks */
+ if (bank_cnt > 1)
+ sdram0_b1cr = (bank_size * 1) | tmp;
+ if (bank_cnt > 2)
+ total_size = 2 * bank_size;
+#endif
+
+ /*
+ * enable sdram controller DCE=1
+ * enable burst read prefetch to 32 bytes BRPF=2
+ * leave other functions off
+ */
+
+ /*------------------------------------------------------------------
+ * now that we've done our calculations, we are ready to
+ * program all the registers.
+ * -------------------------------------------------------------------*/
+
+#define mtsdram0(reg, data) mtdcr(memcfga,reg);mtdcr(memcfgd,data)
+ /* disable memcontroller so updates work */
+ mtsdram0( mem_mcopt1, 0 );
+
+#ifndef CONFIG_405EP /* not on PPC405EP */
+ mtsdram0( mem_besra , sdram0_besr0 );
+ mtsdram0( mem_besrb , sdram0_besr1 );
+ mtsdram0( mem_ecccf , sdram0_ecccfg );
+ mtsdram0( mem_eccerr, sdram0_eccesr );
+#endif
+ mtsdram0( mem_rtr , sdram0_rtr );
+ mtsdram0( mem_pmit , sdram0_pmit );
+ mtsdram0( mem_mb0cf , sdram0_b0cr );
+ mtsdram0( mem_mb1cf , sdram0_b1cr );
+#ifndef CONFIG_405EP /* not on PPC405EP */
+ mtsdram0( mem_mb2cf , sdram0_b2cr );
+ mtsdram0( mem_mb3cf , sdram0_b3cr );
+#endif
+ mtsdram0( mem_sdtr1 , sdram0_tr );
+
+ /* SDRAM have a power on delay, 500 micro should do */
+ udelay(500);
+ sdram0_cfg = SDRAM0_CFG_DCE | SDRAM0_CFG_BRPF(1) | SDRAM0_CFG_ECCDD | SDRAM0_CFG_EMDULR;
+ if (ecc_on)
+ sdram0_cfg |= SDRAM0_CFG_MEMCHK;
+ mtsdram0(mem_mcopt1, sdram0_cfg);
+
+ return (total_size);
+}
+
+int spd_read(uint addr)
+{
+ uchar data[2];
+
+ if (i2c_read(SPD_EEPROM_ADDRESS, addr, 1, data, 1) == 0)
+ return (int)data[0];
+ else
+ return 0;
+}
+
+#endif /* CONFIG_SPD_EEPROM */
diff --git a/cpu/ppc4xx/440spe_pcie.c b/cpu/ppc4xx/440spe_pcie.c
index 6130cd2..d6c4be5 100644
--- a/cpu/ppc4xx/440spe_pcie.c
+++ b/cpu/ppc4xx/440spe_pcie.c
@@ -26,10 +26,9 @@
#include <common.h>
#include <pci.h>
-#include "440spe_pcie.h"
+#if defined(CONFIG_440SPE) && defined(CONFIG_PCI)
-#if defined(CONFIG_440SPE)
-#if defined(CONFIG_PCI)
+#include "440spe_pcie.h"
enum {
PTYPE_ENDPOINT = 0x0,
@@ -958,5 +957,4 @@ int ppc440spe_setup_pcie_endpoint(struct pci_controller *hose, int port)
return 0;
}
-#endif /* CONFIG_PCI */
-#endif /* CONFIG_440SPE */
+#endif /* CONFIG_440SPE && CONFIG_PCI */
diff --git a/cpu/ppc4xx/spd_sdram.c b/cpu/ppc4xx/44x_spd_ddr.c
index c24456b..10b4c18 100644
--- a/cpu/ppc4xx/spd_sdram.c
+++ b/cpu/ppc4xx/44x_spd_ddr.c
@@ -1,4 +1,8 @@
/*
+ * cpu/ppc4xx/44x_spd_ddr.c
+ * This SPD DDR detection code supports IBM/AMCC PPC44x cpu with a
+ * DDR controller. Those are 440GP/GX/EP/GR.
+ *
* (C) Copyright 2001
* Bill Hunter, Wave 7 Optics, williamhunter@attbi.com
*
@@ -42,8 +46,11 @@
#include <asm/processor.h>
#include <i2c.h>
#include <ppc4xx.h>
+#include <asm/mmu.h>
-#ifdef CONFIG_SPD_EEPROM
+#if defined(CONFIG_SPD_EEPROM) && \
+ (defined(CONFIG_440GP) || defined(CONFIG_440GX) || \
+ defined(CONFIG_440EP) || defined(CONFIG_440GR))
/*
* Set default values
@@ -58,414 +65,6 @@
#define ONE_BILLION 1000000000
-#ifndef CONFIG_440 /* for 405 WALNUT/SYCAMORE/BUBINGA boards */
-
-#define SDRAM0_CFG_DCE 0x80000000
-#define SDRAM0_CFG_SRE 0x40000000
-#define SDRAM0_CFG_PME 0x20000000
-#define SDRAM0_CFG_MEMCHK 0x10000000
-#define SDRAM0_CFG_REGEN 0x08000000
-#define SDRAM0_CFG_ECCDD 0x00400000
-#define SDRAM0_CFG_EMDULR 0x00200000
-#define SDRAM0_CFG_DRW_SHIFT (31-6)
-#define SDRAM0_CFG_BRPF_SHIFT (31-8)
-
-#define SDRAM0_TR_CASL_SHIFT (31-8)
-#define SDRAM0_TR_PTA_SHIFT (31-13)
-#define SDRAM0_TR_CTP_SHIFT (31-15)
-#define SDRAM0_TR_LDF_SHIFT (31-17)
-#define SDRAM0_TR_RFTA_SHIFT (31-29)
-#define SDRAM0_TR_RCD_SHIFT (31-31)
-
-#define SDRAM0_RTR_SHIFT (31-15)
-#define SDRAM0_ECCCFG_SHIFT (31-11)
-
-/* SDRAM0_CFG enable macro */
-#define SDRAM0_CFG_BRPF(x) ( ( x & 0x3)<< SDRAM0_CFG_BRPF_SHIFT )
-
-#define SDRAM0_BXCR_SZ_MASK 0x000e0000
-#define SDRAM0_BXCR_AM_MASK 0x0000e000
-
-#define SDRAM0_BXCR_SZ_SHIFT (31-14)
-#define SDRAM0_BXCR_AM_SHIFT (31-18)
-
-#define SDRAM0_BXCR_SZ(x) ( (( x << SDRAM0_BXCR_SZ_SHIFT) & SDRAM0_BXCR_SZ_MASK) )
-#define SDRAM0_BXCR_AM(x) ( (( x << SDRAM0_BXCR_AM_SHIFT) & SDRAM0_BXCR_AM_MASK) )
-
-#ifdef CONFIG_SPDDRAM_SILENT
-# define SPD_ERR(x) do { return 0; } while (0)
-#else
-# define SPD_ERR(x) do { printf(x); return(0); } while (0)
-#endif
-
-#define sdram_HZ_to_ns(hertz) (1000000000/(hertz))
-
-/* function prototypes */
-int spd_read(uint addr);
-
-
-/*
- * This function is reading data from the DIMM module EEPROM over the SPD bus
- * and uses that to program the sdram controller.
- *
- * This works on boards that has the same schematics that the AMCC walnut has.
- *
- * Input: null for default I2C spd functions or a pointer to a custom function
- * returning spd_data.
- */
-
-long int spd_sdram(int(read_spd)(uint addr))
-{
- int tmp,row,col;
- int total_size,bank_size,bank_code;
- int ecc_on;
- int mode;
- int bank_cnt;
-
- int sdram0_pmit=0x07c00000;
-#ifndef CONFIG_405EP /* not on PPC405EP */
- int sdram0_besr0=-1;
- int sdram0_besr1=-1;
- int sdram0_eccesr=-1;
-#endif
- int sdram0_ecccfg;
-
- int sdram0_rtr=0;
- int sdram0_tr=0;
-
- int sdram0_b0cr;
- int sdram0_b1cr;
- int sdram0_b2cr;
- int sdram0_b3cr;
-
- int sdram0_cfg=0;
-
- int t_rp;
- int t_rcd;
- int t_ras;
- int t_rc;
- int min_cas;
-
- PPC405_SYS_INFO sys_info;
- unsigned long bus_period_x_10;
-
- /*
- * get the board info
- */
- get_sys_info(&sys_info);
- bus_period_x_10 = ONE_BILLION / (sys_info.freqPLB / 10);
-
- if (read_spd == 0){
- read_spd=spd_read;
- /*
- * Make sure I2C controller is initialized
- * before continuing.
- */
- i2c_init(CFG_I2C_SPEED, CFG_I2C_SLAVE);
- }
-
- /* Make shure we are using SDRAM */
- if (read_spd(2) != 0x04) {
- SPD_ERR("SDRAM - non SDRAM memory module found\n");
- }
-
- /* ------------------------------------------------------------------
- * configure memory timing register
- *
- * data from DIMM:
- * 27 IN Row Precharge Time ( t RP)
- * 29 MIN RAS to CAS Delay ( t RCD)
- * 127 Component and Clock Detail ,clk0-clk3, junction temp, CAS
- * -------------------------------------------------------------------*/
-
- /*
- * first figure out which cas latency mode to use
- * use the min supported mode
- */
-
- tmp = read_spd(127) & 0x6;
- if (tmp == 0x02) { /* only cas = 2 supported */
- min_cas = 2;
-/* t_ck = read_spd(9); */
-/* t_ac = read_spd(10); */
- } else if (tmp == 0x04) { /* only cas = 3 supported */
- min_cas = 3;
-/* t_ck = read_spd(9); */
-/* t_ac = read_spd(10); */
- } else if (tmp == 0x06) { /* 2,3 supported, so use 2 */
- min_cas = 2;
-/* t_ck = read_spd(23); */
-/* t_ac = read_spd(24); */
- } else {
- SPD_ERR("SDRAM - unsupported CAS latency \n");
- }
-
- /* get some timing values, t_rp,t_rcd,t_ras,t_rc
- */
- t_rp = read_spd(27);
- t_rcd = read_spd(29);
- t_ras = read_spd(30);
- t_rc = t_ras + t_rp;
-
- /* The following timing calcs subtract 1 before deviding.
- * this has effect of using ceiling instead of floor rounding,
- * and also subtracting 1 to convert number to reg value
- */
- /* set up CASL */
- sdram0_tr = (min_cas - 1) << SDRAM0_TR_CASL_SHIFT;
- /* set up PTA */
- sdram0_tr |= ((((t_rp - 1) * 10)/bus_period_x_10) & 0x3) << SDRAM0_TR_PTA_SHIFT;
- /* set up CTP */
- tmp = (((t_rc - t_rcd - t_rp -1) * 10) / bus_period_x_10) & 0x3;
- if (tmp < 1)
- tmp = 1;
- sdram0_tr |= tmp << SDRAM0_TR_CTP_SHIFT;
- /* set LDF = 2 cycles, reg value = 1 */
- sdram0_tr |= 1 << SDRAM0_TR_LDF_SHIFT;
- /* set RFTA = t_rfc/bus_period, use t_rfc = t_rc */
- tmp = (((t_rc - 1) * 10) / bus_period_x_10) - 3;
- if (tmp < 0)
- tmp = 0;
- if (tmp > 6)
- tmp = 6;
- sdram0_tr |= tmp << SDRAM0_TR_RFTA_SHIFT;
- /* set RCD = t_rcd/bus_period*/
- sdram0_tr |= ((((t_rcd - 1) * 10) / bus_period_x_10) &0x3) << SDRAM0_TR_RCD_SHIFT ;
-
-
- /*------------------------------------------------------------------
- * configure RTR register
- * -------------------------------------------------------------------*/
- row = read_spd(3);
- col = read_spd(4);
- tmp = read_spd(12) & 0x7f ; /* refresh type less self refresh bit */
- switch (tmp) {
- case 0x00:
- tmp = 15625;
- break;
- case 0x01:
- tmp = 15625 / 4;
- break;
- case 0x02:
- tmp = 15625 / 2;
- break;
- case 0x03:
- tmp = 15625 * 2;
- break;
- case 0x04:
- tmp = 15625 * 4;
- break;
- case 0x05:
- tmp = 15625 * 8;
- break;
- default:
- SPD_ERR("SDRAM - Bad refresh period \n");
- }
- /* convert from nsec to bus cycles */
- tmp = (tmp * 10) / bus_period_x_10;
- sdram0_rtr = (tmp & 0x3ff8) << SDRAM0_RTR_SHIFT;
-
- /*------------------------------------------------------------------
- * determine the number of banks used
- * -------------------------------------------------------------------*/
- /* byte 7:6 is module data width */
- if (read_spd(7) != 0)
- SPD_ERR("SDRAM - unsupported module width\n");
- tmp = read_spd(6);
- if (tmp < 32)
- SPD_ERR("SDRAM - unsupported module width\n");
- else if (tmp < 64)
- bank_cnt = 1; /* one bank per sdram side */
- else if (tmp < 73)
- bank_cnt = 2; /* need two banks per side */
- else if (tmp < 161)
- bank_cnt = 4; /* need four banks per side */
- else
- SPD_ERR("SDRAM - unsupported module width\n");
-
- /* byte 5 is the module row count (refered to as dimm "sides") */
- tmp = read_spd(5);
- if (tmp == 1)
- ;
- else if (tmp==2)
- bank_cnt *= 2;
- else if (tmp==4)
- bank_cnt *= 4;
- else
- bank_cnt = 8; /* 8 is an error code */
-
- if (bank_cnt > 4) /* we only have 4 banks to work with */
- SPD_ERR("SDRAM - unsupported module rows for this width\n");
-
- /* now check for ECC ability of module. We only support ECC
- * on 32 bit wide devices with 8 bit ECC.
- */
- if ((read_spd(11)==2) && (read_spd(6)==40) && (read_spd(14)==8)) {
- sdram0_ecccfg = 0xf << SDRAM0_ECCCFG_SHIFT;
- ecc_on = 1;
- } else {
- sdram0_ecccfg = 0;
- ecc_on = 0;
- }
-
- /*------------------------------------------------------------------
- * calculate total size
- * -------------------------------------------------------------------*/
- /* calculate total size and do sanity check */
- tmp = read_spd(31);
- total_size = 1 << 22; /* total_size = 4MB */
- /* now multiply 4M by the smallest device row density */
- /* note that we don't support asymetric rows */
- while (((tmp & 0x0001) == 0) && (tmp != 0)) {
- total_size = total_size << 1;
- tmp = tmp >> 1;
- }
- total_size *= read_spd(5); /* mult by module rows (dimm sides) */
-
- /*------------------------------------------------------------------
- * map rows * cols * banks to a mode
- * -------------------------------------------------------------------*/
-
- switch (row) {
- case 11:
- switch (col) {
- case 8:
- mode=4; /* mode 5 */
- break;
- case 9:
- case 10:
- mode=0; /* mode 1 */
- break;
- default:
- SPD_ERR("SDRAM - unsupported mode\n");
- }
- break;
- case 12:
- switch (col) {
- case 8:
- mode=3; /* mode 4 */
- break;
- case 9:
- case 10:
- mode=1; /* mode 2 */
- break;
- default:
- SPD_ERR("SDRAM - unsupported mode\n");
- }
- break;
- case 13:
- switch (col) {
- case 8:
- mode=5; /* mode 6 */
- break;
- case 9:
- case 10:
- if (read_spd(17) == 2)
- mode = 6; /* mode 7 */
- else
- mode = 2; /* mode 3 */
- break;
- case 11:
- mode = 2; /* mode 3 */
- break;
- default:
- SPD_ERR("SDRAM - unsupported mode\n");
- }
- break;
- default:
- SPD_ERR("SDRAM - unsupported mode\n");
- }
-
- /*------------------------------------------------------------------
- * using the calculated values, compute the bank
- * config register values.
- * -------------------------------------------------------------------*/
- sdram0_b1cr = 0;
- sdram0_b2cr = 0;
- sdram0_b3cr = 0;
-
- /* compute the size of each bank */
- bank_size = total_size / bank_cnt;
- /* convert bank size to bank size code for ppc4xx
- by takeing log2(bank_size) - 22 */
- tmp = bank_size; /* start with tmp = bank_size */
- bank_code = 0; /* and bank_code = 0 */
- while (tmp > 1) { /* this takes log2 of tmp */
- bank_code++; /* and stores result in bank_code */
- tmp = tmp >> 1;
- } /* bank_code is now log2(bank_size) */
- bank_code -= 22; /* subtract 22 to get the code */
-
- tmp = SDRAM0_BXCR_SZ(bank_code) | SDRAM0_BXCR_AM(mode) | 1;
- sdram0_b0cr = (bank_size * 0) | tmp;
-#ifndef CONFIG_405EP /* not on PPC405EP */
- if (bank_cnt > 1)
- sdram0_b2cr = (bank_size * 1) | tmp;
- if (bank_cnt > 2)
- sdram0_b1cr = (bank_size * 2) | tmp;
- if (bank_cnt > 3)
- sdram0_b3cr = (bank_size * 3) | tmp;
-#else
- /* PPC405EP chip only supports two SDRAM banks */
- if (bank_cnt > 1)
- sdram0_b1cr = (bank_size * 1) | tmp;
- if (bank_cnt > 2)
- total_size = 2 * bank_size;
-#endif
-
- /*
- * enable sdram controller DCE=1
- * enable burst read prefetch to 32 bytes BRPF=2
- * leave other functions off
- */
-
- /*------------------------------------------------------------------
- * now that we've done our calculations, we are ready to
- * program all the registers.
- * -------------------------------------------------------------------*/
-
-#define mtsdram0(reg, data) mtdcr(memcfga,reg);mtdcr(memcfgd,data)
- /* disable memcontroller so updates work */
- mtsdram0( mem_mcopt1, 0 );
-
-#ifndef CONFIG_405EP /* not on PPC405EP */
- mtsdram0( mem_besra , sdram0_besr0 );
- mtsdram0( mem_besrb , sdram0_besr1 );
- mtsdram0( mem_ecccf , sdram0_ecccfg );
- mtsdram0( mem_eccerr, sdram0_eccesr );
-#endif
- mtsdram0( mem_rtr , sdram0_rtr );
- mtsdram0( mem_pmit , sdram0_pmit );
- mtsdram0( mem_mb0cf , sdram0_b0cr );
- mtsdram0( mem_mb1cf , sdram0_b1cr );
-#ifndef CONFIG_405EP /* not on PPC405EP */
- mtsdram0( mem_mb2cf , sdram0_b2cr );
- mtsdram0( mem_mb3cf , sdram0_b3cr );
-#endif
- mtsdram0( mem_sdtr1 , sdram0_tr );
-
- /* SDRAM have a power on delay, 500 micro should do */
- udelay(500);
- sdram0_cfg = SDRAM0_CFG_DCE | SDRAM0_CFG_BRPF(1) | SDRAM0_CFG_ECCDD | SDRAM0_CFG_EMDULR;
- if (ecc_on)
- sdram0_cfg |= SDRAM0_CFG_MEMCHK;
- mtsdram0(mem_mcopt1, sdram0_cfg);
-
- return (total_size);
-}
-
-int spd_read(uint addr)
-{
- uchar data[2];
-
- if (i2c_read(SPD_EEPROM_ADDRESS, addr, 1, data, 1) == 0)
- return (int)data[0];
- else
- return 0;
-}
-
-#else /* CONFIG_440 */
-
/*-----------------------------------------------------------------------------
| Memory Controller Options 0
+-----------------------------------------------------------------------------*/
@@ -631,6 +230,22 @@ int spd_read(uint addr)
#define TRUE 1
#define FALSE 0
+/*
+ * 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
+
const unsigned long test[NUMMEMTESTS][NUMMEMWORDS] = {
{0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
0xFFFFFFFF, 0xFFFFFFFF},
@@ -661,6 +276,7 @@ typedef struct bank_param BANKPARMS;
#ifdef CFG_SIMULATE_SPD_EEPROM
extern unsigned char cfg_simulate_spd_eeprom[128];
#endif
+void program_tlb(u32 start, u32 size, u32 tlb_word2_i_value);
unsigned char spd_read(uchar chip, uint addr);
@@ -779,6 +395,11 @@ long int spd_sdram(void) {
total_size = program_bxcr(dimm_populated, iic0_dimm_addr,
num_dimm_banks);
+#ifdef CONFIG_PROG_SDRAM_TLB /* this define should eventually be removed */
+ /* and program tlb entries for this size (dynamic) */
+ program_tlb(0, total_size, MY_TLB_WORD2_I_ENABLE);
+#endif
+
/*
* program SDRAM Clock Timing Register (SDRAM0_CLKTR)
*/
@@ -1732,11 +1353,11 @@ unsigned long program_bxcr(unsigned long* dimm_populated,
*/
cr |= SDRAM_BXCR_SDBE;
- for (i = 0; i < num_banks; i++) {
- bank_parms[ctrl_bank_num[dimm_num]+i].bank_size_bytes =
+ for (i = 0; i < num_banks; i++) {
+ bank_parms[ctrl_bank_num[dimm_num]+i+dimm_num].bank_size_bytes =
(4 * 1024 * 1024) * bank_size_id;
- bank_parms[ctrl_bank_num[dimm_num]+i].cr = cr;
- }
+ bank_parms[ctrl_bank_num[dimm_num]+i+dimm_num].cr = cr;
+ }
}
}
@@ -1825,7 +1446,4 @@ void program_ecc (unsigned long num_bytes)
SDRAM_CFG0_MCHK_CHK);
}
}
-
-#endif /* CONFIG_440 */
-
#endif /* CONFIG_SPD_EEPROM */
diff --git a/cpu/ppc4xx/44x_spd_ddr2.c b/cpu/ppc4xx/44x_spd_ddr2.c
new file mode 100644
index 0000000..83c9911
--- /dev/null
+++ b/cpu/ppc4xx/44x_spd_ddr2.c
@@ -0,0 +1,2954 @@
+/*
+ * cpu/ppc4xx/44x_spd_ddr2.c
+ * This SPD SDRAM detection code supports AMCC PPC44x cpu's with a
+ * DDR2 controller (non Denali Core). Those are 440SP/SPe.
+ *
+ * (C) Copyright 2007
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * COPYRIGHT AMCC CORPORATION 2004
+ *
+ * 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
+ *
+ */
+
+/* define DEBUG for debugging output (obviously ;-)) */
+#if 0
+#define DEBUG
+#endif
+
+#include <common.h>
+#include <command.h>
+#include <ppc4xx.h>
+#include <i2c.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/mmu.h>
+
+#if defined(CONFIG_SPD_EEPROM) && \
+ (defined(CONFIG_440SP) || defined(CONFIG_440SPE))
+
+/*-----------------------------------------------------------------------------+
+ * Defines
+ *-----------------------------------------------------------------------------*/
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define SDRAM_DDR1 1
+#define SDRAM_DDR2 2
+#define SDRAM_NONE 0
+
+#define MAXDIMMS 2
+#define MAXRANKS 4
+#define MAXBXCF 4
+#define MAX_SPD_BYTES 256 /* Max number of bytes on the DIMM's SPD EEPROM */
+
+#define ONE_BILLION 1000000000
+
+#define MULDIV64(m1, m2, d) (u32)(((u64)(m1) * (u64)(m2)) / (u64)(d))
+
+#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 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 */
+typedef enum ddr_cas_id {
+ DDR_CAS_2 = 20,
+ DDR_CAS_2_5 = 25,
+ DDR_CAS_3 = 30,
+ DDR_CAS_4 = 40,
+ DDR_CAS_5 = 50
+} ddr_cas_id_t;
+
+/*-----------------------------------------------------------------------------+
+ * Prototypes
+ *-----------------------------------------------------------------------------*/
+static unsigned long sdram_memsize(void);
+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);
+static void check_mem_type(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+static void check_frequency(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+static void check_rank_number(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+static void check_voltage_type(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+static void program_memory_queue(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+static void program_codt(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+static void program_mode(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks,
+ 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);
+static void program_rtr(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+static void program_bxcf(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+static void program_copt1(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+static void program_initplr(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks,
+ ddr_cas_id_t selected_cas,
+ int write_recovery);
+static unsigned long is_ecc_enabled(void);
+#ifdef CONFIG_DDR_ECC
+static void program_ecc(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ 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 tlb_word2_i_value);
+#endif
+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
+#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)
+{
+ u32 val;
+
+ switch (dcr) {
+ case SDRAM_R0BAS + 0:
+ val = mfdcr(SDRAM_R0BAS + 0);
+ break;
+ case SDRAM_R0BAS + 1:
+ val = mfdcr(SDRAM_R0BAS + 1);
+ break;
+ case SDRAM_R0BAS + 2:
+ val = mfdcr(SDRAM_R0BAS + 2);
+ break;
+ case SDRAM_R0BAS + 3:
+ val = mfdcr(SDRAM_R0BAS + 3);
+ break;
+ default:
+ printf("DCR %d not defined in case statement!!!\n", dcr);
+ val = 0; /* just to satisfy the compiler */
+ }
+
+ return val;
+}
+
+static void mtdcr_any(u32 dcr, u32 val)
+{
+ switch (dcr) {
+ case SDRAM_R0BAS + 0:
+ mtdcr(SDRAM_R0BAS + 0, val);
+ break;
+ case SDRAM_R0BAS + 1:
+ mtdcr(SDRAM_R0BAS + 1, val);
+ break;
+ case SDRAM_R0BAS + 2:
+ mtdcr(SDRAM_R0BAS + 2, val);
+ break;
+ case SDRAM_R0BAS + 3:
+ mtdcr(SDRAM_R0BAS + 3, val);
+ break;
+ default:
+ printf("DCR %d not defined in case statement!!!\n", dcr);
+ }
+}
+
+static unsigned char spd_read(uchar chip, uint addr)
+{
+ unsigned char data[2];
+
+ if (i2c_probe(chip) == 0)
+ if (i2c_read(chip, addr, 1, data, 1) == 0)
+ return data[0];
+
+ return 0;
+}
+
+/*-----------------------------------------------------------------------------+
+ * sdram_memsize
+ *-----------------------------------------------------------------------------*/
+static unsigned long sdram_memsize(void)
+{
+ unsigned long mem_size;
+ unsigned long mcopt2;
+ unsigned long mcstat;
+ unsigned long mb0cf;
+ unsigned long sdsz;
+ unsigned long i;
+
+ mem_size = 0;
+
+ mfsdram(SDRAM_MCOPT2, mcopt2);
+ mfsdram(SDRAM_MCSTAT, mcstat);
+
+ /* DDR controller must be enabled and not in self-refresh. */
+ /* Otherwise memsize is zero. */
+ if (((mcopt2 & SDRAM_MCOPT2_DCEN_MASK) == SDRAM_MCOPT2_DCEN_ENABLE)
+ && ((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 < MAXBXCF; i++) {
+ mfsdram(SDRAM_MB0CF + (i << 2), mb0cf);
+ /* Banks enabled */
+ if ((mb0cf & SDRAM_BXCF_M_BE_MASK) == SDRAM_BXCF_M_BE_ENABLE) {
+ sdsz = mfdcr_any(SDRAM_R0BAS + i) & SDRAM_RXBAS_SDSZ_MASK;
+
+ switch(sdsz) {
+ case SDRAM_RXBAS_SDSZ_8:
+ mem_size+=8;
+ break;
+ case SDRAM_RXBAS_SDSZ_16:
+ mem_size+=16;
+ break;
+ case SDRAM_RXBAS_SDSZ_32:
+ mem_size+=32;
+ break;
+ case SDRAM_RXBAS_SDSZ_64:
+ mem_size+=64;
+ break;
+ case SDRAM_RXBAS_SDSZ_128:
+ mem_size+=128;
+ break;
+ case SDRAM_RXBAS_SDSZ_256:
+ mem_size+=256;
+ break;
+ case SDRAM_RXBAS_SDSZ_512:
+ mem_size+=512;
+ break;
+ case SDRAM_RXBAS_SDSZ_1024:
+ mem_size+=1024;
+ break;
+ case SDRAM_RXBAS_SDSZ_2048:
+ mem_size+=2048;
+ break;
+ case SDRAM_RXBAS_SDSZ_4096:
+ mem_size+=4096;
+ break;
+ default:
+ mem_size=0;
+ break;
+ }
+ }
+ }
+ }
+
+ mem_size *= 1024 * 1024;
+ return(mem_size);
+}
+
+/*-----------------------------------------------------------------------------+
+ * initdram. Initializes the 440SP Memory Queue and DDR SDRAM controller.
+ * Note: This routine runs from flash with a stack set up in the chip's
+ * sram space. It is important that the routine does not require .sbss, .bss or
+ * .data sections. It also cannot call routines that require these sections.
+ *-----------------------------------------------------------------------------*/
+/*-----------------------------------------------------------------------------
+ * Function: initdram
+ * Description: Configures SDRAM memory banks for DDR operation.
+ * Auto Memory Configuration option reads the DDR SDRAM EEPROMs
+ * via the IIC bus and then configures the DDR SDRAM memory
+ * banks appropriately. If Auto Memory Configuration is
+ * not used, it is assumed that no DIMM is plugged
+ *-----------------------------------------------------------------------------*/
+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 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);
+
+ /*------------------------------------------------------------------
+ * Set up an array of SPD matrixes.
+ *-----------------------------------------------------------------*/
+ dimm_spd[0] = spd0;
+ dimm_spd[1] = spd1;
+
+ /*------------------------------------------------------------------
+ * Reset the DDR-SDRAM controller.
+ *-----------------------------------------------------------------*/
+ mtsdr(SDR0_SRST, (0x80000000 >> 10));
+ mtsdr(SDR0_SRST, 0x00000000);
+
+ /*
+ * Make sure I2C controller is initialized
+ * before continuing.
+ */
+
+ /* switch to correct I2C bus */
+ I2C_SET_BUS(CFG_SPD_BUS_NUM);
+ i2c_init(CFG_I2C_SPEED, CFG_I2C_SLAVE);
+
+ /*------------------------------------------------------------------
+ * Clear out the serial presence detect buffers.
+ * Perform IIC reads from the dimm. Fill in the spds.
+ * Check to see if the dimm slots are populated
+ *-----------------------------------------------------------------*/
+ get_spd_info(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*------------------------------------------------------------------
+ * Check the memory type for the dimms plugged.
+ *-----------------------------------------------------------------*/
+ check_mem_type(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*------------------------------------------------------------------
+ * Check the frequency supported for the dimms plugged.
+ *-----------------------------------------------------------------*/
+ check_frequency(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*------------------------------------------------------------------
+ * Check the total rank number.
+ *-----------------------------------------------------------------*/
+ check_rank_number(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*------------------------------------------------------------------
+ * Check the voltage type for the dimms plugged.
+ *-----------------------------------------------------------------*/
+ check_voltage_type(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*------------------------------------------------------------------
+ * Program SDRAM controller options 2 register
+ * Except Enabling of the memory controller.
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_MCOPT2, val);
+ mtsdram(SDRAM_MCOPT2,
+ (val &
+ ~(SDRAM_MCOPT2_SREN_MASK | SDRAM_MCOPT2_PMEN_MASK |
+ SDRAM_MCOPT2_IPTR_MASK | SDRAM_MCOPT2_XSRP_MASK |
+ SDRAM_MCOPT2_ISIE_MASK))
+ | (SDRAM_MCOPT2_SREN_ENTER | SDRAM_MCOPT2_PMEN_DISABLE |
+ SDRAM_MCOPT2_IPTR_IDLE | SDRAM_MCOPT2_XSRP_ALLOW |
+ SDRAM_MCOPT2_ISIE_ENABLE));
+
+ /*------------------------------------------------------------------
+ * Program SDRAM controller options 1 register
+ * Note: Does not enable the memory controller.
+ *-----------------------------------------------------------------*/
+ program_copt1(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*------------------------------------------------------------------
+ * Set the SDRAM Controller On Die Termination Register
+ *-----------------------------------------------------------------*/
+ program_codt(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*------------------------------------------------------------------
+ * Program SDRAM refresh register.
+ *-----------------------------------------------------------------*/
+ program_rtr(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*------------------------------------------------------------------
+ * Program SDRAM mode register.
+ *-----------------------------------------------------------------*/
+ program_mode(dimm_populated, iic0_dimm_addr, num_dimm_banks,
+ &selected_cas, &write_recovery);
+
+ /*------------------------------------------------------------------
+ * Set the SDRAM Write Data/DM/DQS Clock Timing Reg
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_WRDTR, val);
+ mtsdram(SDRAM_WRDTR, (val & ~(SDRAM_WRDTR_LLWP_MASK | SDRAM_WRDTR_WTR_MASK)) |
+ (SDRAM_WRDTR_LLWP_1_CYC | SDRAM_WRDTR_WTR_90_DEG_ADV));
+
+ /*------------------------------------------------------------------
+ * Set the SDRAM Clock Timing Register
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_CLKTR, val);
+ mtsdram(SDRAM_CLKTR, (val & ~SDRAM_CLKTR_CLKP_MASK) | SDRAM_CLKTR_CLKP_0_DEG);
+
+ /*------------------------------------------------------------------
+ * Program the BxCF registers.
+ *-----------------------------------------------------------------*/
+ program_bxcf(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*------------------------------------------------------------------
+ * Program SDRAM timing registers.
+ *-----------------------------------------------------------------*/
+ program_tr(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*------------------------------------------------------------------
+ * Set the Extended Mode register
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_MEMODE, val);
+ mtsdram(SDRAM_MEMODE,
+ (val & ~(SDRAM_MEMODE_DIC_MASK | SDRAM_MEMODE_DLL_MASK |
+ SDRAM_MEMODE_RTT_MASK | SDRAM_MEMODE_DQS_MASK)) |
+ (SDRAM_MEMODE_DIC_NORMAL | SDRAM_MEMODE_DLL_ENABLE
+ | SDRAM_MEMODE_RTT_150OHM | SDRAM_MEMODE_DQS_ENABLE));
+
+ /*------------------------------------------------------------------
+ * Program Initialization preload registers.
+ *-----------------------------------------------------------------*/
+ program_initplr(dimm_populated, iic0_dimm_addr, num_dimm_banks,
+ selected_cas, write_recovery);
+
+ /*------------------------------------------------------------------
+ * Delay to ensure 200usec have elapsed since reset.
+ *-----------------------------------------------------------------*/
+ udelay(400);
+
+ /*------------------------------------------------------------------
+ * Set the memory queue core base addr.
+ *-----------------------------------------------------------------*/
+ program_memory_queue(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*------------------------------------------------------------------
+ * Program SDRAM controller options 2 register
+ * Enable the memory controller.
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_MCOPT2, val);
+ mtsdram(SDRAM_MCOPT2,
+ (val & ~(SDRAM_MCOPT2_SREN_MASK | SDRAM_MCOPT2_DCEN_MASK |
+ SDRAM_MCOPT2_IPTR_MASK | SDRAM_MCOPT2_ISIE_MASK)) |
+ (SDRAM_MCOPT2_DCEN_ENABLE | SDRAM_MCOPT2_IPTR_EXECUTE));
+
+ /*------------------------------------------------------------------
+ * Wait for SDRAM_CFG0_DC_EN to complete.
+ *-----------------------------------------------------------------*/
+ do {
+ mfsdram(SDRAM_MCSTAT, val);
+ } while ((val & SDRAM_MCSTAT_MIC_MASK) == SDRAM_MCSTAT_MIC_NOTCOMP);
+
+ /* get installed memory size */
+ dram_size = sdram_memsize();
+
+ /* and program tlb entries for this size (dynamic) */
+ program_tlb(0, dram_size, MY_TLB_WORD2_I_ENABLE);
+
+ /*------------------------------------------------------------------
+ * DQS calibration.
+ *-----------------------------------------------------------------*/
+ program_DQS_calibration(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+#ifdef CONFIG_DDR_ECC
+ /*------------------------------------------------------------------
+ * If ecc is enabled, initialize the parity bits.
+ *-----------------------------------------------------------------*/
+ program_ecc(dimm_populated, iic0_dimm_addr, num_dimm_banks, MY_TLB_WORD2_I_ENABLE);
+#endif
+
+#ifdef DEBUG
+ ppc440sp_sdram_register_dump();
+#endif
+
+ return dram_size;
+}
+
+static void get_spd_info(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long dimm_found;
+ unsigned char num_of_bytes;
+ unsigned char total_size;
+
+ dimm_found = FALSE;
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ num_of_bytes = 0;
+ total_size = 0;
+
+ num_of_bytes = spd_read(iic0_dimm_addr[dimm_num], 0);
+ debug("\nspd_read(0x%x) returned %d\n",
+ iic0_dimm_addr[dimm_num], num_of_bytes);
+ total_size = spd_read(iic0_dimm_addr[dimm_num], 1);
+ debug("spd_read(0x%x) returned %d\n",
+ iic0_dimm_addr[dimm_num], total_size);
+
+ if ((num_of_bytes != 0) && (total_size != 0)) {
+ dimm_populated[dimm_num] = TRUE;
+ dimm_found = TRUE;
+ debug("DIMM slot %lu: populated\n", dimm_num);
+ } else {
+ dimm_populated[dimm_num] = FALSE;
+ debug("DIMM slot %lu: Not populated\n", dimm_num);
+ }
+ }
+
+ if (dimm_found == FALSE) {
+ printf("ERROR - No memory installed. Install a DDR-SDRAM DIMM.\n\n");
+ hang();
+ }
+}
+
+#ifdef CONFIG_ADD_RAM_INFO
+void board_add_ram_info(int use_default)
+{
+ if (is_ecc_enabled())
+ puts(" (ECC enabled)");
+ else
+ puts(" (ECC not enabled)");
+}
+#endif
+
+/*------------------------------------------------------------------
+ * For the memory DIMMs installed, this routine verifies that they
+ * really are DDR specific DIMMs.
+ *-----------------------------------------------------------------*/
+static void check_mem_type(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long dimm_type;
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] == TRUE) {
+ dimm_type = spd_read(iic0_dimm_addr[dimm_num], 2);
+ switch (dimm_type) {
+ case 1:
+ printf("ERROR: Standard Fast Page Mode DRAM DIMM detected in "
+ "slot %d.\n", (unsigned int)dimm_num);
+ printf("Only DDR and DDR2 SDRAM DIMMs are supported.\n");
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ hang();
+ break;
+ case 2:
+ printf("ERROR: EDO DIMM detected in slot %d.\n",
+ (unsigned int)dimm_num);
+ printf("Only DDR and DDR2 SDRAM DIMMs are supported.\n");
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ hang();
+ break;
+ case 3:
+ printf("ERROR: Pipelined Nibble DIMM detected in slot %d.\n",
+ (unsigned int)dimm_num);
+ printf("Only DDR and DDR2 SDRAM DIMMs are supported.\n");
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ hang();
+ break;
+ case 4:
+ printf("ERROR: SDRAM DIMM detected in slot %d.\n",
+ (unsigned int)dimm_num);
+ printf("Only DDR and DDR2 SDRAM DIMMs are supported.\n");
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ hang();
+ break;
+ case 5:
+ printf("ERROR: Multiplexed ROM DIMM detected in slot %d.\n",
+ (unsigned int)dimm_num);
+ printf("Only DDR and DDR2 SDRAM DIMMs are supported.\n");
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ hang();
+ break;
+ case 6:
+ printf("ERROR: SGRAM DIMM detected in slot %d.\n",
+ (unsigned int)dimm_num);
+ printf("Only DDR and DDR2 SDRAM DIMMs are supported.\n");
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ hang();
+ break;
+ case 7:
+ debug("DIMM slot %d: DDR1 SDRAM detected\n", dimm_num);
+ dimm_populated[dimm_num] = SDRAM_DDR1;
+ break;
+ case 8:
+ debug("DIMM slot %d: DDR2 SDRAM detected\n", dimm_num);
+ dimm_populated[dimm_num] = SDRAM_DDR2;
+ break;
+ default:
+ printf("ERROR: Unknown DIMM detected in slot %d.\n",
+ (unsigned int)dimm_num);
+ printf("Only DDR1 and DDR2 SDRAM DIMMs are supported.\n");
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ hang();
+ break;
+ }
+ }
+ }
+ for (dimm_num = 1; dimm_num < num_dimm_banks; dimm_num++) {
+ if ((dimm_populated[dimm_num-1] != SDRAM_NONE)
+ && (dimm_populated[dimm_num] != SDRAM_NONE)
+ && (dimm_populated[dimm_num-1] != dimm_populated[dimm_num])) {
+ printf("ERROR: DIMM's DDR1 and DDR2 type can not be mixed.\n");
+ hang();
+ }
+ }
+}
+
+/*------------------------------------------------------------------
+ * For the memory DIMMs installed, this routine verifies that
+ * frequency previously calculated is supported.
+ *-----------------------------------------------------------------*/
+static void check_frequency(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long tcyc_reg;
+ unsigned long cycle_time;
+ unsigned long calc_cycle_time;
+ unsigned long sdram_freq;
+ unsigned long sdr_ddrpll;
+ PPC440_SYS_INFO board_cfg;
+
+ /*------------------------------------------------------------------
+ * Get the board configuration info.
+ *-----------------------------------------------------------------*/
+ get_sys_info(&board_cfg);
+
+ mfsdr(SDR0_DDR0, sdr_ddrpll);
+ sdram_freq = ((board_cfg.freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
+
+ /*
+ * calc_cycle_time is calculated from DDR frequency set by board/chip
+ * and is expressed in multiple of 10 picoseconds
+ * to match the way DIMM cycle time is calculated below.
+ */
+ calc_cycle_time = MULDIV64(ONE_BILLION, 100, sdram_freq);
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] != SDRAM_NONE) {
+ tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 9);
+ /*
+ * Byte 9, Cycle time for CAS Latency=X, is split into two nibbles:
+ * the higher order nibble (bits 4-7) designates the cycle time
+ * to a granularity of 1ns;
+ * the value presented by the lower order nibble (bits 0-3)
+ * has a granularity of .1ns and is added to the value designated
+ * by the higher nibble. In addition, four lines of the lower order
+ * nibble are assigned to support +.25,+.33, +.66 and +.75.
+ */
+ /* Convert from hex to decimal */
+ if ((tcyc_reg & 0x0F) == 0x0D)
+ cycle_time = (((tcyc_reg & 0xF0) >> 4) * 100) + 75;
+ else if ((tcyc_reg & 0x0F) == 0x0C)
+ cycle_time = (((tcyc_reg & 0xF0) >> 4) * 100) + 66;
+ else if ((tcyc_reg & 0x0F) == 0x0B)
+ cycle_time = (((tcyc_reg & 0xF0) >> 4) * 100) + 33;
+ else if ((tcyc_reg & 0x0F) == 0x0A)
+ cycle_time = (((tcyc_reg & 0xF0) >> 4) * 100) + 25;
+ else
+ cycle_time = (((tcyc_reg & 0xF0) >> 4) * 100) +
+ ((tcyc_reg & 0x0F)*10);
+
+ if (cycle_time > (calc_cycle_time + 10)) {
+ /*
+ * the provided sdram cycle_time is too small
+ * for the available DIMM cycle_time.
+ * The additionnal 100ps is here to accept a small incertainty.
+ */
+ printf("ERROR: DRAM DIMM detected with cycle_time %d ps in "
+ "slot %d \n while calculated cycle time is %d ps.\n",
+ (unsigned int)(cycle_time*10),
+ (unsigned int)dimm_num,
+ (unsigned int)(calc_cycle_time*10));
+ printf("Replace the DIMM, or change DDR frequency via "
+ "strapping bits.\n\n");
+ hang();
+ }
+ }
+ }
+}
+
+/*------------------------------------------------------------------
+ * For the memory DIMMs installed, this routine verifies two
+ * ranks/banks maximum are availables.
+ *-----------------------------------------------------------------*/
+static void check_rank_number(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long dimm_rank;
+ unsigned long total_rank = 0;
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] != SDRAM_NONE) {
+ dimm_rank = spd_read(iic0_dimm_addr[dimm_num], 5);
+ if (((unsigned long)spd_read(iic0_dimm_addr[dimm_num], 2)) == 0x08)
+ dimm_rank = (dimm_rank & 0x0F) +1;
+ else
+ dimm_rank = dimm_rank & 0x0F;
+
+
+ if (dimm_rank > MAXRANKS) {
+ printf("ERROR: DRAM DIMM detected with %d ranks in "
+ "slot %d is not supported.\n", dimm_rank, dimm_num);
+ printf("Only %d ranks are supported for all DIMM.\n", MAXRANKS);
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ hang();
+ } else
+ total_rank += dimm_rank;
+ }
+ if (total_rank > MAXRANKS) {
+ printf("ERROR: DRAM DIMM detected with a total of %d ranks "
+ "for all slots.\n", (unsigned int)total_rank);
+ printf("Only %d ranks are supported for all DIMM.\n", MAXRANKS);
+ printf("Remove one of the DIMM modules.\n\n");
+ hang();
+ }
+ }
+}
+
+/*------------------------------------------------------------------
+ * only support 2.5V modules.
+ * This routine verifies this.
+ *-----------------------------------------------------------------*/
+static void check_voltage_type(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long voltage_type;
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] != SDRAM_NONE) {
+ voltage_type = spd_read(iic0_dimm_addr[dimm_num], 8);
+ switch (voltage_type) {
+ case 0x00:
+ printf("ERROR: Only DIMMs DDR 2.5V or DDR2 1.8V are supported.\n");
+ printf("This DIMM is 5.0 Volt/TTL.\n");
+ printf("Replace the DIMM module in slot %d with a supported DIMM.\n\n",
+ (unsigned int)dimm_num);
+ hang();
+ break;
+ case 0x01:
+ printf("ERROR: Only DIMMs DDR 2.5V or DDR2 1.8V are supported.\n");
+ printf("This DIMM is LVTTL.\n");
+ printf("Replace the DIMM module in slot %d with a supported DIMM.\n\n",
+ (unsigned int)dimm_num);
+ hang();
+ break;
+ case 0x02:
+ printf("ERROR: Only DIMMs DDR 2.5V or DDR2 1.8V are supported.\n");
+ printf("This DIMM is 1.5 Volt.\n");
+ printf("Replace the DIMM module in slot %d with a supported DIMM.\n\n",
+ (unsigned int)dimm_num);
+ hang();
+ break;
+ case 0x03:
+ printf("ERROR: Only DIMMs DDR 2.5V or DDR2 1.8V are supported.\n");
+ printf("This DIMM is 3.3 Volt/TTL.\n");
+ printf("Replace the DIMM module in slot %d with a supported DIMM.\n\n",
+ (unsigned int)dimm_num);
+ hang();
+ break;
+ case 0x04:
+ /* 2.5 Voltage only for DDR1 */
+ break;
+ case 0x05:
+ /* 1.8 Voltage only for DDR2 */
+ break;
+ default:
+ printf("ERROR: Only DIMMs DDR 2.5V or DDR2 1.8V are supported.\n");
+ printf("Replace the DIMM module in slot %d with a supported DIMM.\n\n",
+ (unsigned int)dimm_num);
+ hang();
+ break;
+ }
+ }
+ }
+}
+
+/*-----------------------------------------------------------------------------+
+ * program_copt1.
+ *-----------------------------------------------------------------------------*/
+static void program_copt1(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long mcopt1;
+ unsigned long ecc_enabled;
+ unsigned long ecc = 0;
+ unsigned long data_width = 0;
+ unsigned long dimm_32bit;
+ unsigned long dimm_64bit;
+ unsigned long registered = 0;
+ unsigned long attribute = 0;
+ unsigned long buf0, buf1; /* TODO: code to be changed for IOP1.6 to support 4 DIMMs */
+ unsigned long bankcount;
+ unsigned long ddrtype;
+ unsigned long val;
+
+#ifdef CONFIG_DDR_ECC
+ ecc_enabled = TRUE;
+#else
+ ecc_enabled = FALSE;
+#endif
+ dimm_32bit = FALSE;
+ dimm_64bit = FALSE;
+ buf0 = FALSE;
+ buf1 = FALSE;
+
+ /*------------------------------------------------------------------
+ * Set memory controller options reg 1, SDRAM_MCOPT1.
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_MCOPT1, val);
+ mcopt1 = val & ~(SDRAM_MCOPT1_MCHK_MASK | SDRAM_MCOPT1_RDEN_MASK |
+ SDRAM_MCOPT1_PMU_MASK | SDRAM_MCOPT1_DMWD_MASK |
+ SDRAM_MCOPT1_UIOS_MASK | SDRAM_MCOPT1_BCNT_MASK |
+ SDRAM_MCOPT1_DDR_TYPE_MASK | SDRAM_MCOPT1_RWOO_MASK |
+ SDRAM_MCOPT1_WOOO_MASK | SDRAM_MCOPT1_DCOO_MASK |
+ SDRAM_MCOPT1_DREF_MASK);
+
+ mcopt1 |= SDRAM_MCOPT1_QDEP;
+ mcopt1 |= SDRAM_MCOPT1_PMU_OPEN;
+ mcopt1 |= SDRAM_MCOPT1_RWOO_DISABLED;
+ mcopt1 |= SDRAM_MCOPT1_WOOO_DISABLED;
+ mcopt1 |= SDRAM_MCOPT1_DCOO_DISABLED;
+ mcopt1 |= SDRAM_MCOPT1_DREF_NORMAL;
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] != SDRAM_NONE) {
+ /* test ecc support */
+ ecc = (unsigned long)spd_read(iic0_dimm_addr[dimm_num], 11);
+ if (ecc != 0x02) /* ecc not supported */
+ ecc_enabled = FALSE;
+
+ /* test bank count */
+ bankcount = (unsigned long)spd_read(iic0_dimm_addr[dimm_num], 17);
+ if (bankcount == 0x04) /* bank count = 4 */
+ mcopt1 |= SDRAM_MCOPT1_4_BANKS;
+ else /* bank count = 8 */
+ mcopt1 |= SDRAM_MCOPT1_8_BANKS;
+
+ /* test DDR type */
+ ddrtype = (unsigned long)spd_read(iic0_dimm_addr[dimm_num], 2);
+ /* test for buffered/unbuffered, registered, differential clocks */
+ registered = (unsigned long)spd_read(iic0_dimm_addr[dimm_num], 20);
+ attribute = (unsigned long)spd_read(iic0_dimm_addr[dimm_num], 21);
+
+ /* TODO: code to be changed for IOP1.6 to support 4 DIMMs */
+ if (dimm_num == 0) {
+ if (dimm_populated[dimm_num] == SDRAM_DDR1) /* DDR1 type */
+ mcopt1 |= SDRAM_MCOPT1_DDR1_TYPE;
+ if (dimm_populated[dimm_num] == SDRAM_DDR2) /* DDR2 type */
+ mcopt1 |= SDRAM_MCOPT1_DDR2_TYPE;
+ if (registered == 1) { /* DDR2 always buffered */
+ /* TODO: what about above comments ? */
+ mcopt1 |= SDRAM_MCOPT1_RDEN;
+ buf0 = TRUE;
+ } else {
+ /* TODO: the mask 0x02 doesn't match Samsung def for byte 21. */
+ if ((attribute & 0x02) == 0x00) {
+ /* buffered not supported */
+ buf0 = FALSE;
+ } else {
+ mcopt1 |= SDRAM_MCOPT1_RDEN;
+ buf0 = TRUE;
+ }
+ }
+ }
+ else if (dimm_num == 1) {
+ if (dimm_populated[dimm_num] == SDRAM_DDR1) /* DDR1 type */
+ mcopt1 |= SDRAM_MCOPT1_DDR1_TYPE;
+ if (dimm_populated[dimm_num] == SDRAM_DDR2) /* DDR2 type */
+ mcopt1 |= SDRAM_MCOPT1_DDR2_TYPE;
+ if (registered == 1) {
+ /* DDR2 always buffered */
+ mcopt1 |= SDRAM_MCOPT1_RDEN;
+ buf1 = TRUE;
+ } else {
+ if ((attribute & 0x02) == 0x00) {
+ /* buffered not supported */
+ buf1 = FALSE;
+ } else {
+ mcopt1 |= SDRAM_MCOPT1_RDEN;
+ buf1 = TRUE;
+ }
+ }
+ }
+
+ /* Note that for DDR2 the byte 7 is reserved, but OK to keep code as is. */
+ data_width = (unsigned long)spd_read(iic0_dimm_addr[dimm_num], 6) +
+ (((unsigned long)spd_read(iic0_dimm_addr[dimm_num], 7)) << 8);
+
+ switch (data_width) {
+ case 72:
+ case 64:
+ dimm_64bit = TRUE;
+ break;
+ case 40:
+ case 32:
+ dimm_32bit = TRUE;
+ break;
+ default:
+ printf("WARNING: Detected a DIMM with a data width of %d bits.\n",
+ data_width);
+ printf("Only DIMMs with 32 or 64 bit DDR-SDRAM widths are supported.\n");
+ break;
+ }
+ }
+ }
+
+ /* verify matching properties */
+ if ((dimm_populated[0] != SDRAM_NONE) && (dimm_populated[1] != SDRAM_NONE)) {
+ if (buf0 != buf1) {
+ printf("ERROR: DIMM's buffered/unbuffered, registered, clocking don't match.\n");
+ hang();
+ }
+ }
+
+ if ((dimm_64bit == TRUE) && (dimm_32bit == TRUE)) {
+ printf("ERROR: Cannot mix 32 bit and 64 bit DDR-SDRAM DIMMs together.\n");
+ hang();
+ }
+ else if ((dimm_64bit == TRUE) && (dimm_32bit == FALSE)) {
+ mcopt1 |= SDRAM_MCOPT1_DMWD_64;
+ } else if ((dimm_64bit == FALSE) && (dimm_32bit == TRUE)) {
+ mcopt1 |= SDRAM_MCOPT1_DMWD_32;
+ } else {
+ printf("ERROR: Please install only 32 or 64 bit DDR-SDRAM DIMMs.\n\n");
+ hang();
+ }
+
+ if (ecc_enabled == TRUE)
+ mcopt1 |= SDRAM_MCOPT1_MCHK_GEN;
+ else
+ mcopt1 |= SDRAM_MCOPT1_MCHK_NON;
+
+ mtsdram(SDRAM_MCOPT1, mcopt1);
+}
+
+/*-----------------------------------------------------------------------------+
+ * program_codt.
+ *-----------------------------------------------------------------------------*/
+static void program_codt(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long codt;
+ unsigned long modt0 = 0;
+ unsigned long modt1 = 0;
+ unsigned long modt2 = 0;
+ unsigned long modt3 = 0;
+ unsigned char dimm_num;
+ unsigned char dimm_rank;
+ unsigned char total_rank = 0;
+ unsigned char total_dimm = 0;
+ unsigned char dimm_type = 0;
+ unsigned char firstSlot = 0;
+
+ /*------------------------------------------------------------------
+ * Set the SDRAM Controller On Die Termination Register
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_CODT, codt);
+ codt |= (SDRAM_CODT_IO_NMODE
+ & (~SDRAM_CODT_DQS_SINGLE_END
+ & ~SDRAM_CODT_CKSE_SINGLE_END
+ & ~SDRAM_CODT_FEEBBACK_RCV_SINGLE_END
+ & ~SDRAM_CODT_FEEBBACK_DRV_SINGLE_END));
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] != SDRAM_NONE) {
+ dimm_rank = (unsigned long)spd_read(iic0_dimm_addr[dimm_num], 5);
+ if (((unsigned long)spd_read(iic0_dimm_addr[dimm_num], 2)) == 0x08) {
+ dimm_rank = (dimm_rank & 0x0F) + 1;
+ dimm_type = SDRAM_DDR2;
+ } else {
+ dimm_rank = dimm_rank & 0x0F;
+ dimm_type = SDRAM_DDR1;
+ }
+
+ total_rank += dimm_rank;
+ total_dimm++;
+ if ((dimm_num == 0) && (total_dimm == 1))
+ firstSlot = TRUE;
+ else
+ firstSlot = FALSE;
+ }
+ }
+ if (dimm_type == SDRAM_DDR2) {
+ codt |= SDRAM_CODT_DQS_1_8_V_DDR2;
+ if ((total_dimm == 1) && (firstSlot == TRUE)) {
+ if (total_rank == 1) {
+ codt |= CALC_ODT_R(0);
+ modt0 = CALC_ODT_W(0);
+ modt1 = 0x00000000;
+ modt2 = 0x00000000;
+ modt3 = 0x00000000;
+ }
+ if (total_rank == 2) {
+ codt |= CALC_ODT_R(0) | CALC_ODT_R(1);
+ modt0 = CALC_ODT_W(0);
+ modt1 = CALC_ODT_W(0);
+ modt2 = 0x00000000;
+ modt3 = 0x00000000;
+ }
+ } else if ((total_dimm == 1) && (firstSlot != TRUE)) {
+ if (total_rank == 1) {
+ codt |= CALC_ODT_R(2);
+ modt0 = 0x00000000;
+ modt1 = 0x00000000;
+ modt2 = CALC_ODT_W(2);
+ modt3 = 0x00000000;
+ }
+ if (total_rank == 2) {
+ 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 |= CALC_ODT_R(0) | CALC_ODT_R(2);
+ modt0 = CALC_ODT_RW(2);
+ modt1 = 0x00000000;
+ modt2 = CALC_ODT_RW(0);
+ modt3 = 0x00000000;
+ }
+ if (total_rank == 4) {
+ 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 {
+ codt |= SDRAM_CODT_DQS_2_5_V_DDR1;
+ modt0 = 0x00000000;
+ modt1 = 0x00000000;
+ modt2 = 0x00000000;
+ modt3 = 0x00000000;
+
+ if (total_dimm == 1) {
+ if (total_rank == 1)
+ codt |= 0x00800000;
+ if (total_rank == 2)
+ codt |= 0x02800000;
+ }
+ if (total_dimm == 2) {
+ if (total_rank == 2)
+ codt |= 0x08800000;
+ if (total_rank == 4)
+ codt |= 0x2a800000;
+ }
+ }
+
+ debug("nb of dimm %d\n", total_dimm);
+ debug("nb of rank %d\n", total_rank);
+ if (total_dimm == 1)
+ debug("dimm in slot %d\n", firstSlot);
+
+ mtsdram(SDRAM_CODT, codt);
+ mtsdram(SDRAM_MODT0, modt0);
+ mtsdram(SDRAM_MODT1, modt1);
+ mtsdram(SDRAM_MODT2, modt2);
+ mtsdram(SDRAM_MODT3, modt3);
+}
+
+/*-----------------------------------------------------------------------------+
+ * program_initplr.
+ *-----------------------------------------------------------------------------*/
+static void program_initplr(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks,
+ ddr_cas_id_t selected_cas,
+ int write_recovery)
+{
+ 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
+ ** as already checked in check_memory_type
+ ******************************************************/
+
+ if ((dimm_populated[0] == SDRAM_DDR1) || (dimm_populated[1] == SDRAM_DDR1)) {
+ mtsdram(SDRAM_INITPLR0, 0x81B80000);
+ mtsdram(SDRAM_INITPLR1, 0x81900400);
+ mtsdram(SDRAM_INITPLR2, 0x81810000);
+ mtsdram(SDRAM_INITPLR3, 0xff800162);
+ mtsdram(SDRAM_INITPLR4, 0x81900400);
+ mtsdram(SDRAM_INITPLR5, 0x86080000);
+ mtsdram(SDRAM_INITPLR6, 0x86080000);
+ mtsdram(SDRAM_INITPLR7, 0x81000062);
+ } else if ((dimm_populated[0] == SDRAM_DDR2) || (dimm_populated[1] == SDRAM_DDR2)) {
+ switch (selected_cas) {
+ case DDR_CAS_3:
+ cas = 3 << 4;
+ break;
+ case DDR_CAS_4:
+ cas = 4 << 4;
+ break;
+ case DDR_CAS_5:
+ cas = 5 << 4;
+ break;
+ default:
+ printf("ERROR: ucode error on selected_cas value %d", selected_cas);
+ hang();
+ break;
+ }
+
+#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();
+ }
+}
+
+/*------------------------------------------------------------------
+ * This routine programs the SDRAM_MMODE register.
+ * the selected_cas is an output parameter, that will be passed
+ * by caller to call the above program_initplr( )
+ *-----------------------------------------------------------------*/
+static void program_mode(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks,
+ ddr_cas_id_t *selected_cas,
+ int *write_recovery)
+{
+ unsigned long dimm_num;
+ unsigned long sdram_ddr1;
+ unsigned long t_wr_ns;
+ unsigned long t_wr_clk;
+ unsigned long cas_bit;
+ unsigned long cas_index;
+ unsigned long sdram_freq;
+ unsigned long ddr_check;
+ unsigned long mmode;
+ unsigned long tcyc_reg;
+ unsigned long cycle_2_0_clk;
+ unsigned long cycle_2_5_clk;
+ unsigned long cycle_3_0_clk;
+ unsigned long cycle_4_0_clk;
+ unsigned long cycle_5_0_clk;
+ unsigned long max_2_0_tcyc_ns_x_100;
+ unsigned long max_2_5_tcyc_ns_x_100;
+ unsigned long max_3_0_tcyc_ns_x_100;
+ unsigned long max_4_0_tcyc_ns_x_100;
+ unsigned long max_5_0_tcyc_ns_x_100;
+ unsigned long cycle_time_ns_x_100[3];
+ PPC440_SYS_INFO board_cfg;
+ unsigned char cas_2_0_available;
+ unsigned char cas_2_5_available;
+ unsigned char cas_3_0_available;
+ unsigned char cas_4_0_available;
+ unsigned char cas_5_0_available;
+ unsigned long sdr_ddrpll;
+
+ /*------------------------------------------------------------------
+ * Get the board configuration info.
+ *-----------------------------------------------------------------*/
+ get_sys_info(&board_cfg);
+
+ mfsdr(SDR0_DDR0, sdr_ddrpll);
+ sdram_freq = MULDIV64((board_cfg.freqPLB), SDR0_DDR0_DDRM_DECODE(sdr_ddrpll), 1);
+
+ /*------------------------------------------------------------------
+ * Handle the timing. We need to find the worst case timing of all
+ * the dimm modules installed.
+ *-----------------------------------------------------------------*/
+ t_wr_ns = 0;
+ cas_2_0_available = TRUE;
+ cas_2_5_available = TRUE;
+ cas_3_0_available = TRUE;
+ cas_4_0_available = TRUE;
+ cas_5_0_available = TRUE;
+ max_2_0_tcyc_ns_x_100 = 10;
+ max_2_5_tcyc_ns_x_100 = 10;
+ max_3_0_tcyc_ns_x_100 = 10;
+ max_4_0_tcyc_ns_x_100 = 10;
+ max_5_0_tcyc_ns_x_100 = 10;
+ sdram_ddr1 = TRUE;
+
+ /* loop through all the DIMM slots on the board */
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ /* If a dimm is installed in a particular slot ... */
+ if (dimm_populated[dimm_num] != SDRAM_NONE) {
+ if (dimm_populated[dimm_num] == SDRAM_DDR1)
+ sdram_ddr1 = TRUE;
+ else
+ sdram_ddr1 = FALSE;
+
+ /* t_wr_ns = max(t_wr_ns, (unsigned long)dimm_spd[dimm_num][36] >> 2); */ /* not used in this loop. */
+ cas_bit = spd_read(iic0_dimm_addr[dimm_num], 18);
+
+ /* For a particular DIMM, grab the three CAS values it supports */
+ for (cas_index = 0; cas_index < 3; cas_index++) {
+ switch (cas_index) {
+ case 0:
+ tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 9);
+ break;
+ case 1:
+ tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 23);
+ break;
+ default:
+ tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 25);
+ break;
+ }
+
+ if ((tcyc_reg & 0x0F) >= 10) {
+ if ((tcyc_reg & 0x0F) == 0x0D) {
+ /* Convert from hex to decimal */
+ cycle_time_ns_x_100[cas_index] = (((tcyc_reg & 0xF0) >> 4) * 100) + 75;
+ } else {
+ printf("ERROR: SPD reported Tcyc is incorrect for DIMM "
+ "in slot %d\n", (unsigned int)dimm_num);
+ hang();
+ }
+ } else {
+ /* Convert from hex to decimal */
+ cycle_time_ns_x_100[cas_index] = (((tcyc_reg & 0xF0) >> 4) * 100) +
+ ((tcyc_reg & 0x0F)*10);
+ }
+ }
+
+ /* The rest of this routine determines if CAS 2.0, 2.5, 3.0, 4.0 and 5.0 are */
+ /* supported for a particular DIMM. */
+ cas_index = 0;
+
+ if (sdram_ddr1) {
+ /*
+ * DDR devices use the following bitmask for CAS latency:
+ * Bit 7 6 5 4 3 2 1 0
+ * TBD 4.0 3.5 3.0 2.5 2.0 1.5 1.0
+ */
+ if (((cas_bit & 0x40) == 0x40) && (cas_index < 3) && (cycle_time_ns_x_100[cas_index] != 0)) {
+ max_4_0_tcyc_ns_x_100 = max(max_4_0_tcyc_ns_x_100, cycle_time_ns_x_100[cas_index]);
+ cas_index++;
+ } else {
+ if (cas_index != 0)
+ cas_index++;
+ cas_4_0_available = FALSE;
+ }
+
+ if (((cas_bit & 0x10) == 0x10) && (cas_index < 3) && (cycle_time_ns_x_100[cas_index] != 0)) {
+ max_3_0_tcyc_ns_x_100 = max(max_3_0_tcyc_ns_x_100, cycle_time_ns_x_100[cas_index]);
+ cas_index++;
+ } else {
+ if (cas_index != 0)
+ cas_index++;
+ cas_3_0_available = FALSE;
+ }
+
+ if (((cas_bit & 0x08) == 0x08) && (cas_index < 3) && (cycle_time_ns_x_100[cas_index] != 0)) {
+ max_2_5_tcyc_ns_x_100 = max(max_2_5_tcyc_ns_x_100, cycle_time_ns_x_100[cas_index]);
+ cas_index++;
+ } else {
+ if (cas_index != 0)
+ cas_index++;
+ cas_2_5_available = FALSE;
+ }
+
+ if (((cas_bit & 0x04) == 0x04) && (cas_index < 3) && (cycle_time_ns_x_100[cas_index] != 0)) {
+ max_2_0_tcyc_ns_x_100 = max(max_2_0_tcyc_ns_x_100, cycle_time_ns_x_100[cas_index]);
+ cas_index++;
+ } else {
+ if (cas_index != 0)
+ cas_index++;
+ cas_2_0_available = FALSE;
+ }
+ } else {
+ /*
+ * DDR2 devices use the following bitmask for CAS latency:
+ * Bit 7 6 5 4 3 2 1 0
+ * TBD 6.0 5.0 4.0 3.0 2.0 TBD TBD
+ */
+ if (((cas_bit & 0x20) == 0x20) && (cas_index < 3) && (cycle_time_ns_x_100[cas_index] != 0)) {
+ max_5_0_tcyc_ns_x_100 = max(max_5_0_tcyc_ns_x_100, cycle_time_ns_x_100[cas_index]);
+ cas_index++;
+ } else {
+ if (cas_index != 0)
+ cas_index++;
+ cas_5_0_available = FALSE;
+ }
+
+ if (((cas_bit & 0x10) == 0x10) && (cas_index < 3) && (cycle_time_ns_x_100[cas_index] != 0)) {
+ max_4_0_tcyc_ns_x_100 = max(max_4_0_tcyc_ns_x_100, cycle_time_ns_x_100[cas_index]);
+ cas_index++;
+ } else {
+ if (cas_index != 0)
+ cas_index++;
+ cas_4_0_available = FALSE;
+ }
+
+ if (((cas_bit & 0x08) == 0x08) && (cas_index < 3) && (cycle_time_ns_x_100[cas_index] != 0)) {
+ max_3_0_tcyc_ns_x_100 = max(max_3_0_tcyc_ns_x_100, cycle_time_ns_x_100[cas_index]);
+ cas_index++;
+ } else {
+ if (cas_index != 0)
+ cas_index++;
+ cas_3_0_available = FALSE;
+ }
+ }
+ }
+ }
+
+ /*------------------------------------------------------------------
+ * Set the SDRAM mode, SDRAM_MMODE
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_MMODE, mmode);
+ mmode = mmode & ~(SDRAM_MMODE_WR_MASK | SDRAM_MMODE_DCL_MASK);
+
+ /* add 10 here because of rounding problems */
+ cycle_2_0_clk = MULDIV64(ONE_BILLION, 100, max_2_0_tcyc_ns_x_100) + 10;
+ cycle_2_5_clk = MULDIV64(ONE_BILLION, 100, max_2_5_tcyc_ns_x_100) + 10;
+ cycle_3_0_clk = MULDIV64(ONE_BILLION, 100, max_3_0_tcyc_ns_x_100) + 10;
+ cycle_4_0_clk = MULDIV64(ONE_BILLION, 100, max_4_0_tcyc_ns_x_100) + 10;
+ cycle_5_0_clk = MULDIV64(ONE_BILLION, 100, max_5_0_tcyc_ns_x_100) + 10;
+
+ if (sdram_ddr1 == TRUE) { /* DDR1 */
+ if ((cas_2_0_available == TRUE) && (sdram_freq <= cycle_2_0_clk)) {
+ mmode |= SDRAM_MMODE_DCL_DDR1_2_0_CLK;
+ *selected_cas = DDR_CAS_2;
+ } else if ((cas_2_5_available == TRUE) && (sdram_freq <= cycle_2_5_clk)) {
+ mmode |= SDRAM_MMODE_DCL_DDR1_2_5_CLK;
+ *selected_cas = DDR_CAS_2_5;
+ } else if ((cas_3_0_available == TRUE) && (sdram_freq <= cycle_3_0_clk)) {
+ mmode |= SDRAM_MMODE_DCL_DDR1_3_0_CLK;
+ *selected_cas = DDR_CAS_3;
+ } else {
+ printf("ERROR: Cannot find a supported CAS latency with the installed DIMMs.\n");
+ printf("Only DIMMs DDR1 with CAS latencies of 2.0, 2.5, and 3.0 are supported.\n");
+ printf("Make sure the PLB speed is within the supported range of the DIMMs.\n\n");
+ hang();
+ }
+ } else { /* DDR2 */
+ if ((cas_3_0_available == TRUE) && (sdram_freq <= cycle_3_0_clk)) {
+ mmode |= SDRAM_MMODE_DCL_DDR2_3_0_CLK;
+ *selected_cas = DDR_CAS_3;
+ } else if ((cas_4_0_available == TRUE) && (sdram_freq <= cycle_4_0_clk)) {
+ mmode |= SDRAM_MMODE_DCL_DDR2_4_0_CLK;
+ *selected_cas = DDR_CAS_4;
+ } else if ((cas_5_0_available == TRUE) && (sdram_freq <= cycle_5_0_clk)) {
+ mmode |= SDRAM_MMODE_DCL_DDR2_5_0_CLK;
+ *selected_cas = DDR_CAS_5;
+ } else {
+ printf("ERROR: Cannot find a supported CAS latency with the installed DIMMs.\n");
+ printf("Only DIMMs DDR2 with CAS latencies of 3.0, 4.0, and 5.0 are supported.\n");
+ printf("Make sure the PLB speed is within the supported range of the DIMMs.\n");
+ printf("cas3=%d cas4=%d cas5=%d\n",
+ cas_3_0_available, cas_4_0_available, cas_5_0_available);
+ printf("sdram_freq=%d cycle3=%d cycle4=%d cycle5=%d\n\n",
+ sdram_freq, cycle_3_0_clk, cycle_4_0_clk, cycle_5_0_clk);
+ hang();
+ }
+ }
+
+ if (sdram_ddr1 == TRUE)
+ mmode |= SDRAM_MMODE_WR_DDR1;
+ else {
+
+ /* loop through all the DIMM slots on the board */
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ /* If a dimm is installed in a particular slot ... */
+ if (dimm_populated[dimm_num] != SDRAM_NONE)
+ t_wr_ns = max(t_wr_ns,
+ spd_read(iic0_dimm_addr[dimm_num], 36) >> 2);
+ }
+
+ /*
+ * convert from nanoseconds to ddr clocks
+ * round up if necessary
+ */
+ t_wr_clk = MULDIV64(sdram_freq, t_wr_ns, ONE_BILLION);
+ ddr_check = MULDIV64(ONE_BILLION, t_wr_clk, t_wr_ns);
+ if (sdram_freq != ddr_check)
+ t_wr_clk++;
+
+ switch (t_wr_clk) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ mmode |= SDRAM_MMODE_WR_DDR2_3_CYC;
+ break;
+ case 4:
+ mmode |= SDRAM_MMODE_WR_DDR2_4_CYC;
+ break;
+ case 5:
+ mmode |= SDRAM_MMODE_WR_DDR2_5_CYC;
+ break;
+ default:
+ 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);
+}
+
+/*-----------------------------------------------------------------------------+
+ * program_rtr.
+ *-----------------------------------------------------------------------------*/
+static void program_rtr(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ PPC440_SYS_INFO board_cfg;
+ unsigned long max_refresh_rate;
+ unsigned long dimm_num;
+ unsigned long refresh_rate_type;
+ unsigned long refresh_rate;
+ unsigned long rint;
+ unsigned long sdram_freq;
+ unsigned long sdr_ddrpll;
+ unsigned long val;
+
+ /*------------------------------------------------------------------
+ * Get the board configuration info.
+ *-----------------------------------------------------------------*/
+ get_sys_info(&board_cfg);
+
+ /*------------------------------------------------------------------
+ * Set the SDRAM Refresh Timing Register, SDRAM_RTR
+ *-----------------------------------------------------------------*/
+ mfsdr(SDR0_DDR0, sdr_ddrpll);
+ sdram_freq = ((board_cfg.freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
+
+ max_refresh_rate = 0;
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] != SDRAM_NONE) {
+
+ refresh_rate_type = spd_read(iic0_dimm_addr[dimm_num], 12);
+ refresh_rate_type &= 0x7F;
+ switch (refresh_rate_type) {
+ case 0:
+ refresh_rate = 15625;
+ break;
+ case 1:
+ refresh_rate = 3906;
+ break;
+ case 2:
+ refresh_rate = 7812;
+ break;
+ case 3:
+ refresh_rate = 31250;
+ break;
+ case 4:
+ refresh_rate = 62500;
+ break;
+ case 5:
+ refresh_rate = 125000;
+ break;
+ default:
+ refresh_rate = 0;
+ printf("ERROR: DIMM %d unsupported refresh rate/type.\n",
+ (unsigned int)dimm_num);
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ hang();
+ break;
+ }
+
+ max_refresh_rate = max(max_refresh_rate, refresh_rate);
+ }
+ }
+
+ rint = MULDIV64(sdram_freq, max_refresh_rate, ONE_BILLION);
+ mfsdram(SDRAM_RTR, val);
+ mtsdram(SDRAM_RTR, (val & ~SDRAM_RTR_RINT_MASK) |
+ (SDRAM_RTR_RINT_ENCODE(rint)));
+}
+
+/*------------------------------------------------------------------
+ * This routine programs the SDRAM_TRx registers.
+ *-----------------------------------------------------------------*/
+static void program_tr(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long sdram_ddr1;
+ unsigned long t_rp_ns;
+ unsigned long t_rcd_ns;
+ unsigned long t_rrd_ns;
+ unsigned long t_ras_ns;
+ unsigned long t_rc_ns;
+ unsigned long t_rfc_ns;
+ unsigned long t_wpc_ns;
+ unsigned long t_wtr_ns;
+ unsigned long t_rpc_ns;
+ unsigned long t_rp_clk;
+ unsigned long t_rcd_clk;
+ unsigned long t_rrd_clk;
+ unsigned long t_ras_clk;
+ unsigned long t_rc_clk;
+ unsigned long t_rfc_clk;
+ unsigned long t_wpc_clk;
+ unsigned long t_wtr_clk;
+ unsigned long t_rpc_clk;
+ unsigned long sdtr1, sdtr2, sdtr3;
+ unsigned long ddr_check;
+ unsigned long sdram_freq;
+ unsigned long sdr_ddrpll;
+
+ PPC440_SYS_INFO board_cfg;
+
+ /*------------------------------------------------------------------
+ * Get the board configuration info.
+ *-----------------------------------------------------------------*/
+ get_sys_info(&board_cfg);
+
+ mfsdr(SDR0_DDR0, sdr_ddrpll);
+ sdram_freq = ((board_cfg.freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
+
+ /*------------------------------------------------------------------
+ * Handle the timing. We need to find the worst case timing of all
+ * the dimm modules installed.
+ *-----------------------------------------------------------------*/
+ t_rp_ns = 0;
+ t_rrd_ns = 0;
+ t_rcd_ns = 0;
+ t_ras_ns = 0;
+ t_rc_ns = 0;
+ t_rfc_ns = 0;
+ t_wpc_ns = 0;
+ t_wtr_ns = 0;
+ t_rpc_ns = 0;
+ sdram_ddr1 = TRUE;
+
+ /* loop through all the DIMM slots on the board */
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ /* If a dimm is installed in a particular slot ... */
+ if (dimm_populated[dimm_num] != SDRAM_NONE) {
+ if (dimm_populated[dimm_num] == SDRAM_DDR2)
+ sdram_ddr1 = TRUE;
+ else
+ sdram_ddr1 = FALSE;
+
+ t_rcd_ns = max(t_rcd_ns, spd_read(iic0_dimm_addr[dimm_num], 29) >> 2);
+ t_rrd_ns = max(t_rrd_ns, spd_read(iic0_dimm_addr[dimm_num], 28) >> 2);
+ t_rp_ns = max(t_rp_ns, spd_read(iic0_dimm_addr[dimm_num], 27) >> 2);
+ t_ras_ns = max(t_ras_ns, spd_read(iic0_dimm_addr[dimm_num], 30));
+ t_rc_ns = max(t_rc_ns, spd_read(iic0_dimm_addr[dimm_num], 41));
+ t_rfc_ns = max(t_rfc_ns, spd_read(iic0_dimm_addr[dimm_num], 42));
+ }
+ }
+
+ /*------------------------------------------------------------------
+ * Set the SDRAM Timing Reg 1, SDRAM_TR1
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_SDTR1, sdtr1);
+ sdtr1 &= ~(SDRAM_SDTR1_LDOF_MASK | SDRAM_SDTR1_RTW_MASK |
+ SDRAM_SDTR1_WTWO_MASK | SDRAM_SDTR1_RTRO_MASK);
+
+ /* default values */
+ sdtr1 |= SDRAM_SDTR1_LDOF_2_CLK;
+ sdtr1 |= SDRAM_SDTR1_RTW_2_CLK;
+
+ /* normal operations */
+ sdtr1 |= SDRAM_SDTR1_WTWO_0_CLK;
+ sdtr1 |= SDRAM_SDTR1_RTRO_1_CLK;
+
+ mtsdram(SDRAM_SDTR1, sdtr1);
+
+ /*------------------------------------------------------------------
+ * Set the SDRAM Timing Reg 2, SDRAM_TR2
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_SDTR2, sdtr2);
+ sdtr2 &= ~(SDRAM_SDTR2_RCD_MASK | SDRAM_SDTR2_WTR_MASK |
+ SDRAM_SDTR2_XSNR_MASK | SDRAM_SDTR2_WPC_MASK |
+ SDRAM_SDTR2_RPC_MASK | SDRAM_SDTR2_RP_MASK |
+ SDRAM_SDTR2_RRD_MASK);
+
+ /*
+ * convert t_rcd from nanoseconds to ddr clocks
+ * round up if necessary
+ */
+ t_rcd_clk = MULDIV64(sdram_freq, t_rcd_ns, ONE_BILLION);
+ ddr_check = MULDIV64(ONE_BILLION, t_rcd_clk, t_rcd_ns);
+ if (sdram_freq != ddr_check)
+ t_rcd_clk++;
+
+ switch (t_rcd_clk) {
+ case 0:
+ case 1:
+ sdtr2 |= SDRAM_SDTR2_RCD_1_CLK;
+ break;
+ case 2:
+ sdtr2 |= SDRAM_SDTR2_RCD_2_CLK;
+ break;
+ case 3:
+ sdtr2 |= SDRAM_SDTR2_RCD_3_CLK;
+ break;
+ case 4:
+ sdtr2 |= SDRAM_SDTR2_RCD_4_CLK;
+ break;
+ default:
+ sdtr2 |= SDRAM_SDTR2_RCD_5_CLK;
+ break;
+ }
+
+ if (sdram_ddr1 == TRUE) { /* DDR1 */
+ if (sdram_freq < 200000000) {
+ sdtr2 |= SDRAM_SDTR2_WTR_1_CLK;
+ sdtr2 |= SDRAM_SDTR2_WPC_2_CLK;
+ sdtr2 |= SDRAM_SDTR2_RPC_2_CLK;
+ } else {
+ sdtr2 |= SDRAM_SDTR2_WTR_2_CLK;
+ sdtr2 |= SDRAM_SDTR2_WPC_3_CLK;
+ sdtr2 |= SDRAM_SDTR2_RPC_2_CLK;
+ }
+ } else { /* DDR2 */
+ /* loop through all the DIMM slots on the board */
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ /* If a dimm is installed in a particular slot ... */
+ if (dimm_populated[dimm_num] != SDRAM_NONE) {
+ t_wpc_ns = max(t_wtr_ns, spd_read(iic0_dimm_addr[dimm_num], 36) >> 2);
+ t_wtr_ns = max(t_wtr_ns, spd_read(iic0_dimm_addr[dimm_num], 37) >> 2);
+ t_rpc_ns = max(t_rpc_ns, spd_read(iic0_dimm_addr[dimm_num], 38) >> 2);
+ }
+ }
+
+ /*
+ * convert from nanoseconds to ddr clocks
+ * round up if necessary
+ */
+ t_wpc_clk = MULDIV64(sdram_freq, t_wpc_ns, ONE_BILLION);
+ ddr_check = MULDIV64(ONE_BILLION, t_wpc_clk, t_wpc_ns);
+ if (sdram_freq != ddr_check)
+ t_wpc_clk++;
+
+ switch (t_wpc_clk) {
+ case 0:
+ case 1:
+ case 2:
+ sdtr2 |= SDRAM_SDTR2_WPC_2_CLK;
+ break;
+ case 3:
+ sdtr2 |= SDRAM_SDTR2_WPC_3_CLK;
+ break;
+ case 4:
+ sdtr2 |= SDRAM_SDTR2_WPC_4_CLK;
+ break;
+ case 5:
+ sdtr2 |= SDRAM_SDTR2_WPC_5_CLK;
+ break;
+ default:
+ sdtr2 |= SDRAM_SDTR2_WPC_6_CLK;
+ break;
+ }
+
+ /*
+ * convert from nanoseconds to ddr clocks
+ * round up if necessary
+ */
+ t_wtr_clk = MULDIV64(sdram_freq, t_wtr_ns, ONE_BILLION);
+ ddr_check = MULDIV64(ONE_BILLION, t_wtr_clk, t_wtr_ns);
+ if (sdram_freq != ddr_check)
+ t_wtr_clk++;
+
+ switch (t_wtr_clk) {
+ case 0:
+ case 1:
+ sdtr2 |= SDRAM_SDTR2_WTR_1_CLK;
+ break;
+ case 2:
+ sdtr2 |= SDRAM_SDTR2_WTR_2_CLK;
+ break;
+ case 3:
+ sdtr2 |= SDRAM_SDTR2_WTR_3_CLK;
+ break;
+ default:
+ sdtr2 |= SDRAM_SDTR2_WTR_4_CLK;
+ break;
+ }
+
+ /*
+ * convert from nanoseconds to ddr clocks
+ * round up if necessary
+ */
+ t_rpc_clk = MULDIV64(sdram_freq, t_rpc_ns, ONE_BILLION);
+ ddr_check = MULDIV64(ONE_BILLION, t_rpc_clk, t_rpc_ns);
+ if (sdram_freq != ddr_check)
+ t_rpc_clk++;
+
+ switch (t_rpc_clk) {
+ case 0:
+ case 1:
+ case 2:
+ sdtr2 |= SDRAM_SDTR2_RPC_2_CLK;
+ break;
+ case 3:
+ sdtr2 |= SDRAM_SDTR2_RPC_3_CLK;
+ break;
+ default:
+ sdtr2 |= SDRAM_SDTR2_RPC_4_CLK;
+ break;
+ }
+ }
+
+ /* default value */
+ sdtr2 |= SDRAM_SDTR2_XSNR_16_CLK;
+
+ /*
+ * convert t_rrd from nanoseconds to ddr clocks
+ * round up if necessary
+ */
+ t_rrd_clk = MULDIV64(sdram_freq, t_rrd_ns, ONE_BILLION);
+ ddr_check = MULDIV64(ONE_BILLION, t_rrd_clk, t_rrd_ns);
+ if (sdram_freq != ddr_check)
+ t_rrd_clk++;
+
+ if (t_rrd_clk == 3)
+ sdtr2 |= SDRAM_SDTR2_RRD_3_CLK;
+ else
+ sdtr2 |= SDRAM_SDTR2_RRD_2_CLK;
+
+ /*
+ * convert t_rp from nanoseconds to ddr clocks
+ * round up if necessary
+ */
+ t_rp_clk = MULDIV64(sdram_freq, t_rp_ns, ONE_BILLION);
+ ddr_check = MULDIV64(ONE_BILLION, t_rp_clk, t_rp_ns);
+ if (sdram_freq != ddr_check)
+ t_rp_clk++;
+
+ switch (t_rp_clk) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ sdtr2 |= SDRAM_SDTR2_RP_3_CLK;
+ break;
+ case 4:
+ sdtr2 |= SDRAM_SDTR2_RP_4_CLK;
+ break;
+ case 5:
+ sdtr2 |= SDRAM_SDTR2_RP_5_CLK;
+ break;
+ case 6:
+ sdtr2 |= SDRAM_SDTR2_RP_6_CLK;
+ break;
+ default:
+ sdtr2 |= SDRAM_SDTR2_RP_7_CLK;
+ break;
+ }
+
+ mtsdram(SDRAM_SDTR2, sdtr2);
+
+ /*------------------------------------------------------------------
+ * Set the SDRAM Timing Reg 3, SDRAM_TR3
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_SDTR3, sdtr3);
+ sdtr3 &= ~(SDRAM_SDTR3_RAS_MASK | SDRAM_SDTR3_RC_MASK |
+ SDRAM_SDTR3_XCS_MASK | SDRAM_SDTR3_RFC_MASK);
+
+ /*
+ * convert t_ras from nanoseconds to ddr clocks
+ * round up if necessary
+ */
+ t_ras_clk = MULDIV64(sdram_freq, t_ras_ns, ONE_BILLION);
+ ddr_check = MULDIV64(ONE_BILLION, t_ras_clk, t_ras_ns);
+ if (sdram_freq != ddr_check)
+ t_ras_clk++;
+
+ sdtr3 |= SDRAM_SDTR3_RAS_ENCODE(t_ras_clk);
+
+ /*
+ * convert t_rc from nanoseconds to ddr clocks
+ * round up if necessary
+ */
+ t_rc_clk = MULDIV64(sdram_freq, t_rc_ns, ONE_BILLION);
+ ddr_check = MULDIV64(ONE_BILLION, t_rc_clk, t_rc_ns);
+ if (sdram_freq != ddr_check)
+ t_rc_clk++;
+
+ sdtr3 |= SDRAM_SDTR3_RC_ENCODE(t_rc_clk);
+
+ /* default xcs value */
+ sdtr3 |= SDRAM_SDTR3_XCS;
+
+ /*
+ * convert t_rfc from nanoseconds to ddr clocks
+ * round up if necessary
+ */
+ t_rfc_clk = MULDIV64(sdram_freq, t_rfc_ns, ONE_BILLION);
+ ddr_check = MULDIV64(ONE_BILLION, t_rfc_clk, t_rfc_ns);
+ if (sdram_freq != ddr_check)
+ t_rfc_clk++;
+
+ sdtr3 |= SDRAM_SDTR3_RFC_ENCODE(t_rfc_clk);
+
+ mtsdram(SDRAM_SDTR3, sdtr3);
+}
+
+/*-----------------------------------------------------------------------------+
+ * program_bxcf.
+ *-----------------------------------------------------------------------------*/
+static void program_bxcf(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long num_col_addr;
+ unsigned long num_ranks;
+ unsigned long num_banks;
+ unsigned long mode;
+ unsigned long ind_rank;
+ unsigned long ind;
+ unsigned long ind_bank;
+ unsigned long bank_0_populated;
+
+ /*------------------------------------------------------------------
+ * Set the BxCF regs. First, wipe out the bank config registers.
+ *-----------------------------------------------------------------*/
+ mtdcr(SDRAMC_CFGADDR, SDRAM_MB0CF);
+ mtdcr(SDRAMC_CFGDATA, 0x00000000);
+ mtdcr(SDRAMC_CFGADDR, SDRAM_MB1CF);
+ mtdcr(SDRAMC_CFGDATA, 0x00000000);
+ mtdcr(SDRAMC_CFGADDR, SDRAM_MB2CF);
+ mtdcr(SDRAMC_CFGDATA, 0x00000000);
+ mtdcr(SDRAMC_CFGADDR, SDRAM_MB3CF);
+ mtdcr(SDRAMC_CFGDATA, 0x00000000);
+
+ mode = SDRAM_BXCF_M_BE_ENABLE;
+
+ bank_0_populated = 0;
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] != SDRAM_NONE) {
+ num_col_addr = spd_read(iic0_dimm_addr[dimm_num], 4);
+ num_ranks = spd_read(iic0_dimm_addr[dimm_num], 5);
+ if ((spd_read(iic0_dimm_addr[dimm_num], 2)) == 0x08)
+ num_ranks = (num_ranks & 0x0F) +1;
+ else
+ num_ranks = num_ranks & 0x0F;
+
+ num_banks = spd_read(iic0_dimm_addr[dimm_num], 17);
+
+ for (ind_bank = 0; ind_bank < 2; ind_bank++) {
+ if (num_banks == 4)
+ ind = 0;
+ else
+ ind = 5;
+ switch (num_col_addr) {
+ case 0x08:
+ mode |= (SDRAM_BXCF_M_AM_0 + ind);
+ break;
+ case 0x09:
+ mode |= (SDRAM_BXCF_M_AM_1 + ind);
+ break;
+ case 0x0A:
+ mode |= (SDRAM_BXCF_M_AM_2 + ind);
+ break;
+ case 0x0B:
+ mode |= (SDRAM_BXCF_M_AM_3 + ind);
+ break;
+ case 0x0C:
+ mode |= (SDRAM_BXCF_M_AM_4 + ind);
+ break;
+ default:
+ printf("DDR-SDRAM: DIMM %d BxCF configuration.\n",
+ (unsigned int)dimm_num);
+ printf("ERROR: Unsupported value for number of "
+ "column addresses: %d.\n", (unsigned int)num_col_addr);
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ hang();
+ }
+ }
+
+ if ((dimm_populated[dimm_num] != SDRAM_NONE)&& (dimm_num ==1))
+ bank_0_populated = 1;
+
+ for (ind_rank = 0; ind_rank < num_ranks; ind_rank++) {
+ mtdcr(SDRAMC_CFGADDR, SDRAM_MB0CF + ((dimm_num + bank_0_populated + ind_rank) << 2));
+ mtdcr(SDRAMC_CFGDATA, mode);
+ }
+ }
+ }
+}
+
+/*------------------------------------------------------------------
+ * program memory queue.
+ *-----------------------------------------------------------------*/
+static void program_memory_queue(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long rank_base_addr;
+ unsigned long rank_reg;
+ unsigned long rank_size_bytes;
+ unsigned long rank_size_id;
+ unsigned long num_ranks;
+ unsigned long baseadd_size;
+ unsigned long i;
+ unsigned long bank_0_populated = 0;
+
+ /*------------------------------------------------------------------
+ * Reset the rank_base_address.
+ *-----------------------------------------------------------------*/
+ rank_reg = SDRAM_R0BAS;
+
+ rank_base_addr = 0x00000000;
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] != SDRAM_NONE) {
+ num_ranks = spd_read(iic0_dimm_addr[dimm_num], 5);
+ if ((spd_read(iic0_dimm_addr[dimm_num], 2)) == 0x08)
+ num_ranks = (num_ranks & 0x0F) + 1;
+ else
+ num_ranks = num_ranks & 0x0F;
+
+ rank_size_id = spd_read(iic0_dimm_addr[dimm_num], 31);
+
+ /*------------------------------------------------------------------
+ * Set the sizes
+ *-----------------------------------------------------------------*/
+ baseadd_size = 0;
+ rank_size_bytes = 4 * 1024 * 1024 * rank_size_id;
+ switch (rank_size_id) {
+ case 0x02:
+ baseadd_size |= SDRAM_RXBAS_SDSZ_8;
+ break;
+ case 0x04:
+ baseadd_size |= SDRAM_RXBAS_SDSZ_16;
+ break;
+ case 0x08:
+ baseadd_size |= SDRAM_RXBAS_SDSZ_32;
+ break;
+ case 0x10:
+ baseadd_size |= SDRAM_RXBAS_SDSZ_64;
+ break;
+ case 0x20:
+ baseadd_size |= SDRAM_RXBAS_SDSZ_128;
+ break;
+ case 0x40:
+ baseadd_size |= SDRAM_RXBAS_SDSZ_256;
+ break;
+ case 0x80:
+ baseadd_size |= SDRAM_RXBAS_SDSZ_512;
+ break;
+ default:
+ printf("DDR-SDRAM: DIMM %d memory queue configuration.\n",
+ (unsigned int)dimm_num);
+ printf("ERROR: Unsupported value for the banksize: %d.\n",
+ (unsigned int)rank_size_id);
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ hang();
+ }
+
+ if ((dimm_populated[dimm_num] != SDRAM_NONE) && (dimm_num == 1))
+ bank_0_populated = 1;
+
+ for (i = 0; i < num_ranks; i++) {
+ mtdcr_any(rank_reg+i+dimm_num+bank_0_populated,
+ (SDRAM_RXBAS_SDBA_ENCODE(rank_base_addr) |
+ baseadd_size));
+ rank_base_addr += rank_size_bytes;
+ }
+ }
+ }
+}
+
+/*-----------------------------------------------------------------------------+
+ * is_ecc_enabled.
+ *-----------------------------------------------------------------------------*/
+static unsigned long is_ecc_enabled(void)
+{
+ unsigned long dimm_num;
+ unsigned long ecc;
+ unsigned long val;
+
+ ecc = 0;
+ /* loop through all the DIMM slots on the board */
+ for (dimm_num = 0; dimm_num < MAXDIMMS; dimm_num++) {
+ mfsdram(SDRAM_MCOPT1, val);
+ ecc = max(ecc, SDRAM_MCOPT1_MCHK_CHK_DECODE(val));
+ }
+
+ return ecc;
+}
+
+#ifdef CONFIG_DDR_ECC
+/*-----------------------------------------------------------------------------+
+ * program_ecc.
+ *-----------------------------------------------------------------------------*/
+static void program_ecc(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks,
+ unsigned long tlb_word2_i_value)
+{
+ unsigned long mcopt1;
+ unsigned long mcopt2;
+ unsigned long mcstat;
+ unsigned long dimm_num;
+ unsigned long ecc;
+
+ ecc = 0;
+ /* loop through all the DIMM slots on the board */
+ for (dimm_num = 0; dimm_num < MAXDIMMS; dimm_num++) {
+ /* If a dimm is installed in a particular slot ... */
+ if (dimm_populated[dimm_num] != SDRAM_NONE)
+ ecc = max(ecc, spd_read(iic0_dimm_addr[dimm_num], 11));
+ }
+ if (ecc == 0)
+ return;
+
+ mfsdram(SDRAM_MCOPT1, mcopt1);
+ mfsdram(SDRAM_MCOPT2, mcopt2);
+
+ if ((mcopt1 & SDRAM_MCOPT1_MCHK_MASK) != SDRAM_MCOPT1_MCHK_NON) {
+ /* DDR controller must be enabled and not in self-refresh. */
+ mfsdram(SDRAM_MCSTAT, mcstat);
+ if (((mcopt2 & SDRAM_MCOPT2_DCEN_MASK) == SDRAM_MCOPT2_DCEN_ENABLE)
+ && ((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))) {
+
+ 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
+
+static void wait_ddr_idle(void)
+{
+ u32 val;
+
+ do {
+ mfsdram(SDRAM_MCSTAT, val);
+ } while ((val & SDRAM_MCSTAT_IDLE_MASK) == SDRAM_MCSTAT_IDLE_NOT);
+}
+
+/*-----------------------------------------------------------------------------+
+ * program_ecc_addr.
+ *-----------------------------------------------------------------------------*/
+static void program_ecc_addr(unsigned long start_address,
+ 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);
+ if ((mcopt1 & SDRAM_MCOPT1_MCHK_MASK) != SDRAM_MCOPT1_MCHK_NON) {
+ mtsdram(SDRAM_MCOPT1,
+ (mcopt1 & ~SDRAM_MCOPT1_MCHK_MASK) | SDRAM_MCOPT1_MCHK_GEN);
+ sync();
+ eieio();
+ wait_ddr_idle();
+
+ 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;
+ }
+ } 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_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
+ }
+}
+#endif
+
+/*-----------------------------------------------------------------------------+
+ * program_DQS_calibration.
+ *-----------------------------------------------------------------------------*/
+static void program_DQS_calibration(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long val;
+
+#ifdef HARD_CODED_DQS /* calibration test with hardvalues */
+ mtsdram(SDRAM_RQDC, 0x80000037);
+ mtsdram(SDRAM_RDCC, 0x40000000);
+ mtsdram(SDRAM_RFDC, 0x000001DF);
+
+ test();
+#else
+ /*------------------------------------------------------------------
+ * Program RDCC register
+ * Read sample cycle auto-update enable
+ *-----------------------------------------------------------------*/
+
+ /*
+ * Modified for the Katmai platform: with some DIMMs, the DDR2
+ * controller automatically selects the T2 read cycle, but this
+ * proves unreliable. Go ahead and force the DDR2 controller
+ * to use the T4 sample and disable the automatic update of the
+ * RDSS field.
+ */
+ mfsdram(SDRAM_RDCC, val);
+ mtsdram(SDRAM_RDCC,
+ (val & ~(SDRAM_RDCC_RDSS_MASK | SDRAM_RDCC_RSAE_MASK))
+ | (SDRAM_RDCC_RDSS_T4 | SDRAM_RDCC_RSAE_DISABLE));
+
+ /*------------------------------------------------------------------
+ * Program RQDC register
+ * Internal DQS delay mechanism enable
+ *-----------------------------------------------------------------*/
+ mtsdram(SDRAM_RQDC, (SDRAM_RQDC_RQDE_ENABLE|SDRAM_RQDC_RQFD_ENCODE(0x38)));
+
+ /*------------------------------------------------------------------
+ * Program RFDC register
+ * Set Feedback Fractional Oversample
+ * Auto-detect read sample cycle enable
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_RFDC, val);
+ mtsdram(SDRAM_RFDC,
+ (val & ~(SDRAM_RFDC_ARSE_MASK | SDRAM_RFDC_RFOS_MASK |
+ SDRAM_RFDC_RFFD_MASK))
+ | (SDRAM_RFDC_ARSE_ENABLE | SDRAM_RFDC_RFOS_ENCODE(0) |
+ SDRAM_RFDC_RFFD_ENCODE(0)));
+
+ DQS_calibration_process();
+#endif
+}
+
+static u32 short_mem_test(void)
+{
+ u32 *membase;
+ u32 bxcr_num;
+ u32 bxcf;
+ int i;
+ int j;
+ u32 test[NUMMEMTESTS][NUMMEMWORDS] = {
+ {0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF},
+ {0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000},
+ {0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+ 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555},
+ {0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+ 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA},
+ {0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A,
+ 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A},
+ {0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
+ 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5},
+ {0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
+ 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA},
+ {0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55,
+ 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55} };
+
+ for (bxcr_num = 0; bxcr_num < MAXBXCF; bxcr_num++) {
+ mfsdram(SDRAM_MB0CF + (bxcr_num << 2), bxcf);
+
+ /* Banks enabled */
+ if ((bxcf & SDRAM_BXCF_M_BE_MASK) == SDRAM_BXCF_M_BE_ENABLE) {
+
+ /* Bank is enabled */
+ membase = (u32 *)(SDRAM_RXBAS_SDBA_DECODE(mfdcr_any(SDRAM_R0BAS+bxcr_num)));
+
+ /*------------------------------------------------------------------
+ * Run the short memory test.
+ *-----------------------------------------------------------------*/
+ for (i = 0; i < NUMMEMTESTS; i++) {
+ for (j = 0; j < NUMMEMWORDS; j++) {
+ membase[j] = test[i][j];
+ ppcDcbf((u32)&(membase[j]));
+ }
+ sync();
+ for (j = 0; j < NUMMEMWORDS; j++) {
+ if (membase[j] != test[i][j]) {
+ ppcDcbf((u32)&(membase[j]));
+ break;
+ }
+ ppcDcbf((u32)&(membase[j]));
+ }
+ sync();
+ if (j < NUMMEMWORDS)
+ break;
+ }
+ if (i < NUMMEMTESTS)
+ break;
+ } /* if bank enabled */
+ } /* for bxcf_num */
+
+ return bxcr_num;
+}
+
+#ifndef HARD_CODED_DQS
+/*-----------------------------------------------------------------------------+
+ * DQS_calibration_process.
+ *-----------------------------------------------------------------------------*/
+static void DQS_calibration_process(void)
+{
+ unsigned long ecc_temp;
+ unsigned long rfdc_reg;
+ unsigned long rffd;
+ unsigned long rqdc_reg;
+ unsigned long rqfd;
+ unsigned long bxcr_num;
+ unsigned long val;
+ long rqfd_average;
+ long rffd_average;
+ long max_start;
+ long min_end;
+ unsigned long begin_rqfd[MAXRANKS];
+ unsigned long begin_rffd[MAXRANKS];
+ unsigned long end_rqfd[MAXRANKS];
+ unsigned long end_rffd[MAXRANKS];
+ char window_found;
+ unsigned long dlycal;
+ unsigned long dly_val;
+ unsigned long max_pass_length;
+ unsigned long current_pass_length;
+ unsigned long current_fail_length;
+ unsigned long current_start;
+ long max_end;
+ unsigned char fail_found;
+ unsigned char pass_found;
+
+ /*------------------------------------------------------------------
+ * Test to determine the best read clock delay tuning bits.
+ *
+ * Before the DDR controller can be used, the read clock delay needs to be
+ * set. This is SDRAM_RQDC[RQFD] and SDRAM_RFDC[RFFD].
+ * This value cannot be hardcoded into the program because it changes
+ * depending on the board's setup and environment.
+ * To do this, all delay values are tested to see if they
+ * work or not. By doing this, you get groups of fails with groups of
+ * passing values. The idea is to find the start and end of a passing
+ * window and take the center of it to use as the read clock delay.
+ *
+ * A failure has to be seen first so that when we hit a pass, we know
+ * that it is truely the start of the window. If we get passing values
+ * to start off with, we don't know if we are at the start of the window.
+ *
+ * The code assumes that a failure will always be found.
+ * If a failure is not found, there is no easy way to get the middle
+ * of the passing window. I guess we can pretty much pick any value
+ * but some values will be better than others. Since the lowest speed
+ * we can clock the DDR interface at is 200 MHz (2x 100 MHz PLB speed),
+ * from experimentation it is safe to say you will always have a failure.
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_MCOPT1, ecc_temp);
+ ecc_temp &= SDRAM_MCOPT1_MCHK_MASK;
+ mfsdram(SDRAM_MCOPT1, val);
+ mtsdram(SDRAM_MCOPT1, (val & ~SDRAM_MCOPT1_MCHK_MASK) |
+ SDRAM_MCOPT1_MCHK_NON);
+
+ max_start = 0;
+ min_end = 0;
+ begin_rqfd[0] = 0;
+ begin_rffd[0] = 0;
+ begin_rqfd[1] = 0;
+ begin_rffd[1] = 0;
+ end_rqfd[0] = 0;
+ end_rffd[0] = 0;
+ end_rqfd[1] = 0;
+ end_rffd[1] = 0;
+ window_found = FALSE;
+
+ max_pass_length = 0;
+ max_start = 0;
+ max_end = 0;
+ current_pass_length = 0;
+ current_fail_length = 0;
+ current_start = 0;
+ window_found = FALSE;
+ fail_found = FALSE;
+ pass_found = FALSE;
+
+ /* first fix RQDC[RQFD] to an average of 80 degre phase shift to find RFDC[RFFD] */
+ /* rqdc_reg = mfsdram(SDRAM_RQDC) & ~(SDRAM_RQDC_RQFD_MASK); */
+
+ /*
+ * get the delay line calibration register value
+ */
+ mfsdram(SDRAM_DLCR, dlycal);
+ dly_val = SDRAM_DLYCAL_DLCV_DECODE(dlycal) << 2;
+
+ for (rffd = 0; rffd <= SDRAM_RFDC_RFFD_MAX; rffd++) {
+ mfsdram(SDRAM_RFDC, rfdc_reg);
+ rfdc_reg &= ~(SDRAM_RFDC_RFFD_MASK);
+
+ /*------------------------------------------------------------------
+ * Set the timing reg for the test.
+ *-----------------------------------------------------------------*/
+ mtsdram(SDRAM_RFDC, rfdc_reg | SDRAM_RFDC_RFFD_ENCODE(rffd));
+
+ /* do the small memory test */
+ bxcr_num = short_mem_test();
+
+ /*------------------------------------------------------------------
+ * See if the rffd value passed.
+ *-----------------------------------------------------------------*/
+ if (bxcr_num == MAXBXCF) {
+ if (fail_found == TRUE) {
+ pass_found = TRUE;
+ if (current_pass_length == 0)
+ current_start = rffd;
+
+ current_fail_length = 0;
+ current_pass_length++;
+
+ if (current_pass_length > max_pass_length) {
+ max_pass_length = current_pass_length;
+ max_start = current_start;
+ max_end = rffd;
+ }
+ }
+ } else {
+ current_pass_length = 0;
+ current_fail_length++;
+
+ if (current_fail_length >= (dly_val >> 2)) {
+ if (fail_found == FALSE) {
+ fail_found = TRUE;
+ } else if (pass_found == TRUE) {
+ window_found = TRUE;
+ break;
+ }
+ }
+ }
+ } /* for rffd */
+
+ /*------------------------------------------------------------------
+ * Set the average RFFD value
+ *-----------------------------------------------------------------*/
+ rffd_average = ((max_start + max_end) >> 1);
+
+ if (rffd_average < 0)
+ rffd_average = 0;
+
+ if (rffd_average > SDRAM_RFDC_RFFD_MAX)
+ rffd_average = SDRAM_RFDC_RFFD_MAX;
+ /* now fix RFDC[RFFD] found and find RQDC[RQFD] */
+ mtsdram(SDRAM_RFDC, rfdc_reg | SDRAM_RFDC_RFFD_ENCODE(rffd_average));
+
+ max_pass_length = 0;
+ max_start = 0;
+ max_end = 0;
+ current_pass_length = 0;
+ current_fail_length = 0;
+ current_start = 0;
+ window_found = FALSE;
+ fail_found = FALSE;
+ pass_found = FALSE;
+
+ for (rqfd = 0; rqfd <= SDRAM_RQDC_RQFD_MAX; rqfd++) {
+ mfsdram(SDRAM_RQDC, rqdc_reg);
+ rqdc_reg &= ~(SDRAM_RQDC_RQFD_MASK);
+
+ /*------------------------------------------------------------------
+ * Set the timing reg for the test.
+ *-----------------------------------------------------------------*/
+ mtsdram(SDRAM_RQDC, rqdc_reg | SDRAM_RQDC_RQFD_ENCODE(rqfd));
+
+ /* do the small memory test */
+ bxcr_num = short_mem_test();
+
+ /*------------------------------------------------------------------
+ * See if the rffd value passed.
+ *-----------------------------------------------------------------*/
+ if (bxcr_num == MAXBXCF) {
+ if (fail_found == TRUE) {
+ pass_found = TRUE;
+ if (current_pass_length == 0)
+ current_start = rqfd;
+
+ current_fail_length = 0;
+ current_pass_length++;
+
+ if (current_pass_length > max_pass_length) {
+ max_pass_length = current_pass_length;
+ max_start = current_start;
+ max_end = rqfd;
+ }
+ }
+ } else {
+ current_pass_length = 0;
+ current_fail_length++;
+
+ if (fail_found == FALSE) {
+ fail_found = TRUE;
+ } else if (pass_found == TRUE) {
+ window_found = TRUE;
+ break;
+ }
+ }
+ }
+
+ /*------------------------------------------------------------------
+ * Make sure we found the valid read passing window. Halt if not
+ *-----------------------------------------------------------------*/
+ if (window_found == FALSE) {
+ printf("ERROR: Cannot determine a common read delay for the "
+ "DIMM(s) installed.\n");
+ debug("%s[%d] ERROR : \n", __FUNCTION__,__LINE__);
+ hang();
+ }
+
+ rqfd_average = ((max_start + max_end) >> 1);
+
+ if (rqfd_average < 0)
+ rqfd_average = 0;
+
+ if (rqfd_average > SDRAM_RQDC_RQFD_MAX)
+ rqfd_average = SDRAM_RQDC_RQFD_MAX;
+
+ /*------------------------------------------------------------------
+ * Restore the ECC variable to what it originally was
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_MCOPT1, val);
+ mtsdram(SDRAM_MCOPT1, (val & ~SDRAM_MCOPT1_MCHK_MASK) | ecc_temp);
+
+ mtsdram(SDRAM_RQDC,
+ (rqdc_reg & ~SDRAM_RQDC_RQFD_MASK) |
+ SDRAM_RQDC_RQFD_ENCODE(rqfd_average));
+
+ mfsdram(SDRAM_DLCR, val);
+ debug("%s[%d] DLCR: 0x%08X\n", __FUNCTION__, __LINE__, val);
+ mfsdram(SDRAM_RQDC, val);
+ debug("%s[%d] RQDC: 0x%08X\n", __FUNCTION__, __LINE__, val);
+ mfsdram(SDRAM_RFDC, val);
+ debug("%s[%d] RFDC: 0x%08X\n", __FUNCTION__, __LINE__, val);
+}
+#else /* calibration test with hardvalues */
+/*-----------------------------------------------------------------------------+
+ * DQS_calibration_process.
+ *-----------------------------------------------------------------------------*/
+static void test(void)
+{
+ unsigned long dimm_num;
+ unsigned long ecc_temp;
+ unsigned long i, j;
+ unsigned long *membase;
+ unsigned long bxcf[MAXRANKS];
+ unsigned long val;
+ char window_found;
+ char begin_found[MAXDIMMS];
+ char end_found[MAXDIMMS];
+ char search_end[MAXDIMMS];
+ unsigned long test[NUMMEMTESTS][NUMMEMWORDS] = {
+ {0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF},
+ {0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000},
+ {0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+ 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555},
+ {0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+ 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA},
+ {0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A,
+ 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A},
+ {0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
+ 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5},
+ {0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
+ 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA},
+ {0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55,
+ 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55} };
+
+ /*------------------------------------------------------------------
+ * Test to determine the best read clock delay tuning bits.
+ *
+ * Before the DDR controller can be used, the read clock delay needs to be
+ * set. This is SDRAM_RQDC[RQFD] and SDRAM_RFDC[RFFD].
+ * This value cannot be hardcoded into the program because it changes
+ * depending on the board's setup and environment.
+ * To do this, all delay values are tested to see if they
+ * work or not. By doing this, you get groups of fails with groups of
+ * passing values. The idea is to find the start and end of a passing
+ * window and take the center of it to use as the read clock delay.
+ *
+ * A failure has to be seen first so that when we hit a pass, we know
+ * that it is truely the start of the window. If we get passing values
+ * to start off with, we don't know if we are at the start of the window.
+ *
+ * The code assumes that a failure will always be found.
+ * If a failure is not found, there is no easy way to get the middle
+ * of the passing window. I guess we can pretty much pick any value
+ * but some values will be better than others. Since the lowest speed
+ * we can clock the DDR interface at is 200 MHz (2x 100 MHz PLB speed),
+ * from experimentation it is safe to say you will always have a failure.
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_MCOPT1, ecc_temp);
+ ecc_temp &= SDRAM_MCOPT1_MCHK_MASK;
+ mfsdram(SDRAM_MCOPT1, val);
+ mtsdram(SDRAM_MCOPT1, (val & ~SDRAM_MCOPT1_MCHK_MASK) |
+ SDRAM_MCOPT1_MCHK_NON);
+
+ window_found = FALSE;
+ begin_found[0] = FALSE;
+ end_found[0] = FALSE;
+ search_end[0] = FALSE;
+ begin_found[1] = FALSE;
+ end_found[1] = FALSE;
+ search_end[1] = FALSE;
+
+ for (dimm_num = 0; dimm_num < MAXDIMMS; dimm_num++) {
+ mfsdram(SDRAM_MB0CF + (bxcr_num << 2), bxcf[bxcr_num]);
+
+ /* Banks enabled */
+ if ((bxcf[dimm_num] & SDRAM_BXCF_M_BE_MASK) == SDRAM_BXCF_M_BE_ENABLE) {
+
+ /* Bank is enabled */
+ membase =
+ (unsigned long*)(SDRAM_RXBAS_SDBA_DECODE(mfdcr_any(SDRAM_R0BAS+dimm_num)));
+
+ /*------------------------------------------------------------------
+ * Run the short memory test.
+ *-----------------------------------------------------------------*/
+ for (i = 0; i < NUMMEMTESTS; i++) {
+ for (j = 0; j < NUMMEMWORDS; j++) {
+ membase[j] = test[i][j];
+ ppcDcbf((u32)&(membase[j]));
+ }
+ sync();
+ for (j = 0; j < NUMMEMWORDS; j++) {
+ if (membase[j] != test[i][j]) {
+ ppcDcbf((u32)&(membase[j]));
+ break;
+ }
+ ppcDcbf((u32)&(membase[j]));
+ }
+ sync();
+ if (j < NUMMEMWORDS)
+ break;
+ }
+
+ /*------------------------------------------------------------------
+ * See if the rffd value passed.
+ *-----------------------------------------------------------------*/
+ if (i < NUMMEMTESTS) {
+ if ((end_found[dimm_num] == FALSE) &&
+ (search_end[dimm_num] == TRUE)) {
+ end_found[dimm_num] = TRUE;
+ }
+ if ((end_found[0] == TRUE) &&
+ (end_found[1] == TRUE))
+ break;
+ } else {
+ if (begin_found[dimm_num] == FALSE) {
+ begin_found[dimm_num] = TRUE;
+ search_end[dimm_num] = TRUE;
+ }
+ }
+ } else {
+ begin_found[dimm_num] = TRUE;
+ end_found[dimm_num] = TRUE;
+ }
+ }
+
+ if ((begin_found[0] == TRUE) && (begin_found[1] == TRUE))
+ window_found = TRUE;
+
+ /*------------------------------------------------------------------
+ * Make sure we found the valid read passing window. Halt if not
+ *-----------------------------------------------------------------*/
+ if (window_found == FALSE) {
+ printf("ERROR: Cannot determine a common read delay for the "
+ "DIMM(s) installed.\n");
+ hang();
+ }
+
+ /*------------------------------------------------------------------
+ * Restore the ECC variable to what it originally was
+ *-----------------------------------------------------------------*/
+ mtsdram(SDRAM_MCOPT1,
+ (ppcMfdcr_sdram(SDRAM_MCOPT1) & ~SDRAM_MCOPT1_MCHK_MASK)
+ | ecc_temp);
+}
+#endif
+
+#if defined(DEBUG)
+static void ppc440sp_sdram_register_dump(void)
+{
+ unsigned int sdram_reg;
+ unsigned int sdram_data;
+ unsigned int dcr_data;
+
+ printf("\n Register Dump:\n");
+ sdram_reg = SDRAM_MCSTAT;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_MCSTAT = 0x%08X", sdram_data);
+ sdram_reg = SDRAM_MCOPT1;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_MCOPT1 = 0x%08X\n", sdram_data);
+ sdram_reg = SDRAM_MCOPT2;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_MCOPT2 = 0x%08X", sdram_data);
+ sdram_reg = SDRAM_MODT0;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_MODT0 = 0x%08X\n", sdram_data);
+ sdram_reg = SDRAM_MODT1;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_MODT1 = 0x%08X", sdram_data);
+ sdram_reg = SDRAM_MODT2;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_MODT2 = 0x%08X\n", sdram_data);
+ sdram_reg = SDRAM_MODT3;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_MODT3 = 0x%08X", sdram_data);
+ sdram_reg = SDRAM_CODT;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_CODT = 0x%08X\n", sdram_data);
+ sdram_reg = SDRAM_VVPR;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_VVPR = 0x%08X", sdram_data);
+ sdram_reg = SDRAM_OPARS;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_OPARS = 0x%08X\n", sdram_data);
+ /*
+ * OPAR2 is only used as a trigger register.
+ * No data is contained in this register, and reading or writing
+ * to is can cause bad things to happen (hangs). Just skip it
+ * and report NA
+ * sdram_reg = SDRAM_OPAR2;
+ * mfsdram(sdram_reg, sdram_data);
+ * printf(" SDRAM_OPAR2 = 0x%08X\n", sdram_data);
+ */
+ printf(" SDRAM_OPART = N/A ");
+ sdram_reg = SDRAM_RTR;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_RTR = 0x%08X\n", sdram_data);
+ sdram_reg = SDRAM_MB0CF;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_MB0CF = 0x%08X", sdram_data);
+ sdram_reg = SDRAM_MB1CF;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_MB1CF = 0x%08X\n", sdram_data);
+ sdram_reg = SDRAM_MB2CF;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_MB2CF = 0x%08X", sdram_data);
+ sdram_reg = SDRAM_MB3CF;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_MB3CF = 0x%08X\n", sdram_data);
+ sdram_reg = SDRAM_INITPLR0;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_INITPLR0 = 0x%08X", sdram_data);
+ sdram_reg = SDRAM_INITPLR1;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_INITPLR1 = 0x%08X\n", sdram_data);
+ sdram_reg = SDRAM_INITPLR2;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_INITPLR2 = 0x%08X", sdram_data);
+ sdram_reg = SDRAM_INITPLR3;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_INITPLR3 = 0x%08X\n", sdram_data);
+ sdram_reg = SDRAM_INITPLR4;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_INITPLR4 = 0x%08X", sdram_data);
+ sdram_reg = SDRAM_INITPLR5;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_INITPLR5 = 0x%08X\n", sdram_data);
+ sdram_reg = SDRAM_INITPLR6;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_INITPLR6 = 0x%08X", sdram_data);
+ sdram_reg = SDRAM_INITPLR7;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_INITPLR7 = 0x%08X\n", sdram_data);
+ sdram_reg = SDRAM_INITPLR8;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_INITPLR8 = 0x%08X", sdram_data);
+ sdram_reg = SDRAM_INITPLR9;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_INITPLR9 = 0x%08X\n", sdram_data);
+ sdram_reg = SDRAM_INITPLR10;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_INITPLR10 = 0x%08X", sdram_data);
+ sdram_reg = SDRAM_INITPLR11;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_INITPLR11 = 0x%08X\n", sdram_data);
+ sdram_reg = SDRAM_INITPLR12;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_INITPLR12 = 0x%08X", sdram_data);
+ sdram_reg = SDRAM_INITPLR13;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_INITPLR13 = 0x%08X\n", sdram_data);
+ sdram_reg = SDRAM_INITPLR14;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_INITPLR14 = 0x%08X", sdram_data);
+ sdram_reg = SDRAM_INITPLR15;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_INITPLR15 = 0x%08X\n", sdram_data);
+ sdram_reg = SDRAM_RQDC;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_RQDC = 0x%08X", sdram_data);
+ sdram_reg = SDRAM_RFDC;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_RFDC = 0x%08X\n", sdram_data);
+ sdram_reg = SDRAM_RDCC;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_RDCC = 0x%08X", sdram_data);
+ sdram_reg = SDRAM_DLCR;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_DLCR = 0x%08X\n", sdram_data);
+ sdram_reg = SDRAM_CLKTR;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_CLKTR = 0x%08X", sdram_data);
+ sdram_reg = SDRAM_WRDTR;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_WRDTR = 0x%08X\n", sdram_data);
+ sdram_reg = SDRAM_SDTR1;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_SDTR1 = 0x%08X", sdram_data);
+ sdram_reg = SDRAM_SDTR2;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_SDTR2 = 0x%08X\n", sdram_data);
+ sdram_reg = SDRAM_SDTR3;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_SDTR3 = 0x%08X", sdram_data);
+ sdram_reg = SDRAM_MMODE;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_MMODE = 0x%08X\n", sdram_data);
+ sdram_reg = SDRAM_MEMODE;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_MEMODE = 0x%08X", sdram_data);
+ sdram_reg = SDRAM_ECCCR;
+ mfsdram(sdram_reg, sdram_data);
+ printf(" SDRAM_ECCCR = 0x%08X\n\n", sdram_data);
+
+ dcr_data = mfdcr(SDRAM_R0BAS);
+ printf(" MQ0_B0BAS = 0x%08X", dcr_data);
+ dcr_data = mfdcr(SDRAM_R1BAS);
+ printf(" MQ1_B0BAS = 0x%08X\n", dcr_data);
+ dcr_data = mfdcr(SDRAM_R2BAS);
+ printf(" MQ2_B0BAS = 0x%08X", dcr_data);
+ dcr_data = mfdcr(SDRAM_R3BAS);
+ printf(" MQ3_B0BAS = 0x%08X\n", dcr_data);
+}
+#endif
+#endif /* CONFIG_SPD_EEPROM */
diff --git a/cpu/ppc4xx/4xx_enet.c b/cpu/ppc4xx/4xx_enet.c
index 81d49ff..cf56581 100644
--- a/cpu/ppc4xx/4xx_enet.c
+++ b/cpu/ppc4xx/4xx_enet.c
@@ -166,6 +166,11 @@ struct eth_device *emac0_dev = NULL;
#define LAST_EMAC_NUM 1
#endif
+/* normal boards start with EMAC0 */
+#if !defined(CONFIG_EMAC_NR_START)
+#define CONFIG_EMAC_NR_START 0
+#endif
+
/*-----------------------------------------------------------------------------+
* Prototypes and externals.
*-----------------------------------------------------------------------------*/
@@ -264,10 +269,10 @@ int ppc_4xx_eth_setup_bridge(int devnum, bd_t * bis)
bis->bi_phymode[3] = BI_PHYMODE_ZMII;
break;
case 2:
- zmiifer = ZMII_FER_SMII << ZMII_FER_V(0);
- zmiifer = ZMII_FER_SMII << ZMII_FER_V(1);
- zmiifer = ZMII_FER_SMII << ZMII_FER_V(2);
- zmiifer = ZMII_FER_SMII << ZMII_FER_V(3);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(0);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(1);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(2);
+ zmiifer |= ZMII_FER_SMII << ZMII_FER_V(3);
bis->bi_phymode[0] = BI_PHYMODE_ZMII;
bis->bi_phymode[1] = BI_PHYMODE_ZMII;
bis->bi_phymode[2] = BI_PHYMODE_ZMII;
@@ -470,8 +475,7 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
#else
if ((devnum == 0) || (devnum == 1)) {
out32 (ZMII_FER, (ZMII_FER_SMII | ZMII_FER_MDI) << ZMII_FER_V (devnum));
- }
- else { /* ((devnum == 2) || (devnum == 3)) */
+ } else { /* ((devnum == 2) || (devnum == 3)) */
out32 (ZMII_FER, ZMII_FER_MDI << ZMII_FER_V (devnum));
out32 (RGMII_FER, ((RGMII_FER_RGMII << RGMII_FER_V (2)) |
(RGMII_FER_RGMII << RGMII_FER_V (3))));
@@ -561,22 +565,7 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
* otherwise, just check the speeds & feeds
*/
if (hw_p->first_init == 0) {
-#if defined(CONFIG_88E1111_CLK_DELAY)
- /*
- * On some boards (e.g. ALPR) the Marvell 88E1111 PHY needs
- * the "RGMII transmit timing control" and "RGMII receive
- * timing control" bits set, so that Gbit communication works
- * without problems.
- * Also set the "Transmitter disable" to 1 to enable the
- * transmitter.
- * After setting these bits a soft-reset must occur for this
- * change to become active.
- */
- miiphy_read (dev->name, reg, 0x14, &reg_short);
- reg_short |= (1 << 7) | (1 << 1) | (1 << 0);
- miiphy_write (dev->name, reg, 0x14, reg_short);
-#endif
-#if defined(CONFIG_M88E1111_PHY) /* test-only: merge with CONFIG_88E1111_CLK_DELAY !!! */
+#if defined(CONFIG_M88E1111_PHY)
miiphy_write (dev->name, reg, 0x14, 0x0ce3);
miiphy_write (dev->name, reg, 0x18, 0x4101);
miiphy_write (dev->name, reg, 0x09, 0x0e00);
@@ -617,6 +606,26 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
/* end Vitesse/Cicada errata */
}
#endif
+
+#if defined(CONFIG_ET1011C_PHY)
+ /*
+ * Agere ET1011c PHY needs to have an extended register whacked
+ * for RGMII mode.
+ */
+ if (((devnum == 2) || (devnum ==3)) && (4 == ethgroup)) {
+ miiphy_read (dev->name, reg, 0x16, &reg_short);
+ reg_short &= ~(0x7);
+ reg_short |= 0x6; /* RGMII DLL Delay*/
+ miiphy_write (dev->name, reg, 0x16, reg_short);
+
+ miiphy_read (dev->name, reg, 0x17, &reg_short);
+ reg_short &= ~(0x40);
+ miiphy_write (dev->name, reg, 0x17, reg_short);
+
+ miiphy_write(dev->name, reg, 0x1c, 0x74f0);
+ }
+#endif
+
#endif
/* Start/Restart autonegotiation */
phy_setup_aneg (dev->name, reg);
@@ -659,8 +668,9 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
if (hw_p->print_speed) {
hw_p->print_speed = 0;
- printf ("ENET Speed is %d Mbps - %s duplex connection\n",
- (int) speed, (duplex == HALF) ? "HALF" : "FULL");
+ printf ("ENET Speed is %d Mbps - %s duplex connection (EMAC%d)\n",
+ (int) speed, (duplex == HALF) ? "HALF" : "FULL",
+ hw_p->devnum);
}
#if defined(CONFIG_440) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) && \
@@ -808,7 +818,7 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
hw_p->rx[i].ctrl |= MAL_RX_CTRL_EMPTY | MAL_RX_CTRL_INTR;
hw_p->rx_ready[i] = -1;
#if 0
- printf ("RX_BUFF %d @ 0x%08lx\n", i, (ulong) rx[i].data_ptr);
+ printf ("RX_BUFF %d @ 0x%08lx\n", i, (ulong) hw_p->rx[i].data_ptr);
#endif
}
@@ -1323,6 +1333,9 @@ int enetInt (struct eth_device *dev)
}
}
mtdcr (uicsr, MAL_UIC_DEF|EMAC_UIC_DEF|EMAC_UIC_DEF1); /* Clear */
+#if defined(CONFIG_405EZ)
+ mtsdr (sdricintstat, SDR_ICRX_STAT | SDR_ICTX0_STAT | SDR_ICTX1_STAT);
+#endif /* defined(CONFIG_405EZ) */
}
while (serviced);
@@ -1509,6 +1522,8 @@ int ppc_4xx_eth_initialize (bd_t * bis)
struct eth_device *dev;
int eth_num = 0;
EMAC_4XX_HW_PST hw = NULL;
+ u8 ethaddr[4 + CONFIG_EMAC_NR_START][6];
+ u32 hw_addr[4];
#if defined(CONFIG_440GX)
unsigned long pfc1;
@@ -1518,59 +1533,69 @@ int ppc_4xx_eth_initialize (bd_t * bis)
pfc1 |= 0x01200000;
mtsdr (sdr_pfc1, pfc1);
#endif
- /* set phy num and mode */
- bis->bi_phynum[0] = CONFIG_PHY_ADDR;
- bis->bi_phymode[0] = 0;
-
-#if defined(CONFIG_PHY1_ADDR)
- bis->bi_phynum[1] = CONFIG_PHY1_ADDR;
- bis->bi_phymode[1] = 0;
-#endif
-#if defined(CONFIG_440GX)
- bis->bi_phynum[2] = CONFIG_PHY2_ADDR;
- bis->bi_phynum[3] = CONFIG_PHY3_ADDR;
- bis->bi_phymode[2] = 2;
- bis->bi_phymode[3] = 2;
- ppc_4xx_eth_setup_bridge(0, bis);
-#endif
+ /* first clear all mac-addresses */
+ for (eth_num = 0; eth_num < LAST_EMAC_NUM; eth_num++)
+ memcpy(ethaddr[eth_num], "\0\0\0\0\0\0", 6);
for (eth_num = 0; eth_num < LAST_EMAC_NUM; eth_num++) {
-
- /* See if we can actually bring up the interface, otherwise, skip it */
switch (eth_num) {
default: /* fall through */
case 0:
- if (memcmp (bis->bi_enetaddr, "\0\0\0\0\0\0", 6) == 0) {
- bis->bi_phymode[eth_num] = BI_PHYMODE_NONE;
- continue;
- }
+ memcpy(ethaddr[eth_num + CONFIG_EMAC_NR_START],
+ bis->bi_enetaddr, 6);
+ hw_addr[eth_num] = 0x0;
break;
#ifdef CONFIG_HAS_ETH1
case 1:
- if (memcmp (bis->bi_enet1addr, "\0\0\0\0\0\0", 6) == 0) {
- bis->bi_phymode[eth_num] = BI_PHYMODE_NONE;
- continue;
- }
+ memcpy(ethaddr[eth_num + CONFIG_EMAC_NR_START],
+ bis->bi_enet1addr, 6);
+ hw_addr[eth_num] = 0x100;
break;
#endif
#ifdef CONFIG_HAS_ETH2
case 2:
- if (memcmp (bis->bi_enet2addr, "\0\0\0\0\0\0", 6) == 0) {
- bis->bi_phymode[eth_num] = BI_PHYMODE_NONE;
- continue;
- }
+ memcpy(ethaddr[eth_num + CONFIG_EMAC_NR_START],
+ bis->bi_enet2addr, 6);
+ hw_addr[eth_num] = 0x400;
break;
#endif
#ifdef CONFIG_HAS_ETH3
case 3:
- if (memcmp (bis->bi_enet3addr, "\0\0\0\0\0\0", 6) == 0) {
- bis->bi_phymode[eth_num] = BI_PHYMODE_NONE;
- continue;
- }
+ memcpy(ethaddr[eth_num + CONFIG_EMAC_NR_START],
+ bis->bi_enet3addr, 6);
+ hw_addr[eth_num] = 0x600;
break;
#endif
}
+ }
+
+ /* set phy num and mode */
+ bis->bi_phynum[0] = CONFIG_PHY_ADDR;
+ bis->bi_phymode[0] = 0;
+
+#if defined(CONFIG_PHY1_ADDR)
+ bis->bi_phynum[1] = CONFIG_PHY1_ADDR;
+ bis->bi_phymode[1] = 0;
+#endif
+#if defined(CONFIG_440GX)
+ bis->bi_phynum[2] = CONFIG_PHY2_ADDR;
+ bis->bi_phynum[3] = CONFIG_PHY3_ADDR;
+ bis->bi_phymode[2] = 2;
+ bis->bi_phymode[3] = 2;
+
+ ppc_4xx_eth_setup_bridge(0, bis);
+#endif
+
+ for (eth_num = 0; eth_num < LAST_EMAC_NUM; eth_num++) {
+ /*
+ * See if we can actually bring up the interface,
+ * otherwise, skip it
+ */
+ if (memcmp (ethaddr[eth_num], "\0\0\0\0\0\0", 6) == 0) {
+ bis->bi_phymode[eth_num] = BI_PHYMODE_NONE;
+ continue;
+ }
/* Allocate device structure */
dev = (struct eth_device *) malloc (sizeof (*dev));
@@ -1592,36 +1617,12 @@ int ppc_4xx_eth_initialize (bd_t * bis)
}
memset(hw, 0, sizeof(*hw));
- switch (eth_num) {
- default: /* fall through */
- case 0:
- hw->hw_addr = 0;
- memcpy (dev->enetaddr, bis->bi_enetaddr, 6);
- break;
-#ifdef CONFIG_HAS_ETH1
- case 1:
- hw->hw_addr = 0x100;
- memcpy (dev->enetaddr, bis->bi_enet1addr, 6);
- break;
-#endif
-#ifdef CONFIG_HAS_ETH2
- case 2:
- hw->hw_addr = 0x400;
- memcpy (dev->enetaddr, bis->bi_enet2addr, 6);
- break;
-#endif
-#ifdef CONFIG_HAS_ETH3
- case 3:
- hw->hw_addr = 0x600;
- memcpy (dev->enetaddr, bis->bi_enet3addr, 6);
- break;
-#endif
- }
-
+ hw->hw_addr = hw_addr[eth_num];
+ memcpy (dev->enetaddr, ethaddr[eth_num], 6);
hw->devnum = eth_num;
hw->print_speed = 1;
- sprintf (dev->name, "ppc_4xx_eth%d", eth_num);
+ sprintf (dev->name, "ppc_4xx_eth%d", eth_num - CONFIG_EMAC_NR_START);
dev->priv = (void *) hw;
dev->init = ppc_4xx_eth_init;
dev->halt = ppc_4xx_eth_halt;
@@ -1679,7 +1680,6 @@ int ppc_4xx_eth_initialize (bd_t * bis)
return (1);
}
-
#if !defined(CONFIG_NET_MULTI)
void eth_halt (void) {
if (emac0_dev) {
diff --git a/cpu/ppc4xx/Makefile b/cpu/ppc4xx/Makefile
index 87c6230..1347e0f 100644
--- a/cpu/ppc4xx/Makefile
+++ b/cpu/ppc4xx/Makefile
@@ -31,7 +31,9 @@ COBJS = 405gp_pci.o 440spe_pcie.o 4xx_enet.o \
bedbug_405.o commproc.o \
cpu.o cpu_init.o i2c.o interrupts.o \
miiphy.o ndfc.o sdram.o serial.o \
- spd_sdram.o speed.o traps.o usb_ohci.o usbdev.o usb.o
+ 40x_spd_sdram.o 44x_spd_ddr.o 44x_spd_ddr2.o speed.o \
+ tlb.o traps.o usb_ohci.o usbdev.o usb.o \
+ 440spe_pcie.o
SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
diff --git a/cpu/ppc4xx/cpu.c b/cpu/ppc4xx/cpu.c
index f4a7208..2d8740c 100644
--- a/cpu/ppc4xx/cpu.c
+++ b/cpu/ppc4xx/cpu.c
@@ -41,8 +41,15 @@
DECLARE_GLOBAL_DATA_PTR;
#endif
+#if defined(CONFIG_BOARD_RESET)
+void board_reset(void);
+#endif
+
#if defined(CONFIG_440)
#define FREQ_EBC (sys_info.freqEPB)
+#elif defined(CONFIG_405EZ)
+#define FREQ_EBC ((CONFIG_SYS_CLK_FREQ * sys_info.pllFbkDiv) / \
+ sys_info.pllExtBusDiv)
#else
#define FREQ_EBC (sys_info.freqPLB / sys_info.pllExtBusDiv)
#endif
@@ -84,14 +91,18 @@ int pci_arbiter_enabled(void)
return (mfdcr(cpc0_strp1) & CPC0_STRP1_PAE_MASK);
#endif
-#if defined(CONFIG_440GX) || \
- defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
- defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
- defined(CONFIG_440SP) || defined(CONFIG_440SPE)
+#if defined(CONFIG_440GX) || defined(CONFIG_440SP) || defined(CONFIG_440SPE)
unsigned long val;
- mfsdr(sdr_sdstp1, val);
- return (val & SDR0_SDSTP1_PAE_MASK);
+ mfsdr(sdr_xcr, val);
+ return (val & 0x80000000);
+#endif
+#if defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+ unsigned long val;
+
+ mfsdr(sdr_pci0, val);
+ return (val & 0x80000000);
#endif
}
#endif
@@ -201,7 +212,8 @@ int checkcpu (void)
puts("AMCC PowerPC 4");
-#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_405EP)
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
+ defined(CONFIG_405EP) || defined(CONFIG_405EZ)
puts("05");
#endif
#if defined(CONFIG_440)
@@ -249,6 +261,10 @@ int checkcpu (void)
puts("EP Rev. B");
break;
+ case PVR_405EZ_RA:
+ puts("EZ Rev. A");
+ break;
+
#if defined(CONFIG_440)
case PVR_440GP_RB:
puts("GP Rev. B");
@@ -308,40 +324,68 @@ int checkcpu (void)
#endif /* CONFIG_440GR */
#endif /* CONFIG_440 */
- case PVR_440EPX1_RA:
+#ifdef CONFIG_440EPX
+ case PVR_440EPX1_RA: /* 440EPx rev A and 440GRx rev A have same PVR */
puts("EPx Rev. A");
strcpy(addstr, "Security/Kasumi support");
break;
- case PVR_440EPX2_RA:
+ case PVR_440EPX2_RA: /* 440EPx rev A and 440GRx rev A have same PVR */
puts("EPx Rev. A");
strcpy(addstr, "No Security/Kasumi support");
break;
+#endif /* CONFIG_440EPX */
- case PVR_440GRX1_RA:
+#ifdef CONFIG_440GRX
+ case PVR_440GRX1_RA: /* 440EPx rev A and 440GRx rev A have same PVR */
puts("GRx Rev. A");
strcpy(addstr, "Security/Kasumi support");
break;
- case PVR_440GRX2_RA:
+ case PVR_440GRX2_RA: /* 440EPx rev A and 440GRx rev A have same PVR */
puts("GRx Rev. A");
strcpy(addstr, "No Security/Kasumi support");
break;
+#endif /* CONFIG_440GRX */
+
+ case PVR_440SP_6_RAB:
+ puts("SP Rev. A/B");
+ strcpy(addstr, "RAID 6 support");
+ break;
- case PVR_440SP_RA:
- puts("SP Rev. A");
+ case PVR_440SP_RAB:
+ puts("SP Rev. A/B");
+ strcpy(addstr, "No RAID 6 support");
break;
- case PVR_440SP_RB:
- puts("SP Rev. B");
+ case PVR_440SP_6_RC:
+ puts("SP Rev. C");
+ strcpy(addstr, "RAID 6 support");
+ break;
+
+ case PVR_440SP_RC:
+ puts("SP Rev. C");
+ strcpy(addstr, "No RAID 6 support");
+ break;
+
+ case PVR_440SPe_6_RA:
+ puts("SPe Rev. A");
+ strcpy(addstr, "RAID 6 support");
break;
case PVR_440SPe_RA:
puts("SPe Rev. A");
+ strcpy(addstr, "No RAID 6 support");
+ break;
+
+ case PVR_440SPe_6_RB:
+ puts("SPe Rev. B");
+ strcpy(addstr, "RAID 6 support");
break;
case PVR_440SPe_RB:
puts("SPe Rev. B");
+ strcpy(addstr, "No RAID 6 support");
break;
default:
@@ -350,9 +394,9 @@ int checkcpu (void)
}
printf (" at %s MHz (PLB=%lu, OPB=%lu, EBC=%lu MHz)\n", strmhz(buf, clock),
- sys_info.freqPLB / 1000000,
- sys_info.freqPLB / sys_info.pllOpbDiv / 1000000,
- FREQ_EBC / 1000000);
+ sys_info.freqPLB / 1000000,
+ get_OPB_freq() / 1000000,
+ FREQ_EBC / 1000000);
if (addstr[0] != 0)
printf(" %s\n", addstr);
@@ -382,7 +426,7 @@ int checkcpu (void)
putc('\n');
#endif
-#if defined(CONFIG_405EP)
+#if defined(CONFIG_405EP) || defined(CONFIG_405EZ)
printf (" 16 kB I-Cache 16 kB D-Cache");
#elif defined(CONFIG_440)
printf (" 32 kB I-Cache 32 kB D-Cache");
@@ -411,7 +455,7 @@ int ppc440spe_revB() {
unsigned int pvr;
pvr = get_pvr();
- if (pvr == PVR_440SPe_RB)
+ if ((pvr == PVR_440SPe_6_RB) || (pvr == PVR_440SPe_RB))
return 1;
else
return 0;
@@ -422,23 +466,19 @@ int ppc440spe_revB() {
int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
-#if defined(CONFIG_YOSEMITE) || defined(CONFIG_YELLOWSTONE)
- /*give reset to BCSR*/
- *(unsigned char*)(CFG_BCSR_BASE | 0x06) = 0x09;
-
+#if defined(CONFIG_BOARD_RESET)
+ board_reset();
+#else
+#if defined(CFG_4xx_RESET_TYPE)
+ mtspr(dbcr0, CFG_4xx_RESET_TYPE << 28);
#else
-
/*
* Initiate system reset in debug control register DBCR
*/
- __asm__ __volatile__("lis 3, 0x3000" ::: "r3");
-#if defined(CONFIG_440)
- __asm__ __volatile__("mtspr 0x134, 3");
-#else
- __asm__ __volatile__("mtspr 0x3f2, 3");
-#endif
+ mtspr(dbcr0, 0x30000000);
+#endif /* defined(CFG_4xx_RESET_TYPE) */
+#endif /* defined(CONFIG_BOARD_RESET) */
-#endif/* defined(CONFIG_YOSEMITE) || defined(CONFIG_YELLOWSTONE)*/
return 1;
}
diff --git a/cpu/ppc4xx/cpu_init.c b/cpu/ppc4xx/cpu_init.c
index def46f1..9d1cd13 100644
--- a/cpu/ppc4xx/cpu_init.c
+++ b/cpu/ppc4xx/cpu_init.c
@@ -31,9 +31,6 @@
DECLARE_GLOBAL_DATA_PTR;
#endif
-
-#define mtebc(reg, data) mtdcr(ebccfga,reg);mtdcr(ebccfgd,data)
-
#ifdef CFG_INIT_DCACHE_CS
# if (CFG_INIT_DCACHE_CS == 0)
# define PBxAP pb0ap
@@ -222,6 +219,10 @@ void set_chip_gpio_configuration(gpio_param_s (*gpio_tab)[GPIO_GROUP_MAX][GPIO_M
void
cpu_init_f (void)
{
+#if defined(CONFIG_WATCHDOG)
+ unsigned long val;
+#endif
+
#if defined(CONFIG_405EP)
/*
* GPIO0 setup (select GPIO or alternate function)
@@ -255,7 +256,8 @@ cpu_init_f (void)
*/
#if (defined(CFG_EBC_PB0AP) && defined(CFG_EBC_PB0CR))
#if (defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
- defined(CONFIG_405EP) || defined(CONFIG_405))
+ defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
+ defined(CONFIG_405))
/*
* Move the next instructions into icache, since these modify the flash
* we are running from!
@@ -312,15 +314,21 @@ cpu_init_f (void)
mtebc(pb7cr, CFG_EBC_PB7CR);
#endif
-#if defined(CONFIG_WATCHDOG)
- unsigned long val;
+#if defined (CFG_EBC_CFG)
+ mtebc(EBC0_CFG, CFG_EBC_CFG);
+#endif
+#if defined(CONFIG_WATCHDOG)
val = mfspr(tcr);
#if defined(CONFIG_440EP) || defined(CONFIG_440GR)
val |= 0xb8000000; /* generate system reset after 1.34 seconds */
#else
val |= 0xf0000000; /* generate system reset after 2.684 seconds */
#endif
+#if defined(CFG_4xx_RESET_TYPE)
+ val &= ~0x30000000; /* clear WRC bits */
+ val |= CFG_4xx_RESET_TYPE << 28; /* set board specific WRC type */
+#endif
mtspr(tcr, val);
val = mfspr(tsr);
diff --git a/cpu/ppc4xx/i2c.c b/cpu/ppc4xx/i2c.c
index 7db1cd8..8f4da86 100644
--- a/cpu/ppc4xx/i2c.c
+++ b/cpu/ppc4xx/i2c.c
@@ -1,91 +1,100 @@
-/*****************************************************************************/
-/* I2C Bus interface initialisation and I2C Commands */
-/* for PPC405GP */
-/* Author : AS HARNOIS */
-/* Date : 13.Dec.00 */
-/*****************************************************************************/
+/*
+ * (C) Copyright 2007
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * based on work by Anne Sophie Harnois <anne-sophie.harnois@nextream.fr>
+ *
+ * (C) Copyright 2001
+ * Bill Hunter, Wave 7 Optics, williamhunter@mediaone.net
+ *
+ * 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
+ */
#include <common.h>
#include <ppc4xx.h>
-#if defined(CONFIG_440)
-# include <440_i2c.h>
-#else
-# include <405gp_i2c.h>
-#endif
+#include <4xx_i2c.h>
#include <i2c.h>
+#include <asm-ppc/io.h>
#ifdef CONFIG_HARD_I2C
DECLARE_GLOBAL_DATA_PTR;
-#define IIC_OK 0
-#define IIC_NOK 1
-#define IIC_NOK_LA 2 /* Lost arbitration */
-#define IIC_NOK_ICT 3 /* Incomplete transfer */
-#define IIC_NOK_XFRA 4 /* Transfer aborted */
-#define IIC_NOK_DATA 5 /* No data in buffer */
-#define IIC_NOK_TOUT 6 /* Transfer timeout */
-
-#define IIC_TIMEOUT 1 /* 1 seconde */
-
+#if defined(CONFIG_I2C_MULTI_BUS)
+/* Initialize the bus pointer to whatever one the SPD EEPROM is on.
+ * Default is bus 0. This is necessary because the DDR initialization
+ * runs from ROM, and we can't switch buses because we can't modify
+ * the global variables.
+ */
+#ifdef CFG_SPD_BUS_NUM
+static unsigned int i2c_bus_num __attribute__ ((section ("data"))) = CFG_SPD_BUS_NUM;
+#else
+static unsigned int i2c_bus_num __attribute__ ((section ("data"))) = 0;
+#endif
+#endif /* CONFIG_I2C_MULTI_BUS */
-static void _i2c_bus_reset (void)
+static void _i2c_bus_reset(void)
{
- int i, status;
+ int i;
+ u8 dc;
/* Reset status register */
/* write 1 in SCMP and IRQA to clear these fields */
- out8 (IIC_STS, 0x0A);
+ out_8((u8 *)IIC_STS, 0x0A);
/* write 1 in IRQP IRQD LA ICT XFRA to clear these fields */
- out8 (IIC_EXTSTS, 0x8F);
- __asm__ volatile ("eieio");
-
- /*
- * Get current state, reset bus
- * only if no transfers are pending.
- */
- i = 10;
- do {
- /* Get status */
- status = in8 (IIC_STS);
- udelay (500); /* 500us */
- i--;
- } while ((status & IIC_STS_PT) && (i > 0));
- /* Soft reset controller */
- status = in8 (IIC_XTCNTLSS);
- out8 (IIC_XTCNTLSS, (status | IIC_XTCNTLSS_SRST));
- __asm__ volatile ("eieio");
-
- /* make sure where in initial state, data hi, clock hi */
- out8 (IIC_DIRECTCNTL, 0xC);
- for (i = 0; i < 10; i++) {
- if ((in8 (IIC_DIRECTCNTL) & 0x3) != 0x3) {
- /* clock until we get to known state */
- out8 (IIC_DIRECTCNTL, 0x8); /* clock lo */
- udelay (100); /* 100us */
- out8 (IIC_DIRECTCNTL, 0xC); /* clock hi */
- udelay (100); /* 100us */
- } else {
- break;
+ out_8((u8 *)IIC_EXTSTS, 0x8F);
+
+ /* Place chip in the reset state */
+ out_8((u8 *)IIC_XTCNTLSS, IIC_XTCNTLSS_SRST);
+
+ /* Check if bus is free */
+ dc = in_8((u8 *)IIC_DIRECTCNTL);
+ if (!DIRCTNL_FREE(dc)){
+ /* Try to set bus free state */
+ out_8((u8 *)IIC_DIRECTCNTL, IIC_DIRCNTL_SDAC | IIC_DIRCNTL_SCC);
+
+ /* Wait until we regain bus control */
+ for (i = 0; i < 100; ++i) {
+ dc = in_8((u8 *)IIC_DIRECTCNTL);
+ if (DIRCTNL_FREE(dc))
+ break;
+
+ /* Toggle SCL line */
+ dc ^= IIC_DIRCNTL_SCC;
+ out_8((u8 *)IIC_DIRECTCNTL, dc);
+ udelay(10);
+ dc ^= IIC_DIRCNTL_SCC;
+ out_8((u8 *)IIC_DIRECTCNTL, dc);
}
}
- /* send start condition */
- out8 (IIC_DIRECTCNTL, 0x4);
- udelay (1000); /* 1ms */
- /* send stop condition */
- out8 (IIC_DIRECTCNTL, 0xC);
- udelay (1000); /* 1ms */
- /* Unreset controller */
- out8 (IIC_XTCNTLSS, (status & ~IIC_XTCNTLSS_SRST));
- udelay (1000); /* 1ms */
+
+ /* Remove reset */
+ out_8((u8 *)IIC_XTCNTLSS, 0);
}
-void i2c_init (int speed, int slaveadd)
+void i2c_init(int speed, int slaveadd)
{
sys_info_t sysInfo;
unsigned long freqOPB;
int val, divisor;
+ int bus;
#ifdef CFG_I2C_INIT_BOARD
/* call board specific i2c bus reset routine before accessing the */
@@ -94,101 +103,100 @@ void i2c_init (int speed, int slaveadd)
i2c_init_board();
#endif
- /* Handle possible failed I2C state */
- /* FIXME: put this into i2c_init_board()? */
- _i2c_bus_reset ();
+ for (bus = 0; bus < CFG_MAX_I2C_BUS; bus++) {
+ I2C_SET_BUS(bus);
- /* clear lo master address */
- out8 (IIC_LMADR, 0);
+ /* Handle possible failed I2C state */
+ /* FIXME: put this into i2c_init_board()? */
+ _i2c_bus_reset();
- /* clear hi master address */
- out8 (IIC_HMADR, 0);
+ /* clear lo master address */
+ out_8((u8 *)IIC_LMADR, 0);
- /* clear lo slave address */
- out8 (IIC_LSADR, 0);
+ /* clear hi master address */
+ out_8((u8 *)IIC_HMADR, 0);
- /* clear hi slave address */
- out8 (IIC_HSADR, 0);
+ /* clear lo slave address */
+ out_8((u8 *)IIC_LSADR, 0);
- /* Clock divide Register */
- /* get OPB frequency */
- get_sys_info (&sysInfo);
- freqOPB = sysInfo.freqPLB / sysInfo.pllOpbDiv;
- /* set divisor according to freqOPB */
- divisor = (freqOPB - 1) / 10000000;
- if (divisor == 0)
- divisor = 1;
- out8 (IIC_CLKDIV, divisor);
+ /* clear hi slave address */
+ out_8((u8 *)IIC_HSADR, 0);
- /* no interrupts */
- out8 (IIC_INTRMSK, 0);
+ /* Clock divide Register */
+ /* get OPB frequency */
+ get_sys_info(&sysInfo);
+ freqOPB = sysInfo.freqPLB / sysInfo.pllOpbDiv;
+ /* set divisor according to freqOPB */
+ divisor = (freqOPB - 1) / 10000000;
+ if (divisor == 0)
+ divisor = 1;
+ out_8((u8 *)IIC_CLKDIV, divisor);
- /* clear transfer count */
- out8 (IIC_XFRCNT, 0);
+ /* no interrupts */
+ out_8((u8 *)IIC_INTRMSK, 0);
- /* clear extended control & stat */
- /* write 1 in SRC SRS SWC SWS to clear these fields */
- out8 (IIC_XTCNTLSS, 0xF0);
+ /* clear transfer count */
+ out_8((u8 *)IIC_XFRCNT, 0);
- /* Mode Control Register
- Flush Slave/Master data buffer */
- out8 (IIC_MDCNTL, IIC_MDCNTL_FSDB | IIC_MDCNTL_FMDB);
- __asm__ volatile ("eieio");
+ /* clear extended control & stat */
+ /* write 1 in SRC SRS SWC SWS to clear these fields */
+ out_8((u8 *)IIC_XTCNTLSS, 0xF0);
+ /* Mode Control Register
+ Flush Slave/Master data buffer */
+ out_8((u8 *)IIC_MDCNTL, IIC_MDCNTL_FSDB | IIC_MDCNTL_FMDB);
- val = in8(IIC_MDCNTL);
- __asm__ volatile ("eieio");
+ val = in_8((u8 *)IIC_MDCNTL);
- /* Ignore General Call, slave transfers are ignored,
- disable interrupts, exit unknown bus state, enable hold
- SCL
- 100kHz normaly or FastMode for 400kHz and above
- */
+ /* Ignore General Call, slave transfers are ignored,
+ * disable interrupts, exit unknown bus state, enable hold
+ * SCL 100kHz normaly or FastMode for 400kHz and above
+ */
- val |= IIC_MDCNTL_EUBS|IIC_MDCNTL_HSCL;
- if( speed >= 400000 ){
- val |= IIC_MDCNTL_FSM;
- }
- out8 (IIC_MDCNTL, val);
+ val |= IIC_MDCNTL_EUBS|IIC_MDCNTL_HSCL;
+ if (speed >= 400000)
+ val |= IIC_MDCNTL_FSM;
+ out_8((u8 *)IIC_MDCNTL, val);
- /* clear control reg */
- out8 (IIC_CNTL, 0x00);
- __asm__ volatile ("eieio");
+ /* clear control reg */
+ out_8((u8 *)IIC_CNTL, 0x00);
+ }
+ /* set to SPD bus as default bus upon powerup */
+ I2C_SET_BUS(CFG_SPD_BUS_NUM);
}
/*
- This code tries to use the features of the 405GP i2c
- controller. It will transfer up to 4 bytes in one pass
- on the loop. It only does out8(lbz) to the buffer when it
- is possible to do out16(lhz) transfers.
-
- cmd_type is 0 for write 1 for read.
-
- addr_len can take any value from 0-255, it is only limited
- by the char, we could make it larger if needed. If it is
- 0 we skip the address write cycle.
-
- Typical case is a Write of an addr followd by a Read. The
- IBM FAQ does not cover this. On the last byte of the write
- we don't set the creg CHT bit, and on the first bytes of the
- read we set the RPST bit.
-
- It does not support address only transfers, there must be
- a data part. If you want to write the address yourself, put
- it in the data pointer.
-
- It does not support transfer to/from address 0.
-
- It does not check XFRCNT.
-*/
-static
-int i2c_transfer(unsigned char cmd_type,
- unsigned char chip,
- unsigned char addr[],
- unsigned char addr_len,
- unsigned char data[],
- unsigned short data_len )
+ * This code tries to use the features of the 405GP i2c
+ * controller. It will transfer up to 4 bytes in one pass
+ * on the loop. It only does out_8((u8 *)lbz) to the buffer when it
+ * is possible to do out16(lhz) transfers.
+ *
+ * cmd_type is 0 for write 1 for read.
+ *
+ * addr_len can take any value from 0-255, it is only limited
+ * by the char, we could make it larger if needed. If it is
+ * 0 we skip the address write cycle.
+ *
+ * Typical case is a Write of an addr followd by a Read. The
+ * IBM FAQ does not cover this. On the last byte of the write
+ * we don't set the creg CHT bit, and on the first bytes of the
+ * read we set the RPST bit.
+ *
+ * It does not support address only transfers, there must be
+ * a data part. If you want to write the address yourself, put
+ * it in the data pointer.
+ *
+ * It does not support transfer to/from address 0.
+ *
+ * It does not check XFRCNT.
+ */
+static int i2c_transfer(unsigned char cmd_type,
+ unsigned char chip,
+ unsigned char addr[],
+ unsigned char addr_len,
+ unsigned char data[],
+ unsigned short data_len)
{
unsigned char* ptr;
int reading;
@@ -198,97 +206,88 @@ int i2c_transfer(unsigned char cmd_type,
int i;
uchar creg;
- if( data == 0 || data_len == 0 ){
- /*Don't support data transfer of no length or to address 0*/
+ if (data == 0 || data_len == 0) {
+ /* Don't support data transfer of no length or to address 0 */
printf( "i2c_transfer: bad call\n" );
return IIC_NOK;
}
- if( addr && addr_len ){
+ if (addr && addr_len) {
ptr = addr;
cnt = addr_len;
reading = 0;
- }else{
+ } else {
ptr = data;
cnt = data_len;
reading = cmd_type;
}
- /*Clear Stop Complete Bit*/
- out8(IIC_STS,IIC_STS_SCMP);
+ /* Clear Stop Complete Bit */
+ out_8((u8 *)IIC_STS, IIC_STS_SCMP);
/* Check init */
- i=10;
+ i = 10;
do {
/* Get status */
- status = in8(IIC_STS);
- __asm__ volatile("eieio");
+ status = in_8((u8 *)IIC_STS);
i--;
- } while ((status & IIC_STS_PT) && (i>0));
+ } while ((status & IIC_STS_PT) && (i > 0));
if (status & IIC_STS_PT) {
result = IIC_NOK_TOUT;
return(result);
}
- /*flush the Master/Slave Databuffers*/
- out8(IIC_MDCNTL, ((in8(IIC_MDCNTL))|IIC_MDCNTL_FMDB|IIC_MDCNTL_FSDB));
- /*need to wait 4 OPB clocks? code below should take that long*/
+ /* flush the Master/Slave Databuffers */
+ out_8((u8 *)IIC_MDCNTL, ((in_8((u8 *)IIC_MDCNTL))|IIC_MDCNTL_FMDB|IIC_MDCNTL_FSDB));
+ /* need to wait 4 OPB clocks? code below should take that long */
/* 7-bit adressing */
- out8(IIC_HMADR,0);
- out8(IIC_LMADR, chip);
- __asm__ volatile("eieio");
+ out_8((u8 *)IIC_HMADR, 0);
+ out_8((u8 *)IIC_LMADR, chip);
tran = 0;
result = IIC_OK;
creg = 0;
- while ( tran != cnt && (result == IIC_OK)) {
+ while (tran != cnt && (result == IIC_OK)) {
int bc,j;
/* Control register =
- Normal transfer, 7-bits adressing, Transfer up to bc bytes, Normal start,
- Transfer is a sequence of transfers
- */
+ * Normal transfer, 7-bits adressing, Transfer up to bc bytes, Normal start,
+ * Transfer is a sequence of transfers
+ */
creg |= IIC_CNTL_PT;
- bc = (cnt - tran) > 4 ? 4 :
- cnt - tran;
- creg |= (bc-1)<<4;
- /* if the real cmd type is write continue trans*/
- if ( (!cmd_type && (ptr == addr)) || ((tran+bc) != cnt) )
+ bc = (cnt - tran) > 4 ? 4 : cnt - tran;
+ creg |= (bc - 1) << 4;
+ /* if the real cmd type is write continue trans */
+ if ((!cmd_type && (ptr == addr)) || ((tran + bc) != cnt))
creg |= IIC_CNTL_CHT;
if (reading)
creg |= IIC_CNTL_READ;
- else {
- for(j=0; j<bc; j++) {
+ else
+ for(j=0; j < bc; j++)
/* Set buffer */
- out8(IIC_MDBUF,ptr[tran+j]);
- __asm__ volatile("eieio");
- }
- }
- out8(IIC_CNTL, creg );
- __asm__ volatile("eieio");
+ out_8((u8 *)IIC_MDBUF, ptr[tran+j]);
+ out_8((u8 *)IIC_CNTL, creg);
/* Transfer is in progress
- we have to wait for upto 5 bytes of data
- 1 byte chip address+r/w bit then bc bytes
- of data.
- udelay(10) is 1 bit time at 100khz
- Doubled for slop. 20 is too small.
- */
- i=2*5*8;
+ * we have to wait for upto 5 bytes of data
+ * 1 byte chip address+r/w bit then bc bytes
+ * of data.
+ * udelay(10) is 1 bit time at 100khz
+ * Doubled for slop. 20 is too small.
+ */
+ i = 2*5*8;
do {
/* Get status */
- status = in8(IIC_STS);
- __asm__ volatile("eieio");
- udelay (10);
+ status = in_8((u8 *)IIC_STS);
+ udelay(10);
i--;
- } while ((status & IIC_STS_PT) && !(status & IIC_STS_ERR)
- && (i>0));
+ } while ((status & IIC_STS_PT) && !(status & IIC_STS_ERR) && (i > 0));
if (status & IIC_STS_ERR) {
result = IIC_NOK;
- status = in8 (IIC_EXTSTS);
+ status = in_8((u8 *)IIC_EXTSTS);
/* Lost arbitration? */
if (status & IIC_EXTSTS_LA)
result = IIC_NOK_LA;
@@ -306,34 +305,32 @@ int i2c_transfer(unsigned char cmd_type,
/* Are there data in buffer */
if (status & IIC_STS_MDBS) {
/*
- even if we have data we have to wait 4OPB clocks
- for it to hit the front of the FIFO, after that
- we can just read. We should check XFCNT here and
- if the FIFO is full there is no need to wait.
- */
- udelay (1);
- for(j=0;j<bc;j++) {
- ptr[tran+j] = in8(IIC_MDBUF);
- __asm__ volatile("eieio");
- }
+ * even if we have data we have to wait 4OPB clocks
+ * for it to hit the front of the FIFO, after that
+ * we can just read. We should check XFCNT here and
+ * if the FIFO is full there is no need to wait.
+ */
+ udelay(1);
+ for (j=0; j<bc; j++)
+ ptr[tran+j] = in_8((u8 *)IIC_MDBUF);
} else
result = IIC_NOK_DATA;
}
creg = 0;
- tran+=bc;
- if( ptr == addr && tran == cnt ) {
+ tran += bc;
+ if (ptr == addr && tran == cnt) {
ptr = data;
cnt = data_len;
tran = 0;
reading = cmd_type;
- if( reading )
+ if (reading)
creg = IIC_CNTL_RPST;
}
}
return (result);
}
-int i2c_probe (uchar chip)
+int i2c_probe(uchar chip)
{
uchar buf[1];
@@ -344,21 +341,21 @@ int i2c_probe (uchar chip)
* address was <ACK>ed (i.e. there was a chip at that address which
* drove the data line low).
*/
- return(i2c_transfer (1, chip << 1, 0,0, buf, 1) != 0);
+ return (i2c_transfer(1, chip << 1, 0,0, buf, 1) != 0);
}
-int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len)
+int i2c_read(uchar chip, uint addr, int alen, uchar * buffer, int len)
{
uchar xaddr[4];
int ret;
- if ( alen > 4 ) {
+ if (alen > 4) {
printf ("I2C read: addr len %d not supported\n", alen);
return 1;
}
- if ( alen > 0 ) {
+ if (alen > 0) {
xaddr[0] = (addr >> 24) & 0xFF;
xaddr[1] = (addr >> 16) & 0xFF;
xaddr[2] = (addr >> 8) & 0xFF;
@@ -378,10 +375,10 @@ int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len)
* still be one byte because the extra address bits are
* hidden in the chip address.
*/
- if( alen > 0 )
+ if (alen > 0)
chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW);
#endif
- if( (ret = i2c_transfer( 1, chip<<1, &xaddr[4-alen], alen, buffer, len )) != 0) {
+ if ((ret = i2c_transfer(1, chip<<1, &xaddr[4-alen], alen, buffer, len)) != 0) {
if (gd->have_console)
printf( "I2c read: failed %d\n", ret);
return 1;
@@ -389,16 +386,17 @@ int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len)
return 0;
}
-int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len)
+int i2c_write(uchar chip, uint addr, int alen, uchar * buffer, int len)
{
uchar xaddr[4];
- if ( alen > 4 ) {
+ if (alen > 4) {
printf ("I2C write: addr len %d not supported\n", alen);
return 1;
}
- if ( alen > 0 ) {
+
+ if (alen > 0) {
xaddr[0] = (addr >> 24) & 0xFF;
xaddr[1] = (addr >> 16) & 0xFF;
xaddr[2] = (addr >> 8) & 0xFF;
@@ -417,11 +415,11 @@ int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len)
* still be one byte because the extra address bits are
* hidden in the chip address.
*/
- if( alen > 0 )
+ if (alen > 0)
chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW);
#endif
- return (i2c_transfer( 0, chip<<1, &xaddr[4-alen], alen, buffer, len ) != 0);
+ return (i2c_transfer(0, chip<<1, &xaddr[4-alen], alen, buffer, len ) != 0);
}
/*-----------------------------------------------------------------------
@@ -433,7 +431,7 @@ uchar i2c_reg_read(uchar i2c_addr, uchar reg)
i2c_read(i2c_addr, reg, 1, &buf, 1);
- return(buf);
+ return (buf);
}
/*-----------------------------------------------------------------------
@@ -443,4 +441,38 @@ void i2c_reg_write(uchar i2c_addr, uchar reg, uchar val)
{
i2c_write(i2c_addr, reg, 1, &val, 1);
}
+
+#if defined(CONFIG_I2C_MULTI_BUS)
+/*
+ * Functions for multiple I2C bus handling
+ */
+unsigned int i2c_get_bus_num(void)
+{
+ return i2c_bus_num;
+}
+
+int i2c_set_bus_num(unsigned int bus)
+{
+ if (bus >= CFG_MAX_I2C_BUS)
+ return -1;
+
+ i2c_bus_num = bus;
+
+ return 0;
+}
+#endif /* CONFIG_I2C_MULTI_BUS */
+
+/* TODO: add 100/400k switching */
+unsigned int i2c_get_bus_speed(void)
+{
+ return CFG_I2C_SPEED;
+}
+
+int i2c_set_bus_speed(unsigned int speed)
+{
+ if (speed != CFG_I2C_SPEED)
+ return -1;
+
+ return 0;
+}
#endif /* CONFIG_HARD_I2C */
diff --git a/cpu/ppc4xx/ndfc.c b/cpu/ppc4xx/ndfc.c
index 3521731..b198ff4 100644
--- a/cpu/ppc4xx/ndfc.c
+++ b/cpu/ppc4xx/ndfc.c
@@ -156,7 +156,7 @@ void board_nand_select_device(struct nand_chip *nand, int chip)
out32(base + NDFC_CCR, 0x00000000 | (cs << 24));
}
-void board_nand_init(struct nand_chip *nand)
+int board_nand_init(struct nand_chip *nand)
{
int cs = (ulong)nand->IO_ADDR_W & 0x00000003;
ulong base = (ulong)nand->IO_ADDR_W & 0xfffffffc;
@@ -188,6 +188,7 @@ void board_nand_init(struct nand_chip *nand)
*/
board_nand_select_device(nand, cs);
out32(base + NDFC_BCFG0 + (cs << 2), 0x80002222);
+ return 0;
}
#endif
diff --git a/cpu/ppc4xx/sdram.c b/cpu/ppc4xx/sdram.c
index faeea5c..d520cd3 100644
--- a/cpu/ppc4xx/sdram.c
+++ b/cpu/ppc4xx/sdram.c
@@ -1,5 +1,5 @@
/*
- * (C) Copyright 2005-2006
+ * (C) Copyright 2005-2007
* Stefan Roese, DENX Software Engineering, sr@denx.de.
*
* (C) Copyright 2006
@@ -32,9 +32,9 @@
#include <asm/processor.h>
#include "sdram.h"
-
#ifdef CONFIG_SDRAM_BANK0
+#ifndef CONFIG_440
#ifndef CFG_SDRAM_TABLE
sdram_conf_t mb0cf[] = {
@@ -50,9 +50,6 @@ sdram_conf_t mb0cf[] = CFG_SDRAM_TABLE;
#define N_MB0CF (sizeof(mb0cf) / sizeof(mb0cf[0]))
-
-#ifndef CONFIG_440
-
#ifdef CFG_SDRAM_CASL
static ulong ns2clks(ulong ns)
{
@@ -221,6 +218,26 @@ void sdram_init(void)
#else /* CONFIG_440 */
+/*
+ * Define some default values. Those can be overwritten in the
+ * board config file.
+ */
+
+#ifndef CFG_SDRAM_TABLE
+sdram_conf_t mb0cf[] = {
+ {(256 << 20), 13, 0x000C4001}, /* 256MB mode 3, 13x10(4) */
+ {(64 << 20), 12, 0x00082001} /* 64MB mode 2, 12x9(4) */
+};
+#else
+sdram_conf_t mb0cf[] = CFG_SDRAM_TABLE;
+#endif
+
+#ifndef CFG_SDRAM0_TR0
+#define CFG_SDRAM0_TR0 0x41094012
+#endif
+
+#define N_MB0CF (sizeof(mb0cf) / sizeof(mb0cf[0]))
+
#define NUM_TRIES 64
#define NUM_READS 10
@@ -295,7 +312,6 @@ static void sdram_tr1_set(int ram_address, int* tr1_value)
*tr1_value = (first_good + last_bad) / 2;
}
-
#ifdef CONFIG_SDRAM_ECC
static void ecc_init(ulong start, ulong size)
{
@@ -351,6 +367,15 @@ long int initdram(int board_type)
int i;
int tr1_bank1;
+#if defined(CONFIG_440GX) || defined(CONFIG_440EP) || \
+ defined(CONFIG_440GR) || defined(CONFIG_440SP)
+ /*
+ * Soft-reset SDRAM controller.
+ */
+ mtsdr(sdr_srst, SDR0_SRST_DMC);
+ mtsdr(sdr_srst, 0x00000000);
+#endif
+
for (i=0; i<N_MB0CF; i++) {
/*
* Disable memory controller.
@@ -370,9 +395,9 @@ long int initdram(int board_type)
* Following for CAS Latency = 2.5 @ 133 MHz PLB
*/
mtsdram(mem_b0cr, mb0cf[i].reg);
- mtsdram(mem_tr0, 0x41094012);
+ mtsdram(mem_tr0, CFG_SDRAM0_TR0);
mtsdram(mem_tr1, 0x80800800); /* SS=T2 SL=STAGE 3 CD=1 CT=0x00*/
- mtsdram(mem_rtr, 0x7e000000); /* Interval 15.20µs @ 133MHz PLB*/
+ mtsdram(mem_rtr, 0x04100000); /* Interval 7.8µs @ 133MHz PLB */
mtsdram(mem_cfg1, 0x00000000); /* Self-refresh exit, disable PM*/
udelay(400); /* Delay 200 usecs (min) */
diff --git a/cpu/ppc4xx/serial.c b/cpu/ppc4xx/serial.c
index fab0d95..e62dd9d 100644
--- a/cpu/ppc4xx/serial.c
+++ b/cpu/ppc4xx/serial.c
@@ -264,7 +264,8 @@ int serial_tstc ()
#endif /* CONFIG_IOP480 */
/*****************************************************************************/
-#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_405EP) || \
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
+ defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
defined(CONFIG_440)
#if defined(CONFIG_440)
@@ -309,7 +310,7 @@ int serial_tstc ()
#define MFREG(a, d) mfsdr(a, d)
#define MTREG(a, d) mtsdr(a, d)
#endif /* #if defined(CONFIG_440GP) */
-#elif defined(CONFIG_405EP)
+#elif defined(CONFIG_405EP) || defined(CONFIG_405EZ)
#define UART0_BASE 0xef600300
#define UART1_BASE 0xef600400
#define UCR0_MASK 0x0000007f
@@ -392,47 +393,95 @@ volatile static serial_buffer_t buf_info;
#if defined(CONFIG_440) && !defined(CFG_EXT_SERIAL_CLOCK)
static void serial_divs (int baudrate, unsigned long *pudiv,
- unsigned short *pbdiv )
+ unsigned short *pbdiv)
{
- sys_info_t sysinfo;
+ sys_info_t sysinfo;
unsigned long div; /* total divisor udiv * bdiv */
unsigned long umin; /* minimum udiv */
- unsigned short diff; /* smallest diff */
- unsigned long udiv; /* best udiv */
-
- unsigned short idiff; /* current diff */
- unsigned short ibdiv; /* current bdiv */
+ unsigned short diff; /* smallest diff */
+ unsigned long udiv; /* best udiv */
+ unsigned short idiff; /* current diff */
+ unsigned short ibdiv; /* current bdiv */
unsigned long i;
- unsigned long est; /* current estimate */
+ unsigned long est; /* current estimate */
- get_sys_info( &sysinfo );
+ get_sys_info(&sysinfo);
- udiv = 32; /* Assume lowest possible serial clk */
- div = sysinfo.freqPLB/(16*baudrate); /* total divisor */
- umin = sysinfo.pllOpbDiv<<1; /* 2 x OPB divisor */
- diff = 32; /* highest possible */
+ udiv = 32; /* Assume lowest possible serial clk */
+ div = sysinfo.freqPLB / (16 * baudrate); /* total divisor */
+ umin = sysinfo.pllOpbDiv << 1; /* 2 x OPB divisor */
+ diff = 32; /* highest possible */
/* i is the test udiv value -- start with the largest
* possible (32) to minimize serial clock and constrain
* search to umin.
*/
- for( i = 32; i > umin; i-- ){
- ibdiv = div/i;
+ for (i = 32; i > umin; i--) {
+ ibdiv = div / i;
est = i * ibdiv;
idiff = (est > div) ? (est-div) : (div-est);
- if( idiff == 0 ){
+ if (idiff == 0) {
udiv = i;
break; /* can't do better */
- }
- else if( idiff < diff ){
+ } else if (idiff < diff) {
udiv = i; /* best so far */
diff = idiff; /* update lowest diff*/
}
}
*pudiv = udiv;
- *pbdiv = div/udiv;
+ *pbdiv = div / udiv;
+}
+
+#elif defined(CONFIG_405EZ)
+
+static void serial_divs (int baudrate, unsigned long *pudiv,
+ unsigned short *pbdiv)
+{
+ sys_info_t sysinfo;
+ unsigned long div; /* total divisor udiv * bdiv */
+ unsigned long umin; /* minimum udiv */
+ unsigned short diff; /* smallest diff */
+ unsigned long udiv; /* best udiv */
+ unsigned short idiff; /* current diff */
+ unsigned short ibdiv; /* current bdiv */
+ unsigned long i;
+ unsigned long est; /* current estimate */
+ unsigned long plloutb;
+ u32 reg;
+
+ get_sys_info(&sysinfo);
+ plloutb = ((CONFIG_SYS_CLK_FREQ * sysinfo.pllFwdDiv * sysinfo.pllFbkDiv)
+ / sysinfo.pllFwdDivB);
+ udiv = 256; /* Assume lowest possible serial clk */
+ div = plloutb / (16 * baudrate); /* total divisor */
+ umin = (plloutb / get_OPB_freq()) << 1; /* 2 x OPB divisor */
+ diff = 256; /* highest possible */
+
+ /* i is the test udiv value -- start with the largest
+ * possible (256) to minimize serial clock and constrain
+ * search to umin.
+ */
+ for (i = 256; i > umin; i--) {
+ ibdiv = div / i;
+ est = i * ibdiv;
+ idiff = (est > div) ? (est-div) : (div-est);
+ if (idiff == 0) {
+ udiv = i;
+ break; /* can't do better */
+ } else if (idiff < diff) {
+ udiv = i; /* best so far */
+ diff = idiff; /* update lowest diff*/
+ }
+ }
+
+ *pudiv = udiv;
+ mfcpr(cprperd0, reg);
+ reg &= ~0x0000ffff;
+ reg |= ((udiv - 0) << 8) | (udiv - 0);
+ mtcpr(cprperd0, reg);
+ *pbdiv = div / udiv;
}
#endif /* defined(CONFIG_440) && !defined(CFG_EXT_SERIAL_CLK) */
@@ -518,6 +567,10 @@ int serial_init (void)
unsigned short bdiv;
volatile char val;
+#if defined(CONFIG_405EZ)
+ serial_divs(gd->baudrate, &udiv, &bdiv);
+ clk = tmp = reg = 0;
+#else
#ifdef CONFIG_405EP
reg = mfdcr(cpc0_ucr) & ~(UCR0_MASK | UCR1_MASK);
clk = gd->cpu_clk;
@@ -548,9 +601,9 @@ int serial_init (void)
reg |= (udiv - 1) << CR0_UDIV_POS; /* set the UART divisor */
mtdcr (cntrl0, reg);
#endif /* CONFIG_405EP */
-
tmp = gd->baudrate * udiv * 16;
bdiv = (clk + tmp / 2) / tmp;
+#endif /* CONFIG_405EZ */
out8(UART_BASE + UART_LCR, 0x80); /* set DLAB bit */
out8(UART_BASE + UART_DLL, bdiv); /* set baudrate divisor */
diff --git a/cpu/ppc4xx/speed.c b/cpu/ppc4xx/speed.c
index 2d16a83..028b11a 100644
--- a/cpu/ppc4xx/speed.c
+++ b/cpu/ppc4xx/speed.c
@@ -331,7 +331,7 @@ void get_sys_info (sys_info_t * sysInfo)
unsigned long m;
unsigned long prbdv0;
-#if defined(CONFIG_440SPE)
+#if defined(CONFIG_YUCCA)
unsigned long sys_freq;
unsigned long sys_per=0;
unsigned long msr;
@@ -348,7 +348,7 @@ void get_sys_info (sys_info_t * sysInfo)
/*-------------------------------------------------------------------------+
| Calculate the system clock speed from the period.
+-------------------------------------------------------------------------*/
- sys_freq=(ONE_BILLION/sys_per)*1000;
+ sys_freq = (ONE_BILLION / sys_per) * 1000;
#endif
/* Extract configured divisors */
@@ -385,17 +385,17 @@ void get_sys_info (sys_info_t * sysInfo)
m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
/* Now calculate the individual clocks */
-#if defined(CONFIG_440SPE)
+#if defined(CONFIG_YUCCA)
sysInfo->freqVCOMhz = (m * sys_freq) ;
#else
- sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
+ sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
#endif
sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
sysInfo->freqEPB = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
-#if defined(CONFIG_440SPE)
+#if defined(CONFIG_YUCCA)
/* Determine PCI Clock Period */
pci_clock_per = determine_pci_clock_per();
sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
@@ -408,7 +408,7 @@ void get_sys_info (sys_info_t * sysInfo)
#endif
-#if defined(CONFIG_440SPE)
+#if defined(CONFIG_YUCCA)
unsigned long determine_sysper(void)
{
unsigned int fpga_clocking_reg;
@@ -583,7 +583,6 @@ unsigned long determine_sysper(void)
}
return(sys_per);
-
}
/*-------------------------------------------------------------------------+
@@ -768,11 +767,119 @@ ulong get_PCI_freq (void)
return val;
}
+#elif defined(CONFIG_405EZ)
+void get_sys_info (PPC405_SYS_INFO * sysInfo)
+{
+ unsigned long cpr_plld;
+ unsigned long cpr_primad;
+ unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
+ unsigned long primad_cpudv;
+ unsigned long m;
+
+ /*
+ * Read PLL Mode registers
+ */
+ mfcpr(cprplld, cpr_plld);
+
+ /*
+ * Determine forward divider A
+ */
+ sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
+
+ /*
+ * Determine forward divider B (should be equal to A)
+ */
+ sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
+ if (sysInfo->pllFwdDivB == 0) {
+ sysInfo->pllFwdDivB = 8;
+ }
+
+ /*
+ * Determine FBK_DIV.
+ */
+ sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
+ if (sysInfo->pllFbkDiv == 0) {
+ sysInfo->pllFbkDiv = 256;
+ }
+
+ /*
+ * Read CPR_PRIMAD register
+ */
+ mfcpr(cprprimad, cpr_primad);
+ /*
+ * Determine PLB_DIV.
+ */
+ sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
+ if (sysInfo->pllPlbDiv == 0) {
+ sysInfo->pllPlbDiv = 16;
+ }
+
+ /*
+ * Determine EXTBUS_DIV.
+ */
+ sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
+ if (sysInfo->pllExtBusDiv == 0) {
+ sysInfo->pllExtBusDiv = 16;
+ }
+
+ /*
+ * Determine OPB_DIV.
+ */
+ sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
+ if (sysInfo->pllOpbDiv == 0) {
+ sysInfo->pllOpbDiv = 16;
+ }
+
+ /*
+ * Determine the M factor
+ */
+ m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
+
+ /*
+ * Determine VCO clock frequency
+ */
+ sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
+ (unsigned long long)sysClkPeriodPs;
+
+ /*
+ * Determine CPU clock frequency
+ */
+ primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
+ if (primad_cpudv == 0) {
+ primad_cpudv = 16;
+ }
+
+ sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) / primad_cpudv;
+
+ /*
+ * Determine PLB clock frequency
+ */
+ sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) / sysInfo->pllPlbDiv;
+}
+
+/********************************************
+ * get_OPB_freq
+ * return OPB bus freq in Hz
+ *********************************************/
+ulong get_OPB_freq (void)
+{
+ ulong val = 0;
+
+ PPC405_SYS_INFO sys_info;
+
+ get_sys_info (&sys_info);
+ val = (CONFIG_SYS_CLK_FREQ * sys_info.pllFbkDiv) / sys_info.pllOpbDiv;
+
+ return val;
+}
+
#endif
int get_clocks (void)
{
-#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_440) || defined(CONFIG_405) || defined(CONFIG_405EP)
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
+ defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
+ defined(CONFIG_440) || defined(CONFIG_405)
sys_info_t sys_info;
get_sys_info (&sys_info);
@@ -797,7 +904,9 @@ ulong get_bus_freq (ulong dummy)
{
ulong val;
-#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_405) || defined(CONFIG_440) || defined(CONFIG_405EP)
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
+ defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
+ defined(CONFIG_440) || defined(CONFIG_405)
sys_info_t sys_info;
get_sys_info (&sys_info);
diff --git a/cpu/ppc4xx/start.S b/cpu/ppc4xx/start.S
index 8e000d3..d918b3e 100644
--- a/cpu/ppc4xx/start.S
+++ b/cpu/ppc4xx/start.S
@@ -699,7 +699,9 @@ _start:
#endif /* CONFIG_IOP480 */
/*****************************************************************************/
-#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_405) || defined(CONFIG_405EP)
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
+ defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
+ defined(CONFIG_405)
/*----------------------------------------------------------------------- */
/* Clear and set up some registers. */
/*----------------------------------------------------------------------- */
@@ -727,13 +729,13 @@ _start:
/*----------------------------------------------------------------------- */
/* Enable two 128MB cachable regions. */
/*----------------------------------------------------------------------- */
- addis r4,r0,0x8000
- addi r4,r4,0x0001
+ lis r4,0x8000
+ ori r4,r4,0x0001
mticcr r4 /* instruction cache */
isync
- addis r4,r0,0x0000
- addi r4,r4,0x0000
+ lis r4,0x0000
+ ori r4,r4,0x0000
mtdccr r4 /* data cache */
#if !(defined(CFG_EBC_PB0AP) && defined(CFG_EBC_PB0CR))
@@ -755,6 +757,70 @@ _start:
#endif /* CONFIG_405EP */
#if defined(CFG_OCM_DATA_ADDR) && defined(CFG_OCM_DATA_SIZE)
+/* test-only... (clean up later when NAND booting is supported) */
+#if defined(CONFIG_405EZ)
+ /********************************************************************
+ * Setup OCM - On Chip Memory - PPC405EZ uses OCM Controller V2
+ *******************************************************************/
+ /*
+ * We can map the OCM on the PLB3, so map it at
+ * CFG_OCM_DATA_ADDR + 0x8000
+ */
+ lis r3,CFG_OCM_DATA_ADDR@h /* OCM location */
+ ori r3,r3,CFG_OCM_DATA_ADDR@l
+ ori r3,r3,0x8270 /* 32K Offset, 16K for Bank 1, R/W/Enable */
+ mtdcr ocmplb3cr1,r3 /* Set PLB Access */
+ ori r3,r3,0x4000 /* Add 0x4000 for bank 2 */
+ mtdcr ocmplb3cr2,r3 /* Set PLB Access */
+ isync
+
+ lis r3,CFG_OCM_DATA_ADDR@h /* OCM location */
+ ori r3,r3,CFG_OCM_DATA_ADDR@l
+ ori r3,r3,0x0270 /* 16K for Bank 1, R/W/Enable */
+ mtdcr ocmdscr1, r3 /* Set Data Side */
+ mtdcr ocmiscr1, r3 /* Set Instruction Side */
+ ori r3,r3,0x4000 /* Add 0x4000 for bank 2 */
+ mtdcr ocmdscr2, r3 /* Set Data Side */
+ mtdcr ocmiscr2, r3 /* Set Instruction Side */
+ addis r3,0,0x0800 /* OCM Data Parity Disable - 1 Wait State */
+ mtdcr ocmdsisdpc,r4
+
+ isync
+
+#if defined(CONFIG_NAND_SPL)
+ /*
+ * 405EZ can boot from NAND Flash.
+ * If we are booting the SPL (Pre-loader), copy code from
+ * the mapped 4K NAND Flash to the OCM
+ */
+ li r4,(CFG_NAND_BOOT_SPL_SIZE >> 2) - 1
+ mtctr r4
+ lis r2,CFG_NAND_BOOT_SPL_SRC@h
+ ori r2,r2,CFG_NAND_BOOT_SPL_SRC@l
+ lis r3,CFG_NAND_BOOT_SPL_DST@h
+ ori r3,r3,CFG_NAND_BOOT_SPL_DST@l
+spl_loop:
+ lwzu r4,4(r2)
+ stwu r4,4(r3)
+ bdnz spl_loop
+
+ /*
+ * Jump to code in OCM Ram
+ */
+ bl 00f
+00: mflr r10
+ lis r3,(CFG_NAND_BOOT_SPL_SRC - CFG_NAND_BOOT_SPL_DST)@h
+ ori r3,r3,(CFG_NAND_BOOT_SPL_SRC - CFG_NAND_BOOT_SPL_DST)@l
+ sub r10,r10,r3
+ addi r10,r10,28
+ mtlr r10
+ blr
+start_ram:
+ sync
+ isync
+#endif
+#else
+/* ...test-only */
/********************************************************************
* Setup OCM - On Chip Memory
*******************************************************************/
@@ -774,6 +840,7 @@ _start:
addis r4, 0, 0xC000 /* OCM data area enabled */
mtdcr ocmdscntl, r4
isync
+#endif /* CONFIG_405EZ */
#endif
/*----------------------------------------------------------------------- */
@@ -1361,7 +1428,7 @@ ppcSync:
relocate_code:
#if defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
- defined(CONFIG_440SPE)
+ defined(CONFIG_440SP) || defined(CONFIG_440SPE)
/*
* On some 440er platforms the cache is enabled in the first TLB (Boot-CS)
* to speed up the boot process. Now this cache needs to be disabled.
@@ -1856,3 +1923,103 @@ pll_wait:
/* execution will continue from the poweron */
/* vector of 0xfffffffc */
#endif /* CONFIG_405EP */
+
+#if defined(CONFIG_440)
+#define function_prolog(func_name) .text; \
+ .align 2; \
+ .globl func_name; \
+ func_name:
+#define function_epilog(func_name) .type func_name,@function; \
+ .size func_name,.-func_name
+
+/*----------------------------------------------------------------------------+
+| mttlb3.
++----------------------------------------------------------------------------*/
+ function_prolog(mttlb3)
+ TLBWE(4,3,2)
+ blr
+ function_epilog(mttlb3)
+
+/*----------------------------------------------------------------------------+
+| mftlb3.
++----------------------------------------------------------------------------*/
+ function_prolog(mftlb3)
+ TLBRE(3,3,2)
+ blr
+ function_epilog(mftlb3)
+
+/*----------------------------------------------------------------------------+
+| mttlb2.
++----------------------------------------------------------------------------*/
+ function_prolog(mttlb2)
+ TLBWE(4,3,1)
+ blr
+ function_epilog(mttlb2)
+
+/*----------------------------------------------------------------------------+
+| mftlb2.
++----------------------------------------------------------------------------*/
+ function_prolog(mftlb2)
+ TLBRE(3,3,1)
+ blr
+ function_epilog(mftlb2)
+
+/*----------------------------------------------------------------------------+
+| mttlb1.
++----------------------------------------------------------------------------*/
+ function_prolog(mttlb1)
+ TLBWE(4,3,0)
+ blr
+ function_epilog(mttlb1)
+
+/*----------------------------------------------------------------------------+
+| mftlb1.
++----------------------------------------------------------------------------*/
+ function_prolog(mftlb1)
+ 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
new file mode 100644
index 0000000..50344a4
--- /dev/null
+++ b/cpu/ppc4xx/tlb.c
@@ -0,0 +1,184 @@
+/*
+ * (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
+ */
+
+#include <common.h>
+
+#if defined(CONFIG_440)
+
+#include <ppc4xx.h>
+#include <ppc440.h>
+#include <asm/io.h>
+#include <asm/mmu.h>
+
+typedef struct region {
+ unsigned long base;
+ unsigned long size;
+ unsigned long tlb_word2_i_value;
+} region_t;
+
+static int add_tlb_entry(unsigned long base_addr,
+ unsigned long tlb_word0_size_value,
+ unsigned long tlb_word2_i_value)
+{
+ int i;
+ unsigned long tlb_word0_value;
+ unsigned long tlb_word1_value;
+ unsigned long tlb_word2_value;
+
+ /* First, find the index of a TLB entry not being used */
+ for (i=0; i<PPC4XX_TLB_SIZE; i++) {
+ tlb_word0_value = mftlb1(i);
+ if ((tlb_word0_value & TLB_WORD0_V_MASK) == TLB_WORD0_V_DISABLE)
+ break;
+ }
+ if (i >= PPC4XX_TLB_SIZE)
+ return -1;
+
+ /* Second, create the TLB entry */
+ tlb_word0_value = TLB_WORD0_EPN_ENCODE(base_addr) | TLB_WORD0_V_ENABLE |
+ TLB_WORD0_TS_0 | tlb_word0_size_value;
+ tlb_word1_value = TLB_WORD1_RPN_ENCODE(base_addr) | TLB_WORD1_ERPN_ENCODE(0);
+ tlb_word2_value = TLB_WORD2_U0_DISABLE | TLB_WORD2_U1_DISABLE |
+ TLB_WORD2_U2_DISABLE | TLB_WORD2_U3_DISABLE |
+ TLB_WORD2_W_DISABLE | tlb_word2_i_value |
+ TLB_WORD2_M_DISABLE | TLB_WORD2_G_DISABLE |
+ TLB_WORD2_E_DISABLE | TLB_WORD2_UX_ENABLE |
+ TLB_WORD2_UW_ENABLE | TLB_WORD2_UR_ENABLE |
+ TLB_WORD2_SX_ENABLE | TLB_WORD2_SW_ENABLE |
+ TLB_WORD2_SR_ENABLE;
+
+ /* Wait for all memory accesses to complete */
+ sync();
+
+ /* Third, add the TLB entries */
+ mttlb1(i, tlb_word0_value);
+ mttlb2(i, tlb_word1_value);
+ mttlb3(i, tlb_word2_value);
+
+ /* Execute an ISYNC instruction so that the new TLB entry takes effect */
+ asm("isync");
+
+ return 0;
+}
+
+static void program_tlb_addr(unsigned long base_addr, unsigned long mem_size,
+ unsigned long tlb_word2_i_value)
+{
+ int rc;
+ int tlb_i;
+
+ tlb_i = tlb_word2_i_value;
+ while (mem_size != 0) {
+ rc = 0;
+ /* Add the TLB entries in to map the region. */
+ if (((base_addr & TLB_256MB_ALIGN_MASK) == base_addr) &&
+ (mem_size >= TLB_256MB_SIZE)) {
+ /* Add a 256MB TLB entry */
+ if ((rc = add_tlb_entry(base_addr, TLB_WORD0_SIZE_256MB, tlb_i)) == 0) {
+ mem_size -= TLB_256MB_SIZE;
+ base_addr += TLB_256MB_SIZE;
+ }
+ } else if (((base_addr & TLB_16MB_ALIGN_MASK) == base_addr) &&
+ (mem_size >= TLB_16MB_SIZE)) {
+ /* Add a 16MB TLB entry */
+ if ((rc = add_tlb_entry(base_addr, TLB_WORD0_SIZE_16MB, tlb_i)) == 0) {
+ mem_size -= TLB_16MB_SIZE;
+ base_addr += TLB_16MB_SIZE;
+ }
+ } else if (((base_addr & TLB_1MB_ALIGN_MASK) == base_addr) &&
+ (mem_size >= TLB_1MB_SIZE)) {
+ /* Add a 1MB TLB entry */
+ if ((rc = add_tlb_entry(base_addr, TLB_WORD0_SIZE_1MB, tlb_i)) == 0) {
+ mem_size -= TLB_1MB_SIZE;
+ base_addr += TLB_1MB_SIZE;
+ }
+ } else if (((base_addr & TLB_256KB_ALIGN_MASK) == base_addr) &&
+ (mem_size >= TLB_256KB_SIZE)) {
+ /* Add a 256KB TLB entry */
+ if ((rc = add_tlb_entry(base_addr, TLB_WORD0_SIZE_256KB, tlb_i)) == 0) {
+ mem_size -= TLB_256KB_SIZE;
+ base_addr += TLB_256KB_SIZE;
+ }
+ } else if (((base_addr & TLB_64KB_ALIGN_MASK) == base_addr) &&
+ (mem_size >= TLB_64KB_SIZE)) {
+ /* Add a 64KB TLB entry */
+ if ((rc = add_tlb_entry(base_addr, TLB_WORD0_SIZE_64KB, tlb_i)) == 0) {
+ mem_size -= TLB_64KB_SIZE;
+ base_addr += TLB_64KB_SIZE;
+ }
+ } else if (((base_addr & TLB_16KB_ALIGN_MASK) == base_addr) &&
+ (mem_size >= TLB_16KB_SIZE)) {
+ /* Add a 16KB TLB entry */
+ if ((rc = add_tlb_entry(base_addr, TLB_WORD0_SIZE_16KB, tlb_i)) == 0) {
+ mem_size -= TLB_16KB_SIZE;
+ base_addr += TLB_16KB_SIZE;
+ }
+ } else if (((base_addr & TLB_4KB_ALIGN_MASK) == base_addr) &&
+ (mem_size >= TLB_4KB_SIZE)) {
+ /* Add a 4KB TLB entry */
+ if ((rc = add_tlb_entry(base_addr, TLB_WORD0_SIZE_4KB, tlb_i)) == 0) {
+ mem_size -= TLB_4KB_SIZE;
+ base_addr += TLB_4KB_SIZE;
+ }
+ } else if (((base_addr & TLB_1KB_ALIGN_MASK) == base_addr) &&
+ (mem_size >= TLB_1KB_SIZE)) {
+ /* Add a 1KB TLB entry */
+ if ((rc = add_tlb_entry(base_addr, TLB_WORD0_SIZE_1KB, tlb_i)) == 0) {
+ mem_size -= TLB_1KB_SIZE;
+ base_addr += TLB_1KB_SIZE;
+ }
+ } else {
+ printf("ERROR: no TLB size exists for the base address 0x%0X.\n",
+ base_addr);
+ }
+
+ if (rc != 0)
+ printf("ERROR: no TLB entries available for the base addr 0x%0X.\n",
+ base_addr);
+ }
+
+ return;
+}
+
+/*
+ * Program one (or multiple) TLB entries for one memory region
+ *
+ * Common usage for boards with SDRAM DIMM modules to dynamically
+ * configure the TLB's for the SDRAM
+ */
+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_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,
+ region_array.tlb_word2_i_value);
+
+ return;
+}
+
+#endif /* CONFIG_440 */
diff --git a/cpu/ppc4xx/usb_ohci.c b/cpu/ppc4xx/usb_ohci.c
index ab852c5..c71a6a9 100644
--- a/cpu/ppc4xx/usb_ohci.c
+++ b/cpu/ppc4xx/usb_ohci.c
@@ -76,7 +76,7 @@
#define m16_swap(x) swap_16(x)
#define m32_swap(x) swap_32(x)
-#if defined(CONFIG_440EP) || defined(CONFIG_440EPX)
+#if defined(CONFIG_405EZ) || defined(CONFIG_440EP) || defined(CONFIG_440EPX)
#define ohci_cpu_to_le16(x) (x)
#define ohci_cpu_to_le32(x) (x)
#else
@@ -1601,7 +1601,7 @@ int usb_lowlevel_init(void)
gohci.irq = -1;
#if defined(CONFIG_440EP)
gohci.regs = (struct ohci_regs *)(CFG_PERIPHERAL_BASE | 0x1000);
-#elif defined(CONFIG_440EPX)
+#elif defined(CONFIG_440EPX) || defined(CFG_USB_HOST)
gohci.regs = (struct ohci_regs *)(CFG_USB_HOST);
#endif
@@ -1625,8 +1625,10 @@ int usb_lowlevel_init(void)
ohci_inited = 1;
urb_finished = 1;
+#if defined(CONFIG_440EP) || defined(CONFIG_440EPX)
/* init the device driver */
usb_dev_init();
+#endif
return 0;
}
diff --git a/cpu/ppc4xx/vecnum.h b/cpu/ppc4xx/vecnum.h
index 685d48b..bddf9e5 100644
--- a/cpu/ppc4xx/vecnum.h
+++ b/cpu/ppc4xx/vecnum.h
@@ -231,6 +231,47 @@
#else /* !defined(CONFIG_440) */
+#if defined(CONFIG_405EZ)
+#define VECNUM_D0 0 /* DMA channel 0 */
+#define VECNUM_D1 1 /* DMA channel 1 */
+#define VECNUM_D2 2 /* DMA channel 2 */
+#define VECNUM_D3 3 /* DMA channel 3 */
+#define VECNUM_1588 4 /* IEEE 1588 network synchronization */
+#define VECNUM_U0 5 /* UART0 */
+#define VECNUM_U1 6 /* UART1 */
+#define VECNUM_CAN0 7 /* CAN 0 */
+#define VECNUM_CAN1 8 /* CAN 1 */
+#define VECNUM_SPI 9 /* SPI */
+#define VECNUM_IIC0 10 /* I2C */
+#define VECNUM_CHT0 11 /* Chameleon timer high pri interrupt */
+#define VECNUM_CHT1 12 /* Chameleon timer high pri interrupt */
+#define VECNUM_USBH1 13 /* USB Host 1 */
+#define VECNUM_USBH2 14 /* USB Host 2 */
+#define VECNUM_USBDEV 15 /* USB Device */
+#define VECNUM_ETH0 16 /* 10/100 Ethernet interrupt status */
+#define VECNUM_EWU0 17 /* Ethernet wakeup sequence detected */
+
+#define VECNUM_MADMAL 18 /* Logical OR of following MadMAL int */
+#define VECNUM_MS 18 /* MAL_SERR_INT */
+#define VECNUM_TXDE 18 /* MAL_TXDE_INT */
+#define VECNUM_RXDE 18 /* MAL_RXDE_INT */
+
+#define VECNUM_MTE 19 /* MAL TXEOB */
+#define VECNUM_MTE1 20 /* MAL TXEOB1 */
+#define VECNUM_MRE 21 /* MAL RXEOB */
+#define VECNUM_NAND 22 /* NAND Flash controller */
+#define VECNUM_ADC 23 /* ADC */
+#define VECNUM_DAC 24 /* DAC */
+#define VECNUM_OPB2PLB 25 /* OPB to PLB bridge interrupt */
+#define VECNUM_RESERVED0 26 /* Reserved */
+#define VECNUM_EIR0 27 /* External interrupt 0 */
+#define VECNUM_EIR1 28 /* External interrupt 1 */
+#define VECNUM_EIR2 29 /* External interrupt 2 */
+#define VECNUM_EIR3 30 /* External interrupt 3 */
+#define VECNUM_EIR4 31 /* External interrupt 4 */
+
+#else /* !CONFIG_405EZ */
+
#define VECNUM_U0 0 /* UART0 */
#define VECNUM_U1 1 /* UART1 */
#define VECNUM_D0 5 /* DMA channel 0 */
@@ -251,6 +292,7 @@
#define VECNUM_EIR4 29 /* External interrupt 4 */
#define VECNUM_EIR5 30 /* External interrupt 5 */
#define VECNUM_EIR6 31 /* External interrupt 6 */
+#endif /* defined(CONFIG_405EZ) */
#endif /* defined(CONFIG_440) */