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 struct pci_bus *root_bus; 23 24 root_bus = pci_scan_bus_parented(&ofdev->dev, 0, info->ops, info); 25 if (root_bus) { 26 root_bus->resource[0] = &info->io_space; 27 root_bus->resource[1] = &info->mem_space; 28 root_bus->resource[2] = NULL; 29 30 /* Init all PCI devices into PCI tree */ 31 pci_bus_add_devices(root_bus); 32 33 /* Setup IRQs of all devices using custom routines */ 34 pci_fixup_irqs(pci_common_swizzle, info->map_irq); 35 36 /* Assign devices with resources */ 37 pci_assign_unassigned_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 /* Generic PCI bus probing sets these to point at 87 * &io{port,mem}_resouce which is wrong for us. 88 */ 89 if (pbus->self == NULL) { 90 pbus->resource[0] = &info->io_space; 91 pbus->resource[1] = &info->mem_space; 92 pbus->resource[2] = NULL; 93 } 94 95 list_for_each_entry(dev, &pbus->devices, bus_list) { 96 /* 97 * We can not rely on that the bootloader has enabled I/O 98 * or memory access to PCI devices. Instead we enable it here 99 * if the device has BARs of respective type. 100 */ 101 has_io = has_mem = 0; 102 for (i = 0; i < PCI_ROM_RESOURCE; i++) { 103 unsigned long f = dev->resource[i].flags; 104 if (f & IORESOURCE_IO) 105 has_io = 1; 106 else if (f & IORESOURCE_MEM) 107 has_mem = 1; 108 } 109 /* ROM BARs are mapped into 32-bit memory space */ 110 if (dev->resource[PCI_ROM_RESOURCE].end != 0) { 111 dev->resource[PCI_ROM_RESOURCE].flags |= 112 IORESOURCE_ROM_ENABLE; 113 has_mem = 1; 114 } 115 pci_bus_read_config_word(pbus, dev->devfn, PCI_COMMAND, &cmd); 116 if (has_io && !(cmd & PCI_COMMAND_IO)) { 117 #ifdef CONFIG_PCI_DEBUG 118 printk(KERN_INFO "LEONPCI: Enabling I/O for dev %s\n", 119 pci_name(dev)); 120 #endif 121 cmd |= PCI_COMMAND_IO; 122 pci_bus_write_config_word(pbus, dev->devfn, PCI_COMMAND, 123 cmd); 124 } 125 if (has_mem && !(cmd & PCI_COMMAND_MEMORY)) { 126 #ifdef CONFIG_PCI_DEBUG 127 printk(KERN_INFO "LEONPCI: Enabling MEMORY for dev" 128 "%s\n", pci_name(dev)); 129 #endif 130 cmd |= PCI_COMMAND_MEMORY; 131 pci_bus_write_config_word(pbus, dev->devfn, PCI_COMMAND, 132 cmd); 133 } 134 } 135 } 136 137 /* 138 * Other archs parse arguments here. 139 */ 140 char * __devinit pcibios_setup(char *str) 141 { 142 return str; 143 } 144 145 resource_size_t pcibios_align_resource(void *data, const struct resource *res, 146 resource_size_t size, resource_size_t align) 147 { 148 return res->start; 149 } 150 151 int pcibios_enable_device(struct pci_dev *dev, int mask) 152 { 153 return pci_enable_resources(dev, mask); 154 } 155 156 struct device_node *pci_device_to_OF_node(struct pci_dev *pdev) 157 { 158 /* 159 * Currently the OpenBoot nodes are not connected with the PCI device, 160 * this is because the LEON PROM does not create PCI nodes. Eventually 161 * this will change and the same approach as pcic.c can be used to 162 * match PROM nodes with pci devices. 163 */ 164 return NULL; 165 } 166 EXPORT_SYMBOL(pci_device_to_OF_node); 167 168 void __devinit pcibios_update_irq(struct pci_dev *dev, int irq) 169 { 170 #ifdef CONFIG_PCI_DEBUG 171 printk(KERN_DEBUG "LEONPCI: Assigning IRQ %02d to %s\n", irq, 172 pci_name(dev)); 173 #endif 174 pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); 175 } 176 177 /* in/out routines taken from pcic.c 178 * 179 * This probably belongs here rather than ioport.c because 180 * we do not want this crud linked into SBus kernels. 181 * Also, think for a moment about likes of floppy.c that 182 * include architecture specific parts. They may want to redefine ins/outs. 183 * 184 * We do not use horrible macros here because we want to 185 * advance pointer by sizeof(size). 186 */ 187 void outsb(unsigned long addr, const void *src, unsigned long count) 188 { 189 while (count) { 190 count -= 1; 191 outb(*(const char *)src, addr); 192 src += 1; 193 /* addr += 1; */ 194 } 195 } 196 EXPORT_SYMBOL(outsb); 197 198 void outsw(unsigned long addr, const void *src, unsigned long count) 199 { 200 while (count) { 201 count -= 2; 202 outw(*(const short *)src, addr); 203 src += 2; 204 /* addr += 2; */ 205 } 206 } 207 EXPORT_SYMBOL(outsw); 208 209 void outsl(unsigned long addr, const void *src, unsigned long count) 210 { 211 while (count) { 212 count -= 4; 213 outl(*(const long *)src, addr); 214 src += 4; 215 /* addr += 4; */ 216 } 217 } 218 EXPORT_SYMBOL(outsl); 219 220 void insb(unsigned long addr, void *dst, unsigned long count) 221 { 222 while (count) { 223 count -= 1; 224 *(unsigned char *)dst = inb(addr); 225 dst += 1; 226 /* addr += 1; */ 227 } 228 } 229 EXPORT_SYMBOL(insb); 230 231 void insw(unsigned long addr, void *dst, unsigned long count) 232 { 233 while (count) { 234 count -= 2; 235 *(unsigned short *)dst = inw(addr); 236 dst += 2; 237 /* addr += 2; */ 238 } 239 } 240 EXPORT_SYMBOL(insw); 241 242 void insl(unsigned long addr, void *dst, unsigned long count) 243 { 244 while (count) { 245 count -= 4; 246 /* 247 * XXX I am sure we are in for an unaligned trap here. 248 */ 249 *(unsigned long *)dst = inl(addr); 250 dst += 4; 251 /* addr += 4; */ 252 } 253 } 254 EXPORT_SYMBOL(insl); 255