From c7c6da23028f146d912514b95aefa3da7cf37699 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Wed, 3 Oct 2007 07:34:10 +0200 Subject: ppc4xx: Make 440SPe PCIe code more generic to use on different 4xx PPCs (1) This patch is the first patch of a series to make the 440SPe PCIe code usable on different 4xx PPC platforms. In preperation for the new 405EX which is also equipped with PCIe interfaces. (1) This patch renames the files from 440spe_pcie to 4xx_pcie Signed-off-by: Stefan Roese --- cpu/ppc4xx/4xx_pcie.c | 1067 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1067 insertions(+) create mode 100644 cpu/ppc4xx/4xx_pcie.c (limited to 'cpu/ppc4xx/4xx_pcie.c') diff --git a/cpu/ppc4xx/4xx_pcie.c b/cpu/ppc4xx/4xx_pcie.c new file mode 100644 index 0000000..8906adc --- /dev/null +++ b/cpu/ppc4xx/4xx_pcie.c @@ -0,0 +1,1067 @@ +/* + * (C) Copyright 2006 - 2007 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * Roland Dreier + * + * 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. + * + */ + +#include +#include +#include +#include +#include + +#if defined(CONFIG_440SPE) && defined(CONFIG_PCI) + +#include + +enum { + PTYPE_ENDPOINT = 0x0, + PTYPE_LEGACY_ENDPOINT = 0x1, + PTYPE_ROOT_PORT = 0x4, + + LNKW_X1 = 0x1, + LNKW_X4 = 0x4, + LNKW_X8 = 0x8 +}; + +static u8* pcie_get_base(struct pci_controller *hose, unsigned int devfn) +{ + u8 *base = (u8*)hose->cfg_data; + + /* use local configuration space for the first bus */ + if (PCI_BUS(devfn) == 0) { + if (hose->cfg_data == (u8*)CFG_PCIE0_CFGBASE) + base = (u8*)CFG_PCIE0_XCFGBASE; + if (hose->cfg_data == (u8*)CFG_PCIE1_CFGBASE) + base = (u8*)CFG_PCIE1_XCFGBASE; + if (hose->cfg_data == (u8*)CFG_PCIE2_CFGBASE) + base = (u8*)CFG_PCIE2_XCFGBASE; + } + + return base; +} + +static void pcie_dmer_disable(void) +{ + mtdcr (DCRN_PEGPL_CFG(DCRN_PCIE0_BASE), + mfdcr (DCRN_PEGPL_CFG(DCRN_PCIE0_BASE)) | GPL_DMER_MASK_DISA); + mtdcr (DCRN_PEGPL_CFG(DCRN_PCIE1_BASE), + mfdcr (DCRN_PEGPL_CFG(DCRN_PCIE1_BASE)) | GPL_DMER_MASK_DISA); + mtdcr (DCRN_PEGPL_CFG(DCRN_PCIE2_BASE), + mfdcr (DCRN_PEGPL_CFG(DCRN_PCIE2_BASE)) | GPL_DMER_MASK_DISA); +} + +static void pcie_dmer_enable(void) +{ + mtdcr (DCRN_PEGPL_CFG (DCRN_PCIE0_BASE), + mfdcr (DCRN_PEGPL_CFG(DCRN_PCIE0_BASE)) & ~GPL_DMER_MASK_DISA); + mtdcr (DCRN_PEGPL_CFG (DCRN_PCIE1_BASE), + mfdcr (DCRN_PEGPL_CFG(DCRN_PCIE1_BASE)) & ~GPL_DMER_MASK_DISA); + mtdcr (DCRN_PEGPL_CFG (DCRN_PCIE2_BASE), + mfdcr (DCRN_PEGPL_CFG(DCRN_PCIE2_BASE)) & ~GPL_DMER_MASK_DISA); +} + +static int pcie_read_config(struct pci_controller *hose, unsigned int devfn, + int offset, int len, u32 *val) { + + u8 *address; + *val = 0; + + /* + * Bus numbers are relative to hose->first_busno + */ + devfn -= PCI_BDF(hose->first_busno, 0, 0); + + /* + * NOTICE: configuration space ranges are currenlty mapped only for + * the first 16 buses, so such limit must be imposed. In case more + * buses are required the TLB settings in board/amcc//init.S + * need to be altered accordingly (one bus takes 1 MB of memory space). + */ + if (PCI_BUS(devfn) >= 16) + return 0; + + /* + * Only single device/single function is supported for the primary and + * secondary buses of the 440SPe host bridge. + */ + if ((!((PCI_FUNC(devfn) == 0) && (PCI_DEV(devfn) == 0))) && + ((PCI_BUS(devfn) == 0) || (PCI_BUS(devfn) == 1))) + return 0; + + address = pcie_get_base(hose, devfn); + offset += devfn << 4; + + /* + * Reading from configuration space of non-existing device can + * generate transaction errors. For the read duration we suppress + * assertion of machine check exceptions to avoid those. + */ + pcie_dmer_disable (); + + switch (len) { + case 1: + *val = in_8(hose->cfg_data + offset); + break; + case 2: + *val = in_le16((u16 *)(hose->cfg_data + offset)); + break; + default: + *val = in_le32((u32*)(hose->cfg_data + offset)); + break; + } + + pcie_dmer_enable (); + + return 0; +} + +static int pcie_write_config(struct pci_controller *hose, unsigned int devfn, + int offset, int len, u32 val) { + + u8 *address; + + /* + * Bus numbers are relative to hose->first_busno + */ + devfn -= PCI_BDF(hose->first_busno, 0, 0); + + /* + * Same constraints as in pcie_read_config(). + */ + if (PCI_BUS(devfn) >= 16) + return 0; + + if ((!((PCI_FUNC(devfn) == 0) && (PCI_DEV(devfn) == 0))) && + ((PCI_BUS(devfn) == 0) || (PCI_BUS(devfn) == 1))) + return 0; + + address = pcie_get_base(hose, devfn); + offset += devfn << 4; + + /* + * Suppress MCK exceptions, similar to pcie_read_config() + */ + pcie_dmer_disable (); + + switch (len) { + case 1: + out_8(hose->cfg_data + offset, val); + break; + case 2: + out_le16((u16 *)(hose->cfg_data + offset), val); + break; + default: + out_le32((u32 *)(hose->cfg_data + offset), val); + break; + } + + pcie_dmer_enable (); + + return 0; +} + +int pcie_read_config_byte(struct pci_controller *hose,pci_dev_t dev,int offset,u8 *val) +{ + u32 v; + int rv; + + rv = pcie_read_config(hose, dev, offset, 1, &v); + *val = (u8)v; + return rv; +} + +int pcie_read_config_word(struct pci_controller *hose,pci_dev_t dev,int offset,u16 *val) +{ + u32 v; + int rv; + + rv = pcie_read_config(hose, dev, offset, 2, &v); + *val = (u16)v; + return rv; +} + +int pcie_read_config_dword(struct pci_controller *hose,pci_dev_t dev,int offset,u32 *val) +{ + u32 v; + int rv; + + rv = pcie_read_config(hose, dev, offset, 3, &v); + *val = (u32)v; + return rv; +} + +int pcie_write_config_byte(struct pci_controller *hose,pci_dev_t dev,int offset,u8 val) +{ + return pcie_write_config(hose,(u32)dev,offset,1,val); +} + +int pcie_write_config_word(struct pci_controller *hose,pci_dev_t dev,int offset,u16 val) +{ + return pcie_write_config(hose,(u32)dev,offset,2,(u32 )val); +} + +int pcie_write_config_dword(struct pci_controller *hose,pci_dev_t dev,int offset,u32 val) +{ + return pcie_write_config(hose,(u32)dev,offset,3,(u32 )val); +} + +static void ppc440spe_setup_utl(u32 port) { + + volatile void *utl_base = NULL; + + /* + * Map UTL registers + */ + switch (port) { + case 0: + mtdcr(DCRN_PEGPL_REGBAH(PCIE0), 0x0000000c); + mtdcr(DCRN_PEGPL_REGBAL(PCIE0), 0x20000000); + mtdcr(DCRN_PEGPL_REGMSK(PCIE0), 0x00007001); + mtdcr(DCRN_PEGPL_SPECIAL(PCIE0), 0x68782800); + break; + + case 1: + mtdcr(DCRN_PEGPL_REGBAH(PCIE1), 0x0000000c); + mtdcr(DCRN_PEGPL_REGBAL(PCIE1), 0x20001000); + mtdcr(DCRN_PEGPL_REGMSK(PCIE1), 0x00007001); + mtdcr(DCRN_PEGPL_SPECIAL(PCIE1), 0x68782800); + break; + + case 2: + mtdcr(DCRN_PEGPL_REGBAH(PCIE2), 0x0000000c); + mtdcr(DCRN_PEGPL_REGBAL(PCIE2), 0x20002000); + mtdcr(DCRN_PEGPL_REGMSK(PCIE2), 0x00007001); + mtdcr(DCRN_PEGPL_SPECIAL(PCIE2), 0x68782800); + break; + } + utl_base = (unsigned int *)(CFG_PCIE_BASE + 0x1000 * port); + + /* + * Set buffer allocations and then assert VRB and TXE. + */ + out_be32(utl_base + PEUTL_OUTTR, 0x08000000); + out_be32(utl_base + PEUTL_INTR, 0x02000000); + out_be32(utl_base + PEUTL_OPDBSZ, 0x10000000); + out_be32(utl_base + PEUTL_PBBSZ, 0x53000000); + out_be32(utl_base + PEUTL_IPHBSZ, 0x08000000); + out_be32(utl_base + PEUTL_IPDBSZ, 0x10000000); + out_be32(utl_base + PEUTL_RCIRQEN, 0x00f00000); + out_be32(utl_base + PEUTL_PCTL, 0x80800066); +} + +static int check_error(void) +{ + u32 valPE0, valPE1, valPE2; + int err = 0; + + /* SDR0_PEGPLLLCT1 reset */ + if (!(valPE0 = SDR_READ(PESDR0_PLLLCT1) & 0x01000000)) { + printf("PCIE: SDR0_PEGPLLLCT1 reset error 0x%x\n", valPE0); + } + + valPE0 = SDR_READ(PESDR0_RCSSET); + valPE1 = SDR_READ(PESDR1_RCSSET); + valPE2 = SDR_READ(PESDR2_RCSSET); + + /* SDR0_PExRCSSET rstgu */ + if (!(valPE0 & 0x01000000) || + !(valPE1 & 0x01000000) || + !(valPE2 & 0x01000000)) { + printf("PCIE: SDR0_PExRCSSET rstgu error\n"); + err = -1; + } + + /* SDR0_PExRCSSET rstdl */ + if (!(valPE0 & 0x00010000) || + !(valPE1 & 0x00010000) || + !(valPE2 & 0x00010000)) { + printf("PCIE: SDR0_PExRCSSET rstdl error\n"); + err = -1; + } + + /* SDR0_PExRCSSET rstpyn */ + if ((valPE0 & 0x00001000) || + (valPE1 & 0x00001000) || + (valPE2 & 0x00001000)) { + printf("PCIE: SDR0_PExRCSSET rstpyn error\n"); + err = -1; + } + + /* SDR0_PExRCSSET hldplb */ + if ((valPE0 & 0x10000000) || + (valPE1 & 0x10000000) || + (valPE2 & 0x10000000)) { + printf("PCIE: SDR0_PExRCSSET hldplb error\n"); + err = -1; + } + + /* SDR0_PExRCSSET rdy */ + if ((valPE0 & 0x00100000) || + (valPE1 & 0x00100000) || + (valPE2 & 0x00100000)) { + printf("PCIE: SDR0_PExRCSSET rdy error\n"); + err = -1; + } + + /* SDR0_PExRCSSET shutdown */ + if ((valPE0 & 0x00000100) || + (valPE1 & 0x00000100) || + (valPE2 & 0x00000100)) { + printf("PCIE: SDR0_PExRCSSET shutdown error\n"); + err = -1; + } + return err; +} + +/* + * Initialize PCI Express core + */ +int ppc440spe_init_pcie(void) +{ + int time_out = 20; + + /* Set PLL clock receiver to LVPECL */ + SDR_WRITE(PESDR0_PLLLCT1, SDR_READ(PESDR0_PLLLCT1) | 1 << 28); + + if (check_error()) + return -1; + + if (!(SDR_READ(PESDR0_PLLLCT2) & 0x10000)) + { + printf("PCIE: PESDR_PLLCT2 resistance calibration failed (0x%08x)\n", + SDR_READ(PESDR0_PLLLCT2)); + return -1; + } + /* De-assert reset of PCIe PLL, wait for lock */ + SDR_WRITE(PESDR0_PLLLCT1, SDR_READ(PESDR0_PLLLCT1) & ~(1 << 24)); + udelay(3); + + while (time_out) { + if (!(SDR_READ(PESDR0_PLLLCT3) & 0x10000000)) { + time_out--; + udelay(1); + } else + break; + } + if (!time_out) { + printf("PCIE: VCO output not locked\n"); + return -1; + } + return 0; +} + +/* + * Yucca board as End point and root point setup + * and + * testing inbound and out bound windows + * + * YUCCA board can be plugged into another yucca board or you can get PCI-E + * cable which can be used to setup loop back from one port to another port. + * Please rememeber that unless there is a endpoint plugged in to root port it + * will not initialize. It is the same in case of endpoint , unless there is + * root port attached it will not initialize. + * + * In this release of software all the PCI-E ports are configured as either + * endpoint or rootpoint.In future we will have support for selective ports + * setup as endpoint and root point in single board. + * + * Once your board came up as root point , you can verify by reading + * /proc/bus/pci/devices. Where you can see the configuration registers + * of end point device attached to the port. + * + * Enpoint cofiguration can be verified by connecting Yucca board to any + * host or another yucca board. Then try to scan the device. In case of + * linux use "lspci" or appripriate os command. + * + * How do I verify the inbound and out bound windows ?(yucca to yucca) + * in this configuration inbound and outbound windows are setup to access + * sram memroy area. SRAM is at 0x4 0000 0000 , on PLB bus. This address + * is mapped at 0x90000000. From u-boot prompt write data 0xb000 0000, + * This is waere your POM(PLB out bound memory window) mapped. then + * read the data from other yucca board's u-boot prompt at address + * 0x9000 0000(SRAM). Data should match. + * In case of inbound , write data to u-boot command prompt at 0xb000 0000 + * which is mapped to 0x4 0000 0000. Now on rootpoint yucca u-boot prompt check + * data at 0x9000 0000(SRAM).Data should match. + */ +int ppc440spe_init_pcie_rootport(int port) +{ + static int core_init; + volatile u32 val = 0; + int attempts; + + if (!core_init) { + ++core_init; + if (ppc440spe_init_pcie()) + return -1; + } + + /* + * Initialize various parts of the PCI Express core for our port: + * + * - Set as a root port and enable max width + * (PXIE0 -> X8, PCIE1 and PCIE2 -> X4). + * - Set up UTL configuration. + * - Increase SERDES drive strength to levels suggested by AMCC. + * - De-assert RSTPYN, RSTDL and RSTGU. + * + * NOTICE for revB chip: PESDRn_UTLSET2 is not set - we leave it with + * default setting 0x11310000. The register has new fields, + * PESDRn_UTLSET2[LKINE] in particular: clearing it leads to PCIE core + * hang. + */ + switch (port) { + case 0: + SDR_WRITE(PESDR0_DLPSET, 1 << 24 | PTYPE_ROOT_PORT << 20 | LNKW_X8 << 12); + + SDR_WRITE(PESDR0_UTLSET1, 0x21222222); + if (!ppc440spe_revB()) + SDR_WRITE(PESDR0_UTLSET2, 0x11000000); + SDR_WRITE(PESDR0_HSSL0SET1, 0x35000000); + SDR_WRITE(PESDR0_HSSL1SET1, 0x35000000); + SDR_WRITE(PESDR0_HSSL2SET1, 0x35000000); + SDR_WRITE(PESDR0_HSSL3SET1, 0x35000000); + SDR_WRITE(PESDR0_HSSL4SET1, 0x35000000); + SDR_WRITE(PESDR0_HSSL5SET1, 0x35000000); + SDR_WRITE(PESDR0_HSSL6SET1, 0x35000000); + SDR_WRITE(PESDR0_HSSL7SET1, 0x35000000); + SDR_WRITE(PESDR0_RCSSET, + (SDR_READ(PESDR0_RCSSET) & ~(1 << 24 | 1 << 16)) | 1 << 12); + break; + + case 1: + SDR_WRITE(PESDR1_DLPSET, 1 << 24 | PTYPE_ROOT_PORT << 20 | LNKW_X4 << 12); + SDR_WRITE(PESDR1_UTLSET1, 0x21222222); + if (!ppc440spe_revB()) + SDR_WRITE(PESDR1_UTLSET2, 0x11000000); + SDR_WRITE(PESDR1_HSSL0SET1, 0x35000000); + SDR_WRITE(PESDR1_HSSL1SET1, 0x35000000); + SDR_WRITE(PESDR1_HSSL2SET1, 0x35000000); + SDR_WRITE(PESDR1_HSSL3SET1, 0x35000000); + SDR_WRITE(PESDR1_RCSSET, + (SDR_READ(PESDR1_RCSSET) & ~(1 << 24 | 1 << 16)) | 1 << 12); + break; + + case 2: + SDR_WRITE(PESDR2_DLPSET, 1 << 24 | PTYPE_ROOT_PORT << 20 | LNKW_X4 << 12); + SDR_WRITE(PESDR2_UTLSET1, 0x21222222); + if (!ppc440spe_revB()) + SDR_WRITE(PESDR2_UTLSET2, 0x11000000); + SDR_WRITE(PESDR2_HSSL0SET1, 0x35000000); + SDR_WRITE(PESDR2_HSSL1SET1, 0x35000000); + SDR_WRITE(PESDR2_HSSL2SET1, 0x35000000); + SDR_WRITE(PESDR2_HSSL3SET1, 0x35000000); + SDR_WRITE(PESDR2_RCSSET, + (SDR_READ(PESDR2_RCSSET) & ~(1 << 24 | 1 << 16)) | 1 << 12); + break; + } + /* + * Notice: the following delay has critical impact on device + * initialization - if too short (<50ms) the link doesn't get up. + */ + mdelay(100); + + switch (port) { + case 0: + val = SDR_READ(PESDR0_RCSSTS); + break; + case 1: + val = SDR_READ(PESDR1_RCSSTS); + break; + case 2: + val = SDR_READ(PESDR2_RCSSTS); + break; + } + + if (val & (1 << 20)) { + printf("PCIE%d: PGRST failed %08x\n", port, val); + return -1; + } + + /* + * Verify link is up + */ + val = 0; + switch (port) { + case 0: + val = SDR_READ(PESDR0_LOOP); + break; + case 1: + val = SDR_READ(PESDR1_LOOP); + break; + case 2: + val = SDR_READ(PESDR2_LOOP); + break; + } + if (!(val & 0x00001000)) { + printf("PCIE%d: link is not up.\n", port); + return -1; + } + + /* + * Setup UTL registers - but only on revA! + * We use default settings for revB chip. + */ + if (!ppc440spe_revB()) + ppc440spe_setup_utl(port); + + /* + * We map PCI Express configuration access into the 512MB regions + * + * NOTICE: revB 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. + * + * For revA: + * PCIE0: 0xc_4000_0000 + * PCIE1: 0xc_8000_0000 + * PCIE2: 0xc_c000_0000 + * + * For revB: + * PCIE0: 0xd_0000_0000 + * PCIE1: 0xd_2000_0000 + * PCIE2: 0xd_4000_0000 + */ + + switch (port) { + case 0: + if (ppc440spe_revB()) { + mtdcr(DCRN_PEGPL_CFGBAH(PCIE0), 0x0000000d); + mtdcr(DCRN_PEGPL_CFGBAL(PCIE0), 0x00000000); + } else { + /* revA */ + mtdcr(DCRN_PEGPL_CFGBAH(PCIE0), 0x0000000c); + mtdcr(DCRN_PEGPL_CFGBAL(PCIE0), 0x40000000); + } + mtdcr(DCRN_PEGPL_CFGMSK(PCIE0), 0xe0000001); /* 512MB region, valid */ + break; + + case 1: + if (ppc440spe_revB()) { + mtdcr(DCRN_PEGPL_CFGBAH(PCIE1), 0x0000000d); + mtdcr(DCRN_PEGPL_CFGBAL(PCIE1), 0x20000000); + } else { + mtdcr(DCRN_PEGPL_CFGBAH(PCIE1), 0x0000000c); + mtdcr(DCRN_PEGPL_CFGBAL(PCIE1), 0x80000000); + } + mtdcr(DCRN_PEGPL_CFGMSK(PCIE1), 0xe0000001); /* 512MB region, valid */ + break; + + case 2: + if (ppc440spe_revB()) { + mtdcr(DCRN_PEGPL_CFGBAH(PCIE2), 0x0000000d); + mtdcr(DCRN_PEGPL_CFGBAL(PCIE2), 0x40000000); + } else { + mtdcr(DCRN_PEGPL_CFGBAH(PCIE2), 0x0000000c); + mtdcr(DCRN_PEGPL_CFGBAL(PCIE2), 0xc0000000); + } + mtdcr(DCRN_PEGPL_CFGMSK(PCIE2), 0xe0000001); /* 512MB region, valid */ + break; + } + + /* + * Check for VC0 active and assert RDY. + */ + attempts = 10; + switch (port) { + case 0: + while(!(SDR_READ(PESDR0_RCSSTS) & (1 << 16))) { + if (!(attempts--)) { + printf("PCIE0: VC0 not active\n"); + return -1; + } + mdelay(1000); + } + SDR_WRITE(PESDR0_RCSSET, SDR_READ(PESDR0_RCSSET) | 1 << 20); + break; + case 1: + while(!(SDR_READ(PESDR1_RCSSTS) & (1 << 16))) { + if (!(attempts--)) { + printf("PCIE1: VC0 not active\n"); + return -1; + } + mdelay(1000); + } + + SDR_WRITE(PESDR1_RCSSET, SDR_READ(PESDR1_RCSSET) | 1 << 20); + break; + case 2: + while(!(SDR_READ(PESDR2_RCSSTS) & (1 << 16))) { + if (!(attempts--)) { + printf("PCIE2: VC0 not active\n"); + return -1; + } + mdelay(1000); + } + + SDR_WRITE(PESDR2_RCSSET, SDR_READ(PESDR2_RCSSET) | 1 << 20); + break; + } + mdelay(100); + + return 0; +} + +int ppc440spe_init_pcie_endport(int port) +{ + static int core_init; + volatile u32 val = 0; + int attempts; + + if (!core_init) { + ++core_init; + if (ppc440spe_init_pcie()) + return -1; + } + + /* + * Initialize various parts of the PCI Express core for our port: + * + * - Set as a end port and enable max width + * (PXIE0 -> X8, PCIE1 and PCIE2 -> X4). + * - Set up UTL configuration. + * - Increase SERDES drive strength to levels suggested by AMCC. + * - De-assert RSTPYN, RSTDL and RSTGU. + * + * NOTICE for revB chip: PESDRn_UTLSET2 is not set - we leave it with + * default setting 0x11310000. The register has new fields, + * PESDRn_UTLSET2[LKINE] in particular: clearing it leads to PCIE core + * hang. + */ + switch (port) { + case 0: + SDR_WRITE(PESDR0_DLPSET, 1 << 24 | PTYPE_LEGACY_ENDPOINT << 20 | LNKW_X8 << 12); + + SDR_WRITE(PESDR0_UTLSET1, 0x20222222); + if (!ppc440spe_revB()) + SDR_WRITE(PESDR0_UTLSET2, 0x11000000); + SDR_WRITE(PESDR0_HSSL0SET1, 0x35000000); + SDR_WRITE(PESDR0_HSSL1SET1, 0x35000000); + SDR_WRITE(PESDR0_HSSL2SET1, 0x35000000); + SDR_WRITE(PESDR0_HSSL3SET1, 0x35000000); + SDR_WRITE(PESDR0_HSSL4SET1, 0x35000000); + SDR_WRITE(PESDR0_HSSL5SET1, 0x35000000); + SDR_WRITE(PESDR0_HSSL6SET1, 0x35000000); + SDR_WRITE(PESDR0_HSSL7SET1, 0x35000000); + SDR_WRITE(PESDR0_RCSSET, + (SDR_READ(PESDR0_RCSSET) & ~(1 << 24 | 1 << 16)) | 1 << 12); + break; + + case 1: + SDR_WRITE(PESDR1_DLPSET, 1 << 24 | PTYPE_LEGACY_ENDPOINT << 20 | LNKW_X4 << 12); + SDR_WRITE(PESDR1_UTLSET1, 0x20222222); + if (!ppc440spe_revB()) + SDR_WRITE(PESDR1_UTLSET2, 0x11000000); + SDR_WRITE(PESDR1_HSSL0SET1, 0x35000000); + SDR_WRITE(PESDR1_HSSL1SET1, 0x35000000); + SDR_WRITE(PESDR1_HSSL2SET1, 0x35000000); + SDR_WRITE(PESDR1_HSSL3SET1, 0x35000000); + SDR_WRITE(PESDR1_RCSSET, + (SDR_READ(PESDR1_RCSSET) & ~(1 << 24 | 1 << 16)) | 1 << 12); + break; + + case 2: + SDR_WRITE(PESDR2_DLPSET, 1 << 24 | PTYPE_LEGACY_ENDPOINT << 20 | LNKW_X4 << 12); + SDR_WRITE(PESDR2_UTLSET1, 0x20222222); + if (!ppc440spe_revB()) + SDR_WRITE(PESDR2_UTLSET2, 0x11000000); + SDR_WRITE(PESDR2_HSSL0SET1, 0x35000000); + SDR_WRITE(PESDR2_HSSL1SET1, 0x35000000); + SDR_WRITE(PESDR2_HSSL2SET1, 0x35000000); + SDR_WRITE(PESDR2_HSSL3SET1, 0x35000000); + SDR_WRITE(PESDR2_RCSSET, + (SDR_READ(PESDR2_RCSSET) & ~(1 << 24 | 1 << 16)) | 1 << 12); + break; + } + /* + * Notice: the following delay has critical impact on device + * initialization - if too short (<50ms) the link doesn't get up. + */ + mdelay(100); + + switch (port) { + case 0: val = SDR_READ(PESDR0_RCSSTS); break; + case 1: val = SDR_READ(PESDR1_RCSSTS); break; + case 2: val = SDR_READ(PESDR2_RCSSTS); break; + } + + if (val & (1 << 20)) { + printf("PCIE%d: PGRST failed %08x\n", port, val); + return -1; + } + + /* + * Verify link is up + */ + val = 0; + switch (port) + { + case 0: + val = SDR_READ(PESDR0_LOOP); + break; + case 1: + val = SDR_READ(PESDR1_LOOP); + break; + case 2: + val = SDR_READ(PESDR2_LOOP); + break; + } + if (!(val & 0x00001000)) { + printf("PCIE%d: link is not up.\n", port); + return -1; + } + + /* + * Setup UTL registers - but only on revA! + * We use default settings for revB chip. + */ + if (!ppc440spe_revB()) + ppc440spe_setup_utl(port); + + /* + * We map PCI Express configuration access into the 512MB regions + * + * NOTICE: revB 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. + * + * For revA: + * PCIE0: 0xc_4000_0000 + * PCIE1: 0xc_8000_0000 + * PCIE2: 0xc_c000_0000 + * + * For revB: + * PCIE0: 0xd_0000_0000 + * PCIE1: 0xd_2000_0000 + * PCIE2: 0xd_4000_0000 + */ + switch (port) { + case 0: + if (ppc440spe_revB()) { + mtdcr(DCRN_PEGPL_CFGBAH(PCIE0), 0x0000000d); + mtdcr(DCRN_PEGPL_CFGBAL(PCIE0), 0x00000000); + } else { + /* revA */ + mtdcr(DCRN_PEGPL_CFGBAH(PCIE0), 0x0000000c); + mtdcr(DCRN_PEGPL_CFGBAL(PCIE0), 0x40000000); + } + mtdcr(DCRN_PEGPL_CFGMSK(PCIE0), 0xe0000001); /* 512MB region, valid */ + break; + + case 1: + if (ppc440spe_revB()) { + mtdcr(DCRN_PEGPL_CFGBAH(PCIE1), 0x0000000d); + mtdcr(DCRN_PEGPL_CFGBAL(PCIE1), 0x20000000); + } else { + mtdcr(DCRN_PEGPL_CFGBAH(PCIE1), 0x0000000c); + mtdcr(DCRN_PEGPL_CFGBAL(PCIE1), 0x80000000); + } + mtdcr(DCRN_PEGPL_CFGMSK(PCIE1), 0xe0000001); /* 512MB region, valid */ + break; + + case 2: + if (ppc440spe_revB()) { + mtdcr(DCRN_PEGPL_CFGBAH(PCIE2), 0x0000000d); + mtdcr(DCRN_PEGPL_CFGBAL(PCIE2), 0x40000000); + } else { + mtdcr(DCRN_PEGPL_CFGBAH(PCIE2), 0x0000000c); + mtdcr(DCRN_PEGPL_CFGBAL(PCIE2), 0xc0000000); + } + mtdcr(DCRN_PEGPL_CFGMSK(PCIE2), 0xe0000001); /* 512MB region, valid */ + break; + } + + /* + * Check for VC0 active and assert RDY. + */ + attempts = 10; + switch (port) { + case 0: + while(!(SDR_READ(PESDR0_RCSSTS) & (1 << 16))) { + if (!(attempts--)) { + printf("PCIE0: VC0 not active\n"); + return -1; + } + mdelay(1000); + } + SDR_WRITE(PESDR0_RCSSET, SDR_READ(PESDR0_RCSSET) | 1 << 20); + break; + case 1: + while(!(SDR_READ(PESDR1_RCSSTS) & (1 << 16))) { + if (!(attempts--)) { + printf("PCIE1: VC0 not active\n"); + return -1; + } + mdelay(1000); + } + + SDR_WRITE(PESDR1_RCSSET, SDR_READ(PESDR1_RCSSET) | 1 << 20); + break; + case 2: + while(!(SDR_READ(PESDR2_RCSSTS) & (1 << 16))) { + if (!(attempts--)) { + printf("PCIE2: VC0 not active\n"); + return -1; + } + mdelay(1000); + } + + SDR_WRITE(PESDR2_RCSSET, SDR_READ(PESDR2_RCSSET) | 1 << 20); + break; + } + mdelay(100); + + return 0; +} + +void ppc440spe_setup_pcie_rootpoint(struct pci_controller *hose, int port) +{ + volatile void *mbase = NULL; + volatile void *rmbase = NULL; + + pci_set_ops(hose, + pcie_read_config_byte, + pcie_read_config_word, + pcie_read_config_dword, + pcie_write_config_byte, + pcie_write_config_word, + pcie_write_config_dword); + + switch (port) { + case 0: + mbase = (u32 *)CFG_PCIE0_XCFGBASE; + rmbase = (u32 *)CFG_PCIE0_CFGBASE; + hose->cfg_data = (u8 *)CFG_PCIE0_CFGBASE; + break; + case 1: + mbase = (u32 *)CFG_PCIE1_XCFGBASE; + rmbase = (u32 *)CFG_PCIE1_CFGBASE; + hose->cfg_data = (u8 *)CFG_PCIE1_CFGBASE; + break; + case 2: + mbase = (u32 *)CFG_PCIE2_XCFGBASE; + rmbase = (u32 *)CFG_PCIE2_CFGBASE; + hose->cfg_data = (u8 *)CFG_PCIE2_CFGBASE; + break; + } + + /* + * Set bus numbers on our root port + */ + out_8((u8 *)mbase + PCI_PRIMARY_BUS, 0); + out_8((u8 *)mbase + PCI_SECONDARY_BUS, 1); + out_8((u8 *)mbase + PCI_SUBORDINATE_BUS, 1); + + /* + * Set up outbound translation to hose->mem_space from PLB + * addresses at an offset of 0xd_0000_0000. We set the low + * bits of the mask to 11 to turn off splitting into 8 + * subregions and to enable the outbound translation. + */ + out_le32(mbase + PECFG_POM0LAH, 0x00000000); + out_le32(mbase + PECFG_POM0LAL, 0x00000000); + + switch (port) { + case 0: + mtdcr(DCRN_PEGPL_OMR1BAH(PCIE0), 0x0000000d); + mtdcr(DCRN_PEGPL_OMR1BAL(PCIE0), CFG_PCIE_MEMBASE + + port * CFG_PCIE_MEMSIZE); + mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE0), 0x7fffffff); + mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE0), + ~(CFG_PCIE_MEMSIZE - 1) | 3); + break; + case 1: + mtdcr(DCRN_PEGPL_OMR1BAH(PCIE1), 0x0000000d); + mtdcr(DCRN_PEGPL_OMR1BAL(PCIE1), (CFG_PCIE_MEMBASE + + port * CFG_PCIE_MEMSIZE)); + mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE1), 0x7fffffff); + mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE1), + ~(CFG_PCIE_MEMSIZE - 1) | 3); + break; + case 2: + mtdcr(DCRN_PEGPL_OMR1BAH(PCIE2), 0x0000000d); + mtdcr(DCRN_PEGPL_OMR1BAL(PCIE2), (CFG_PCIE_MEMBASE + + port * CFG_PCIE_MEMSIZE)); + mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE2), 0x7fffffff); + mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE2), + ~(CFG_PCIE_MEMSIZE - 1) | 3); + break; + } + + /* Set up 16GB inbound memory window at 0 */ + out_le32(mbase + PCI_BASE_ADDRESS_0, 0); + out_le32(mbase + PCI_BASE_ADDRESS_1, 0); + out_le32(mbase + PECFG_BAR0HMPA, 0x7fffffc); + out_le32(mbase + PECFG_BAR0LMPA, 0); + + out_le32(mbase + PECFG_PIM01SAH, 0xffff0000); + out_le32(mbase + PECFG_PIM01SAL, 0x00000000); + out_le32(mbase + PECFG_PIM0LAL, 0); + out_le32(mbase + PECFG_PIM0LAH, 0); + out_le32(mbase + PECFG_PIM1LAL, 0x00000000); + out_le32(mbase + PECFG_PIM1LAH, 0x00000004); + out_le32(mbase + PECFG_PIMEN, 0x1); + + /* Enable I/O, Mem, and Busmaster cycles */ + out_le16((u16 *)(mbase + PCI_COMMAND), + in_le16((u16 *)(mbase + PCI_COMMAND)) | + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + printf("PCIE:%d successfully set as rootpoint\n",port); + + /* Set Device and Vendor Id */ + switch (port) { + case 0: + out_le16(mbase + 0x200, 0xaaa0); + out_le16(mbase + 0x202, 0xbed0); + break; + case 1: + out_le16(mbase + 0x200, 0xaaa1); + out_le16(mbase + 0x202, 0xbed1); + break; + case 2: + out_le16(mbase + 0x200, 0xaaa2); + out_le16(mbase + 0x202, 0xbed2); + break; + default: + out_le16(mbase + 0x200, 0xaaa3); + out_le16(mbase + 0x202, 0xbed3); + } + + /* Set Class Code to PCI-PCI bridge and Revision Id to 1 */ + out_le32(mbase + 0x208, 0x06040001); + +} + +int ppc440spe_setup_pcie_endpoint(struct pci_controller *hose, int port) +{ + volatile void *mbase = NULL; + int attempts = 0; + + pci_set_ops(hose, + pcie_read_config_byte, + pcie_read_config_word, + pcie_read_config_dword, + pcie_write_config_byte, + pcie_write_config_word, + pcie_write_config_dword); + + switch (port) { + case 0: + mbase = (u32 *)CFG_PCIE0_XCFGBASE; + hose->cfg_data = (u8 *)CFG_PCIE0_CFGBASE; + break; + case 1: + mbase = (u32 *)CFG_PCIE1_XCFGBASE; + hose->cfg_data = (u8 *)CFG_PCIE1_CFGBASE; + break; + case 2: + mbase = (u32 *)CFG_PCIE2_XCFGBASE; + hose->cfg_data = (u8 *)CFG_PCIE2_CFGBASE; + break; + } + + /* + * Set up outbound translation to hose->mem_space from PLB + * addresses at an offset of 0xd_0000_0000. We set the low + * bits of the mask to 11 to turn off splitting into 8 + * subregions and to enable the outbound translation. + */ + out_le32(mbase + PECFG_POM0LAH, 0x00001ff8); + out_le32(mbase + PECFG_POM0LAL, 0x00001000); + + switch (port) { + case 0: + mtdcr(DCRN_PEGPL_OMR1BAH(PCIE0), 0x0000000d); + mtdcr(DCRN_PEGPL_OMR1BAL(PCIE0), CFG_PCIE_MEMBASE + + port * CFG_PCIE_MEMSIZE); + mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE0), 0x7fffffff); + mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE0), + ~(CFG_PCIE_MEMSIZE - 1) | 3); + break; + case 1: + mtdcr(DCRN_PEGPL_OMR1BAH(PCIE1), 0x0000000d); + mtdcr(DCRN_PEGPL_OMR1BAL(PCIE1), (CFG_PCIE_MEMBASE + + port * CFG_PCIE_MEMSIZE)); + mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE1), 0x7fffffff); + mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE1), + ~(CFG_PCIE_MEMSIZE - 1) | 3); + break; + case 2: + mtdcr(DCRN_PEGPL_OMR1BAH(PCIE2), 0x0000000d); + mtdcr(DCRN_PEGPL_OMR1BAL(PCIE2), (CFG_PCIE_MEMBASE + + port * CFG_PCIE_MEMSIZE)); + mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE2), 0x7fffffff); + mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE2), + ~(CFG_PCIE_MEMSIZE - 1) | 3); + break; + } + + /* Set up 16GB inbound memory window at 0 */ + out_le32(mbase + PCI_BASE_ADDRESS_0, 0); + out_le32(mbase + PCI_BASE_ADDRESS_1, 0); + out_le32(mbase + PECFG_BAR0HMPA, 0x7fffffc); + out_le32(mbase + PECFG_BAR0LMPA, 0); + out_le32(mbase + PECFG_PIM0LAL, 0x00000000); + out_le32(mbase + PECFG_PIM0LAH, 0x00000004); /* pointing to SRAM */ + out_le32(mbase + PECFG_PIMEN, 0x1); + + /* Enable I/O, Mem, and Busmaster cycles */ + out_le16((u16 *)(mbase + PCI_COMMAND), + in_le16((u16 *)(mbase + PCI_COMMAND)) | + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + out_le16(mbase + 0x200,0xcaad); /* Setting vendor ID */ + out_le16(mbase + 0x202,0xfeed); /* Setting device ID */ + attempts = 10; + switch (port) { + case 0: + while (!(SDR_READ(PESDR0_RCSSTS) & (1 << 8))) { + if (!(attempts--)) { + printf("PCIE0: BMEN is not active\n"); + return -1; + } + mdelay(1000); + } + break; + case 1: + while (!(SDR_READ(PESDR1_RCSSTS) & (1 << 8))) { + if (!(attempts--)) { + printf("PCIE1: BMEN is not active\n"); + return -1; + } + mdelay(1000); + } + break; + case 2: + while (!(SDR_READ(PESDR2_RCSSTS) & (1 << 8))) { + if (!(attempts--)) { + printf("PCIE2: BMEN is not active\n"); + return -1; + } + mdelay(1000); + } + break; + } + printf("PCIE:%d successfully set as endpoint\n",port); + + return 0; +} +#endif /* CONFIG_440SPE && CONFIG_PCI */ -- cgit v1.1 From 026f71106871f31d17d0ea0db9a7547ff92934bc Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Wed, 3 Oct 2007 07:48:09 +0200 Subject: ppc4xx: Make 440SPe PCIe code more generic to use on different 4xx PPCs (2) This patch is the first patch of a series to make the 440SPe PCIe code usable on different 4xx PPC platforms. In preperation for the new 405EX which is also equipped with PCIe interfaces. (2) This patch renames the functions from 440spe_ to 4xx_ with a little additional cleanup Signed-off-by: Stefan Roese --- cpu/ppc4xx/4xx_pcie.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'cpu/ppc4xx/4xx_pcie.c') diff --git a/cpu/ppc4xx/4xx_pcie.c b/cpu/ppc4xx/4xx_pcie.c index 8906adc..c7b2141 100644 --- a/cpu/ppc4xx/4xx_pcie.c +++ b/cpu/ppc4xx/4xx_pcie.c @@ -222,7 +222,7 @@ int pcie_write_config_dword(struct pci_controller *hose,pci_dev_t dev,int offset return pcie_write_config(hose,(u32)dev,offset,3,(u32 )val); } -static void ppc440spe_setup_utl(u32 port) { +static void ppc4xx_setup_utl(u32 port) { volatile void *utl_base = NULL; @@ -333,7 +333,7 @@ static int check_error(void) /* * Initialize PCI Express core */ -int ppc440spe_init_pcie(void) +int ppc4xx_init_pcie(void) { int time_out = 20; @@ -401,7 +401,7 @@ int ppc440spe_init_pcie(void) * which is mapped to 0x4 0000 0000. Now on rootpoint yucca u-boot prompt check * data at 0x9000 0000(SRAM).Data should match. */ -int ppc440spe_init_pcie_rootport(int port) +int ppc4xx_init_pcie_rootport(int port) { static int core_init; volatile u32 val = 0; @@ -409,7 +409,7 @@ int ppc440spe_init_pcie_rootport(int port) if (!core_init) { ++core_init; - if (ppc440spe_init_pcie()) + if (ppc4xx_init_pcie()) return -1; } @@ -520,7 +520,7 @@ int ppc440spe_init_pcie_rootport(int port) * We use default settings for revB chip. */ if (!ppc440spe_revB()) - ppc440spe_setup_utl(port); + ppc4xx_setup_utl(port); /* * We map PCI Express configuration access into the 512MB regions @@ -620,7 +620,7 @@ int ppc440spe_init_pcie_rootport(int port) return 0; } -int ppc440spe_init_pcie_endport(int port) +int ppc4xx_init_pcie_endport(int port) { static int core_init; volatile u32 val = 0; @@ -628,7 +628,7 @@ int ppc440spe_init_pcie_endport(int port) if (!core_init) { ++core_init; - if (ppc440spe_init_pcie()) + if (ppc4xx_init_pcie()) return -1; } @@ -734,7 +734,7 @@ int ppc440spe_init_pcie_endport(int port) * We use default settings for revB chip. */ if (!ppc440spe_revB()) - ppc440spe_setup_utl(port); + ppc4xx_setup_utl(port); /* * We map PCI Express configuration access into the 512MB regions @@ -833,7 +833,7 @@ int ppc440spe_init_pcie_endport(int port) return 0; } -void ppc440spe_setup_pcie_rootpoint(struct pci_controller *hose, int port) +void ppc4xx_setup_pcie_rootpoint(struct pci_controller *hose, int port) { volatile void *mbase = NULL; volatile void *rmbase = NULL; @@ -951,7 +951,7 @@ void ppc440spe_setup_pcie_rootpoint(struct pci_controller *hose, int port) } -int ppc440spe_setup_pcie_endpoint(struct pci_controller *hose, int port) +int ppc4xx_setup_pcie_endpoint(struct pci_controller *hose, int port) { volatile void *mbase = NULL; int attempts = 0; -- cgit v1.1 From 03d344bb6a5f082ea10ec9d753558ea7dfd1c626 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Wed, 3 Oct 2007 10:38:09 +0200 Subject: ppc4xx: Make 440SPe PCIe code more generic to use on different 4xx PPCs (3) (3) This patch introduces macros like SDRN_PESDR_DLPSET(port) to access the SDR registers of the PCIe ports. This makes the overall design clearer, since it removed a lot of switch statements which are not needed anymore. Also, the functions ppc4xx_init_pcie_rootport() and ppc4xx_init_pcie_entport() are merged into a single function ppc4xx_init_pcie_port(), since most of the code was duplicated. This makes maintainance and porting to other 4xx platforms easier. Signed-off-by: Stefan Roese --- cpu/ppc4xx/4xx_pcie.c | 642 ++++++++++++++++++-------------------------------- 1 file changed, 223 insertions(+), 419 deletions(-) (limited to 'cpu/ppc4xx/4xx_pcie.c') diff --git a/cpu/ppc4xx/4xx_pcie.c b/cpu/ppc4xx/4xx_pcie.c index c7b2141..2bc9638 100644 --- a/cpu/ppc4xx/4xx_pcie.c +++ b/cpu/ppc4xx/4xx_pcie.c @@ -368,11 +368,167 @@ int ppc4xx_init_pcie(void) } /* - * Yucca board as End point and root point setup + * Board-specific pcie initialization + * Platform code can reimplement ppc4xx_init_pcie_port_hw() if needed + */ + +/* + * Initialize various parts of the PCI Express core for our port: + * + * - Set as a root port and enable max width + * (PXIE0 -> X8, PCIE1 and PCIE2 -> X4). + * - Set up UTL configuration. + * - Increase SERDES drive strength to levels suggested by AMCC. + * - De-assert RSTPYN, RSTDL and RSTGU. + * + * NOTICE for 440SPE revB chip: PESDRn_UTLSET2 is not set - we leave it + * with default setting 0x11310000. The register has new fields, + * PESDRn_UTLSET2[LKINE] in particular: clearing it leads to PCIE core + * hang. + */ +#if defined(CONFIG_440SPE) +int __ppc4xx_init_pcie_port_hw(int port, int rootport) +{ + u32 val = 1 << 24; + u32 utlset1; + + if (rootport) { + val = PTYPE_ROOT_PORT << 20; + utlset1 = 0x21222222; + } else { + val = PTYPE_LEGACY_ENDPOINT << 20; + utlset1 = 0x20222222; + } + + if (port == 0) + val |= LNKW_X8 << 12; + else + val |= LNKW_X4 << 12; + + SDR_WRITE(SDRN_PESDR_DLPSET(port), val); + SDR_WRITE(SDRN_PESDR_UTLSET1(port), utlset1); + if (!ppc440spe_revB()) + SDR_WRITE(SDRN_PESDR_UTLSET2(port), 0x11000000); + SDR_WRITE(SDRN_PESDR_HSSL0SET1(port), 0x35000000); + SDR_WRITE(SDRN_PESDR_HSSL1SET1(port), 0x35000000); + SDR_WRITE(SDRN_PESDR_HSSL2SET1(port), 0x35000000); + SDR_WRITE(SDRN_PESDR_HSSL3SET1(port), 0x35000000); + if (port == 0) { + SDR_WRITE(PESDR0_HSSL4SET1, 0x35000000); + SDR_WRITE(PESDR0_HSSL5SET1, 0x35000000); + SDR_WRITE(PESDR0_HSSL6SET1, 0x35000000); + SDR_WRITE(PESDR0_HSSL7SET1, 0x35000000); + } + SDR_WRITE(SDRN_PESDR_RCSSET(port), (SDR_READ(SDRN_PESDR_RCSSET(port)) & + ~(1 << 24 | 1 << 16)) | 1 << 12); + + return 0; +} +#endif /* CONFIG_440SPE */ + +#if defined(CONFIG_405EX) +int __ppc4xx_init_pcie_port_hw(int port, int rootport) +{ + u32 val; + + if (rootport) + val = 0x00401000; + else + val = 0x00101000; + + SDR_WRITE(SDRN_PESDR_DLPSET(port), val); + SDR_WRITE(SDRN_PESDR_UTLSET1(port), 0x20222222); + SDR_WRITE(SDRN_PESDR_UTLSET2(port), 0x01110000); + SDR_WRITE(SDRN_PESDR_PHYSET1(port), 0x720F0000); + SDR_WRITE(SDRN_PESDR_PHYSET2(port), 0x70600003); + + /* Assert the PE0_PHY reset */ + SDR_WRITE(SDRN_PESDR_RCSSET(port), 0x01010000); + udelay(1000); + + /* deassert the PE0_hotreset */ + SDR_WRITE(SDRN_PESDR_RCSSET(port), 0x01101000); + + /* poll for phy !reset */ + while (!(SDR_READ(SDRN_PESDR_PHYSTA(port)) & 0x00001000)) + ; + + /* deassert the PE0_gpl_utl_reset */ + SDR_WRITE(SDRN_PESDR_RCSSET(port), 0x00101000); + + if (port == 0) + mtdcr(DCRN_PEGPL_CFG(PCIE0), 0x10000000); /* guarded on */ + else + mtdcr(DCRN_PEGPL_CFG(PCIE1), 0x10000000); /* guarded on */ + + return 0; +} +#endif /* CONFIG_405EX */ + +int ppc4xx_init_pcie_port_hw(int port, int rootport) + __attribute__((weak, alias("__ppc4xx_init_pcie_port_hw"))); + +/* + * We map PCI Express configuration access into the 512MB regions + * + * NOTICE: revB 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. + * + * For revA: + * PCIE0: 0xc_4000_0000 + * PCIE1: 0xc_8000_0000 + * PCIE2: 0xc_c000_0000 + * + * For revB: + * PCIE0: 0xd_0000_0000 + * PCIE1: 0xd_2000_0000 + * PCIE2: 0xd_4000_0000 + * + * For 405EX: + * PCIE0: 0xa000_0000 + * PCIE1: 0xc000_0000 + */ +static inline u64 ppc4xx_get_cfgaddr(int port) +{ +#if defined(CONFIG_405EX) + if (port == 0) + return (u64)CFG_PCIE0_CFGBASE; + else + return (u64)CFG_PCIE1_CFGBASE; +#endif +#if defined(CONFIG_440SPE) + if (ppc440spe_revB()) { + switch (port) { + default: /* to satisfy compiler */ + case 0: + return 0x0000000d00000000ULL; + case 1: + return 0x0000000d20000000ULL; + case 2: + return 0x0000000d40000000ULL; + } + } else { + switch (port) { + default: /* to satisfy compiler */ + case 0: + return 0x0000000c40000000ULL; + case 1: + return 0x0000000c80000000ULL; + case 2: + return 0x0000000cc0000000ULL; + } + } +#endif +} + +/* + * 4xx boards as end point and root point setup * and * testing inbound and out bound windows * - * YUCCA board can be plugged into another yucca board or you can get PCI-E + * 4xx boards can be plugged into another 4xx boards or you can get PCI-E * cable which can be used to setup loop back from one port to another port. * Please rememeber that unless there is a endpoint plugged in to root port it * will not initialize. It is the same in case of endpoint , unless there is @@ -386,26 +542,28 @@ int ppc4xx_init_pcie(void) * /proc/bus/pci/devices. Where you can see the configuration registers * of end point device attached to the port. * - * Enpoint cofiguration can be verified by connecting Yucca board to any - * host or another yucca board. Then try to scan the device. In case of + * Enpoint cofiguration can be verified by connecting 4xx board to any + * host or another 4xx board. Then try to scan the device. In case of * linux use "lspci" or appripriate os command. * - * How do I verify the inbound and out bound windows ?(yucca to yucca) + * How do I verify the inbound and out bound windows ? (4xx to 4xx) * in this configuration inbound and outbound windows are setup to access * sram memroy area. SRAM is at 0x4 0000 0000 , on PLB bus. This address * is mapped at 0x90000000. From u-boot prompt write data 0xb000 0000, * This is waere your POM(PLB out bound memory window) mapped. then - * read the data from other yucca board's u-boot prompt at address + * read the data from other 4xx board's u-boot prompt at address * 0x9000 0000(SRAM). Data should match. * In case of inbound , write data to u-boot command prompt at 0xb000 0000 * which is mapped to 0x4 0000 0000. Now on rootpoint yucca u-boot prompt check * data at 0x9000 0000(SRAM).Data should match. */ -int ppc4xx_init_pcie_rootport(int port) +int ppc4xx_init_pcie_port(int port, int rootport) { static int core_init; volatile u32 val = 0; int attempts; + u64 addr; + u32 low, high; if (!core_init) { ++core_init; @@ -414,82 +572,17 @@ int ppc4xx_init_pcie_rootport(int port) } /* - * Initialize various parts of the PCI Express core for our port: - * - * - Set as a root port and enable max width - * (PXIE0 -> X8, PCIE1 and PCIE2 -> X4). - * - Set up UTL configuration. - * - Increase SERDES drive strength to levels suggested by AMCC. - * - De-assert RSTPYN, RSTDL and RSTGU. - * - * NOTICE for revB chip: PESDRn_UTLSET2 is not set - we leave it with - * default setting 0x11310000. The register has new fields, - * PESDRn_UTLSET2[LKINE] in particular: clearing it leads to PCIE core - * hang. + * Initialize various parts of the PCI Express core for our port */ - switch (port) { - case 0: - SDR_WRITE(PESDR0_DLPSET, 1 << 24 | PTYPE_ROOT_PORT << 20 | LNKW_X8 << 12); - - SDR_WRITE(PESDR0_UTLSET1, 0x21222222); - if (!ppc440spe_revB()) - SDR_WRITE(PESDR0_UTLSET2, 0x11000000); - SDR_WRITE(PESDR0_HSSL0SET1, 0x35000000); - SDR_WRITE(PESDR0_HSSL1SET1, 0x35000000); - SDR_WRITE(PESDR0_HSSL2SET1, 0x35000000); - SDR_WRITE(PESDR0_HSSL3SET1, 0x35000000); - SDR_WRITE(PESDR0_HSSL4SET1, 0x35000000); - SDR_WRITE(PESDR0_HSSL5SET1, 0x35000000); - SDR_WRITE(PESDR0_HSSL6SET1, 0x35000000); - SDR_WRITE(PESDR0_HSSL7SET1, 0x35000000); - SDR_WRITE(PESDR0_RCSSET, - (SDR_READ(PESDR0_RCSSET) & ~(1 << 24 | 1 << 16)) | 1 << 12); - break; + ppc4xx_init_pcie_port_hw(port, rootport); - case 1: - SDR_WRITE(PESDR1_DLPSET, 1 << 24 | PTYPE_ROOT_PORT << 20 | LNKW_X4 << 12); - SDR_WRITE(PESDR1_UTLSET1, 0x21222222); - if (!ppc440spe_revB()) - SDR_WRITE(PESDR1_UTLSET2, 0x11000000); - SDR_WRITE(PESDR1_HSSL0SET1, 0x35000000); - SDR_WRITE(PESDR1_HSSL1SET1, 0x35000000); - SDR_WRITE(PESDR1_HSSL2SET1, 0x35000000); - SDR_WRITE(PESDR1_HSSL3SET1, 0x35000000); - SDR_WRITE(PESDR1_RCSSET, - (SDR_READ(PESDR1_RCSSET) & ~(1 << 24 | 1 << 16)) | 1 << 12); - break; - - case 2: - SDR_WRITE(PESDR2_DLPSET, 1 << 24 | PTYPE_ROOT_PORT << 20 | LNKW_X4 << 12); - SDR_WRITE(PESDR2_UTLSET1, 0x21222222); - if (!ppc440spe_revB()) - SDR_WRITE(PESDR2_UTLSET2, 0x11000000); - SDR_WRITE(PESDR2_HSSL0SET1, 0x35000000); - SDR_WRITE(PESDR2_HSSL1SET1, 0x35000000); - SDR_WRITE(PESDR2_HSSL2SET1, 0x35000000); - SDR_WRITE(PESDR2_HSSL3SET1, 0x35000000); - SDR_WRITE(PESDR2_RCSSET, - (SDR_READ(PESDR2_RCSSET) & ~(1 << 24 | 1 << 16)) | 1 << 12); - break; - } /* * Notice: the following delay has critical impact on device * initialization - if too short (<50ms) the link doesn't get up. */ mdelay(100); - switch (port) { - case 0: - val = SDR_READ(PESDR0_RCSSTS); - break; - case 1: - val = SDR_READ(PESDR1_RCSSTS); - break; - case 2: - val = SDR_READ(PESDR2_RCSSTS); - break; - } - + val = SDR_READ(SDRN_PESDR_RCSSTS(sdr_base(port))); if (val & (1 << 20)) { printf("PCIE%d: PGRST failed %08x\n", port, val); return -1; @@ -498,18 +591,7 @@ int ppc4xx_init_pcie_rootport(int port) /* * Verify link is up */ - val = 0; - switch (port) { - case 0: - val = SDR_READ(PESDR0_LOOP); - break; - case 1: - val = SDR_READ(PESDR1_LOOP); - break; - case 2: - val = SDR_READ(PESDR2_LOOP); - break; - } + val = SDR_READ(SDRN_PESDR_LOOP(sdr_base(port))); if (!(val & 0x00001000)) { printf("PCIE%d: link is not up.\n", port); return -1; @@ -524,55 +606,25 @@ int ppc4xx_init_pcie_rootport(int port) /* * We map PCI Express configuration access into the 512MB regions - * - * NOTICE: revB 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. - * - * For revA: - * PCIE0: 0xc_4000_0000 - * PCIE1: 0xc_8000_0000 - * PCIE2: 0xc_c000_0000 - * - * For revB: - * PCIE0: 0xd_0000_0000 - * PCIE1: 0xd_2000_0000 - * PCIE2: 0xd_4000_0000 */ + addr = ppc4xx_get_cfgaddr(port); + low = (u32)(addr & 0x00000000ffffffff); + high = (u32)(addr >> 32); switch (port) { case 0: - if (ppc440spe_revB()) { - mtdcr(DCRN_PEGPL_CFGBAH(PCIE0), 0x0000000d); - mtdcr(DCRN_PEGPL_CFGBAL(PCIE0), 0x00000000); - } else { - /* revA */ - mtdcr(DCRN_PEGPL_CFGBAH(PCIE0), 0x0000000c); - mtdcr(DCRN_PEGPL_CFGBAL(PCIE0), 0x40000000); - } + mtdcr(DCRN_PEGPL_CFGBAH(PCIE0), high); + mtdcr(DCRN_PEGPL_CFGBAL(PCIE0), low); mtdcr(DCRN_PEGPL_CFGMSK(PCIE0), 0xe0000001); /* 512MB region, valid */ break; - case 1: - if (ppc440spe_revB()) { - mtdcr(DCRN_PEGPL_CFGBAH(PCIE1), 0x0000000d); - mtdcr(DCRN_PEGPL_CFGBAL(PCIE1), 0x20000000); - } else { - mtdcr(DCRN_PEGPL_CFGBAH(PCIE1), 0x0000000c); - mtdcr(DCRN_PEGPL_CFGBAL(PCIE1), 0x80000000); - } + mtdcr(DCRN_PEGPL_CFGBAH(PCIE1), high); + mtdcr(DCRN_PEGPL_CFGBAL(PCIE1), low); mtdcr(DCRN_PEGPL_CFGMSK(PCIE1), 0xe0000001); /* 512MB region, valid */ break; - case 2: - if (ppc440spe_revB()) { - mtdcr(DCRN_PEGPL_CFGBAH(PCIE2), 0x0000000d); - mtdcr(DCRN_PEGPL_CFGBAL(PCIE2), 0x40000000); - } else { - mtdcr(DCRN_PEGPL_CFGBAH(PCIE2), 0x0000000c); - mtdcr(DCRN_PEGPL_CFGBAL(PCIE2), 0xc0000000); - } + mtdcr(DCRN_PEGPL_CFGBAH(PCIE2), high); + mtdcr(DCRN_PEGPL_CFGBAL(PCIE2), low); mtdcr(DCRN_PEGPL_CFGMSK(PCIE2), 0xe0000001); /* 512MB region, valid */ break; } @@ -581,256 +633,28 @@ int ppc4xx_init_pcie_rootport(int port) * Check for VC0 active and assert RDY. */ attempts = 10; - switch (port) { - case 0: - while(!(SDR_READ(PESDR0_RCSSTS) & (1 << 16))) { - if (!(attempts--)) { - printf("PCIE0: VC0 not active\n"); - return -1; - } - mdelay(1000); - } - SDR_WRITE(PESDR0_RCSSET, SDR_READ(PESDR0_RCSSET) | 1 << 20); - break; - case 1: - while(!(SDR_READ(PESDR1_RCSSTS) & (1 << 16))) { - if (!(attempts--)) { - printf("PCIE1: VC0 not active\n"); - return -1; - } - mdelay(1000); - } - - SDR_WRITE(PESDR1_RCSSET, SDR_READ(PESDR1_RCSSET) | 1 << 20); - break; - case 2: - while(!(SDR_READ(PESDR2_RCSSTS) & (1 << 16))) { - if (!(attempts--)) { - printf("PCIE2: VC0 not active\n"); - return -1; - } - mdelay(1000); + while(!(SDR_READ(SDRN_PESDR_RCSSTS(sdr_base(port))) & (1 << 16))) { + if (!(attempts--)) { + printf("PCIE%d: VC0 not active\n", port); + return -1; } - - SDR_WRITE(PESDR2_RCSSET, SDR_READ(PESDR2_RCSSET) | 1 << 20); - break; + mdelay(1000); } + SDR_WRITE(SDRN_PESDR_RCSSET(sdr_base(port)), + SDR_READ(SDRN_PESDR_RCSSET(sdr_base(port))) | 1 << 20); mdelay(100); return 0; } -int ppc4xx_init_pcie_endport(int port) +int ppc4xx_init_pcie_rootport(int port) { - static int core_init; - volatile u32 val = 0; - int attempts; - - if (!core_init) { - ++core_init; - if (ppc4xx_init_pcie()) - return -1; - } - - /* - * Initialize various parts of the PCI Express core for our port: - * - * - Set as a end port and enable max width - * (PXIE0 -> X8, PCIE1 and PCIE2 -> X4). - * - Set up UTL configuration. - * - Increase SERDES drive strength to levels suggested by AMCC. - * - De-assert RSTPYN, RSTDL and RSTGU. - * - * NOTICE for revB chip: PESDRn_UTLSET2 is not set - we leave it with - * default setting 0x11310000. The register has new fields, - * PESDRn_UTLSET2[LKINE] in particular: clearing it leads to PCIE core - * hang. - */ - switch (port) { - case 0: - SDR_WRITE(PESDR0_DLPSET, 1 << 24 | PTYPE_LEGACY_ENDPOINT << 20 | LNKW_X8 << 12); - - SDR_WRITE(PESDR0_UTLSET1, 0x20222222); - if (!ppc440spe_revB()) - SDR_WRITE(PESDR0_UTLSET2, 0x11000000); - SDR_WRITE(PESDR0_HSSL0SET1, 0x35000000); - SDR_WRITE(PESDR0_HSSL1SET1, 0x35000000); - SDR_WRITE(PESDR0_HSSL2SET1, 0x35000000); - SDR_WRITE(PESDR0_HSSL3SET1, 0x35000000); - SDR_WRITE(PESDR0_HSSL4SET1, 0x35000000); - SDR_WRITE(PESDR0_HSSL5SET1, 0x35000000); - SDR_WRITE(PESDR0_HSSL6SET1, 0x35000000); - SDR_WRITE(PESDR0_HSSL7SET1, 0x35000000); - SDR_WRITE(PESDR0_RCSSET, - (SDR_READ(PESDR0_RCSSET) & ~(1 << 24 | 1 << 16)) | 1 << 12); - break; - - case 1: - SDR_WRITE(PESDR1_DLPSET, 1 << 24 | PTYPE_LEGACY_ENDPOINT << 20 | LNKW_X4 << 12); - SDR_WRITE(PESDR1_UTLSET1, 0x20222222); - if (!ppc440spe_revB()) - SDR_WRITE(PESDR1_UTLSET2, 0x11000000); - SDR_WRITE(PESDR1_HSSL0SET1, 0x35000000); - SDR_WRITE(PESDR1_HSSL1SET1, 0x35000000); - SDR_WRITE(PESDR1_HSSL2SET1, 0x35000000); - SDR_WRITE(PESDR1_HSSL3SET1, 0x35000000); - SDR_WRITE(PESDR1_RCSSET, - (SDR_READ(PESDR1_RCSSET) & ~(1 << 24 | 1 << 16)) | 1 << 12); - break; - - case 2: - SDR_WRITE(PESDR2_DLPSET, 1 << 24 | PTYPE_LEGACY_ENDPOINT << 20 | LNKW_X4 << 12); - SDR_WRITE(PESDR2_UTLSET1, 0x20222222); - if (!ppc440spe_revB()) - SDR_WRITE(PESDR2_UTLSET2, 0x11000000); - SDR_WRITE(PESDR2_HSSL0SET1, 0x35000000); - SDR_WRITE(PESDR2_HSSL1SET1, 0x35000000); - SDR_WRITE(PESDR2_HSSL2SET1, 0x35000000); - SDR_WRITE(PESDR2_HSSL3SET1, 0x35000000); - SDR_WRITE(PESDR2_RCSSET, - (SDR_READ(PESDR2_RCSSET) & ~(1 << 24 | 1 << 16)) | 1 << 12); - break; - } - /* - * Notice: the following delay has critical impact on device - * initialization - if too short (<50ms) the link doesn't get up. - */ - mdelay(100); - - switch (port) { - case 0: val = SDR_READ(PESDR0_RCSSTS); break; - case 1: val = SDR_READ(PESDR1_RCSSTS); break; - case 2: val = SDR_READ(PESDR2_RCSSTS); break; - } - - if (val & (1 << 20)) { - printf("PCIE%d: PGRST failed %08x\n", port, val); - return -1; - } - - /* - * Verify link is up - */ - val = 0; - switch (port) - { - case 0: - val = SDR_READ(PESDR0_LOOP); - break; - case 1: - val = SDR_READ(PESDR1_LOOP); - break; - case 2: - val = SDR_READ(PESDR2_LOOP); - break; - } - if (!(val & 0x00001000)) { - printf("PCIE%d: link is not up.\n", port); - return -1; - } - - /* - * Setup UTL registers - but only on revA! - * We use default settings for revB chip. - */ - if (!ppc440spe_revB()) - ppc4xx_setup_utl(port); - - /* - * We map PCI Express configuration access into the 512MB regions - * - * NOTICE: revB 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. - * - * For revA: - * PCIE0: 0xc_4000_0000 - * PCIE1: 0xc_8000_0000 - * PCIE2: 0xc_c000_0000 - * - * For revB: - * PCIE0: 0xd_0000_0000 - * PCIE1: 0xd_2000_0000 - * PCIE2: 0xd_4000_0000 - */ - switch (port) { - case 0: - if (ppc440spe_revB()) { - mtdcr(DCRN_PEGPL_CFGBAH(PCIE0), 0x0000000d); - mtdcr(DCRN_PEGPL_CFGBAL(PCIE0), 0x00000000); - } else { - /* revA */ - mtdcr(DCRN_PEGPL_CFGBAH(PCIE0), 0x0000000c); - mtdcr(DCRN_PEGPL_CFGBAL(PCIE0), 0x40000000); - } - mtdcr(DCRN_PEGPL_CFGMSK(PCIE0), 0xe0000001); /* 512MB region, valid */ - break; - - case 1: - if (ppc440spe_revB()) { - mtdcr(DCRN_PEGPL_CFGBAH(PCIE1), 0x0000000d); - mtdcr(DCRN_PEGPL_CFGBAL(PCIE1), 0x20000000); - } else { - mtdcr(DCRN_PEGPL_CFGBAH(PCIE1), 0x0000000c); - mtdcr(DCRN_PEGPL_CFGBAL(PCIE1), 0x80000000); - } - mtdcr(DCRN_PEGPL_CFGMSK(PCIE1), 0xe0000001); /* 512MB region, valid */ - break; - - case 2: - if (ppc440spe_revB()) { - mtdcr(DCRN_PEGPL_CFGBAH(PCIE2), 0x0000000d); - mtdcr(DCRN_PEGPL_CFGBAL(PCIE2), 0x40000000); - } else { - mtdcr(DCRN_PEGPL_CFGBAH(PCIE2), 0x0000000c); - mtdcr(DCRN_PEGPL_CFGBAL(PCIE2), 0xc0000000); - } - mtdcr(DCRN_PEGPL_CFGMSK(PCIE2), 0xe0000001); /* 512MB region, valid */ - break; - } - - /* - * Check for VC0 active and assert RDY. - */ - attempts = 10; - switch (port) { - case 0: - while(!(SDR_READ(PESDR0_RCSSTS) & (1 << 16))) { - if (!(attempts--)) { - printf("PCIE0: VC0 not active\n"); - return -1; - } - mdelay(1000); - } - SDR_WRITE(PESDR0_RCSSET, SDR_READ(PESDR0_RCSSET) | 1 << 20); - break; - case 1: - while(!(SDR_READ(PESDR1_RCSSTS) & (1 << 16))) { - if (!(attempts--)) { - printf("PCIE1: VC0 not active\n"); - return -1; - } - mdelay(1000); - } - - SDR_WRITE(PESDR1_RCSSET, SDR_READ(PESDR1_RCSSET) | 1 << 20); - break; - case 2: - while(!(SDR_READ(PESDR2_RCSSTS) & (1 << 16))) { - if (!(attempts--)) { - printf("PCIE2: VC0 not active\n"); - return -1; - } - mdelay(1000); - } - - SDR_WRITE(PESDR2_RCSSET, SDR_READ(PESDR2_RCSSET) | 1 << 20); - break; - } - mdelay(100); + return ppc4xx_init_pcie_port(port, 1); +} - return 0; +int ppc4xx_init_pcie_endport(int port) +{ + return ppc4xx_init_pcie_port(port, 0); } void ppc4xx_setup_pcie_rootpoint(struct pci_controller *hose, int port) @@ -839,12 +663,12 @@ void ppc4xx_setup_pcie_rootpoint(struct pci_controller *hose, int port) volatile void *rmbase = NULL; pci_set_ops(hose, - pcie_read_config_byte, - pcie_read_config_word, - pcie_read_config_dword, - pcie_write_config_byte, - pcie_write_config_word, - pcie_write_config_dword); + pcie_read_config_byte, + pcie_read_config_word, + pcie_read_config_dword, + pcie_write_config_byte, + pcie_write_config_word, + pcie_write_config_dword); switch (port) { case 0: @@ -884,26 +708,26 @@ void ppc4xx_setup_pcie_rootpoint(struct pci_controller *hose, int port) case 0: mtdcr(DCRN_PEGPL_OMR1BAH(PCIE0), 0x0000000d); mtdcr(DCRN_PEGPL_OMR1BAL(PCIE0), CFG_PCIE_MEMBASE + - port * CFG_PCIE_MEMSIZE); + port * CFG_PCIE_MEMSIZE); mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE0), 0x7fffffff); mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE0), - ~(CFG_PCIE_MEMSIZE - 1) | 3); + ~(CFG_PCIE_MEMSIZE - 1) | 3); break; case 1: mtdcr(DCRN_PEGPL_OMR1BAH(PCIE1), 0x0000000d); - mtdcr(DCRN_PEGPL_OMR1BAL(PCIE1), (CFG_PCIE_MEMBASE + - port * CFG_PCIE_MEMSIZE)); + mtdcr(DCRN_PEGPL_OMR1BAL(PCIE1), CFG_PCIE_MEMBASE + + port * CFG_PCIE_MEMSIZE); mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE1), 0x7fffffff); mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE1), - ~(CFG_PCIE_MEMSIZE - 1) | 3); + ~(CFG_PCIE_MEMSIZE - 1) | 3); break; case 2: mtdcr(DCRN_PEGPL_OMR1BAH(PCIE2), 0x0000000d); - mtdcr(DCRN_PEGPL_OMR1BAL(PCIE2), (CFG_PCIE_MEMBASE + - port * CFG_PCIE_MEMSIZE)); + mtdcr(DCRN_PEGPL_OMR1BAL(PCIE2), CFG_PCIE_MEMBASE + + port * CFG_PCIE_MEMSIZE); mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE2), 0x7fffffff); mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE2), - ~(CFG_PCIE_MEMSIZE - 1) | 3); + ~(CFG_PCIE_MEMSIZE - 1) | 3); break; } @@ -925,7 +749,6 @@ void ppc4xx_setup_pcie_rootpoint(struct pci_controller *hose, int port) out_le16((u16 *)(mbase + PCI_COMMAND), in_le16((u16 *)(mbase + PCI_COMMAND)) | PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); - printf("PCIE:%d successfully set as rootpoint\n",port); /* Set Device and Vendor Id */ switch (port) { @@ -949,6 +772,7 @@ void ppc4xx_setup_pcie_rootpoint(struct pci_controller *hose, int port) /* Set Class Code to PCI-PCI bridge and Revision Id to 1 */ out_le32(mbase + 0x208, 0x06040001); + printf("PCIE:%d successfully set as rootpoint\n", port); } int ppc4xx_setup_pcie_endpoint(struct pci_controller *hose, int port) @@ -992,26 +816,26 @@ int ppc4xx_setup_pcie_endpoint(struct pci_controller *hose, int port) case 0: mtdcr(DCRN_PEGPL_OMR1BAH(PCIE0), 0x0000000d); mtdcr(DCRN_PEGPL_OMR1BAL(PCIE0), CFG_PCIE_MEMBASE + - port * CFG_PCIE_MEMSIZE); + port * CFG_PCIE_MEMSIZE); mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE0), 0x7fffffff); mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE0), - ~(CFG_PCIE_MEMSIZE - 1) | 3); + ~(CFG_PCIE_MEMSIZE - 1) | 3); break; case 1: mtdcr(DCRN_PEGPL_OMR1BAH(PCIE1), 0x0000000d); - mtdcr(DCRN_PEGPL_OMR1BAL(PCIE1), (CFG_PCIE_MEMBASE + - port * CFG_PCIE_MEMSIZE)); + mtdcr(DCRN_PEGPL_OMR1BAL(PCIE1), CFG_PCIE_MEMBASE + + port * CFG_PCIE_MEMSIZE); mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE1), 0x7fffffff); mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE1), - ~(CFG_PCIE_MEMSIZE - 1) | 3); + ~(CFG_PCIE_MEMSIZE - 1) | 3); break; case 2: mtdcr(DCRN_PEGPL_OMR1BAH(PCIE2), 0x0000000d); - mtdcr(DCRN_PEGPL_OMR1BAL(PCIE2), (CFG_PCIE_MEMBASE + - port * CFG_PCIE_MEMSIZE)); + mtdcr(DCRN_PEGPL_OMR1BAL(PCIE2), CFG_PCIE_MEMBASE + + port * CFG_PCIE_MEMSIZE); mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE2), 0x7fffffff); mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE2), - ~(CFG_PCIE_MEMSIZE - 1) | 3); + ~(CFG_PCIE_MEMSIZE - 1) | 3); break; } @@ -1026,40 +850,20 @@ int ppc4xx_setup_pcie_endpoint(struct pci_controller *hose, int port) /* Enable I/O, Mem, and Busmaster cycles */ out_le16((u16 *)(mbase + PCI_COMMAND), - in_le16((u16 *)(mbase + PCI_COMMAND)) | - PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + in_le16((u16 *)(mbase + PCI_COMMAND)) | + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); out_le16(mbase + 0x200,0xcaad); /* Setting vendor ID */ out_le16(mbase + 0x202,0xfeed); /* Setting device ID */ + attempts = 10; - switch (port) { - case 0: - while (!(SDR_READ(PESDR0_RCSSTS) & (1 << 8))) { - if (!(attempts--)) { - printf("PCIE0: BMEN is not active\n"); - return -1; - } - mdelay(1000); - } - break; - case 1: - while (!(SDR_READ(PESDR1_RCSSTS) & (1 << 8))) { - if (!(attempts--)) { - printf("PCIE1: BMEN is not active\n"); - return -1; - } - mdelay(1000); - } - break; - case 2: - while (!(SDR_READ(PESDR2_RCSSTS) & (1 << 8))) { - if (!(attempts--)) { - printf("PCIE2: BMEN is not active\n"); - return -1; - } - mdelay(1000); + while(!(SDR_READ(SDRN_PESDR_RCSSTS(sdr_base(port))) & (1 << 8))) { + if (!(attempts--)) { + printf("PCIE%d: BME not active\n", port); + return -1; } - break; + mdelay(1000); } + printf("PCIE:%d successfully set as endpoint\n",port); return 0; -- cgit v1.1 From 94276eb0a7a35b9e8c053d589ae225b0f017a237 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Wed, 3 Oct 2007 14:14:58 +0200 Subject: ppc4xx: Add a comment for 405EX PCIe endpoint configuration Signed-off-by: Stefan Roese --- cpu/ppc4xx/4xx_pcie.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'cpu/ppc4xx/4xx_pcie.c') diff --git a/cpu/ppc4xx/4xx_pcie.c b/cpu/ppc4xx/4xx_pcie.c index 2bc9638..177e2ad 100644 --- a/cpu/ppc4xx/4xx_pcie.c +++ b/cpu/ppc4xx/4xx_pcie.c @@ -431,6 +431,12 @@ int __ppc4xx_init_pcie_port_hw(int port, int rootport) { u32 val; + /* + * test-only: + * This needs some testing and perhaps changes for + * endpoint configuration. Probably no PHY reset at all, etc. + * sr, 2007-10-03 + */ if (rootport) val = 0x00401000; else -- cgit v1.1 From 6d95289281ed2958ebf76d2b55f86bbd88591fd2 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Wed, 3 Oct 2007 21:16:32 +0200 Subject: ppc4xx: 4xx_pcie: Fix problem with SDRN access using port number as idx Signed-off-by: Stefan Roese --- cpu/ppc4xx/4xx_pcie.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'cpu/ppc4xx/4xx_pcie.c') diff --git a/cpu/ppc4xx/4xx_pcie.c b/cpu/ppc4xx/4xx_pcie.c index 177e2ad..2b3e657 100644 --- a/cpu/ppc4xx/4xx_pcie.c +++ b/cpu/ppc4xx/4xx_pcie.c @@ -588,7 +588,7 @@ int ppc4xx_init_pcie_port(int port, int rootport) */ mdelay(100); - val = SDR_READ(SDRN_PESDR_RCSSTS(sdr_base(port))); + val = SDR_READ(SDRN_PESDR_RCSSTS(port)); if (val & (1 << 20)) { printf("PCIE%d: PGRST failed %08x\n", port, val); return -1; @@ -597,7 +597,7 @@ int ppc4xx_init_pcie_port(int port, int rootport) /* * Verify link is up */ - val = SDR_READ(SDRN_PESDR_LOOP(sdr_base(port))); + val = SDR_READ(SDRN_PESDR_LOOP(port)); if (!(val & 0x00001000)) { printf("PCIE%d: link is not up.\n", port); return -1; @@ -639,15 +639,15 @@ int ppc4xx_init_pcie_port(int port, int rootport) * Check for VC0 active and assert RDY. */ attempts = 10; - while(!(SDR_READ(SDRN_PESDR_RCSSTS(sdr_base(port))) & (1 << 16))) { + while(!(SDR_READ(SDRN_PESDR_RCSSTS(port)) & (1 << 16))) { if (!(attempts--)) { printf("PCIE%d: VC0 not active\n", port); return -1; } mdelay(1000); } - SDR_WRITE(SDRN_PESDR_RCSSET(sdr_base(port)), - SDR_READ(SDRN_PESDR_RCSSET(sdr_base(port))) | 1 << 20); + SDR_WRITE(SDRN_PESDR_RCSSET(port), + SDR_READ(SDRN_PESDR_RCSSET(port)) | 1 << 20); mdelay(100); return 0; @@ -862,7 +862,7 @@ int ppc4xx_setup_pcie_endpoint(struct pci_controller *hose, int port) out_le16(mbase + 0x202,0xfeed); /* Setting device ID */ attempts = 10; - while(!(SDR_READ(SDRN_PESDR_RCSSTS(sdr_base(port))) & (1 << 8))) { + while(!(SDR_READ(SDRN_PESDR_RCSSTS(port)) & (1 << 8))) { if (!(attempts--)) { printf("PCIE%d: BME not active\n", port); return -1; -- cgit v1.1 From 4dbee8a90df613eb517aadbecebd70f168913d30 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Fri, 5 Oct 2007 07:57:20 +0200 Subject: ppc4xx: 4xx_pcie: Change CFG_PCIE_MEMSIZE to 128MB on Yucca & Katmai 128MB seems to be the smallest possible value for the memory size for on PCIe port. With this change now the BAR's of the PCIe cards are accessible under U-Boot. One big note: This only works for PCIe port 0 & 1. For port 2 this currently doesn't work, since the base address is now 0xc0000000 (0xb0000000 + 2 * 0x08000000), and this is already occupied by CFG_PCIE0_CFGBASE. But solving this issue for port 2 would mean to change the base addresses completely and this change would have too much impact right now. This patch adds debug output to the 4xx pcie driver too. Signed-off-by: Stefan Roese --- cpu/ppc4xx/4xx_pcie.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'cpu/ppc4xx/4xx_pcie.c') diff --git a/cpu/ppc4xx/4xx_pcie.c b/cpu/ppc4xx/4xx_pcie.c index 2b3e657..7ac8ce0 100644 --- a/cpu/ppc4xx/4xx_pcie.c +++ b/cpu/ppc4xx/4xx_pcie.c @@ -20,6 +20,11 @@ * */ +/* define DEBUG for debugging output (obviously ;-)) */ +#if 1 +#define DEBUG +#endif + #include #include #include @@ -708,7 +713,10 @@ void ppc4xx_setup_pcie_rootpoint(struct pci_controller *hose, int port) * subregions and to enable the outbound translation. */ out_le32(mbase + PECFG_POM0LAH, 0x00000000); - out_le32(mbase + PECFG_POM0LAL, 0x00000000); + out_le32(mbase + PECFG_POM0LAL, CFG_PCIE_MEMBASE + + port * CFG_PCIE_MEMSIZE); + debug("PECFG_POM0LA=%08x.%08x\n", in_le32(mbase + PECFG_POM0LAH), + in_le32(mbase + PECFG_POM0LAL)); switch (port) { case 0: @@ -718,6 +726,11 @@ void ppc4xx_setup_pcie_rootpoint(struct pci_controller *hose, int port) mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE0), 0x7fffffff); mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE0), ~(CFG_PCIE_MEMSIZE - 1) | 3); + debug("0:PEGPL_OMR1BA=%08x.%08x MSK=%08x.%08x\n", + mfdcr(DCRN_PEGPL_OMR1BAH(PCIE0)), + mfdcr(DCRN_PEGPL_OMR1BAL(PCIE0)), + mfdcr(DCRN_PEGPL_OMR1MSKH(PCIE0)), + mfdcr(DCRN_PEGPL_OMR1MSKL(PCIE0))); break; case 1: mtdcr(DCRN_PEGPL_OMR1BAH(PCIE1), 0x0000000d); @@ -726,6 +739,11 @@ void ppc4xx_setup_pcie_rootpoint(struct pci_controller *hose, int port) mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE1), 0x7fffffff); mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE1), ~(CFG_PCIE_MEMSIZE - 1) | 3); + debug("1:PEGPL_OMR1BA=%08x.%08x MSK=%08x.%08x\n", + mfdcr(DCRN_PEGPL_OMR1BAH(PCIE1)), + mfdcr(DCRN_PEGPL_OMR1BAL(PCIE1)), + mfdcr(DCRN_PEGPL_OMR1MSKH(PCIE1)), + mfdcr(DCRN_PEGPL_OMR1MSKL(PCIE1))); break; case 2: mtdcr(DCRN_PEGPL_OMR1BAH(PCIE2), 0x0000000d); @@ -734,6 +752,11 @@ void ppc4xx_setup_pcie_rootpoint(struct pci_controller *hose, int port) mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE2), 0x7fffffff); mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE2), ~(CFG_PCIE_MEMSIZE - 1) | 3); + debug("2:PEGPL_OMR1BA=%08x.%08x MSK=%08x.%08x\n", + mfdcr(DCRN_PEGPL_OMR1BAH(PCIE2)), + mfdcr(DCRN_PEGPL_OMR1BAL(PCIE2)), + mfdcr(DCRN_PEGPL_OMR1MSKH(PCIE2)), + mfdcr(DCRN_PEGPL_OMR1MSKL(PCIE2))); break; } -- cgit v1.1 From 97923770cb52b64d69eec958a11b2eda8d46e0f7 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Fri, 5 Oct 2007 09:18:23 +0200 Subject: ppc4xx: 4xx_pcie: More general cleanup and 405EX PCIe support added Signed-off-by: Stefan Roese --- cpu/ppc4xx/4xx_pcie.c | 93 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 54 insertions(+), 39 deletions(-) (limited to 'cpu/ppc4xx/4xx_pcie.c') diff --git a/cpu/ppc4xx/4xx_pcie.c b/cpu/ppc4xx/4xx_pcie.c index 7ac8ce0..d1ba890 100644 --- a/cpu/ppc4xx/4xx_pcie.c +++ b/cpu/ppc4xx/4xx_pcie.c @@ -31,7 +31,8 @@ #include #include -#if defined(CONFIG_440SPE) && defined(CONFIG_PCI) +#if (defined(CONFIG_440SPE) || defined(CONFIG_405EX)) && \ + defined(CONFIG_PCI) #include @@ -55,8 +56,10 @@ static u8* pcie_get_base(struct pci_controller *hose, unsigned int devfn) base = (u8*)CFG_PCIE0_XCFGBASE; if (hose->cfg_data == (u8*)CFG_PCIE1_CFGBASE) base = (u8*)CFG_PCIE1_XCFGBASE; +#if CFG_PCIE_NR_PORTS > 2 if (hose->cfg_data == (u8*)CFG_PCIE2_CFGBASE) base = (u8*)CFG_PCIE2_XCFGBASE; +#endif } return base; @@ -68,8 +71,10 @@ static void pcie_dmer_disable(void) mfdcr (DCRN_PEGPL_CFG(DCRN_PCIE0_BASE)) | GPL_DMER_MASK_DISA); mtdcr (DCRN_PEGPL_CFG(DCRN_PCIE1_BASE), mfdcr (DCRN_PEGPL_CFG(DCRN_PCIE1_BASE)) | GPL_DMER_MASK_DISA); +#if CFG_PCIE_NR_PORTS > 2 mtdcr (DCRN_PEGPL_CFG(DCRN_PCIE2_BASE), mfdcr (DCRN_PEGPL_CFG(DCRN_PCIE2_BASE)) | GPL_DMER_MASK_DISA); +#endif } static void pcie_dmer_enable(void) @@ -78,8 +83,10 @@ static void pcie_dmer_enable(void) mfdcr (DCRN_PEGPL_CFG(DCRN_PCIE0_BASE)) & ~GPL_DMER_MASK_DISA); mtdcr (DCRN_PEGPL_CFG (DCRN_PCIE1_BASE), mfdcr (DCRN_PEGPL_CFG(DCRN_PCIE1_BASE)) & ~GPL_DMER_MASK_DISA); +#if CFG_PCIE_NR_PORTS > 2 mtdcr (DCRN_PEGPL_CFG (DCRN_PCIE2_BASE), mfdcr (DCRN_PEGPL_CFG(DCRN_PCIE2_BASE)) & ~GPL_DMER_MASK_DISA); +#endif } static int pcie_read_config(struct pci_controller *hose, unsigned int devfn, @@ -120,6 +127,7 @@ static int pcie_read_config(struct pci_controller *hose, unsigned int devfn, */ pcie_dmer_disable (); + debug("%s: cfg_data=%08x offset=%08x\n", __func__, hose->cfg_data, offset); switch (len) { case 1: *val = in_8(hose->cfg_data + offset); @@ -227,6 +235,7 @@ int pcie_write_config_dword(struct pci_controller *hose,pci_dev_t dev,int offset return pcie_write_config(hose,(u32)dev,offset,3,(u32 )val); } +#if defined(CONFIG_440SPE) static void ppc4xx_setup_utl(u32 port) { volatile void *utl_base = NULL; @@ -371,6 +380,15 @@ int ppc4xx_init_pcie(void) } return 0; } +#else +int ppc4xx_init_pcie(void) +{ + /* + * Nothing to do on 405EX + */ + return 0; +} +#endif /* * Board-specific pcie initialization @@ -608,19 +626,21 @@ int ppc4xx_init_pcie_port(int port, int rootport) return -1; } +#if defined(CONFIG_440SPE) /* * Setup UTL registers - but only on revA! * We use default settings for revB chip. */ if (!ppc440spe_revB()) ppc4xx_setup_utl(port); +#endif /* * We map PCI Express configuration access into the 512MB regions */ addr = ppc4xx_get_cfgaddr(port); - low = (u32)(addr & 0x00000000ffffffff); - high = (u32)(addr >> 32); + low = U64_TO_U32_LOW(addr); + high = U64_TO_U32_HIGH(addr); switch (port) { case 0: @@ -633,11 +653,13 @@ int ppc4xx_init_pcie_port(int port, int rootport) mtdcr(DCRN_PEGPL_CFGBAL(PCIE1), low); mtdcr(DCRN_PEGPL_CFGMSK(PCIE1), 0xe0000001); /* 512MB region, valid */ break; +#if CFG_PCIE_NR_PORTS > 2 case 2: mtdcr(DCRN_PEGPL_CFGBAH(PCIE2), high); mtdcr(DCRN_PEGPL_CFGBAL(PCIE2), low); mtdcr(DCRN_PEGPL_CFGMSK(PCIE2), 0xe0000001); /* 512MB region, valid */ break; +#endif } /* @@ -692,11 +714,13 @@ void ppc4xx_setup_pcie_rootpoint(struct pci_controller *hose, int port) rmbase = (u32 *)CFG_PCIE1_CFGBASE; hose->cfg_data = (u8 *)CFG_PCIE1_CFGBASE; break; +#if CFG_PCIE_NR_PORTS > 2 case 2: mbase = (u32 *)CFG_PCIE2_XCFGBASE; rmbase = (u32 *)CFG_PCIE2_CFGBASE; hose->cfg_data = (u8 *)CFG_PCIE2_CFGBASE; break; +#endif } /* @@ -720,8 +744,8 @@ void ppc4xx_setup_pcie_rootpoint(struct pci_controller *hose, int port) switch (port) { case 0: - mtdcr(DCRN_PEGPL_OMR1BAH(PCIE0), 0x0000000d); - mtdcr(DCRN_PEGPL_OMR1BAL(PCIE0), CFG_PCIE_MEMBASE + + mtdcr(DCRN_PEGPL_OMR1BAH(PCIE0), CFG_PCIE_ADDR_HIGH); + mtdcr(DCRN_PEGPL_OMR1BAL(PCIE0), CFG_PCIE_MEMBASE + port * CFG_PCIE_MEMSIZE); mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE0), 0x7fffffff); mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE0), @@ -733,8 +757,8 @@ void ppc4xx_setup_pcie_rootpoint(struct pci_controller *hose, int port) mfdcr(DCRN_PEGPL_OMR1MSKL(PCIE0))); break; case 1: - mtdcr(DCRN_PEGPL_OMR1BAH(PCIE1), 0x0000000d); - mtdcr(DCRN_PEGPL_OMR1BAL(PCIE1), CFG_PCIE_MEMBASE + + mtdcr(DCRN_PEGPL_OMR1BAH(PCIE1), CFG_PCIE_ADDR_HIGH); + mtdcr(DCRN_PEGPL_OMR1BAL(PCIE1), CFG_PCIE_MEMBASE + port * CFG_PCIE_MEMSIZE); mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE1), 0x7fffffff); mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE1), @@ -745,9 +769,10 @@ void ppc4xx_setup_pcie_rootpoint(struct pci_controller *hose, int port) mfdcr(DCRN_PEGPL_OMR1MSKH(PCIE1)), mfdcr(DCRN_PEGPL_OMR1MSKL(PCIE1))); break; +#if CFG_PCIE_NR_PORTS > 2 case 2: - mtdcr(DCRN_PEGPL_OMR1BAH(PCIE2), 0x0000000d); - mtdcr(DCRN_PEGPL_OMR1BAL(PCIE2), CFG_PCIE_MEMBASE + + mtdcr(DCRN_PEGPL_OMR1BAH(PCIE2), CFG_PCIE_ADDR_HIGH); + mtdcr(DCRN_PEGPL_OMR1BAL(PCIE2), CFG_PCIE_MEMBASE + port * CFG_PCIE_MEMSIZE); mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE2), 0x7fffffff); mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE2), @@ -758,6 +783,7 @@ void ppc4xx_setup_pcie_rootpoint(struct pci_controller *hose, int port) mfdcr(DCRN_PEGPL_OMR1MSKH(PCIE2)), mfdcr(DCRN_PEGPL_OMR1MSKL(PCIE2))); break; +#endif } /* Set up 16GB inbound memory window at 0 */ @@ -770,8 +796,8 @@ void ppc4xx_setup_pcie_rootpoint(struct pci_controller *hose, int port) out_le32(mbase + PECFG_PIM01SAL, 0x00000000); out_le32(mbase + PECFG_PIM0LAL, 0); out_le32(mbase + PECFG_PIM0LAH, 0); - out_le32(mbase + PECFG_PIM1LAL, 0x00000000); - out_le32(mbase + PECFG_PIM1LAH, 0x00000004); + out_le32(mbase + PECFG_PIM1LAL, 0x00000000); + out_le32(mbase + PECFG_PIM1LAH, 0x00000004); out_le32(mbase + PECFG_PIMEN, 0x1); /* Enable I/O, Mem, and Busmaster cycles */ @@ -780,23 +806,8 @@ void ppc4xx_setup_pcie_rootpoint(struct pci_controller *hose, int port) PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); /* Set Device and Vendor Id */ - switch (port) { - case 0: - out_le16(mbase + 0x200, 0xaaa0); - out_le16(mbase + 0x202, 0xbed0); - break; - case 1: - out_le16(mbase + 0x200, 0xaaa1); - out_le16(mbase + 0x202, 0xbed1); - break; - case 2: - out_le16(mbase + 0x200, 0xaaa2); - out_le16(mbase + 0x202, 0xbed2); - break; - default: - out_le16(mbase + 0x200, 0xaaa3); - out_le16(mbase + 0x202, 0xbed3); - } + out_le16(mbase + 0x200, 0xaaa0 + port); + out_le16(mbase + 0x202, 0xbed0 + port); /* Set Class Code to PCI-PCI bridge and Revision Id to 1 */ out_le32(mbase + 0x208, 0x06040001); @@ -826,10 +837,12 @@ int ppc4xx_setup_pcie_endpoint(struct pci_controller *hose, int port) mbase = (u32 *)CFG_PCIE1_XCFGBASE; hose->cfg_data = (u8 *)CFG_PCIE1_CFGBASE; break; +#if defined(CFG_PCIE2_CFGBASE) case 2: mbase = (u32 *)CFG_PCIE2_XCFGBASE; hose->cfg_data = (u8 *)CFG_PCIE2_CFGBASE; break; +#endif } /* @@ -843,29 +856,31 @@ int ppc4xx_setup_pcie_endpoint(struct pci_controller *hose, int port) switch (port) { case 0: - mtdcr(DCRN_PEGPL_OMR1BAH(PCIE0), 0x0000000d); - mtdcr(DCRN_PEGPL_OMR1BAL(PCIE0), CFG_PCIE_MEMBASE + + mtdcr(DCRN_PEGPL_OMR1BAH(PCIE0), CFG_PCIE_ADDR_HIGH); + mtdcr(DCRN_PEGPL_OMR1BAL(PCIE0), CFG_PCIE_MEMBASE + port * CFG_PCIE_MEMSIZE); mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE0), 0x7fffffff); mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE0), ~(CFG_PCIE_MEMSIZE - 1) | 3); break; case 1: - mtdcr(DCRN_PEGPL_OMR1BAH(PCIE1), 0x0000000d); - mtdcr(DCRN_PEGPL_OMR1BAL(PCIE1), CFG_PCIE_MEMBASE + + mtdcr(DCRN_PEGPL_OMR1BAH(PCIE1), CFG_PCIE_ADDR_HIGH); + mtdcr(DCRN_PEGPL_OMR1BAL(PCIE1), CFG_PCIE_MEMBASE + port * CFG_PCIE_MEMSIZE); mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE1), 0x7fffffff); mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE1), ~(CFG_PCIE_MEMSIZE - 1) | 3); break; +#if CFG_PCIE_NR_PORTS > 2 case 2: - mtdcr(DCRN_PEGPL_OMR1BAH(PCIE2), 0x0000000d); - mtdcr(DCRN_PEGPL_OMR1BAL(PCIE2), CFG_PCIE_MEMBASE + + mtdcr(DCRN_PEGPL_OMR1BAH(PCIE2), CFG_PCIE_ADDR_HIGH); + mtdcr(DCRN_PEGPL_OMR1BAL(PCIE2), CFG_PCIE_MEMBASE + port * CFG_PCIE_MEMSIZE); mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE2), 0x7fffffff); mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE2), ~(CFG_PCIE_MEMSIZE - 1) | 3); break; +#endif } /* Set up 16GB inbound memory window at 0 */ @@ -873,16 +888,16 @@ int ppc4xx_setup_pcie_endpoint(struct pci_controller *hose, int port) out_le32(mbase + PCI_BASE_ADDRESS_1, 0); out_le32(mbase + PECFG_BAR0HMPA, 0x7fffffc); out_le32(mbase + PECFG_BAR0LMPA, 0); - out_le32(mbase + PECFG_PIM0LAL, 0x00000000); - out_le32(mbase + PECFG_PIM0LAH, 0x00000004); /* pointing to SRAM */ + out_le32(mbase + PECFG_PIM0LAL, U64_TO_U32_LOW(CFG_PCIE_INBOUND_BASE)); + out_le32(mbase + PECFG_PIM0LAH, U64_TO_U32_HIGH(CFG_PCIE_INBOUND_BASE)); out_le32(mbase + PECFG_PIMEN, 0x1); /* Enable I/O, Mem, and Busmaster cycles */ out_le16((u16 *)(mbase + PCI_COMMAND), in_le16((u16 *)(mbase + PCI_COMMAND)) | PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); - out_le16(mbase + 0x200,0xcaad); /* Setting vendor ID */ - out_le16(mbase + 0x202,0xfeed); /* Setting device ID */ + out_le16(mbase + 0x200, 0xcaad); /* Setting vendor ID */ + out_le16(mbase + 0x202, 0xfeed); /* Setting device ID */ attempts = 10; while(!(SDR_READ(SDRN_PESDR_RCSSTS(port)) & (1 << 8))) { @@ -893,7 +908,7 @@ int ppc4xx_setup_pcie_endpoint(struct pci_controller *hose, int port) mdelay(1000); } - printf("PCIE:%d successfully set as endpoint\n",port); + printf("PCIE:%d successfully set as endpoint\n", port); return 0; } -- cgit v1.1 From ff68f66bcb0da847845aa2fac11eba6c25938c99 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Fri, 5 Oct 2007 09:22:33 +0200 Subject: ppc4xx: 4xx_pcie: Disable debug output as default Signed-off-by: Stefan Roese --- cpu/ppc4xx/4xx_pcie.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cpu/ppc4xx/4xx_pcie.c') diff --git a/cpu/ppc4xx/4xx_pcie.c b/cpu/ppc4xx/4xx_pcie.c index d1ba890..167aba6 100644 --- a/cpu/ppc4xx/4xx_pcie.c +++ b/cpu/ppc4xx/4xx_pcie.c @@ -21,7 +21,7 @@ */ /* define DEBUG for debugging output (obviously ;-)) */ -#if 1 +#if 0 #define DEBUG #endif -- cgit v1.1 From 19e93b1e16d267220440d827b920fbad8abfa70f Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Fri, 5 Oct 2007 14:23:43 +0200 Subject: ppc4xx: 4xx_pcie: Change PCIe status output to match common style Signed-off-by: Stefan Roese --- cpu/ppc4xx/4xx_pcie.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'cpu/ppc4xx/4xx_pcie.c') diff --git a/cpu/ppc4xx/4xx_pcie.c b/cpu/ppc4xx/4xx_pcie.c index 167aba6..7ee0e5b 100644 --- a/cpu/ppc4xx/4xx_pcie.c +++ b/cpu/ppc4xx/4xx_pcie.c @@ -812,7 +812,7 @@ void ppc4xx_setup_pcie_rootpoint(struct pci_controller *hose, int port) /* Set Class Code to PCI-PCI bridge and Revision Id to 1 */ out_le32(mbase + 0x208, 0x06040001); - printf("PCIE:%d successfully set as rootpoint\n", port); + printf("PCIE%d: successfully set as root-complex\n", port); } int ppc4xx_setup_pcie_endpoint(struct pci_controller *hose, int port) @@ -908,7 +908,7 @@ int ppc4xx_setup_pcie_endpoint(struct pci_controller *hose, int port) mdelay(1000); } - printf("PCIE:%d successfully set as endpoint\n", port); + printf("PCIE%d: successfully set as endpoint\n", port); return 0; } -- cgit v1.1 From d4cb2d17946466740afeb195a57d6cb290bf4cc0 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Sat, 13 Oct 2007 16:43:23 +0200 Subject: ppc4xx: Dynamic configuration of 4xx PCIe mode as root or endpoint mode This patch adds support for dynamic configuration of PCIe ports for the AMCC PPC4xx boards equipped with PCIe interfaces. These are the PPC440SPe boards Yucca & Katmai and the 405EX board Kilauea. This dynamic configuration is done via the "pcie_mode" environement variable. This variable can be set to "EP" or "RP" for endpoint or rootpoint mode. Multiple values can be joined via the ":" delimiter. Here an example: pcie_mode=RP:EP:EP This way, PCIe port 0 will be configured as rootpoint, PCIe port 1 and 2 as endpoint. Per default Yucca will be configured as: pcie_mode=RP:EP:EP Per default Katmai will be configured as: pcie_mode=RP:RP:REP Per default Kilauea will be configured as: pcie_mode=RP:RP Signed-off-by: Tirumala R Marri Signed-off-by: Stefan Roese --- cpu/ppc4xx/4xx_pcie.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'cpu/ppc4xx/4xx_pcie.c') diff --git a/cpu/ppc4xx/4xx_pcie.c b/cpu/ppc4xx/4xx_pcie.c index 7ee0e5b..9ab3588 100644 --- a/cpu/ppc4xx/4xx_pcie.c +++ b/cpu/ppc4xx/4xx_pcie.c @@ -46,6 +46,20 @@ enum { LNKW_X8 = 0x8 }; +static int validate_endpoint(struct pci_controller *hose) +{ + if (hose->cfg_data == (u8 *)CFG_PCIE0_CFGBASE) + return (is_end_point(0)); + else if (hose->cfg_data == (u8 *)CFG_PCIE1_CFGBASE) + return (is_end_point(1)); +#if CFG_PCIE_NR_PORTS > 2 + else if (hose->cfg_data == (u8 *)CFG_PCIE2_CFGBASE) + return (is_end_point(2)); +#endif + + return 0; +} + static u8* pcie_get_base(struct pci_controller *hose, unsigned int devfn) { u8 *base = (u8*)hose->cfg_data; @@ -95,6 +109,9 @@ static int pcie_read_config(struct pci_controller *hose, unsigned int devfn, u8 *address; *val = 0; + if (validate_endpoint(hose)) + return 0; /* No upstream config access */ + /* * Bus numbers are relative to hose->first_busno */ @@ -150,6 +167,9 @@ static int pcie_write_config(struct pci_controller *hose, unsigned int devfn, u8 *address; + if (validate_endpoint(hose)) + return 0; /* No upstream config access */ + /* * Bus numbers are relative to hose->first_busno */ @@ -595,9 +615,9 @@ int ppc4xx_init_pcie_port(int port, int rootport) u32 low, high; if (!core_init) { - ++core_init; if (ppc4xx_init_pcie()) return -1; + ++core_init; } /* -- cgit v1.1 From 5cb4af4791f61843432155142b6cfac901f66c10 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 18 Oct 2007 07:39:38 +0200 Subject: ppc4xx: Add PCIe endpoint support on Kilauea (405EX) This patch adds endpoint support for the AMCC Kilauea eval board. It can be tested by connecting a reworked PCIe cable (only 1x lane singles connected) to another root-complex. In this test setup, a 64MB inbound window is configured at BAR0 which maps to 0 on the PLB side. So accessing this BAR0 from the root-complex will access the first 64MB of the SDRAM on the PPC side. Signed-off-by: Stefan Roese --- cpu/ppc4xx/4xx_pcie.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) (limited to 'cpu/ppc4xx/4xx_pcie.c') diff --git a/cpu/ppc4xx/4xx_pcie.c b/cpu/ppc4xx/4xx_pcie.c index 9ab3588..da179f9 100644 --- a/cpu/ppc4xx/4xx_pcie.c +++ b/cpu/ppc4xx/4xx_pcie.c @@ -474,12 +474,6 @@ int __ppc4xx_init_pcie_port_hw(int port, int rootport) { u32 val; - /* - * test-only: - * This needs some testing and perhaps changes for - * endpoint configuration. Probably no PHY reset at all, etc. - * sr, 2007-10-03 - */ if (rootport) val = 0x00401000; else @@ -496,7 +490,10 @@ int __ppc4xx_init_pcie_port_hw(int port, int rootport) udelay(1000); /* deassert the PE0_hotreset */ - SDR_WRITE(SDRN_PESDR_RCSSET(port), 0x01101000); + if (is_end_point(port)) + SDR_WRITE(SDRN_PESDR_RCSSET(port), 0x01111000); + else + SDR_WRITE(SDRN_PESDR_RCSSET(port), 0x01101000); /* poll for phy !reset */ while (!(SDR_READ(SDRN_PESDR_PHYSTA(port)) & 0x00001000)) @@ -903,11 +900,22 @@ int ppc4xx_setup_pcie_endpoint(struct pci_controller *hose, int port) #endif } - /* Set up 16GB inbound memory window at 0 */ + /* Set up 64MB inbound memory window at 0 */ out_le32(mbase + PCI_BASE_ADDRESS_0, 0); out_le32(mbase + PCI_BASE_ADDRESS_1, 0); - out_le32(mbase + PECFG_BAR0HMPA, 0x7fffffc); - out_le32(mbase + PECFG_BAR0LMPA, 0); + + out_le32(mbase + PECFG_PIM01SAH, 0xffffffff); + out_le32(mbase + PECFG_PIM01SAL, 0xfc000000); + + /* Setup BAR0 */ + out_le32(mbase + PECFG_BAR0HMPA, 0x7fffffff); + out_le32(mbase + PECFG_BAR0LMPA, 0xfc000000 | PCI_BASE_ADDRESS_MEM_TYPE_64); + + /* Disable BAR1 & BAR2 */ + out_le32(mbase + PECFG_BAR1MPA, 0); + out_le32(mbase + PECFG_BAR2HMPA, 0); + out_le32(mbase + PECFG_BAR2LMPA, 0); + out_le32(mbase + PECFG_PIM0LAL, U64_TO_U32_LOW(CFG_PCIE_INBOUND_BASE)); out_le32(mbase + PECFG_PIM0LAH, U64_TO_U32_HIGH(CFG_PCIE_INBOUND_BASE)); out_le32(mbase + PECFG_PIMEN, 0x1); @@ -919,6 +927,9 @@ int ppc4xx_setup_pcie_endpoint(struct pci_controller *hose, int port) out_le16(mbase + 0x200, 0xcaad); /* Setting vendor ID */ out_le16(mbase + 0x202, 0xfeed); /* Setting device ID */ + /* Set Class Code to Processor/PPC */ + out_le32(mbase + 0x208, 0x0b200001); + attempts = 10; while(!(SDR_READ(SDRN_PESDR_RCSSTS(port)) & (1 << 8))) { if (!(attempts--)) { -- cgit v1.1 From 7d0a4066b5a6b698e5fc1b66cfe9705774bbce93 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Tue, 13 Nov 2007 08:06:11 +0100 Subject: ppc4xx: Fix 405EX PCIe UTLSET register setup Signed-off-by: Stefan Roese --- cpu/ppc4xx/4xx_pcie.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'cpu/ppc4xx/4xx_pcie.c') diff --git a/cpu/ppc4xx/4xx_pcie.c b/cpu/ppc4xx/4xx_pcie.c index da179f9..de79552 100644 --- a/cpu/ppc4xx/4xx_pcie.c +++ b/cpu/ppc4xx/4xx_pcie.c @@ -480,8 +480,8 @@ int __ppc4xx_init_pcie_port_hw(int port, int rootport) val = 0x00101000; SDR_WRITE(SDRN_PESDR_DLPSET(port), val); - SDR_WRITE(SDRN_PESDR_UTLSET1(port), 0x20222222); - SDR_WRITE(SDRN_PESDR_UTLSET2(port), 0x01110000); + SDR_WRITE(SDRN_PESDR_UTLSET1(port), 0x00000000); + SDR_WRITE(SDRN_PESDR_UTLSET2(port), 0x01010000); SDR_WRITE(SDRN_PESDR_PHYSET1(port), 0x720F0000); SDR_WRITE(SDRN_PESDR_PHYSET2(port), 0x70600003); -- cgit v1.1 From f31d38b9eea9b32f6a1ac848a298cc71ca4c9a03 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Fri, 16 Nov 2007 14:16:54 +0100 Subject: ppc4xx: Enable 405EX PCIe UTL register configuration Till now the UTL registers on 405EX were not initialized but left with their default values. This patch new initializes some of the UTL registers on 405EX. Signed-off-by: Stefan Roese --- cpu/ppc4xx/4xx_pcie.c | 44 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) (limited to 'cpu/ppc4xx/4xx_pcie.c') diff --git a/cpu/ppc4xx/4xx_pcie.c b/cpu/ppc4xx/4xx_pcie.c index de79552..cafd933 100644 --- a/cpu/ppc4xx/4xx_pcie.c +++ b/cpu/ppc4xx/4xx_pcie.c @@ -401,6 +401,48 @@ int ppc4xx_init_pcie(void) return 0; } #else +static void ppc4xx_setup_utl(u32 port) +{ + u32 utl_base; + + /* + * Map UTL registers at 0xef4f_n000 (4K 0xfff mask) PEGPLn_REGMSK + */ + switch (port) { + case 0: + mtdcr(DCRN_PEGPL_REGBAH(PCIE0), 0x00000000); + mtdcr(DCRN_PEGPL_REGBAL(PCIE0), CFG_PCIE0_UTLBASE); + mtdcr(DCRN_PEGPL_REGMSK(PCIE0), 0xfffffc01); /* 4k region, valid */ + mtdcr(DCRN_PEGPL_SPECIAL(PCIE0), 0); + break; + + case 1: + mtdcr(DCRN_PEGPL_REGBAH(PCIE1), 0x00000000); + mtdcr(DCRN_PEGPL_REGBAL(PCIE1), CFG_PCIE1_UTLBASE); + mtdcr(DCRN_PEGPL_REGMSK(PCIE1), 0xfffffc01); /* 4k region, valid */ + mtdcr(DCRN_PEGPL_SPECIAL(PCIE1), 0); + + break; + } + utl_base = (port==0) ? CFG_PCIE0_UTLBASE : CFG_PCIE1_UTLBASE; + + /* + * Set buffer allocations and then assert VRB and TXE. + */ + out_be32((u32 *)(utl_base + PEUTL_OUTTR), 0x02000000); + out_be32((u32 *)(utl_base + PEUTL_INTR), 0x02000000); + out_be32((u32 *)(utl_base + PEUTL_OPDBSZ), 0x04000000); + out_be32((u32 *)(utl_base + PEUTL_PBBSZ), 0x21000000); + out_be32((u32 *)(utl_base + PEUTL_IPHBSZ), 0x02000000); + out_be32((u32 *)(utl_base + PEUTL_IPDBSZ), 0x04000000); + out_be32((u32 *)(utl_base + PEUTL_RCIRQEN), 0x00f00000); + out_be32((u32 *)(utl_base + PEUTL_PCTL), 0x80800066); + + out_be32((u32 *)(utl_base + PEUTL_PBCTL), 0x0800000c); + out_be32((u32 *)(utl_base + PEUTL_RCSTA), + in_be32((u32 *)(utl_base + PEUTL_RCSTA)) | 0x000040000); +} + int ppc4xx_init_pcie(void) { /* @@ -643,14 +685,12 @@ int ppc4xx_init_pcie_port(int port, int rootport) return -1; } -#if defined(CONFIG_440SPE) /* * Setup UTL registers - but only on revA! * We use default settings for revB chip. */ if (!ppc440spe_revB()) ppc4xx_setup_utl(port); -#endif /* * We map PCI Express configuration access into the 512MB regions -- cgit v1.1 From 653811a3c2b35856bf12e196dcc8c4694e28e420 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Sun, 18 Nov 2007 14:44:44 +0100 Subject: ppc4xx: Correct 405EX PCIe UTL register mapping Map 4k mem space for UTL registers for each port. Signed-off-by: Stefan Roese --- cpu/ppc4xx/4xx_pcie.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'cpu/ppc4xx/4xx_pcie.c') diff --git a/cpu/ppc4xx/4xx_pcie.c b/cpu/ppc4xx/4xx_pcie.c index cafd933..3af9862 100644 --- a/cpu/ppc4xx/4xx_pcie.c +++ b/cpu/ppc4xx/4xx_pcie.c @@ -412,14 +412,14 @@ static void ppc4xx_setup_utl(u32 port) case 0: mtdcr(DCRN_PEGPL_REGBAH(PCIE0), 0x00000000); mtdcr(DCRN_PEGPL_REGBAL(PCIE0), CFG_PCIE0_UTLBASE); - mtdcr(DCRN_PEGPL_REGMSK(PCIE0), 0xfffffc01); /* 4k region, valid */ + mtdcr(DCRN_PEGPL_REGMSK(PCIE0), 0x00007001); /* 4k region, valid */ mtdcr(DCRN_PEGPL_SPECIAL(PCIE0), 0); break; case 1: mtdcr(DCRN_PEGPL_REGBAH(PCIE1), 0x00000000); mtdcr(DCRN_PEGPL_REGBAL(PCIE1), CFG_PCIE1_UTLBASE); - mtdcr(DCRN_PEGPL_REGMSK(PCIE1), 0xfffffc01); /* 4k region, valid */ + mtdcr(DCRN_PEGPL_REGMSK(PCIE1), 0x00007001); /* 4k region, valid */ mtdcr(DCRN_PEGPL_SPECIAL(PCIE1), 0); break; @@ -554,7 +554,7 @@ int __ppc4xx_init_pcie_port_hw(int port, int rootport) #endif /* CONFIG_405EX */ int ppc4xx_init_pcie_port_hw(int port, int rootport) - __attribute__((weak, alias("__ppc4xx_init_pcie_port_hw"))); +__attribute__((weak, alias("__ppc4xx_init_pcie_port_hw"))); /* * We map PCI Express configuration access into the 512MB regions -- cgit v1.1