18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/arch/alpha/kernel/sys_ruffian.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1995 David A Rusling 68c2ecf20Sopenharmony_ci * Copyright (C) 1996 Jay A Estabrook 78c2ecf20Sopenharmony_ci * Copyright (C) 1998, 1999, 2000 Richard Henderson 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Code supporting the RUFFIAN. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/types.h> 148c2ecf20Sopenharmony_ci#include <linux/mm.h> 158c2ecf20Sopenharmony_ci#include <linux/sched.h> 168c2ecf20Sopenharmony_ci#include <linux/pci.h> 178c2ecf20Sopenharmony_ci#include <linux/ioport.h> 188c2ecf20Sopenharmony_ci#include <linux/timex.h> 198c2ecf20Sopenharmony_ci#include <linux/init.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <asm/ptrace.h> 228c2ecf20Sopenharmony_ci#include <asm/dma.h> 238c2ecf20Sopenharmony_ci#include <asm/irq.h> 248c2ecf20Sopenharmony_ci#include <asm/mmu_context.h> 258c2ecf20Sopenharmony_ci#include <asm/io.h> 268c2ecf20Sopenharmony_ci#include <asm/core_cia.h> 278c2ecf20Sopenharmony_ci#include <asm/tlbflush.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include "proto.h" 308c2ecf20Sopenharmony_ci#include "irq_impl.h" 318c2ecf20Sopenharmony_ci#include "pci_impl.h" 328c2ecf20Sopenharmony_ci#include "machvec_impl.h" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic void __init 368c2ecf20Sopenharmony_ciruffian_init_irq(void) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci /* Invert 6&7 for i82371 */ 398c2ecf20Sopenharmony_ci *(vulp)PYXIS_INT_HILO = 0x000000c0UL; mb(); 408c2ecf20Sopenharmony_ci *(vulp)PYXIS_INT_CNFG = 0x00002064UL; mb(); /* all clear */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci outb(0x11,0xA0); 438c2ecf20Sopenharmony_ci outb(0x08,0xA1); 448c2ecf20Sopenharmony_ci outb(0x02,0xA1); 458c2ecf20Sopenharmony_ci outb(0x01,0xA1); 468c2ecf20Sopenharmony_ci outb(0xFF,0xA1); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci outb(0x11,0x20); 498c2ecf20Sopenharmony_ci outb(0x00,0x21); 508c2ecf20Sopenharmony_ci outb(0x04,0x21); 518c2ecf20Sopenharmony_ci outb(0x01,0x21); 528c2ecf20Sopenharmony_ci outb(0xFF,0x21); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci /* Finish writing the 82C59A PIC Operation Control Words */ 558c2ecf20Sopenharmony_ci outb(0x20,0xA0); 568c2ecf20Sopenharmony_ci outb(0x20,0x20); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci init_i8259a_irqs(); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci /* Not interested in the bogus interrupts (0,3,6), 618c2ecf20Sopenharmony_ci NMI (1), HALT (2), flash (5), or 21142 (8). */ 628c2ecf20Sopenharmony_ci init_pyxis_irqs(0x16f0000); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci common_init_isa_dma(); 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#define RUFFIAN_LATCH DIV_ROUND_CLOSEST(PIT_TICK_RATE, HZ) 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic void __init 708c2ecf20Sopenharmony_ciruffian_init_rtc(void) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci /* Ruffian does not have the RTC connected to the CPU timer 738c2ecf20Sopenharmony_ci interrupt. Instead, it uses the PIT connected to IRQ 0. */ 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci /* Setup interval timer. */ 768c2ecf20Sopenharmony_ci outb(0x34, 0x43); /* binary, mode 2, LSB/MSB, ch 0 */ 778c2ecf20Sopenharmony_ci outb(RUFFIAN_LATCH & 0xff, 0x40); /* LSB */ 788c2ecf20Sopenharmony_ci outb(RUFFIAN_LATCH >> 8, 0x40); /* MSB */ 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci outb(0xb6, 0x43); /* pit counter 2: speaker */ 818c2ecf20Sopenharmony_ci outb(0x31, 0x42); 828c2ecf20Sopenharmony_ci outb(0x13, 0x42); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci if (request_irq(0, rtc_timer_interrupt, 0, "timer", NULL)) 858c2ecf20Sopenharmony_ci pr_err("Failed to request irq 0 (timer)\n"); 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic void 898c2ecf20Sopenharmony_ciruffian_kill_arch (int mode) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci cia_kill_arch(mode); 928c2ecf20Sopenharmony_ci#if 0 938c2ecf20Sopenharmony_ci /* This only causes re-entry to ARCSBIOS */ 948c2ecf20Sopenharmony_ci /* Perhaps this works for other PYXIS as well? */ 958c2ecf20Sopenharmony_ci *(vuip) PYXIS_RESET = 0x0000dead; 968c2ecf20Sopenharmony_ci mb(); 978c2ecf20Sopenharmony_ci#endif 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci/* 1018c2ecf20Sopenharmony_ci * Interrupt routing: 1028c2ecf20Sopenharmony_ci * 1038c2ecf20Sopenharmony_ci * Primary bus 1048c2ecf20Sopenharmony_ci * IdSel INTA INTB INTC INTD 1058c2ecf20Sopenharmony_ci * 21052 13 - - - - 1068c2ecf20Sopenharmony_ci * SIO 14 23 - - - 1078c2ecf20Sopenharmony_ci * 21143 15 44 - - - 1088c2ecf20Sopenharmony_ci * Slot 0 17 43 42 41 40 1098c2ecf20Sopenharmony_ci * 1108c2ecf20Sopenharmony_ci * Secondary bus 1118c2ecf20Sopenharmony_ci * IdSel INTA INTB INTC INTD 1128c2ecf20Sopenharmony_ci * Slot 0 8 (18) 19 18 17 16 1138c2ecf20Sopenharmony_ci * Slot 1 9 (19) 31 30 29 28 1148c2ecf20Sopenharmony_ci * Slot 2 10 (20) 27 26 25 24 1158c2ecf20Sopenharmony_ci * Slot 3 11 (21) 39 38 37 36 1168c2ecf20Sopenharmony_ci * Slot 4 12 (22) 35 34 33 32 1178c2ecf20Sopenharmony_ci * 53c875 13 (23) 20 - - - 1188c2ecf20Sopenharmony_ci * 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic int 1228c2ecf20Sopenharmony_ciruffian_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci static char irq_tab[11][5] = { 1258c2ecf20Sopenharmony_ci /*INT INTA INTB INTC INTD */ 1268c2ecf20Sopenharmony_ci {-1, -1, -1, -1, -1}, /* IdSel 13, 21052 */ 1278c2ecf20Sopenharmony_ci {-1, -1, -1, -1, -1}, /* IdSel 14, SIO */ 1288c2ecf20Sopenharmony_ci {44, 44, 44, 44, 44}, /* IdSel 15, 21143 */ 1298c2ecf20Sopenharmony_ci {-1, -1, -1, -1, -1}, /* IdSel 16, none */ 1308c2ecf20Sopenharmony_ci {43, 43, 42, 41, 40}, /* IdSel 17, 64-bit slot */ 1318c2ecf20Sopenharmony_ci /* the next 6 are actually on PCI bus 1, across the bridge */ 1328c2ecf20Sopenharmony_ci {19, 19, 18, 17, 16}, /* IdSel 8, slot 0 */ 1338c2ecf20Sopenharmony_ci {31, 31, 30, 29, 28}, /* IdSel 9, slot 1 */ 1348c2ecf20Sopenharmony_ci {27, 27, 26, 25, 24}, /* IdSel 10, slot 2 */ 1358c2ecf20Sopenharmony_ci {39, 39, 38, 37, 36}, /* IdSel 11, slot 3 */ 1368c2ecf20Sopenharmony_ci {35, 35, 34, 33, 32}, /* IdSel 12, slot 4 */ 1378c2ecf20Sopenharmony_ci {20, 20, 20, 20, 20}, /* IdSel 13, 53c875 */ 1388c2ecf20Sopenharmony_ci }; 1398c2ecf20Sopenharmony_ci const long min_idsel = 13, max_idsel = 23, irqs_per_slot = 5; 1408c2ecf20Sopenharmony_ci return COMMON_TABLE_LOOKUP; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic u8 1448c2ecf20Sopenharmony_ciruffian_swizzle(struct pci_dev *dev, u8 *pinp) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci int slot, pin = *pinp; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (dev->bus->number == 0) { 1498c2ecf20Sopenharmony_ci slot = PCI_SLOT(dev->devfn); 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci /* Check for the built-in bridge. */ 1528c2ecf20Sopenharmony_ci else if (PCI_SLOT(dev->bus->self->devfn) == 13) { 1538c2ecf20Sopenharmony_ci slot = PCI_SLOT(dev->devfn) + 10; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci else 1568c2ecf20Sopenharmony_ci { 1578c2ecf20Sopenharmony_ci /* Must be a card-based bridge. */ 1588c2ecf20Sopenharmony_ci do { 1598c2ecf20Sopenharmony_ci if (PCI_SLOT(dev->bus->self->devfn) == 13) { 1608c2ecf20Sopenharmony_ci slot = PCI_SLOT(dev->devfn) + 10; 1618c2ecf20Sopenharmony_ci break; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci pin = pci_swizzle_interrupt_pin(dev, pin); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* Move up the chain of bridges. */ 1668c2ecf20Sopenharmony_ci dev = dev->bus->self; 1678c2ecf20Sopenharmony_ci /* Slot of the next bridge. */ 1688c2ecf20Sopenharmony_ci slot = PCI_SLOT(dev->devfn); 1698c2ecf20Sopenharmony_ci } while (dev->bus->self); 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci *pinp = pin; 1728c2ecf20Sopenharmony_ci return slot; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci#ifdef BUILDING_FOR_MILO 1768c2ecf20Sopenharmony_ci/* 1778c2ecf20Sopenharmony_ci * The DeskStation Ruffian motherboard firmware does not place 1788c2ecf20Sopenharmony_ci * the memory size in the PALimpure area. Therefore, we use 1798c2ecf20Sopenharmony_ci * the Bank Configuration Registers in PYXIS to obtain the size. 1808c2ecf20Sopenharmony_ci */ 1818c2ecf20Sopenharmony_cistatic unsigned long __init 1828c2ecf20Sopenharmony_ciruffian_get_bank_size(unsigned long offset) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci unsigned long bank_addr, bank, ret = 0; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* Valid offsets are: 0x800, 0x840 and 0x880 1878c2ecf20Sopenharmony_ci since Ruffian only uses three banks. */ 1888c2ecf20Sopenharmony_ci bank_addr = (unsigned long)PYXIS_MCR + offset; 1898c2ecf20Sopenharmony_ci bank = *(vulp)bank_addr; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci /* Check BANK_ENABLE */ 1928c2ecf20Sopenharmony_ci if (bank & 0x01) { 1938c2ecf20Sopenharmony_ci static unsigned long size[] __initdata = { 1948c2ecf20Sopenharmony_ci 0x40000000UL, /* 0x00, 1G */ 1958c2ecf20Sopenharmony_ci 0x20000000UL, /* 0x02, 512M */ 1968c2ecf20Sopenharmony_ci 0x10000000UL, /* 0x04, 256M */ 1978c2ecf20Sopenharmony_ci 0x08000000UL, /* 0x06, 128M */ 1988c2ecf20Sopenharmony_ci 0x04000000UL, /* 0x08, 64M */ 1998c2ecf20Sopenharmony_ci 0x02000000UL, /* 0x0a, 32M */ 2008c2ecf20Sopenharmony_ci 0x01000000UL, /* 0x0c, 16M */ 2018c2ecf20Sopenharmony_ci 0x00800000UL, /* 0x0e, 8M */ 2028c2ecf20Sopenharmony_ci 0x80000000UL, /* 0x10, 2G */ 2038c2ecf20Sopenharmony_ci }; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci bank = (bank & 0x1e) >> 1; 2068c2ecf20Sopenharmony_ci if (bank < ARRAY_SIZE(size)) 2078c2ecf20Sopenharmony_ci ret = size[bank]; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci return ret; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci#endif /* BUILDING_FOR_MILO */ 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci/* 2158c2ecf20Sopenharmony_ci * The System Vector 2168c2ecf20Sopenharmony_ci */ 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistruct alpha_machine_vector ruffian_mv __initmv = { 2198c2ecf20Sopenharmony_ci .vector_name = "Ruffian", 2208c2ecf20Sopenharmony_ci DO_EV5_MMU, 2218c2ecf20Sopenharmony_ci DO_DEFAULT_RTC, 2228c2ecf20Sopenharmony_ci DO_PYXIS_IO, 2238c2ecf20Sopenharmony_ci .machine_check = cia_machine_check, 2248c2ecf20Sopenharmony_ci .max_isa_dma_address = ALPHA_RUFFIAN_MAX_ISA_DMA_ADDRESS, 2258c2ecf20Sopenharmony_ci .min_io_address = DEFAULT_IO_BASE, 2268c2ecf20Sopenharmony_ci .min_mem_address = DEFAULT_MEM_BASE, 2278c2ecf20Sopenharmony_ci .pci_dac_offset = PYXIS_DAC_OFFSET, 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci .nr_irqs = 48, 2308c2ecf20Sopenharmony_ci .device_interrupt = pyxis_device_interrupt, 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci .init_arch = pyxis_init_arch, 2338c2ecf20Sopenharmony_ci .init_irq = ruffian_init_irq, 2348c2ecf20Sopenharmony_ci .init_rtc = ruffian_init_rtc, 2358c2ecf20Sopenharmony_ci .init_pci = cia_init_pci, 2368c2ecf20Sopenharmony_ci .kill_arch = ruffian_kill_arch, 2378c2ecf20Sopenharmony_ci .pci_map_irq = ruffian_map_irq, 2388c2ecf20Sopenharmony_ci .pci_swizzle = ruffian_swizzle, 2398c2ecf20Sopenharmony_ci}; 2408c2ecf20Sopenharmony_ciALIAS_MV(ruffian) 241