18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/arch/arm/mach-footbridge/common.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1998-2000 Russell King, Dave Gilbert. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#include <linux/module.h> 88c2ecf20Sopenharmony_ci#include <linux/types.h> 98c2ecf20Sopenharmony_ci#include <linux/mm.h> 108c2ecf20Sopenharmony_ci#include <linux/ioport.h> 118c2ecf20Sopenharmony_ci#include <linux/list.h> 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/io.h> 148c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 158c2ecf20Sopenharmony_ci#include <video/vga.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <asm/page.h> 188c2ecf20Sopenharmony_ci#include <asm/irq.h> 198c2ecf20Sopenharmony_ci#include <asm/mach-types.h> 208c2ecf20Sopenharmony_ci#include <asm/setup.h> 218c2ecf20Sopenharmony_ci#include <asm/system_misc.h> 228c2ecf20Sopenharmony_ci#include <asm/hardware/dec21285.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <asm/mach/irq.h> 258c2ecf20Sopenharmony_ci#include <asm/mach/map.h> 268c2ecf20Sopenharmony_ci#include <asm/mach/pci.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include "common.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ciunsigned int mem_fclk_21285 = 50000000; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mem_fclk_21285); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic int __init early_fclk(char *arg) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci mem_fclk_21285 = simple_strtoul(arg, NULL, 0); 378c2ecf20Sopenharmony_ci return 0; 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ciearly_param("mem_fclk_21285", early_fclk); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic int __init parse_tag_memclk(const struct tag *tag) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci mem_fclk_21285 = tag->u.memclk.fmemclk; 458c2ecf20Sopenharmony_ci return 0; 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci__tagtable(ATAG_MEMCLK, parse_tag_memclk); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* 518c2ecf20Sopenharmony_ci * Footbridge IRQ translation table 528c2ecf20Sopenharmony_ci * Converts from our IRQ numbers into FootBridge masks 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_cistatic const int fb_irq_mask[] = { 558c2ecf20Sopenharmony_ci IRQ_MASK_UART_RX, /* 0 */ 568c2ecf20Sopenharmony_ci IRQ_MASK_UART_TX, /* 1 */ 578c2ecf20Sopenharmony_ci IRQ_MASK_TIMER1, /* 2 */ 588c2ecf20Sopenharmony_ci IRQ_MASK_TIMER2, /* 3 */ 598c2ecf20Sopenharmony_ci IRQ_MASK_TIMER3, /* 4 */ 608c2ecf20Sopenharmony_ci IRQ_MASK_IN0, /* 5 */ 618c2ecf20Sopenharmony_ci IRQ_MASK_IN1, /* 6 */ 628c2ecf20Sopenharmony_ci IRQ_MASK_IN2, /* 7 */ 638c2ecf20Sopenharmony_ci IRQ_MASK_IN3, /* 8 */ 648c2ecf20Sopenharmony_ci IRQ_MASK_DOORBELLHOST, /* 9 */ 658c2ecf20Sopenharmony_ci IRQ_MASK_DMA1, /* 10 */ 668c2ecf20Sopenharmony_ci IRQ_MASK_DMA2, /* 11 */ 678c2ecf20Sopenharmony_ci IRQ_MASK_PCI, /* 12 */ 688c2ecf20Sopenharmony_ci IRQ_MASK_SDRAMPARITY, /* 13 */ 698c2ecf20Sopenharmony_ci IRQ_MASK_I2OINPOST, /* 14 */ 708c2ecf20Sopenharmony_ci IRQ_MASK_PCI_ABORT, /* 15 */ 718c2ecf20Sopenharmony_ci IRQ_MASK_PCI_SERR, /* 16 */ 728c2ecf20Sopenharmony_ci IRQ_MASK_DISCARD_TIMER, /* 17 */ 738c2ecf20Sopenharmony_ci IRQ_MASK_PCI_DPERR, /* 18 */ 748c2ecf20Sopenharmony_ci IRQ_MASK_PCI_PERR, /* 19 */ 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic void fb_mask_irq(struct irq_data *d) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci *CSR_IRQ_DISABLE = fb_irq_mask[_DC21285_INR(d->irq)]; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic void fb_unmask_irq(struct irq_data *d) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci *CSR_IRQ_ENABLE = fb_irq_mask[_DC21285_INR(d->irq)]; 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic struct irq_chip fb_chip = { 888c2ecf20Sopenharmony_ci .irq_ack = fb_mask_irq, 898c2ecf20Sopenharmony_ci .irq_mask = fb_mask_irq, 908c2ecf20Sopenharmony_ci .irq_unmask = fb_unmask_irq, 918c2ecf20Sopenharmony_ci}; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic void __init __fb_init_irq(void) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci unsigned int irq; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci /* 988c2ecf20Sopenharmony_ci * setup DC21285 IRQs 998c2ecf20Sopenharmony_ci */ 1008c2ecf20Sopenharmony_ci *CSR_IRQ_DISABLE = -1; 1018c2ecf20Sopenharmony_ci *CSR_FIQ_DISABLE = -1; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci for (irq = _DC21285_IRQ(0); irq < _DC21285_IRQ(20); irq++) { 1048c2ecf20Sopenharmony_ci irq_set_chip_and_handler(irq, &fb_chip, handle_level_irq); 1058c2ecf20Sopenharmony_ci irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_civoid __init footbridge_init_irq(void) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci __fb_init_irq(); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci if (!footbridge_cfn_mode()) 1148c2ecf20Sopenharmony_ci return; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci if (machine_is_ebsa285()) 1178c2ecf20Sopenharmony_ci /* The following is dependent on which slot 1188c2ecf20Sopenharmony_ci * you plug the Southbridge card into. We 1198c2ecf20Sopenharmony_ci * currently assume that you plug it into 1208c2ecf20Sopenharmony_ci * the right-hand most slot. 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_ci isa_init_irq(IRQ_PCI); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (machine_is_cats()) 1258c2ecf20Sopenharmony_ci isa_init_irq(IRQ_IN2); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (machine_is_netwinder()) 1288c2ecf20Sopenharmony_ci isa_init_irq(IRQ_IN3); 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci/* 1328c2ecf20Sopenharmony_ci * Common mapping for all systems. Note that the outbound write flush is 1338c2ecf20Sopenharmony_ci * commented out since there is a "No Fix" problem with it. Not mapping 1348c2ecf20Sopenharmony_ci * it means that we have extra bullet protection on our feet. 1358c2ecf20Sopenharmony_ci */ 1368c2ecf20Sopenharmony_cistatic struct map_desc fb_common_io_desc[] __initdata = { 1378c2ecf20Sopenharmony_ci { 1388c2ecf20Sopenharmony_ci .virtual = ARMCSR_BASE, 1398c2ecf20Sopenharmony_ci .pfn = __phys_to_pfn(DC21285_ARMCSR_BASE), 1408c2ecf20Sopenharmony_ci .length = ARMCSR_SIZE, 1418c2ecf20Sopenharmony_ci .type = MT_DEVICE, 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci}; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci/* 1468c2ecf20Sopenharmony_ci * The mapping when the footbridge is in host mode. We don't map any of 1478c2ecf20Sopenharmony_ci * this when we are in add-in mode. 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_cistatic struct map_desc ebsa285_host_io_desc[] __initdata = { 1508c2ecf20Sopenharmony_ci#if defined(CONFIG_ARCH_FOOTBRIDGE) && defined(CONFIG_FOOTBRIDGE_HOST) 1518c2ecf20Sopenharmony_ci { 1528c2ecf20Sopenharmony_ci .virtual = PCIMEM_BASE, 1538c2ecf20Sopenharmony_ci .pfn = __phys_to_pfn(DC21285_PCI_MEM), 1548c2ecf20Sopenharmony_ci .length = PCIMEM_SIZE, 1558c2ecf20Sopenharmony_ci .type = MT_DEVICE, 1568c2ecf20Sopenharmony_ci }, { 1578c2ecf20Sopenharmony_ci .virtual = PCICFG0_BASE, 1588c2ecf20Sopenharmony_ci .pfn = __phys_to_pfn(DC21285_PCI_TYPE_0_CONFIG), 1598c2ecf20Sopenharmony_ci .length = PCICFG0_SIZE, 1608c2ecf20Sopenharmony_ci .type = MT_DEVICE, 1618c2ecf20Sopenharmony_ci }, { 1628c2ecf20Sopenharmony_ci .virtual = PCICFG1_BASE, 1638c2ecf20Sopenharmony_ci .pfn = __phys_to_pfn(DC21285_PCI_TYPE_1_CONFIG), 1648c2ecf20Sopenharmony_ci .length = PCICFG1_SIZE, 1658c2ecf20Sopenharmony_ci .type = MT_DEVICE, 1668c2ecf20Sopenharmony_ci }, { 1678c2ecf20Sopenharmony_ci .virtual = PCIIACK_BASE, 1688c2ecf20Sopenharmony_ci .pfn = __phys_to_pfn(DC21285_PCI_IACK), 1698c2ecf20Sopenharmony_ci .length = PCIIACK_SIZE, 1708c2ecf20Sopenharmony_ci .type = MT_DEVICE, 1718c2ecf20Sopenharmony_ci }, 1728c2ecf20Sopenharmony_ci#endif 1738c2ecf20Sopenharmony_ci}; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_civoid __init footbridge_map_io(void) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci /* 1788c2ecf20Sopenharmony_ci * Set up the common mapping first; we need this to 1798c2ecf20Sopenharmony_ci * determine whether we're in host mode or not. 1808c2ecf20Sopenharmony_ci */ 1818c2ecf20Sopenharmony_ci iotable_init(fb_common_io_desc, ARRAY_SIZE(fb_common_io_desc)); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci /* 1848c2ecf20Sopenharmony_ci * Now, work out what we've got to map in addition on this 1858c2ecf20Sopenharmony_ci * platform. 1868c2ecf20Sopenharmony_ci */ 1878c2ecf20Sopenharmony_ci if (footbridge_cfn_mode()) { 1888c2ecf20Sopenharmony_ci iotable_init(ebsa285_host_io_desc, ARRAY_SIZE(ebsa285_host_io_desc)); 1898c2ecf20Sopenharmony_ci pci_map_io_early(__phys_to_pfn(DC21285_PCI_IO)); 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci vga_base = PCIMEM_BASE; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_civoid footbridge_restart(enum reboot_mode mode, const char *cmd) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci if (mode == REBOOT_SOFT) { 1988c2ecf20Sopenharmony_ci /* Jump into the ROM */ 1998c2ecf20Sopenharmony_ci soft_restart(0x41000000); 2008c2ecf20Sopenharmony_ci } else { 2018c2ecf20Sopenharmony_ci /* 2028c2ecf20Sopenharmony_ci * Force the watchdog to do a CPU reset. 2038c2ecf20Sopenharmony_ci * 2048c2ecf20Sopenharmony_ci * After making sure that the watchdog is disabled 2058c2ecf20Sopenharmony_ci * (so we can change the timer registers) we first 2068c2ecf20Sopenharmony_ci * enable the timer to autoreload itself. Next, the 2078c2ecf20Sopenharmony_ci * timer interval is set really short and any 2088c2ecf20Sopenharmony_ci * current interrupt request is cleared (so we can 2098c2ecf20Sopenharmony_ci * see an edge transition). Finally, TIMER4 is 2108c2ecf20Sopenharmony_ci * enabled as the watchdog. 2118c2ecf20Sopenharmony_ci */ 2128c2ecf20Sopenharmony_ci *CSR_SA110_CNTL &= ~(1 << 13); 2138c2ecf20Sopenharmony_ci *CSR_TIMER4_CNTL = TIMER_CNTL_ENABLE | 2148c2ecf20Sopenharmony_ci TIMER_CNTL_AUTORELOAD | 2158c2ecf20Sopenharmony_ci TIMER_CNTL_DIV16; 2168c2ecf20Sopenharmony_ci *CSR_TIMER4_LOAD = 0x2; 2178c2ecf20Sopenharmony_ci *CSR_TIMER4_CLR = 0; 2188c2ecf20Sopenharmony_ci *CSR_SA110_CNTL |= (1 << 13); 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci#ifdef CONFIG_FOOTBRIDGE_ADDIN 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic inline unsigned long fb_bus_sdram_offset(void) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci return *CSR_PCISDRAMBASE & 0xfffffff0; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci/* 2308c2ecf20Sopenharmony_ci * These two functions convert virtual addresses to PCI addresses and PCI 2318c2ecf20Sopenharmony_ci * addresses to virtual addresses. Note that it is only legal to use these 2328c2ecf20Sopenharmony_ci * on memory obtained via get_zeroed_page or kmalloc. 2338c2ecf20Sopenharmony_ci */ 2348c2ecf20Sopenharmony_ciunsigned long __virt_to_bus(unsigned long res) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci WARN_ON(res < PAGE_OFFSET || res >= (unsigned long)high_memory); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return res + (fb_bus_sdram_offset() - PAGE_OFFSET); 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__virt_to_bus); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ciunsigned long __bus_to_virt(unsigned long res) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci res = res - (fb_bus_sdram_offset() - PAGE_OFFSET); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci WARN_ON(res < PAGE_OFFSET || res >= (unsigned long)high_memory); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci return res; 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__bus_to_virt); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ciunsigned long __pfn_to_bus(unsigned long pfn) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci return __pfn_to_phys(pfn) + (fb_bus_sdram_offset() - PHYS_OFFSET); 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__pfn_to_bus); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ciunsigned long __bus_to_pfn(unsigned long bus) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci return __phys_to_pfn(bus - (fb_bus_sdram_offset() - PHYS_OFFSET)); 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__bus_to_pfn); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci#endif 265