|
1 | 1 | #include <linux/efi.h> |
| 2 | +#include <linux/dmi.h> |
| 3 | +#include <linux/ioport.h> |
| 4 | +#include <linux/logic_pio.h> |
| 5 | +#include <linux/sizes.h> |
2 | 6 | #include <linux/memblock.h> |
3 | 7 | #include <linux/acpi.h> |
4 | 8 | #include <linux/kmemleak.h> |
@@ -88,6 +92,10 @@ static u64 __initdata bpi_flags = 0; |
88 | 92 |
|
89 | 93 | static int have_bpi = 0; |
90 | 94 |
|
| 95 | +static void __iomem *legacy_isa_base; |
| 96 | +static struct resource *legacy_isa_res; |
| 97 | +static struct fwnode_handle *legacy_isa_fwnode; |
| 98 | + |
91 | 99 | static __initdata struct { |
92 | 100 | size_t map_count; |
93 | 101 | struct loongarch_bpi_memmap{ |
@@ -718,3 +726,68 @@ void __init acpi_arch_init (){ |
718 | 726 | int loongarch_have_legacy_bpi (void){ |
719 | 727 | return have_bpi; |
720 | 728 | } |
| 729 | + |
| 730 | +/* DMI matching table for hardware requiring legacy ISA support */ |
| 731 | +static const struct dmi_system_id loongarch_legacy_isa_table[] = { |
| 732 | + { |
| 733 | + .ident = "Seewo CB.L3A6.MA01", |
| 734 | + .matches = { |
| 735 | + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "CB.L3A6.MA01"), |
| 736 | + }, |
| 737 | + }, |
| 738 | + { } |
| 739 | +}; |
| 740 | + |
| 741 | +static int __init add_legacy_isa_io(struct fwnode_handle *fwnode, |
| 742 | + resource_size_t hw_start, resource_size_t size) |
| 743 | +{ |
| 744 | + int ret = 0; |
| 745 | + unsigned long vaddr; |
| 746 | + struct logic_pio_hwaddr *range; |
| 747 | + |
| 748 | + range = kzalloc(sizeof(*range), GFP_ATOMIC); |
| 749 | + if (!range) |
| 750 | + return -ENOMEM; |
| 751 | + |
| 752 | + range->fwnode = fwnode; |
| 753 | + range->size = size = round_up(size, PAGE_SIZE); |
| 754 | + range->hw_start = hw_start; |
| 755 | + range->flags = LOGIC_PIO_CPU_MMIO; |
| 756 | + |
| 757 | + ret = logic_pio_register_range(range); |
| 758 | + if (ret) { |
| 759 | + kfree(range); |
| 760 | + return ret; |
| 761 | + } |
| 762 | + |
| 763 | + /* Legacy ISA must placed at the start of PCI_IOBASE */ |
| 764 | + if (range->io_start != 0) { |
| 765 | + logic_pio_unregister_range(range); |
| 766 | + kfree(range); |
| 767 | + return -EINVAL; |
| 768 | + } |
| 769 | + |
| 770 | + vaddr = (unsigned long)(PCI_IOBASE + range->io_start); |
| 771 | + vmap_page_range(vaddr, vaddr + size, hw_start, pgprot_device(PAGE_KERNEL)); |
| 772 | + |
| 773 | + return 0; |
| 774 | +} |
| 775 | + |
| 776 | +static __init int loongarch_reserve_pio_range(void) |
| 777 | +{ |
| 778 | + struct fwnode_handle *fwnode; |
| 779 | + |
| 780 | + if (!acpi_disabled && dmi_check_system(loongarch_legacy_isa_table)) { |
| 781 | + fwnode = acpi_alloc_fwnode_static(); |
| 782 | + pr_info("Legacy ISA: Detected Legacy hardware (%s), setting up legacy ISA I/O\n", |
| 783 | + dmi_get_system_info(DMI_PRODUCT_NAME)); |
| 784 | + if (add_legacy_isa_io(fwnode, LOONGSON_LIO_BASE, SZ_64K)) { |
| 785 | + pr_warn("Legacy ISA: Failed to setup legacy ISA I/O, some devices may not work!\n"); |
| 786 | + acpi_free_fwnode_static(fwnode); |
| 787 | + } |
| 788 | + } |
| 789 | + |
| 790 | + return 0; |
| 791 | +} |
| 792 | + |
| 793 | +arch_initcall(loongarch_reserve_pio_range); |
0 commit comments