| /* |
| * This file is subject to the terms and conditions of the GNU General Public |
| * License. See the file "COPYING" in the main directory of this archive |
| * for more details. |
| * |
| * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org) |
| */ |
| |
| #include <linux/types.h> |
| #include <linux/pci.h> |
| #include <asm/mv64340.h> |
| |
| #include <linux/init.h> |
| |
| /* |
| * We assume the address ranges have already been setup appropriately by |
| * the firmware. PMON in case of the Ocelot C does that. |
| */ |
| static struct resource mv_pci_io_mem0_resource = { |
| .name = "MV64340 PCI0 IO MEM", |
| .flags = IORESOURCE_IO |
| }; |
| |
| static struct resource mv_pci_mem0_resource = { |
| .name = "MV64340 PCI0 MEM", |
| .flags = IORESOURCE_MEM |
| }; |
| |
| static struct mv_pci_controller mv_bus0_controller = { |
| .pcic = { |
| .pci_ops = &mv_pci_ops, |
| .mem_resource = &mv_pci_mem0_resource, |
| .io_resource = &mv_pci_io_mem0_resource, |
| }, |
| .config_addr = MV64340_PCI_0_CONFIG_ADDR, |
| .config_vreg = MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG, |
| }; |
| |
| static uint32_t mv_io_base, mv_io_size; |
| |
| static void mv64340_pci0_init(void) |
| { |
| uint32_t mem0_base, mem0_size; |
| uint32_t io_base, io_size; |
| |
| io_base = MV_READ(MV64340_PCI_0_IO_BASE_ADDR) << 16; |
| io_size = (MV_READ(MV64340_PCI_0_IO_SIZE) + 1) << 16; |
| mem0_base = MV_READ(MV64340_PCI_0_MEMORY0_BASE_ADDR) << 16; |
| mem0_size = (MV_READ(MV64340_PCI_0_MEMORY0_SIZE) + 1) << 16; |
| |
| mv_pci_io_mem0_resource.start = 0; |
| mv_pci_io_mem0_resource.end = io_size - 1; |
| mv_pci_mem0_resource.start = mem0_base; |
| mv_pci_mem0_resource.end = mem0_base + mem0_size - 1; |
| mv_bus0_controller.pcic.mem_offset = mem0_base; |
| mv_bus0_controller.pcic.io_offset = 0; |
| |
| ioport_resource.end = io_size - 1; |
| |
| register_pci_controller(&mv_bus0_controller.pcic); |
| |
| mv_io_base = io_base; |
| mv_io_size = io_size; |
| } |
| |
| static struct resource mv_pci_io_mem1_resource = { |
| .name = "MV64340 PCI1 IO MEM", |
| .flags = IORESOURCE_IO |
| }; |
| |
| static struct resource mv_pci_mem1_resource = { |
| .name = "MV64340 PCI1 MEM", |
| .flags = IORESOURCE_MEM |
| }; |
| |
| static struct mv_pci_controller mv_bus1_controller = { |
| .pcic = { |
| .pci_ops = &mv_pci_ops, |
| .mem_resource = &mv_pci_mem1_resource, |
| .io_resource = &mv_pci_io_mem1_resource, |
| }, |
| .config_addr = MV64340_PCI_1_CONFIG_ADDR, |
| .config_vreg = MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG, |
| }; |
| |
| static __init void mv64340_pci1_init(void) |
| { |
| uint32_t mem0_base, mem0_size; |
| uint32_t io_base, io_size; |
| |
| io_base = MV_READ(MV64340_PCI_1_IO_BASE_ADDR) << 16; |
| io_size = (MV_READ(MV64340_PCI_1_IO_SIZE) + 1) << 16; |
| mem0_base = MV_READ(MV64340_PCI_1_MEMORY0_BASE_ADDR) << 16; |
| mem0_size = (MV_READ(MV64340_PCI_1_MEMORY0_SIZE) + 1) << 16; |
| |
| /* |
| * Here we assume the I/O window of second bus to be contiguous with |
| * the first. A gap is no problem but would waste address space for |
| * remapping the port space. |
| */ |
| mv_pci_io_mem1_resource.start = mv_io_size; |
| mv_pci_io_mem1_resource.end = mv_io_size + io_size - 1; |
| mv_pci_mem1_resource.start = mem0_base; |
| mv_pci_mem1_resource.end = mem0_base + mem0_size - 1; |
| mv_bus1_controller.pcic.mem_offset = mem0_base; |
| mv_bus1_controller.pcic.io_offset = 0; |
| |
| ioport_resource.end = io_base + io_size -mv_io_base - 1; |
| |
| register_pci_controller(&mv_bus1_controller.pcic); |
| |
| mv_io_size = io_base + io_size - mv_io_base; |
| } |
| |
| static __init int __init ocelot_c_pci_init(void) |
| { |
| unsigned long io_v_base; |
| uint32_t enable; |
| |
| enable = ~MV_READ(MV64340_BASE_ADDR_ENABLE); |
| |
| /* |
| * We require at least one enabled I/O or PCI memory window or we |
| * will ignore this PCI bus. We ignore PCI windows 1, 2 and 3. |
| */ |
| if (enable & (0x01 << 9) || enable & (0x01 << 10)) |
| mv64340_pci0_init(); |
| |
| if (enable & (0x01 << 14) || enable & (0x01 << 15)) |
| mv64340_pci1_init(); |
| |
| if (mv_io_size) { |
| io_v_base = (unsigned long) ioremap(mv_io_base, mv_io_size); |
| if (!io_v_base) |
| panic("Could not ioremap I/O port range"); |
| |
| set_io_port_base(io_v_base); |
| } |
| |
| return 0; |
| } |
| |
| arch_initcall(ocelot_c_pci_init); |