1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * linux/arch/arm/mach-footbridge/common.c 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (C) 1998-2000 Russell King, Dave Gilbert. 61da177e4SLinus Torvalds */ 71da177e4SLinus Torvalds #include <linux/module.h> 81da177e4SLinus Torvalds #include <linux/types.h> 91da177e4SLinus Torvalds #include <linux/mm.h> 101da177e4SLinus Torvalds #include <linux/ioport.h> 111da177e4SLinus Torvalds #include <linux/list.h> 121da177e4SLinus Torvalds #include <linux/init.h> 13fced80c7SRussell King #include <linux/io.h> 1470d13e08SRussell King #include <linux/spinlock.h> 15af6f23b8SChristoph Hellwig #include <linux/dma-direct.h> 1643659222SRussell King #include <video/vga.h> 171da177e4SLinus Torvalds 181da177e4SLinus Torvalds #include <asm/page.h> 191da177e4SLinus Torvalds #include <asm/irq.h> 201da177e4SLinus Torvalds #include <asm/mach-types.h> 211da177e4SLinus Torvalds #include <asm/setup.h> 229f97da78SDavid Howells #include <asm/system_misc.h> 231da177e4SLinus Torvalds #include <asm/hardware/dec21285.h> 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds #include <asm/mach/irq.h> 261da177e4SLinus Torvalds #include <asm/mach/map.h> 278ef6e620SRob Herring #include <asm/mach/pci.h> 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds #include "common.h" 301da177e4SLinus Torvalds 3190890f17SArnd Bergmann #include <mach/hardware.h> 3290890f17SArnd Bergmann #include <mach/irqs.h> 3390890f17SArnd Bergmann #include <asm/hardware/dec21285.h> 3490890f17SArnd Bergmann 3590890f17SArnd Bergmann static int dc21285_get_irq(void) 3690890f17SArnd Bergmann { 3790890f17SArnd Bergmann void __iomem *irqstatus = (void __iomem *)CSR_IRQ_STATUS; 3890890f17SArnd Bergmann u32 mask = readl(irqstatus); 3990890f17SArnd Bergmann 4090890f17SArnd Bergmann if (mask & IRQ_MASK_SDRAMPARITY) 4190890f17SArnd Bergmann return IRQ_SDRAMPARITY; 4290890f17SArnd Bergmann 4390890f17SArnd Bergmann if (mask & IRQ_MASK_UART_RX) 4490890f17SArnd Bergmann return IRQ_CONRX; 4590890f17SArnd Bergmann 4690890f17SArnd Bergmann if (mask & IRQ_MASK_DMA1) 4790890f17SArnd Bergmann return IRQ_DMA1; 4890890f17SArnd Bergmann 4990890f17SArnd Bergmann if (mask & IRQ_MASK_DMA2) 5090890f17SArnd Bergmann return IRQ_DMA2; 5190890f17SArnd Bergmann 5290890f17SArnd Bergmann if (mask & IRQ_MASK_IN0) 5390890f17SArnd Bergmann return IRQ_IN0; 5490890f17SArnd Bergmann 5590890f17SArnd Bergmann if (mask & IRQ_MASK_IN1) 5690890f17SArnd Bergmann return IRQ_IN1; 5790890f17SArnd Bergmann 5890890f17SArnd Bergmann if (mask & IRQ_MASK_IN2) 5990890f17SArnd Bergmann return IRQ_IN2; 6090890f17SArnd Bergmann 6190890f17SArnd Bergmann if (mask & IRQ_MASK_IN3) 6290890f17SArnd Bergmann return IRQ_IN3; 6390890f17SArnd Bergmann 6490890f17SArnd Bergmann if (mask & IRQ_MASK_PCI) 6590890f17SArnd Bergmann return IRQ_PCI; 6690890f17SArnd Bergmann 6790890f17SArnd Bergmann if (mask & IRQ_MASK_DOORBELLHOST) 6890890f17SArnd Bergmann return IRQ_DOORBELLHOST; 6990890f17SArnd Bergmann 7090890f17SArnd Bergmann if (mask & IRQ_MASK_I2OINPOST) 7190890f17SArnd Bergmann return IRQ_I2OINPOST; 7290890f17SArnd Bergmann 7390890f17SArnd Bergmann if (mask & IRQ_MASK_TIMER1) 7490890f17SArnd Bergmann return IRQ_TIMER1; 7590890f17SArnd Bergmann 7690890f17SArnd Bergmann if (mask & IRQ_MASK_TIMER2) 7790890f17SArnd Bergmann return IRQ_TIMER2; 7890890f17SArnd Bergmann 7990890f17SArnd Bergmann if (mask & IRQ_MASK_TIMER3) 8090890f17SArnd Bergmann return IRQ_TIMER3; 8190890f17SArnd Bergmann 8290890f17SArnd Bergmann if (mask & IRQ_MASK_UART_TX) 8390890f17SArnd Bergmann return IRQ_CONTX; 8490890f17SArnd Bergmann 8590890f17SArnd Bergmann if (mask & IRQ_MASK_PCI_ABORT) 8690890f17SArnd Bergmann return IRQ_PCI_ABORT; 8790890f17SArnd Bergmann 8890890f17SArnd Bergmann if (mask & IRQ_MASK_PCI_SERR) 8990890f17SArnd Bergmann return IRQ_PCI_SERR; 9090890f17SArnd Bergmann 9190890f17SArnd Bergmann if (mask & IRQ_MASK_DISCARD_TIMER) 9290890f17SArnd Bergmann return IRQ_DISCARD_TIMER; 9390890f17SArnd Bergmann 9490890f17SArnd Bergmann if (mask & IRQ_MASK_PCI_DPERR) 9590890f17SArnd Bergmann return IRQ_PCI_DPERR; 9690890f17SArnd Bergmann 9790890f17SArnd Bergmann if (mask & IRQ_MASK_PCI_PERR) 9890890f17SArnd Bergmann return IRQ_PCI_PERR; 9990890f17SArnd Bergmann 10090890f17SArnd Bergmann return 0; 10190890f17SArnd Bergmann } 10290890f17SArnd Bergmann 10390890f17SArnd Bergmann static void dc21285_handle_irq(struct pt_regs *regs) 10490890f17SArnd Bergmann { 10590890f17SArnd Bergmann int irq; 10690890f17SArnd Bergmann do { 10790890f17SArnd Bergmann irq = dc21285_get_irq(); 10890890f17SArnd Bergmann if (!irq) 10990890f17SArnd Bergmann break; 11090890f17SArnd Bergmann 11190890f17SArnd Bergmann generic_handle_irq(irq); 11290890f17SArnd Bergmann } while (1); 11390890f17SArnd Bergmann } 11490890f17SArnd Bergmann 11590890f17SArnd Bergmann 1161da177e4SLinus Torvalds unsigned int mem_fclk_21285 = 50000000; 1171da177e4SLinus Torvalds 1181da177e4SLinus Torvalds EXPORT_SYMBOL(mem_fclk_21285); 1191da177e4SLinus Torvalds 1202b0d8c25SJeremy Kerr static int __init early_fclk(char *arg) 121613e09b4SRussell King { 1222b0d8c25SJeremy Kerr mem_fclk_21285 = simple_strtoul(arg, NULL, 0); 1232b0d8c25SJeremy Kerr return 0; 124613e09b4SRussell King } 125613e09b4SRussell King 1262b0d8c25SJeremy Kerr early_param("mem_fclk_21285", early_fclk); 127613e09b4SRussell King 1281da177e4SLinus Torvalds static int __init parse_tag_memclk(const struct tag *tag) 1291da177e4SLinus Torvalds { 1301da177e4SLinus Torvalds mem_fclk_21285 = tag->u.memclk.fmemclk; 1311da177e4SLinus Torvalds return 0; 1321da177e4SLinus Torvalds } 1331da177e4SLinus Torvalds 1341da177e4SLinus Torvalds __tagtable(ATAG_MEMCLK, parse_tag_memclk); 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds /* 1371da177e4SLinus Torvalds * Footbridge IRQ translation table 1381da177e4SLinus Torvalds * Converts from our IRQ numbers into FootBridge masks 1391da177e4SLinus Torvalds */ 1401da177e4SLinus Torvalds static const int fb_irq_mask[] = { 1411da177e4SLinus Torvalds IRQ_MASK_UART_RX, /* 0 */ 1421da177e4SLinus Torvalds IRQ_MASK_UART_TX, /* 1 */ 1431da177e4SLinus Torvalds IRQ_MASK_TIMER1, /* 2 */ 1441da177e4SLinus Torvalds IRQ_MASK_TIMER2, /* 3 */ 1451da177e4SLinus Torvalds IRQ_MASK_TIMER3, /* 4 */ 1461da177e4SLinus Torvalds IRQ_MASK_IN0, /* 5 */ 1471da177e4SLinus Torvalds IRQ_MASK_IN1, /* 6 */ 1481da177e4SLinus Torvalds IRQ_MASK_IN2, /* 7 */ 1491da177e4SLinus Torvalds IRQ_MASK_IN3, /* 8 */ 1501da177e4SLinus Torvalds IRQ_MASK_DOORBELLHOST, /* 9 */ 1511da177e4SLinus Torvalds IRQ_MASK_DMA1, /* 10 */ 1521da177e4SLinus Torvalds IRQ_MASK_DMA2, /* 11 */ 1531da177e4SLinus Torvalds IRQ_MASK_PCI, /* 12 */ 1541da177e4SLinus Torvalds IRQ_MASK_SDRAMPARITY, /* 13 */ 1551da177e4SLinus Torvalds IRQ_MASK_I2OINPOST, /* 14 */ 1561da177e4SLinus Torvalds IRQ_MASK_PCI_ABORT, /* 15 */ 1571da177e4SLinus Torvalds IRQ_MASK_PCI_SERR, /* 16 */ 1581da177e4SLinus Torvalds IRQ_MASK_DISCARD_TIMER, /* 17 */ 1591da177e4SLinus Torvalds IRQ_MASK_PCI_DPERR, /* 18 */ 1601da177e4SLinus Torvalds IRQ_MASK_PCI_PERR, /* 19 */ 1611da177e4SLinus Torvalds }; 1621da177e4SLinus Torvalds 163dc2caf6cSLennert Buytenhek static void fb_mask_irq(struct irq_data *d) 1641da177e4SLinus Torvalds { 165dc2caf6cSLennert Buytenhek *CSR_IRQ_DISABLE = fb_irq_mask[_DC21285_INR(d->irq)]; 1661da177e4SLinus Torvalds } 1671da177e4SLinus Torvalds 168dc2caf6cSLennert Buytenhek static void fb_unmask_irq(struct irq_data *d) 1691da177e4SLinus Torvalds { 170dc2caf6cSLennert Buytenhek *CSR_IRQ_ENABLE = fb_irq_mask[_DC21285_INR(d->irq)]; 1711da177e4SLinus Torvalds } 1721da177e4SLinus Torvalds 17310dd5ce2SRussell King static struct irq_chip fb_chip = { 174dc2caf6cSLennert Buytenhek .irq_ack = fb_mask_irq, 175dc2caf6cSLennert Buytenhek .irq_mask = fb_mask_irq, 176dc2caf6cSLennert Buytenhek .irq_unmask = fb_unmask_irq, 1771da177e4SLinus Torvalds }; 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds static void __init __fb_init_irq(void) 1801da177e4SLinus Torvalds { 1811da177e4SLinus Torvalds unsigned int irq; 1821da177e4SLinus Torvalds 1831da177e4SLinus Torvalds /* 1841da177e4SLinus Torvalds * setup DC21285 IRQs 1851da177e4SLinus Torvalds */ 1861da177e4SLinus Torvalds *CSR_IRQ_DISABLE = -1; 1871da177e4SLinus Torvalds *CSR_FIQ_DISABLE = -1; 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds for (irq = _DC21285_IRQ(0); irq < _DC21285_IRQ(20); irq++) { 190f38c02f3SThomas Gleixner irq_set_chip_and_handler(irq, &fb_chip, handle_level_irq); 191e8d36d5dSRob Herring irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); 1921da177e4SLinus Torvalds } 1931da177e4SLinus Torvalds } 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds void __init footbridge_init_irq(void) 1961da177e4SLinus Torvalds { 19790890f17SArnd Bergmann set_handle_irq(dc21285_handle_irq); 19890890f17SArnd Bergmann 1991da177e4SLinus Torvalds __fb_init_irq(); 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds if (machine_is_ebsa285()) 2021da177e4SLinus Torvalds /* The following is dependent on which slot 2031da177e4SLinus Torvalds * you plug the Southbridge card into. We 2041da177e4SLinus Torvalds * currently assume that you plug it into 2051da177e4SLinus Torvalds * the right-hand most slot. 2061da177e4SLinus Torvalds */ 2071da177e4SLinus Torvalds isa_init_irq(IRQ_PCI); 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds if (machine_is_cats()) 2101da177e4SLinus Torvalds isa_init_irq(IRQ_IN2); 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds if (machine_is_netwinder()) 2131da177e4SLinus Torvalds isa_init_irq(IRQ_IN3); 2141da177e4SLinus Torvalds } 2151da177e4SLinus Torvalds 2161da177e4SLinus Torvalds /* 2171da177e4SLinus Torvalds * Common mapping for all systems. Note that the outbound write flush is 2181da177e4SLinus Torvalds * commented out since there is a "No Fix" problem with it. Not mapping 2191da177e4SLinus Torvalds * it means that we have extra bullet protection on our feet. 2201da177e4SLinus Torvalds */ 221*b519c9c7SArnd Bergmann static struct map_desc ebsa285_host_io_desc[] __initdata = { 222a427ceefSDeepak Saxena { 223a427ceefSDeepak Saxena .virtual = ARMCSR_BASE, 224865052fdSRussell King .pfn = __phys_to_pfn(DC21285_ARMCSR_BASE), 225a427ceefSDeepak Saxena .length = ARMCSR_SIZE, 2266460177fSRussell King .type = MT_DEVICE, 227*b519c9c7SArnd Bergmann }, 228a427ceefSDeepak Saxena { 229a427ceefSDeepak Saxena .virtual = PCIMEM_BASE, 230a427ceefSDeepak Saxena .pfn = __phys_to_pfn(DC21285_PCI_MEM), 231a427ceefSDeepak Saxena .length = PCIMEM_SIZE, 2326460177fSRussell King .type = MT_DEVICE, 233a427ceefSDeepak Saxena }, { 234a427ceefSDeepak Saxena .virtual = PCICFG0_BASE, 235a427ceefSDeepak Saxena .pfn = __phys_to_pfn(DC21285_PCI_TYPE_0_CONFIG), 236a427ceefSDeepak Saxena .length = PCICFG0_SIZE, 2376460177fSRussell King .type = MT_DEVICE, 238a427ceefSDeepak Saxena }, { 239a427ceefSDeepak Saxena .virtual = PCICFG1_BASE, 240a427ceefSDeepak Saxena .pfn = __phys_to_pfn(DC21285_PCI_TYPE_1_CONFIG), 241a427ceefSDeepak Saxena .length = PCICFG1_SIZE, 2426460177fSRussell King .type = MT_DEVICE, 243a427ceefSDeepak Saxena }, { 244a427ceefSDeepak Saxena .virtual = PCIIACK_BASE, 245a427ceefSDeepak Saxena .pfn = __phys_to_pfn(DC21285_PCI_IACK), 246a427ceefSDeepak Saxena .length = PCIIACK_SIZE, 2476460177fSRussell King .type = MT_DEVICE, 2486460177fSRussell King }, 2491da177e4SLinus Torvalds }; 2501da177e4SLinus Torvalds 2511da177e4SLinus Torvalds void __init footbridge_map_io(void) 2521da177e4SLinus Torvalds { 2531da177e4SLinus Torvalds iotable_init(ebsa285_host_io_desc, ARRAY_SIZE(ebsa285_host_io_desc)); 2548ef6e620SRob Herring pci_map_io_early(__phys_to_pfn(DC21285_PCI_IO)); 25543659222SRussell King vga_base = PCIMEM_BASE; 2561da177e4SLinus Torvalds } 2571da177e4SLinus Torvalds 2587b6d864bSRobin Holt void footbridge_restart(enum reboot_mode mode, const char *cmd) 2596fca1e17SRussell King { 2607b6d864bSRobin Holt if (mode == REBOOT_SOFT) { 2616fca1e17SRussell King /* Jump into the ROM */ 2626fca1e17SRussell King soft_restart(0x41000000); 2636fca1e17SRussell King } else { 2646fca1e17SRussell King /* 2656fca1e17SRussell King * Force the watchdog to do a CPU reset. 2666fca1e17SRussell King * 2676fca1e17SRussell King * After making sure that the watchdog is disabled 2686fca1e17SRussell King * (so we can change the timer registers) we first 2696fca1e17SRussell King * enable the timer to autoreload itself. Next, the 2706fca1e17SRussell King * timer interval is set really short and any 2716fca1e17SRussell King * current interrupt request is cleared (so we can 2726fca1e17SRussell King * see an edge transition). Finally, TIMER4 is 2736fca1e17SRussell King * enabled as the watchdog. 2746fca1e17SRussell King */ 2756fca1e17SRussell King *CSR_SA110_CNTL &= ~(1 << 13); 2766fca1e17SRussell King *CSR_TIMER4_CNTL = TIMER_CNTL_ENABLE | 2776fca1e17SRussell King TIMER_CNTL_AUTORELOAD | 2786fca1e17SRussell King TIMER_CNTL_DIV16; 2796fca1e17SRussell King *CSR_TIMER4_LOAD = 0x2; 2806fca1e17SRussell King *CSR_TIMER4_CLR = 0; 2816fca1e17SRussell King *CSR_SA110_CNTL |= (1 << 13); 2826fca1e17SRussell King } 2836fca1e17SRussell King } 2846fca1e17SRussell King 285af6f23b8SChristoph Hellwig dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) 286c7baab5dSRussell King { 287*b519c9c7SArnd Bergmann return paddr + (BUS_OFFSET - PHYS_OFFSET); 288c7baab5dSRussell King } 289c7baab5dSRussell King 290af6f23b8SChristoph Hellwig phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dev_addr) 291af6f23b8SChristoph Hellwig { 292*b519c9c7SArnd Bergmann return dev_addr - (BUS_OFFSET - PHYS_OFFSET); 293af6f23b8SChristoph Hellwig } 294