From e90ddd813df7897af34226ed1cd442f7a182816e Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 2 May 2007 17:59:44 +0100 Subject: [PATCH] [ARM] 4348/4: iop3xx: Give Linux control over PCI initialization Currently the iop3xx platform support code assumes that RedBoot is the bootloader and has already initialized the ATU. Linux should handle this initialization for three reasons: 1/ The memory map that RedBoot sets up is not optimal (page_to_dma and virt_to_phys return different addresses). The effect of this is that using the dma mapping API for the internal bus dma units generates pci bus addresses that are incorrect for the internal bus. 2/ Not all iop platforms use RedBoot 3/ If the ATU is already initialized it indicates that the iop is an add-in card in another host, it does not own the PCI bus, and should not be re-initialized. Changelog: * rather than change nr_controllers to zero, simply do not call pci_common_init Cc: Lennert Buytenhek Signed-off-by: Dan Williams Signed-off-by: Russell King --- arch/arm/mach-iop32x/Kconfig | 8 ++ arch/arm/mach-iop32x/iq31244.c | 11 ++- arch/arm/mach-iop32x/iq80321.c | 3 +- arch/arm/mach-iop33x/Kconfig | 8 ++ arch/arm/mach-iop33x/iq80331.c | 3 +- arch/arm/mach-iop33x/iq80332.c | 3 +- arch/arm/plat-iop/pci.c | 140 ++++++++++++++++++++++++++- include/asm-arm/arch-iop32x/iop32x.h | 9 ++ include/asm-arm/arch-iop32x/memory.h | 4 +- include/asm-arm/arch-iop33x/iop33x.h | 10 ++ include/asm-arm/arch-iop33x/memory.h | 4 +- include/asm-arm/hardware/iop3xx.h | 22 ++++- 12 files changed, 209 insertions(+), 16 deletions(-) diff --git a/arch/arm/mach-iop32x/Kconfig b/arch/arm/mach-iop32x/Kconfig index 9dd49cff21ff..9bb02b6d7ae1 100644 --- a/arch/arm/mach-iop32x/Kconfig +++ b/arch/arm/mach-iop32x/Kconfig @@ -34,6 +34,14 @@ config MACH_N2100 Say Y here if you want to run your kernel on the Thecus n2100 NAS appliance. +config IOP3XX_ATU + bool "Enable the PCI Controller" + default y + help + Say Y here if you want the IOP to initialize its PCI Controller. + Say N if the IOP is an add in card, the host system owns the PCI + bus in this case. + endmenu endif diff --git a/arch/arm/mach-iop32x/iq31244.c b/arch/arm/mach-iop32x/iq31244.c index 60e74309a458..7b21c6e13e59 100644 --- a/arch/arm/mach-iop32x/iq31244.c +++ b/arch/arm/mach-iop32x/iq31244.c @@ -178,9 +178,10 @@ static struct hw_pci iq31244_pci __initdata = { static int __init iq31244_pci_init(void) { - if (is_ep80219()) - pci_common_init(&ep80219_pci); - else if (machine_is_iq31244()) { + if (is_ep80219()) { + if (iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) + pci_common_init(&ep80219_pci); + } else if (machine_is_iq31244()) { if (is_80219()) { printk("note: iq31244 board type has been selected\n"); printk("note: to select ep80219 operation:\n"); @@ -189,7 +190,9 @@ static int __init iq31244_pci_init(void) printk("\t2/ update boot loader to pass" " the ep80219 id: %d\n", MACH_TYPE_EP80219); } - pci_common_init(&iq31244_pci); + + if (iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) + pci_common_init(&iq31244_pci); } return 0; diff --git a/arch/arm/mach-iop32x/iq80321.c b/arch/arm/mach-iop32x/iq80321.c index 361c70c0f64c..bc25fb91e7b9 100644 --- a/arch/arm/mach-iop32x/iq80321.c +++ b/arch/arm/mach-iop32x/iq80321.c @@ -113,7 +113,8 @@ static struct hw_pci iq80321_pci __initdata = { static int __init iq80321_pci_init(void) { - if (machine_is_iq80321()) + if ((iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) && + machine_is_iq80321()) pci_common_init(&iq80321_pci); return 0; diff --git a/arch/arm/mach-iop33x/Kconfig b/arch/arm/mach-iop33x/Kconfig index 9aa016bb18f9..45598e096898 100644 --- a/arch/arm/mach-iop33x/Kconfig +++ b/arch/arm/mach-iop33x/Kconfig @@ -16,6 +16,14 @@ config MACH_IQ80332 Say Y here if you want to run your kernel on the Intel IQ80332 evaluation kit for the IOP332 chipset. +config IOP3XX_ATU + bool "Enable the PCI Controller" + default y + help + Say Y here if you want the IOP to initialize its PCI Controller. + Say N if the IOP is an add in card, the host system owns the PCI + bus in this case. + endmenu endif diff --git a/arch/arm/mach-iop33x/iq80331.c b/arch/arm/mach-iop33x/iq80331.c index 1a9e36138d80..376c932830be 100644 --- a/arch/arm/mach-iop33x/iq80331.c +++ b/arch/arm/mach-iop33x/iq80331.c @@ -96,7 +96,8 @@ static struct hw_pci iq80331_pci __initdata = { static int __init iq80331_pci_init(void) { - if (machine_is_iq80331()) + if ((iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) && + machine_is_iq80331()) pci_common_init(&iq80331_pci); return 0; diff --git a/arch/arm/mach-iop33x/iq80332.c b/arch/arm/mach-iop33x/iq80332.c index 96d6f0f3cd21..58c81496c6f6 100644 --- a/arch/arm/mach-iop33x/iq80332.c +++ b/arch/arm/mach-iop33x/iq80332.c @@ -96,7 +96,8 @@ static struct hw_pci iq80332_pci __initdata = { static int __init iq80332_pci_init(void) { - if (machine_is_iq80332()) + if ((iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) && + machine_is_iq80332()) pci_common_init(&iq80332_pci); return 0; diff --git a/arch/arm/plat-iop/pci.c b/arch/arm/plat-iop/pci.c index b5f6ec35aafb..e2744b7227c5 100644 --- a/arch/arm/plat-iop/pci.c +++ b/arch/arm/plat-iop/pci.c @@ -55,7 +55,7 @@ static u32 iop3xx_cfg_address(struct pci_bus *bus, int devfn, int where) * This routine checks the status of the last configuration cycle. If an error * was detected it returns a 1, else it returns a 0. The errors being checked * are parity, master abort, target abort (master and target). These types of - * errors occure during a config cycle where there is no device, like during + * errors occur during a config cycle where there is no device, like during * the discovery stage. */ static int iop3xx_pci_status(void) @@ -223,8 +223,111 @@ struct pci_bus *iop3xx_pci_scan_bus(int nr, struct pci_sys_data *sys) return pci_scan_bus(sys->busnr, &iop3xx_ops, sys); } +void __init iop3xx_atu_setup(void) +{ + /* BAR 0 ( Disabled ) */ + *IOP3XX_IAUBAR0 = 0x0; + *IOP3XX_IABAR0 = 0x0; + *IOP3XX_IATVR0 = 0x0; + *IOP3XX_IALR0 = 0x0; + + /* BAR 1 ( Disabled ) */ + *IOP3XX_IAUBAR1 = 0x0; + *IOP3XX_IABAR1 = 0x0; + *IOP3XX_IALR1 = 0x0; + + /* BAR 2 (1:1 mapping with Physical RAM) */ + /* Set limit and enable */ + *IOP3XX_IALR2 = ~((u32)IOP3XX_MAX_RAM_SIZE - 1) & ~0x1; + *IOP3XX_IAUBAR2 = 0x0; + + /* Align the inbound bar with the base of memory */ + *IOP3XX_IABAR2 = PHYS_OFFSET | + PCI_BASE_ADDRESS_MEM_TYPE_64 | + PCI_BASE_ADDRESS_MEM_PREFETCH; + + *IOP3XX_IATVR2 = PHYS_OFFSET; + + /* Outbound window 0 */ + *IOP3XX_OMWTVR0 = IOP3XX_PCI_LOWER_MEM_PA; + *IOP3XX_OUMWTVR0 = 0; + + /* Outbound window 1 */ + *IOP3XX_OMWTVR1 = IOP3XX_PCI_LOWER_MEM_PA + IOP3XX_PCI_MEM_WINDOW_SIZE; + *IOP3XX_OUMWTVR1 = 0; + + /* BAR 3 ( Disabled ) */ + *IOP3XX_IAUBAR3 = 0x0; + *IOP3XX_IABAR3 = 0x0; + *IOP3XX_IATVR3 = 0x0; + *IOP3XX_IALR3 = 0x0; + + /* Setup the I/O Bar + */ + *IOP3XX_OIOWTVR = IOP3XX_PCI_LOWER_IO_PA;; + + /* Enable inbound and outbound cycles + */ + *IOP3XX_ATUCMD |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | + PCI_COMMAND_PARITY | PCI_COMMAND_SERR; + *IOP3XX_ATUCR |= IOP3XX_ATUCR_OUT_EN; +} + +void __init iop3xx_atu_disable(void) +{ + *IOP3XX_ATUCMD = 0; + *IOP3XX_ATUCR = 0; + + /* wait for cycles to quiesce */ + while (*IOP3XX_PCSR & (IOP3XX_PCSR_OUT_Q_BUSY | + IOP3XX_PCSR_IN_Q_BUSY)) + cpu_relax(); + + /* BAR 0 ( Disabled ) */ + *IOP3XX_IAUBAR0 = 0x0; + *IOP3XX_IABAR0 = 0x0; + *IOP3XX_IATVR0 = 0x0; + *IOP3XX_IALR0 = 0x0; + + /* BAR 1 ( Disabled ) */ + *IOP3XX_IAUBAR1 = 0x0; + *IOP3XX_IABAR1 = 0x0; + *IOP3XX_IALR1 = 0x0; + + /* BAR 2 ( Disabled ) */ + *IOP3XX_IAUBAR2 = 0x0; + *IOP3XX_IABAR2 = 0x0; + *IOP3XX_IATVR2 = 0x0; + *IOP3XX_IALR2 = 0x0; + + /* BAR 3 ( Disabled ) */ + *IOP3XX_IAUBAR3 = 0x0; + *IOP3XX_IABAR3 = 0x0; + *IOP3XX_IATVR3 = 0x0; + *IOP3XX_IALR3 = 0x0; + + /* Clear the outbound windows */ + *IOP3XX_OIOWTVR = 0; + + /* Outbound window 0 */ + *IOP3XX_OMWTVR0 = 0; + *IOP3XX_OUMWTVR0 = 0; + + /* Outbound window 1 */ + *IOP3XX_OMWTVR1 = 0; + *IOP3XX_OUMWTVR1 = 0; +} + +/* Flag to determine whether the ATU is initialized and the PCI bus scanned */ +int init_atu; + void iop3xx_pci_preinit(void) { + if (iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) { + iop3xx_atu_disable(); + iop3xx_atu_setup(); + } + DBG("PCI: Intel 803xx PCI init code.\n"); DBG("ATU: IOP3XX_ATUCMD=0x%04x\n", *IOP3XX_ATUCMD); DBG("ATU: IOP3XX_OMWTVR0=0x%04x, IOP3XX_OIOWTVR=0x%04x\n", @@ -245,3 +348,38 @@ void iop3xx_pci_preinit(void) hook_fault_code(16+6, iop3xx_pci_abort, SIGBUS, "imprecise external abort"); } + +/* allow init_atu to be user overridden */ +static int __init iop3xx_init_atu_setup(char *str) +{ + init_atu = IOP3XX_INIT_ATU_DEFAULT; + if (str) { + while (*str != '\0') { + switch (*str) { + case 'y': + case 'Y': + init_atu = IOP3XX_INIT_ATU_ENABLE; + break; + case 'n': + case 'N': + init_atu = IOP3XX_INIT_ATU_DISABLE; + break; + case ',': + case '=': + break; + default: + printk(KERN_DEBUG "\"%s\" malformed at " + "character: \'%c\'", + __FUNCTION__, + *str); + *(str + 1) = '\0'; + } + str++; + } + } + + return 1; +} + +__setup("iop3xx_init_atu", iop3xx_init_atu_setup); + diff --git a/include/asm-arm/arch-iop32x/iop32x.h b/include/asm-arm/arch-iop32x/iop32x.h index 2e9469047eb1..0d8af57221a1 100644 --- a/include/asm-arm/arch-iop32x/iop32x.h +++ b/include/asm-arm/arch-iop32x/iop32x.h @@ -24,5 +24,14 @@ #include +/* ATU Parameters + * set up a 1:1 bus to physical ram relationship + * w/ physical ram on top of pci in the memory map + */ +#define IOP32X_MAX_RAM_SIZE 0x40000000UL +#define IOP3XX_MAX_RAM_SIZE IOP32X_MAX_RAM_SIZE +#define IOP3XX_PCI_LOWER_MEM_BA 0x80000000 +#define IOP32X_PCI_MEM_WINDOW_SIZE 0x04000000 +#define IOP3XX_PCI_MEM_WINDOW_SIZE IOP32X_PCI_MEM_WINDOW_SIZE #endif diff --git a/include/asm-arm/arch-iop32x/memory.h b/include/asm-arm/arch-iop32x/memory.h index 764cd3f0d416..c51072af214e 100644 --- a/include/asm-arm/arch-iop32x/memory.h +++ b/include/asm-arm/arch-iop32x/memory.h @@ -19,8 +19,8 @@ * bus_to_virt: Used to convert an address for DMA operations * to an address that the kernel can use. */ -#define __virt_to_bus(x) (((__virt_to_phys(x)) & ~(*IOP3XX_IATVR2)) | ((*IOP3XX_IABAR2) & 0xfffffff0)) -#define __bus_to_virt(x) (__phys_to_virt(((x) & ~(*IOP3XX_IALR2)) | ( *IOP3XX_IATVR2))) +#define __virt_to_bus(x) (__virt_to_phys(x)) +#define __bus_to_virt(x) (__phys_to_virt(x)) #endif diff --git a/include/asm-arm/arch-iop33x/iop33x.h b/include/asm-arm/arch-iop33x/iop33x.h index 7ac6e93db5ff..766985b9a723 100644 --- a/include/asm-arm/arch-iop33x/iop33x.h +++ b/include/asm-arm/arch-iop33x/iop33x.h @@ -29,5 +29,15 @@ #define IOP33X_UART1_PHYS (IOP3XX_PERIPHERAL_PHYS_BASE + 0x1740) #define IOP33X_UART1_VIRT (IOP3XX_PERIPHERAL_VIRT_BASE + 0x1740) +/* ATU Parameters + * set up a 1:1 bus to physical ram relationship + * w/ pci on top of physical ram in memory map + */ +#define IOP33X_MAX_RAM_SIZE 0x80000000UL +#define IOP3XX_MAX_RAM_SIZE IOP33X_MAX_RAM_SIZE +#define IOP3XX_PCI_LOWER_MEM_BA (PHYS_OFFSET + IOP33X_MAX_RAM_SIZE) +#define IOP33X_PCI_MEM_WINDOW_SIZE 0x08000000 +#define IOP3XX_PCI_MEM_WINDOW_SIZE IOP33X_PCI_MEM_WINDOW_SIZE + #endif diff --git a/include/asm-arm/arch-iop33x/memory.h b/include/asm-arm/arch-iop33x/memory.h index 0d39139b241e..c8749127d6ab 100644 --- a/include/asm-arm/arch-iop33x/memory.h +++ b/include/asm-arm/arch-iop33x/memory.h @@ -19,8 +19,8 @@ * bus_to_virt: Used to convert an address for DMA operations * to an address that the kernel can use. */ -#define __virt_to_bus(x) (((__virt_to_phys(x)) & ~(*IOP3XX_IATVR2)) | ((*IOP3XX_IABAR2) & 0xfffffff0)) -#define __bus_to_virt(x) (__phys_to_virt(((x) & ~(*IOP3XX_IALR2)) | ( *IOP3XX_IATVR2))) +#define __virt_to_bus(x) (__virt_to_phys(x)) +#define __bus_to_virt(x) (__phys_to_virt(x)) #endif diff --git a/include/asm-arm/hardware/iop3xx.h b/include/asm-arm/hardware/iop3xx.h index 15141a9caca8..ebbcd9be3fe5 100644 --- a/include/asm-arm/hardware/iop3xx.h +++ b/include/asm-arm/hardware/iop3xx.h @@ -28,6 +28,7 @@ extern void gpio_line_config(int line, int direction); extern int gpio_line_get(int line); extern void gpio_line_set(int line, int value); +extern int init_atu; #endif @@ -103,6 +104,21 @@ extern void gpio_line_set(int line, int value); #define IOP3XX_PCIXCMD (volatile u16 *)IOP3XX_REG_ADDR(0x01e2) #define IOP3XX_PCIXSR (volatile u32 *)IOP3XX_REG_ADDR(0x01e4) #define IOP3XX_PCIIRSR (volatile u32 *)IOP3XX_REG_ADDR(0x01ec) +#define IOP3XX_PCSR_OUT_Q_BUSY (1 << 15) +#define IOP3XX_PCSR_IN_Q_BUSY (1 << 14) +#define IOP3XX_ATUCR_OUT_EN (1 << 1) + +#define IOP3XX_INIT_ATU_DEFAULT 0 +#define IOP3XX_INIT_ATU_DISABLE -1 +#define IOP3XX_INIT_ATU_ENABLE 1 + +#ifdef CONFIG_IOP3XX_ATU +#define iop3xx_get_init_atu(x) (init_atu == IOP3XX_INIT_ATU_DEFAULT ?\ + IOP3XX_INIT_ATU_ENABLE : init_atu) +#else +#define iop3xx_get_init_atu(x) (init_atu == IOP3XX_INIT_ATU_DEFAULT ?\ + IOP3XX_INIT_ATU_DISABLE : init_atu) +#endif /* Messaging Unit */ #define IOP3XX_IMR0 (volatile u32 *)IOP3XX_REG_ADDR(0x0310) @@ -253,14 +269,12 @@ extern void gpio_line_set(int line, int value); /* * IOP3XX I/O and Mem space regions for PCI autoconfiguration */ -#define IOP3XX_PCI_MEM_WINDOW_SIZE 0x04000000 -#define IOP3XX_PCI_LOWER_MEM_PA 0x80000000 -#define IOP3XX_PCI_LOWER_MEM_BA (*IOP3XX_OMWTVR0) +#define IOP3XX_PCI_LOWER_MEM_PA 0x80000000 #define IOP3XX_PCI_IO_WINDOW_SIZE 0x00010000 #define IOP3XX_PCI_LOWER_IO_PA 0x90000000 #define IOP3XX_PCI_LOWER_IO_VA 0xfe000000 -#define IOP3XX_PCI_LOWER_IO_BA (*IOP3XX_OIOWTVR) +#define IOP3XX_PCI_LOWER_IO_BA 0x90000000 #define IOP3XX_PCI_UPPER_IO_PA (IOP3XX_PCI_LOWER_IO_PA +\ IOP3XX_PCI_IO_WINDOW_SIZE - 1) #define IOP3XX_PCI_UPPER_IO_VA (IOP3XX_PCI_LOWER_IO_VA +\ -- GitLab