From 692519b1edfd5803cd2a841921492889f46f0ce3 Mon Sep 17 00:00:00 2001 From: Rafal Jaworowski Date: Thu, 10 Aug 2006 12:43:17 +0200 Subject: Add support for PCI-Express on PPC440SPe (Yucca board). --- board/amcc/yucca/init.S | 62 ++++++++++++++++++++-- board/amcc/yucca/yucca.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 186 insertions(+), 6 deletions(-) (limited to 'board') diff --git a/board/amcc/yucca/init.S b/board/amcc/yucca/init.S index 8cf2636..a950eac 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 1ae3a54..a6589ec 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 #include #include #include +#include + #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); } - -- cgit v1.1