Merge branch 'master' of /home/stefan/git/u-boot/u-boot into next
[platform/kernel/u-boot.git] / lib_i386 / bios_pci.S
1 /*
2  * (C) Copyright 2002
3  * Daniel Engström, Omicron Ceti AB, daniel@omicron.se
4  *
5  * 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
26  * for platforms that use one PCI hose and configuration
27  * access type 1. (The common case for low-end PC's)
28  */
29
30 #include "bios.h"
31
32 #define PCI_BIOS_DEBUG
33
34 .section .bios, "ax"
35 .code16
36 .globl realmode_pci_bios_call_entry
37 realmode_pci_bios_call_entry:
38         MAKE_BIOS_STACK
39         call realmode_pci_bios
40         RESTORE_CALLERS_STACK
41         ret
42
43
44 .globl realmode_pci_bios
45 realmode_pci_bios:
46 gs      movw    OFFS_AX(%bp), %ax
47         cmpb    $1, %al
48         je      pci_bios_present
49         cmpb    $2, %al
50         je      pci_bios_find_device
51         cmpb    $3, %al
52         je      pci_bios_find_class
53         cmpb    $6, %al
54         je      pci_bios_generate_special_cycle
55         cmpb    $8, %al
56         je      pci_bios_read_cfg_byte
57         cmpb    $9, %al
58         je      pci_bios_read_cfg_word
59         cmpb    $10, %al
60         je      pci_bios_read_cfg_dword
61         cmpb    $11, %al
62         je      pci_bios_write_cfg_byte
63         cmpb    $12, %al
64         je      pci_bios_write_cfg_word
65         cmpb    $13, %al
66         je      pci_bios_write_cfg_dword
67         cmpb    $14, %al
68         je      pci_bios_get_irq_routing
69         cmpb    $15, %al
70         je      pci_bios_set_irq
71         jmp     unknown_function
72
73 /*****************************************************************************/
74
75 pci_bios_present:
76 #ifdef PCI_BIOS_DEBUG
77 cs      incl    num_pci_bios_present
78 #endif
79         movl    $0x20494350, %eax
80 gs      movl    %eax, OFFS_EDX(%bp)
81         movb    $0x01, %al
82 gs      movb    %al, OFFS_AL(%bp)       /* We support cfg type 1 */
83         movw    $0x0210, %ax            /* version 2.10 */
84 gs      movw    %ax, OFFS_BX(%bp)
85 cs      movb    pci_last_bus, %al       /* last bus number */
86 gs      movb    %al, OFFS_CL(%bp)
87         jmp     clear_carry
88
89 /*****************************************************************************/
90
91 /* device 0-31, function 0-7 */
92 pci_bios_find_device:
93 #ifdef PCI_BIOS_DEBUG
94 cs      incl    num_pci_bios_find_device
95 #endif
96 gs      movw    OFFS_CX(%bp), %di
97         shll    $16, %edi
98 gs      movw    OFFS_DX(%bp), %di       /* edi now holds device in upper 16
99                                          * bits and vendor in lower 16 bits */
100 gs      movw    OFFS_SI(%bp), %si
101         xorw    %bx, %bx                /* start at bus 0 dev 0 function 0 */
102 pfd_loop:
103         xorw    %ax, %ax                /* dword 0 is vendor/device */
104         call    __pci_bios_select_register
105         movw    $0xcfc, %dx
106         inl     %dx, %eax
107         cmpl    %edi, %eax              /* our device ? */
108         je      pfd_found_one
109 pfd_next_dev:
110         /* check for multi function devices */
111         movw    %bx, %ax
112         andw    $3, %ax
113         jnz     pfd_function_not_zero
114         movw    $0x000c, %ax
115         call    __pci_bios_select_register
116         movw    $0xcfe, %dx
117         inb     %dx, %al
118         andb    $0x80, %al
119         jz      pfd_not_multi_function
120 pfd_function_not_zero:
121         incw    %bx                     /* next function, overflows in to
122                                          * device number, then bus number */
123         jmp     pfd_check_bus
124
125 pfd_not_multi_function:
126         andw    $0xfff8, %bx            /* remove function bits */
127         addw    $0x0008, %bx            /* next device, overflows in to bus number */
128 pfd_check_bus:
129 cs      movb    pci_last_bus, %ah
130         cmpb    %ah, %bh
131         ja      pfd_not_found
132         jmp     pfd_loop
133 pfd_found_one:
134         decw    %si
135         js      pfd_done
136         jmp     pfd_next_dev
137
138 pfd_done:
139 gs      movw    %bx, OFFS_BX(%bp)
140         jmp     clear_carry
141
142 pfd_not_found:
143         movb    $0x86, %ah              /* device not found */
144         jmp     set_carry
145
146 /*****************************************************************************/
147
148 pci_bios_find_class:
149 #ifdef PCI_BIOS_DEBUG
150 cs      incl    num_pci_bios_find_class
151 #endif
152 gs      movl    OFFS_ECX(%bp), %edi
153         andl    $0x00ffffff, %edi       /* edi now holds class-code in lower 24 bits */
154 gs      movw    OFFS_SI(%bp), %si
155         xorw    %bx, %bx                /* start at bus 0 dev 0 function 0 */
156 pfc_loop:
157         movw    $8, %ax                 /* dword 8 is class-code high 24bits */
158         call    __pci_bios_select_register
159         movw    $0xcfc, %dx
160         inl     %dx, %eax
161         shrl    $8, %eax
162         andl    $0x00ffffff, %eax
163         cmpl    %edi, %eax              /* our device ? */
164         je      pfc_found_one
165 pfc_next_dev:
166         /* check for multi function devices */
167         andw    $3, %bx
168         jnz     pfc_function_not_zero
169         movw    $0x000c, %ax
170         call    __pci_bios_select_register
171         movw    $0xcfe, %dx
172         inb     %dx, %al
173         andb    $0x80, %al
174         jz      pfc_not_multi_function
175 pfc_function_not_zero:
176         incw    %bx                     /* next function, overflows in to
177                                          * device number, then bus number */
178         jmp     pfc_check_bus
179
180 pfc_not_multi_function:
181         andw    $0xfff8, %bx            /* remove function bits */
182         addw    $0x0008, %bx            /* next device, overflows in to bus number */
183 pfc_check_bus:
184 cs      movb    pci_last_bus, %ah
185         cmpb    %ah, %bh
186         ja      pfc_not_found
187         jmp     pfc_loop
188 pfc_found_one:
189         decw    %si
190         js      pfc_done
191         jmp     pfc_next_dev
192
193 pfc_done:
194 gs      movw    %bx, OFFS_BX(%bp)
195         jmp     clear_carry
196
197 pfc_not_found:
198         movb    $0x86, %ah              /* device not found */
199         jmp     set_carry
200
201 /*****************************************************************************/
202
203 pci_bios_generate_special_cycle:
204 #ifdef PCI_BIOS_DEBUG
205 cs      incl    num_pci_bios_generate_special_cycle
206 #endif
207         movb    $0x81, %ah              /* function not supported */
208         jmp     set_carry
209
210 /*****************************************************************************/
211
212 pci_bios_read_cfg_byte:
213 #ifdef PCI_BIOS_DEBUG
214 cs      incl    num_pci_bios_read_cfg_byte
215 #endif
216         call    pci_bios_select_register
217 gs      movw    OFFS_DI(%bp), %dx
218         andw    $3, %dx
219         addw    $0xcfc, %dx
220         inb     %dx, %al
221 gs      movb    %al, OFFS_CL(%bp)
222         jmp     clear_carry
223
224 /*****************************************************************************/
225
226 pci_bios_read_cfg_word:
227 #ifdef PCI_BIOS_DEBUG
228 cs      incl    num_pci_bios_read_cfg_word
229 #endif
230         call    pci_bios_select_register
231 gs      movw    OFFS_DI(%bp), %dx
232         andw    $2, %dx
233         addw    $0xcfc, %dx
234         inw     %dx, %ax
235 gs      movw    %ax, OFFS_CX(%bp)
236         jmp     clear_carry
237
238
239 /*****************************************************************************/
240
241 pci_bios_read_cfg_dword:
242 #ifdef PCI_BIOS_DEBUG
243 cs      incl    num_pci_bios_read_cfg_dword
244 #endif
245         call    pci_bios_select_register
246         movw    $0xcfc, %dx
247         inl     %dx, %eax
248 gs      movl    %eax, OFFS_ECX(%bp)
249         jmp     clear_carry
250
251 /*****************************************************************************/
252
253 pci_bios_write_cfg_byte:
254 #ifdef PCI_BIOS_DEBUG
255 cs      incl    num_pci_bios_write_cfg_byte
256 #endif
257         call    pci_bios_select_register
258 gs      movw    OFFS_DI(%bp), %dx
259 gs      movb    OFFS_CL(%bp), %al
260         andw    $3, %dx
261         addw    $0xcfc, %dx
262         outb    %al, %dx
263         jmp     clear_carry
264
265 /*****************************************************************************/
266
267 pci_bios_write_cfg_word:
268 #ifdef PCI_BIOS_DEBUG
269 cs      incl    num_pci_bios_write_cfg_word
270 #endif
271         call    pci_bios_select_register
272 gs      movw    OFFS_DI(%bp), %dx
273 gs      movw    OFFS_CX(%bp), %ax
274         andw    $2, %dx
275         addw    $0xcfc, %dx
276         outw    %ax, %dx
277         jmp     clear_carry
278
279 /*****************************************************************************/
280
281 pci_bios_write_cfg_dword:
282 #ifdef PCI_BIOS_DEBUG
283 cs      incl    num_pci_bios_write_cfg_dword
284 #endif
285         call    pci_bios_select_register
286 gs      movl    OFFS_ECX(%bp), %eax
287         movw    $0xcfc, %dx
288         outl    %eax, %dx
289         jmp     clear_carry
290
291 /*****************************************************************************/
292
293 pci_bios_get_irq_routing:
294 #ifdef PCI_BIOS_DEBUG
295 cs      incl    num_pci_bios_get_irq_routing
296 #endif
297         movb    $0x81, %ah              /* function not supported */
298         jmp     set_carry
299
300 /*****************************************************************************/
301
302 pci_bios_set_irq:
303 #ifdef PCI_BIOS_DEBUG
304 cs      incl    num_pci_bios_set_irq
305 #endif
306         movb    $0x81, %ah              /* function not supported */
307         jmp     set_carry
308
309 /*****************************************************************************/
310
311 unknown_function:
312 #ifdef PCI_BIOS_DEBUG
313 cs      incl    num_pci_bios_unknown_function
314 #endif
315         movb    $0x81, %ah              /* function not supported */
316         jmp     set_carry
317
318 /*****************************************************************************/
319
320 pci_bios_select_register:
321 gs      movw    OFFS_BX(%bp), %bx
322 gs      movw    OFFS_DI(%bp), %ax
323 /* destroys eax, dx */
324 __pci_bios_select_register:               /* BX holds device id, AX holds register index */
325         pushl   %ebx
326         andl    $0xfc, %eax
327         andl    $0xffff, %ebx
328         shll    $8, %ebx
329         orl     %ebx, %eax
330         orl     $0x80000000, %eax
331         movw    $0xcf8, %dx
332         outl    %eax, %dx
333         popl    %ebx
334         ret
335
336
337 clear_carry:
338 gs      movw    OFFS_FLAGS(%bp), %ax
339         andw    $0xfffe, %ax                    /* clear carry -- function succeeded */
340 gs      movw    %ax, OFFS_FLAGS(%bp)
341         xorw    %ax, %ax
342 gs      movb    %ah, OFFS_AH(%bp)
343         ret
344
345 set_carry:
346 gs      movb    %ah, OFFS_AH(%bp)
347 gs      movw    OFFS_FLAGS(%bp), %ax
348         orw     $1, %ax                         /* return carry -- function not supported */
349 gs      movw    %ax, OFFS_FLAGS(%bp)
350         movw    $-1, %ax
351         ret
352
353 /*****************************************************************************/
354
355 .globl pci_last_bus
356 pci_last_bus:
357         .byte   0
358
359 #ifdef PCI_BIOS_DEBUG
360 .globl num_pci_bios_present
361 num_pci_bios_present:
362         .long   0
363
364 .globl num_pci_bios_find_device
365 num_pci_bios_find_device:
366         .long   0
367
368 .globl num_pci_bios_find_class
369 num_pci_bios_find_class:
370         .long   0
371
372 .globl num_pci_bios_generate_special_cycle
373 num_pci_bios_generate_special_cycle:
374         .long 0
375
376 .globl num_pci_bios_read_cfg_byte
377 num_pci_bios_read_cfg_byte:
378         .long   0
379
380 .globl num_pci_bios_read_cfg_word
381 num_pci_bios_read_cfg_word:
382         .long   0
383
384 .globl num_pci_bios_read_cfg_dword
385 num_pci_bios_read_cfg_dword:
386         .long   0
387
388 .globl num_pci_bios_write_cfg_byte
389 num_pci_bios_write_cfg_byte:
390         .long   0
391
392 .globl num_pci_bios_write_cfg_word
393 num_pci_bios_write_cfg_word:
394         .long   0
395
396 .globl num_pci_bios_write_cfg_dword
397 num_pci_bios_write_cfg_dword:
398         .long   0
399
400 .globl num_pci_bios_get_irq_routing
401 num_pci_bios_get_irq_routing:
402         .long   0
403
404 .globl num_pci_bios_set_irq
405 num_pci_bios_set_irq:
406         .long   0
407
408 .globl num_pci_bios_unknown_function
409 num_pci_bios_unknown_function:
410         .long   0
411 #endif