summaryrefslogtreecommitdiffstats
path: root/board
diff options
context:
space:
mode:
authorRafal Jaworowski <raj@semihalf.com>2006-08-10 12:43:17 +0200
committerRafal Jaworowski <raj@pollux.denx.de>2006-08-10 12:43:17 +0200
commit692519b1edfd5803cd2a841921492889f46f0ce3 (patch)
tree1a761268c5b203444769a19257a317d09ce396c4 /board
parentedd6cf20e1be63f84e0f5af0280473cf31f0e86c (diff)
downloadbarebox-692519b1edfd5803cd2a841921492889f46f0ce3.tar.gz
barebox-692519b1edfd5803cd2a841921492889f46f0ce3.tar.xz
Add support for PCI-Express on PPC440SPe (Yucca board).
Diffstat (limited to 'board')
-rw-r--r--board/amcc/yucca/init.S62
-rw-r--r--board/amcc/yucca/yucca.c130
2 files changed, 186 insertions, 6 deletions
diff --git a/board/amcc/yucca/init.S b/board/amcc/yucca/init.S
index 8cf2636228..a950eac44f 100644
--- a/board/amcc/yucca/init.S
+++ b/board/amcc/yucca/init.S
@@ -82,9 +82,12 @@
*************************************************************************/
.section .bootpg,"ax"
- .globl tlbtab
-tlbtab:
+/**************************************************************************
+ * TLB table for revA
+ *************************************************************************/
+ .globl tlbtabA
+tlbtabA:
tlbtab_start
tlbentry(0xfff00000, SZ_16M, 0xfff00000, 4, AC_R|AC_W|AC_X|SA_G)
@@ -94,12 +97,63 @@ tlbtab:
tlbentry(CFG_SDRAM_BASE + 0x30000000, SZ_256M, 0x30000000, 0, AC_R|AC_W|AC_X|SA_G|SA_I)
tlbentry(CFG_ISRAM_BASE, SZ_256K, 0x00000000, 4, AC_R|AC_W|AC_X|SA_I)
- tlbentry(CFG_FPGA_BASE,SZ_1K, 0xE2000000, 4,AC_R|AC_W|SA_I)
+ tlbentry(CFG_FPGA_BASE, SZ_1K, 0xE2000000, 4,AC_R|AC_W|SA_I)
- tlbentry(CFG_OPER_FLASH,SZ_16M,0xE7000000, 4,AC_R|AC_W|AC_X|SA_G|SA_I)
+ tlbentry(CFG_OPER_FLASH, SZ_16M, 0xE7000000, 4,AC_R|AC_W|AC_X|SA_G|SA_I)
tlbentry(CFG_PERIPHERAL_BASE, SZ_4K, 0xF0000000, 4, AC_R|AC_W|SA_G|SA_I)
tlbentry(CFG_PCI_BASE, SZ_256M, 0x00000000, 0xC, AC_R|AC_W|SA_G|SA_I)
tlbentry(CFG_PCI_MEMBASE, SZ_256M, 0x10000000, 0xC, AC_R|AC_W|SA_G|SA_I)
+ tlbentry(CFG_PCIE_MEMBASE, SZ_256M, 0xB0000000, 0xD, AC_R|AC_W|SA_G|SA_I)
+
+ tlbentry(CFG_PCIE0_CFGBASE, SZ_16M, 0x40000000, 0xC, AC_R|AC_W|SA_G|SA_I)
+ tlbentry(CFG_PCIE1_CFGBASE, SZ_16M, 0x80000000, 0xC, AC_R|AC_W|SA_G|SA_I)
+ tlbentry(CFG_PCIE2_CFGBASE, SZ_16M, 0xC0000000, 0xC, AC_R|AC_W|SA_G|SA_I)
+ tlbentry(CFG_PCIE0_XCFGBASE, SZ_4K, 0x50000000, 0xC, AC_R|AC_W|SA_G|SA_I)
+ tlbentry(CFG_PCIE1_XCFGBASE, SZ_4K, 0x90000000, 0xC, AC_R|AC_W|SA_G|SA_I)
+ tlbentry(CFG_PCIE2_XCFGBASE, SZ_4K, 0xD0000000, 0xC, AC_R|AC_W|SA_G|SA_I)
+
+ tlbentry(CFG_PCIE1_REGBASE, SZ_1K, 0x60000400, 0xD, AC_R|AC_W|SA_G|SA_I)
+ tlbentry(CFG_PCIE3_REGBASE, SZ_1K, 0x60001400, 0xD, AC_R|AC_W|SA_G|SA_I)
+ tlbentry(CFG_PCIE5_REGBASE, SZ_1K, 0x60002400, 0xD, AC_R|AC_W|SA_G|SA_I)
tlbtab_end
+/**************************************************************************
+ * TLB table for revB
+ *
+ * Notice: revB of the 440SPe chip is very strict about PLB real addressess
+ * and ranges to be mapped for config space: it seems to only work with
+ * d_nnnn_nnnn range (hangs the core upon config transaction attempts when
+ * set otherwise) while revA uses c_nnnn_nnnn.
+ *************************************************************************/
+ .globl tlbtabB
+tlbtabB:
+ tlbtab_start
+ tlbentry(0xfff00000, SZ_16M, 0xfff00000, 4, AC_R|AC_W|AC_X|SA_G)
+
+ tlbentry(CFG_SDRAM_BASE, SZ_256M, 0x00000000, 0, AC_R|AC_W|AC_X|SA_G|SA_I)
+ tlbentry(CFG_SDRAM_BASE + 0x10000000, SZ_256M, 0x10000000, 0, AC_R|AC_W|AC_X|SA_G|SA_I)
+ tlbentry(CFG_SDRAM_BASE + 0x20000000, SZ_256M, 0x20000000, 0, AC_R|AC_W|AC_X|SA_G|SA_I)
+ tlbentry(CFG_SDRAM_BASE + 0x30000000, SZ_256M, 0x30000000, 0, AC_R|AC_W|AC_X|SA_G|SA_I)
+
+ tlbentry(CFG_ISRAM_BASE, SZ_256K, 0x00000000, 4, AC_R|AC_W|AC_X|SA_I)
+ tlbentry(CFG_FPGA_BASE, SZ_1K, 0xE2000000, 4,AC_R|AC_W|SA_I)
+
+ tlbentry(CFG_OPER_FLASH, SZ_16M, 0xE7000000, 4,AC_R|AC_W|AC_X|SA_G|SA_I)
+ tlbentry(CFG_PERIPHERAL_BASE, SZ_4K, 0xF0000000, 4, AC_R|AC_W|SA_G|SA_I)
+
+ tlbentry(CFG_PCI_BASE, SZ_256M, 0x00000000, 0xC, AC_R|AC_W|SA_G|SA_I)
+ tlbentry(CFG_PCI_MEMBASE, SZ_256M, 0x10000000, 0xC, AC_R|AC_W|SA_G|SA_I)
+ tlbentry(CFG_PCIE_MEMBASE, SZ_256M, 0xB0000000, 0xD, AC_R|AC_W|SA_G|SA_I)
+
+ tlbentry(CFG_PCIE0_CFGBASE, SZ_1K, 0x00100000, 0xD, AC_R|AC_W|SA_G|SA_I)
+ tlbentry(CFG_PCIE1_CFGBASE, SZ_1K, 0x20100000, 0xD, AC_R|AC_W|SA_G|SA_I)
+ tlbentry(CFG_PCIE2_CFGBASE, SZ_1K, 0x40100000, 0xD, AC_R|AC_W|SA_G|SA_I)
+ tlbentry(CFG_PCIE0_XCFGBASE, SZ_1K, 0x10000000, 0xD, AC_R|AC_W|SA_G|SA_I)
+ tlbentry(CFG_PCIE1_XCFGBASE, SZ_1K, 0x30000000, 0xD, AC_R|AC_W|SA_G|SA_I)
+ tlbentry(CFG_PCIE2_XCFGBASE, SZ_1K, 0x50000000, 0xD, AC_R|AC_W|SA_G|SA_I)
+
+ tlbentry(CFG_PCIE1_REGBASE, SZ_1K, 0x60000400, 0xD, AC_R|AC_W|SA_G|SA_I)
+ tlbentry(CFG_PCIE3_REGBASE, SZ_1K, 0x60001400, 0xD, AC_R|AC_W|SA_G|SA_I)
+ tlbentry(CFG_PCIE5_REGBASE, SZ_1K, 0x60002400, 0xD, AC_R|AC_W|SA_G|SA_I)
+ tlbtab_end
diff --git a/board/amcc/yucca/yucca.c b/board/amcc/yucca/yucca.c
index 1ae3a549b9..a6589ec262 100644
--- a/board/amcc/yucca/yucca.c
+++ b/board/amcc/yucca/yucca.c
@@ -21,12 +21,16 @@
* 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"
void fpga_init (void);
@@ -39,6 +43,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)
@@ -908,6 +915,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 +931,131 @@ 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));
+}
+
+
+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;
+
+ yucca_setup_pcie_fpga_rootpoint(i);
+ if (ppc440spe_init_pcie_rootport(i)) {
+ 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);
+
+ ppc440spe_setup_pcie(hose, i);
+ hose->last_busno = pci_hose_scan(hose);
+ }
+}
#endif /* defined(CONFIG_PCI) */
int misc_init_f (void)
@@ -1094,4 +1221,3 @@ unsigned long ppcMfsdr(unsigned long sdr_reg)
return (sdr_value);
}
-