blob: 950a2475c500720e978ba370cfac700e08e358b9 [file] [log] [blame]
wdenkc6097192002-11-03 00:24:07 +00001/*
2 * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
3 * Andreas Heppel <aheppel@sysgo.de>
4 *
wdenkf07771c2003-05-28 08:06:31 +00005 * (C) Copyright 2002, 2003
wdenkc6097192002-11-03 00:24:07 +00006 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
7 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02008 * SPDX-License-Identifier: GPL-2.0+
wdenkc6097192002-11-03 00:24:07 +00009 */
10
11/*
12 * PCI routines
13 */
14
15#include <common.h>
16
wdenkc6097192002-11-03 00:24:07 +000017#include <command.h>
wdenkc6097192002-11-03 00:24:07 +000018#include <asm/processor.h>
19#include <asm/io.h>
20#include <pci.h>
21
Bin Meng8f9052f2014-12-30 22:53:21 +080022DECLARE_GLOBAL_DATA_PTR;
23
wdenkf07771c2003-05-28 08:06:31 +000024#define PCI_HOSE_OP(rw, size, type) \
Wolfgang Denk53677ef2008-05-20 16:00:29 +020025int pci_hose_##rw##_config_##size(struct pci_controller *hose, \
26 pci_dev_t dev, \
wdenkf07771c2003-05-28 08:06:31 +000027 int offset, type value) \
28{ \
29 return hose->rw##_##size(hose, dev, offset, value); \
wdenkc6097192002-11-03 00:24:07 +000030}
31
32PCI_HOSE_OP(read, byte, u8 *)
33PCI_HOSE_OP(read, word, u16 *)
34PCI_HOSE_OP(read, dword, u32 *)
35PCI_HOSE_OP(write, byte, u8)
36PCI_HOSE_OP(write, word, u16)
37PCI_HOSE_OP(write, dword, u32)
38
wdenkf07771c2003-05-28 08:06:31 +000039#define PCI_OP(rw, size, type, error_code) \
40int pci_##rw##_config_##size(pci_dev_t dev, int offset, type value) \
41{ \
42 struct pci_controller *hose = pci_bus_to_hose(PCI_BUS(dev)); \
43 \
44 if (!hose) \
45 { \
46 error_code; \
47 return -1; \
48 } \
49 \
50 return pci_hose_##rw##_config_##size(hose, dev, offset, value); \
wdenkc6097192002-11-03 00:24:07 +000051}
52
53PCI_OP(read, byte, u8 *, *value = 0xff)
54PCI_OP(read, word, u16 *, *value = 0xffff)
55PCI_OP(read, dword, u32 *, *value = 0xffffffff)
56PCI_OP(write, byte, u8, )
57PCI_OP(write, word, u16, )
58PCI_OP(write, dword, u32, )
59
wdenkf07771c2003-05-28 08:06:31 +000060#define PCI_READ_VIA_DWORD_OP(size, type, off_mask) \
61int pci_hose_read_config_##size##_via_dword(struct pci_controller *hose,\
Wolfgang Denk53677ef2008-05-20 16:00:29 +020062 pci_dev_t dev, \
wdenkf07771c2003-05-28 08:06:31 +000063 int offset, type val) \
64{ \
65 u32 val32; \
66 \
Shinya Kuribayashi815b5bd2007-08-17 12:43:44 +090067 if (pci_hose_read_config_dword(hose, dev, offset & 0xfc, &val32) < 0) { \
68 *val = -1; \
wdenkf07771c2003-05-28 08:06:31 +000069 return -1; \
Shinya Kuribayashi815b5bd2007-08-17 12:43:44 +090070 } \
wdenkf07771c2003-05-28 08:06:31 +000071 \
72 *val = (val32 >> ((offset & (int)off_mask) * 8)); \
73 \
74 return 0; \
wdenkc6097192002-11-03 00:24:07 +000075}
76
wdenkf07771c2003-05-28 08:06:31 +000077#define PCI_WRITE_VIA_DWORD_OP(size, type, off_mask, val_mask) \
78int pci_hose_write_config_##size##_via_dword(struct pci_controller *hose,\
Wolfgang Denk53677ef2008-05-20 16:00:29 +020079 pci_dev_t dev, \
wdenkf07771c2003-05-28 08:06:31 +000080 int offset, type val) \
81{ \
wdenk498b8db2004-04-18 22:26:17 +000082 u32 val32, mask, ldata, shift; \
wdenkf07771c2003-05-28 08:06:31 +000083 \
84 if (pci_hose_read_config_dword(hose, dev, offset & 0xfc, &val32) < 0)\
85 return -1; \
86 \
wdenk498b8db2004-04-18 22:26:17 +000087 shift = ((offset & (int)off_mask) * 8); \
88 ldata = (((unsigned long)val) & val_mask) << shift; \
89 mask = val_mask << shift; \
wdenkf07771c2003-05-28 08:06:31 +000090 val32 = (val32 & ~mask) | ldata; \
91 \
92 if (pci_hose_write_config_dword(hose, dev, offset & 0xfc, val32) < 0)\
93 return -1; \
94 \
95 return 0; \
wdenkc6097192002-11-03 00:24:07 +000096}
97
98PCI_READ_VIA_DWORD_OP(byte, u8 *, 0x03)
99PCI_READ_VIA_DWORD_OP(word, u16 *, 0x02)
100PCI_WRITE_VIA_DWORD_OP(byte, u8, 0x03, 0x000000ff)
101PCI_WRITE_VIA_DWORD_OP(word, u16, 0x02, 0x0000ffff)
102
Becky Bruce6e61fae2009-02-03 18:10:50 -0600103/* Get a virtual address associated with a BAR region */
104void *pci_map_bar(pci_dev_t pdev, int bar, int flags)
105{
106 pci_addr_t pci_bus_addr;
Kumar Galacf5787f2012-09-19 04:47:36 +0000107 u32 bar_response;
Becky Bruce6e61fae2009-02-03 18:10:50 -0600108
109 /* read BAR address */
110 pci_read_config_dword(pdev, bar, &bar_response);
Kumar Galacf5787f2012-09-19 04:47:36 +0000111 pci_bus_addr = (pci_addr_t)(bar_response & ~0xf);
Becky Bruce6e61fae2009-02-03 18:10:50 -0600112
113 /*
114 * Pass "0" as the length argument to pci_bus_to_virt. The arg
115 * isn't actualy used on any platform because u-boot assumes a static
116 * linear mapping. In the future, this could read the BAR size
117 * and pass that as the size if needed.
118 */
119 return pci_bus_to_virt(pdev, pci_bus_addr, flags, 0, MAP_NOCACHE);
120}
121
wdenkc6097192002-11-03 00:24:07 +0000122/*
123 *
124 */
125
John Schmoller96d61602010-10-22 00:20:23 -0500126static struct pci_controller* hose_head;
wdenkc6097192002-11-03 00:24:07 +0000127
Bin Meng8f9052f2014-12-30 22:53:21 +0800128struct pci_controller *pci_get_hose_head(void)
129{
130 if (gd->hose)
131 return gd->hose;
132
133 return hose_head;
134}
135
wdenkc6097192002-11-03 00:24:07 +0000136void pci_register_hose(struct pci_controller* hose)
137{
138 struct pci_controller **phose = &hose_head;
139
140 while(*phose)
141 phose = &(*phose)->next;
142
143 hose->next = NULL;
144
145 *phose = hose;
146}
147
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000148struct pci_controller *pci_bus_to_hose(int bus)
wdenkc6097192002-11-03 00:24:07 +0000149{
150 struct pci_controller *hose;
151
Bin Meng8f9052f2014-12-30 22:53:21 +0800152 for (hose = pci_get_hose_head(); hose; hose = hose->next) {
wdenkf07771c2003-05-28 08:06:31 +0000153 if (bus >= hose->first_busno && bus <= hose->last_busno)
wdenkc6097192002-11-03 00:24:07 +0000154 return hose;
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000155 }
wdenkc6097192002-11-03 00:24:07 +0000156
Rafal Jaworowski6902df52005-10-17 02:39:53 +0200157 printf("pci_bus_to_hose() failed\n");
wdenkc6097192002-11-03 00:24:07 +0000158 return NULL;
159}
160
Kumar Gala3a0e3c22010-12-17 05:57:25 -0600161struct pci_controller *find_hose_by_cfg_addr(void *cfg_addr)
162{
163 struct pci_controller *hose;
164
Bin Meng8f9052f2014-12-30 22:53:21 +0800165 for (hose = pci_get_hose_head(); hose; hose = hose->next) {
Kumar Gala3a0e3c22010-12-17 05:57:25 -0600166 if (hose->cfg_addr == cfg_addr)
167 return hose;
168 }
169
170 return NULL;
171}
172
Anton Vorontsovcc2a8c72009-02-19 18:20:41 +0300173int pci_last_busno(void)
174{
Bin Meng8f9052f2014-12-30 22:53:21 +0800175 struct pci_controller *hose = pci_get_hose_head();
Anton Vorontsovcc2a8c72009-02-19 18:20:41 +0300176
177 if (!hose)
178 return -1;
179
180 while (hose->next)
181 hose = hose->next;
182
183 return hose->last_busno;
184}
185
wdenkc6097192002-11-03 00:24:07 +0000186pci_dev_t pci_find_devices(struct pci_device_id *ids, int index)
187{
188 struct pci_controller * hose;
189 u16 vendor, device;
190 u8 header_type;
191 pci_dev_t bdf;
192 int i, bus, found_multi = 0;
193
Bin Meng8f9052f2014-12-30 22:53:21 +0800194 for (hose = pci_get_hose_head(); hose; hose = hose->next) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200195#ifdef CONFIG_SYS_SCSI_SCAN_BUS_REVERSE
wdenkc6097192002-11-03 00:24:07 +0000196 for (bus = hose->last_busno; bus >= hose->first_busno; bus--)
197#else
198 for (bus = hose->first_busno; bus <= hose->last_busno; bus++)
199#endif
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000200 for (bdf = PCI_BDF(bus, 0, 0);
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000201 bdf < PCI_BDF(bus + 1, 0, 0);
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000202 bdf += PCI_BDF(0, 0, 1)) {
Thierry Reding4efe52b2014-11-12 18:26:49 -0700203 if (pci_skip_dev(hose, bdf))
204 continue;
205
wdenkf07771c2003-05-28 08:06:31 +0000206 if (!PCI_FUNC(bdf)) {
wdenkc6097192002-11-03 00:24:07 +0000207 pci_read_config_byte(bdf,
208 PCI_HEADER_TYPE,
209 &header_type);
210
211 found_multi = header_type & 0x80;
wdenkf07771c2003-05-28 08:06:31 +0000212 } else {
wdenkc6097192002-11-03 00:24:07 +0000213 if (!found_multi)
214 continue;
215 }
216
217 pci_read_config_word(bdf,
218 PCI_VENDOR_ID,
219 &vendor);
220 pci_read_config_word(bdf,
221 PCI_DEVICE_ID,
222 &device);
223
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000224 for (i = 0; ids[i].vendor != 0; i++) {
wdenkc6097192002-11-03 00:24:07 +0000225 if (vendor == ids[i].vendor &&
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000226 device == ids[i].device) {
wdenkc6097192002-11-03 00:24:07 +0000227 if (index <= 0)
228 return bdf;
229
230 index--;
231 }
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000232 }
wdenkc6097192002-11-03 00:24:07 +0000233 }
234 }
235
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000236 return -1;
wdenkc6097192002-11-03 00:24:07 +0000237}
238
239pci_dev_t pci_find_device(unsigned int vendor, unsigned int device, int index)
240{
Bin Meng8f9052f2014-12-30 22:53:21 +0800241 struct pci_device_id ids[2] = { {}, {0, 0} };
wdenkc6097192002-11-03 00:24:07 +0000242
243 ids[0].vendor = vendor;
244 ids[0].device = device;
245
246 return pci_find_devices(ids, index);
247}
248
249/*
250 *
251 */
252
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000253int __pci_hose_phys_to_bus(struct pci_controller *hose,
Kumar Gala2d43e872009-02-06 09:49:32 -0600254 phys_addr_t phys_addr,
255 unsigned long flags,
256 unsigned long skip_mask,
257 pci_addr_t *ba)
wdenkc6097192002-11-03 00:24:07 +0000258{
259 struct pci_region *res;
Kumar Gala30e76d52008-10-21 08:36:08 -0500260 pci_addr_t bus_addr;
wdenkc6097192002-11-03 00:24:07 +0000261 int i;
262
wdenkf07771c2003-05-28 08:06:31 +0000263 for (i = 0; i < hose->region_count; i++) {
wdenkc6097192002-11-03 00:24:07 +0000264 res = &hose->regions[i];
265
266 if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
267 continue;
268
Kumar Gala2d43e872009-02-06 09:49:32 -0600269 if (res->flags & skip_mask)
270 continue;
271
wdenkc6097192002-11-03 00:24:07 +0000272 bus_addr = phys_addr - res->phys_start + res->bus_start;
273
274 if (bus_addr >= res->bus_start &&
wdenkf07771c2003-05-28 08:06:31 +0000275 bus_addr < res->bus_start + res->size) {
Kumar Gala2d43e872009-02-06 09:49:32 -0600276 *ba = bus_addr;
277 return 0;
wdenkc6097192002-11-03 00:24:07 +0000278 }
279 }
280
Kumar Gala2d43e872009-02-06 09:49:32 -0600281 return 1;
wdenkc6097192002-11-03 00:24:07 +0000282}
283
Kumar Gala2d43e872009-02-06 09:49:32 -0600284pci_addr_t pci_hose_phys_to_bus (struct pci_controller *hose,
285 phys_addr_t phys_addr,
286 unsigned long flags)
287{
288 pci_addr_t bus_addr = 0;
289 int ret;
290
291 if (!hose) {
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000292 puts("pci_hose_phys_to_bus: invalid hose\n");
Kumar Gala2d43e872009-02-06 09:49:32 -0600293 return bus_addr;
294 }
295
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000296 /*
297 * if PCI_REGION_MEM is set we do a two pass search with preference
298 * on matches that don't have PCI_REGION_SYS_MEMORY set
299 */
Kumar Gala2d43e872009-02-06 09:49:32 -0600300 if ((flags & PCI_REGION_MEM) == PCI_REGION_MEM) {
301 ret = __pci_hose_phys_to_bus(hose, phys_addr,
302 flags, PCI_REGION_SYS_MEMORY, &bus_addr);
303 if (!ret)
304 return bus_addr;
305 }
306
307 ret = __pci_hose_phys_to_bus(hose, phys_addr, flags, 0, &bus_addr);
308
309 if (ret)
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000310 puts("pci_hose_phys_to_bus: invalid physical address\n");
Kumar Gala2d43e872009-02-06 09:49:32 -0600311
312 return bus_addr;
313}
314
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000315int __pci_hose_bus_to_phys(struct pci_controller *hose,
Kumar Gala2d43e872009-02-06 09:49:32 -0600316 pci_addr_t bus_addr,
317 unsigned long flags,
318 unsigned long skip_mask,
319 phys_addr_t *pa)
wdenkc6097192002-11-03 00:24:07 +0000320{
321 struct pci_region *res;
322 int i;
323
wdenkf07771c2003-05-28 08:06:31 +0000324 for (i = 0; i < hose->region_count; i++) {
wdenkc6097192002-11-03 00:24:07 +0000325 res = &hose->regions[i];
326
327 if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
328 continue;
329
Kumar Gala2d43e872009-02-06 09:49:32 -0600330 if (res->flags & skip_mask)
331 continue;
332
wdenkc6097192002-11-03 00:24:07 +0000333 if (bus_addr >= res->bus_start &&
Stephen Warrend878c9a2014-08-11 16:09:28 -0600334 (bus_addr - res->bus_start) < res->size) {
Kumar Gala2d43e872009-02-06 09:49:32 -0600335 *pa = (bus_addr - res->bus_start + res->phys_start);
336 return 0;
wdenkc6097192002-11-03 00:24:07 +0000337 }
338 }
339
Kumar Gala2d43e872009-02-06 09:49:32 -0600340 return 1;
341}
wdenkc6097192002-11-03 00:24:07 +0000342
Kumar Gala2d43e872009-02-06 09:49:32 -0600343phys_addr_t pci_hose_bus_to_phys(struct pci_controller* hose,
344 pci_addr_t bus_addr,
345 unsigned long flags)
346{
347 phys_addr_t phys_addr = 0;
348 int ret;
349
350 if (!hose) {
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000351 puts("pci_hose_bus_to_phys: invalid hose\n");
Kumar Gala2d43e872009-02-06 09:49:32 -0600352 return phys_addr;
353 }
354
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000355 /*
356 * if PCI_REGION_MEM is set we do a two pass search with preference
357 * on matches that don't have PCI_REGION_SYS_MEMORY set
358 */
Kumar Gala2d43e872009-02-06 09:49:32 -0600359 if ((flags & PCI_REGION_MEM) == PCI_REGION_MEM) {
360 ret = __pci_hose_bus_to_phys(hose, bus_addr,
361 flags, PCI_REGION_SYS_MEMORY, &phys_addr);
362 if (!ret)
363 return phys_addr;
364 }
365
366 ret = __pci_hose_bus_to_phys(hose, bus_addr, flags, 0, &phys_addr);
367
368 if (ret)
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000369 puts("pci_hose_bus_to_phys: invalid physical address\n");
Kumar Gala2d43e872009-02-06 09:49:32 -0600370
371 return phys_addr;
wdenkc6097192002-11-03 00:24:07 +0000372}
373
Simon Glasse8a552e2014-11-14 18:18:30 -0700374void pci_write_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum,
375 u32 addr_and_ctrl)
376{
377 int bar;
378
379 bar = PCI_BASE_ADDRESS_0 + barnum * 4;
380 pci_hose_write_config_dword(hose, dev, bar, addr_and_ctrl);
381}
382
383u32 pci_read_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum)
384{
385 u32 addr;
386 int bar;
387
388 bar = PCI_BASE_ADDRESS_0 + barnum * 4;
389 pci_hose_read_config_dword(hose, dev, bar, &addr);
390 if (addr & PCI_BASE_ADDRESS_SPACE_IO)
391 return addr & PCI_BASE_ADDRESS_IO_MASK;
392 else
393 return addr & PCI_BASE_ADDRESS_MEM_MASK;
394}
wdenkc6097192002-11-03 00:24:07 +0000395
396int pci_hose_config_device(struct pci_controller *hose,
397 pci_dev_t dev,
398 unsigned long io,
Kumar Gala30e76d52008-10-21 08:36:08 -0500399 pci_addr_t mem,
wdenkc6097192002-11-03 00:24:07 +0000400 unsigned long command)
401{
Kumar Galacf5787f2012-09-19 04:47:36 +0000402 u32 bar_response;
Andrew Sharpaf778c62012-08-01 12:27:16 +0000403 unsigned int old_command;
Kumar Gala30e76d52008-10-21 08:36:08 -0500404 pci_addr_t bar_value;
405 pci_size_t bar_size;
wdenkc6097192002-11-03 00:24:07 +0000406 unsigned char pin;
407 int bar, found_mem64;
408
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000409 debug("PCI Config: I/O=0x%lx, Memory=0x%llx, Command=0x%lx\n", io,
410 (u64)mem, command);
wdenkc6097192002-11-03 00:24:07 +0000411
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000412 pci_hose_write_config_dword(hose, dev, PCI_COMMAND, 0);
wdenkc6097192002-11-03 00:24:07 +0000413
Wolfgang Denk252b4042010-03-09 14:27:25 +0100414 for (bar = PCI_BASE_ADDRESS_0; bar <= PCI_BASE_ADDRESS_5; bar += 4) {
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000415 pci_hose_write_config_dword(hose, dev, bar, 0xffffffff);
416 pci_hose_read_config_dword(hose, dev, bar, &bar_response);
wdenkc6097192002-11-03 00:24:07 +0000417
418 if (!bar_response)
419 continue;
420
421 found_mem64 = 0;
422
423 /* Check the BAR type and set our address mask */
wdenkf07771c2003-05-28 08:06:31 +0000424 if (bar_response & PCI_BASE_ADDRESS_SPACE) {
wdenkc6097192002-11-03 00:24:07 +0000425 bar_size = ~(bar_response & PCI_BASE_ADDRESS_IO_MASK) + 1;
wdenkf07771c2003-05-28 08:06:31 +0000426 /* round up region base address to a multiple of size */
wdenkc6097192002-11-03 00:24:07 +0000427 io = ((io - 1) | (bar_size - 1)) + 1;
wdenkf07771c2003-05-28 08:06:31 +0000428 bar_value = io;
429 /* compute new region base address */
430 io = io + bar_size;
431 } else {
432 if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
Kumar Gala30e76d52008-10-21 08:36:08 -0500433 PCI_BASE_ADDRESS_MEM_TYPE_64) {
434 u32 bar_response_upper;
435 u64 bar64;
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000436 pci_hose_write_config_dword(hose, dev, bar + 4,
437 0xffffffff);
438 pci_hose_read_config_dword(hose, dev, bar + 4,
439 &bar_response_upper);
wdenkc6097192002-11-03 00:24:07 +0000440
Kumar Gala30e76d52008-10-21 08:36:08 -0500441 bar64 = ((u64)bar_response_upper << 32) | bar_response;
442
443 bar_size = ~(bar64 & PCI_BASE_ADDRESS_MEM_MASK) + 1;
444 found_mem64 = 1;
445 } else {
446 bar_size = (u32)(~(bar_response & PCI_BASE_ADDRESS_MEM_MASK) + 1);
447 }
wdenkc6097192002-11-03 00:24:07 +0000448
wdenkf07771c2003-05-28 08:06:31 +0000449 /* round up region base address to multiple of size */
wdenkc6097192002-11-03 00:24:07 +0000450 mem = ((mem - 1) | (bar_size - 1)) + 1;
wdenkf07771c2003-05-28 08:06:31 +0000451 bar_value = mem;
452 /* compute new region base address */
453 mem = mem + bar_size;
wdenkc6097192002-11-03 00:24:07 +0000454 }
455
456 /* Write it out and update our limit */
Kumar Gala30e76d52008-10-21 08:36:08 -0500457 pci_hose_write_config_dword (hose, dev, bar, (u32)bar_value);
wdenkc6097192002-11-03 00:24:07 +0000458
wdenkf07771c2003-05-28 08:06:31 +0000459 if (found_mem64) {
wdenkc6097192002-11-03 00:24:07 +0000460 bar += 4;
Kumar Gala30e76d52008-10-21 08:36:08 -0500461#ifdef CONFIG_SYS_PCI_64BIT
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000462 pci_hose_write_config_dword(hose, dev, bar,
463 (u32)(bar_value >> 32));
Kumar Gala30e76d52008-10-21 08:36:08 -0500464#else
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000465 pci_hose_write_config_dword(hose, dev, bar, 0x00000000);
Kumar Gala30e76d52008-10-21 08:36:08 -0500466#endif
wdenkc6097192002-11-03 00:24:07 +0000467 }
468 }
469
470 /* Configure Cache Line Size Register */
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000471 pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE, 0x08);
wdenkc6097192002-11-03 00:24:07 +0000472
473 /* Configure Latency Timer */
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000474 pci_hose_write_config_byte(hose, dev, PCI_LATENCY_TIMER, 0x80);
wdenkc6097192002-11-03 00:24:07 +0000475
476 /* Disable interrupt line, if device says it wants to use interrupts */
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000477 pci_hose_read_config_byte(hose, dev, PCI_INTERRUPT_PIN, &pin);
wdenkf07771c2003-05-28 08:06:31 +0000478 if (pin != 0) {
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000479 pci_hose_write_config_byte(hose, dev, PCI_INTERRUPT_LINE, 0xff);
wdenkc6097192002-11-03 00:24:07 +0000480 }
481
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000482 pci_hose_read_config_dword(hose, dev, PCI_COMMAND, &old_command);
483 pci_hose_write_config_dword(hose, dev, PCI_COMMAND,
wdenkf07771c2003-05-28 08:06:31 +0000484 (old_command & 0xffff0000) | command);
wdenkc6097192002-11-03 00:24:07 +0000485
486 return 0;
487}
488
489/*
490 *
491 */
492
493struct pci_config_table *pci_find_config(struct pci_controller *hose,
494 unsigned short class,
495 unsigned int vendor,
496 unsigned int device,
497 unsigned int bus,
498 unsigned int dev,
499 unsigned int func)
500{
501 struct pci_config_table *table;
502
wdenkf07771c2003-05-28 08:06:31 +0000503 for (table = hose->config_table; table && table->vendor; table++) {
wdenkc6097192002-11-03 00:24:07 +0000504 if ((table->vendor == PCI_ANY_ID || table->vendor == vendor) &&
505 (table->device == PCI_ANY_ID || table->device == device) &&
506 (table->class == PCI_ANY_ID || table->class == class) &&
507 (table->bus == PCI_ANY_ID || table->bus == bus) &&
508 (table->dev == PCI_ANY_ID || table->dev == dev) &&
wdenkf07771c2003-05-28 08:06:31 +0000509 (table->func == PCI_ANY_ID || table->func == func)) {
wdenkc6097192002-11-03 00:24:07 +0000510 return table;
511 }
512 }
513
514 return NULL;
515}
516
517void pci_cfgfunc_config_device(struct pci_controller *hose,
518 pci_dev_t dev,
519 struct pci_config_table *entry)
520{
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000521 pci_hose_config_device(hose, dev, entry->priv[0], entry->priv[1],
522 entry->priv[2]);
wdenkc6097192002-11-03 00:24:07 +0000523}
524
525void pci_cfgfunc_do_nothing(struct pci_controller *hose,
526 pci_dev_t dev, struct pci_config_table *entry)
527{
528}
529
530/*
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000531 * HJF: Changed this to return int. I think this is required
wdenkc7de8292002-11-19 11:04:11 +0000532 * to get the correct result when scanning bridges
533 */
534extern int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev);
wdenkc6097192002-11-03 00:24:07 +0000535
Peter Tyser983eb9d2010-10-29 17:59:27 -0500536#if defined(CONFIG_CMD_PCI) || defined(CONFIG_PCI_SCAN_SHOW)
537const char * pci_class_str(u8 class)
538{
539 switch (class) {
540 case PCI_CLASS_NOT_DEFINED:
541 return "Build before PCI Rev2.0";
542 break;
543 case PCI_BASE_CLASS_STORAGE:
544 return "Mass storage controller";
545 break;
546 case PCI_BASE_CLASS_NETWORK:
547 return "Network controller";
548 break;
549 case PCI_BASE_CLASS_DISPLAY:
550 return "Display controller";
551 break;
552 case PCI_BASE_CLASS_MULTIMEDIA:
553 return "Multimedia device";
554 break;
555 case PCI_BASE_CLASS_MEMORY:
556 return "Memory controller";
557 break;
558 case PCI_BASE_CLASS_BRIDGE:
559 return "Bridge device";
560 break;
561 case PCI_BASE_CLASS_COMMUNICATION:
562 return "Simple comm. controller";
563 break;
564 case PCI_BASE_CLASS_SYSTEM:
565 return "Base system peripheral";
566 break;
567 case PCI_BASE_CLASS_INPUT:
568 return "Input device";
569 break;
570 case PCI_BASE_CLASS_DOCKING:
571 return "Docking station";
572 break;
573 case PCI_BASE_CLASS_PROCESSOR:
574 return "Processor";
575 break;
576 case PCI_BASE_CLASS_SERIAL:
577 return "Serial bus controller";
578 break;
579 case PCI_BASE_CLASS_INTELLIGENT:
580 return "Intelligent controller";
581 break;
582 case PCI_BASE_CLASS_SATELLITE:
583 return "Satellite controller";
584 break;
585 case PCI_BASE_CLASS_CRYPT:
586 return "Cryptographic device";
587 break;
588 case PCI_BASE_CLASS_SIGNAL_PROCESSING:
589 return "DSP";
590 break;
591 case PCI_CLASS_OTHERS:
592 return "Does not fit any class";
593 break;
594 default:
595 return "???";
596 break;
597 };
598}
599#endif /* CONFIG_CMD_PCI || CONFIG_PCI_SCAN_SHOW */
600
Jeroen Hofstee7b19fd62014-10-08 22:57:27 +0200601__weak int pci_skip_dev(struct pci_controller *hose, pci_dev_t dev)
Stefan Roesedc1da422008-07-08 12:01:47 +0200602{
603 /*
604 * Check if pci device should be skipped in configuration
605 */
606 if (dev == PCI_BDF(hose->first_busno, 0, 0)) {
607#if defined(CONFIG_PCI_CONFIG_HOST_BRIDGE) /* don't skip host bridge */
608 /*
609 * Only skip configuration if "pciconfighost" is not set
610 */
611 if (getenv("pciconfighost") == NULL)
612 return 1;
613#else
614 return 1;
615#endif
616 }
617
618 return 0;
619}
Stefan Roesedc1da422008-07-08 12:01:47 +0200620
621#ifdef CONFIG_PCI_SCAN_SHOW
Jeroen Hofstee7b19fd62014-10-08 22:57:27 +0200622__weak int pci_print_dev(struct pci_controller *hose, pci_dev_t dev)
Stefan Roesedc1da422008-07-08 12:01:47 +0200623{
624 if (dev == PCI_BDF(hose->first_busno, 0, 0))
625 return 0;
626
627 return 1;
628}
Stefan Roesedc1da422008-07-08 12:01:47 +0200629#endif /* CONFIG_PCI_SCAN_SHOW */
630
wdenkc6097192002-11-03 00:24:07 +0000631int pci_hose_scan_bus(struct pci_controller *hose, int bus)
632{
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000633 unsigned int sub_bus, found_multi = 0;
wdenkc6097192002-11-03 00:24:07 +0000634 unsigned short vendor, device, class;
635 unsigned char header_type;
Andrew Sharp03992ac2012-08-29 14:16:30 +0000636#ifndef CONFIG_PCI_PNP
wdenkc6097192002-11-03 00:24:07 +0000637 struct pci_config_table *cfg;
Andrew Sharp03992ac2012-08-29 14:16:30 +0000638#endif
wdenkc6097192002-11-03 00:24:07 +0000639 pci_dev_t dev;
Peter Tyser009884a2010-10-29 17:59:29 -0500640#ifdef CONFIG_PCI_SCAN_SHOW
641 static int indent = 0;
642#endif
wdenkc6097192002-11-03 00:24:07 +0000643
644 sub_bus = bus;
645
646 for (dev = PCI_BDF(bus,0,0);
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000647 dev < PCI_BDF(bus, PCI_MAX_PCI_DEVICES - 1,
648 PCI_MAX_PCI_FUNCTIONS - 1);
649 dev += PCI_BDF(0, 0, 1)) {
Stefan Roesedc1da422008-07-08 12:01:47 +0200650
651 if (pci_skip_dev(hose, dev))
652 continue;
wdenkc6097192002-11-03 00:24:07 +0000653
654 if (PCI_FUNC(dev) && !found_multi)
655 continue;
656
657 pci_hose_read_config_byte(hose, dev, PCI_HEADER_TYPE, &header_type);
658
659 pci_hose_read_config_word(hose, dev, PCI_VENDOR_ID, &vendor);
660
Peter Tyser983eb9d2010-10-29 17:59:27 -0500661 if (vendor == 0xffff || vendor == 0x0000)
662 continue;
wdenkc6097192002-11-03 00:24:07 +0000663
Peter Tyser983eb9d2010-10-29 17:59:27 -0500664 if (!PCI_FUNC(dev))
665 found_multi = header_type & 0x80;
wdenkc6097192002-11-03 00:24:07 +0000666
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000667 debug("PCI Scan: Found Bus %d, Device %d, Function %d\n",
668 PCI_BUS(dev), PCI_DEV(dev), PCI_FUNC(dev));
wdenkc6097192002-11-03 00:24:07 +0000669
Peter Tyser983eb9d2010-10-29 17:59:27 -0500670 pci_hose_read_config_word(hose, dev, PCI_DEVICE_ID, &device);
671 pci_hose_read_config_word(hose, dev, PCI_CLASS_DEVICE, &class);
wdenkc6097192002-11-03 00:24:07 +0000672
Tim Harvey09918662014-08-07 22:49:56 -0700673#ifdef CONFIG_PCI_FIXUP_DEV
674 board_pci_fixup_dev(hose, dev, vendor, device, class);
675#endif
676
Peter Tysera38d2162010-10-29 17:59:28 -0500677#ifdef CONFIG_PCI_SCAN_SHOW
Peter Tyser009884a2010-10-29 17:59:29 -0500678 indent++;
679
680 /* Print leading space, including bus indentation */
681 printf("%*c", indent + 1, ' ');
682
Peter Tysera38d2162010-10-29 17:59:28 -0500683 if (pci_print_dev(hose, dev)) {
Peter Tyser009884a2010-10-29 17:59:29 -0500684 printf("%02x:%02x.%-*x - %04x:%04x - %s\n",
685 PCI_BUS(dev), PCI_DEV(dev), 6 - indent, PCI_FUNC(dev),
Peter Tysera38d2162010-10-29 17:59:28 -0500686 vendor, device, pci_class_str(class >> 8));
687 }
688#endif
689
Andrew Sharp03992ac2012-08-29 14:16:30 +0000690#ifdef CONFIG_PCI_PNP
Masahiro Yamadab4141192014-11-07 03:03:31 +0900691 sub_bus = max((unsigned int)pciauto_config_device(hose, dev),
692 sub_bus);
Andrew Sharp03992ac2012-08-29 14:16:30 +0000693#else
Peter Tyser983eb9d2010-10-29 17:59:27 -0500694 cfg = pci_find_config(hose, class, vendor, device,
695 PCI_BUS(dev), PCI_DEV(dev), PCI_FUNC(dev));
696 if (cfg) {
697 cfg->config_device(hose, dev, cfg);
Masahiro Yamadab4141192014-11-07 03:03:31 +0900698 sub_bus = max(sub_bus,
699 (unsigned int)hose->current_busno);
wdenkc6097192002-11-03 00:24:07 +0000700 }
Andrew Sharp03992ac2012-08-29 14:16:30 +0000701#endif
Peter Tysera38d2162010-10-29 17:59:28 -0500702
Peter Tyser009884a2010-10-29 17:59:29 -0500703#ifdef CONFIG_PCI_SCAN_SHOW
704 indent--;
705#endif
706
Peter Tyser983eb9d2010-10-29 17:59:27 -0500707 if (hose->fixup_irq)
708 hose->fixup_irq(hose, dev);
wdenkc6097192002-11-03 00:24:07 +0000709 }
710
711 return sub_bus;
712}
713
714int pci_hose_scan(struct pci_controller *hose)
715{
Anatolij Gustschin0da1fb02011-10-11 22:44:30 +0000716#if defined(CONFIG_PCI_BOOTDELAY)
Anatolij Gustschin0da1fb02011-10-11 22:44:30 +0000717 char *s;
718 int i;
719
Bin Meng8f9052f2014-12-30 22:53:21 +0800720 if (!gd->pcidelay_done) {
Anatolij Gustschin0da1fb02011-10-11 22:44:30 +0000721 /* wait "pcidelay" ms (if defined)... */
722 s = getenv("pcidelay");
723 if (s) {
724 int val = simple_strtoul(s, NULL, 10);
725 for (i = 0; i < val; i++)
726 udelay(1000);
727 }
Bin Meng8f9052f2014-12-30 22:53:21 +0800728 gd->pcidelay_done = 1;
Anatolij Gustschin0da1fb02011-10-11 22:44:30 +0000729 }
730#endif /* CONFIG_PCI_BOOTDELAY */
731
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000732 /*
733 * Start scan at current_busno.
Ed Swarthout40e81ad2007-07-11 14:51:35 -0500734 * PCIe will start scan at first_busno+1.
735 */
Andrew Sharpcb2bf932012-08-29 14:16:29 +0000736 /* For legacy support, ensure current >= first */
Ed Swarthout40e81ad2007-07-11 14:51:35 -0500737 if (hose->first_busno > hose->current_busno)
738 hose->current_busno = hose->first_busno;
wdenkc6097192002-11-03 00:24:07 +0000739#ifdef CONFIG_PCI_PNP
740 pciauto_config_init(hose);
741#endif
Ed Swarthout40e81ad2007-07-11 14:51:35 -0500742 return pci_hose_scan_bus(hose, hose->current_busno);
wdenkc6097192002-11-03 00:24:07 +0000743}
744
stroesead10dd92003-02-14 11:21:23 +0000745void pci_init(void)
746{
John Schmoller96d61602010-10-22 00:20:23 -0500747 hose_head = NULL;
748
stroesead10dd92003-02-14 11:21:23 +0000749 /* now call board specific pci_init()... */
750 pci_init_board();
751}
Zhao Qiang287df012013-10-12 13:46:33 +0800752
753/* Returns the address of the requested capability structure within the
754 * device's PCI configuration space or 0 in case the device does not
755 * support it.
756 * */
757int pci_hose_find_capability(struct pci_controller *hose, pci_dev_t dev,
758 int cap)
759{
760 int pos;
761 u8 hdr_type;
762
763 pci_hose_read_config_byte(hose, dev, PCI_HEADER_TYPE, &hdr_type);
764
765 pos = pci_hose_find_cap_start(hose, dev, hdr_type & 0x7F);
766
767 if (pos)
768 pos = pci_find_cap(hose, dev, pos, cap);
769
770 return pos;
771}
772
773/* Find the header pointer to the Capabilities*/
774int pci_hose_find_cap_start(struct pci_controller *hose, pci_dev_t dev,
775 u8 hdr_type)
776{
777 u16 status;
778
779 pci_hose_read_config_word(hose, dev, PCI_STATUS, &status);
780
781 if (!(status & PCI_STATUS_CAP_LIST))
782 return 0;
783
784 switch (hdr_type) {
785 case PCI_HEADER_TYPE_NORMAL:
786 case PCI_HEADER_TYPE_BRIDGE:
787 return PCI_CAPABILITY_LIST;
788 case PCI_HEADER_TYPE_CARDBUS:
789 return PCI_CB_CAPABILITY_LIST;
790 default:
791 return 0;
792 }
793}
794
795int pci_find_cap(struct pci_controller *hose, pci_dev_t dev, int pos, int cap)
796{
797 int ttl = PCI_FIND_CAP_TTL;
798 u8 id;
799 u8 next_pos;
800
801 while (ttl--) {
802 pci_hose_read_config_byte(hose, dev, pos, &next_pos);
803 if (next_pos < CAP_START_POS)
804 break;
805 next_pos &= ~3;
806 pos = (int) next_pos;
807 pci_hose_read_config_byte(hose, dev,
808 pos + PCI_CAP_LIST_ID, &id);
809 if (id == 0xff)
810 break;
811 if (id == cap)
812 return pos;
813 pos += PCI_CAP_LIST_NEXT;
814 }
815 return 0;
816}