broadcom_bus.c 3.1 KB

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