3 * Copyright (C) 2007 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
4 * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
5 * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
36 #include "../drivers/bus/pci/devlist.h"
40 #define inportb(P) inb(P)
41 #define inportw(P) inw(P)
42 #define outportb(P,V) outb(P,V)
43 #define outportw(P,V) outw_p(P,V)
44 #define inportl(P) inl(P)
45 #define outportl(P,V) outl(P,V)
48 /* else [in|out]portl() defined below */
49 #define PCI_READ_CONFIG_BYTE 0xB108
50 #define PCI_READ_CONFIG_WORD 0xB109
51 #define PCI_READ_CONFIG_DWORD 0xB10A
52 #define PCI_WRITE_CONFIG_BYTE 0xB10B
53 #define PCI_WRITE_CONFIG_WORD 0xB10C
54 #define PCI_WRITE_CONFIG_DWORD 0xB10D
56 #define PCI_ADR_REG 0xCF8
57 #define PCI_DATA_REG 0xCFC
59 /*****************************************************************************
60 If you have PnP code available, device PNP0A03 also
61 indicates the presence of a PCI controller in the system.
62 *****************************************************************************/
63 static int pci_detect ()
65 kprintf ("PCI controller: ");
67 /* poke 32-bit I/O register at 0xCF8 to see if
68 there's a PCI controller there */
69 outportl (PCI_ADR_REG
, 0x80000000L
); /* bus 0, dev 0, fn 0, reg 0 */
71 unsigned long ret
= inportl (PCI_ADR_REG
);
73 if(ret
!= 0x80000000L
) {
74 kprintf ("not found / %x\n", ret
);
82 /*****************************************************************************
83 *****************************************************************************/
84 int pci_read_config_byte (pcidev_t
*pci
, unsigned reg
, unsigned char *val
)
87 0x80000000L
| /* "enable configuration space mapping" */
88 ((unsigned long)pci
->bus
<< 16) | /* b23-b16=bus */
89 ((unsigned)pci
->dev
<< 11) | /* b15-b11=dev */
90 ((unsigned)pci
->fn
<< 8) | /* b10-b8 =fn */
91 (reg
& ~3)); /* b7 -b2 =reg */
93 *val
= inportb(PCI_DATA_REG
+ (reg
& 3)); // xxx - is this legit?
97 /*****************************************************************************
98 *****************************************************************************/
99 int pci_read_config_word (pcidev_t
*pci
, unsigned reg
, unsigned short *val
)
101 outportl (PCI_ADR_REG
, 0x80000000L
|
102 ((unsigned long) pci
->bus
<< 16) |
103 ((unsigned) pci
->dev
<< 11) |
104 ((unsigned) pci
->fn
<< 8) | (reg
& ~3));
106 *val
= inportw (PCI_DATA_REG
+ (reg
& 2));
110 /*****************************************************************************
111 *****************************************************************************/
112 int pci_read_config_dword (pcidev_t
*pci
, unsigned reg
, unsigned long *val
)
114 outportl (PCI_ADR_REG
, 0x80000000L
|
115 ((unsigned long) pci
->bus
<< 16) |
116 ((unsigned) pci
->dev
<< 11) |
117 ((unsigned) pci
->fn
<< 8) | (reg
& ~3));
119 *val
= inportl (PCI_DATA_REG
+ 0);
123 /*****************************************************************************
124 *****************************************************************************/
125 int pci_write_config_byte (pcidev_t
*pci
, unsigned reg
,
128 outportl (PCI_ADR_REG
, 0x80000000L
|
129 ((unsigned long)pci
->bus
<< 16) |
130 ((unsigned)pci
->dev
<< 11) |
131 ((unsigned)pci
->fn
<< 8) | (reg
& ~3));
133 outportb (PCI_DATA_REG
+ (reg
& 3), val
);
137 /*****************************************************************************
138 *****************************************************************************/
139 int pci_write_config_word(pcidev_t
*pci
, unsigned reg
,
142 outportl (PCI_ADR_REG
, 0x80000000L
|
143 ((unsigned long)pci
->bus
<< 16) |
144 ((unsigned)pci
->dev
<< 11) |
145 ((unsigned)pci
->fn
<< 8) | (reg
& ~3));
147 outportw (PCI_DATA_REG
+ (reg
& 2), val
);
151 /*****************************************************************************
152 *****************************************************************************/
153 int pci_write_config_dword(pcidev_t
*pci
, unsigned reg
,
156 outportl(PCI_ADR_REG
, 0x80000000L
|
157 ((unsigned long)pci
->bus
<< 16) |
158 ((unsigned)pci
->dev
<< 11) |
159 ((unsigned)pci
->fn
<< 8) | (reg
& ~3));
161 outportl (PCI_DATA_REG
+ 0, val
);
165 /*****************************************************************************
166 *****************************************************************************/
167 static int pci_iterate (pcidev_t
*pci
)
169 unsigned char hdr_type
= 0x80;
171 /* if first function of this device, check if multi-function device
172 (otherwise fn==0 is the _only_ function of this device) */
174 if(pci_read_config_byte(pci
, 0x0E, &hdr_type
))
175 return -1; /* error */
178 /* increment iterators
179 fn (function) is the least significant, bus is the most significant */
182 if(pci
->fn
>= 8 || (hdr_type
& 0x80) == 0) {
188 // if(pci->bus > g_last_pci_bus)
196 /*****************************************************************************
197 *****************************************************************************/
199 * Set device to be a busmaster in case BIOS neglected to do so.
200 * Also adjust PCI latency timer to a reasonable value, 32.
203 void pci_device_adjust (pcidev_t
*pci
)
205 unsigned short new_command
, pci_command
;
206 unsigned char pci_latency
;
208 pci_read_config_word (pci
, PCI_command
, &pci_command
);
210 new_command
= pci_command
| PCI_command_master
| PCI_command_io
;
212 if (pci_command
!= new_command
) {
213 kprintf("The PCI BIOS has not enabled this device!\nUpdating PCI command %X->%X\n",
214 pci_command
, new_command
);
216 pci_write_config_word (pci
, PCI_command
, new_command
);
219 pci_read_config_byte (pci
, PCI_latency
, &pci_latency
);
221 if (pci_latency
< 32) {
222 kprintf("PCI latency timer (CFLT) is unreasonably low at %d. Setting to 32 clocks.\n", pci_latency
);
223 pci_write_config_byte(pci
, PCI_latency
, 32);
226 /*****************************************************************************
227 *****************************************************************************/
228 int pci_device_enable (pcidev_t
*pci
)
231 pci_read_config_byte (pci
, PCI_pm_status
, &r
);
233 if (r
& PCI_pm_state_d0
)
234 pci_write_config_byte (pci
, PCI_pm_status
, PCI_pm_state_d0
);
238 /*****************************************************************************
239 *****************************************************************************/
240 void pcidev_display ()
243 for (pcidev
= pcidev_list
.next
; pcidev
!= &pcidev_list
; pcidev
= pcidev
->next
) {
248 for (i
= 0; i
< PCI_DEVTABLE_LEN
; i
++)
249 if (PciDevTable
[i
].VenId
== (unsigned short) (pcidev
->id
& 0xFFFF)) {
250 if (PciDevTable
[i
].DevId
== (unsigned short) (pcidev
->id
>> 16))
255 printf ("%02u:%02u:%u %04lX:%04lX %s: %s\n",
256 pcidev
->bus
, pcidev
->dev
, pcidev
->fn
,
257 pcidev
->id
& 0xFFFF, pcidev
->id
>> 16,
258 //pcidev->u.h0.base_registers[0], pcidev->u.h0.base_register_sizes[0], pcidev->u.h0.base_registers[3],
259 i
== PCI_DEVTABLE_LEN
? "Unknown" : PciDevTable
[i
].Chip
,
260 i
== PCI_DEVTABLE_LEN
? "Unknown" : PciDevTable
[i
].ChipDesc
);
264 /*****************************************************************************
265 *****************************************************************************/
266 pcidev_t
*pcidev_register (unsigned char bus
, unsigned char dev
, unsigned char fn
, unsigned long id
)
270 /* alloc and init context */
271 pcidev
= (pcidev_t
*) kmalloc (sizeof (pcidev_t
));
279 pcidev
->next
= &pcidev_list
;
280 pcidev
->prev
= pcidev_list
.prev
;
281 pcidev
->prev
->next
= pcidev
;
282 pcidev
->next
->prev
= pcidev
;
287 pcidev_t
*pcidev_find (unsigned short vendor
, unsigned short device
)
290 for (pcidev
= pcidev_list
.next
; pcidev
!= &pcidev_list
; pcidev
= pcidev
->next
) {
294 if (vendor
== (unsigned short) (pcidev
->id
& 0xFFFF))
295 if (device
== (unsigned short) (pcidev
->id
>> 16))
302 bool bus_pci_acthandler (unsigned act
, char *block
, unsigned block_len
)
307 pcidev_list
.next
= &pcidev_list
;
308 pcidev_list
.prev
= &pcidev_list
;
313 /* check for PCI BIOS */
317 /* display numeric ID of all PCI devices detected */
318 memset (&pci
, 0, sizeof(pci
));
322 /* 00=PCI_VENDOR_ID */
323 err
= pci_read_config_dword (&pci
, 0x00, &pci
.id
);
326 ERR
: kprintf ("PCI: error 0x%02X reading PCI config\n", err
);
330 pcidev_t
*pcidev
= 0;
331 /* anything there? */
332 if(pci
.id
!= 0xFFFFFFFFL
) {
333 pcidev
= pcidev_register (pci
.bus
, pci
.dev
, pci
.fn
, pci
.id
);
336 pci_read_config_byte (pcidev
, PCI_revision
, &pcidev
->revision
);
337 pci_read_config_byte (pcidev
, PCI_class_api
, &pcidev
->class_api
);
338 pci_read_config_byte (pcidev
, PCI_class_sub
, &pcidev
->class_sub
);
339 pci_read_config_byte (pcidev
, PCI_class_base
, &pcidev
->class_base
);
341 pci_read_config_byte (pcidev
, PCI_header_type
, &pcidev
->header_type
);
342 pcidev
->header_type
&= PCI_header_type_mask
;
344 pci_read_config_byte (pcidev
, PCI_latency
, &pcidev
->latency
);
345 pci_read_config_byte (pcidev
, PCI_bist
, &pcidev
->bist
);
346 pci_read_config_byte (pcidev
, PCI_line_size
, &pcidev
->line_size
);
349 unsigned temp
, temp2
;
351 if(pcidev
->header_type
== 0) {
352 for (i
= 0; i
< 6; i
++) {
353 pci_read_config_dword (pcidev
, PCI_base_registers
+ i
*4, (unsigned long *) &temp
);
355 pci_write_config_dword (pcidev
, PCI_base_registers
+ i
*4, 0xffffffff);
356 pci_read_config_dword (pcidev
, PCI_base_registers
+ i
*4, (unsigned long *) &temp2
);
359 pci_write_config_dword (pcidev
, PCI_base_registers
+ i
*4, temp
);
363 pcidev
->u
.h0
.base_registers
[i
] = temp
& 0xfff0;
364 pcidev
->u
.h0
.base_register_sizes
[i
] = temp2
& 0xffff;
366 pcidev
->u
.h0
.base_registers
[i
] = temp
& 0xfffffff0;
367 pcidev
->u
.h0
.base_register_sizes
[i
] = temp2
;
370 pcidev
->u
.h0
.base_registers
[i
] = 0;
371 pcidev
->u
.h0
.base_register_sizes
[i
] = 0;
374 pci_read_config_byte (pcidev
, PCI_interrupt_line
, &pcidev
->u
.h0
.interrupt_line
);
375 pci_read_config_byte (pcidev
, PCI_interrupt_pin
, &pcidev
->u
.h0
.interrupt_pin
);
376 pcidev
->u
.h1
.interrupt_pin
&= PCI_pin_mask
;
377 // dprintf("basereg %d:%d:%d 0x%x\n", bus, dev, func, pcii->u.h0.base_registers[i]);
378 // dprintf("size %d:%d:%d 0x%x\n", bus, dev, func, pcii->u.h0.base_register_sizes[i]);
385 } while (!pci_iterate (&pci
));
388 /* find a USB controller */
389 memset (&pci
, 0, sizeof (pci
));
393 unsigned char major
, minor
;
398 err
= pci_read_config_dword (&pci
, 0x00, &id
);
404 err
= pci_read_config_byte (&pci
, 0x0B, &major
);
410 err
= pci_read_config_byte (&pci
, 0x0A, &minor
);
415 /* anything there? */
416 if (major
!= 0xFF || minor
!= 0xFF) {
417 //printf("detected device of class %u.%u\n", major, minor);
418 if(major
== 12 && minor
== 3) {
419 //printf("USB controller detected: 0x%x, 0x%x\n", id & 0xFFFF, id >> 16);
420 pcidev_t
*pcidev
= pcidev_find (id
& 0xFFFF, id
>> 16);
425 usb_controller_register (pcidev
);
431 } while (!pci_iterate (&pci
));