[SerialICE] New patch to review for serialice: 05f5923 Add SMBus decoder
Kyösti Mälkki (kyosti.malkki@gmail.com)
gerrit at coreboot.org
Sun Oct 28 21:09:08 CET 2012
Kyösti Mälkki (kyosti.malkki at gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/1649
-gerrit
commit 05f592394eff03e6ec0ca51c9fd0ce39334cd2eb
Author: Kyösti Mälkki <kyosti.malkki at gmail.com>
Date: Sun Oct 28 12:19:03 2012 +0200
Add SMBus decoder
Decodes a series of IO accesses to the SMBus controller device
as a series of bytes transmitted on the SMBus.
Tested mostly on Intel ICH4, some VIA seemed to be compatible too.
Change-Id: Id5248f4d9a2d550e8fd06d4252a67a404f719b77
Signed-off-by: Kyösti Mälkki <kyosti.malkki at gmail.com>
---
SerialICE/simba/intel_smbus.lua | 259 +++++++++++++++++++
SerialICE/simba/serialice.lua | 1 +
SerialICE/simba/smbus_host.lua | 559 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 819 insertions(+)
diff --git a/SerialICE/simba/intel_smbus.lua b/SerialICE/simba/intel_smbus.lua
new file mode 100644
index 0000000..daa0b9d
--- /dev/null
+++ b/SerialICE/simba/intel_smbus.lua
@@ -0,0 +1,259 @@
+
+
+dofile("smbus_host.lua")
+
+-- ********************************************
+-- Intel 82801 SMBus Host controller
+
+I801_SMB_HSTSTS = 0
+I801_SMB_HSTCNT = 2
+I801_SMB_HSTCMD = 3
+I801_SMB_HSTADD = 4
+I801_SMB_HSTDAT0 = 5
+I801_SMB_HSTDAT1 = 6
+I801_SMB_BLKDAT = 7
+I801_SMB_PEC = 8
+I801_SMB_AUXSTS = 12
+I801_SMB_AUXCTL = 13
+
+I801_QUICK = 0x00
+I801_BYTE = 0x04
+I801_BYTE_DATA = 0x08
+I801_WORD_DATA = 0x0C
+I801_PROC_CALL = 0x10
+I801_BLOCK_DATA = 0x14
+I801_I2C_BLOCK_DATA = 0x18
+I801_BLOCK_PROCESS = 0x1C
+I801_BLOCK_LAST = 0x34 -- 0x14 | 0x20
+I801_I2C_BLOCK_LAST = 0x38 -- 0x18 | 0x20
+I801_START = 0x40
+I801_PEC_EN = 0x80
+
+
+local function intel_smbus_get_protocol(f)
+ local proto = bit32.band(f.reg.control, 0x1c)
+
+ if proto == I801_QUICK then
+ return SMBUS_QUICK
+
+ elseif proto == I801_BYTE then
+ return SMBUS_BYTE
+
+ elseif proto == I801_BYTE_DATA then
+ return SMBUS_BYTE_DATA
+
+ elseif proto == I801_WORD_DATA then
+ return SMBUS_WORD_DATA
+
+ elseif proto == I801_PROC_CALL then
+ return SMBUS_PROC_CALL
+
+ elseif proto == I801_BLOCK_DATA then
+ return SMBUS_BLOCK_DATA
+
+ elseif proto == I801_I2C_BLOCK_DATA then
+ return SMBUS_I2C_BLOCK_DATA
+
+ elseif proto == I801_BLOCK_PROCESS then
+ return SMBUS_BLOCK_PROCESS
+
+ else
+ printk(f, action, "Unknown protocol\n")
+ return SMBUS_NOOP
+ end
+end
+
+local function intel_smbus_host_status(f, action)
+ if not action.write then
+ if smbus.passive(f) then
+ f.reg.status = action.data;
+ end
+
+ if smbus.state(f, HOST_IDLE) then
+ if not smbus.passive(f) then
+ f.reg.status = 0x0
+ end
+ if bit32.band(f.reg.status, 0x40) ~= 0 then
+ printk(f, action, "Host may be busy, ignoring.\n")
+ end
+ smbus.get_resource(f)
+
+ elseif smbus.state(f, HOST_ACTIVE) then
+ f.reg.busy_count = 3
+
+ elseif smbus.state(f, HOST_STARTED) then
+ if not smbus.passive(f) then
+ f.reg.status = bit32.band(f.reg.status, 0xFE)
+ if f.reg.busy_count > 0 then
+ f.reg.busy_count = f.reg.busy_count - 1
+ f.reg.status = bit32.bor(f.reg.status, 0x01)
+ end
+ if bit32.band(f.reg.status, 0x02) == 0 then
+ smbus_transaction(host)
+ end
+ end
+
+ local irq = bit32.band(f.reg.status, 0x02) ~= 0
+ local failures = bit32.band(f.reg.status, 0x1c) ~= 0
+ local host_busy = bit32.band(f.reg.status, 0x01) ~= 0
+
+ if irq and not host_busy then
+ smbus.done(f)
+ end
+ if failures then
+ smbus.timeout(f)
+ end
+ end
+
+ if not smbus.passive(f) then
+ action.data = f.reg.status;
+ f.reg.status = bit32.bor(f.reg.status, 0x40)
+ end
+ else
+
+ if not smbus.passive(f) then
+ f.reg.status = bit32.band(f.reg.status, bit32.bnot(action.data))
+ end
+
+ local ack_irq = bit32.band(action.data, 0x02) ~= 0
+ local release_host = bit32.band(action.data, 0x40) ~= 0
+ local failures = bit32.band(action.data, 0x1c) ~= 0
+ if release_host then
+ smbus.put_resource(f)
+ end
+ if failures then
+ smbus.timeout_ack(f)
+ end
+ if ack_irq then
+ smbus.ack(f)
+ end
+ end
+
+end
+
+
+local function intel_smbus_host_control(f, action)
+
+ if not action.write then
+ f.reg.block_ptr=0;
+ if not smbus.passive(f) then
+ action.data = bit32.band(f.reg.control, bit32.bnot(0x40))
+ end
+
+ else
+
+ f.reg.control = action.data;
+ if bit32.band(f.reg.control, 0x80) ~= 0 then
+ printk(f, action, "No PEC simulation\n")
+ end
+
+ local abort = bit32.band(f.reg.control, 0x02) ~= 0
+ local start = bit32.band(f.reg.control, 0x40) ~= 0
+ if abort then
+ smbus.abort(f)
+ end
+ if start then
+ f.reg.block_ptr=0;
+ smbus.update_register(f, action, SMB_REG_PROTO)
+ smbus.start(f, intel_smbus_get_protocol(f))
+ end
+ end
+end
+
+
+
+local function intel_smbus_block_data(f, action)
+ if f.reg.block_ptr < MAX_BLOCK_SRAM then
+ smbus.block_data(f, action, f.reg.block_ptr)
+ end
+ f.reg.block_ptr = f.reg.block_ptr + 1
+ smbus.update_register(f, action, SMB_REG_BLOCK)
+end
+
+local function intel_smbus_host_access(f, action)
+ local reg = bit32.band(action.addr, (f.size-1))
+
+ -- mirror hw register both ways
+ local data_write = 0
+
+ -- Store this to display CS:IP etc.
+ f.host.action = action
+
+ if reg == I801_SMB_HSTSTS then
+ intel_smbus_host_status(f, action);
+
+ elseif reg == I801_SMB_HSTCNT then
+ intel_smbus_host_control(f, action);
+
+ elseif reg == I801_SMB_HSTCMD then
+ smbus.update_register(f, action, SMB_REG_CMD)
+
+ elseif reg == I801_SMB_HSTADD then
+ smbus.update_register(f, action, SMB_REG_SLAVE)
+
+ elseif reg == I801_SMB_HSTDAT0 then
+ smbus.update_register(f, action, SMB_REG_DATA0)
+
+ elseif reg == I801_SMB_HSTDAT1 then
+ smbus.update_register(f, action, SMB_REG_DATA1)
+
+ elseif reg == I801_SMB_BLKDAT then
+ intel_smbus_block_data(f, action);
+
+ elseif reg == I801_SMB_AUXSTS then
+ if data_write then
+ f.reg.aux_sts = action.data;
+ else
+ action.data = f.reg.aux_sts;
+ end
+
+ elseif reg == I801_SMB_AUXCTL then
+ if data_write then
+ f.reg.aux_ctl = action.data;
+ else
+ action.data = f.reg.aux_ctl;
+ end
+
+ else
+ printk(f, action, "Unknown register 0x%02x\n", reg);
+ end
+end
+
+
+function intel_smbus_host_pre(f, action)
+ if action.write then
+ intel_smbus_host_access(f, action)
+ end
+ return handle_action(f, action)
+end
+
+function intel_smbus_host_post(f, action)
+ if not action.write then
+ intel_smbus_host_access(f, action)
+ end
+ return true
+end
+
+
+local intel_smbus_host = {
+ id = -1,
+ name = "i801-smbus",
+ pre = intel_smbus_host_pre,
+ post = intel_smbus_host_post,
+ hide = hide_smbus_io,
+ base = 0x0,
+ size = 0x0,
+}
+
+function intel_smbus_setup(base, size)
+ local f = intel_smbus_host
+ f.base = bit32.band(base, bit32.bnot(size-1))
+ f.size = size
+ if not f.reg then
+ f.reg = { control = 0, status = 0, busy_count = 0, block_ptr = 0, aux_ctl = 0, aux_sts = 0 }
+ end
+ smbus.init(f)
+
+ enable_hook(io_hooks, f)
+end
+
diff --git a/SerialICE/simba/serialice.lua b/SerialICE/simba/serialice.lua
index 08625d6..9d2f672 100644
--- a/SerialICE/simba/serialice.lua
+++ b/SerialICE/simba/serialice.lua
@@ -35,6 +35,7 @@ hide_i8237_io = true
hide_i8254_io = true
hide_i8259_io = true
hide_superio_cfg = true
+hide_smbus_io = true
-- Set to "true" to log every memory and IO access
log_everything = false
diff --git a/SerialICE/simba/smbus_host.lua b/SerialICE/simba/smbus_host.lua
new file mode 100644
index 0000000..a407843
--- /dev/null
+++ b/SerialICE/simba/smbus_host.lua
@@ -0,0 +1,559 @@
+
+
+local debug_smbus = false
+smbus = {}
+
+smbus.host = {
+ state = { current = 0, jump_to = 0 },
+ proto = 0,
+ start_proto = 0,
+
+ passive = true,
+ signals = 0,
+
+ slave = 0,
+ cmd = 0,
+ data0 = 0,
+ data1 = 0,
+ data0_valid = false,
+ data1_valid = false,
+ wr_data0 = 0,
+ wr_data1 = 0,
+ block_register = 0,
+
+ block = {},
+ max_index = 0,
+}
+
+MAX_BLOCK_SRAM = 32
+
+if true then
+ for i = 0, MAX_BLOCK_SRAM-1, 1 do
+ smbus.host.block[i] = { hw = 0, tmp = 0, hw_valid = false, tmp_valid = false }
+ end
+end
+
+-- *******************
+
+SIG_INUSE = 0
+SIG_RELEASE = 1
+SIG_START = 2
+SIG_ABORT = 3
+SIG_DONE = 4
+SIG_ACK = 5
+SIG_TIMEOUT = 6
+SIG_TIMEOUT_ACK = 7
+SIG_DATA_WRITE = 8
+
+local function signal_reset(f)
+ f.host.signals = 0
+end
+
+local function signal_set(f, flag)
+ local mask = bit32.lshift(1, flag)
+ f.host.signals = bit32.bor(f.host.signals, mask)
+end
+
+local function signal_clr(f, flag)
+ local mask = bit32.bnot(bit32.lshift(1, flag))
+ f.host.signals = bit32.band(f.host.signals, mask)
+
+end
+
+local function signal_in(f, flag)
+ local mask = bit32.lshift(1, flag)
+ return bit32.band(f.host.signals, mask) ~= 0
+end
+
+-- *******************
+
+-- SMBus Protocol Message Types
+SMBUS_NOOP = 0
+SMBUS_QUICK = 1
+SMBUS_BYTE = 2
+SMBUS_BYTE_DATA = 3
+SMBUS_WORD_DATA = 4
+SMBUS_PROC_CALL = 5
+SMBUS_BLOCK_DATA = 6
+SMBUS_I2C_BLOCK_DATA = 7
+SMBUS_BLOCK_PROCESS = 8
+
+local proto_name = {}
+proto_name[SMBUS_NOOP] = "(no-op)"
+proto_name[SMBUS_QUICK] = "quick"
+proto_name[SMBUS_BYTE] = "byte"
+proto_name[SMBUS_BYTE_DATA] = "byte_data"
+proto_name[SMBUS_WORD_DATA] = "word_data"
+proto_name[SMBUS_PROC_CALL] = "proc_call"
+proto_name[SMBUS_BLOCK_DATA] = "block"
+proto_name[SMBUS_I2C_BLOCK_DATA] = "i2c_block"
+proto_name[SMBUS_BLOCK_PROCESS] = "block_process"
+
+-- SMBus Host
+SMB_REG_CMD = 1
+SMB_REG_SLAVE = 2
+SMB_REG_DATA0 = 3
+SMB_REG_DATA1 = 4
+SMB_REG_BLOCK = 5
+SMB_REG_PROTO = 6
+
+
+local function dump_block(f, length)
+ local block = ""
+ local max_length = math.min(length, MAX_BLOCK_SRAM)
+
+ for i=0, max_length-1, 1 do
+ if f.host.block[i].hw_valid then
+ block = block .. string.format(" %02x", f.host.block[i].hw)
+ else
+ block = block .. " xx"
+ end
+ end
+ return block
+end
+
+
+-- FIXME: Probably wrong for process calls and hw-dependent.
+local function host_proto(f, proto)
+ return f.host.proto == proto
+end
+
+local function host_reading(f)
+ return bit32.band(f.host.slave, 0x01) == 0x01
+end
+
+
+
+local function dump_transaction(f, action)
+
+ local data0, data1, length, dir
+ local invalid_data = "xx"
+ local iodir = {}
+ iodir[0] = "<="
+ iodir[1] = "=>"
+
+ if host_reading(f) then
+ dir = iodir[1]
+ data0 = invalid_data
+ length = f.host.max_index
+ if f.host.data0_valid then
+ length = f.host.data0
+ data0 = string.format("%02x", f.host.data0)
+ end
+ data1 = invalid_data
+ if f.host.data1_valid then
+ data1 = string.format("%02x", f.host.data1)
+ end
+ else
+ dir = iodir[0]
+ length = f.host.wr_data0
+ data0 = string.format("%02x", f.host.wr_data0)
+ data1 = string.format("%02x", f.host.wr_data1)
+ end
+
+
+ local dump = string.format("%02x %s ", f.host.slave / 2, proto_name[f.host.proto])
+
+ if host_proto(f, SMBUS_QUICK) then
+
+ elseif host_proto(f, SMBUS_BYTE) then
+ dump = dump .. string.format("%02x %s %s", f.host.cmd, dir, data0)
+
+ elseif host_proto(f, SMBUS_BYTE_DATA) then
+ dump = dump .. string.format("%02x %s %s", f.host.cmd, dir, data0)
+
+ elseif host_proto(f, SMBUS_WORD_DATA) then
+ dump = dump .. string.format("%02x %s %s%s", f.host.cmd, dir, data0, data1)
+
+ elseif host_proto(f, SMBUS_PROC_CALL) then
+ dump = dump .. string.format("%02x %02x %02x %s %s %s", f.host.cmd,
+ f.host.wr_data0, f.host.wr_data1, iodir[1], data0, data1)
+
+ elseif host_proto(f, SMBUS_BLOCK_DATA) then
+ dump = dump .. string.format("%02x len=%02d %s", f.host.cmd, length, dir)
+ dump = dump .. dump_block(f, length) .. ""
+
+ elseif host_proto(f, SMBUS_I2C_BLOCK_DATA) then
+ dump = dump .. string.format("%02x %02x %02x len=%02d %s",
+ f.host.cmd, f.host.data0, f.host.data1, f.host.max_index, dir)
+ dump = dump .. dump_block(f, length) .. ""
+
+ elseif host_proto(f, SMBUS_BLOCK_PROCESS) then
+ dump = dump .. string.format("%02x len=%02d %s", f.host.cmd, length, iodir[1])
+ dump = dump .. dump_block(f, length) .. ""
+ else
+ dump = dump .. "Cannot parse command"
+ end
+
+ if signal_in(f, SIG_TIMEOUT) then
+ action.undefined = true
+ dump = dump .. " (TIMEOUT) "
+ end
+
+ printk(f, action, "%s\n", dump)
+end
+
+
+-- *******************
+
+HOST_NOOP = 0
+HOST_IDLE = 1
+HOST_ACTIVE = 2
+HOST_STARTED = 3
+HOST_WAIT = 4
+HOST_COMPLETE = 5
+HOST_FAIL = 6
+
+local ctrl_state = {}
+ctrl_state[HOST_NOOP] = "noop"
+ctrl_state[HOST_IDLE] = "idle"
+ctrl_state[HOST_ACTIVE] = "active"
+ctrl_state[HOST_STARTED] = "started"
+ctrl_state[HOST_WAIT] = "wait"
+ctrl_state[HOST_COMPLETE] = "complete"
+ctrl_state[HOST_FAIL] = "failed"
+
+function dprintk(...)
+ if debug_smbus then
+ printk(...)
+ end
+end
+
+local function host_jump(f, state)
+ f.host.state.jump_to = state
+end
+
+local function host_change_state(f, prev_state, new_state)
+
+ if new_state == HOST_NOOP then
+ --printk(f, f.host.action, "state switch to HOST_NOOP\n")
+ new_state = HOST_IDLE
+ end
+
+ dprintk(f, f.host.action, "%s -> %s\n",
+ ctrl_state[prev_state], ctrl_state[new_state])
+
+ -- Jumping to current is no jump.
+ f.host.state.current = new_state
+ f.host.state.jump_to = new_state
+
+ if smbus.state(f, HOST_IDLE) then
+ signal_reset(f)
+
+ elseif smbus.state(f, HOST_ACTIVE) then
+ signal_reset(f)
+ signal_set(f, SIG_INUSE)
+
+ elseif smbus.state(f, HOST_STARTED) then
+ local i
+ f.host.proto = f.host.start_proto
+ f.host.wr_data0 = f.host.data0
+ f.host.wr_data1 = f.host.data1
+
+ -- Invalidation used with reads
+ f.host.data0_valid = false
+ f.host.data1_valid = false
+
+ for i = 0, MAX_BLOCK_SRAM-1, 1 do
+ f.host.max_index = 0
+ -- On block writes, previously read data in buffer is also valid.
+ if f.host.block[i].tmp_valid then
+ f.host.block[i].hw = f.host.block[i].tmp
+ f.host.block[i].tmp_valid = false
+ f.host.block[i].hw_valid = true
+ end
+ -- On block reads, no data in buffer is yet valid.
+ if host_reading(f) and host_proto(f, SMBUS_BLOCK_DATA) then
+ f.host.block[i].hw_valid = false;
+ end
+ end
+
+ elseif smbus.state(f, HOST_COMPLETE) then
+ dump_transaction(f, f.host.action)
+ if signal_in(f, SIG_RELEASE) then
+ host_jump(f, HOST_IDLE)
+ else
+ host_jump(f, HOST_ACTIVE)
+ end
+
+-- elseif smbus.state(f, HOST_FAIL) then
+-- dump_transaction(f, f.host.action)
+-- host_jump(f, HOST_ACTIVE)
+ end
+
+end
+
+local function host_switch(f, new_state)
+ local prev_state = f.host.state.current
+ while prev_state ~= new_state do
+ host_change_state(f, prev_state, new_state)
+ prev_state = f.host.state.current
+ new_state = f.host.state.jump_to
+ end
+end
+
+local function host_read_completed(f)
+
+ if not host_reading(f) then
+ return true
+ end
+
+ local complete = false
+
+ if host_proto(f, SMBUS_QUICK) then
+ complete = true
+
+ elseif host_proto(f, SMBUS_BYTE) then
+ complete = f.host.data0_valid
+
+ elseif host_proto(f, SMBUS_BYTE_DATA) then
+ complete = f.host.data0_valid
+
+ elseif host_proto(f, SMBUS_WORD_DATA) then
+ complete = f.host.data0_valid and f.host.data1_valid
+
+ elseif host_proto(f, SMBUS_BLOCK_DATA) then
+ complete = f.host.data0_valid and f.host.max_index >= f.host.data0
+
+ elseif host_proto(f, SMBUS_PROC_CALL) or host_proto(f, SMBUS_I2C_BLOCK_DATA)
+ or host_proto(f, SMBUS_BLOCK_PROCESS) then
+ printk(f, f.host.action, "Unimplemented completion (proto %d)\n", f.host.proto)
+ end
+ return complete
+end
+
+
+-- Syncronize state machine according to input signals.
+local function host_sync(f)
+
+-- if release and not smbus.state(f, HOST_ACTIVE) then
+-- printk(f, f.host.action, "Premature reset of bit INUSE_STS\n")
+-- end
+ if signal_in(f, SIG_ABORT) then
+ -- FIXME Killing on-going transaction.
+ host_switch(f, HOST_COMPLETE)
+ end
+
+ if smbus.state(f, HOST_IDLE) then
+ if signal_in(f, SIG_INUSE) then
+ host_switch(f, HOST_ACTIVE)
+ end
+ if signal_in(f, SIG_START) then
+ host_switch(f, HOST_STARTED)
+ end
+
+ elseif smbus.state(f, HOST_ACTIVE) then
+ if signal_in(f, SIG_START) then
+ host_switch(f, HOST_STARTED)
+ end
+
+ elseif smbus.state(f, HOST_STARTED) then
+ if signal_in(f, SIG_TIMEOUT) then
+ host_switch(f, HOST_FAIL)
+ elseif signal_in(f, SIG_DONE) then
+ host_switch(f, HOST_WAIT)
+ end
+
+ elseif smbus.state(f, HOST_WAIT) then
+ if signal_in(f, SIG_START) then
+ -- Restarting previous transaction.
+ host_switch(f, HOST_COMPLETE)
+ host_switch(f, HOST_STARTED)
+ elseif signal_in(f, SIG_ACK) and not host_reading(f) then
+ -- Complete after sw ack.
+ host_switch(f, HOST_COMPLETE)
+ elseif signal_in(f, SIG_DATA_WRITE) or host_read_completed(f) then
+ -- Complete after all data read or new data written
+ -- remain active
+ signal_clr(f, SIG_RELEASE)
+ host_switch(f, HOST_COMPLETE)
+ end
+ elseif smbus.state(f, HOST_FAIL) then
+ if signal_in(f, SIG_TIMEOUT_ACK) then
+ host_switch(f, HOST_COMPLETE)
+ end
+ end
+
+ if signal_in(f, SIG_START) and not smbus.state(f, HOST_STARTED) then
+ printk(f, f.host.action, "Starting from illegal state\n");
+ end
+
+ signal_clr(f, SIG_DONE)
+ signal_clr(f, SIG_START)
+ signal_clr(f, SIG_DATA_WRITE)
+end
+
+
+
+-- *******************************
+
+-- Mutual exclusion.
+function smbus.get_resource(f)
+ signal_set(f, SIG_INUSE)
+ host_sync(f)
+end
+
+function smbus.put_resource(f)
+ signal_set(f, SIG_RELEASE)
+ host_sync(f)
+end
+
+-- status
+function smbus.state(f, state)
+ return f.host.state.current == state
+end
+
+function smbus.passive(f)
+ return f.host.passive
+end
+
+-- control
+function smbus.start(f, proto)
+ signal_set(f, SIG_START)
+ f.host.start_proto = proto
+ host_sync(f)
+end
+
+function smbus.timeout(f)
+ signal_set(f, SIG_TIMEOUT)
+ host_sync(f)
+end
+
+function smbus.timeout_ack(f)
+ signal_set(f, SIG_TIMEOUT_ACK)
+ host_sync(f)
+end
+
+function smbus.done(f)
+ signal_set(f, SIG_DONE)
+ host_sync(f)
+end
+
+function smbus.ack(f)
+ signal_set(f, SIG_ACK)
+ host_sync(f)
+end
+
+function smbus.abort(f)
+ signal_set(f, SIG_ABORT)
+ host_sync(f)
+end
+
+-- A data read may complete and close an active transaction.
+function smbus.data_read(f, action)
+ if not action.write then
+ signal_clr(f, SIG_DATA_WRITE)
+ host_sync(f)
+ end
+end
+
+-- A data write will close active transaction.
+function smbus.data_write(f, action)
+ if action.write then
+ signal_set(f, SIG_DATA_WRITE)
+ host_sync(f)
+ end
+end
+
+
+
+function smbus.update_register(f, action, smb_reg)
+
+ local data_write = action.write or smbus.passive(f)
+
+ -- A write to data registers completes previous transaction.
+ smbus.data_write(f, action)
+
+ if smb_reg == SMB_REG_SLAVE then
+ if data_write then
+ f.host.slave = action.data
+ else
+ action.data = f.host.slave
+ end
+
+ elseif smb_reg == SMB_REG_CMD then
+ if data_write then
+ f.host.cmd = action.data
+ else
+ action.data = f.host.cmd
+ end
+
+ elseif smb_reg == SMB_REG_DATA0 then
+ if data_write then
+ f.host.data0 = action.data
+ else
+ action.data = f.host.data0
+ end
+ f.host.data0_valid = true
+
+ elseif smb_reg == SMB_REG_DATA1 then
+ if data_write then
+ f.host.data1 = action.data
+ else
+ action.data = f.host.data1
+ end
+ f.host.data1_valid = true
+
+ elseif smb_reg == SMB_REG_BLOCK then
+ if data_write then
+ f.host.block_register = action.data
+ else
+ action.data = f.host.block_register
+ end
+ -- Nothing here, smbus.host_block_data updates datas.
+ -- This exist to check completion below for blocks.
+ elseif smb_reg == SMB_REG_PROTO then
+ -- Nothing here. Protocol updates when signalling start.
+ else
+ printk(f, f.host.action, "Undefined host register\n")
+ end
+
+ -- New read data may complete a waiting transaction.
+ smbus.data_read(f, action)
+end
+
+function smbus.block_data(f, action, index)
+
+ if smbus.passive(f) then
+ if not action.write then
+ f.host.block[index].hw = action.data
+ f.host.block[index].hw_valid = true
+ end
+ f.host.block[index].tmp = action.data
+ f.host.block[index].tmp_valid = true
+ else
+ if action.write then
+ f.host.block[index].tmp = action.data
+ f.host.block[index].tmp_valid = true
+ else
+ action.data = 0xff
+ if f.host.block[index].tmp_valid then
+ action.data = f.host.block[index].tmp
+ elseif f.host.block[index].hw_valid then
+ action.data = f.host.block[index].hw
+ end
+ end
+ end
+
+ -- Detect for block read completion via maximum indexed item.
+ if not action.write then
+ f.host.max_index = math.max(f.host.max_index, index+1)
+ end
+end
+
+local init_action = {
+ name = "init",
+ cs = 0,
+ eip = 0,
+ my_id = 0,
+ parent_id = 0,
+}
+function smbus.init(f)
+ if not f.host then
+ f.host = smbus.host
+ f.host.action = init_action
+ end
+ host_switch(f, HOST_IDLE)
+end
+
+
More information about the SerialICE
mailing list