summaryrefslogtreecommitdiff
path: root/board/amcc/yucca/yucca.c
diff options
context:
space:
mode:
Diffstat (limited to 'board/amcc/yucca/yucca.c')
-rw-r--r--board/amcc/yucca/yucca.c228
1 files changed, 220 insertions, 8 deletions
diff --git a/board/amcc/yucca/yucca.c b/board/amcc/yucca/yucca.c
index ce1312c..e9b34dd 100644
--- a/board/amcc/yucca/yucca.c
+++ b/board/amcc/yucca/yucca.c
@@ -21,13 +21,21 @@
* MA 02111-1307 USA
*
* Port to AMCC-440SPE Evaluation Board SOP - April 2005
+ *
+ * PCIe supporting routines derived from Linux 440SPe PCIe driver.
*/
#include <common.h>
#include <ppc4xx.h>
#include <asm/processor.h>
#include <i2c.h>
+#include <asm-ppc/io.h>
+
#include "yucca.h"
+#include "../cpu/ppc4xx/440spe_pcie.h"
+
+#undef PCIE_ENDPOINT
+/* #define PCIE_ENDPOINT 1 */
void fpga_init (void);
@@ -39,6 +47,9 @@ int get_console_port(void);
unsigned long ppcMfcpr(unsigned long cpr_reg);
unsigned long ppcMfsdr(unsigned long sdr_reg);
+int ppc440spe_init_pcie_rootport(int port);
+void ppc440spe_setup_pcie(struct pci_controller *hose, int port);
+
#define DEBUG_ENV
#ifdef DEBUG_ENV
#define DEBUGF(fmt,args...) printf(fmt ,##args)
@@ -555,10 +566,11 @@ int checkboard (void)
static long int yucca_probe_for_dimms(void)
{
- long int dimm_installed[MAXDIMMS];
- long int dimm_num, probe_result;
- long int dimms_found = 0;
- uchar dimm_addr = IIC0_DIMM0_ADDR;
+ int dimm_installed[MAXDIMMS];
+ int dimm_num, result;
+ int dimms_found = 0;
+ uchar dimm_addr = IIC0_DIMM0_ADDR;
+ uchar dimm_spd_data[MAX_SPD_BYTES];
for (dimm_num = 0; dimm_num < MAXDIMMS; dimm_num++) {
/* check if there is a chip at the dimm address */
@@ -570,12 +582,28 @@ static long int yucca_probe_for_dimms(void)
dimm_addr = IIC0_DIMM1_ADDR;
break;
}
- probe_result = i2c_probe(dimm_addr);
- if (probe_result == 0) {
+ result = i2c_probe(dimm_addr);
+
+ memset(dimm_spd_data, 0, MAX_SPD_BYTES * sizeof(char));
+ if (result == 0) {
+ /* read first byte of SPD data, if there is any data */
+ result = i2c_read(dimm_addr, 0, 1, dimm_spd_data, 1);
+
+ if (result == 0) {
+ result = dimm_spd_data[0];
+ result = result > MAX_SPD_BYTES ?
+ MAX_SPD_BYTES : result;
+ result = i2c_read(dimm_addr, 0, 1,
+ dimm_spd_data, result);
+ }
+ }
+
+ if ((result == 0) &&
+ (dimm_spd_data[64] == MICRON_SPD_JEDEC_ID)) {
dimm_installed[dimm_num] = TRUE;
dimms_found++;
- debug("DIMM slot %d: DDR2 SDRAM detected\n",dimm_num);
+ debug("DIMM slot %d: DDR2 SDRAM detected\n", dimm_num);
} else {
dimm_installed[dimm_num] = FALSE;
debug("DIMM slot %d: Not populated or cannot sucessfully probe the DIMM\n", dimm_num);
@@ -908,6 +936,7 @@ void pci_target_init(struct pci_controller * hose )
}
#endif /* defined(CONFIG_PCI) && defined(CFG_PCI_TARGET_INIT) */
+#if defined(CONFIG_PCI)
/*************************************************************************
* is_pci_host
*
@@ -923,12 +952,195 @@ void pci_target_init(struct pci_controller * hose )
*
*
************************************************************************/
-#if defined(CONFIG_PCI)
int is_pci_host(struct pci_controller *hose)
{
/* The yucca board is always configured as host. */
return 1;
}
+
+int yucca_pcie_card_present(int port)
+{
+ u16 reg;
+
+ reg = in_be16((u16 *)FPGA_REG1C);
+ switch(port) {
+ case 0:
+ return !(reg & FPGA_REG1C_PE0_PRSNT);
+ case 1:
+ return !(reg & FPGA_REG1C_PE1_PRSNT);
+ case 2:
+ return !(reg & FPGA_REG1C_PE2_PRSNT);
+ default:
+ return 0;
+ }
+}
+
+/*
+ * For the given slot, set rootpoint mode, send power to the slot,
+ * turn on the green LED and turn off the yellow LED, enable the clock
+ * and turn off reset.
+ */
+void yucca_setup_pcie_fpga_rootpoint(int port)
+{
+ u16 power, clock, green_led, yellow_led, reset_off, rootpoint, endpoint;
+
+ switch(port) {
+ case 0:
+ rootpoint = FPGA_REG1C_PE0_ROOTPOINT;
+ endpoint = 0;
+ power = FPGA_REG1A_PE0_PWRON;
+ green_led = FPGA_REG1A_PE0_GLED;
+ clock = FPGA_REG1A_PE0_REFCLK_ENABLE;
+ yellow_led = FPGA_REG1A_PE0_YLED;
+ reset_off = FPGA_REG1C_PE0_PERST;
+ break;
+ case 1:
+ rootpoint = 0;
+ endpoint = FPGA_REG1C_PE1_ENDPOINT;
+ power = FPGA_REG1A_PE1_PWRON;
+ green_led = FPGA_REG1A_PE1_GLED;
+ clock = FPGA_REG1A_PE1_REFCLK_ENABLE;
+ yellow_led = FPGA_REG1A_PE1_YLED;
+ reset_off = FPGA_REG1C_PE1_PERST;
+ break;
+ case 2:
+ rootpoint = 0;
+ endpoint = FPGA_REG1C_PE2_ENDPOINT;
+ power = FPGA_REG1A_PE2_PWRON;
+ green_led = FPGA_REG1A_PE2_GLED;
+ clock = FPGA_REG1A_PE2_REFCLK_ENABLE;
+ yellow_led = FPGA_REG1A_PE2_YLED;
+ reset_off = FPGA_REG1C_PE2_PERST;
+ break;
+
+ default:
+ return;
+ }
+
+ out_be16((u16 *)FPGA_REG1A,
+ ~(power | clock | green_led) &
+ (yellow_led | in_be16((u16 *)FPGA_REG1A)));
+
+ out_be16((u16 *)FPGA_REG1C,
+ ~(endpoint | reset_off) &
+ (rootpoint | in_be16((u16 *)FPGA_REG1C)));
+ /*
+ * Leave device in reset for a while after powering on the
+ * slot to give it a chance to initialize.
+ */
+ udelay(250 * 1000);
+
+ out_be16((u16 *)FPGA_REG1C, reset_off | in_be16((u16 *)FPGA_REG1C));
+}
+/*
+ * For the given slot, set endpoint mode, send power to the slot,
+ * turn on the green LED and turn off the yellow LED, enable the clock
+ * .In end point mode reset bit is read only.
+ */
+void yucca_setup_pcie_fpga_endpoint(int port)
+{
+ u16 power, clock, green_led, yellow_led, reset_off, rootpoint, endpoint;
+
+ switch(port) {
+ case 0:
+ rootpoint = FPGA_REG1C_PE0_ROOTPOINT;
+ endpoint = 0;
+ power = FPGA_REG1A_PE0_PWRON;
+ green_led = FPGA_REG1A_PE0_GLED;
+ clock = FPGA_REG1A_PE0_REFCLK_ENABLE;
+ yellow_led = FPGA_REG1A_PE0_YLED;
+ reset_off = FPGA_REG1C_PE0_PERST;
+ break;
+ case 1:
+ rootpoint = 0;
+ endpoint = FPGA_REG1C_PE1_ENDPOINT;
+ power = FPGA_REG1A_PE1_PWRON;
+ green_led = FPGA_REG1A_PE1_GLED;
+ clock = FPGA_REG1A_PE1_REFCLK_ENABLE;
+ yellow_led = FPGA_REG1A_PE1_YLED;
+ reset_off = FPGA_REG1C_PE1_PERST;
+ break;
+ case 2:
+ rootpoint = 0;
+ endpoint = FPGA_REG1C_PE2_ENDPOINT;
+ power = FPGA_REG1A_PE2_PWRON;
+ green_led = FPGA_REG1A_PE2_GLED;
+ clock = FPGA_REG1A_PE2_REFCLK_ENABLE;
+ yellow_led = FPGA_REG1A_PE2_YLED;
+ reset_off = FPGA_REG1C_PE2_PERST;
+ break;
+
+ default:
+ return;
+ }
+
+ out_be16((u16 *)FPGA_REG1A,
+ ~(power | clock | green_led) &
+ (yellow_led | in_be16((u16 *)FPGA_REG1A)));
+
+ out_be16((u16 *)FPGA_REG1C,
+ ~(rootpoint | reset_off) &
+ (endpoint | in_be16((u16 *)FPGA_REG1C)));
+}
+
+static struct pci_controller pcie_hose[3] = {{0},{0},{0}};
+
+void pcie_setup_hoses(void)
+{
+ struct pci_controller *hose;
+ int i, bus;
+
+ /*
+ * assume we're called after the PCIX hose is initialized, which takes
+ * bus ID 0 and therefore start numbering PCIe's from 1.
+ */
+ bus = 1;
+ for (i = 0; i <= 2; i++) {
+ /* Check for yucca card presence */
+ if (!yucca_pcie_card_present(i))
+ continue;
+
+#ifdef PCIE_ENDPOINT
+ yucca_setup_pcie_fpga_endpoint(i);
+ if (ppc440spe_init_pcie_endport(i)) {
+#else
+ yucca_setup_pcie_fpga_rootpoint(i);
+ if (ppc440spe_init_pcie_rootport(i)) {
+#endif
+ printf("PCIE%d: initialization failed\n", i);
+ continue;
+ }
+
+ hose = &pcie_hose[i];
+ hose->first_busno = bus;
+ hose->last_busno = bus;
+ bus++;
+
+ /* setup mem resource */
+ pci_set_region(hose->regions + 0,
+ CFG_PCIE_MEMBASE + i * CFG_PCIE_MEMSIZE,
+ CFG_PCIE_MEMBASE + i * CFG_PCIE_MEMSIZE,
+ CFG_PCIE_MEMSIZE,
+ PCI_REGION_MEM
+ );
+ hose->region_count = 1;
+ pci_register_hose(hose);
+
+#ifdef PCIE_ENDPOINT
+ ppc440spe_setup_pcie_endpoint(hose, i);
+ /*
+ * Reson for no scanning is endpoint can not generate
+ * upstream configuration accesses.
+ */
+#else
+ ppc440spe_setup_pcie_rootpoint(hose, i);
+ /*
+ * Config access can only go down stream
+ */
+ hose->last_busno = pci_hose_scan(hose);
+#endif
+ }
+}
#endif /* defined(CONFIG_PCI) */
int misc_init_f (void)