diff options
Diffstat (limited to 'src/northbridge/intel/i82830')
-rw-r--r-- | src/northbridge/intel/i82830/Makefile.inc | 2 | ||||
-rw-r--r-- | src/northbridge/intel/i82830/i82830_smihandler.c | 374 | ||||
-rw-r--r-- | src/northbridge/intel/i82830/northbridge.c | 2 | ||||
-rw-r--r-- | src/northbridge/intel/i82830/raminit.c | 1 | ||||
-rw-r--r-- | src/northbridge/intel/i82830/vga.c | 60 |
5 files changed, 435 insertions, 4 deletions
diff --git a/src/northbridge/intel/i82830/Makefile.inc b/src/northbridge/intel/i82830/Makefile.inc index 3ebb8a5aaf..57dedfde73 100644 --- a/src/northbridge/intel/i82830/Makefile.inc +++ b/src/northbridge/intel/i82830/Makefile.inc @@ -1,2 +1,4 @@ driver-y += northbridge.o driver-y += vga.o + +smmobj-$(CONFIG_HAVE_SMI_HANDLER) += i82830_smihandler.o diff --git a/src/northbridge/intel/i82830/i82830_smihandler.c b/src/northbridge/intel/i82830/i82830_smihandler.c new file mode 100644 index 0000000000..ae5d5e2872 --- /dev/null +++ b/src/northbridge/intel/i82830/i82830_smihandler.c @@ -0,0 +1,374 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2010 coresystems GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of + * the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <types.h> +#include <string.h> +#include <arch/io.h> +#include <arch/romcc_io.h> +#include <console/console.h> +#include <cpu/x86/cache.h> +#include <cpu/x86/smm.h> +#include <device/pci_def.h> +#include "i82830.h" + +extern unsigned char *mbi; +extern u32 mbi_len; + +#define DEBUG_SMI + +/* If YABEL is enabled and it's not running at 0x00000000, we have to add some + * offset to all our mbi object memory accesses + */ +#if defined(CONFIG_PCI_OPTION_ROM_RUN_YABEL) && !defined(CONFIG_YABEL_DIRECTHW) +#define OBJ_OFFSET CONFIG_YABEL_VIRTMEM_LOCATION +#else +#define OBJ_OFFSET 0x00000 +#endif + +/* I830M */ +#define SMRAM 0x90 +#define D_OPEN (1 << 6) +#define D_CLS (1 << 5) +#define D_LCK (1 << 4) +#define G_SMRANE (1 << 3) +#define C_BASE_SEG ((0 << 2) | (1 << 1) | (0 << 0)) + + +typedef struct { + u32 mhid; + u32 function; + u32 retsts; + u32 rfu; +} __attribute__((packed)) banner_id_t; + +#define MSH_OK 0x0000 +#define MSH_OK_RESTART 0x0001 +#define MSH_FWH_ERR 0x00ff +#define MSH_IF_BAD_ID 0x0100 +#define MSH_IF_BAD_FUNC 0x0101 +#define MSH_IF_MBI_CORRUPT 0x0102 +#define MSH_IF_BAD_HANDLE 0x0103 +#define MSH_ALRDY_ATCHED 0x0104 +#define MSH_NOT_ATCHED 0x0105 +#define MSH_IF 0x0106 +#define MSH_IF_INVADDR 0x0107 +#define MSH_IF_UKN_TYPE 0x0108 +#define MSH_IF_NOT_FOUND 0x0109 +#define MSH_IF_NO_KEY 0x010a +#define MSH_IF_BUF_SIZE 0x010b +#define MSH_IF_NOT_PENDING 0x010c + +static void +dump(u8 * addr, u32 len) +{ + printk_debug("\n%s(%p, %x):\n", __func__, addr, len); + while (len) { + unsigned int tmpCnt = len; + unsigned char x; + if (tmpCnt > 8) + tmpCnt = 8; + printk_debug("\n%p: ", addr); + // print hex + while (tmpCnt--) { + x = *addr++; + printk_debug("%02x ", x); + } + tmpCnt = len; + if (tmpCnt > 8) + tmpCnt = 8; + len -= tmpCnt; + //reset addr ptr to print ascii + addr = addr - tmpCnt; + // print ascii + while (tmpCnt--) { + x = *addr++; + if ((x < 32) || (x >= 127)) { + //non-printable char + x = '.'; + } + printk_debug("%c", x); + } + } + printk_debug("\n"); +} + +typedef struct { + banner_id_t banner; + u16 versionmajor; + u16 versionminor; + u32 smicombuffersize; +} __attribute__((packed)) version_t; + +typedef struct { + u16 header_id; + u16 attributes; + u16 size; + u8 name_len; + u8 reserved; + u32 type; + u32 header_ext; + u8 name[0]; +} __attribute__((packed)) mbi_header_t; + +typedef struct { + banner_id_t banner; + u64 handle; + u32 objnum; + mbi_header_t header; +} __attribute__((packed)) obj_header_t; + +typedef struct { + banner_id_t banner; + u64 handle; + u32 objnum; + u32 start; + u32 numbytes; + u32 buflen; + u32 buffer; +} __attribute__((packed)) get_object_t; + +static void mbi_call(u8 subf, banner_id_t *banner_id) +{ + // printk_debug("MBI\n"); + // printk_debug("|- sub function %x\n", subf); + // printk_debug("|- banner id @ %x\n", (u32)banner_id); + // printk_debug("| |- mhid %x\n", banner_id->mhid); + // printk_debug("| |- function %x\n", banner_id->function); + // printk_debug("| |- return status %x\n", banner_id->retsts); + // printk_debug("| |- rfu %x\n", banner_id->rfu); + + switch(banner_id->function) { + case 0x0001: { + version_t *version; + printk_debug("|- MBI_QueryInterface\n"); + version = (version_t *)banner_id; + version->banner.retsts = MSH_OK; + version->versionmajor=1; + version->versionminor=3; + version->smicombuffersize=0x1000; + break; + } + case 0x0002: + printk_debug("|- MBI_Attach\n"); + printk_debug("| |- Not Implemented!\n"); + break; + case 0x0003: + printk_debug("|- MBI_Detach\n"); + printk_debug("| |- Not Implemented!\n"); + break; + case 0x0201: { + obj_header_t *obj_header = (obj_header_t *)banner_id; + mbi_header_t *mbi_header = NULL; + printk_debug("|- MBI_GetObjectHeader\n"); + printk_debug("| |- objnum = %d\n", obj_header->objnum); + + int i, count=0; + obj_header->banner.retsts = MSH_IF_NOT_FOUND; + + for (i=0; i< mbi_len;) { + int len; + + if (!(mbi[i] == 0xf0 && mbi [i+1] == 0xf6)) { + i+=16; + continue; + } + + mbi_header = (mbi_header_t *)&mbi[i]; + len = ALIGN((mbi_header->size * 16) + sizeof(mbi_header) + mbi_header->name_len, 16); + + if (obj_header->objnum == count) { + int headerlen = ALIGN(sizeof(mbi_header) + mbi_header->name_len + 15, 16); + // printk_debug("| |- headerlen = %d\n", headerlen); + memcpy(&obj_header->header, mbi_header, headerlen); + obj_header->banner.retsts = MSH_OK; + printk_debug("| |- MBI module '"); + int j; + for (j=0; j < mbi_header->name_len && mbi_header->name[j]; j++) + printk_debug("%c", mbi_header->name[j]); + printk_debug("' found.\n", obj_header->objnum); + // dump(banner_id, sizeof(obj_header_t) + 16); + break; + } + i += len; + count++; + } + if (obj_header->banner.retsts == MSH_IF_NOT_FOUND) + printk_debug("| |- MBI object #%d not found.\n", obj_header->objnum); + break; + } + case 0x0203: { + get_object_t *getobj = (get_object_t *)banner_id; + mbi_header_t *mbi_header = NULL; + printk_debug("|- MBI_GetObject\n"); + // printk_debug("| |- handle = %016lx\n", getobj->handle); + printk_debug("| |- objnum = %d\n", getobj->objnum); + printk_debug("| |- start = %x\n", getobj->start); + printk_debug("| |- numbytes = %x\n", getobj->numbytes); + printk_debug("| |- buflen = %x\n", getobj->buflen); + printk_debug("| |- buffer = %x\n", getobj->buffer); + + int i, count=0; + getobj->banner.retsts = MSH_IF_NOT_FOUND; + + for (i=0; i< mbi_len;) { + int len; + + if (!(mbi[i] == 0xf0 && mbi [i+1] == 0xf6)) { + i+=16; + continue; + } + + mbi_header = (mbi_header_t *)&mbi[i]; + len = ALIGN((mbi_header->size * 16) + sizeof(mbi_header) + mbi_header->name_len, 16); + + if (getobj->objnum == count) { + printk_debug("| |- len = %x\n", len); + memcpy((void *)(getobj->buffer + OBJ_OFFSET), + ((char *)mbi_header) + 0x20 , (len > getobj->buflen ? getobj->buflen : len)); + + getobj->banner.retsts = MSH_OK; + //dump(banner_id, sizeof(getobj) + len); + break; + } + i += len; + count++; + } + if (getobj->banner.retsts == MSH_IF_NOT_FOUND) + printk_debug("MBI module %d not found.\n", getobj->objnum); + break; + } + default: + printk_debug("|- function %x\n", banner_id->function); + printk_debug("| |- Unknown Function!\n"); + break; + } + printk_debug("\n"); + //dump(banner_id, 0x20); +} + +#define SMI_IFC_SUCCESS 1 +#define SMI_IFC_FAILURE_GENERIC 0 +#define SMI_IFC_FAILURE_INVALID 2 +#define SMI_IFC_FAILURE_CRITICAL 4 +#define SMI_IFC_FAILURE_NONCRITICAL 6 + +#define PC10 0x10 +#define PC11 0x11 +#define PC12 0x12 +#define PC13 0x13 + +void smi_interface_call(void) +{ + u32 mmio; + mmio = pci_read_config32(PCI_DEV(0, 0x02, 0), 0x14); + // mmio &= 0xfff80000; + // printk_debug("mmio=%x\n", mmio); + + u16 swsmi; + swsmi=pci_read_config16(PCI_DEV(0, 0x02, 0), 0xe0); + + if (!(swsmi & 1)) + return; + + swsmi &= ~(1 << 0); // clear SMI toggle + + switch ((swsmi>>1) & 0xf) { + case 0: + printk_debug("Interface Function Presence Test.\n"); + swsmi = 0; + swsmi &= ~(7 << 5); // Exit: Result + swsmi |= (SMI_IFC_SUCCESS << 5); + swsmi &= 0xff; + swsmi |= (PC13 << 8); + pci_write_config16(PCI_DEV(0, 0x02, 0), 0xe0, swsmi); + // pathetic + write32(mmio + 0x71428, 0x494e5443); + return; + case 4: + printk_debug("Get BIOS Data.\n"); + printk_debug("swsmi=%04x\n", swsmi); + break; + case 5: + printk_debug("Call MBI Functions.\n"); + mbi_call(swsmi >> 8, (banner_id_t *)((readl(mmio + 0x71428) & 0x000fffff) + OBJ_OFFSET) ); + // swsmi = 0x0000; + swsmi &= ~(7 << 5); // Exit: Result + swsmi |= (SMI_IFC_SUCCESS << 5); + pci_write_config16(PCI_DEV(0, 0x02, 0), 0xe0, swsmi); + return; + case 6: + printk_debug("System BIOS Callbacks.\n"); + printk_debug("swsmi=%04x\n", swsmi); + break; + default: + printk_debug("Unknown SMI interface call %04x\n", swsmi); + break; + } + + swsmi &= ~(7 << 5); // Exit: Result + swsmi |= (SMI_IFC_FAILURE_CRITICAL << 7); + pci_write_config16(PCI_DEV(0, 0x02, 0), 0xe0, swsmi); +} + +/** + * @brief read and clear ERRSTS + * @return ERRSTS register + */ +static u16 reset_err_status(void) +{ + u16 reg16; + + reg16 = pci_read_config16(PCI_DEV(0, 0x00, 0), ERRSTS); + /* set status bits are cleared by writing 1 to them */ + pci_write_config16(PCI_DEV(0, 0x00, 0), ERRSTS, reg16); + + return reg16; +} + +static void dump_err_status(u32 errsts) +{ + printk_debug("ERRSTS: "); + if (errsts & (1 << 12)) printk_debug("MBI "); + if (errsts & (1 << 9)) printk_debug("LCKF "); + if (errsts & (1 << 8)) printk_debug("DTF "); + if (errsts & (1 << 5)) printk_debug("UNSC "); + if (errsts & (1 << 4)) printk_debug("OOGF "); + if (errsts & (1 << 3)) printk_debug("IAAF "); + if (errsts & (1 << 2)) printk_debug("ITTEF "); + printk_debug("\n"); +} + +void northbridge_smi_handler(unsigned int node, smm_state_save_area_t *state_save) +{ + u16 errsts; + + /* We need to clear the SMI status registers, or we won't see what's + * happening in the following calls. + */ + errsts = reset_err_status(); + if (errsts & (1 << 12)) { + smi_interface_call(); + } else { + if (errsts) + dump_err_status(errsts); + } + +} diff --git a/src/northbridge/intel/i82830/northbridge.c b/src/northbridge/intel/i82830/northbridge.c index e482db6cf6..af9663df09 100644 --- a/src/northbridge/intel/i82830/northbridge.c +++ b/src/northbridge/intel/i82830/northbridge.c @@ -116,7 +116,7 @@ static void pci_domain_set_resources(device_t dev) */ tomk = ((unsigned long)pci_read_config8(mc_dev, DRB + 3)) << 15; tomk -= igd_memory; - printk_debug("Setting RAM size to %ld\n", tomk); + printk_debug("Memory detected: %ldKB RAM\n", tomk); /* Compute the top of low memory. */ tolmk = pci_tolm >> 10; diff --git a/src/northbridge/intel/i82830/raminit.c b/src/northbridge/intel/i82830/raminit.c index 9cb194ec22..2b747158c6 100644 --- a/src/northbridge/intel/i82830/raminit.c +++ b/src/northbridge/intel/i82830/raminit.c @@ -536,6 +536,7 @@ static void northbridge_set_registers(void) value = pci_read_config16(NORTHBRIDGE, GCC1); value |= igd_memory << 4; + value |= 1; // 64MB aperture pci_write_config16(NORTHBRIDGE, GCC1, value); PRINT_DEBUG("Initial northbridge registers have been set.\r\n"); diff --git a/src/northbridge/intel/i82830/vga.c b/src/northbridge/intel/i82830/vga.c index e9cfdac0c6..8c1cac0a84 100644 --- a/src/northbridge/intel/i82830/vga.c +++ b/src/northbridge/intel/i82830/vga.c @@ -24,13 +24,67 @@ #include <device/device.h> #include <device/pci.h> #include <device/pci_ids.h> +#include <cbfs.h> +#include <x86emu/x86emu.h> -static void vga_init(device_t dev) { - +static void vga_init(device_t dev) +{ printk_info("Starting Graphics Initialization\n"); + struct cbfs_file *file = cbfs_find("mbi.bin"); + void *mbi = NULL; + unsigned int mbi_len = 0; + + if (file) { + if (ntohl(file->type) != CBFS_TYPE_MBI) { + printk_info( "CBFS: MBI binary is of type %x instead of" + "type %x\n", file->type, CBFS_TYPE_MBI); + } else { + mbi = (void *) CBFS_SUBHEADER(file); + mbi_len = file->len; + } + } else { + printk_info( "Could not find MBI.\n"); + } + + if (mbi && mbi_len) { + /* The GDT or coreboot table is going to live here. But + * a long time after we relocated the GNVS, so this is + * not troublesome. + */ + *(u32 *)0x500 = (u32)mbi; + *(u32 *)0x504 = (u32)mbi_len; + outb(0xeb, 0xb2); + } + pci_dev_init(dev); printk_info("Graphics Initialization Complete\n"); - /* Future TV-OUT code will be called from here. */ + + /* Enable TV-Out */ +#if defined(CONFIG_PCI_OPTION_ROM_RUN_YABEL) && CONFIG_PCI_OPTION_ROM_RUN_YABEL +#define PIPE_A_CRT (1 << 0) +#define PIPE_A_LFP (1 << 1) +#define PIPE_A_TV (1 << 3) +#define PIPE_B_CRT (1 << 8) +#define PIPE_B_TV (1 << 10) + printk_debug("Enabling TV-Out\n"); + void runInt10(void); + M.x86.R_AX = 0x5f64; + M.x86.R_BX = 0x0001; // Set Display Device, force execution + M.x86.R_CX = PIPE_A_CRT | PIPE_A_TV; + // M.x86.R_CX = PIPE_B_TV; + runInt10(); + switch (M.x86.R_AX) { + case 0x005f: + printk_debug("... failed.\n"); + break; + case 0x015f: + printk_debug("... ok.\n"); + break; + default: + printk_debug("... not supported.\n"); + break; + } +#endif } static const struct device_operations vga_operations = { |