Kyösti Mälkki (kyosti.malkki@gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/1647
-gerrit
commit eb43380a5a24737214e43f9200630ef96fdbcc79 Author: Kyösti Mälkki kyosti.malkki@gmail.com Date: Sun Oct 28 11:32:48 2012 +0200
Add superio filtering
Decoder is able to pretty-print the config cycles to port 0x2e/0x4e and activate new IO regions. One should provide a map of LDN functions with the size of each IO region as part of the mainboard script.
Change-Id: I976f43818b43a30db97b4e679de04e399f691b97 Signed-off-by: Kyösti Mälkki kyosti.malkki@gmail.com --- SerialICE/simba/serialice.lua | 11 ++ SerialICE/simba/superio.lua | 259 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 270 insertions(+)
diff --git a/SerialICE/simba/serialice.lua b/SerialICE/simba/serialice.lua index 4b63e25..3700589 100644 --- a/SerialICE/simba/serialice.lua +++ b/SerialICE/simba/serialice.lua @@ -34,6 +34,7 @@ hide_i8042_io = false hide_i8237_io = true hide_i8254_io = true hide_i8259_io = true +hide_superio_cfg = true
-- Set to "true" to log every memory and IO access log_everything = false @@ -43,6 +44,9 @@ log_everything = false -- RTC registers 0x0-0xd go to HW cache_nvram = false
+-- SMSC 0x07, Winbond 0x06 ? +DEFAULT_SUPERIO_LDN_REGISTER = 0x07 + rom_size = 4 * 1024 * 1024 rom_base = 0x100000000 - rom_size
@@ -59,6 +63,7 @@ dofile("memory.lua") dofile("cpu.lua") dofile("pci_cfg.lua") dofile("pc80.lua") +dofile("superio.lua")
function do_minimal_setup() enable_hook(io_hooks, filter_io_fallback) @@ -73,6 +78,12 @@ function do_default_setup() enable_ram() enable_hook(io_hooks, filter_pci_io_cfg) enable_hook_pc80() + enable_hook_superio(0x2e, DEFAULT_SUPERIO_LDN_REGISTER) + enable_hook_superio(0x4e, DEFAULT_SUPERIO_LDN_REGISTER) + enable_hook(io_hooks, filter_com1) + if superio_initialization then + superio_initialization() + end end
do_minimal_setup() diff --git a/SerialICE/simba/superio.lua b/SerialICE/simba/superio.lua new file mode 100644 index 0000000..1248af5 --- /dev/null +++ b/SerialICE/simba/superio.lua @@ -0,0 +1,259 @@ + + +function pnp_switch_ldn(f, data) + if not f.ldn[data] then + f.ldn[data] = { data = {}, set = {}, bar0 = {}, bar1 = {} } + end + f.pnp.active_ldn = data +end + +function pnp_select_cfg(f, data) + f.pnp.reg = data +end + +function pnp_store_cfg(f, data) + local reg = f.pnp.reg + if reg < 0x30 then + f.chip.data[reg] = data; + f.chip.set[reg] = true; + else + local ldn = f.pnp.active_ldn + f.ldn[ldn].data[reg] = data; + f.ldn[ldn].set[reg] = true; + end +end + + +-- ********************************************************** +-- +-- SuperIO device handling + +function superio_pnpdev(f) + return string.format("%s %02x:%02x", f.name, f.base, f.pnp.active_ldn) +end + +function superio_dev_post(f, action) + if f.pnp.reg < 0x30 then + printk(f, action, "%02x: ", f.base) + else + printk(f, action, "%02x:%02x ", f.base, f.pnp.active_ldn) + end +end + +function superio_register_post(f, action) + superio_dev_post(f, action) + if action.write then + printf("[%02x] <= %02x\n", f.pnp.reg, action.data) + else + printf("[%02x] => %02x\n", f.pnp.reg, action.data) + end +end + +function superio_try_enable_io(f, idx) + + local ldn = f.ldn[f.pnp.active_ldn] + + if ldn.set[0x30] and ldn.data[0x30] ~= 0x0 then + if idx == 0 and ldn.set[0x60] and ldn.set[0x61] then + local iobase = bit32.bor(bit32.lshift(ldn.data[0x60], 8), ldn.data[0x61]) + if not ldn.bar0.size then + ldn.bar0.size = 1 + end + if not ldn.bar0.name then + ldn.bar0.name = superio_pnpdev(f) + end + ldn.bar0.val = iobase + generic_io_bar(ldn.bar0) + end + if idx == 1 and ldn.set[0x62] and ldn.set[0x63] then + local iobase = bit32.bor(bit32.lshift(ldn.data[0x62], 8), ldn.data[0x63]) + if not ldn.bar1.size then + ldn.bar1.size = 1 + end + if not ldn.bar1.name then + ldn.bar1.name = superio_pnpdev(f) + end + ldn.bar1.val = iobase + generic_io_bar(ldn.bar1) + end + end +end + +function superio_try_enable_ldn(f, action) + local ldn = f.ldn[f.pnp.active_ldn] + + if ldn.set[0x30] and ldn.data[0x30] == 0x0 then + superio_dev_post(f, action) + printf("disabled\n") + else + superio_dev_post(f, action) + printf("enabled\n") + end +end + +function superio_pre(f, action) + if not action.write then + return handle_action(f, action) + end + + if action.addr == f.base then + pnp_select_cfg(f, action.data) + return handle_action(f, action) + end + + if action.addr == f.base + 0x01 then + -- Also creates new LDN instance, if necessary. + if f.pnp.reg == f.pnp.ldn_register then + pnp_switch_ldn(f, action.data) + end + + pnp_store_cfg(f, action.data) + + -- Don't allow that our SIO power gets disabled. + if f.pnp.reg == 0x02 then + return drop_action(f, action, 0) + end + + -- Don't mess with oscillator setup. + if f.pnp.reg == 0x24 then + return drop_action(f, action, 0) + end + return handle_action(f, action) + end + + -- should not reach here + return skip_filter(f, action) +end + +function superio_post(f, action) + + -- Do not log change of register or LDN. + if action.addr == f.base or f.pnp.reg == f.pnp.ldn_register then + return true + end + + if not action.write then + superio_register_post(f, action) + return true + end + + local ldn = f.ldn[f.pnp.active_ldn] + + -- Log base address once both bytes are set. + + if ( f.pnp.reg == 0x60 or f.pnp.reg == 0x61 ) then + superio_try_enable_io(f, 0) + return true + end + + if ( f.pnp.reg == 0x62 or f.pnp.reg == 0x63 ) then + superio_try_enable_io(f, 1) + return true + end + + if f.pnp.reg == 0x30 then + superio_try_enable_io(f, 0) + superio_try_enable_io(f, 1) + superio_try_enable_ldn(f, action) + return true + end + + if f.pnp.reg == 0x70 then + superio_dev_post(f, action) + printf("irq = %d\n", ldn.data[0x70]) + return true + end + if f.pnp.reg == 0x72 then + superio_dev_post(f, action) + printf("irq2 = %d\n", ldn.data[0x72]) + return true + end + + superio_register_post(f, action) + return true +end + + +filter_superio_2e = { + id = -1, + name = "PnP", + pre = superio_pre, + post = superio_post, + base = 0x2e, + size = 0x02, + hide = hide_superio_cfg, + chip = { data = {}, set = {} }, + pnp = { reg = 0, active_ldn = -1, ldn_register = 0 }, + ldn = {}, +} +filter_superio_4e = { + id = -1, + name = "PnP", + pre = superio_pre, + post = superio_post, + base = 0x4e, + size = 0x02, + hide = hide_superio_cfg, + chip = { data = {}, set = {} }, + pnp = { reg = 0, active_ldn = -1, ldn_register = 0 }, + ldn = {}, +} + + +function superio_get_filter(cfg_base) + if cfg_base == 0x2e then + return filter_superio_2e + elseif cfg_base == 0x4e then + return filter_superio_4e + else + return nil + end +end + +function superio_set_ldn_register(f, ldn_register) + f.pnp.ldn_register = ldn_register +end + +function superio_new_ldn(f, idx) + if not f.ldn[idx] then + f.ldn[idx] = { data = {}, set = {}, bar0 = {}, bar1 = {} } + end +end + +function superio_ldn_iobase0(f, idx, name, size) + f.ldn[idx].bar0.name = name + f.ldn[idx].bar0.size = size +end + +function superio_ldn_iobase1(f, idx, name, size) + f.ldn[idx].bar1.name = name + f.ldn[idx].bar1.size = size +end + +function enable_hook_superio(base, ldn_register) + local sio = superio_get_filter(base) + superio_set_ldn_register(sio, ldn_register) + enable_hook(io_hooks, sio) +end + +-- ********************************************************** +-- +-- Serial Port handling + +function com_pre(f, action) + if (action.write) then + return drop_action(f, action, action.data) + else + return drop_action(f, action, 0xff) + end +end + +filter_com1 = { + id = -1, + name = "COM1", + pre = com_pre, + post = io_post, + base = 0x3f8, + size = 8, + hide = false, +}