aboutsummaryrefslogtreecommitdiff
path: root/src/northbridge/intel/i82830
diff options
context:
space:
mode:
Diffstat (limited to 'src/northbridge/intel/i82830')
-rw-r--r--src/northbridge/intel/i82830/Makefile.inc2
-rw-r--r--src/northbridge/intel/i82830/i82830_smihandler.c374
-rw-r--r--src/northbridge/intel/i82830/northbridge.c2
-rw-r--r--src/northbridge/intel/i82830/raminit.c1
-rw-r--r--src/northbridge/intel/i82830/vga.c60
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 = {