^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2009 Lemote Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Author: Wu Zhangjin, wuzhangjin@gmail.com
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/irqchip.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/logic_pio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/memblock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <asm/bootinfo.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <asm/traps.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <asm/smp-ops.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <asm/cacheflush.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <asm/fw/fw.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <loongson.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <boot_param.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define NODE_ID_OFFSET_ADDR ((void __iomem *)TO_UNCAC(0x1001041c))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) u32 node_id_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static void __init mips_nmi_setup(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) void *base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) extern char except_vec_nmi[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) base = (void *)(CAC_BASE + 0x380);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) memcpy(base, except_vec_nmi, 0x80);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) flush_icache_range((unsigned long)base, (unsigned long)base + 0x80);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) void ls7a_early_config(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) node_id_offset = ((readl(NODE_ID_OFFSET_ADDR) >> 8) & 0x1f) + 36;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) void rs780e_early_config(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) node_id_offset = 37;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) void virtual_early_config(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) node_id_offset = 44;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) void __init prom_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) fw_init_cmdline();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) prom_init_env();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) /* init base address of io space */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) set_io_port_base(PCI_IOBASE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) loongson_sysconf.early_config();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) prom_init_numa_memory();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) /* Hardcode to CPU UART 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) setup_8250_early_printk_port(TO_UNCAC(LOONGSON_REG_BASE + 0x1e0), 0, 1024);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) register_smp_ops(&loongson3_smp_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) board_nmi_handler_setup = mips_nmi_setup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) void __init prom_free_prom_memory(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) static int __init add_legacy_isa_io(struct fwnode_handle *fwnode, resource_size_t hw_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) resource_size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) struct logic_pio_hwaddr *range;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) unsigned long vaddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) range = kzalloc(sizeof(*range), GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (!range)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) range->fwnode = fwnode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) range->size = size = round_up(size, PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) range->hw_start = hw_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) range->flags = LOGIC_PIO_CPU_MMIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) ret = logic_pio_register_range(range);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) kfree(range);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) /* Legacy ISA must placed at the start of PCI_IOBASE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) if (range->io_start != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) logic_pio_unregister_range(range);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) kfree(range);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) vaddr = PCI_IOBASE + range->io_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) ioremap_page_range(vaddr, vaddr + size, hw_start, pgprot_device(PAGE_KERNEL));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) static __init void reserve_pio_range(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) struct device_node *np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) for_each_node_by_name(np, "isa") {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) struct of_range range;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) struct of_range_parser parser;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) pr_info("ISA Bridge: %pOF\n", np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) if (of_range_parser_init(&parser, np)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) pr_info("Failed to parse resources.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) for_each_of_range(&parser, &range) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) switch (range.flags & IORESOURCE_TYPE_BITS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) case IORESOURCE_IO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) range.cpu_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) range.cpu_addr + range.size - 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) range.bus_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (add_legacy_isa_io(&np->fwnode, range.cpu_addr, range.size))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) pr_warn("Failed to reserve legacy IO in Logic PIO\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) case IORESOURCE_MEM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) range.cpu_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) range.cpu_addr + range.size - 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) range.bus_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) void __init arch_init_irq(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) reserve_pio_range();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) irqchip_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }