coreboot-kgpe-d16/util/x86emu/yabel/io.c
Uwe Hermann 01ce601bdb This patch is from 2009-10-20
Convert all DEBUG_SMBUS, DEBUG_SMI, and DEBUG_RAM_SETUP custom and
local #defines into globally configurable kconfig options (and Options.lb
options for as long as newconfig still exists) which can be enabled
by the user in the "Debugging" menu.

The respective menu items only appear if a board is selected where the
chipset code actually provides such additional DEBUG output.

All three variables default to 0 / off for now.

Also, drop a small chunk of dead/useless code in the
src/northbridge/via/cn700/raminit.c file, which would otherwise break
compilation.

Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>

Reworked to still apply to trunk, added X86EMU_DEBUG (and make the x86emu/yabel
code only work printf instead of a redefined version of printk and 
Acked-by: Stefan Reinauer <stepan@coresystems.de>




git-svn-id: svn://svn.coreboot.org/coreboot/trunk@5185 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
2010-03-05 10:03:50 +00:00

535 lines
14 KiB
C

/******************************************************************************
* Copyright (c) 2004, 2008 IBM Corporation
* Copyright (c) 2009 Pattrick Hueper <phueper@hueper.net>
* All rights reserved.
* This program and the accompanying materials
* are made available under the terms of the BSD License
* which accompanies this distribution, and is available at
* http://www.opensource.org/licenses/bsd-license.php
*
* Contributors:
* IBM Corporation - initial implementation
*****************************************************************************/
#include <types.h>
#include "compat/rtas.h"
#include "compat/time.h"
#include "device.h"
#include "debug.h"
#include <x86emu/x86emu.h>
#include "io.h"
#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
#include <device/pci.h>
#include <device/pci_ops.h>
#endif
// those are defined in net-snk/oflib/pci.c
extern unsigned int read_io(void *, size_t);
extern int write_io(void *, unsigned int, size_t);
//defined in net-snk/kernel/timer.c
extern u64 get_time(void);
#ifdef CONFIG_ARCH_X86
#include <arch/io.h>
#else
// these are not used, only needed for linking, must be overridden using X86emu_setupPioFuncs
// with the functions and struct below
void
outb(u8 val, u16 port)
{
printf("WARNING: outb not implemented!\n");
HALT_SYS();
}
void
outw(u16 val, u16 port)
{
printf("WARNING: outw not implemented!\n");
HALT_SYS();
}
void
outl(u32 val, u16 port)
{
printf("WARNING: outl not implemented!\n");
HALT_SYS();
}
u8
inb(u16 port)
{
printf("WARNING: inb not implemented!\n");
HALT_SYS();
return 0;
}
u16
inw(u16 port)
{
printf("WARNING: inw not implemented!\n");
HALT_SYS();
return 0;
}
u32
inl(u16 port)
{
printf("WARNING: inl not implemented!\n");
HALT_SYS();
return 0;
}
#endif
#if defined(CONFIG_YABEL_DIRECTHW) && (CONFIG_YABEL_DIRECTHW == 1)
u8 my_inb(X86EMU_pioAddr addr)
{
u8 val;
val = inb(addr);
DEBUG_PRINTF_IO("inb(0x%04x) = 0x%02x\n", addr, val);
return val;
}
u16 my_inw(X86EMU_pioAddr addr)
{
u16 val;
val = inw(addr);
DEBUG_PRINTF_IO("inw(0x%04x) = 0x%04x\n", addr, val);
return val;
}
u32 my_inl(X86EMU_pioAddr addr)
{
u32 val;
val = inl(addr);
DEBUG_PRINTF_IO("inl(0x%04x) = 0x%08x\n", addr, val);
return val;
}
void my_outb(X86EMU_pioAddr addr, u8 val)
{
DEBUG_PRINTF_IO("outb(0x%02x, 0x%04x)\n", val, addr);
outb(val, addr);
}
void my_outw(X86EMU_pioAddr addr, u16 val)
{
DEBUG_PRINTF_IO("outw(0x%04x, 0x%04x)\n", val, addr);
outw(val, addr);
}
void my_outl(X86EMU_pioAddr addr, u32 val)
{
DEBUG_PRINTF_IO("outl(0x%08x, 0x%04x)\n", val, addr);
outl(val, addr);
}
#else
u32 pci_cfg_read(X86EMU_pioAddr addr, u8 size);
void pci_cfg_write(X86EMU_pioAddr addr, u32 val, u8 size);
u8 handle_port_61h(void);
u8
my_inb(X86EMU_pioAddr addr)
{
u8 rval = 0xFF;
unsigned long translated_addr = addr;
u8 translated = biosemu_dev_translate_address(&translated_addr);
if (translated != 0) {
//translation successfull, access Device I/O (BAR or Legacy...)
DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __func__,
addr);
//DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
rval = read_io((void *)translated_addr, 1);
DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %02x\n", __func__,
addr, rval);
return rval;
} else {
switch (addr) {
case 0x61:
//8254 KB Controller / Timer Port
// rval = handle_port_61h();
rval = inb(0x61);
//DEBUG_PRINTF_IO("%s(%04x) KB / Timer Port B --> %02x\n", __func__, addr, rval);
return rval;
break;
case 0xCFC:
case 0xCFD:
case 0xCFE:
case 0xCFF:
// PCI Config Mechanism 1 Ports
return (u8) pci_cfg_read(addr, 1);
break;
case 0x0a:
CHECK_DBG(DEBUG_INTR) {
X86EMU_trace_on();
}
M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
//HALT_SYS();
// no break, intentional fall-through to default!!
default:
DEBUG_PRINTF_IO
("%s(%04x) reading from bios_device.io_buffer\n",
__func__, addr);
rval = *((u8 *) (bios_device.io_buffer + addr));
DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %02x\n",
__func__, addr, rval);
return rval;
break;
}
}
}
u16
my_inw(X86EMU_pioAddr addr)
{
unsigned long translated_addr = addr;
u8 translated = biosemu_dev_translate_address(&translated_addr);
if (translated != 0) {
//translation successfull, access Device I/O (BAR or Legacy...)
DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __func__,
addr);
//DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
u16 rval;
if ((translated_addr & (u64) 0x1) == 0) {
// 16 bit aligned access...
u16 tempval = read_io((void *)translated_addr, 2);
//little endian conversion
rval = in16le((void *) &tempval);
} else {
// unaligned access, read single bytes, little-endian
rval = (read_io((void *)translated_addr, 1) << 8)
| (read_io((void *)(translated_addr + 1), 1));
}
DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %04x\n", __func__,
addr, rval);
return rval;
} else {
switch (addr) {
case 0xCFC:
case 0xCFE:
//PCI Config Mechanism 1
return (u16) pci_cfg_read(addr, 2);
break;
default:
DEBUG_PRINTF_IO
("%s(%04x) reading from bios_device.io_buffer\n",
__func__, addr);
u16 rval =
in16le((void *) bios_device.io_buffer + addr);
DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %04x\n",
__func__, addr, rval);
return rval;
break;
}
}
}
u32
my_inl(X86EMU_pioAddr addr)
{
unsigned long translated_addr = addr;
u8 translated = biosemu_dev_translate_address(&translated_addr);
if (translated != 0) {
//translation successfull, access Device I/O (BAR or Legacy...)
DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __func__,
addr);
//DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
u32 rval;
if ((translated_addr & (u64) 0x3) == 0) {
// 32 bit aligned access...
u32 tempval = read_io((void *) translated_addr, 4);
//little endian conversion
rval = in32le((void *) &tempval);
} else {
// unaligned access, read single bytes, little-endian
rval = (read_io((void *)(translated_addr), 1) << 24)
| (read_io((void *)(translated_addr + 1), 1) << 16)
| (read_io((void *)(translated_addr + 2), 1) << 8)
| (read_io((void *)(translated_addr + 3), 1));
}
DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %08x\n", __func__,
addr, rval);
return rval;
} else {
switch (addr) {
case 0xCFC:
//PCI Config Mechanism 1
return pci_cfg_read(addr, 4);
break;
default:
DEBUG_PRINTF_IO
("%s(%04x) reading from bios_device.io_buffer\n",
__func__, addr);
u32 rval =
in32le((void *) bios_device.io_buffer + addr);
DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %08x\n",
__func__, addr, rval);
return rval;
break;
}
}
}
void
my_outb(X86EMU_pioAddr addr, u8 val)
{
unsigned long translated_addr = addr;
u8 translated = biosemu_dev_translate_address(&translated_addr);
if (translated != 0) {
//translation successfull, access Device I/O (BAR or Legacy...)
DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
__func__, addr, val);
//DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
write_io((void *) translated_addr, val, 1);
DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %02x\n", __func__,
addr, val);
} else {
switch (addr) {
case 0xCFC:
case 0xCFD:
case 0xCFE:
case 0xCFF:
// PCI Config Mechanism 1 Ports
pci_cfg_write(addr, val, 1);
break;
default:
DEBUG_PRINTF_IO
("%s(%04x,%02x) writing to bios_device.io_buffer\n",
__func__, addr, val);
*((u8 *) (bios_device.io_buffer + addr)) = val;
break;
}
}
}
void
my_outw(X86EMU_pioAddr addr, u16 val)
{
unsigned long translated_addr = addr;
u8 translated = biosemu_dev_translate_address(&translated_addr);
if (translated != 0) {
//translation successfull, access Device I/O (BAR or Legacy...)
DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
__func__, addr, val);
//DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
if ((translated_addr & (u64) 0x1) == 0) {
// little-endian conversion
u16 tempval = in16le((void *) &val);
// 16 bit aligned access...
write_io((void *) translated_addr, tempval, 2);
} else {
// unaligned access, write single bytes, little-endian
write_io(((void *) (translated_addr + 1)),
(u8) ((val & 0xFF00) >> 8), 1);
write_io(((void *) translated_addr),
(u8) (val & 0x00FF), 1);
}
DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %04x\n", __func__,
addr, val);
} else {
switch (addr) {
case 0xCFC:
case 0xCFE:
// PCI Config Mechanism 1 Ports
pci_cfg_write(addr, val, 2);
break;
default:
DEBUG_PRINTF_IO
("%s(%04x,%04x) writing to bios_device.io_buffer\n",
__func__, addr, val);
out16le((void *) bios_device.io_buffer + addr, val);
break;
}
}
}
void
my_outl(X86EMU_pioAddr addr, u32 val)
{
unsigned long translated_addr = addr;
u8 translated = biosemu_dev_translate_address(&translated_addr);
if (translated != 0) {
//translation successfull, access Device I/O (BAR or Legacy...)
DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
__func__, addr, val);
//DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
if ((translated_addr & (u64) 0x3) == 0) {
// little-endian conversion
u32 tempval = in32le((void *) &val);
// 32 bit aligned access...
write_io((void *) translated_addr, tempval, 4);
} else {
// unaligned access, write single bytes, little-endian
write_io(((void *) translated_addr + 3),
(u8) ((val & 0xFF000000) >> 24), 1);
write_io(((void *) translated_addr + 2),
(u8) ((val & 0x00FF0000) >> 16), 1);
write_io(((void *) translated_addr + 1),
(u8) ((val & 0x0000FF00) >> 8), 1);
write_io(((void *) translated_addr),
(u8) (val & 0x000000FF), 1);
}
DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %08x\n", __func__,
addr, val);
} else {
switch (addr) {
case 0xCFC:
// PCI Config Mechanism 1 Ports
pci_cfg_write(addr, val, 4);
break;
default:
DEBUG_PRINTF_IO
("%s(%04x,%08x) writing to bios_device.io_buffer\n",
__func__, addr, val);
out32le((void *) bios_device.io_buffer + addr, val);
break;
}
}
}
u32
pci_cfg_read(X86EMU_pioAddr addr, u8 size)
{
u32 rval = 0xFFFFFFFF;
struct device * dev;
if ((addr >= 0xCFC) && ((addr + size) <= 0xD00)) {
// PCI Configuration Mechanism 1 step 1
// write to 0xCF8, sets bus, device, function and Config Space offset
// later read from 0xCFC-0xCFF returns the value...
u8 bus, devfn, offs;
u32 port_cf8_val = my_inl(0xCF8);
if ((port_cf8_val & 0x80000000) != 0) {
//highest bit enables config space mapping
bus = (port_cf8_val & 0x00FF0000) >> 16;
devfn = (port_cf8_val & 0x0000FF00) >> 8;
offs = (port_cf8_val & 0x000000FF);
offs += (addr - 0xCFC); // if addr is not 0xcfc, the offset is moved accordingly
DEBUG_PRINTF_INTR("%s(): PCI Config Read from device: bus: %02x, devfn: %02x, offset: %02x\n",
__func__, bus, devfn, offs);
#if defined(CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES) && CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES==1
dev = dev_find_slot(bus, devfn);
DEBUG_PRINTF_INTR("%s(): dev_find_slot() returned: %s\n",
__func__, dev_path(dev));
if (dev == 0) {
// fail accesses to non-existent devices...
#else
dev = bios_device.dev;
if ((bus != bios_device.bus)
|| (devfn != bios_device.devfn)) {
// fail accesses to any device but ours...
#endif
printf
("%s(): Config read access invalid device! bus: %02x (%02x), devfn: %02x (%02x), offs: %02x\n",
__func__, bus, bios_device.bus, devfn,
bios_device.devfn, offs);
SET_FLAG(F_CF);
HALT_SYS();
return 0;
} else {
#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
switch (size) {
case 1:
rval = pci_read_config8(dev, offs);
break;
case 2:
rval = pci_read_config16(dev, offs);
break;
case 4:
rval = pci_read_config32(dev, offs);
break;
}
#else
rval =
(u32) rtas_pci_config_read(bios_device.
puid, size,
bus, devfn,
offs);
#endif
DEBUG_PRINTF_IO
("%s(%04x) PCI Config Read @%02x, size: %d --> 0x%08x\n",
__func__, addr, offs, size, rval);
}
}
}
return rval;
}
void
pci_cfg_write(X86EMU_pioAddr addr, u32 val, u8 size)
{
if ((addr >= 0xCFC) && ((addr + size) <= 0xD00)) {
// PCI Configuration Mechanism 1 step 1
// write to 0xCF8, sets bus, device, function and Config Space offset
// later write to 0xCFC-0xCFF sets the value...
u8 bus, devfn, offs;
u32 port_cf8_val = my_inl(0xCF8);
if ((port_cf8_val & 0x80000000) != 0) {
//highest bit enables config space mapping
bus = (port_cf8_val & 0x00FF0000) >> 16;
devfn = (port_cf8_val & 0x0000FF00) >> 8;
offs = (port_cf8_val & 0x000000FF);
offs += (addr - 0xCFC); // if addr is not 0xcfc, the offset is moved accordingly
if ((bus != bios_device.bus)
|| (devfn != bios_device.devfn)) {
// fail accesses to any device but ours...
printf
("Config write access invalid! PCI device %x:%x.%x, offs: %x\n",
bus, devfn >> 3, devfn & 7, offs);
HALT_SYS();
} else {
#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
switch (size) {
case 1:
pci_write_config8(bios_device.dev, offs, val);
break;
case 2:
pci_write_config16(bios_device.dev, offs, val);
break;
case 4:
pci_write_config32(bios_device.dev, offs, val);
break;
}
#else
rtas_pci_config_write(bios_device.puid,
size, bus, devfn, offs,
val);
#endif
DEBUG_PRINTF_IO
("%s(%04x) PCI Config Write @%02x, size: %d <-- 0x%08x\n",
__func__, addr, offs, size, val);
}
}
}
}
u8
handle_port_61h(void)
{
static u64 last_time = 0;
u64 curr_time = get_time();
u64 time_diff; // time since last call
u32 period_ticks; // length of a period in ticks
u32 nr_periods; //number of periods passed since last call
// bit 4 should toggle with every (DRAM) refresh cycle... (66kHz??)
time_diff = curr_time - last_time;
// at 66kHz a period is ~ 15 ns long, converted to ticks: (tb_freq is ticks/second)
// TODO: as long as the frequency does not change, we should not calculate this every time
period_ticks = (15 * tb_freq) / 1000000;
nr_periods = time_diff / period_ticks;
// if the number if ticks passed since last call is odd, we toggle bit 4
if ((nr_periods % 2) != 0) {
*((u8 *) (bios_device.io_buffer + 0x61)) ^= 0x10;
}
//finally read the value from the io_buffer
return *((u8 *) (bios_device.io_buffer + 0x61));
}
#endif