mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-25 14:10:43 +00:00
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 <tmarri@amcc.com> Signed-off-by: Stefan Roese <sr@denx.de>
This commit is contained in:
parent
fd671802b6
commit
d4cb2d1794
8 changed files with 173 additions and 102 deletions
|
@ -30,9 +30,6 @@
|
|||
#include <asm/gpio.h>
|
||||
#include <asm/4xx_pcie.h>
|
||||
|
||||
#undef PCIE_ENDPOINT
|
||||
/* #define PCIE_ENDPOINT 1 */
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
int board_early_init_f (void)
|
||||
|
@ -392,6 +389,7 @@ void pcie_setup_hoses(int busno)
|
|||
{
|
||||
struct pci_controller *hose;
|
||||
int i, bus;
|
||||
int ret = 0;
|
||||
char *env;
|
||||
unsigned int delay;
|
||||
|
||||
|
@ -405,11 +403,14 @@ void pcie_setup_hoses(int busno)
|
|||
if (!katmai_pcie_card_present(i))
|
||||
continue;
|
||||
|
||||
#ifdef PCIE_ENDPOINT
|
||||
if (ppc4xx_init_pcie_endport(i)) {
|
||||
#else
|
||||
if (ppc4xx_init_pcie_rootport(i)) {
|
||||
#endif
|
||||
if (is_end_point(i)) {
|
||||
printf("PCIE%d: will be configured as endpoint\n", i);
|
||||
ret = ppc4xx_init_pcie_endport(i);
|
||||
} else {
|
||||
printf("PCIE%d: will be configured as root-complex\n", i);
|
||||
ret = ppc4xx_init_pcie_rootport(i);
|
||||
}
|
||||
if (ret) {
|
||||
printf("PCIE%d: initialization failed\n", i);
|
||||
continue;
|
||||
}
|
||||
|
@ -424,35 +425,33 @@ void pcie_setup_hoses(int busno)
|
|||
CFG_PCIE_MEMBASE + i * CFG_PCIE_MEMSIZE,
|
||||
CFG_PCIE_MEMBASE + i * CFG_PCIE_MEMSIZE,
|
||||
CFG_PCIE_MEMSIZE,
|
||||
PCI_REGION_MEM
|
||||
);
|
||||
PCI_REGION_MEM);
|
||||
hose->region_count = 1;
|
||||
pci_register_hose(hose);
|
||||
|
||||
#ifdef PCIE_ENDPOINT
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Config access can only go down stream
|
||||
*/
|
||||
hose->last_busno = pci_hose_scan(hose);
|
||||
bus = hose->last_busno + 1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif /* defined(CONFIG_PCI) */
|
||||
|
|
|
@ -299,35 +299,29 @@ void pci_target_init(struct pci_controller * hose )
|
|||
#endif /* defined(CONFIG_PCI) && defined(CFG_PCI_TARGET_INIT) */
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
static int pcie_port_is_rootpoint(int port)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct pci_controller pcie_hose[2] = {{0},{0}};
|
||||
|
||||
void pcie_setup_hoses(int busno)
|
||||
{
|
||||
struct pci_controller *hose;
|
||||
int i, bus;
|
||||
int ret = 0;
|
||||
bus = busno;
|
||||
char *env;
|
||||
unsigned int delay;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
|
||||
if (pcie_port_is_rootpoint(i)) {
|
||||
printf("PORT%d will be configured as root-complex\n", i);
|
||||
if (ppc4xx_init_pcie_rootport(i)) {
|
||||
printf("PCIE%d: initialization failed\n", i);
|
||||
continue;
|
||||
}
|
||||
if (is_end_point(i)) {
|
||||
printf("PCIE%d: will be configured as endpoint\n", i);
|
||||
ret = ppc4xx_init_pcie_endport(i);
|
||||
} else {
|
||||
printf("PORT%d will be configured as endpoint\n", i);
|
||||
if (ppc4xx_init_pcie_endport(i)) {
|
||||
printf("PCIE%d: initialization failed\n", i);
|
||||
continue;
|
||||
}
|
||||
printf("PCIE%d: will be configured as root-complex\n", i);
|
||||
ret = ppc4xx_init_pcie_rootport(i);
|
||||
}
|
||||
if (ret) {
|
||||
printf("PCIE%d: initialization failed\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
hose = &pcie_hose[i];
|
||||
|
@ -344,25 +338,29 @@ void pcie_setup_hoses(int busno)
|
|||
hose->region_count = 1;
|
||||
pci_register_hose(hose);
|
||||
|
||||
if (pcie_port_is_rootpoint(i))
|
||||
ppc4xx_setup_pcie_rootpoint(hose, i);
|
||||
else
|
||||
ppc4xx_setup_pcie_endpoint(hose, i);
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Config access can only go down stream
|
||||
*/
|
||||
hose->last_busno = pci_hose_scan(hose);
|
||||
bus = hose->last_busno + 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -36,11 +36,8 @@
|
|||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#undef PCIE_ENDPOINT
|
||||
/* #define PCIE_ENDPOINT 1 */
|
||||
|
||||
void fpga_init (void);
|
||||
|
||||
void get_sys_info(PPC440_SYS_INFO *board_cfg );
|
||||
int compare_to_true(char *str );
|
||||
char *remove_l_w_space(char *in_str );
|
||||
|
@ -847,6 +844,7 @@ void pcie_setup_hoses(int busno)
|
|||
{
|
||||
struct pci_controller *hose;
|
||||
int i, bus;
|
||||
int ret = 0;
|
||||
char *env;
|
||||
unsigned int delay;
|
||||
|
||||
|
@ -860,16 +858,19 @@ void pcie_setup_hoses(int busno)
|
|||
if (!yucca_pcie_card_present(i))
|
||||
continue;
|
||||
|
||||
#ifdef PCIE_ENDPOINT
|
||||
yucca_setup_pcie_fpga_endpoint(i);
|
||||
if (ppc4xx_init_pcie_endport(i)) {
|
||||
#else
|
||||
yucca_setup_pcie_fpga_rootpoint(i);
|
||||
if (ppc4xx_init_pcie_rootport(i)) {
|
||||
#endif
|
||||
printf("PCIE%d: initialization failed\n", i);
|
||||
continue;
|
||||
if (is_end_point(i)) {
|
||||
printf("PCIE%d: will be configured as endpoint\n",i);
|
||||
yucca_setup_pcie_fpga_endpoint(i);
|
||||
ret = ppc4xx_init_pcie_endport(i);
|
||||
} else {
|
||||
printf("PCIE%d: will be configured as root-complex\n",i);
|
||||
yucca_setup_pcie_fpga_rootpoint(i);
|
||||
ret = ppc4xx_init_pcie_rootport(i);
|
||||
}
|
||||
if (ret) {
|
||||
printf("PCIE%d: initialization failed\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
hose = &pcie_hose[i];
|
||||
hose->first_busno = bus;
|
||||
|
@ -881,35 +882,33 @@ void pcie_setup_hoses(int busno)
|
|||
CFG_PCIE_MEMBASE + i * CFG_PCIE_MEMSIZE,
|
||||
CFG_PCIE_MEMBASE + i * CFG_PCIE_MEMSIZE,
|
||||
CFG_PCIE_MEMSIZE,
|
||||
PCI_REGION_MEM
|
||||
);
|
||||
PCI_REGION_MEM);
|
||||
hose->region_count = 1;
|
||||
pci_register_hose(hose);
|
||||
|
||||
#ifdef PCIE_ENDPOINT
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Config access can only go down stream
|
||||
*/
|
||||
hose->last_busno = pci_hose_scan(hose);
|
||||
bus = hose->last_busno + 1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif /* defined(CONFIG_PCI) */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -244,6 +244,9 @@
|
|||
#define U64_TO_U32_LOW(val) ((u32)((val) & 0x00000000ffffffffULL))
|
||||
#define U64_TO_U32_HIGH(val) ((u32)((val) >> 32))
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
int ppc4xx_init_pcie(void);
|
||||
int ppc4xx_init_pcie_rootport(int port);
|
||||
int ppc4xx_init_pcie_endport(int port);
|
||||
|
@ -251,6 +254,55 @@ void ppc4xx_setup_pcie_rootpoint(struct pci_controller *hose, int port);
|
|||
int ppc4xx_setup_pcie_endpoint(struct pci_controller *hose, int port);
|
||||
int pcie_hose_scan(struct pci_controller *hose, int bus);
|
||||
|
||||
/*
|
||||
* Function to determine root port or endport from env variable.
|
||||
*/
|
||||
static inline int is_end_point(int port)
|
||||
{
|
||||
static char s[10], *tk;
|
||||
|
||||
strcpy(s, getenv("pcie_mode"));
|
||||
tk = strtok(s, ":");
|
||||
|
||||
switch (port) {
|
||||
case 0:
|
||||
if (tk != NULL) {
|
||||
if (!(strcmp(tk, "ep") && strcmp(tk, "EP")))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
|
||||
case 1:
|
||||
tk = strtok(NULL, ":");
|
||||
if (tk != NULL) {
|
||||
if (!(strcmp(tk, "ep") && strcmp(tk, "EP")))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
|
||||
case 2:
|
||||
tk = strtok(NULL, ":");
|
||||
if (tk != NULL)
|
||||
tk = strtok(NULL, ":");
|
||||
if (tk != NULL) {
|
||||
if (!(strcmp(tk, "ep") && strcmp(tk, "EP")))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void mdelay(int n)
|
||||
{
|
||||
u32 ms = n;
|
||||
|
|
|
@ -205,6 +205,7 @@
|
|||
"upd=run load;run update\0" \
|
||||
"kozio=bootm ffc60000\0" \
|
||||
"pciconfighost=1\0" \
|
||||
"pcie_mode=RP:RP:RP\0" \
|
||||
""
|
||||
#define CONFIG_BOOTCOMMAND "run flash_self"
|
||||
|
||||
|
|
|
@ -205,6 +205,7 @@
|
|||
"setenv filesize;saveenv\0" \
|
||||
"nupd=run nload nupdate\0" \
|
||||
"pciconfighost=1\0" \
|
||||
"pcie_mode=RP:RP\0" \
|
||||
""
|
||||
#define CONFIG_BOOTCOMMAND "run flash_self"
|
||||
|
||||
|
|
|
@ -186,6 +186,7 @@
|
|||
"setenv filesize;saveenv\0" \
|
||||
"upd=run load;run update\0" \
|
||||
"pciconfighost=1\0" \
|
||||
"pcie_mode=RP:EP:EP\0" \
|
||||
""
|
||||
#define CONFIG_BOOTCOMMAND "run flash_self"
|
||||
|
||||
|
|
Loading…
Reference in a new issue