[POWERPC] 4xx: Add 460EX PCIe support to 4xx pci driver

All this code is needed to properly initialize the 460EX PCIe host
bridge(s). We re-initialize all ports again, even though this has been done
in the bootloader (U-Boot) before. This way we make sure, that we always
run the latest init code in Linux and don't depend on code versions from
U-Boot.

Unfortunately all IBM/AMCC chips currently supported in this PCIe driver need
a different reset-/init-sequence.

Tested on AMCC Canyonlands eval board.

Signed-off-by: Stefan Roese <sr@denx.de>
Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
This commit is contained in:
Stefan Roese 2008-02-24 08:08:27 +11:00 committed by Josh Boyer
parent 8bc4a51d28
commit 66b7e504c0
2 changed files with 173 additions and 0 deletions

View file

@ -527,6 +527,7 @@ static void __init ppc4xx_probe_pcix_bridge(struct device_node *np)
*
* ibm,plb-pciex-440spe
* ibm,plb-pciex-405ex
* ibm,plb-pciex-460ex
*
* Anything else will be rejected for now as they are all subtly
* different unfortunately.
@ -775,6 +776,117 @@ static struct ppc4xx_pciex_hwops ppc440speB_pcie_hwops __initdata =
.setup_utl = ppc440speB_pciex_init_utl,
};
static int __init ppc460ex_pciex_core_init(struct device_node *np)
{
/* Nothing to do, return 2 ports */
return 2;
}
static int ppc460ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
{
u32 val;
u32 utlset1;
if (port->endpoint) {
val = PTYPE_LEGACY_ENDPOINT << 20;
utlset1 = 0x20222222;
} else {
val = PTYPE_ROOT_PORT << 20;
utlset1 = 0x21222222;
}
if (port->index == 0) {
val |= LNKW_X1 << 12;
} else {
val |= LNKW_X4 << 12;
utlset1 |= 0x00101101;
}
mtdcri(SDR0, port->sdr_base + PESDRn_DLPSET, val);
mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET1, utlset1);
mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET2, 0x01210000);
switch (port->index) {
case 0:
mtdcri(SDR0, PESDR0_460EX_L0CDRCTL, 0x00003230);
mtdcri(SDR0, PESDR0_460EX_L0DRV, 0x00000136);
mtdcri(SDR0, PESDR0_460EX_L0CLK, 0x00000006);
mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST,0x10000000);
break;
case 1:
mtdcri(SDR0, PESDR1_460EX_L0CDRCTL, 0x00003230);
mtdcri(SDR0, PESDR1_460EX_L1CDRCTL, 0x00003230);
mtdcri(SDR0, PESDR1_460EX_L2CDRCTL, 0x00003230);
mtdcri(SDR0, PESDR1_460EX_L3CDRCTL, 0x00003230);
mtdcri(SDR0, PESDR1_460EX_L0DRV, 0x00000136);
mtdcri(SDR0, PESDR1_460EX_L1DRV, 0x00000136);
mtdcri(SDR0, PESDR1_460EX_L2DRV, 0x00000136);
mtdcri(SDR0, PESDR1_460EX_L3DRV, 0x00000136);
mtdcri(SDR0, PESDR1_460EX_L0CLK, 0x00000006);
mtdcri(SDR0, PESDR1_460EX_L1CLK, 0x00000006);
mtdcri(SDR0, PESDR1_460EX_L2CLK, 0x00000006);
mtdcri(SDR0, PESDR1_460EX_L3CLK, 0x00000006);
mtdcri(SDR0, PESDR1_460EX_PHY_CTL_RST,0x10000000);
break;
}
mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET,
mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) |
(PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTPYN));
/* Poll for PHY reset */
/* XXX FIXME add timeout */
switch (port->index) {
case 0:
while (!(mfdcri(SDR0, PESDR0_460EX_RSTSTA) & 0x1))
udelay(10);
break;
case 1:
while (!(mfdcri(SDR0, PESDR1_460EX_RSTSTA) & 0x1))
udelay(10);
break;
}
mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET,
(mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) &
~(PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTDL)) |
PESDRx_RCSSET_RSTPYN);
port->has_ibpre = 1;
return 0;
}
static int ppc460ex_pciex_init_utl(struct ppc4xx_pciex_port *port)
{
dcr_write(port->dcrs, DCRO_PEGPL_SPECIAL, 0x0);
/*
* Set buffer allocations and then assert VRB and TXE.
*/
out_be32(port->utl_base + PEUTL_PBCTL, 0x0800000c);
out_be32(port->utl_base + PEUTL_OUTTR, 0x08000000);
out_be32(port->utl_base + PEUTL_INTR, 0x02000000);
out_be32(port->utl_base + PEUTL_OPDBSZ, 0x04000000);
out_be32(port->utl_base + PEUTL_PBBSZ, 0x00000000);
out_be32(port->utl_base + PEUTL_IPHBSZ, 0x02000000);
out_be32(port->utl_base + PEUTL_IPDBSZ, 0x04000000);
out_be32(port->utl_base + PEUTL_RCIRQEN,0x00f00000);
out_be32(port->utl_base + PEUTL_PCTL, 0x80800066);
return 0;
}
static struct ppc4xx_pciex_hwops ppc460ex_pcie_hwops __initdata =
{
.core_init = ppc460ex_pciex_core_init,
.port_init_hw = ppc460ex_pciex_init_port_hw,
.setup_utl = ppc460ex_pciex_init_utl,
};
#endif /* CONFIG_44x */
#ifdef CONFIG_40x
@ -896,6 +1008,8 @@ static int __init ppc4xx_pciex_check_core_init(struct device_node *np)
else
ppc4xx_pciex_hwops = &ppc440speB_pcie_hwops;
}
if (of_device_is_compatible(np, "ibm,plb-pciex-460ex"))
ppc4xx_pciex_hwops = &ppc460ex_pcie_hwops;
#endif /* CONFIG_44x */
#ifdef CONFIG_40x
if (of_device_is_compatible(np, "ibm,plb-pciex-405ex"))

