1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (C) 2001,2002,2005 Broadcom Corporation |
4 | * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org) |
5 | */ |
6 | |
7 | /* |
8 | * BCM1x80/1x55-specific PCI support |
9 | * |
10 | * This module provides the glue between Linux's PCI subsystem |
11 | * and the hardware. We basically provide glue for accessing |
12 | * configuration space, and set up the translation for I/O |
13 | * space accesses. |
14 | * |
15 | * To access configuration space, we use ioremap. In the 32-bit |
16 | * kernel, this consumes either 4 or 8 page table pages, and 16MB of |
17 | * kernel mapped memory. Hopefully neither of these should be a huge |
18 | * problem. |
19 | * |
20 | * XXX: AT THIS TIME, ONLY the NATIVE PCI-X INTERFACE IS SUPPORTED. |
21 | */ |
22 | #include <linux/types.h> |
23 | #include <linux/pci.h> |
24 | #include <linux/kernel.h> |
25 | #include <linux/init.h> |
26 | #include <linux/mm.h> |
27 | #include <linux/console.h> |
28 | #include <linux/tty.h> |
29 | #include <linux/vt.h> |
30 | |
31 | #include <asm/sibyte/bcm1480_regs.h> |
32 | #include <asm/sibyte/bcm1480_scd.h> |
33 | #include <asm/sibyte/board.h> |
34 | #include <asm/io.h> |
35 | |
36 | /* |
37 | * Macros for calculating offsets into config space given a device |
38 | * structure or dev/fun/reg |
39 | */ |
40 | #define CFGOFFSET(bus, devfn, where) (((bus)<<16)+((devfn)<<8)+(where)) |
41 | #define CFGADDR(bus, devfn, where) CFGOFFSET((bus)->number, (devfn), where) |
42 | |
43 | static void *cfg_space; |
44 | |
45 | #define PCI_BUS_ENABLED 1 |
46 | #define PCI_DEVICE_MODE 2 |
47 | |
48 | static int bcm1480_bus_status; |
49 | |
50 | #define PCI_BRIDGE_DEVICE 0 |
51 | |
52 | /* |
53 | * Read/write 32-bit values in config space. |
54 | */ |
55 | static inline u32 READCFG32(u32 addr) |
56 | { |
57 | return *(u32 *)(cfg_space + (addr&~3)); |
58 | } |
59 | |
60 | static inline void WRITECFG32(u32 addr, u32 data) |
61 | { |
62 | *(u32 *)(cfg_space + (addr & ~3)) = data; |
63 | } |
64 | |
65 | int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) |
66 | { |
67 | if (pin == 0) |
68 | return -1; |
69 | |
70 | return K_BCM1480_INT_PCI_INTA - 1 + pin; |
71 | } |
72 | |
73 | /* Do platform specific device initialization at pci_enable_device() time */ |
74 | int pcibios_plat_dev_init(struct pci_dev *dev) |
75 | { |
76 | return 0; |
77 | } |
78 | |
79 | /* |
80 | * Some checks before doing config cycles: |
81 | * In PCI Device Mode, hide everything on bus 0 except the LDT host |
82 | * bridge. Otherwise, access is controlled by bridge MasterEn bits. |
83 | */ |
84 | static int bcm1480_pci_can_access(struct pci_bus *bus, int devfn) |
85 | { |
86 | u32 devno; |
87 | |
88 | if (!(bcm1480_bus_status & (PCI_BUS_ENABLED | PCI_DEVICE_MODE))) |
89 | return 0; |
90 | |
91 | if (bus->number == 0) { |
92 | devno = PCI_SLOT(devfn); |
93 | if (bcm1480_bus_status & PCI_DEVICE_MODE) |
94 | return 0; |
95 | else |
96 | return 1; |
97 | } else |
98 | return 1; |
99 | } |
100 | |
101 | /* |
102 | * Read/write access functions for various sizes of values |
103 | * in config space. Return all 1's for disallowed accesses |
104 | * for a kludgy but adequate simulation of master aborts. |
105 | */ |
106 | |
107 | static int bcm1480_pcibios_read(struct pci_bus *bus, unsigned int devfn, |
108 | int where, int size, u32 * val) |
109 | { |
110 | u32 data = 0; |
111 | |
112 | if ((size == 2) && (where & 1)) |
113 | return PCIBIOS_BAD_REGISTER_NUMBER; |
114 | else if ((size == 4) && (where & 3)) |
115 | return PCIBIOS_BAD_REGISTER_NUMBER; |
116 | |
117 | if (bcm1480_pci_can_access(bus, devfn)) |
118 | data = READCFG32(CFGADDR(bus, devfn, where)); |
119 | else |
120 | data = 0xFFFFFFFF; |
121 | |
122 | if (size == 1) |
123 | *val = (data >> ((where & 3) << 3)) & 0xff; |
124 | else if (size == 2) |
125 | *val = (data >> ((where & 3) << 3)) & 0xffff; |
126 | else |
127 | *val = data; |
128 | |
129 | return PCIBIOS_SUCCESSFUL; |
130 | } |
131 | |
132 | static int bcm1480_pcibios_write(struct pci_bus *bus, unsigned int devfn, |
133 | int where, int size, u32 val) |
134 | { |
135 | u32 cfgaddr = CFGADDR(bus, devfn, where); |
136 | u32 data = 0; |
137 | |
138 | if ((size == 2) && (where & 1)) |
139 | return PCIBIOS_BAD_REGISTER_NUMBER; |
140 | else if ((size == 4) && (where & 3)) |
141 | return PCIBIOS_BAD_REGISTER_NUMBER; |
142 | |
143 | if (!bcm1480_pci_can_access(bus, devfn)) |
144 | return PCIBIOS_BAD_REGISTER_NUMBER; |
145 | |
146 | data = READCFG32(addr: cfgaddr); |
147 | |
148 | if (size == 1) |
149 | data = (data & ~(0xff << ((where & 3) << 3))) | |
150 | (val << ((where & 3) << 3)); |
151 | else if (size == 2) |
152 | data = (data & ~(0xffff << ((where & 3) << 3))) | |
153 | (val << ((where & 3) << 3)); |
154 | else |
155 | data = val; |
156 | |
157 | WRITECFG32(addr: cfgaddr, data); |
158 | |
159 | return PCIBIOS_SUCCESSFUL; |
160 | } |
161 | |
162 | struct pci_ops bcm1480_pci_ops = { |
163 | .read = bcm1480_pcibios_read, |
164 | .write = bcm1480_pcibios_write, |
165 | }; |
166 | |
167 | static struct resource bcm1480_mem_resource = { |
168 | .name = "BCM1480 PCI MEM" , |
169 | .start = A_BCM1480_PHYS_PCI_MEM_MATCH_BYTES, |
170 | .end = A_BCM1480_PHYS_PCI_MEM_MATCH_BYTES + 0xfffffffUL, |
171 | .flags = IORESOURCE_MEM, |
172 | }; |
173 | |
174 | static struct resource bcm1480_io_resource = { |
175 | .name = "BCM1480 PCI I/O" , |
176 | .start = A_BCM1480_PHYS_PCI_IO_MATCH_BYTES, |
177 | .end = A_BCM1480_PHYS_PCI_IO_MATCH_BYTES + 0x1ffffffUL, |
178 | .flags = IORESOURCE_IO, |
179 | }; |
180 | |
181 | struct pci_controller bcm1480_controller = { |
182 | .pci_ops = &bcm1480_pci_ops, |
183 | .mem_resource = &bcm1480_mem_resource, |
184 | .io_resource = &bcm1480_io_resource, |
185 | .io_offset = A_BCM1480_PHYS_PCI_IO_MATCH_BYTES, |
186 | }; |
187 | |
188 | |
189 | static int __init bcm1480_pcibios_init(void) |
190 | { |
191 | uint32_t cmdreg; |
192 | uint64_t reg; |
193 | |
194 | /* CFE will assign PCI resources */ |
195 | pci_set_flags(flags: PCI_PROBE_ONLY); |
196 | |
197 | /* Avoid ISA compat ranges. */ |
198 | PCIBIOS_MIN_IO = 0x00008000UL; |
199 | PCIBIOS_MIN_MEM = 0x01000000UL; |
200 | |
201 | /* Set I/O resource limits. - unlimited for now to accommodate HT */ |
202 | ioport_resource.end = 0xffffffffUL; |
203 | iomem_resource.end = 0xffffffffUL; |
204 | |
205 | cfg_space = ioremap(offset: A_BCM1480_PHYS_PCI_CFG_MATCH_BITS, size: 16*1024*1024); |
206 | |
207 | /* |
208 | * See if the PCI bus has been configured by the firmware. |
209 | */ |
210 | reg = __raw_readq(addr: IOADDR(A_SCD_SYSTEM_CFG)); |
211 | if (!(reg & M_BCM1480_SYS_PCI_HOST)) { |
212 | bcm1480_bus_status |= PCI_DEVICE_MODE; |
213 | } else { |
214 | cmdreg = READCFG32(CFGOFFSET(0, PCI_DEVFN(PCI_BRIDGE_DEVICE, 0), |
215 | PCI_COMMAND)); |
216 | if (!(cmdreg & PCI_COMMAND_MASTER)) { |
217 | printk |
218 | ("PCI: Skipping PCI probe. Bus is not initialized.\n" ); |
219 | iounmap(addr: cfg_space); |
220 | return 1; /* XXX */ |
221 | } |
222 | bcm1480_bus_status |= PCI_BUS_ENABLED; |
223 | } |
224 | |
225 | /* turn on ExpMemEn */ |
226 | cmdreg = READCFG32(CFGOFFSET(0, PCI_DEVFN(PCI_BRIDGE_DEVICE, 0), 0x40)); |
227 | WRITECFG32(CFGOFFSET(0, PCI_DEVFN(PCI_BRIDGE_DEVICE, 0), 0x40), |
228 | data: cmdreg | 0x10); |
229 | cmdreg = READCFG32(CFGOFFSET(0, PCI_DEVFN(PCI_BRIDGE_DEVICE, 0), 0x40)); |
230 | |
231 | /* |
232 | * Establish mappings in KSEG2 (kernel virtual) to PCI I/O |
233 | * space. Use "match bytes" policy to make everything look |
234 | * little-endian. So, you need to also set |
235 | * CONFIG_SWAP_IO_SPACE, but this is the combination that |
236 | * works correctly with most of Linux's drivers. |
237 | * XXX ehs: Should this happen in PCI Device mode? |
238 | */ |
239 | |
240 | bcm1480_controller.io_map_base = (unsigned long) |
241 | ioremap(A_BCM1480_PHYS_PCI_IO_MATCH_BYTES, 65536); |
242 | bcm1480_controller.io_map_base -= bcm1480_controller.io_offset; |
243 | set_io_port_base(bcm1480_controller.io_map_base); |
244 | |
245 | register_pci_controller(&bcm1480_controller); |
246 | |
247 | #ifdef CONFIG_VGA_CONSOLE |
248 | console_lock(); |
249 | do_take_over_console(sw: &vga_con, first: 0, MAX_NR_CONSOLES-1, deflt: 1); |
250 | console_unlock(); |
251 | #endif |
252 | return 0; |
253 | } |
254 | |
255 | arch_initcall(bcm1480_pcibios_init); |
256 | |