root/arch/arm/mach-footbridge/dc21285.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dc21285_base_address
  2. dc21285_read_config
  3. dc21285_write_config
  4. dc21285_enable_error
  5. dc21285_abort_irq
  6. dc21285_serr_irq
  7. dc21285_discard_irq
  8. dc21285_dparity_irq
  9. dc21285_parity_irq
  10. dc21285_setup
  11. dc21285_preinit
  12. dc21285_postinit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  *  linux/arch/arm/kernel/dec21285.c: PCI functions for DC21285
   4  *
   5  *  Copyright (C) 1998-2001 Russell King
   6  *  Copyright (C) 1998-2000 Phil Blundell
   7  */
   8 #include <linux/kernel.h>
   9 #include <linux/pci.h>
  10 #include <linux/interrupt.h>
  11 #include <linux/mm.h>
  12 #include <linux/slab.h>
  13 #include <linux/init.h>
  14 #include <linux/ioport.h>
  15 #include <linux/irq.h>
  16 #include <linux/io.h>
  17 #include <linux/spinlock.h>
  18 
  19 #include <asm/irq.h>
  20 #include <asm/mach/pci.h>
  21 #include <asm/hardware/dec21285.h>
  22 
  23 #define MAX_SLOTS               21
  24 
  25 #define PCICMD_ABORT            ((PCI_STATUS_REC_MASTER_ABORT| \
  26                                   PCI_STATUS_REC_TARGET_ABORT)<<16)
  27 
  28 #define PCICMD_ERROR_BITS       ((PCI_STATUS_DETECTED_PARITY | \
  29                                   PCI_STATUS_REC_MASTER_ABORT | \
  30                                   PCI_STATUS_REC_TARGET_ABORT | \
  31                                   PCI_STATUS_PARITY) << 16)
  32 
  33 extern int setup_arm_irq(int, struct irqaction *);
  34 extern void pcibios_report_status(u_int status_mask, int warn);
  35 
  36 static unsigned long
  37 dc21285_base_address(struct pci_bus *bus, unsigned int devfn)
  38 {
  39         unsigned long addr = 0;
  40 
  41         if (bus->number == 0) {
  42                 if (PCI_SLOT(devfn) == 0)
  43                         /*
  44                          * For devfn 0, point at the 21285
  45                          */
  46                         addr = ARMCSR_BASE;
  47                 else {
  48                         devfn -= 1 << 3;
  49 
  50                         if (devfn < PCI_DEVFN(MAX_SLOTS, 0))
  51                                 addr = PCICFG0_BASE | 0xc00000 | (devfn << 8);
  52                 }
  53         } else
  54                 addr = PCICFG1_BASE | (bus->number << 16) | (devfn << 8);
  55 
  56         return addr;
  57 }
  58 
  59 static int
  60 dc21285_read_config(struct pci_bus *bus, unsigned int devfn, int where,
  61                     int size, u32 *value)
  62 {
  63         unsigned long addr = dc21285_base_address(bus, devfn);
  64         u32 v = 0xffffffff;
  65 
  66         if (addr)
  67                 switch (size) {
  68                 case 1:
  69                         asm("ldrb       %0, [%1, %2]"
  70                                 : "=r" (v) : "r" (addr), "r" (where) : "cc");
  71                         break;
  72                 case 2:
  73                         asm("ldrh       %0, [%1, %2]"
  74                                 : "=r" (v) : "r" (addr), "r" (where) : "cc");
  75                         break;
  76                 case 4:
  77                         asm("ldr        %0, [%1, %2]"
  78                                 : "=r" (v) : "r" (addr), "r" (where) : "cc");
  79                         break;
  80                 }
  81 
  82         *value = v;
  83 
  84         v = *CSR_PCICMD;
  85         if (v & PCICMD_ABORT) {
  86                 *CSR_PCICMD = v & (0xffff|PCICMD_ABORT);
  87                 return -1;
  88         }
  89 
  90         return PCIBIOS_SUCCESSFUL;
  91 }
  92 
  93 static int
  94 dc21285_write_config(struct pci_bus *bus, unsigned int devfn, int where,
  95                      int size, u32 value)
  96 {
  97         unsigned long addr = dc21285_base_address(bus, devfn);
  98         u32 v;
  99 
 100         if (addr)
 101                 switch (size) {
 102                 case 1:
 103                         asm("strb       %0, [%1, %2]"
 104                                 : : "r" (value), "r" (addr), "r" (where)
 105                                 : "cc");
 106                         break;
 107                 case 2:
 108                         asm("strh       %0, [%1, %2]"
 109                                 : : "r" (value), "r" (addr), "r" (where)
 110                                 : "cc");
 111                         break;
 112                 case 4:
 113                         asm("str        %0, [%1, %2]"
 114                                 : : "r" (value), "r" (addr), "r" (where)
 115                                 : "cc");
 116                         break;
 117                 }
 118 
 119         v = *CSR_PCICMD;
 120         if (v & PCICMD_ABORT) {
 121                 *CSR_PCICMD = v & (0xffff|PCICMD_ABORT);
 122                 return -1;
 123         }
 124 
 125         return PCIBIOS_SUCCESSFUL;
 126 }
 127 
 128 struct pci_ops dc21285_ops = {
 129         .read   = dc21285_read_config,
 130         .write  = dc21285_write_config,
 131 };
 132 
 133 static struct timer_list serr_timer;
 134 static struct timer_list perr_timer;
 135 
 136 static void dc21285_enable_error(struct timer_list *timer)
 137 {
 138         del_timer(timer);
 139 
 140         if (timer == &serr_timer)
 141                 enable_irq(IRQ_PCI_SERR);
 142         else if (timer == &perr_timer)
 143                 enable_irq(IRQ_PCI_PERR);
 144 }
 145 
 146 /*
 147  * Warn on PCI errors.
 148  */
 149 static irqreturn_t dc21285_abort_irq(int irq, void *dev_id)
 150 {
 151         unsigned int cmd;
 152         unsigned int status;
 153 
 154         cmd = *CSR_PCICMD;
 155         status = cmd >> 16;
 156         cmd = cmd & 0xffff;
 157 
 158         if (status & PCI_STATUS_REC_MASTER_ABORT) {
 159                 printk(KERN_DEBUG "PCI: master abort, pc=0x%08lx\n",
 160                         instruction_pointer(get_irq_regs()));
 161                 cmd |= PCI_STATUS_REC_MASTER_ABORT << 16;
 162         }
 163 
 164         if (status & PCI_STATUS_REC_TARGET_ABORT) {
 165                 printk(KERN_DEBUG "PCI: target abort: ");
 166                 pcibios_report_status(PCI_STATUS_REC_MASTER_ABORT |
 167                                       PCI_STATUS_SIG_TARGET_ABORT |
 168                                       PCI_STATUS_REC_TARGET_ABORT, 1);
 169                 printk("\n");
 170 
 171                 cmd |= PCI_STATUS_REC_TARGET_ABORT << 16;
 172         }
 173 
 174         *CSR_PCICMD = cmd;
 175 
 176         return IRQ_HANDLED;
 177 }
 178 
 179 static irqreturn_t dc21285_serr_irq(int irq, void *dev_id)
 180 {
 181         struct timer_list *timer = dev_id;
 182         unsigned int cntl;
 183 
 184         printk(KERN_DEBUG "PCI: system error received: ");
 185         pcibios_report_status(PCI_STATUS_SIG_SYSTEM_ERROR, 1);
 186         printk("\n");
 187 
 188         cntl = *CSR_SA110_CNTL & 0xffffdf07;
 189         *CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR;
 190 
 191         /*
 192          * back off this interrupt
 193          */
 194         disable_irq(irq);
 195         timer->expires = jiffies + HZ;
 196         add_timer(timer);
 197 
 198         return IRQ_HANDLED;
 199 }
 200 
 201 static irqreturn_t dc21285_discard_irq(int irq, void *dev_id)
 202 {
 203         printk(KERN_DEBUG "PCI: discard timer expired\n");
 204         *CSR_SA110_CNTL &= 0xffffde07;
 205 
 206         return IRQ_HANDLED;
 207 }
 208 
 209 static irqreturn_t dc21285_dparity_irq(int irq, void *dev_id)
 210 {
 211         unsigned int cmd;
 212 
 213         printk(KERN_DEBUG "PCI: data parity error detected: ");
 214         pcibios_report_status(PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY, 1);
 215         printk("\n");
 216 
 217         cmd = *CSR_PCICMD & 0xffff;
 218         *CSR_PCICMD = cmd | 1 << 24;
 219 
 220         return IRQ_HANDLED;
 221 }
 222 
 223 static irqreturn_t dc21285_parity_irq(int irq, void *dev_id)
 224 {
 225         struct timer_list *timer = dev_id;
 226         unsigned int cmd;
 227 
 228         printk(KERN_DEBUG "PCI: parity error detected: ");
 229         pcibios_report_status(PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY, 1);
 230         printk("\n");
 231 
 232         cmd = *CSR_PCICMD & 0xffff;
 233         *CSR_PCICMD = cmd | 1 << 31;
 234 
 235         /*
 236          * back off this interrupt
 237          */
 238         disable_irq(irq);
 239         timer->expires = jiffies + HZ;
 240         add_timer(timer);
 241 
 242         return IRQ_HANDLED;
 243 }
 244 
 245 int __init dc21285_setup(int nr, struct pci_sys_data *sys)
 246 {
 247         struct resource *res;
 248 
 249         if (nr || !footbridge_cfn_mode())
 250                 return 0;
 251 
 252         res = kcalloc(2, sizeof(struct resource), GFP_KERNEL);
 253         if (!res) {
 254                 printk("out of memory for root bus resources");
 255                 return 0;
 256         }
 257 
 258         res[0].flags = IORESOURCE_MEM;
 259         res[0].name  = "Footbridge non-prefetch";
 260         res[1].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
 261         res[1].name  = "Footbridge prefetch";
 262 
 263         allocate_resource(&iomem_resource, &res[1], 0x20000000,
 264                           0xa0000000, 0xffffffff, 0x20000000, NULL, NULL);
 265         allocate_resource(&iomem_resource, &res[0], 0x40000000,
 266                           0x80000000, 0xffffffff, 0x40000000, NULL, NULL);
 267 
 268         sys->mem_offset  = DC21285_PCI_MEM;
 269 
 270         pci_add_resource_offset(&sys->resources, &res[0], sys->mem_offset);
 271         pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
 272 
 273         return 1;
 274 }
 275 
 276 #define dc21285_request_irq(_a, _b, _c, _d, _e) \
 277         WARN_ON(request_irq(_a, _b, _c, _d, _e) < 0)
 278 
 279 void __init dc21285_preinit(void)
 280 {
 281         unsigned int mem_size, mem_mask;
 282         int cfn_mode;
 283 
 284         pcibios_min_mem = 0x81000000;
 285 
 286         mem_size = (unsigned int)high_memory - PAGE_OFFSET;
 287         for (mem_mask = 0x00100000; mem_mask < 0x10000000; mem_mask <<= 1)
 288                 if (mem_mask >= mem_size)
 289                         break;
 290 
 291         /*
 292          * These registers need to be set up whether we're the
 293          * central function or not.
 294          */
 295         *CSR_SDRAMBASEMASK    = (mem_mask - 1) & 0x0ffc0000;
 296         *CSR_SDRAMBASEOFFSET  = 0;
 297         *CSR_ROMBASEMASK      = 0x80000000;
 298         *CSR_CSRBASEMASK      = 0;
 299         *CSR_CSRBASEOFFSET    = 0;
 300         *CSR_PCIADDR_EXTN     = 0;
 301 
 302         cfn_mode = __footbridge_cfn_mode();
 303 
 304         printk(KERN_INFO "PCI: DC21285 footbridge, revision %02lX, in "
 305                 "%s mode\n", *CSR_CLASSREV & 0xff, cfn_mode ?
 306                 "central function" : "addin");
 307 
 308         if (footbridge_cfn_mode()) {
 309                 /*
 310                  * Clear any existing errors - we aren't
 311                  * interested in historical data...
 312                  */
 313                 *CSR_SA110_CNTL = (*CSR_SA110_CNTL & 0xffffde07) |
 314                                   SA110_CNTL_RXSERR;
 315                 *CSR_PCICMD = (*CSR_PCICMD & 0xffff) | PCICMD_ERROR_BITS;
 316         }
 317 
 318         timer_setup(&serr_timer, dc21285_enable_error, 0);
 319         timer_setup(&perr_timer, dc21285_enable_error, 0);
 320 
 321         /*
 322          * We don't care if these fail.
 323          */
 324         dc21285_request_irq(IRQ_PCI_SERR, dc21285_serr_irq, 0,
 325                             "PCI system error", &serr_timer);
 326         dc21285_request_irq(IRQ_PCI_PERR, dc21285_parity_irq, 0,
 327                             "PCI parity error", &perr_timer);
 328         dc21285_request_irq(IRQ_PCI_ABORT, dc21285_abort_irq, 0,
 329                             "PCI abort", NULL);
 330         dc21285_request_irq(IRQ_DISCARD_TIMER, dc21285_discard_irq, 0,
 331                             "Discard timer", NULL);
 332         dc21285_request_irq(IRQ_PCI_DPERR, dc21285_dparity_irq, 0,
 333                             "PCI data parity", NULL);
 334 
 335         if (cfn_mode) {
 336                 /*
 337                  * Map our SDRAM at a known address in PCI space, just in case
 338                  * the firmware had other ideas.  Using a nonzero base is
 339                  * necessary, since some VGA cards forcefully use PCI addresses
 340                  * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards).
 341                  */
 342                 *CSR_PCICSRBASE       = 0xf4000000;
 343                 *CSR_PCICSRIOBASE     = 0;
 344                 *CSR_PCISDRAMBASE     = __virt_to_bus(PAGE_OFFSET);
 345                 *CSR_PCIROMBASE       = 0;
 346                 *CSR_PCICMD = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
 347                               PCI_COMMAND_INVALIDATE | PCICMD_ERROR_BITS;
 348         } else if (footbridge_cfn_mode() != 0) {
 349                 /*
 350                  * If we are not compiled to accept "add-in" mode, then
 351                  * we are using a constant virt_to_bus translation which
 352                  * can not hope to cater for the way the host BIOS  has
 353                  * set up the machine.
 354                  */
 355                 panic("PCI: this kernel is compiled for central "
 356                         "function mode only");
 357         }
 358 }
 359 
 360 void __init dc21285_postinit(void)
 361 {
 362         register_isa_ports(DC21285_PCI_MEM, DC21285_PCI_IO, 0);
 363 }

/* [<][>][^][v][top][bottom][index][help] */