# HG changeset patch # User Paul Boddie # Date 1563736224 -7200 # Node ID ccb30374bad23b26ab81e2236199ad0a95938362 # Parent 9213bb0bab76416b12caa02eda74ddc7fb3e9bbe Tidied up somewhat, removing superfluous members, adding commentary. Clear transmission abort conditions when resetting flags. Made the disable method public, adding a function for C programs. diff -r 9213bb0bab76 -r ccb30374bad2 pkg/devices/lib/i2c/include/i2c-jz4780.h --- a/pkg/devices/lib/i2c/include/i2c-jz4780.h Sun Jul 21 19:17:00 2019 +0200 +++ b/pkg/devices/lib/i2c/include/i2c-jz4780.h Sun Jul 21 21:10:24 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017, 2018 Paul Boddie + * Copyright (C) 2017, 2018, 2019 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -37,33 +37,45 @@ Hw::Register_block<32> _regs; Cpm_jz4780_chip *_cpm; uint32_t _frequency; - unsigned queued, _pos, _reqpos, _total; + + // Buffer management. + + unsigned int _pos, _reqpos, _total; uint8_t *_buf; - int _fail, _stop, _last; + + // Status conditions. + + int _fail; public: I2c_jz4780_channel(l4_addr_t start, Cpm_jz4780_chip *cpm, uint32_t frequency); void set_target(uint8_t addr); - void start_read(uint8_t buf[], unsigned total); + void start_read(uint8_t buf[], unsigned int total); void read(); + void write(uint8_t buf[], unsigned int total); + + // Transaction control. + + void stop(); + void disable(); + + // Specific status conditions. + + unsigned int have_read(); int read_done(); - unsigned have_read(); int read_incomplete(); - void write(uint8_t buf[], unsigned total); - void stop(); + int read_failed(); + int write_failed(); private: - void disable(); void enable(); int active(); int have_input(); int have_output(); int can_send(); - int read_failed(); - int write_failed(); void reset_flags(); void init_parameters(); @@ -71,7 +83,7 @@ void set_read_threshold(); void queue_reads(); - void queue_writes(uint8_t buf[], unsigned *pos, unsigned total); + void queue_writes(uint8_t buf[], unsigned int *pos, unsigned int total); void store_reads(); }; @@ -102,15 +114,24 @@ void *jz4780_i2c_init(l4_addr_t start, l4_addr_t end, void *cpm, uint32_t frequency); +void jz4780_i2c_disable(void *i2c_channel); + void *jz4780_i2c_get_channel(void *i2c, uint8_t channel); void jz4780_i2c_set_target(void *i2c_channel, uint8_t addr); -void jz4780_i2c_start_read(void *i2c_channel, uint8_t buf[], unsigned total); + +void jz4780_i2c_start_read(void *i2c_channel, uint8_t buf[], unsigned int total); + void jz4780_i2c_read(void *i2c_channel); + int jz4780_i2c_read_done(void *i2c_channel); -unsigned jz4780_i2c_have_read(void *i2c_channel); + +unsigned int jz4780_i2c_have_read(void *i2c_channel); + int jz4780_i2c_read_incomplete(void *i2c_channel); -void jz4780_i2c_write(void *i2c_channel, uint8_t buf[], unsigned total); + +void jz4780_i2c_write(void *i2c_channel, uint8_t buf[], unsigned int total); + void jz4780_i2c_stop(void *i2c_channel); EXTERN_C_END diff -r 9213bb0bab76 -r ccb30374bad2 pkg/devices/lib/i2c/src/jz4780.cc --- a/pkg/devices/lib/i2c/src/jz4780.cc Sun Jul 21 19:17:00 2019 +0200 +++ b/pkg/devices/lib/i2c/src/jz4780.cc Sun Jul 21 21:10:24 2019 +0200 @@ -41,7 +41,7 @@ */ enum Regs -{ +{ Smb_control = 0x000, // SMBCON Smb_target_address = 0x004, // SMBTAR Smb_slave_address = 0x008, // SMBSAR @@ -160,7 +160,7 @@ I2c_jz4780_channel::I2c_jz4780_channel(l4_addr_t start, Cpm_jz4780_chip *cpm, - uint32_t frequency) + uint32_t frequency) : _cpm(cpm), _frequency(frequency) { _regs = new Hw::Mmio_register_block<32>(start); @@ -171,8 +171,6 @@ void I2c_jz4780_channel::enable() { - _regs[Smb_control] = _regs[Smb_control] | Smb_no_stop_empty; - _regs[Smb_enable] = Smb_enable_enabled; while (!(_regs[Smb_enable_status] & Smb_enable_enabled)); } @@ -198,7 +196,7 @@ uint32_t smb_clk = _cpm->get_pclock_frequency() / 1000; uint32_t i2c_clk = _frequency / 1000; - unsigned speed = (i2c_clk <= 100) ? 1 : 2; + unsigned int speed = (i2c_clk <= 100) ? 1 : 2; _regs[Smb_control] = _regs[Smb_control] | (speed << Smb_speed_bit) | Smb_disable_slave | @@ -334,7 +332,6 @@ _regs[Smb_target_address] = address & Smb_target_7bits; enable(); init_parameters(); - queued = 0; } @@ -352,6 +349,8 @@ r = _regs[Int_combined_clear]; (void) r; + r = _regs[Trans_abort_status0]; + (void) r; } // Initialise interrupt flags and queue thresholds for reading and writing. @@ -432,44 +431,44 @@ void I2c_jz4780_channel::queue_reads() { - unsigned remaining = _total - _reqpos; - unsigned can_queue = Smb_fifo_limit - queued + 1; + unsigned int remaining = _total - _reqpos; + unsigned int queued = _reqpos - _pos; - if (!remaining) - { - _regs[Smb_data_command] = Smb_command_read; - return; - } + // Permit one more issued read request due to the behaviour of the peripheral + // to withhold a request unless the stop condition has been issued. + + unsigned int can_queue = Smb_fifo_limit - queued + 1; // Keep the number of reads in progress below the length of the read queue. if (!can_queue) - { - //printf("remaining=%d queued=%d\n", remaining, queued); return; - } if (remaining < can_queue) can_queue = remaining; // Queue read requests for any remaining queue entries. - for (unsigned i = 0; i < can_queue; i++) + for (unsigned int i = 0; i < can_queue; i++) _regs[Smb_data_command] = Smb_command_read; // Track queued messages and requested positions. - queued += can_queue; _reqpos += can_queue; + // Issue the stop condition after the final read request. + // In practice, an extra read request works better since it does not risk a + // transmission abort condition and would permit following transactions. + if (_total == _reqpos) - printf("Written %d read requests.\n", _reqpos); + _regs[Smb_data_command] = Smb_command_read; + //stop(); } // Send write commands for empty queue entries. void -I2c_jz4780_channel::queue_writes(uint8_t buf[], unsigned *pos, unsigned total) +I2c_jz4780_channel::queue_writes(uint8_t buf[], unsigned int *pos, unsigned int total) { // Queue write requests for any remaining queue entries. @@ -492,7 +491,6 @@ while (have_input() && (_pos < _total)) { _buf[_pos] = _regs[Smb_data_command] & 0xff; - queued--; _pos++; have_read = 1; @@ -502,58 +500,55 @@ if (have_read) set_read_threshold(); +} - //printf("Read to %d, still %d queued.\n", _pos, queued); +void +I2c_jz4780_channel::set_read_threshold() +{ + unsigned int remaining = _total - _pos; + + if (!remaining) + return; + + // Read all remaining. + + if (remaining <= Smb_fifo_limit) + _regs[Rx_fifo_thold] = remaining - 1; + + // Read to limit. + + else + _regs[Rx_fifo_thold] = Smb_fifo_limit - 1; } // Read from the target device. void -I2c_jz4780_channel::start_read(uint8_t buf[], unsigned total) +I2c_jz4780_channel::start_read(uint8_t buf[], unsigned int total) { - printf("intst=%x\n", (uint32_t) _regs[Int_status]); - _buf = buf; _total = total; _pos = 0; _reqpos = 0; _fail = 0; - _stop = 0; set_read_threshold(); } void -I2c_jz4780_channel::set_read_threshold() -{ - unsigned remaining = _total - _pos; - - if (!remaining) - return; - - if (remaining <= Smb_fifo_limit) - _regs[Rx_fifo_thold] = remaining - 1; // read all remaining - else - _regs[Rx_fifo_thold] = Smb_fifo_limit - 1; // read to limit - - //printf("rxthold=%d\n", (uint32_t) _regs[Rx_fifo_thold] + 1); -} - -void I2c_jz4780_channel::read() { if (read_failed() || write_failed()) { +#if 0 printf("intst*=%x\n", (uint32_t) _regs[Int_status]); printf("rxfifo=%d\n", (uint32_t) _regs[Rx_fifo_count] & 0x3f); printf("smbabtsrc=%x\n", (uint32_t) _regs[Trans_abort_status0]); +#endif _fail = 1; return; } - //printf("rxfifo=%d\n", (uint32_t) _regs[Rx_fifo_count]); - //printf("intst=%x\n", (uint32_t) _regs[Int_status]); - if (_pos < _total) { if (_regs[Int_status] & Int_rx_full) @@ -561,11 +556,6 @@ if (_regs[Int_status] & Int_tx_empty) queue_reads(); } - else - { - stop(); - _regs[Int_mask] = 0; - } } int @@ -589,9 +579,9 @@ // Write to the target device. void -I2c_jz4780_channel::write(uint8_t buf[], unsigned total) +I2c_jz4780_channel::write(uint8_t buf[], unsigned int total) { - unsigned pos = 0; + unsigned int pos = 0; while ((pos < total) && !write_failed()) { @@ -604,12 +594,7 @@ void I2c_jz4780_channel::stop() { - if (_stop) - return; - _regs[Smb_control] = _regs[Smb_control] & ~Smb_no_stop_empty; - _stop = 1; - printf("Stop sent.\n"); } @@ -648,6 +633,11 @@ return (void *) new I2c_jz4780_chip(start, end, static_cast(cpm), frequency); } +void jz4780_i2c_disable(void *i2c_channel) +{ + static_cast(i2c_channel)->disable(); +} + void *jz4780_i2c_get_channel(void *i2c, uint8_t channel) { return static_cast(i2c)->get_channel(channel); @@ -658,7 +648,7 @@ static_cast(i2c_channel)->set_target(addr); } -void jz4780_i2c_start_read(void *i2c_channel, uint8_t buf[], unsigned total) +void jz4780_i2c_start_read(void *i2c_channel, uint8_t buf[], unsigned int total) { static_cast(i2c_channel)->start_read(buf, total); } @@ -673,7 +663,7 @@ return static_cast(i2c_channel)->read_done(); } -unsigned jz4780_i2c_have_read(void *i2c_channel) +unsigned int jz4780_i2c_have_read(void *i2c_channel) { return static_cast(i2c_channel)->have_read(); } @@ -683,7 +673,7 @@ return static_cast(i2c_channel)->read_incomplete(); } -void jz4780_i2c_write(void *i2c_channel, uint8_t buf[], unsigned total) +void jz4780_i2c_write(void *i2c_channel, uint8_t buf[], unsigned int total) { static_cast(i2c_channel)->write(buf, total); }