Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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 <kernel@wantstofly.org>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

authored by

Dan Williams and committed by
Russell King
e90ddd81 fa543f00

+209 -16
+8
arch/arm/mach-iop32x/Kconfig
··· 34 34 Say Y here if you want to run your kernel on the Thecus n2100 35 35 NAS appliance. 36 36 37 + config IOP3XX_ATU 38 + bool "Enable the PCI Controller" 39 + default y 40 + help 41 + Say Y here if you want the IOP to initialize its PCI Controller. 42 + Say N if the IOP is an add in card, the host system owns the PCI 43 + bus in this case. 44 + 37 45 endmenu 38 46 39 47 endif
+7 -4
arch/arm/mach-iop32x/iq31244.c
··· 178 178 179 179 static int __init iq31244_pci_init(void) 180 180 { 181 - if (is_ep80219()) 182 - pci_common_init(&ep80219_pci); 183 - else if (machine_is_iq31244()) { 181 + if (is_ep80219()) { 182 + if (iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) 183 + pci_common_init(&ep80219_pci); 184 + } else if (machine_is_iq31244()) { 184 185 if (is_80219()) { 185 186 printk("note: iq31244 board type has been selected\n"); 186 187 printk("note: to select ep80219 operation:\n"); ··· 190 189 printk("\t2/ update boot loader to pass" 191 190 " the ep80219 id: %d\n", MACH_TYPE_EP80219); 192 191 } 193 - pci_common_init(&iq31244_pci); 192 + 193 + if (iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) 194 + pci_common_init(&iq31244_pci); 194 195 } 195 196 196 197 return 0;
+2 -1
arch/arm/mach-iop32x/iq80321.c
··· 113 113 114 114 static int __init iq80321_pci_init(void) 115 115 { 116 - if (machine_is_iq80321()) 116 + if ((iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) && 117 + machine_is_iq80321()) 117 118 pci_common_init(&iq80321_pci); 118 119 119 120 return 0;
+8
arch/arm/mach-iop33x/Kconfig
··· 16 16 Say Y here if you want to run your kernel on the Intel IQ80332 17 17 evaluation kit for the IOP332 chipset. 18 18 19 + config IOP3XX_ATU 20 + bool "Enable the PCI Controller" 21 + default y 22 + help 23 + Say Y here if you want the IOP to initialize its PCI Controller. 24 + Say N if the IOP is an add in card, the host system owns the PCI 25 + bus in this case. 26 + 19 27 endmenu 20 28 21 29 endif
+2 -1
arch/arm/mach-iop33x/iq80331.c
··· 96 96 97 97 static int __init iq80331_pci_init(void) 98 98 { 99 - if (machine_is_iq80331()) 99 + if ((iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) && 100 + machine_is_iq80331()) 100 101 pci_common_init(&iq80331_pci); 101 102 102 103 return 0;
+2 -1
arch/arm/mach-iop33x/iq80332.c
··· 96 96 97 97 static int __init iq80332_pci_init(void) 98 98 { 99 - if (machine_is_iq80332()) 99 + if ((iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) && 100 + machine_is_iq80332()) 100 101 pci_common_init(&iq80332_pci); 101 102 102 103 return 0;
+139 -1
arch/arm/plat-iop/pci.c
··· 55 55 * This routine checks the status of the last configuration cycle. If an error 56 56 * was detected it returns a 1, else it returns a 0. The errors being checked 57 57 * are parity, master abort, target abort (master and target). These types of 58 - * errors occure during a config cycle where there is no device, like during 58 + * errors occur during a config cycle where there is no device, like during 59 59 * the discovery stage. 60 60 */ 61 61 static int iop3xx_pci_status(void) ··· 223 223 return pci_scan_bus(sys->busnr, &iop3xx_ops, sys); 224 224 } 225 225 226 + void __init iop3xx_atu_setup(void) 227 + { 228 + /* BAR 0 ( Disabled ) */ 229 + *IOP3XX_IAUBAR0 = 0x0; 230 + *IOP3XX_IABAR0 = 0x0; 231 + *IOP3XX_IATVR0 = 0x0; 232 + *IOP3XX_IALR0 = 0x0; 233 + 234 + /* BAR 1 ( Disabled ) */ 235 + *IOP3XX_IAUBAR1 = 0x0; 236 + *IOP3XX_IABAR1 = 0x0; 237 + *IOP3XX_IALR1 = 0x0; 238 + 239 + /* BAR 2 (1:1 mapping with Physical RAM) */ 240 + /* Set limit and enable */ 241 + *IOP3XX_IALR2 = ~((u32)IOP3XX_MAX_RAM_SIZE - 1) & ~0x1; 242 + *IOP3XX_IAUBAR2 = 0x0; 243 + 244 + /* Align the inbound bar with the base of memory */ 245 + *IOP3XX_IABAR2 = PHYS_OFFSET | 246 + PCI_BASE_ADDRESS_MEM_TYPE_64 | 247 + PCI_BASE_ADDRESS_MEM_PREFETCH; 248 + 249 + *IOP3XX_IATVR2 = PHYS_OFFSET; 250 + 251 + /* Outbound window 0 */ 252 + *IOP3XX_OMWTVR0 = IOP3XX_PCI_LOWER_MEM_PA; 253 + *IOP3XX_OUMWTVR0 = 0; 254 + 255 + /* Outbound window 1 */ 256 + *IOP3XX_OMWTVR1 = IOP3XX_PCI_LOWER_MEM_PA + IOP3XX_PCI_MEM_WINDOW_SIZE; 257 + *IOP3XX_OUMWTVR1 = 0; 258 + 259 + /* BAR 3 ( Disabled ) */ 260 + *IOP3XX_IAUBAR3 = 0x0; 261 + *IOP3XX_IABAR3 = 0x0; 262 + *IOP3XX_IATVR3 = 0x0; 263 + *IOP3XX_IALR3 = 0x0; 264 + 265 + /* Setup the I/O Bar 266 + */ 267 + *IOP3XX_OIOWTVR = IOP3XX_PCI_LOWER_IO_PA;; 268 + 269 + /* Enable inbound and outbound cycles 270 + */ 271 + *IOP3XX_ATUCMD |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | 272 + PCI_COMMAND_PARITY | PCI_COMMAND_SERR; 273 + *IOP3XX_ATUCR |= IOP3XX_ATUCR_OUT_EN; 274 + } 275 + 276 + void __init iop3xx_atu_disable(void) 277 + { 278 + *IOP3XX_ATUCMD = 0; 279 + *IOP3XX_ATUCR = 0; 280 + 281 + /* wait for cycles to quiesce */ 282 + while (*IOP3XX_PCSR & (IOP3XX_PCSR_OUT_Q_BUSY | 283 + IOP3XX_PCSR_IN_Q_BUSY)) 284 + cpu_relax(); 285 + 286 + /* BAR 0 ( Disabled ) */ 287 + *IOP3XX_IAUBAR0 = 0x0; 288 + *IOP3XX_IABAR0 = 0x0; 289 + *IOP3XX_IATVR0 = 0x0; 290 + *IOP3XX_IALR0 = 0x0; 291 + 292 + /* BAR 1 ( Disabled ) */ 293 + *IOP3XX_IAUBAR1 = 0x0; 294 + *IOP3XX_IABAR1 = 0x0; 295 + *IOP3XX_IALR1 = 0x0; 296 + 297 + /* BAR 2 ( Disabled ) */ 298 + *IOP3XX_IAUBAR2 = 0x0; 299 + *IOP3XX_IABAR2 = 0x0; 300 + *IOP3XX_IATVR2 = 0x0; 301 + *IOP3XX_IALR2 = 0x0; 302 + 303 + /* BAR 3 ( Disabled ) */ 304 + *IOP3XX_IAUBAR3 = 0x0; 305 + *IOP3XX_IABAR3 = 0x0; 306 + *IOP3XX_IATVR3 = 0x0; 307 + *IOP3XX_IALR3 = 0x0; 308 + 309 + /* Clear the outbound windows */ 310 + *IOP3XX_OIOWTVR = 0; 311 + 312 + /* Outbound window 0 */ 313 + *IOP3XX_OMWTVR0 = 0; 314 + *IOP3XX_OUMWTVR0 = 0; 315 + 316 + /* Outbound window 1 */ 317 + *IOP3XX_OMWTVR1 = 0; 318 + *IOP3XX_OUMWTVR1 = 0; 319 + } 320 + 321 + /* Flag to determine whether the ATU is initialized and the PCI bus scanned */ 322 + int init_atu; 323 + 226 324 void iop3xx_pci_preinit(void) 227 325 { 326 + if (iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) { 327 + iop3xx_atu_disable(); 328 + iop3xx_atu_setup(); 329 + } 330 + 228 331 DBG("PCI: Intel 803xx PCI init code.\n"); 229 332 DBG("ATU: IOP3XX_ATUCMD=0x%04x\n", *IOP3XX_ATUCMD); 230 333 DBG("ATU: IOP3XX_OMWTVR0=0x%04x, IOP3XX_OIOWTVR=0x%04x\n", ··· 348 245 349 246 hook_fault_code(16+6, iop3xx_pci_abort, SIGBUS, "imprecise external abort"); 350 247 } 248 + 249 + /* allow init_atu to be user overridden */ 250 + static int __init iop3xx_init_atu_setup(char *str) 251 + { 252 + init_atu = IOP3XX_INIT_ATU_DEFAULT; 253 + if (str) { 254 + while (*str != '\0') { 255 + switch (*str) { 256 + case 'y': 257 + case 'Y': 258 + init_atu = IOP3XX_INIT_ATU_ENABLE; 259 + break; 260 + case 'n': 261 + case 'N': 262 + init_atu = IOP3XX_INIT_ATU_DISABLE; 263 + break; 264 + case ',': 265 + case '=': 266 + break; 267 + default: 268 + printk(KERN_DEBUG "\"%s\" malformed at " 269 + "character: \'%c\'", 270 + __FUNCTION__, 271 + *str); 272 + *(str + 1) = '\0'; 273 + } 274 + str++; 275 + } 276 + } 277 + 278 + return 1; 279 + } 280 + 281 + __setup("iop3xx_init_atu", iop3xx_init_atu_setup); 282 +
+9
include/asm-arm/arch-iop32x/iop32x.h
··· 24 24 25 25 #include <asm/hardware/iop3xx.h> 26 26 27 + /* ATU Parameters 28 + * set up a 1:1 bus to physical ram relationship 29 + * w/ physical ram on top of pci in the memory map 30 + */ 31 + #define IOP32X_MAX_RAM_SIZE 0x40000000UL 32 + #define IOP3XX_MAX_RAM_SIZE IOP32X_MAX_RAM_SIZE 33 + #define IOP3XX_PCI_LOWER_MEM_BA 0x80000000 34 + #define IOP32X_PCI_MEM_WINDOW_SIZE 0x04000000 35 + #define IOP3XX_PCI_MEM_WINDOW_SIZE IOP32X_PCI_MEM_WINDOW_SIZE 27 36 28 37 #endif
+2 -2
include/asm-arm/arch-iop32x/memory.h
··· 19 19 * bus_to_virt: Used to convert an address for DMA operations 20 20 * to an address that the kernel can use. 21 21 */ 22 - #define __virt_to_bus(x) (((__virt_to_phys(x)) & ~(*IOP3XX_IATVR2)) | ((*IOP3XX_IABAR2) & 0xfffffff0)) 23 - #define __bus_to_virt(x) (__phys_to_virt(((x) & ~(*IOP3XX_IALR2)) | ( *IOP3XX_IATVR2))) 22 + #define __virt_to_bus(x) (__virt_to_phys(x)) 23 + #define __bus_to_virt(x) (__phys_to_virt(x)) 24 24 25 25 26 26 #endif
+10
include/asm-arm/arch-iop33x/iop33x.h
··· 29 29 #define IOP33X_UART1_PHYS (IOP3XX_PERIPHERAL_PHYS_BASE + 0x1740) 30 30 #define IOP33X_UART1_VIRT (IOP3XX_PERIPHERAL_VIRT_BASE + 0x1740) 31 31 32 + /* ATU Parameters 33 + * set up a 1:1 bus to physical ram relationship 34 + * w/ pci on top of physical ram in memory map 35 + */ 36 + #define IOP33X_MAX_RAM_SIZE 0x80000000UL 37 + #define IOP3XX_MAX_RAM_SIZE IOP33X_MAX_RAM_SIZE 38 + #define IOP3XX_PCI_LOWER_MEM_BA (PHYS_OFFSET + IOP33X_MAX_RAM_SIZE) 39 + #define IOP33X_PCI_MEM_WINDOW_SIZE 0x08000000 40 + #define IOP3XX_PCI_MEM_WINDOW_SIZE IOP33X_PCI_MEM_WINDOW_SIZE 41 + 32 42 33 43 #endif
+2 -2
include/asm-arm/arch-iop33x/memory.h
··· 19 19 * bus_to_virt: Used to convert an address for DMA operations 20 20 * to an address that the kernel can use. 21 21 */ 22 - #define __virt_to_bus(x) (((__virt_to_phys(x)) & ~(*IOP3XX_IATVR2)) | ((*IOP3XX_IABAR2) & 0xfffffff0)) 23 - #define __bus_to_virt(x) (__phys_to_virt(((x) & ~(*IOP3XX_IALR2)) | ( *IOP3XX_IATVR2))) 22 + #define __virt_to_bus(x) (__virt_to_phys(x)) 23 + #define __bus_to_virt(x) (__phys_to_virt(x)) 24 24 25 25 26 26 #endif
+18 -4
include/asm-arm/hardware/iop3xx.h
··· 28 28 extern void gpio_line_config(int line, int direction); 29 29 extern int gpio_line_get(int line); 30 30 extern void gpio_line_set(int line, int value); 31 + extern int init_atu; 31 32 #endif 32 33 33 34 ··· 104 103 #define IOP3XX_PCIXCMD (volatile u16 *)IOP3XX_REG_ADDR(0x01e2) 105 104 #define IOP3XX_PCIXSR (volatile u32 *)IOP3XX_REG_ADDR(0x01e4) 106 105 #define IOP3XX_PCIIRSR (volatile u32 *)IOP3XX_REG_ADDR(0x01ec) 106 + #define IOP3XX_PCSR_OUT_Q_BUSY (1 << 15) 107 + #define IOP3XX_PCSR_IN_Q_BUSY (1 << 14) 108 + #define IOP3XX_ATUCR_OUT_EN (1 << 1) 109 + 110 + #define IOP3XX_INIT_ATU_DEFAULT 0 111 + #define IOP3XX_INIT_ATU_DISABLE -1 112 + #define IOP3XX_INIT_ATU_ENABLE 1 113 + 114 + #ifdef CONFIG_IOP3XX_ATU 115 + #define iop3xx_get_init_atu(x) (init_atu == IOP3XX_INIT_ATU_DEFAULT ?\ 116 + IOP3XX_INIT_ATU_ENABLE : init_atu) 117 + #else 118 + #define iop3xx_get_init_atu(x) (init_atu == IOP3XX_INIT_ATU_DEFAULT ?\ 119 + IOP3XX_INIT_ATU_DISABLE : init_atu) 120 + #endif 107 121 108 122 /* Messaging Unit */ 109 123 #define IOP3XX_IMR0 (volatile u32 *)IOP3XX_REG_ADDR(0x0310) ··· 269 253 /* 270 254 * IOP3XX I/O and Mem space regions for PCI autoconfiguration 271 255 */ 272 - #define IOP3XX_PCI_MEM_WINDOW_SIZE 0x04000000 273 - #define IOP3XX_PCI_LOWER_MEM_PA 0x80000000 274 - #define IOP3XX_PCI_LOWER_MEM_BA (*IOP3XX_OMWTVR0) 256 + #define IOP3XX_PCI_LOWER_MEM_PA 0x80000000 275 257 276 258 #define IOP3XX_PCI_IO_WINDOW_SIZE 0x00010000 277 259 #define IOP3XX_PCI_LOWER_IO_PA 0x90000000 278 260 #define IOP3XX_PCI_LOWER_IO_VA 0xfe000000 279 - #define IOP3XX_PCI_LOWER_IO_BA (*IOP3XX_OIOWTVR) 261 + #define IOP3XX_PCI_LOWER_IO_BA 0x90000000 280 262 #define IOP3XX_PCI_UPPER_IO_PA (IOP3XX_PCI_LOWER_IO_PA +\ 281 263 IOP3XX_PCI_IO_WINDOW_SIZE - 1) 282 264 #define IOP3XX_PCI_UPPER_IO_VA (IOP3XX_PCI_LOWER_IO_VA +\