18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2009 Lemote Inc. 48c2ecf20Sopenharmony_ci * Author: Wu Zhangjin, wuzhangjin@gmail.com 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/irqchip.h> 88c2ecf20Sopenharmony_ci#include <linux/logic_pio.h> 98c2ecf20Sopenharmony_ci#include <linux/memblock.h> 108c2ecf20Sopenharmony_ci#include <linux/of.h> 118c2ecf20Sopenharmony_ci#include <linux/of_address.h> 128c2ecf20Sopenharmony_ci#include <asm/bootinfo.h> 138c2ecf20Sopenharmony_ci#include <asm/traps.h> 148c2ecf20Sopenharmony_ci#include <asm/smp-ops.h> 158c2ecf20Sopenharmony_ci#include <asm/cacheflush.h> 168c2ecf20Sopenharmony_ci#include <asm/fw/fw.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <loongson.h> 198c2ecf20Sopenharmony_ci#include <boot_param.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define NODE_ID_OFFSET_ADDR ((void __iomem *)TO_UNCAC(0x1001041c)) 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ciu32 node_id_offset; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic void __init mips_nmi_setup(void) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci void *base; 288c2ecf20Sopenharmony_ci extern char except_vec_nmi[]; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci base = (void *)(CAC_BASE + 0x380); 318c2ecf20Sopenharmony_ci memcpy(base, except_vec_nmi, 0x80); 328c2ecf20Sopenharmony_ci flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_civoid ls7a_early_config(void) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci node_id_offset = ((readl(NODE_ID_OFFSET_ADDR) >> 8) & 0x1f) + 36; 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_civoid rs780e_early_config(void) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci node_id_offset = 37; 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_civoid virtual_early_config(void) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci node_id_offset = 44; 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_civoid __init prom_init(void) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci fw_init_cmdline(); 538c2ecf20Sopenharmony_ci prom_init_env(); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci /* init base address of io space */ 568c2ecf20Sopenharmony_ci set_io_port_base(PCI_IOBASE); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci loongson_sysconf.early_config(); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci prom_init_numa_memory(); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci /* Hardcode to CPU UART 0 */ 638c2ecf20Sopenharmony_ci setup_8250_early_printk_port(TO_UNCAC(LOONGSON_REG_BASE + 0x1e0), 0, 1024); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci register_smp_ops(&loongson3_smp_ops); 668c2ecf20Sopenharmony_ci board_nmi_handler_setup = mips_nmi_setup; 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_civoid __init prom_free_prom_memory(void) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic int __init add_legacy_isa_io(struct fwnode_handle *fwnode, resource_size_t hw_start, 748c2ecf20Sopenharmony_ci resource_size_t size) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci int ret = 0; 778c2ecf20Sopenharmony_ci struct logic_pio_hwaddr *range; 788c2ecf20Sopenharmony_ci unsigned long vaddr; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci range = kzalloc(sizeof(*range), GFP_ATOMIC); 818c2ecf20Sopenharmony_ci if (!range) 828c2ecf20Sopenharmony_ci return -ENOMEM; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci range->fwnode = fwnode; 858c2ecf20Sopenharmony_ci range->size = size = round_up(size, PAGE_SIZE); 868c2ecf20Sopenharmony_ci range->hw_start = hw_start; 878c2ecf20Sopenharmony_ci range->flags = LOGIC_PIO_CPU_MMIO; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci ret = logic_pio_register_range(range); 908c2ecf20Sopenharmony_ci if (ret) { 918c2ecf20Sopenharmony_ci kfree(range); 928c2ecf20Sopenharmony_ci return ret; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci /* Legacy ISA must placed at the start of PCI_IOBASE */ 968c2ecf20Sopenharmony_ci if (range->io_start != 0) { 978c2ecf20Sopenharmony_ci logic_pio_unregister_range(range); 988c2ecf20Sopenharmony_ci kfree(range); 998c2ecf20Sopenharmony_ci return -EINVAL; 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci vaddr = PCI_IOBASE + range->io_start; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci ioremap_page_range(vaddr, vaddr + size, hw_start, pgprot_device(PAGE_KERNEL)); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci return 0; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic __init void reserve_pio_range(void) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci struct device_node *np; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci for_each_node_by_name(np, "isa") { 1148c2ecf20Sopenharmony_ci struct of_range range; 1158c2ecf20Sopenharmony_ci struct of_range_parser parser; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci pr_info("ISA Bridge: %pOF\n", np); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (of_range_parser_init(&parser, np)) { 1208c2ecf20Sopenharmony_ci pr_info("Failed to parse resources.\n"); 1218c2ecf20Sopenharmony_ci break; 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci for_each_of_range(&parser, &range) { 1258c2ecf20Sopenharmony_ci switch (range.flags & IORESOURCE_TYPE_BITS) { 1268c2ecf20Sopenharmony_ci case IORESOURCE_IO: 1278c2ecf20Sopenharmony_ci pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n", 1288c2ecf20Sopenharmony_ci range.cpu_addr, 1298c2ecf20Sopenharmony_ci range.cpu_addr + range.size - 1, 1308c2ecf20Sopenharmony_ci range.bus_addr); 1318c2ecf20Sopenharmony_ci if (add_legacy_isa_io(&np->fwnode, range.cpu_addr, range.size)) 1328c2ecf20Sopenharmony_ci pr_warn("Failed to reserve legacy IO in Logic PIO\n"); 1338c2ecf20Sopenharmony_ci break; 1348c2ecf20Sopenharmony_ci case IORESOURCE_MEM: 1358c2ecf20Sopenharmony_ci pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx\n", 1368c2ecf20Sopenharmony_ci range.cpu_addr, 1378c2ecf20Sopenharmony_ci range.cpu_addr + range.size - 1, 1388c2ecf20Sopenharmony_ci range.bus_addr); 1398c2ecf20Sopenharmony_ci break; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci /* Reserve vgabios if it comes from firmware */ 1458c2ecf20Sopenharmony_ci if (loongson_sysconf.vgabios_addr) 1468c2ecf20Sopenharmony_ci memblock_reserve(virt_to_phys((void *)loongson_sysconf.vgabios_addr), 1478c2ecf20Sopenharmony_ci SZ_256K); 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_civoid __init arch_init_irq(void) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci reserve_pio_range(); 1538c2ecf20Sopenharmony_ci irqchip_init(); 1548c2ecf20Sopenharmony_ci} 155