10ca2426bSSimon Glass /*
20ca2426bSSimon Glass * From Coreboot
30ca2426bSSimon Glass *
40ca2426bSSimon Glass * Copyright (C) 2001 Ronald G. Minnich
50ca2426bSSimon Glass * Copyright (C) 2005 Nick.Barker9@btinternet.com
60ca2426bSSimon Glass * Copyright (C) 2007-2009 coresystems GmbH
70ca2426bSSimon Glass *
80ca2426bSSimon Glass * SPDX-License-Identifier: GPL-2.0
90ca2426bSSimon Glass */
100ca2426bSSimon Glass
110ca2426bSSimon Glass #include <common.h>
120ca2426bSSimon Glass #include <asm/pci.h>
130ca2426bSSimon Glass #include "bios_emul.h"
140ca2426bSSimon Glass
150ca2426bSSimon Glass /* errors go in AH. Just set these up so that word assigns will work */
160ca2426bSSimon Glass enum {
170ca2426bSSimon Glass PCIBIOS_SUCCESSFUL = 0x0000,
180ca2426bSSimon Glass PCIBIOS_UNSUPPORTED = 0x8100,
190ca2426bSSimon Glass PCIBIOS_BADVENDOR = 0x8300,
200ca2426bSSimon Glass PCIBIOS_NODEV = 0x8600,
210ca2426bSSimon Glass PCIBIOS_BADREG = 0x8700
220ca2426bSSimon Glass };
230ca2426bSSimon Glass
int10_handler(void)240ca2426bSSimon Glass int int10_handler(void)
250ca2426bSSimon Glass {
260ca2426bSSimon Glass static u8 cursor_row, cursor_col;
270ca2426bSSimon Glass int res = 0;
280ca2426bSSimon Glass
290ca2426bSSimon Glass switch ((M.x86.R_EAX & 0xff00) >> 8) {
300ca2426bSSimon Glass case 0x01: /* Set cursor shape */
310ca2426bSSimon Glass res = 1;
320ca2426bSSimon Glass break;
330ca2426bSSimon Glass case 0x02: /* Set cursor position */
340ca2426bSSimon Glass if (cursor_row != ((M.x86.R_EDX >> 8) & 0xff) ||
350ca2426bSSimon Glass cursor_col >= (M.x86.R_EDX & 0xff)) {
360ca2426bSSimon Glass debug("\n");
370ca2426bSSimon Glass }
380ca2426bSSimon Glass cursor_row = (M.x86.R_EDX >> 8) & 0xff;
390ca2426bSSimon Glass cursor_col = M.x86.R_EDX & 0xff;
400ca2426bSSimon Glass res = 1;
410ca2426bSSimon Glass break;
420ca2426bSSimon Glass case 0x03: /* Get cursor position */
430ca2426bSSimon Glass M.x86.R_EAX &= 0x00ff;
440ca2426bSSimon Glass M.x86.R_ECX = 0x0607;
450ca2426bSSimon Glass M.x86.R_EDX = (cursor_row << 8) | cursor_col;
460ca2426bSSimon Glass res = 1;
470ca2426bSSimon Glass break;
480ca2426bSSimon Glass case 0x06: /* Scroll up */
490ca2426bSSimon Glass debug("\n");
500ca2426bSSimon Glass res = 1;
510ca2426bSSimon Glass break;
520ca2426bSSimon Glass case 0x08: /* Get Character and Mode at Cursor Position */
530ca2426bSSimon Glass M.x86.R_EAX = 0x0f00 | 'A'; /* White on black 'A' */
540ca2426bSSimon Glass res = 1;
550ca2426bSSimon Glass break;
560ca2426bSSimon Glass case 0x09: /* Write Character and attribute */
570ca2426bSSimon Glass case 0x0e: /* Write Character */
580ca2426bSSimon Glass debug("%c", M.x86.R_EAX & 0xff);
590ca2426bSSimon Glass res = 1;
600ca2426bSSimon Glass break;
610ca2426bSSimon Glass case 0x0f: /* Get video mode */
620ca2426bSSimon Glass M.x86.R_EAX = 0x5002; /*80 x 25 */
630ca2426bSSimon Glass M.x86.R_EBX &= 0x00ff;
640ca2426bSSimon Glass res = 1;
650ca2426bSSimon Glass break;
660ca2426bSSimon Glass default:
670ca2426bSSimon Glass printf("Unknown INT10 function %04x\n", M.x86.R_EAX & 0xffff);
680ca2426bSSimon Glass break;
690ca2426bSSimon Glass }
700ca2426bSSimon Glass return res;
710ca2426bSSimon Glass }
720ca2426bSSimon Glass
int12_handler(void)730ca2426bSSimon Glass int int12_handler(void)
740ca2426bSSimon Glass {
750ca2426bSSimon Glass M.x86.R_EAX = 64 * 1024;
760ca2426bSSimon Glass return 1;
770ca2426bSSimon Glass }
780ca2426bSSimon Glass
int16_handler(void)790ca2426bSSimon Glass int int16_handler(void)
800ca2426bSSimon Glass {
810ca2426bSSimon Glass int res = 0;
820ca2426bSSimon Glass
830ca2426bSSimon Glass switch ((M.x86.R_EAX & 0xff00) >> 8) {
840ca2426bSSimon Glass case 0x00: /* Check for Keystroke */
850ca2426bSSimon Glass M.x86.R_EAX = 0x6120; /* Space Bar, Space */
860ca2426bSSimon Glass res = 1;
870ca2426bSSimon Glass break;
880ca2426bSSimon Glass case 0x01: /* Check for Keystroke */
890ca2426bSSimon Glass M.x86.R_EFLG |= 1 << 6; /* Zero Flag set (no key available) */
900ca2426bSSimon Glass res = 1;
910ca2426bSSimon Glass break;
920ca2426bSSimon Glass default:
930ca2426bSSimon Glass printf("Unknown INT16 function %04x\n", M.x86.R_EAX & 0xffff);
940ca2426bSSimon Glass
950ca2426bSSimon Glass break;
960ca2426bSSimon Glass }
970ca2426bSSimon Glass return res;
980ca2426bSSimon Glass }
990ca2426bSSimon Glass
1000ca2426bSSimon Glass #define PCI_CONFIG_SPACE_TYPE1 (1 << 0)
1010ca2426bSSimon Glass #define PCI_SPECIAL_CYCLE_TYPE1 (1 << 4)
1020ca2426bSSimon Glass
int1a_handler(void)1030ca2426bSSimon Glass int int1a_handler(void)
1040ca2426bSSimon Glass {
1050ca2426bSSimon Glass unsigned short func = (unsigned short)M.x86.R_EAX;
1060ca2426bSSimon Glass int retval = 1;
1070ca2426bSSimon Glass unsigned short devid, vendorid, devfn;
108*7d8e4042SSimon Glass struct udevice *dev;
1090ca2426bSSimon Glass /* Use short to get rid of gabage in upper half of 32-bit register */
1100ca2426bSSimon Glass short devindex;
1110ca2426bSSimon Glass unsigned char bus;
112*7d8e4042SSimon Glass pci_dev_t bdf;
1130ca2426bSSimon Glass u32 dword;
1140ca2426bSSimon Glass u16 word;
1150ca2426bSSimon Glass u8 byte, reg;
116*7d8e4042SSimon Glass int ret;
1170ca2426bSSimon Glass
1180ca2426bSSimon Glass switch (func) {
1190ca2426bSSimon Glass case 0xb101: /* PCIBIOS Check */
1200ca2426bSSimon Glass M.x86.R_EDX = 0x20494350; /* ' ICP' */
1210ca2426bSSimon Glass M.x86.R_EAX &= 0xffff0000; /* Clear AH / AL */
1220ca2426bSSimon Glass M.x86.R_EAX |= PCI_CONFIG_SPACE_TYPE1 |
1230ca2426bSSimon Glass PCI_SPECIAL_CYCLE_TYPE1;
1240ca2426bSSimon Glass /*
1250ca2426bSSimon Glass * last bus in the system. Hard code to 255 for now.
1260ca2426bSSimon Glass * dev_enumerate() does not seem to tell us (publically)
1270ca2426bSSimon Glass */
1280ca2426bSSimon Glass M.x86.R_ECX = 0xff;
1290ca2426bSSimon Glass M.x86.R_EDI = 0x00000000; /* protected mode entry */
1300ca2426bSSimon Glass retval = 1;
1310ca2426bSSimon Glass break;
1320ca2426bSSimon Glass case 0xb102: /* Find Device */
1330ca2426bSSimon Glass devid = M.x86.R_ECX;
1340ca2426bSSimon Glass vendorid = M.x86.R_EDX;
1350ca2426bSSimon Glass devindex = M.x86.R_ESI;
136*7d8e4042SSimon Glass bdf = -1;
137*7d8e4042SSimon Glass ret = dm_pci_find_device(vendorid, devid, devindex, &dev);
138*7d8e4042SSimon Glass if (!ret) {
1390ca2426bSSimon Glass unsigned short busdevfn;
140*7d8e4042SSimon Glass
141*7d8e4042SSimon Glass bdf = dm_pci_get_bdf(dev);
1420ca2426bSSimon Glass M.x86.R_EAX &= 0xffff00ff; /* Clear AH */
1430ca2426bSSimon Glass M.x86.R_EAX |= PCIBIOS_SUCCESSFUL;
1440ca2426bSSimon Glass /*
1450ca2426bSSimon Glass * busnum is an unsigned char;
1460ca2426bSSimon Glass * devfn is an int, so we mask it off.
1470ca2426bSSimon Glass */
148*7d8e4042SSimon Glass busdevfn = (PCI_BUS(bdf) << 8) | PCI_DEV(bdf) << 3 |
149*7d8e4042SSimon Glass PCI_FUNC(bdf);
1500ca2426bSSimon Glass debug("0x%x: return 0x%x\n", func, busdevfn);
1510ca2426bSSimon Glass M.x86.R_EBX = busdevfn;
1520ca2426bSSimon Glass retval = 1;
1530ca2426bSSimon Glass } else {
1540ca2426bSSimon Glass M.x86.R_EAX &= 0xffff00ff; /* Clear AH */
1550ca2426bSSimon Glass M.x86.R_EAX |= PCIBIOS_NODEV;
1560ca2426bSSimon Glass retval = 0;
1570ca2426bSSimon Glass }
1580ca2426bSSimon Glass break;
1590ca2426bSSimon Glass case 0xb10a: /* Read Config Dword */
1600ca2426bSSimon Glass case 0xb109: /* Read Config Word */
1610ca2426bSSimon Glass case 0xb108: /* Read Config Byte */
1620ca2426bSSimon Glass case 0xb10d: /* Write Config Dword */
1630ca2426bSSimon Glass case 0xb10c: /* Write Config Word */
1640ca2426bSSimon Glass case 0xb10b: /* Write Config Byte */
1650ca2426bSSimon Glass devfn = M.x86.R_EBX & 0xff;
1660ca2426bSSimon Glass bus = M.x86.R_EBX >> 8;
1670ca2426bSSimon Glass reg = M.x86.R_EDI;
168*7d8e4042SSimon Glass bdf = PCI_BDF(bus, devfn >> 3, devfn & 7);
169*7d8e4042SSimon Glass
170*7d8e4042SSimon Glass ret = dm_pci_bus_find_bdf(bdf, &dev);
171*7d8e4042SSimon Glass if (ret) {
172*7d8e4042SSimon Glass debug("%s: Device %x not found\n", __func__, bdf);
173*7d8e4042SSimon Glass break;
174*7d8e4042SSimon Glass }
1751441d81aSJian Luo
1760ca2426bSSimon Glass switch (func) {
1770ca2426bSSimon Glass case 0xb108: /* Read Config Byte */
178*7d8e4042SSimon Glass dm_pci_read_config8(dev, reg, &byte);
1790ca2426bSSimon Glass M.x86.R_ECX = byte;
1800ca2426bSSimon Glass break;
1810ca2426bSSimon Glass case 0xb109: /* Read Config Word */
182*7d8e4042SSimon Glass dm_pci_read_config16(dev, reg, &word);
1830ca2426bSSimon Glass M.x86.R_ECX = word;
1840ca2426bSSimon Glass break;
1850ca2426bSSimon Glass case 0xb10a: /* Read Config Dword */
186*7d8e4042SSimon Glass dm_pci_read_config32(dev, reg, &dword);
1870ca2426bSSimon Glass M.x86.R_ECX = dword;
1880ca2426bSSimon Glass break;
1890ca2426bSSimon Glass case 0xb10b: /* Write Config Byte */
1900ca2426bSSimon Glass byte = M.x86.R_ECX;
191*7d8e4042SSimon Glass dm_pci_write_config8(dev, reg, byte);
1920ca2426bSSimon Glass break;
1930ca2426bSSimon Glass case 0xb10c: /* Write Config Word */
1940ca2426bSSimon Glass word = M.x86.R_ECX;
195*7d8e4042SSimon Glass dm_pci_write_config16(dev, reg, word);
1960ca2426bSSimon Glass break;
1970ca2426bSSimon Glass case 0xb10d: /* Write Config Dword */
1980ca2426bSSimon Glass dword = M.x86.R_ECX;
199*7d8e4042SSimon Glass dm_pci_write_config32(dev, reg, dword);
2000ca2426bSSimon Glass break;
2010ca2426bSSimon Glass }
2020ca2426bSSimon Glass #ifdef CONFIG_REALMODE_DEBUG
2030ca2426bSSimon Glass debug("0x%x: bus %d devfn 0x%x reg 0x%x val 0x%x\n", func,
2040ca2426bSSimon Glass bus, devfn, reg, M.x86.R_ECX);
2050ca2426bSSimon Glass #endif
2060ca2426bSSimon Glass M.x86.R_EAX &= 0xffff00ff; /* Clear AH */
2070ca2426bSSimon Glass M.x86.R_EAX |= PCIBIOS_SUCCESSFUL;
2080ca2426bSSimon Glass retval = 1;
2090ca2426bSSimon Glass break;
2100ca2426bSSimon Glass default:
2110ca2426bSSimon Glass printf("UNSUPPORTED PCIBIOS FUNCTION 0x%x\n", func);
2120ca2426bSSimon Glass M.x86.R_EAX &= 0xffff00ff; /* Clear AH */
2130ca2426bSSimon Glass M.x86.R_EAX |= PCIBIOS_UNSUPPORTED;
2140ca2426bSSimon Glass retval = 0;
2150ca2426bSSimon Glass break;
2160ca2426bSSimon Glass }
2170ca2426bSSimon Glass
2180ca2426bSSimon Glass return retval;
2190ca2426bSSimon Glass }
220