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> 15*af6f23b8SChristoph 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 (!footbridge_cfn_mode()) 2021da177e4SLinus Torvalds return; 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds if (machine_is_ebsa285()) 2051da177e4SLinus Torvalds /* The following is dependent on which slot 2061da177e4SLinus Torvalds * you plug the Southbridge card into. We 2071da177e4SLinus Torvalds * currently assume that you plug it into 2081da177e4SLinus Torvalds * the right-hand most slot. 2091da177e4SLinus Torvalds */ 2101da177e4SLinus Torvalds isa_init_irq(IRQ_PCI); 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds if (machine_is_cats()) 2131da177e4SLinus Torvalds isa_init_irq(IRQ_IN2); 2141da177e4SLinus Torvalds 2151da177e4SLinus Torvalds if (machine_is_netwinder()) 2161da177e4SLinus Torvalds isa_init_irq(IRQ_IN3); 2171da177e4SLinus Torvalds } 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds /* 2201da177e4SLinus Torvalds * Common mapping for all systems. Note that the outbound write flush is 2211da177e4SLinus Torvalds * commented out since there is a "No Fix" problem with it. Not mapping 2221da177e4SLinus Torvalds * it means that we have extra bullet protection on our feet. 2231da177e4SLinus Torvalds */ 2241da177e4SLinus Torvalds static struct map_desc fb_common_io_desc[] __initdata = { 225a427ceefSDeepak Saxena { 226a427ceefSDeepak Saxena .virtual = ARMCSR_BASE, 227865052fdSRussell King .pfn = __phys_to_pfn(DC21285_ARMCSR_BASE), 228a427ceefSDeepak Saxena .length = ARMCSR_SIZE, 2296460177fSRussell King .type = MT_DEVICE, 230a427ceefSDeepak Saxena } 2311da177e4SLinus Torvalds }; 2321da177e4SLinus Torvalds 2331da177e4SLinus Torvalds /* 2341da177e4SLinus Torvalds * The mapping when the footbridge is in host mode. We don't map any of 2351da177e4SLinus Torvalds * this when we are in add-in mode. 2361da177e4SLinus Torvalds */ 2371da177e4SLinus Torvalds static struct map_desc ebsa285_host_io_desc[] __initdata = { 2381da177e4SLinus Torvalds #if defined(CONFIG_ARCH_FOOTBRIDGE) && defined(CONFIG_FOOTBRIDGE_HOST) 239a427ceefSDeepak Saxena { 240a427ceefSDeepak Saxena .virtual = PCIMEM_BASE, 241a427ceefSDeepak Saxena .pfn = __phys_to_pfn(DC21285_PCI_MEM), 242a427ceefSDeepak Saxena .length = PCIMEM_SIZE, 2436460177fSRussell King .type = MT_DEVICE, 244a427ceefSDeepak Saxena }, { 245a427ceefSDeepak Saxena .virtual = PCICFG0_BASE, 246a427ceefSDeepak Saxena .pfn = __phys_to_pfn(DC21285_PCI_TYPE_0_CONFIG), 247a427ceefSDeepak Saxena .length = PCICFG0_SIZE, 2486460177fSRussell King .type = MT_DEVICE, 249a427ceefSDeepak Saxena }, { 250a427ceefSDeepak Saxena .virtual = PCICFG1_BASE, 251a427ceefSDeepak Saxena .pfn = __phys_to_pfn(DC21285_PCI_TYPE_1_CONFIG), 252a427ceefSDeepak Saxena .length = PCICFG1_SIZE, 2536460177fSRussell King .type = MT_DEVICE, 254a427ceefSDeepak Saxena }, { 255a427ceefSDeepak Saxena .virtual = PCIIACK_BASE, 256a427ceefSDeepak Saxena .pfn = __phys_to_pfn(DC21285_PCI_IACK), 257a427ceefSDeepak Saxena .length = PCIIACK_SIZE, 2586460177fSRussell King .type = MT_DEVICE, 2596460177fSRussell King }, 2601da177e4SLinus Torvalds #endif 2611da177e4SLinus Torvalds }; 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds void __init footbridge_map_io(void) 2641da177e4SLinus Torvalds { 2651da177e4SLinus Torvalds /* 2661da177e4SLinus Torvalds * Set up the common mapping first; we need this to 2671da177e4SLinus Torvalds * determine whether we're in host mode or not. 2681da177e4SLinus Torvalds */ 2691da177e4SLinus Torvalds iotable_init(fb_common_io_desc, ARRAY_SIZE(fb_common_io_desc)); 2701da177e4SLinus Torvalds 2711da177e4SLinus Torvalds /* 2721da177e4SLinus Torvalds * Now, work out what we've got to map in addition on this 2731da177e4SLinus Torvalds * platform. 2741da177e4SLinus Torvalds */ 2758ef6e620SRob Herring if (footbridge_cfn_mode()) { 2761da177e4SLinus Torvalds iotable_init(ebsa285_host_io_desc, ARRAY_SIZE(ebsa285_host_io_desc)); 2778ef6e620SRob Herring pci_map_io_early(__phys_to_pfn(DC21285_PCI_IO)); 2788ef6e620SRob Herring } 27943659222SRussell King 28043659222SRussell King vga_base = PCIMEM_BASE; 2811da177e4SLinus Torvalds } 2821da177e4SLinus Torvalds 2837b6d864bSRobin Holt void footbridge_restart(enum reboot_mode mode, const char *cmd) 2846fca1e17SRussell King { 2857b6d864bSRobin Holt if (mode == REBOOT_SOFT) { 2866fca1e17SRussell King /* Jump into the ROM */ 2876fca1e17SRussell King soft_restart(0x41000000); 2886fca1e17SRussell King } else { 2896fca1e17SRussell King /* 2906fca1e17SRussell King * Force the watchdog to do a CPU reset. 2916fca1e17SRussell King * 2926fca1e17SRussell King * After making sure that the watchdog is disabled 2936fca1e17SRussell King * (so we can change the timer registers) we first 2946fca1e17SRussell King * enable the timer to autoreload itself. Next, the 2956fca1e17SRussell King * timer interval is set really short and any 2966fca1e17SRussell King * current interrupt request is cleared (so we can 2976fca1e17SRussell King * see an edge transition). Finally, TIMER4 is 2986fca1e17SRussell King * enabled as the watchdog. 2996fca1e17SRussell King */ 3006fca1e17SRussell King *CSR_SA110_CNTL &= ~(1 << 13); 3016fca1e17SRussell King *CSR_TIMER4_CNTL = TIMER_CNTL_ENABLE | 3026fca1e17SRussell King TIMER_CNTL_AUTORELOAD | 3036fca1e17SRussell King TIMER_CNTL_DIV16; 3046fca1e17SRussell King *CSR_TIMER4_LOAD = 0x2; 3056fca1e17SRussell King *CSR_TIMER4_CLR = 0; 3066fca1e17SRussell King *CSR_SA110_CNTL |= (1 << 13); 3076fca1e17SRussell King } 3086fca1e17SRussell King } 3096fca1e17SRussell King 3101da177e4SLinus Torvalds #ifdef CONFIG_FOOTBRIDGE_ADDIN 3111da177e4SLinus Torvalds 312c7baab5dSRussell King static inline unsigned long fb_bus_sdram_offset(void) 313c7baab5dSRussell King { 314c7baab5dSRussell King return *CSR_PCISDRAMBASE & 0xfffffff0; 315c7baab5dSRussell King } 316c7baab5dSRussell King 3171da177e4SLinus Torvalds /* 3181da177e4SLinus Torvalds * These two functions convert virtual addresses to PCI addresses and PCI 3191da177e4SLinus Torvalds * addresses to virtual addresses. Note that it is only legal to use these 3201da177e4SLinus Torvalds * on memory obtained via get_zeroed_page or kmalloc. 3211da177e4SLinus Torvalds */ 3221da177e4SLinus Torvalds unsigned long __virt_to_bus(unsigned long res) 3231da177e4SLinus Torvalds { 3241da177e4SLinus Torvalds WARN_ON(res < PAGE_OFFSET || res >= (unsigned long)high_memory); 3251da177e4SLinus Torvalds 326c7baab5dSRussell King return res + (fb_bus_sdram_offset() - PAGE_OFFSET); 3271da177e4SLinus Torvalds } 3281da177e4SLinus Torvalds EXPORT_SYMBOL(__virt_to_bus); 3291da177e4SLinus Torvalds 3301da177e4SLinus Torvalds unsigned long __bus_to_virt(unsigned long res) 3311da177e4SLinus Torvalds { 332c7baab5dSRussell King res = res - (fb_bus_sdram_offset() - PAGE_OFFSET); 3331da177e4SLinus Torvalds 3341da177e4SLinus Torvalds WARN_ON(res < PAGE_OFFSET || res >= (unsigned long)high_memory); 3351da177e4SLinus Torvalds 3361da177e4SLinus Torvalds return res; 3371da177e4SLinus Torvalds } 3381da177e4SLinus Torvalds EXPORT_SYMBOL(__bus_to_virt); 339*af6f23b8SChristoph Hellwig #else 340*af6f23b8SChristoph Hellwig static inline unsigned long fb_bus_sdram_offset(void) 341c7baab5dSRussell King { 342*af6f23b8SChristoph Hellwig return BUS_OFFSET; 343c7baab5dSRussell King } 344*af6f23b8SChristoph Hellwig #endif /* CONFIG_FOOTBRIDGE_ADDIN */ 345c7baab5dSRussell King 346*af6f23b8SChristoph Hellwig dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) 347c7baab5dSRussell King { 348*af6f23b8SChristoph Hellwig return paddr + (fb_bus_sdram_offset() - PHYS_OFFSET); 349c7baab5dSRussell King } 350c7baab5dSRussell King 351*af6f23b8SChristoph Hellwig phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dev_addr) 352*af6f23b8SChristoph Hellwig { 353*af6f23b8SChristoph Hellwig return dev_addr - (fb_bus_sdram_offset() - PHYS_OFFSET); 354*af6f23b8SChristoph Hellwig } 355