1.1 --- a/pkg/devices/lib/i2c/include/i2c-jz4780.h Sun Jul 21 19:17:00 2019 +0200
1.2 +++ b/pkg/devices/lib/i2c/include/i2c-jz4780.h Sun Jul 21 21:10:24 2019 +0200
1.3 @@ -1,5 +1,5 @@
1.4 /*
1.5 - * Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk>
1.6 + * Copyright (C) 2017, 2018, 2019 Paul Boddie <paul@boddie.org.uk>
1.7 *
1.8 * This program is free software; you can redistribute it and/or
1.9 * modify it under the terms of the GNU General Public License as
1.10 @@ -37,33 +37,45 @@
1.11 Hw::Register_block<32> _regs;
1.12 Cpm_jz4780_chip *_cpm;
1.13 uint32_t _frequency;
1.14 - unsigned queued, _pos, _reqpos, _total;
1.15 +
1.16 + // Buffer management.
1.17 +
1.18 + unsigned int _pos, _reqpos, _total;
1.19 uint8_t *_buf;
1.20 - int _fail, _stop, _last;
1.21 +
1.22 + // Status conditions.
1.23 +
1.24 + int _fail;
1.25
1.26 public:
1.27 I2c_jz4780_channel(l4_addr_t start, Cpm_jz4780_chip *cpm,
1.28 uint32_t frequency);
1.29
1.30 void set_target(uint8_t addr);
1.31 - void start_read(uint8_t buf[], unsigned total);
1.32 + void start_read(uint8_t buf[], unsigned int total);
1.33 void read();
1.34 + void write(uint8_t buf[], unsigned int total);
1.35 +
1.36 + // Transaction control.
1.37 +
1.38 + void stop();
1.39 + void disable();
1.40 +
1.41 + // Specific status conditions.
1.42 +
1.43 + unsigned int have_read();
1.44 int read_done();
1.45 - unsigned have_read();
1.46 int read_incomplete();
1.47 - void write(uint8_t buf[], unsigned total);
1.48 - void stop();
1.49 + int read_failed();
1.50 + int write_failed();
1.51
1.52 private:
1.53 - void disable();
1.54 void enable();
1.55
1.56 int active();
1.57 int have_input();
1.58 int have_output();
1.59 int can_send();
1.60 - int read_failed();
1.61 - int write_failed();
1.62
1.63 void reset_flags();
1.64 void init_parameters();
1.65 @@ -71,7 +83,7 @@
1.66
1.67 void set_read_threshold();
1.68 void queue_reads();
1.69 - void queue_writes(uint8_t buf[], unsigned *pos, unsigned total);
1.70 + void queue_writes(uint8_t buf[], unsigned int *pos, unsigned int total);
1.71 void store_reads();
1.72 };
1.73
1.74 @@ -102,15 +114,24 @@
1.75 void *jz4780_i2c_init(l4_addr_t start, l4_addr_t end, void *cpm,
1.76 uint32_t frequency);
1.77
1.78 +void jz4780_i2c_disable(void *i2c_channel);
1.79 +
1.80 void *jz4780_i2c_get_channel(void *i2c, uint8_t channel);
1.81
1.82 void jz4780_i2c_set_target(void *i2c_channel, uint8_t addr);
1.83 -void jz4780_i2c_start_read(void *i2c_channel, uint8_t buf[], unsigned total);
1.84 +
1.85 +void jz4780_i2c_start_read(void *i2c_channel, uint8_t buf[], unsigned int total);
1.86 +
1.87 void jz4780_i2c_read(void *i2c_channel);
1.88 +
1.89 int jz4780_i2c_read_done(void *i2c_channel);
1.90 -unsigned jz4780_i2c_have_read(void *i2c_channel);
1.91 +
1.92 +unsigned int jz4780_i2c_have_read(void *i2c_channel);
1.93 +
1.94 int jz4780_i2c_read_incomplete(void *i2c_channel);
1.95 -void jz4780_i2c_write(void *i2c_channel, uint8_t buf[], unsigned total);
1.96 +
1.97 +void jz4780_i2c_write(void *i2c_channel, uint8_t buf[], unsigned int total);
1.98 +
1.99 void jz4780_i2c_stop(void *i2c_channel);
1.100
1.101 EXTERN_C_END
2.1 --- a/pkg/devices/lib/i2c/src/jz4780.cc Sun Jul 21 19:17:00 2019 +0200
2.2 +++ b/pkg/devices/lib/i2c/src/jz4780.cc Sun Jul 21 21:10:24 2019 +0200
2.3 @@ -41,7 +41,7 @@
2.4 */
2.5
2.6 enum Regs
2.7 -{
2.8 +{
2.9 Smb_control = 0x000, // SMBCON
2.10 Smb_target_address = 0x004, // SMBTAR
2.11 Smb_slave_address = 0x008, // SMBSAR
2.12 @@ -160,7 +160,7 @@
2.13
2.14 I2c_jz4780_channel::I2c_jz4780_channel(l4_addr_t start,
2.15 Cpm_jz4780_chip *cpm,
2.16 - uint32_t frequency)
2.17 + uint32_t frequency)
2.18 : _cpm(cpm), _frequency(frequency)
2.19 {
2.20 _regs = new Hw::Mmio_register_block<32>(start);
2.21 @@ -171,8 +171,6 @@
2.22 void
2.23 I2c_jz4780_channel::enable()
2.24 {
2.25 - _regs[Smb_control] = _regs[Smb_control] | Smb_no_stop_empty;
2.26 -
2.27 _regs[Smb_enable] = Smb_enable_enabled;
2.28 while (!(_regs[Smb_enable_status] & Smb_enable_enabled));
2.29 }
2.30 @@ -198,7 +196,7 @@
2.31
2.32 uint32_t smb_clk = _cpm->get_pclock_frequency() / 1000;
2.33 uint32_t i2c_clk = _frequency / 1000;
2.34 - unsigned speed = (i2c_clk <= 100) ? 1 : 2;
2.35 + unsigned int speed = (i2c_clk <= 100) ? 1 : 2;
2.36
2.37 _regs[Smb_control] = _regs[Smb_control] | (speed << Smb_speed_bit) |
2.38 Smb_disable_slave |
2.39 @@ -334,7 +332,6 @@
2.40 _regs[Smb_target_address] = address & Smb_target_7bits;
2.41 enable();
2.42 init_parameters();
2.43 - queued = 0;
2.44 }
2.45
2.46
2.47 @@ -352,6 +349,8 @@
2.48
2.49 r = _regs[Int_combined_clear];
2.50 (void) r;
2.51 + r = _regs[Trans_abort_status0];
2.52 + (void) r;
2.53 }
2.54
2.55 // Initialise interrupt flags and queue thresholds for reading and writing.
2.56 @@ -432,44 +431,44 @@
2.57 void
2.58 I2c_jz4780_channel::queue_reads()
2.59 {
2.60 - unsigned remaining = _total - _reqpos;
2.61 - unsigned can_queue = Smb_fifo_limit - queued + 1;
2.62 + unsigned int remaining = _total - _reqpos;
2.63 + unsigned int queued = _reqpos - _pos;
2.64
2.65 - if (!remaining)
2.66 - {
2.67 - _regs[Smb_data_command] = Smb_command_read;
2.68 - return;
2.69 - }
2.70 + // Permit one more issued read request due to the behaviour of the peripheral
2.71 + // to withhold a request unless the stop condition has been issued.
2.72 +
2.73 + unsigned int can_queue = Smb_fifo_limit - queued + 1;
2.74
2.75 // Keep the number of reads in progress below the length of the read queue.
2.76
2.77 if (!can_queue)
2.78 - {
2.79 - //printf("remaining=%d queued=%d\n", remaining, queued);
2.80 return;
2.81 - }
2.82
2.83 if (remaining < can_queue)
2.84 can_queue = remaining;
2.85
2.86 // Queue read requests for any remaining queue entries.
2.87
2.88 - for (unsigned i = 0; i < can_queue; i++)
2.89 + for (unsigned int i = 0; i < can_queue; i++)
2.90 _regs[Smb_data_command] = Smb_command_read;
2.91
2.92 // Track queued messages and requested positions.
2.93
2.94 - queued += can_queue;
2.95 _reqpos += can_queue;
2.96
2.97 + // Issue the stop condition after the final read request.
2.98 + // In practice, an extra read request works better since it does not risk a
2.99 + // transmission abort condition and would permit following transactions.
2.100 +
2.101 if (_total == _reqpos)
2.102 - printf("Written %d read requests.\n", _reqpos);
2.103 + _regs[Smb_data_command] = Smb_command_read;
2.104 + //stop();
2.105 }
2.106
2.107 // Send write commands for empty queue entries.
2.108
2.109 void
2.110 -I2c_jz4780_channel::queue_writes(uint8_t buf[], unsigned *pos, unsigned total)
2.111 +I2c_jz4780_channel::queue_writes(uint8_t buf[], unsigned int *pos, unsigned int total)
2.112 {
2.113 // Queue write requests for any remaining queue entries.
2.114
2.115 @@ -492,7 +491,6 @@
2.116 while (have_input() && (_pos < _total))
2.117 {
2.118 _buf[_pos] = _regs[Smb_data_command] & 0xff;
2.119 - queued--;
2.120 _pos++;
2.121
2.122 have_read = 1;
2.123 @@ -502,58 +500,55 @@
2.124
2.125 if (have_read)
2.126 set_read_threshold();
2.127 +}
2.128
2.129 - //printf("Read to %d, still %d queued.\n", _pos, queued);
2.130 +void
2.131 +I2c_jz4780_channel::set_read_threshold()
2.132 +{
2.133 + unsigned int remaining = _total - _pos;
2.134 +
2.135 + if (!remaining)
2.136 + return;
2.137 +
2.138 + // Read all remaining.
2.139 +
2.140 + if (remaining <= Smb_fifo_limit)
2.141 + _regs[Rx_fifo_thold] = remaining - 1;
2.142 +
2.143 + // Read to limit.
2.144 +
2.145 + else
2.146 + _regs[Rx_fifo_thold] = Smb_fifo_limit - 1;
2.147 }
2.148
2.149 // Read from the target device.
2.150
2.151 void
2.152 -I2c_jz4780_channel::start_read(uint8_t buf[], unsigned total)
2.153 +I2c_jz4780_channel::start_read(uint8_t buf[], unsigned int total)
2.154 {
2.155 - printf("intst=%x\n", (uint32_t) _regs[Int_status]);
2.156 -
2.157 _buf = buf;
2.158 _total = total;
2.159 _pos = 0;
2.160 _reqpos = 0;
2.161 _fail = 0;
2.162 - _stop = 0;
2.163
2.164 set_read_threshold();
2.165 }
2.166
2.167 void
2.168 -I2c_jz4780_channel::set_read_threshold()
2.169 -{
2.170 - unsigned remaining = _total - _pos;
2.171 -
2.172 - if (!remaining)
2.173 - return;
2.174 -
2.175 - if (remaining <= Smb_fifo_limit)
2.176 - _regs[Rx_fifo_thold] = remaining - 1; // read all remaining
2.177 - else
2.178 - _regs[Rx_fifo_thold] = Smb_fifo_limit - 1; // read to limit
2.179 -
2.180 - //printf("rxthold=%d\n", (uint32_t) _regs[Rx_fifo_thold] + 1);
2.181 -}
2.182 -
2.183 -void
2.184 I2c_jz4780_channel::read()
2.185 {
2.186 if (read_failed() || write_failed())
2.187 {
2.188 +#if 0
2.189 printf("intst*=%x\n", (uint32_t) _regs[Int_status]);
2.190 printf("rxfifo=%d\n", (uint32_t) _regs[Rx_fifo_count] & 0x3f);
2.191 printf("smbabtsrc=%x\n", (uint32_t) _regs[Trans_abort_status0]);
2.192 +#endif
2.193 _fail = 1;
2.194 return;
2.195 }
2.196
2.197 - //printf("rxfifo=%d\n", (uint32_t) _regs[Rx_fifo_count]);
2.198 - //printf("intst=%x\n", (uint32_t) _regs[Int_status]);
2.199 -
2.200 if (_pos < _total)
2.201 {
2.202 if (_regs[Int_status] & Int_rx_full)
2.203 @@ -561,11 +556,6 @@
2.204 if (_regs[Int_status] & Int_tx_empty)
2.205 queue_reads();
2.206 }
2.207 - else
2.208 - {
2.209 - stop();
2.210 - _regs[Int_mask] = 0;
2.211 - }
2.212 }
2.213
2.214 int
2.215 @@ -589,9 +579,9 @@
2.216 // Write to the target device.
2.217
2.218 void
2.219 -I2c_jz4780_channel::write(uint8_t buf[], unsigned total)
2.220 +I2c_jz4780_channel::write(uint8_t buf[], unsigned int total)
2.221 {
2.222 - unsigned pos = 0;
2.223 + unsigned int pos = 0;
2.224
2.225 while ((pos < total) && !write_failed())
2.226 {
2.227 @@ -604,12 +594,7 @@
2.228 void
2.229 I2c_jz4780_channel::stop()
2.230 {
2.231 - if (_stop)
2.232 - return;
2.233 -
2.234 _regs[Smb_control] = _regs[Smb_control] & ~Smb_no_stop_empty;
2.235 - _stop = 1;
2.236 - printf("Stop sent.\n");
2.237 }
2.238
2.239
2.240 @@ -648,6 +633,11 @@
2.241 return (void *) new I2c_jz4780_chip(start, end, static_cast<Cpm_jz4780_chip *>(cpm), frequency);
2.242 }
2.243
2.244 +void jz4780_i2c_disable(void *i2c_channel)
2.245 +{
2.246 + static_cast<I2c_jz4780_channel *>(i2c_channel)->disable();
2.247 +}
2.248 +
2.249 void *jz4780_i2c_get_channel(void *i2c, uint8_t channel)
2.250 {
2.251 return static_cast<I2c_jz4780_chip *>(i2c)->get_channel(channel);
2.252 @@ -658,7 +648,7 @@
2.253 static_cast<I2c_jz4780_channel *>(i2c_channel)->set_target(addr);
2.254 }
2.255
2.256 -void jz4780_i2c_start_read(void *i2c_channel, uint8_t buf[], unsigned total)
2.257 +void jz4780_i2c_start_read(void *i2c_channel, uint8_t buf[], unsigned int total)
2.258 {
2.259 static_cast<I2c_jz4780_channel *>(i2c_channel)->start_read(buf, total);
2.260 }
2.261 @@ -673,7 +663,7 @@
2.262 return static_cast<I2c_jz4780_channel *>(i2c_channel)->read_done();
2.263 }
2.264
2.265 -unsigned jz4780_i2c_have_read(void *i2c_channel)
2.266 +unsigned int jz4780_i2c_have_read(void *i2c_channel)
2.267 {
2.268 return static_cast<I2c_jz4780_channel *>(i2c_channel)->have_read();
2.269 }
2.270 @@ -683,7 +673,7 @@
2.271 return static_cast<I2c_jz4780_channel *>(i2c_channel)->read_incomplete();
2.272 }
2.273
2.274 -void jz4780_i2c_write(void *i2c_channel, uint8_t buf[], unsigned total)
2.275 +void jz4780_i2c_write(void *i2c_channel, uint8_t buf[], unsigned int total)
2.276 {
2.277 static_cast<I2c_jz4780_channel *>(i2c_channel)->write(buf, total);
2.278 }