Пример #1
0
static int ppc405ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
{
	u32 val;

	if (port->endpoint)
		val = PTYPE_LEGACY_ENDPOINT;
	else
		val = PTYPE_ROOT_PORT;

	mtdcri(SDR0, port->sdr_base + PESDRn_DLPSET,
	       1 << 24 | val << 20 | LNKW_X1 << 12);

	mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET1, 0x00000000);
	mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET2, 0x01010000);
	mtdcri(SDR0, port->sdr_base + PESDRn_405EX_PHYSET1, 0x720F0000);
	mtdcri(SDR0, port->sdr_base + PESDRn_405EX_PHYSET2, 0x70600003);

	/*
	 * Only reset the PHY when no link is currently established.
	 * This is for the Atheros PCIe board which has problems to establish
	 * the link (again) after this PHY reset. All other currently tested
	 * PCIe boards don't show this problem.
	 * This has to be re-tested and fixed in a later release!
	 */
	val = mfdcri(SDR0, port->sdr_base + PESDRn_LOOP);
	if (!(val & 0x00001000))
		ppc405ex_pcie_phy_reset(port);

	dcr_write(port->dcrs, DCRO_PEGPL_CFG, 0x10000000);  /* guarded on */

	port->has_ibpre = 1;

	return 0;
}
Пример #2
0
/* Global PCIe core initializations for 440SPe core */
static int __init ppc440spe_pciex_core_init(struct device_node *np)
{
	int time_out = 20;

	/* Set PLL clock receiver to LVPECL */
	mtdcri(SDR0, PESDR0_PLLLCT1, mfdcri(SDR0, PESDR0_PLLLCT1) | 1 << 28);

	/* Shouldn't we do all the calibration stuff etc... here ? */
	if (ppc440spe_pciex_check_reset(np))
		return -ENXIO;

	if (!(mfdcri(SDR0, PESDR0_PLLLCT2) & 0x10000)) {
		printk(KERN_INFO "PCIE: PESDR_PLLCT2 resistance calibration "
		       "failed (0x%08x)\n",
		       mfdcri(SDR0, PESDR0_PLLLCT2));
		return -1;
	}

	/* De-assert reset of PCIe PLL, wait for lock */
	mtdcri(SDR0, PESDR0_PLLLCT1,
	       mfdcri(SDR0, PESDR0_PLLLCT1) & ~(1 << 24));
	udelay(3);

	while (time_out) {
		if (!(mfdcri(SDR0, PESDR0_PLLLCT3) & 0x10000000)) {
			time_out--;
			udelay(1);
		} else
			break;
	}
	if (!time_out) {
		printk(KERN_INFO "PCIE: VCO output not locked\n");
		return -1;
	}

	pr_debug("PCIE initialization OK\n");

	return 3;
}
Пример #3
0
static int __init kilauea_probe(void)
{
	unsigned long root = of_get_flat_dt_root();

	if (!of_flat_dt_is_compatible(root, "amcc,kilauea"))
		return 0;

	ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;

	/*
	 * 405EX(r) has SDR0_MFR[E0CS/E1CS] set after reset. This selects
	 * the internal loopback mode. Clear these bits so that both EMACs
	 * don't use loopback mode as deafult.
	 */
	mtdcri(SDR0, SDR0_MFR, mfdcri(SDR0, SDR0_MFR) & ~0x0c000000);

	return 1;
}
Пример #4
0
static int __init ppc4xx_pciex_wait_on_sdr(struct ppc4xx_pciex_port *port,
					   unsigned int sdr_offset,
					   unsigned int mask,
					   unsigned int value,
					   int timeout_ms)
{
	u32 val;

	while(timeout_ms--) {
		val = mfdcri(SDR0, port->sdr_base + sdr_offset);
		if ((val & mask) == value) {
			pr_debug("PCIE%d: Wait on SDR %x success with tm %d (%08x)\n",
				 port->index, sdr_offset, timeout_ms, val);
			return 0;
		}
		msleep(1);
	}
	return -1;
}
Пример #5
0
static void ppc405ex_pcie_phy_reset(struct ppc4xx_pciex_port *port)
{
	/* Assert the PE0_PHY reset */
	mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 0x01010000);
	msleep(1);

	/* deassert the PE0_hotreset */
	if (port->endpoint)
		mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 0x01111000);
	else
		mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 0x01101000);

	/* poll for phy !reset */
	/* XXX FIXME add timeout */
	while (!(mfdcri(SDR0, port->sdr_base + PESDRn_405EX_PHYSTA) & 0x00001000))
		;

	/* deassert the PE0_gpl_utl_reset */
	mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 0x00101000);
}
Пример #6
0
static int ppc440spe_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
{
	u32 val = 1 << 24;

	if (port->endpoint)
		val = PTYPE_LEGACY_ENDPOINT << 20;
	else
		val = PTYPE_ROOT_PORT << 20;

	if (port->index == 0)
		val |= LNKW_X8 << 12;
	else
		val |= LNKW_X4 << 12;

	mtdcri(SDR0, port->sdr_base + PESDRn_DLPSET, val);
	mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET1, 0x20222222);
	if (ppc440spe_revA())
		mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET2, 0x11000000);
	mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL0SET1, 0x35000000);
	mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL1SET1, 0x35000000);
	mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL2SET1, 0x35000000);
	mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL3SET1, 0x35000000);
	if (port->index == 0) {
		mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL4SET1,
		       0x35000000);
		mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL5SET1,
		       0x35000000);
		mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL6SET1,
		       0x35000000);
		mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL7SET1,
		       0x35000000);
	}
	val = mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET);
	mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET,
	       (val & ~(1 << 24 | 1 << 16)) | 1 << 12);

	return 0;
}
Пример #7
0
static int ppc460ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
{
	u32 val;
	u32 utlset1;

	if (port->endpoint)
		val = PTYPE_LEGACY_ENDPOINT << 20;
	else
		val = PTYPE_ROOT_PORT << 20;

	if (port->index == 0) {
		val |= LNKW_X1 << 12;
		utlset1 = 0x20000000;
	} else {
		val |= LNKW_X4 << 12;
		utlset1 = 0x20101101;
	}

	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, 0x00000130);
		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, 0x00000130);
		mtdcri(SDR0, PESDR1_460EX_L1DRV, 0x00000130);
		mtdcri(SDR0, PESDR1_460EX_L2DRV, 0x00000130);
		mtdcri(SDR0, PESDR1_460EX_L3DRV, 0x00000130);
		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;
}
Пример #8
0
/* Check various reset bits of the 440SPe PCIe core */
static int __init ppc440spe_pciex_check_reset(struct device_node *np)
{
	u32 valPE0, valPE1, valPE2;
	int err = 0;

	/* SDR0_PEGPLLLCT1 reset */
	if (!(mfdcri(SDR0, PESDR0_PLLLCT1) & 0x01000000)) {
		/*
		 * the PCIe core was probably already initialised
		 * by firmware - let's re-reset RCSSET regs
		 *
		 * -- Shouldn't we also re-reset the whole thing ? -- BenH
		 */
		pr_debug("PCIE: SDR0_PLLLCT1 already reset.\n");
		mtdcri(SDR0, PESDR0_440SPE_RCSSET, 0x01010000);
		mtdcri(SDR0, PESDR1_440SPE_RCSSET, 0x01010000);
		mtdcri(SDR0, PESDR2_440SPE_RCSSET, 0x01010000);
	}

	valPE0 = mfdcri(SDR0, PESDR0_440SPE_RCSSET);
	valPE1 = mfdcri(SDR0, PESDR1_440SPE_RCSSET);
	valPE2 = mfdcri(SDR0, PESDR2_440SPE_RCSSET);

	/* SDR0_PExRCSSET rstgu */
	if (!(valPE0 & 0x01000000) ||
	    !(valPE1 & 0x01000000) ||
	    !(valPE2 & 0x01000000)) {
		printk(KERN_INFO "PCIE: SDR0_PExRCSSET rstgu error\n");
		err = -1;
	}

	/* SDR0_PExRCSSET rstdl */
	if (!(valPE0 & 0x00010000) ||
	    !(valPE1 & 0x00010000) ||
	    !(valPE2 & 0x00010000)) {
		printk(KERN_INFO "PCIE: SDR0_PExRCSSET rstdl error\n");
		err = -1;
	}

	/* SDR0_PExRCSSET rstpyn */
	if ((valPE0 & 0x00001000) ||
	    (valPE1 & 0x00001000) ||
	    (valPE2 & 0x00001000)) {
		printk(KERN_INFO "PCIE: SDR0_PExRCSSET rstpyn error\n");
		err = -1;
	}

	/* SDR0_PExRCSSET hldplb */
	if ((valPE0 & 0x10000000) ||
	    (valPE1 & 0x10000000) ||
	    (valPE2 & 0x10000000)) {
		printk(KERN_INFO "PCIE: SDR0_PExRCSSET hldplb error\n");
		err = -1;
	}

	/* SDR0_PExRCSSET rdy */
	if ((valPE0 & 0x00100000) ||
	    (valPE1 & 0x00100000) ||
	    (valPE2 & 0x00100000)) {
		printk(KERN_INFO "PCIE: SDR0_PExRCSSET rdy error\n");
		err = -1;
	}

	/* SDR0_PExRCSSET shutdown */
	if ((valPE0 & 0x00000100) ||
	    (valPE1 & 0x00000100) ||
	    (valPE2 & 0x00000100)) {
		printk(KERN_INFO "PCIE: SDR0_PExRCSSET shutdown error\n");
		err = -1;
	}

	return err;
}
Пример #9
0
static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port)
{
	int rc = 0;

	/* Init HW */
	if (ppc4xx_pciex_hwops->port_init_hw)
		rc = ppc4xx_pciex_hwops->port_init_hw(port);
	if (rc != 0)
		return rc;

	printk(KERN_INFO "PCIE%d: Checking link...\n",
	       port->index);

	/* Wait for reset to complete */
	if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, 1 << 20, 0, 10)) {
		printk(KERN_WARNING "PCIE%d: PGRST failed\n",
		       port->index);
		return -1;
	}

	/* Check for card presence detect if supported, if not, just wait for
	 * link unconditionally.
	 *
	 * note that we don't fail if there is no link, we just filter out
	 * config space accesses. That way, it will be easier to implement
	 * hotplug later on.
	 */
	if (!port->has_ibpre ||
	    !ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP,
				      1 << 28, 1 << 28, 100)) {
		printk(KERN_INFO
		       "PCIE%d: Device detected, waiting for link...\n",
		       port->index);
		if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP,
					     0x1000, 0x1000, 2000))
			printk(KERN_WARNING
			       "PCIE%d: Link up failed\n", port->index);
		else {
			printk(KERN_INFO
			       "PCIE%d: link is up !\n", port->index);
			port->link = 1;
		}
	} else
		printk(KERN_INFO "PCIE%d: No device detected.\n", port->index);

	/*
	 * Initialize mapping: disable all regions and configure
	 * CFG and REG regions based on resources in the device tree
	 */
	ppc4xx_pciex_port_init_mapping(port);

	/*
	 * Map UTL
	 */
	port->utl_base = ioremap(port->utl_regs.start, 0x100);
	BUG_ON(port->utl_base == NULL);

	/*
	 * Setup UTL registers --BenH.
	 */
	if (ppc4xx_pciex_hwops->setup_utl)
		ppc4xx_pciex_hwops->setup_utl(port);

	/*
	 * Check for VC0 active and assert RDY.
	 */
	if (port->link &&
	    ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS,
				     1 << 16, 1 << 16, 5000)) {
		printk(KERN_INFO "PCIE%d: VC0 not active\n", port->index);
		port->link = 0;
	}

	mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET,
	       mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) | 1 << 20);
	msleep(100);

	return 0;
}