1/* 2 * PCI code for the Freescale MPC52xx embedded CPU. 3 * 4 * 5 * Maintainer : Sylvain Munaut <tnt@246tNt.com> 6 * 7 * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com> 8 * 9 * This file is licensed under the terms of the GNU General Public License 10 * version 2. This program is licensed "as is" without any warranty of any 11 * kind, whether express or implied. 12 */ 13 14 15#include <asm/pci.h> 16 17#include <asm/mpc52xx.h> 18#include "mpc52xx_pci.h" 19 20#include <asm/delay.h> 21#include <asm/machdep.h> 22 23 24#define MPC5200_BUG_435_WORKAROUND 25 26 27static int 28mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, 29 int offset, int len, u32 *val) 30{ 31 struct pci_controller *hose = bus->sysdata; 32 u32 value; 33 34 if (ppc_md.pci_exclude_device) 35 if (ppc_md.pci_exclude_device(bus->number, devfn)) 36 return PCIBIOS_DEVICE_NOT_FOUND; 37 38 out_be32(hose->cfg_addr, 39 (1 << 31) | 40 ((bus->number - hose->bus_offset) << 16) | 41 (devfn << 8) | 42 (offset & 0xfc)); 43 mb(); 44 45#ifdef MPC5200_BUG_435_WORKAROUND 46 if (bus->number != hose->bus_offset) { 47 switch (len) { 48 case 1: 49 value = in_8(((u8 __iomem *)hose->cfg_data) + (offset & 3)); 50 break; 51 case 2: 52 value = in_le16(((u16 __iomem *)hose->cfg_data) + ((offset>>1) & 1)); 53 break; 54 55 default: 56 value = in_le16((u16 __iomem *)hose->cfg_data) | 57 (in_le16(((u16 __iomem *)hose->cfg_data) + 1) << 16); 58 break; 59 } 60 } 61 else 62#endif 63 { 64 value = in_le32(hose->cfg_data); 65 66 if (len != 4) { 67 value >>= ((offset & 0x3) << 3); 68 value &= 0xffffffff >> (32 - (len << 3)); 69 } 70 } 71 72 *val = value; 73 74 out_be32(hose->cfg_addr, 0); 75 mb(); 76 77 return PCIBIOS_SUCCESSFUL; 78} 79 80static int 81mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, 82 int offset, int len, u32 val) 83{ 84 struct pci_controller *hose = bus->sysdata; 85 u32 value, mask; 86 87 if (ppc_md.pci_exclude_device) 88 if (ppc_md.pci_exclude_device(bus->number, devfn)) 89 return PCIBIOS_DEVICE_NOT_FOUND; 90 91 out_be32(hose->cfg_addr, 92 (1 << 31) | 93 ((bus->number - hose->bus_offset) << 16) | 94 (devfn << 8) | 95 (offset & 0xfc)); 96 mb(); 97 98#ifdef MPC5200_BUG_435_WORKAROUND 99 if (bus->number != hose->bus_offset) { 100 switch (len) { 101 case 1: 102 out_8(((u8 __iomem *)hose->cfg_data) + 103 (offset & 3), val); 104 break; 105 case 2: 106 out_le16(((u16 __iomem *)hose->cfg_data) + 107 ((offset>>1) & 1), val); 108 break; 109 110 default: 111 out_le16((u16 __iomem *)hose->cfg_data, 112 (u16)val); 113 out_le16(((u16 __iomem *)hose->cfg_data) + 1, 114 (u16)(val>>16)); 115 break; 116 } 117 } 118 else 119#endif 120 { 121 if (len != 4) { 122 value = in_le32(hose->cfg_data); 123 124 offset = (offset & 0x3) << 3; 125 mask = (0xffffffff >> (32 - (len << 3))); 126 mask <<= offset; 127 128 value &= ~mask; 129 val = value | ((val << offset) & mask); 130 } 131 132 out_le32(hose->cfg_data, val); 133 } 134 mb(); 135 136 out_be32(hose->cfg_addr, 0); 137 mb(); 138 139 return PCIBIOS_SUCCESSFUL; 140} 141 142static struct pci_ops mpc52xx_pci_ops = { 143 .read = mpc52xx_pci_read_config, 144 .write = mpc52xx_pci_write_config 145}; 146 147 148static void __init 149mpc52xx_pci_setup(struct mpc52xx_pci __iomem *pci_regs) 150{ 151 u32 tmp; 152 153 /* Setup control regs */ 154 tmp = in_be32(&pci_regs->scr); 155 tmp |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; 156 out_be32(&pci_regs->scr, tmp); 157 158 /* Setup windows */ 159 out_be32(&pci_regs->iw0btar, MPC52xx_PCI_IWBTAR_TRANSLATION( 160 MPC52xx_PCI_MEM_START + MPC52xx_PCI_MEM_OFFSET, 161 MPC52xx_PCI_MEM_START, 162 MPC52xx_PCI_MEM_SIZE )); 163 164 out_be32(&pci_regs->iw1btar, MPC52xx_PCI_IWBTAR_TRANSLATION( 165 MPC52xx_PCI_MMIO_START + MPC52xx_PCI_MEM_OFFSET, 166 MPC52xx_PCI_MMIO_START, 167 MPC52xx_PCI_MMIO_SIZE )); 168 169 out_be32(&pci_regs->iw2btar, MPC52xx_PCI_IWBTAR_TRANSLATION( 170 MPC52xx_PCI_IO_BASE, 171 MPC52xx_PCI_IO_START, 172 MPC52xx_PCI_IO_SIZE )); 173 174 out_be32(&pci_regs->iwcr, MPC52xx_PCI_IWCR_PACK( 175 ( MPC52xx_PCI_IWCR_ENABLE | /* iw0btar */ 176 MPC52xx_PCI_IWCR_READ_MULTI | 177 MPC52xx_PCI_IWCR_MEM ), 178 ( MPC52xx_PCI_IWCR_ENABLE | /* iw1btar */ 179 MPC52xx_PCI_IWCR_READ | 180 MPC52xx_PCI_IWCR_MEM ), 181 ( MPC52xx_PCI_IWCR_ENABLE | /* iw2btar */ 182 MPC52xx_PCI_IWCR_IO ) 183 )); 184 185 186 out_be32(&pci_regs->tbatr0, 187 MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_IO ); 188 out_be32(&pci_regs->tbatr1, 189 MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_MEM ); 190 191 out_be32(&pci_regs->tcr, MPC52xx_PCI_TCR_LD); 192 193 /* Reset the exteral bus ( internal PCI controller is NOT resetted ) */ 194 /* Not necessary and can be a bad thing if for example the bootloader 195 is displaying a splash screen or ... Just left here for 196 documentation purpose if anyone need it */ 197 tmp = in_be32(&pci_regs->gscr); 198 out_be32(&pci_regs->gscr, tmp & ~MPC52xx_PCI_GSCR_PR); 199} 200 201static void 202mpc52xx_pci_fixup_resources(struct pci_dev *dev) 203{ 204 int i; 205 206 /* We don't rely on boot loader for PCI and resets all 207 devices */ 208 for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { 209 struct resource *res = &dev->resource[i]; 210 if (res->end > res->start) { /* Only valid resources */ 211 res->end -= res->start; 212 res->start = 0; 213 res->flags |= IORESOURCE_UNSET; 214 } 215 } 216 217 /* The PCI Host bridge of MPC52xx has a prefetch memory resource 218 fixed to 1Gb. Doesn't fit in the resource system so we remove it */ 219 if ( (dev->vendor == PCI_VENDOR_ID_MOTOROLA) && 220 ( dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200 221 || dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200B) ) { 222 struct resource *res = &dev->resource[1]; 223 res->start = res->end = res->flags = 0; 224 } 225} 226 227void __init 228mpc52xx_find_bridges(void) 229{ 230 struct mpc52xx_pci __iomem *pci_regs; 231 struct pci_controller *hose; 232 233 pci_assign_all_buses = 1; 234 235 pci_regs = ioremap(MPC52xx_PA(MPC52xx_PCI_OFFSET), MPC52xx_PCI_SIZE); 236 if (!pci_regs) 237 return; 238 239 hose = pcibios_alloc_controller(); 240 if (!hose) { 241 iounmap(pci_regs); 242 return; 243 } 244 245 ppc_md.pci_swizzle = common_swizzle; 246 ppc_md.pcibios_fixup_resources = mpc52xx_pci_fixup_resources; 247 248 hose->first_busno = 0; 249 hose->last_busno = 0xff; 250 hose->bus_offset = 0; 251 hose->ops = &mpc52xx_pci_ops; 252 253 mpc52xx_pci_setup(pci_regs); 254 255 hose->pci_mem_offset = MPC52xx_PCI_MEM_OFFSET; 256 257 hose->io_base_virt = ioremap(MPC52xx_PCI_IO_BASE, MPC52xx_PCI_IO_SIZE); 258 isa_io_base = (unsigned long) hose->io_base_virt; 259 260 hose->cfg_addr = &pci_regs->car; 261 hose->cfg_data = hose->io_base_virt; 262 263 /* Setup resources */ 264 pci_init_resource(&hose->mem_resources[0], 265 MPC52xx_PCI_MEM_START, 266 MPC52xx_PCI_MEM_STOP, 267 IORESOURCE_MEM|IORESOURCE_PREFETCH, 268 "PCI prefetchable memory"); 269 270 pci_init_resource(&hose->mem_resources[1], 271 MPC52xx_PCI_MMIO_START, 272 MPC52xx_PCI_MMIO_STOP, 273 IORESOURCE_MEM, 274 "PCI memory"); 275 276 pci_init_resource(&hose->io_resource, 277 MPC52xx_PCI_IO_START, 278 MPC52xx_PCI_IO_STOP, 279 IORESOURCE_IO, 280 "PCI I/O"); 281 282} 283