diff options
Diffstat (limited to 'cpu/ppc4xx/4xx_pcie.c')
| -rw-r--r-- | cpu/ppc4xx/4xx_pcie.c | 119 | 
1 files changed, 119 insertions, 0 deletions
| diff --git a/cpu/ppc4xx/4xx_pcie.c b/cpu/ppc4xx/4xx_pcie.c index 19d2c7dd2..d9605c30b 100644 --- a/cpu/ppc4xx/4xx_pcie.c +++ b/cpu/ppc4xx/4xx_pcie.c @@ -48,6 +48,125 @@ enum {  	LNKW_X8			= 0x8  }; +static struct pci_controller pcie_hose[CONFIG_SYS_PCIE_NR_PORTS]; + +/* + * Per default, all cards are present, so we need to check if the + * link comes up. + */ +int __board_pcie_card_present(int port) +{ +	return 1; +} +int board_pcie_card_present(int port) +	__attribute__((weak, alias("__board_pcie_card_present"))); + +/* + * Some boards have runtime detection of the first and last PCIe + * slot used, so let's provide weak default functions for the + * common version. + */ +int __board_pcie_first(void) +{ +	return 0; +} +int board_pcie_first(void) +	__attribute__((weak, alias("__board_pcie_first"))); + +int __board_pcie_last(void) +{ +	return CONFIG_SYS_PCIE_NR_PORTS - 1; +} +int board_pcie_last(void) +	__attribute__((weak, alias("__board_pcie_last"))); + +void __board_pcie_setup_port(int port, int rootpoint) +{ +	/* noting in this weak default implementation */ +} +void board_pcie_setup_port(int port, int rootpoint) +	__attribute__((weak, alias("__board_pcie_setup_port"))); + +void pcie_setup_hoses(int busno) +{ +	struct pci_controller *hose; +	int i, bus; +	int ret = 0; +	char *env; +	unsigned int delay; +	int first = board_pcie_first(); +	int last = board_pcie_last(); + +	/* +	 * Assume we're called after the PCI(X) hose(s) are initialized, +	 * which takes bus ID 0... and therefore start numbering PCIe's +	 * from the next number. +	 */ +	bus = busno; + +	for (i = first; i <= last; i++) { +		/* +		 * Some boards (e.g. Katmai) can detects via hardware +		 * if a PCIe card is plugged, so let's check this. +		 */ +		if (!board_pcie_card_present(i)) +			continue; + +		if (is_end_point(i)) { +			board_pcie_setup_port(i, 0); +			ret = ppc4xx_init_pcie_endport(i); +		} else { +			board_pcie_setup_port(i, 1); +			ret = ppc4xx_init_pcie_rootport(i); +		} +		if (ret == -ENODEV) +			continue; +		if (ret) { +			printf("PCIE%d: initialization as %s failed\n", i, +			       is_end_point(i) ? "endpoint" : "root-complex"); +			continue; +		} + +		hose = &pcie_hose[i]; +		hose->first_busno = bus; +		hose->last_busno = bus; +		hose->current_busno = bus; + +		/* setup mem resource */ +		pci_set_region(hose->regions + 0, +			       CONFIG_SYS_PCIE_MEMBASE + i * CONFIG_SYS_PCIE_MEMSIZE, +			       CONFIG_SYS_PCIE_MEMBASE + i * CONFIG_SYS_PCIE_MEMSIZE, +			       CONFIG_SYS_PCIE_MEMSIZE, +			       PCI_REGION_MEM); +		hose->region_count = 1; +		pci_register_hose(hose); + +		if (is_end_point(i)) { +			ppc4xx_setup_pcie_endpoint(hose, i); +			/* +			 * Reson for no scanning is endpoint can not generate +			 * upstream configuration accesses. +			 */ +		} else { +			ppc4xx_setup_pcie_rootpoint(hose, i); +			env = getenv ("pciscandelay"); +			if (env != NULL) { +				delay = simple_strtoul(env, NULL, 10); +				if (delay > 5) +					printf("Warning, expect noticable delay before " +					       "PCIe scan due to 'pciscandelay' value!\n"); +				mdelay(delay * 1000); +			} + +			/* +			 * Config access can only go down stream +			 */ +			hose->last_busno = pci_hose_scan(hose); +			bus = hose->last_busno + 1; +		} +	} +} +  static int validate_endpoint(struct pci_controller *hose)  {  	if (hose->cfg_data == (u8 *)CONFIG_SYS_PCIE0_CFGBASE) |