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.hidden realmode_pci_bios_call_entry
38.type realmode_pci_bios_call_entry, @function
39realmode_pci_bios_call_entry:
40	MAKE_BIOS_STACK
41	call realmode_pci_bios
42	RESTORE_CALLERS_STACK
43	ret
44
45
46.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
74
75/*****************************************************************************/
76
77pci_bios_present:
78#ifdef PCI_BIOS_DEBUG
79cs	incl	num_pci_bios_present
80#endif
81	movl	$0x20494350, %eax
82gs	movl	%eax, OFFS_EDX(%bp)
83	movb	$0x01, %al
84gs	movb	%al, OFFS_AL(%bp)	/* We support cfg type 1 */
85	movw	$0x0210, %ax            /* version 2.10 */
86gs	movw	%ax, OFFS_BX(%bp)
87cs	movb	pci_last_bus, %al       /* last bus number */
88gs	movb	%al, OFFS_CL(%bp)
89	jmp	clear_carry
90
91/*****************************************************************************/
92
93/* device 0-31, function 0-7 */
94pci_bios_find_device:
95#ifdef PCI_BIOS_DEBUG
96cs	incl	num_pci_bios_find_device
97#endif
98gs	movw	OFFS_CX(%bp), %di
99	shll	$16, %edi
100gs	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
103	xorw	%bx, %bx                /* start at bus 0 dev 0 function 0 */
104pfd_loop:
105	xorw	%ax, %ax		/* dword 0 is vendor/device */
106	call	__pci_bios_select_register
107	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
116	movw	$0x000c, %ax
117	call	__pci_bios_select_register
118	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
126
127pfd_not_multi_function:
128	andw	$0xfff8, %bx            /* remove function bits */
129	addw	$0x0008, %bx            /* next device, overflows in to bus number */
130pfd_check_bus:
131cs	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:
141gs	movw	%bx, OFFS_BX(%bp)
142	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
154gs	movl	OFFS_ECX(%bp), %edi
155	andl	$0x00ffffff, %edi       /* edi now holds class-code in lower 24 bits */
156gs	movw	OFFS_SI(%bp), %si
157	xorw	%bx, %bx                /* start at bus 0 dev 0 function 0 */
158pfc_loop:
159	movw	$8, %ax			/* dword 8 is class-code high 24bits */
160	call	__pci_bios_select_register
161	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
171	movw	$0x000c, %ax
172	call	__pci_bios_select_register
173	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
181
182pfc_not_multi_function:
183	andw	$0xfff8, %bx            /* remove function bits */
184	addw	$0x0008, %bx            /* next device, overflows in to bus number */
185pfc_check_bus:
186cs	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:
196gs	movw	%bx, OFFS_BX(%bp)
197	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
211
212/*****************************************************************************/
213
214pci_bios_read_cfg_byte:
215#ifdef PCI_BIOS_DEBUG
216cs	incl	num_pci_bios_read_cfg_byte
217#endif
218	call	pci_bios_select_register
219gs	movw	OFFS_DI(%bp), %dx
220	andw	$3, %dx
221	addw	$0xcfc, %dx
222	inb	%dx, %al
223gs	movb	%al, OFFS_CL(%bp)
224	jmp	clear_carry
225
226/*****************************************************************************/
227
228pci_bios_read_cfg_word:
229#ifdef PCI_BIOS_DEBUG
230cs	incl	num_pci_bios_read_cfg_word
231#endif
232	call	pci_bios_select_register
233gs	movw	OFFS_DI(%bp), %dx
234	andw	$2, %dx
235	addw	$0xcfc, %dx
236	inw	%dx, %ax
237gs	movw	%ax, OFFS_CX(%bp)
238	jmp	clear_carry
239
240
241/*****************************************************************************/
242
243pci_bios_read_cfg_dword:
244#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
250gs	movl	%eax, OFFS_ECX(%bp)
251	jmp	clear_carry
252
253/*****************************************************************************/
254
255pci_bios_write_cfg_byte:
256#ifdef PCI_BIOS_DEBUG
257cs	incl	num_pci_bios_write_cfg_byte
258#endif
259	call	pci_bios_select_register
260gs	movw	OFFS_DI(%bp), %dx
261gs	movb	OFFS_CL(%bp), %al
262	andw	$3, %dx
263	addw	$0xcfc, %dx
264	outb	%al, %dx
265	jmp	clear_carry
266
267/*****************************************************************************/
268
269pci_bios_write_cfg_word:
270#ifdef PCI_BIOS_DEBUG
271cs	incl	num_pci_bios_write_cfg_word
272#endif
273	call	pci_bios_select_register
274gs	movw	OFFS_DI(%bp), %dx
275gs	movw	OFFS_CX(%bp), %ax
276	andw	$2, %dx
277	addw	$0xcfc, %dx
278	outw	%ax, %dx
279	jmp	clear_carry
280
281/*****************************************************************************/
282
283pci_bios_write_cfg_dword:
284#ifdef PCI_BIOS_DEBUG
285cs	incl	num_pci_bios_write_cfg_dword
286#endif
287	call	pci_bios_select_register
288gs	movl	OFFS_ECX(%bp), %eax
289	movw	$0xcfc, %dx
290	outl	%eax, %dx
291	jmp	clear_carry
292
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
301
302/*****************************************************************************/
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/*****************************************************************************/
321
322pci_bios_select_register:
323gs	movw	OFFS_BX(%bp), %bx
324gs	movw	OFFS_DI(%bp), %ax
325/* 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
344gs	movb	%ah, OFFS_AH(%bp)
345	ret
346
347set_carry:
348gs	movb	%ah, OFFS_AH(%bp)
349gs	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:
359	.byte	0
360
361#ifdef PCI_BIOS_DEBUG
362.globl num_pci_bios_present
363num_pci_bios_present:
364	.long	0
365
366.globl num_pci_bios_find_device
367num_pci_bios_find_device:
368	.long	0
369
370.globl num_pci_bios_find_class
371num_pci_bios_find_class:
372	.long	0
373
374.globl num_pci_bios_generate_special_cycle
375num_pci_bios_generate_special_cycle:
376	.long 0
377
378.globl num_pci_bios_read_cfg_byte
379num_pci_bios_read_cfg_byte:
380	.long	0
381
382.globl num_pci_bios_read_cfg_word
383num_pci_bios_read_cfg_word:
384	.long	0
385
386.globl num_pci_bios_read_cfg_dword
387num_pci_bios_read_cfg_dword:
388	.long	0
389
390.globl num_pci_bios_write_cfg_byte
391num_pci_bios_write_cfg_byte:
392	.long	0
393
394.globl num_pci_bios_write_cfg_word
395num_pci_bios_write_cfg_word:
396	.long	0
397
398.globl num_pci_bios_write_cfg_dword
399num_pci_bios_write_cfg_dword:
400	.long	0
401
402.globl num_pci_bios_get_irq_routing
403num_pci_bios_get_irq_routing:
404	.long	0
405
406.globl num_pci_bios_set_irq
407num_pci_bios_set_irq:
408	.long	0
409
410.globl num_pci_bios_unknown_function
411num_pci_bios_unknown_function:
412	.long	0
413#endif
414