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 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 730ca2426bSSimon Glass int int12_handler(void) 740ca2426bSSimon Glass { 750ca2426bSSimon Glass M.x86.R_EAX = 64 * 1024; 760ca2426bSSimon Glass return 1; 770ca2426bSSimon Glass } 780ca2426bSSimon Glass 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 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