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