View file

@ -270,6 +270,59 @@
#define PESDR1_405EX_LPB 0x044B
#define PESDR1_405EX_PHYSTA 0x044C
/*
* 460EX additional DCRs
*/
#define PESDR0_460EX_L0BIST 0x0308
#define PESDR0_460EX_L0BISTSTS 0x0309
#define PESDR0_460EX_L0CDRCTL 0x030A
#define PESDR0_460EX_L0DRV 0x030B
#define PESDR0_460EX_L0REC 0x030C
#define PESDR0_460EX_L0LPB 0x030D
#define PESDR0_460EX_L0CLK 0x030E
#define PESDR0_460EX_PHY_CTL_RST 0x030F
#define PESDR0_460EX_RSTSTA 0x0310
#define PESDR0_460EX_OBS 0x0311
#define PESDR0_460EX_L0ERRC 0x0320
#define PESDR1_460EX_L0BIST 0x0348
#define PESDR1_460EX_L1BIST 0x0349
#define PESDR1_460EX_L2BIST 0x034A
#define PESDR1_460EX_L3BIST 0x034B
#define PESDR1_460EX_L0BISTSTS 0x034C
#define PESDR1_460EX_L1BISTSTS 0x034D
#define PESDR1_460EX_L2BISTSTS 0x034E
#define PESDR1_460EX_L3BISTSTS 0x034F
#define PESDR1_460EX_L0CDRCTL 0x0350
#define PESDR1_460EX_L1CDRCTL 0x0351
#define PESDR1_460EX_L2CDRCTL 0x0352
#define PESDR1_460EX_L3CDRCTL 0x0353
#define PESDR1_460EX_L0DRV 0x0354
#define PESDR1_460EX_L1DRV 0x0355
#define PESDR1_460EX_L2DRV 0x0356
#define PESDR1_460EX_L3DRV 0x0357
#define PESDR1_460EX_L0REC 0x0358
#define PESDR1_460EX_L1REC 0x0359
#define PESDR1_460EX_L2REC 0x035A
#define PESDR1_460EX_L3REC 0x035B
#define PESDR1_460EX_L0LPB 0x035C
#define PESDR1_460EX_L1LPB 0x035D
#define PESDR1_460EX_L2LPB 0x035E
#define PESDR1_460EX_L3LPB 0x035F
#define PESDR1_460EX_L0CLK 0x0360
#define PESDR1_460EX_L1CLK 0x0361
#define PESDR1_460EX_L2CLK 0x0362
#define PESDR1_460EX_L3CLK 0x0363
#define PESDR1_460EX_PHY_CTL_RST 0x0364
#define PESDR1_460EX_RSTSTA 0x0365
#define PESDR1_460EX_OBS 0x0366
#define PESDR1_460EX_L0ERRC 0x0368
#define PESDR1_460EX_L1ERRC 0x0369
#define PESDR1_460EX_L2ERRC 0x036A
#define PESDR1_460EX_L3ERRC 0x036B
#define PESDR0_460EX_IHS1 0x036C
#define PESDR0_460EX_IHS2 0x036D
/*
* Of the above, some are common offsets from the base
*/
@ -353,6 +406,12 @@
#define PECFG_POM2LAL 0x390
#define PECFG_POM2LAH 0x394
/* SDR Bit Mappings */
#define PESDRx_RCSSET_HLDPLB 0x10000000
#define PESDRx_RCSSET_RSTGU 0x01000000
#define PESDRx_RCSSET_RDY 0x00100000
#define PESDRx_RCSSET_RSTDL 0x00010000
#define PESDRx_RCSSET_RSTPYN 0x00001000
enum
{