^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) * Read address ranges from a Broadcom CNB20LE Host Bridge
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2010 Ira W. Snyder <iws@ovro.caltech.edu>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/dmi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <asm/pci_x86.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <asm/pci-direct.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "bus_numa.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) static void __init cnb20le_res(u8 bus, u8 slot, u8 func)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) struct pci_root_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) struct pci_root_res *root_res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) struct resource res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) u16 word1, word2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) u8 fbus, lbus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) /* read the PCI bus numbers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) fbus = read_pci_config_byte(bus, slot, func, 0x44);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) lbus = read_pci_config_byte(bus, slot, func, 0x45);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) info = alloc_pci_root_info(fbus, lbus, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * Add the legacy IDE ports on bus 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * These do not exist anywhere in the bridge registers, AFAICT. I do
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * not have the datasheet, so this is the best I can do.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) if (fbus == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) update_res(info, 0x01f0, 0x01f7, IORESOURCE_IO, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) update_res(info, 0x03f6, 0x03f6, IORESOURCE_IO, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) update_res(info, 0x0170, 0x0177, IORESOURCE_IO, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) update_res(info, 0x0376, 0x0376, IORESOURCE_IO, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) update_res(info, 0xffa0, 0xffaf, IORESOURCE_IO, 0);
^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) /* read the non-prefetchable memory window */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) word1 = read_pci_config_16(bus, slot, func, 0xc0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) word2 = read_pci_config_16(bus, slot, func, 0xc2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) if (word1 != word2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) res.start = ((resource_size_t) word1 << 16) | 0x0000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) res.end = ((resource_size_t) word2 << 16) | 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) res.flags = IORESOURCE_MEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) update_res(info, res.start, res.end, res.flags, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) /* read the prefetchable memory window */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) word1 = read_pci_config_16(bus, slot, func, 0xc4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) word2 = read_pci_config_16(bus, slot, func, 0xc6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) if (word1 != word2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) res.start = ((resource_size_t) word1 << 16) | 0x0000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) res.end = ((resource_size_t) word2 << 16) | 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) res.flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) update_res(info, res.start, res.end, res.flags, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) /* read the IO port window */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) word1 = read_pci_config_16(bus, slot, func, 0xd0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) word2 = read_pci_config_16(bus, slot, func, 0xd2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) if (word1 != word2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) res.start = word1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) res.end = word2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) res.flags = IORESOURCE_IO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) update_res(info, res.start, res.end, res.flags, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) /* print information about this host bridge */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) res.start = fbus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) res.end = lbus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) res.flags = IORESOURCE_BUS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) printk(KERN_INFO "CNB20LE PCI Host Bridge (domain 0000 %pR)\n", &res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) list_for_each_entry(root_res, &info->resources, list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) printk(KERN_INFO "host bridge window %pR\n", &root_res->res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static int __init broadcom_postcore_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) u8 bus = 0, slot = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) u32 id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) u16 vendor, device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) #ifdef CONFIG_ACPI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * We should get host bridge information from ACPI unless the BIOS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * doesn't support it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) if (!acpi_disabled && acpi_os_get_root_pointer())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) id = read_pci_config(bus, slot, 0, PCI_VENDOR_ID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) vendor = id & 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) device = (id >> 16) & 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) if (vendor == PCI_VENDOR_ID_SERVERWORKS &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) device == PCI_DEVICE_ID_SERVERWORKS_LE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) cnb20le_res(bus, slot, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) cnb20le_res(bus, slot, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) postcore_initcall(broadcom_postcore_init);