~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm/mach-footbridge/dc21285.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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/dma-map-ops.h>
  9 #include <linux/kernel.h>
 10 #include <linux/pci.h>
 11 #include <linux/interrupt.h>
 12 #include <linux/mm.h>
 13 #include <linux/slab.h>
 14 #include <linux/init.h>
 15 #include <linux/ioport.h>
 16 #include <linux/irq.h>
 17 #include <linux/io.h>
 18 #include <linux/spinlock.h>
 19 
 20 #include <asm/irq.h>
 21 #include <asm/mach/pci.h>
 22 #include <asm/hardware/dec21285.h>
 23 
 24 #define MAX_SLOTS               21
 25 
 26 #define PCICMD_ABORT            ((PCI_STATUS_REC_MASTER_ABORT| \
 27                                   PCI_STATUS_REC_TARGET_ABORT)<<16)
 28 
 29 #define PCICMD_ERROR_BITS       ((PCI_STATUS_DETECTED_PARITY | \
 30                                   PCI_STATUS_REC_MASTER_ABORT | \
 31                                   PCI_STATUS_REC_TARGET_ABORT | \
 32                                   PCI_STATUS_PARITY) << 16)
 33 
 34 extern int setup_arm_irq(int, struct irqaction *);
 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 volatile("ldrb      %0, [%1, %2]"
 70                                 : "=r" (v) : "r" (addr), "r" (where) : "cc");
 71                         break;
 72                 case 2:
 73                         asm volatile("ldrh      %0, [%1, %2]"
 74                                 : "=r" (v) : "r" (addr), "r" (where) : "cc");
 75                         break;
 76                 case 4:
 77                         asm volatile("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 volatile("strb      %0, [%1, %2]"
104                                 : : "r" (value), "r" (addr), "r" (where)
105                                 : "cc");
106                         break;
107                 case 2:
108                         asm volatile("strh      %0, [%1, %2]"
109                                 : : "r" (value), "r" (addr), "r" (where)
110                                 : "cc");
111                         break;
112                 case 4:
113                         asm volatile("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 static int dc21285_pci_bus_notifier(struct notifier_block *nb,
246                                     unsigned long action,
247                                     void *data)
248 {
249         if (action != BUS_NOTIFY_ADD_DEVICE)
250                 return NOTIFY_DONE;
251 
252         dma_direct_set_offset(data, PHYS_OFFSET, BUS_OFFSET, SZ_256M);
253 
254         return NOTIFY_OK;
255 }
256 
257 static struct notifier_block dc21285_pci_bus_nb = {
258         .notifier_call = dc21285_pci_bus_notifier,
259 };
260 
261 int __init dc21285_setup(int nr, struct pci_sys_data *sys)
262 {
263         struct resource *res;
264 
265         res = kcalloc(2, sizeof(struct resource), GFP_KERNEL);
266         if (!res) {
267                 printk("out of memory for root bus resources");
268                 return 0;
269         }
270 
271         res[0].flags = IORESOURCE_MEM;
272         res[0].name  = "Footbridge non-prefetch";
273         res[1].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
274         res[1].name  = "Footbridge prefetch";
275 
276         allocate_resource(&iomem_resource, &res[1], 0x20000000,
277                           0xa0000000, 0xffffffff, 0x20000000, NULL, NULL);
278         allocate_resource(&iomem_resource, &res[0], 0x40000000,
279                           0x80000000, 0xffffffff, 0x40000000, NULL, NULL);
280 
281         sys->mem_offset  = DC21285_PCI_MEM;
282 
283         pci_add_resource_offset(&sys->resources, &res[0], sys->mem_offset);
284         pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
285 
286         bus_register_notifier(&pci_bus_type, &dc21285_pci_bus_nb);
287 
288         return 1;
289 }
290 
291 #define dc21285_request_irq(_a, _b, _c, _d, _e) \
292         WARN_ON(request_irq(_a, _b, _c, _d, _e) < 0)
293 
294 void __init dc21285_preinit(void)
295 {
296         unsigned int mem_size, mem_mask;
297 
298         pcibios_min_mem = 0x81000000;
299 
300         mem_size = (unsigned int)high_memory - PAGE_OFFSET;
301         for (mem_mask = 0x00100000; mem_mask < 0x10000000; mem_mask <<= 1)
302                 if (mem_mask >= mem_size)
303                         break;
304 
305         /*
306          * These registers need to be set up whether we're the
307          * central function or not.
308          */
309         *CSR_SDRAMBASEMASK    = (mem_mask - 1) & 0x0ffc0000;
310         *CSR_SDRAMBASEOFFSET  = 0;
311         *CSR_ROMBASEMASK      = 0x80000000;
312         *CSR_CSRBASEMASK      = 0;
313         *CSR_CSRBASEOFFSET    = 0;
314         *CSR_PCIADDR_EXTN     = 0;
315 
316         printk(KERN_INFO "PCI: DC21285 footbridge, revision %02lX, in "
317                 "central function mode\n", *CSR_CLASSREV & 0xff);
318 
319         /*
320          * Clear any existing errors - we aren't
321          * interested in historical data...
322          */
323         *CSR_SA110_CNTL = (*CSR_SA110_CNTL & 0xffffde07) | SA110_CNTL_RXSERR;
324         *CSR_PCICMD = (*CSR_PCICMD & 0xffff) | PCICMD_ERROR_BITS;
325 
326         timer_setup(&serr_timer, dc21285_enable_error, 0);
327         timer_setup(&perr_timer, dc21285_enable_error, 0);
328 
329         /*
330          * We don't care if these fail.
331          */
332         dc21285_request_irq(IRQ_PCI_SERR, dc21285_serr_irq, 0,
333                             "PCI system error", &serr_timer);
334         dc21285_request_irq(IRQ_PCI_PERR, dc21285_parity_irq, 0,
335                             "PCI parity error", &perr_timer);
336         dc21285_request_irq(IRQ_PCI_ABORT, dc21285_abort_irq, 0,
337                             "PCI abort", NULL);
338         dc21285_request_irq(IRQ_DISCARD_TIMER, dc21285_discard_irq, 0,
339                             "Discard timer", NULL);
340         dc21285_request_irq(IRQ_PCI_DPERR, dc21285_dparity_irq, 0,
341                             "PCI data parity", NULL);
342 
343         /*
344          * Map our SDRAM at a known address in PCI space, just in case
345          * the firmware had other ideas.  Using a nonzero base is
346          * necessary, since some VGA cards forcefully use PCI addresses
347          * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards).
348          */
349         *CSR_PCICSRBASE       = 0xf4000000;
350         *CSR_PCICSRIOBASE     = 0;
351         *CSR_PCISDRAMBASE     = BUS_OFFSET;
352         *CSR_PCIROMBASE       = 0;
353         *CSR_PCICMD = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
354                       PCI_COMMAND_INVALIDATE | PCICMD_ERROR_BITS;
355 }
356 
357 void __init dc21285_postinit(void)
358 {
359         register_isa_ports(DC21285_PCI_MEM, DC21285_PCI_IO, 0);
360 }
361 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php