1 /* 2 * leon_pci.c: LEON Host PCI support 3 * 4 * Copyright (C) 2011 Aeroflex Gaisler AB, Daniel Hellstrom 5 * 6 * Code is partially derived from pcic.c 7 */ 8 9 #include <linux/of_device.h> 10 #include <linux/kernel.h> 11 #include <linux/pci.h> 12 #include <linux/export.h> 13 #include <asm/leon.h> 14 #include <asm/leon_pci.h> 15 16 /* The LEON architecture does not rely on a BIOS or bootloader to setup 17 * PCI for us. The Linux generic routines are used to setup resources, 18 * reset values of confuration-space registers settings ae preseved. 19 */ 20 void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info) 21 { 22 LIST_HEAD(resources); 23 struct pci_bus *root_bus; 24 25 pci_add_resource(&resources, &info->io_space); 26 pci_add_resource(&resources, &info->mem_space); 27 28 root_bus = pci_scan_root_bus(&ofdev->dev, 0, info->ops, info, 29 &resources); 30 if (root_bus) { 31 /* Setup IRQs of all devices using custom routines */ 32 pci_fixup_irqs(pci_common_swizzle, info->map_irq); 33 34 /* Assign devices with resources */ 35 pci_assign_unassigned_resources(); 36 } else { 37 pci_free_resource_list(&resources); 38 } 39 } 40 41 /* PCI Memory and Prefetchable Memory is direct-mapped. However I/O Space is 42 * accessed through a Window which is translated to low 64KB in PCI space, the 43 * first 4KB is not used so 60KB is available. 44 * 45 * This function is used by generic code to translate resource addresses into 46 * PCI addresses. 47 */ 48 void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, 49 struct resource *res) 50 { 51 struct leon_pci_info *info = dev->bus->sysdata; 52 53 region->start = res->start; 54 region->end = res->end; 55 56 if (res->flags & IORESOURCE_IO) { 57 region->start -= (info->io_space.start - 0x1000); 58 region->end -= (info->io_space.start - 0x1000); 59 } 60 } 61 EXPORT_SYMBOL(pcibios_resource_to_bus); 62 63 /* see pcibios_resource_to_bus() comment */ 64 void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, 65 struct pci_bus_region *region) 66 { 67 struct leon_pci_info *info = dev->bus->sysdata; 68 69 res->start = region->start; 70 res->end = region->end; 71 72 if (res->flags & IORESOURCE_IO) { 73 res->start += (info->io_space.start - 0x1000); 74 res->end += (info->io_space.start - 0x1000); 75 } 76 } 77 EXPORT_SYMBOL(pcibios_bus_to_resource); 78 79 void __devinit pcibios_fixup_bus(struct pci_bus *pbus) 80 { 81 struct leon_pci_info *info = pbus->sysdata; 82 struct pci_dev *dev; 83 int i, has_io, has_mem; 84 u16 cmd; 85 86 list_for_each_entry(dev, &pbus->devices, bus_list) { 87 /* 88 * We can not rely on that the bootloader has enabled I/O 89 * or memory access to PCI devices. Instead we enable it here 90 * if the device has BARs of respective type. 91 */ 92 has_io = has_mem = 0; 93 for (i = 0; i < PCI_ROM_RESOURCE; i++) { 94 unsigned long f = dev->resource[i].flags; 95 if (f & IORESOURCE_IO) 96 has_io = 1; 97 else if (f & IORESOURCE_MEM) 98 has_mem = 1; 99 } 100 /* ROM BARs are mapped into 32-bit memory space */ 101 if (dev->resource[PCI_ROM_RESOURCE].end != 0) { 102 dev->resource[PCI_ROM_RESOURCE].flags |= 103 IORESOURCE_ROM_ENABLE; 104 has_mem = 1; 105 } 106 pci_bus_read_config_word(pbus, dev->devfn, PCI_COMMAND, &cmd); 107 if (has_io && !(cmd & PCI_COMMAND_IO)) { 108 #ifdef CONFIG_PCI_DEBUG 109 printk(KERN_INFO "LEONPCI: Enabling I/O for dev %s\n", 110 pci_name(dev)); 111 #endif 112 cmd |= PCI_COMMAND_IO; 113 pci_bus_write_config_word(pbus, dev->devfn, PCI_COMMAND, 114 cmd); 115 } 116 if (has_mem && !(cmd & PCI_COMMAND_MEMORY)) { 117 #ifdef CONFIG_PCI_DEBUG 118 printk(KERN_INFO "LEONPCI: Enabling MEMORY for dev" 119 "%s\n", pci_name(dev)); 120 #endif 121 cmd |= PCI_COMMAND_MEMORY; 122 pci_bus_write_config_word(pbus, dev->devfn, PCI_COMMAND, 123 cmd); 124 } 125 } 126 } 127 128 /* 129 * Other archs parse arguments here. 130 */ 131 char * __devinit pcibios_setup(char *str) 132 { 133 return str; 134 } 135 136 resource_size_t pcibios_align_resource(void *data, const struct resource *res, 137 resource_size_t size, resource_size_t align) 138 { 139 return res->start; 140 } 141 142 int pcibios_enable_device(struct pci_dev *dev, int mask) 143 { 144 return pci_enable_resources(dev, mask); 145 } 146 147 struct device_node *pci_device_to_OF_node(struct pci_dev *pdev) 148 { 149 /* 150 * Currently the OpenBoot nodes are not connected with the PCI device, 151 * this is because the LEON PROM does not create PCI nodes. Eventually 152 * this will change and the same approach as pcic.c can be used to 153 * match PROM nodes with pci devices. 154 */ 155 return NULL; 156 } 157 EXPORT_SYMBOL(pci_device_to_OF_node); 158 159 void __devinit pcibios_update_irq(struct pci_dev *dev, int irq) 160 { 161 #ifdef CONFIG_PCI_DEBUG 162 printk(KERN_DEBUG "LEONPCI: Assigning IRQ %02d to %s\n", irq, 163 pci_name(dev)); 164 #endif 165 pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); 166 } 167 168 /* in/out routines taken from pcic.c 169 * 170 * This probably belongs here rather than ioport.c because 171 * we do not want this crud linked into SBus kernels. 172 * Also, think for a moment about likes of floppy.c that 173 * include architecture specific parts. They may want to redefine ins/outs. 174 * 175 * We do not use horrible macros here because we want to 176 * advance pointer by sizeof(size). 177 */ 178 void outsb(unsigned long addr, const void *src, unsigned long count) 179 { 180 while (count) { 181 count -= 1; 182 outb(*(const char *)src, addr); 183 src += 1; 184 /* addr += 1; */ 185 } 186 } 187 EXPORT_SYMBOL(outsb); 188 189 void outsw(unsigned long addr, const void *src, unsigned long count) 190 { 191 while (count) { 192 count -= 2; 193 outw(*(const short *)src, addr); 194 src += 2; 195 /* addr += 2; */ 196 } 197 } 198 EXPORT_SYMBOL(outsw); 199 200 void outsl(unsigned long addr, const void *src, unsigned long count) 201 { 202 while (count) { 203 count -= 4; 204 outl(*(const long *)src, addr); 205 src += 4; 206 /* addr += 4; */ 207 } 208 } 209 EXPORT_SYMBOL(outsl); 210 211 void insb(unsigned long addr, void *dst, unsigned long count) 212 { 213 while (count) { 214 count -= 1; 215 *(unsigned char *)dst = inb(addr); 216 dst += 1; 217 /* addr += 1; */ 218 } 219 } 220 EXPORT_SYMBOL(insb); 221 222 void insw(unsigned long addr, void *dst, unsigned long count) 223 { 224 while (count) { 225 count -= 2; 226 *(unsigned short *)dst = inw(addr); 227 dst += 2; 228 /* addr += 2; */ 229 } 230 } 231 EXPORT_SYMBOL(insw); 232 233 void insl(unsigned long addr, void *dst, unsigned long count) 234 { 235 while (count) { 236 count -= 4; 237 /* 238 * XXX I am sure we are in for an unaligned trap here. 239 */ 240 *(unsigned long *)dst = inl(addr); 241 dst += 4; 242 /* addr += 4; */ 243 } 244 } 245 EXPORT_SYMBOL(insl); 246