blob: 9e412e5e4c460a419aa50ef6de7872bac77f03ae [file] [log] [blame]
wdenk7a8e9bed2003-05-31 18:35:21 +00001/*
2 * (C) Copyright 2002
3 * Daniel Engström, Omicron Ceti AB, daniel@omicron.se
wdenk8bde7f72003-06-27 21:31:46 +00004 *
wdenk7a8e9bed2003-05-31 18:35:21 +00005 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24/*
25 * x86 realmode assembly implementation of a PCI BIOS
wdenk8bde7f72003-06-27 21:31:46 +000026 * for platforms that use one PCI hose and configuration
wdenk7a8e9bed2003-05-31 18:35:21 +000027 * access type 1. (The common case for low-end PC's)
28 */
wdenk8bde7f72003-06-27 21:31:46 +000029
wdenk7a8e9bed2003-05-31 18:35:21 +000030#include "bios.h"
31
32#define PCI_BIOS_DEBUG
33
34.section .bios, "ax"
35.code16
36.globl realmode_pci_bios_call_entry
Graeme Russ0fc1b492009-11-24 20:04:19 +110037.hidden realmode_pci_bios_call_entry
38.type realmode_pci_bios_call_entry, @function
wdenk7a8e9bed2003-05-31 18:35:21 +000039realmode_pci_bios_call_entry:
40 MAKE_BIOS_STACK
41 call realmode_pci_bios
42 RESTORE_CALLERS_STACK
43 ret
wdenk8bde7f72003-06-27 21:31:46 +000044
45
wdenk7a8e9bed2003-05-31 18:35:21 +000046.globl realmode_pci_bios
47realmode_pci_bios:
48gs movw OFFS_AX(%bp), %ax
49 cmpb $1, %al
50 je pci_bios_present
51 cmpb $2, %al
52 je pci_bios_find_device
53 cmpb $3, %al
54 je pci_bios_find_class
55 cmpb $6, %al
56 je pci_bios_generate_special_cycle
57 cmpb $8, %al
58 je pci_bios_read_cfg_byte
59 cmpb $9, %al
60 je pci_bios_read_cfg_word
61 cmpb $10, %al
62 je pci_bios_read_cfg_dword
63 cmpb $11, %al
64 je pci_bios_write_cfg_byte
65 cmpb $12, %al
66 je pci_bios_write_cfg_word
67 cmpb $13, %al
68 je pci_bios_write_cfg_dword
69 cmpb $14, %al
70 je pci_bios_get_irq_routing
71 cmpb $15, %al
72 je pci_bios_set_irq
73 jmp unknown_function
wdenk8bde7f72003-06-27 21:31:46 +000074
wdenk7a8e9bed2003-05-31 18:35:21 +000075/*****************************************************************************/
76
77pci_bios_present:
78#ifdef PCI_BIOS_DEBUG
79cs incl num_pci_bios_present
80#endif
81 movl $0x20494350, %eax
wdenk8bde7f72003-06-27 21:31:46 +000082gs movl %eax, OFFS_EDX(%bp)
wdenk7a8e9bed2003-05-31 18:35:21 +000083 movb $0x01, %al
wdenk8bde7f72003-06-27 21:31:46 +000084gs movb %al, OFFS_AL(%bp) /* We support cfg type 1 */
85 movw $0x0210, %ax /* version 2.10 */
86gs movw %ax, OFFS_BX(%bp)
wdenk7a8e9bed2003-05-31 18:35:21 +000087cs movb pci_last_bus, %al /* last bus number */
wdenk8bde7f72003-06-27 21:31:46 +000088gs movb %al, OFFS_CL(%bp)
Wolfgang Denk53677ef2008-05-20 16:00:29 +020089 jmp clear_carry
wdenk7a8e9bed2003-05-31 18:35:21 +000090
91/*****************************************************************************/
92
93/* device 0-31, function 0-7 */
wdenk8bde7f72003-06-27 21:31:46 +000094pci_bios_find_device:
wdenk7a8e9bed2003-05-31 18:35:21 +000095#ifdef PCI_BIOS_DEBUG
Wolfgang Denk53677ef2008-05-20 16:00:29 +020096cs incl num_pci_bios_find_device
wdenk7a8e9bed2003-05-31 18:35:21 +000097#endif
wdenk8bde7f72003-06-27 21:31:46 +000098gs movw OFFS_CX(%bp), %di
wdenk7a8e9bed2003-05-31 18:35:21 +000099 shll $16, %edi
wdenk8bde7f72003-06-27 21:31:46 +0000100gs movw OFFS_DX(%bp), %di /* edi now holds device in upper 16
101 * bits and vendor in lower 16 bits */
102gs movw OFFS_SI(%bp), %si
wdenk7a8e9bed2003-05-31 18:35:21 +0000103 xorw %bx, %bx /* start at bus 0 dev 0 function 0 */
wdenk8bde7f72003-06-27 21:31:46 +0000104pfd_loop:
105 xorw %ax, %ax /* dword 0 is vendor/device */
106 call __pci_bios_select_register
wdenk7a8e9bed2003-05-31 18:35:21 +0000107 movw $0xcfc, %dx
108 inl %dx, %eax
109 cmpl %edi, %eax /* our device ? */
110 je pfd_found_one
111pfd_next_dev:
112 /* check for multi function devices */
113 movw %bx, %ax
114 andw $3, %ax
115 jnz pfd_function_not_zero
wdenk8bde7f72003-06-27 21:31:46 +0000116 movw $0x000c, %ax
117 call __pci_bios_select_register
wdenk7a8e9bed2003-05-31 18:35:21 +0000118 movw $0xcfe, %dx
119 inb %dx, %al
120 andb $0x80, %al
121 jz pfd_not_multi_function
122pfd_function_not_zero:
123 incw %bx /* next function, overflows in to
124 * device number, then bus number */
125 jmp pfd_check_bus
wdenk8bde7f72003-06-27 21:31:46 +0000126
wdenk7a8e9bed2003-05-31 18:35:21 +0000127pfd_not_multi_function:
128 andw $0xfff8, %bx /* remove function bits */
129 addw $0x0008, %bx /* next device, overflows in to bus number */
wdenk8bde7f72003-06-27 21:31:46 +0000130pfd_check_bus:
wdenk7a8e9bed2003-05-31 18:35:21 +0000131cs movb pci_last_bus, %ah
132 cmpb %ah, %bh
133 ja pfd_not_found
134 jmp pfd_loop
135pfd_found_one:
136 decw %si
137 js pfd_done
138 jmp pfd_next_dev
139
140pfd_done:
wdenk8bde7f72003-06-27 21:31:46 +0000141gs movw %bx, OFFS_BX(%bp)
wdenk7a8e9bed2003-05-31 18:35:21 +0000142 jmp clear_carry
143
144pfd_not_found:
145 movb $0x86, %ah /* device not found */
146 jmp set_carry
147
148/*****************************************************************************/
149
150pci_bios_find_class:
151#ifdef PCI_BIOS_DEBUG
152cs incl num_pci_bios_find_class
153#endif
wdenk8bde7f72003-06-27 21:31:46 +0000154gs movl OFFS_ECX(%bp), %edi
155 andl $0x00ffffff, %edi /* edi now holds class-code in lower 24 bits */
156gs movw OFFS_SI(%bp), %si
wdenk7a8e9bed2003-05-31 18:35:21 +0000157 xorw %bx, %bx /* start at bus 0 dev 0 function 0 */
wdenk8bde7f72003-06-27 21:31:46 +0000158pfc_loop:
159 movw $8, %ax /* dword 8 is class-code high 24bits */
160 call __pci_bios_select_register
wdenk7a8e9bed2003-05-31 18:35:21 +0000161 movw $0xcfc, %dx
162 inl %dx, %eax
163 shrl $8, %eax
164 andl $0x00ffffff, %eax
165 cmpl %edi, %eax /* our device ? */
166 je pfc_found_one
167pfc_next_dev:
168 /* check for multi function devices */
169 andw $3, %bx
170 jnz pfc_function_not_zero
wdenk8bde7f72003-06-27 21:31:46 +0000171 movw $0x000c, %ax
172 call __pci_bios_select_register
wdenk7a8e9bed2003-05-31 18:35:21 +0000173 movw $0xcfe, %dx
174 inb %dx, %al
175 andb $0x80, %al
176 jz pfc_not_multi_function
177pfc_function_not_zero:
178 incw %bx /* next function, overflows in to
179 * device number, then bus number */
180 jmp pfc_check_bus
wdenk8bde7f72003-06-27 21:31:46 +0000181
wdenk7a8e9bed2003-05-31 18:35:21 +0000182pfc_not_multi_function:
183 andw $0xfff8, %bx /* remove function bits */
184 addw $0x0008, %bx /* next device, overflows in to bus number */
wdenk8bde7f72003-06-27 21:31:46 +0000185pfc_check_bus:
wdenk7a8e9bed2003-05-31 18:35:21 +0000186cs movb pci_last_bus, %ah
187 cmpb %ah, %bh
188 ja pfc_not_found
189 jmp pfc_loop
190pfc_found_one:
191 decw %si
192 js pfc_done
193 jmp pfc_next_dev
194
195pfc_done:
wdenk8bde7f72003-06-27 21:31:46 +0000196gs movw %bx, OFFS_BX(%bp)
wdenk7a8e9bed2003-05-31 18:35:21 +0000197 jmp clear_carry
198
199pfc_not_found:
200 movb $0x86, %ah /* device not found */
201 jmp set_carry
202
203/*****************************************************************************/
204
205pci_bios_generate_special_cycle:
206#ifdef PCI_BIOS_DEBUG
207cs incl num_pci_bios_generate_special_cycle
208#endif
209 movb $0x81, %ah /* function not supported */
210 jmp set_carry
wdenk8bde7f72003-06-27 21:31:46 +0000211
wdenk7a8e9bed2003-05-31 18:35:21 +0000212/*****************************************************************************/
213
wdenk8bde7f72003-06-27 21:31:46 +0000214pci_bios_read_cfg_byte:
wdenk7a8e9bed2003-05-31 18:35:21 +0000215#ifdef PCI_BIOS_DEBUG
216cs incl num_pci_bios_read_cfg_byte
217#endif
wdenk8bde7f72003-06-27 21:31:46 +0000218 call pci_bios_select_register
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200219gs movw OFFS_DI(%bp), %dx
wdenk7a8e9bed2003-05-31 18:35:21 +0000220 andw $3, %dx
221 addw $0xcfc, %dx
222 inb %dx, %al
wdenk8bde7f72003-06-27 21:31:46 +0000223gs movb %al, OFFS_CL(%bp)
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200224 jmp clear_carry
wdenk7a8e9bed2003-05-31 18:35:21 +0000225
226/*****************************************************************************/
227
wdenk8bde7f72003-06-27 21:31:46 +0000228pci_bios_read_cfg_word:
wdenk7a8e9bed2003-05-31 18:35:21 +0000229#ifdef PCI_BIOS_DEBUG
230cs incl num_pci_bios_read_cfg_word
231#endif
232 call pci_bios_select_register
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200233gs movw OFFS_DI(%bp), %dx
wdenk7a8e9bed2003-05-31 18:35:21 +0000234 andw $2, %dx
235 addw $0xcfc, %dx
236 inw %dx, %ax
wdenk8bde7f72003-06-27 21:31:46 +0000237gs movw %ax, OFFS_CX(%bp)
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200238 jmp clear_carry
wdenk7a8e9bed2003-05-31 18:35:21 +0000239
240
241/*****************************************************************************/
242
wdenk8bde7f72003-06-27 21:31:46 +0000243pci_bios_read_cfg_dword:
wdenk7a8e9bed2003-05-31 18:35:21 +0000244#ifdef PCI_BIOS_DEBUG
245cs incl num_pci_bios_read_cfg_dword
246#endif
247 call pci_bios_select_register
248 movw $0xcfc, %dx
249 inl %dx, %eax
wdenk8bde7f72003-06-27 21:31:46 +0000250gs movl %eax, OFFS_ECX(%bp)
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200251 jmp clear_carry
wdenk7a8e9bed2003-05-31 18:35:21 +0000252
253/*****************************************************************************/
254
255pci_bios_write_cfg_byte:
256#ifdef PCI_BIOS_DEBUG
257cs incl num_pci_bios_write_cfg_byte
258#endif
wdenk8bde7f72003-06-27 21:31:46 +0000259 call pci_bios_select_register
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200260gs movw OFFS_DI(%bp), %dx
wdenk7a8e9bed2003-05-31 18:35:21 +0000261gs movb OFFS_CL(%bp), %al
262 andw $3, %dx
263 addw $0xcfc, %dx
264 outb %al, %dx
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200265 jmp clear_carry
wdenk8bde7f72003-06-27 21:31:46 +0000266
wdenk7a8e9bed2003-05-31 18:35:21 +0000267/*****************************************************************************/
268
269pci_bios_write_cfg_word:
270#ifdef PCI_BIOS_DEBUG
271cs incl num_pci_bios_write_cfg_word
272#endif
wdenk8bde7f72003-06-27 21:31:46 +0000273 call pci_bios_select_register
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200274gs movw OFFS_DI(%bp), %dx
wdenk7a8e9bed2003-05-31 18:35:21 +0000275gs movw OFFS_CX(%bp), %ax
276 andw $2, %dx
277 addw $0xcfc, %dx
278 outw %ax, %dx
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200279 jmp clear_carry
wdenk8bde7f72003-06-27 21:31:46 +0000280
wdenk7a8e9bed2003-05-31 18:35:21 +0000281/*****************************************************************************/
282
283pci_bios_write_cfg_dword:
284#ifdef PCI_BIOS_DEBUG
285cs incl num_pci_bios_write_cfg_dword
286#endif
wdenk8bde7f72003-06-27 21:31:46 +0000287 call pci_bios_select_register
wdenk7a8e9bed2003-05-31 18:35:21 +0000288gs movl OFFS_ECX(%bp), %eax
289 movw $0xcfc, %dx
290 outl %eax, %dx
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200291 jmp clear_carry
wdenk7a8e9bed2003-05-31 18:35:21 +0000292
293/*****************************************************************************/
294
295pci_bios_get_irq_routing:
296#ifdef PCI_BIOS_DEBUG
297cs incl num_pci_bios_get_irq_routing
298#endif
299 movb $0x81, %ah /* function not supported */
300 jmp set_carry
wdenk8bde7f72003-06-27 21:31:46 +0000301
wdenk7a8e9bed2003-05-31 18:35:21 +0000302/*****************************************************************************/
303
304pci_bios_set_irq:
305#ifdef PCI_BIOS_DEBUG
306cs incl num_pci_bios_set_irq
307#endif
308 movb $0x81, %ah /* function not supported */
309 jmp set_carry
310
311/*****************************************************************************/
312
313unknown_function:
314#ifdef PCI_BIOS_DEBUG
315cs incl num_pci_bios_unknown_function
316#endif
317 movb $0x81, %ah /* function not supported */
318 jmp set_carry
319
320/*****************************************************************************/
wdenk8bde7f72003-06-27 21:31:46 +0000321
wdenk7a8e9bed2003-05-31 18:35:21 +0000322pci_bios_select_register:
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200323gs movw OFFS_BX(%bp), %bx
324gs movw OFFS_DI(%bp), %ax
wdenk7a8e9bed2003-05-31 18:35:21 +0000325/* destroys eax, dx */
326__pci_bios_select_register: /* BX holds device id, AX holds register index */
327 pushl %ebx
328 andl $0xfc, %eax
329 andl $0xffff, %ebx
330 shll $8, %ebx
331 orl %ebx, %eax
332 orl $0x80000000, %eax
333 movw $0xcf8, %dx
334 outl %eax, %dx
335 popl %ebx
336 ret
337
338
339clear_carry:
340gs movw OFFS_FLAGS(%bp), %ax
341 andw $0xfffe, %ax /* clear carry -- function succeeded */
342gs movw %ax, OFFS_FLAGS(%bp)
343 xorw %ax, %ax
wdenk8bde7f72003-06-27 21:31:46 +0000344gs movb %ah, OFFS_AH(%bp)
wdenk7a8e9bed2003-05-31 18:35:21 +0000345 ret
346
347set_carry:
wdenk8bde7f72003-06-27 21:31:46 +0000348gs movb %ah, OFFS_AH(%bp)
wdenk7a8e9bed2003-05-31 18:35:21 +0000349gs movw OFFS_FLAGS(%bp), %ax
350 orw $1, %ax /* return carry -- function not supported */
351gs movw %ax, OFFS_FLAGS(%bp)
352 movw $-1, %ax
353 ret
354
355/*****************************************************************************/
356
357.globl pci_last_bus
358pci_last_bus:
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200359 .byte 0
wdenk7a8e9bed2003-05-31 18:35:21 +0000360
361#ifdef PCI_BIOS_DEBUG
362.globl num_pci_bios_present
363num_pci_bios_present:
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200364 .long 0
wdenk8bde7f72003-06-27 21:31:46 +0000365
wdenk7a8e9bed2003-05-31 18:35:21 +0000366.globl num_pci_bios_find_device
367num_pci_bios_find_device:
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200368 .long 0
wdenk7a8e9bed2003-05-31 18:35:21 +0000369
370.globl num_pci_bios_find_class
371num_pci_bios_find_class:
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200372 .long 0
wdenk7a8e9bed2003-05-31 18:35:21 +0000373
374.globl num_pci_bios_generate_special_cycle
wdenk8bde7f72003-06-27 21:31:46 +0000375num_pci_bios_generate_special_cycle:
wdenk7a8e9bed2003-05-31 18:35:21 +0000376 .long 0
wdenk8bde7f72003-06-27 21:31:46 +0000377
wdenk7a8e9bed2003-05-31 18:35:21 +0000378.globl num_pci_bios_read_cfg_byte
379num_pci_bios_read_cfg_byte:
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200380 .long 0
wdenk7a8e9bed2003-05-31 18:35:21 +0000381
382.globl num_pci_bios_read_cfg_word
383num_pci_bios_read_cfg_word:
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200384 .long 0
wdenk7a8e9bed2003-05-31 18:35:21 +0000385
386.globl num_pci_bios_read_cfg_dword
387num_pci_bios_read_cfg_dword:
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200388 .long 0
wdenk7a8e9bed2003-05-31 18:35:21 +0000389
390.globl num_pci_bios_write_cfg_byte
391num_pci_bios_write_cfg_byte:
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200392 .long 0
wdenk7a8e9bed2003-05-31 18:35:21 +0000393
394.globl num_pci_bios_write_cfg_word
395num_pci_bios_write_cfg_word:
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200396 .long 0
wdenk7a8e9bed2003-05-31 18:35:21 +0000397
398.globl num_pci_bios_write_cfg_dword
399num_pci_bios_write_cfg_dword:
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200400 .long 0
wdenk7a8e9bed2003-05-31 18:35:21 +0000401
402.globl num_pci_bios_get_irq_routing
403num_pci_bios_get_irq_routing:
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200404 .long 0
wdenk7a8e9bed2003-05-31 18:35:21 +0000405
406.globl num_pci_bios_set_irq
407num_pci_bios_set_irq:
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200408 .long 0
wdenk7a8e9bed2003-05-31 18:35:21 +0000409
410.globl num_pci_bios_unknown_function
411num_pci_bios_unknown_function:
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200412 .long 0
wdenk7a8e9bed2003-05-31 18:35:21 +0000413#endif