0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/kernel.h>
0012 #include <linux/pci.h>
0013 #include <linux/slab.h>
0014 #include <linux/mm.h>
0015 #include <linux/init.h>
0016 #include <linux/ioport.h>
0017 #include <linux/io.h>
0018 #include <asm/irq.h>
0019 #include <asm/signal.h>
0020 #include <asm/mach/pci.h>
0021 #include "hardware.h"
0022 #include "iop3xx.h"
0023
0024
0025
0026 #ifdef DEBUG
0027 #define DBG(x...) printk(x)
0028 #else
0029 #define DBG(x...) do { } while (0)
0030 #endif
0031
0032
0033
0034
0035
0036 static u32 iop3xx_cfg_address(struct pci_bus *bus, int devfn, int where)
0037 {
0038 struct pci_sys_data *sys = bus->sysdata;
0039 u32 addr;
0040
0041 if (sys->busnr == bus->number)
0042 addr = 1 << (PCI_SLOT(devfn) + 16) | (PCI_SLOT(devfn) << 11);
0043 else
0044 addr = bus->number << 16 | PCI_SLOT(devfn) << 11 | 1;
0045
0046 addr |= PCI_FUNC(devfn) << 8 | (where & ~3);
0047
0048 return addr;
0049 }
0050
0051
0052
0053
0054
0055
0056
0057
0058 static int iop3xx_pci_status(void)
0059 {
0060 unsigned int status;
0061 int ret = 0;
0062
0063
0064
0065
0066 status = *IOP3XX_ATUSR;
0067 if (status & 0xf900) {
0068 DBG("\t\t\tPCI: P0 - status = 0x%08x\n", status);
0069 *IOP3XX_ATUSR = status & 0xf900;
0070 ret = 1;
0071 }
0072
0073 status = *IOP3XX_ATUISR;
0074 if (status & 0x679f) {
0075 DBG("\t\t\tPCI: P1 - status = 0x%08x\n", status);
0076 *IOP3XX_ATUISR = status & 0x679f;
0077 ret = 1;
0078 }
0079
0080 return ret;
0081 }
0082
0083
0084
0085
0086
0087
0088 static u32 iop3xx_read(unsigned long addr)
0089 {
0090 u32 val;
0091
0092 __asm__ __volatile__(
0093 "str %1, [%2]\n\t"
0094 "ldr %0, [%3]\n\t"
0095 "nop\n\t"
0096 "nop\n\t"
0097 "nop\n\t"
0098 "nop\n\t"
0099 : "=r" (val)
0100 : "r" (addr), "r" (IOP3XX_OCCAR), "r" (IOP3XX_OCCDR));
0101
0102 return val;
0103 }
0104
0105
0106
0107
0108
0109 static int
0110 iop3xx_read_config(struct pci_bus *bus, unsigned int devfn, int where,
0111 int size, u32 *value)
0112 {
0113 unsigned long addr = iop3xx_cfg_address(bus, devfn, where);
0114 u32 val = iop3xx_read(addr) >> ((where & 3) * 8);
0115
0116 if (iop3xx_pci_status())
0117 val = 0xffffffff;
0118
0119 *value = val;
0120
0121 return PCIBIOS_SUCCESSFUL;
0122 }
0123
0124 static int
0125 iop3xx_write_config(struct pci_bus *bus, unsigned int devfn, int where,
0126 int size, u32 value)
0127 {
0128 unsigned long addr = iop3xx_cfg_address(bus, devfn, where);
0129 u32 val;
0130
0131 if (size != 4) {
0132 val = iop3xx_read(addr);
0133 if (iop3xx_pci_status())
0134 return PCIBIOS_SUCCESSFUL;
0135
0136 where = (where & 3) * 8;
0137
0138 if (size == 1)
0139 val &= ~(0xff << where);
0140 else
0141 val &= ~(0xffff << where);
0142
0143 *IOP3XX_OCCDR = val | value << where;
0144 } else {
0145 asm volatile(
0146 "str %1, [%2]\n\t"
0147 "str %0, [%3]\n\t"
0148 "nop\n\t"
0149 "nop\n\t"
0150 "nop\n\t"
0151 "nop\n\t"
0152 :
0153 : "r" (value), "r" (addr),
0154 "r" (IOP3XX_OCCAR), "r" (IOP3XX_OCCDR));
0155 }
0156
0157 return PCIBIOS_SUCCESSFUL;
0158 }
0159
0160 struct pci_ops iop3xx_ops = {
0161 .read = iop3xx_read_config,
0162 .write = iop3xx_write_config,
0163 };
0164
0165
0166
0167
0168
0169 static int
0170 iop3xx_pci_abort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
0171 {
0172 DBG("PCI abort: address = 0x%08lx fsr = 0x%03x PC = 0x%08lx LR = 0x%08lx\n",
0173 addr, fsr, regs->ARM_pc, regs->ARM_lr);
0174
0175
0176
0177
0178
0179 if (fsr & (1 << 10))
0180 regs->ARM_pc += 4;
0181
0182 return 0;
0183 }
0184
0185 int iop3xx_pci_setup(int nr, struct pci_sys_data *sys)
0186 {
0187 struct resource *res;
0188 struct resource realio;
0189
0190 if (nr != 0)
0191 return 0;
0192
0193 res = kzalloc(sizeof(struct resource), GFP_KERNEL);
0194 if (!res)
0195 panic("PCI: unable to alloc resources");
0196
0197 res->start = IOP3XX_PCI_LOWER_MEM_PA;
0198 res->end = IOP3XX_PCI_LOWER_MEM_PA + IOP3XX_PCI_MEM_WINDOW_SIZE - 1;
0199 res->name = "IOP3XX PCI Memory Space";
0200 res->flags = IORESOURCE_MEM;
0201 request_resource(&iomem_resource, res);
0202
0203
0204
0205
0206 sys->mem_offset = IOP3XX_PCI_LOWER_MEM_PA - *IOP3XX_OMWTVR0;
0207
0208 pci_add_resource_offset(&sys->resources, res, sys->mem_offset);
0209
0210 realio.start = 0;
0211 realio.end = realio.start + SZ_64K - 1;
0212 pci_remap_iospace(&realio, IOP3XX_PCI_LOWER_IO_PA);
0213
0214 return 1;
0215 }
0216
0217 void __init iop3xx_atu_setup(void)
0218 {
0219
0220 *IOP3XX_IAUBAR0 = 0x0;
0221 *IOP3XX_IABAR0 = 0x0;
0222 *IOP3XX_IATVR0 = 0x0;
0223 *IOP3XX_IALR0 = 0x0;
0224
0225
0226 *IOP3XX_IAUBAR1 = 0x0;
0227 *IOP3XX_IABAR1 = 0x0;
0228 *IOP3XX_IALR1 = 0x0;
0229
0230
0231
0232 *IOP3XX_IALR2 = ~((u32)IOP3XX_MAX_RAM_SIZE - 1) & ~0x1;
0233 *IOP3XX_IAUBAR2 = 0x0;
0234
0235
0236 *IOP3XX_IABAR2 = PHYS_OFFSET |
0237 PCI_BASE_ADDRESS_MEM_TYPE_64 |
0238 PCI_BASE_ADDRESS_MEM_PREFETCH;
0239
0240 *IOP3XX_IATVR2 = PHYS_OFFSET;
0241
0242
0243 *IOP3XX_OMWTVR0 = IOP3XX_PCI_LOWER_MEM_BA;
0244 *IOP3XX_OUMWTVR0 = 0;
0245
0246
0247 *IOP3XX_OMWTVR1 = IOP3XX_PCI_LOWER_MEM_BA +
0248 IOP3XX_PCI_MEM_WINDOW_SIZE / 2;
0249 *IOP3XX_OUMWTVR1 = 0;
0250
0251
0252 *IOP3XX_IAUBAR3 = 0x0;
0253 *IOP3XX_IABAR3 = 0x0;
0254 *IOP3XX_IATVR3 = 0x0;
0255 *IOP3XX_IALR3 = 0x0;
0256
0257
0258
0259 *IOP3XX_OIOWTVR = IOP3XX_PCI_LOWER_IO_BA;
0260
0261
0262
0263 *IOP3XX_ATUCMD |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
0264 PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
0265 *IOP3XX_ATUCR |= IOP3XX_ATUCR_OUT_EN;
0266 }
0267
0268 void __init iop3xx_atu_disable(void)
0269 {
0270 *IOP3XX_ATUCMD = 0;
0271 *IOP3XX_ATUCR = 0;
0272
0273
0274 while (*IOP3XX_PCSR & (IOP3XX_PCSR_OUT_Q_BUSY |
0275 IOP3XX_PCSR_IN_Q_BUSY))
0276 cpu_relax();
0277
0278
0279 *IOP3XX_IAUBAR0 = 0x0;
0280 *IOP3XX_IABAR0 = 0x0;
0281 *IOP3XX_IATVR0 = 0x0;
0282 *IOP3XX_IALR0 = 0x0;
0283
0284
0285 *IOP3XX_IAUBAR1 = 0x0;
0286 *IOP3XX_IABAR1 = 0x0;
0287 *IOP3XX_IALR1 = 0x0;
0288
0289
0290 *IOP3XX_IAUBAR2 = 0x0;
0291 *IOP3XX_IABAR2 = 0x0;
0292 *IOP3XX_IATVR2 = 0x0;
0293 *IOP3XX_IALR2 = 0x0;
0294
0295
0296 *IOP3XX_IAUBAR3 = 0x0;
0297 *IOP3XX_IABAR3 = 0x0;
0298 *IOP3XX_IATVR3 = 0x0;
0299 *IOP3XX_IALR3 = 0x0;
0300
0301
0302 *IOP3XX_OIOWTVR = 0;
0303
0304
0305 *IOP3XX_OMWTVR0 = 0;
0306 *IOP3XX_OUMWTVR0 = 0;
0307
0308
0309 *IOP3XX_OMWTVR1 = 0;
0310 *IOP3XX_OUMWTVR1 = 0;
0311 }
0312
0313
0314 int init_atu;
0315
0316 int iop3xx_get_init_atu(void) {
0317
0318 if (init_atu != IOP3XX_INIT_ATU_DEFAULT)
0319 return init_atu;
0320 else
0321 return IOP3XX_INIT_ATU_DISABLE;
0322 }
0323
0324 static void __init iop3xx_atu_debug(void)
0325 {
0326 DBG("PCI: Intel IOP3xx PCI init.\n");
0327 DBG("PCI: Outbound memory window 0: PCI 0x%08x%08x\n",
0328 *IOP3XX_OUMWTVR0, *IOP3XX_OMWTVR0);
0329 DBG("PCI: Outbound memory window 1: PCI 0x%08x%08x\n",
0330 *IOP3XX_OUMWTVR1, *IOP3XX_OMWTVR1);
0331 DBG("PCI: Outbound IO window: PCI 0x%08x\n",
0332 *IOP3XX_OIOWTVR);
0333
0334 DBG("PCI: Inbound memory window 0: PCI 0x%08x%08x 0x%08x -> 0x%08x\n",
0335 *IOP3XX_IAUBAR0, *IOP3XX_IABAR0, *IOP3XX_IALR0, *IOP3XX_IATVR0);
0336 DBG("PCI: Inbound memory window 1: PCI 0x%08x%08x 0x%08x\n",
0337 *IOP3XX_IAUBAR1, *IOP3XX_IABAR1, *IOP3XX_IALR1);
0338 DBG("PCI: Inbound memory window 2: PCI 0x%08x%08x 0x%08x -> 0x%08x\n",
0339 *IOP3XX_IAUBAR2, *IOP3XX_IABAR2, *IOP3XX_IALR2, *IOP3XX_IATVR2);
0340 DBG("PCI: Inbound memory window 3: PCI 0x%08x%08x 0x%08x -> 0x%08x\n",
0341 *IOP3XX_IAUBAR3, *IOP3XX_IABAR3, *IOP3XX_IALR3, *IOP3XX_IATVR3);
0342
0343 DBG("PCI: Expansion ROM window: PCI 0x%08x%08x 0x%08x -> 0x%08x\n",
0344 0, *IOP3XX_ERBAR, *IOP3XX_ERLR, *IOP3XX_ERTVR);
0345
0346 DBG("ATU: IOP3XX_ATUCMD=0x%04x\n", *IOP3XX_ATUCMD);
0347 DBG("ATU: IOP3XX_ATUCR=0x%08x\n", *IOP3XX_ATUCR);
0348
0349 hook_fault_code(16+6, iop3xx_pci_abort, SIGBUS, 0, "imprecise external abort");
0350 }
0351
0352
0353 void __init iop3xx_pci_preinit_cond(void)
0354 {
0355 if (iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) {
0356 iop3xx_atu_disable();
0357 iop3xx_atu_setup();
0358 iop3xx_atu_debug();
0359 }
0360 }
0361
0362 void __init iop3xx_pci_preinit(void)
0363 {
0364 pcibios_min_mem = 0;
0365
0366 iop3xx_atu_disable();
0367 iop3xx_atu_setup();
0368 iop3xx_atu_debug();
0369 }
0370
0371
0372 static int __init iop3xx_init_atu_setup(char *str)
0373 {
0374 init_atu = IOP3XX_INIT_ATU_DEFAULT;
0375 if (str) {
0376 while (*str != '\0') {
0377 switch (*str) {
0378 case 'y':
0379 case 'Y':
0380 init_atu = IOP3XX_INIT_ATU_ENABLE;
0381 break;
0382 case 'n':
0383 case 'N':
0384 init_atu = IOP3XX_INIT_ATU_DISABLE;
0385 break;
0386 case ',':
0387 case '=':
0388 break;
0389 default:
0390 printk(KERN_DEBUG "\"%s\" malformed at "
0391 "character: \'%c\'",
0392 __func__,
0393 *str);
0394 *(str + 1) = '\0';
0395 }
0396 str++;
0397 }
0398 }
0399
0400 return 1;
0401 }
0402
0403 __setup("iop3xx_init_atu", iop3xx_init_atu_setup);
0404