1.1 --- a/pkg/devices/lib/i2c/src/jz4780.cc Sun Jul 21 19:17:00 2019 +0200
1.2 +++ b/pkg/devices/lib/i2c/src/jz4780.cc Sun Jul 21 21:10:24 2019 +0200
1.3 @@ -41,7 +41,7 @@
1.4 */
1.5
1.6 enum Regs
1.7 -{
1.8 +{
1.9 Smb_control = 0x000, // SMBCON
1.10 Smb_target_address = 0x004, // SMBTAR
1.11 Smb_slave_address = 0x008, // SMBSAR
1.12 @@ -160,7 +160,7 @@
1.13
1.14 I2c_jz4780_channel::I2c_jz4780_channel(l4_addr_t start,
1.15 Cpm_jz4780_chip *cpm,
1.16 - uint32_t frequency)
1.17 + uint32_t frequency)
1.18 : _cpm(cpm), _frequency(frequency)
1.19 {
1.20 _regs = new Hw::Mmio_register_block<32>(start);
1.21 @@ -171,8 +171,6 @@
1.22 void
1.23 I2c_jz4780_channel::enable()
1.24 {
1.25 - _regs[Smb_control] = _regs[Smb_control] | Smb_no_stop_empty;
1.26 -
1.27 _regs[Smb_enable] = Smb_enable_enabled;
1.28 while (!(_regs[Smb_enable_status] & Smb_enable_enabled));
1.29 }
1.30 @@ -198,7 +196,7 @@
1.31
1.32 uint32_t smb_clk = _cpm->get_pclock_frequency() / 1000;
1.33 uint32_t i2c_clk = _frequency / 1000;
1.34 - unsigned speed = (i2c_clk <= 100) ? 1 : 2;
1.35 + unsigned int speed = (i2c_clk <= 100) ? 1 : 2;
1.36
1.37 _regs[Smb_control] = _regs[Smb_control] | (speed << Smb_speed_bit) |
1.38 Smb_disable_slave |
1.39 @@ -334,7 +332,6 @@
1.40 _regs[Smb_target_address] = address & Smb_target_7bits;
1.41 enable();
1.42 init_parameters();
1.43 - queued = 0;
1.44 }
1.45
1.46
1.47 @@ -352,6 +349,8 @@
1.48
1.49 r = _regs[Int_combined_clear];
1.50 (void) r;
1.51 + r = _regs[Trans_abort_status0];
1.52 + (void) r;
1.53 }
1.54
1.55 // Initialise interrupt flags and queue thresholds for reading and writing.
1.56 @@ -432,44 +431,44 @@
1.57 void
1.58 I2c_jz4780_channel::queue_reads()
1.59 {
1.60 - unsigned remaining = _total - _reqpos;
1.61 - unsigned can_queue = Smb_fifo_limit - queued + 1;
1.62 + unsigned int remaining = _total - _reqpos;
1.63 + unsigned int queued = _reqpos - _pos;
1.64
1.65 - if (!remaining)
1.66 - {
1.67 - _regs[Smb_data_command] = Smb_command_read;
1.68 - return;
1.69 - }
1.70 + // Permit one more issued read request due to the behaviour of the peripheral
1.71 + // to withhold a request unless the stop condition has been issued.
1.72 +
1.73 + unsigned int can_queue = Smb_fifo_limit - queued + 1;
1.74
1.75 // Keep the number of reads in progress below the length of the read queue.
1.76
1.77 if (!can_queue)
1.78 - {
1.79 - //printf("remaining=%d queued=%d\n", remaining, queued);
1.80 return;
1.81 - }
1.82
1.83 if (remaining < can_queue)
1.84 can_queue = remaining;
1.85
1.86 // Queue read requests for any remaining queue entries.
1.87
1.88 - for (unsigned i = 0; i < can_queue; i++)
1.89 + for (unsigned int i = 0; i < can_queue; i++)
1.90 _regs[Smb_data_command] = Smb_command_read;
1.91
1.92 // Track queued messages and requested positions.
1.93
1.94 - queued += can_queue;
1.95 _reqpos += can_queue;
1.96
1.97 + // Issue the stop condition after the final read request.
1.98 + // In practice, an extra read request works better since it does not risk a
1.99 + // transmission abort condition and would permit following transactions.
1.100 +
1.101 if (_total == _reqpos)
1.102 - printf("Written %d read requests.\n", _reqpos);
1.103 + _regs[Smb_data_command] = Smb_command_read;
1.104 + //stop();
1.105 }
1.106
1.107 // Send write commands for empty queue entries.
1.108
1.109 void
1.110 -I2c_jz4780_channel::queue_writes(uint8_t buf[], unsigned *pos, unsigned total)
1.111 +I2c_jz4780_channel::queue_writes(uint8_t buf[], unsigned int *pos, unsigned int total)
1.112 {
1.113 // Queue write requests for any remaining queue entries.
1.114
1.115 @@ -492,7 +491,6 @@
1.116 while (have_input() && (_pos < _total))
1.117 {
1.118 _buf[_pos] = _regs[Smb_data_command] & 0xff;
1.119 - queued--;
1.120 _pos++;
1.121
1.122 have_read = 1;
1.123 @@ -502,58 +500,55 @@
1.124
1.125 if (have_read)
1.126 set_read_threshold();
1.127 +}
1.128
1.129 - //printf("Read to %d, still %d queued.\n", _pos, queued);
1.130 +void
1.131 +I2c_jz4780_channel::set_read_threshold()
1.132 +{
1.133 + unsigned int remaining = _total - _pos;
1.134 +
1.135 + if (!remaining)
1.136 + return;
1.137 +
1.138 + // Read all remaining.
1.139 +
1.140 + if (remaining <= Smb_fifo_limit)
1.141 + _regs[Rx_fifo_thold] = remaining - 1;
1.142 +
1.143 + // Read to limit.
1.144 +
1.145 + else
1.146 + _regs[Rx_fifo_thold] = Smb_fifo_limit - 1;
1.147 }
1.148
1.149 // Read from the target device.
1.150
1.151 void
1.152 -I2c_jz4780_channel::start_read(uint8_t buf[], unsigned total)
1.153 +I2c_jz4780_channel::start_read(uint8_t buf[], unsigned int total)
1.154 {
1.155 - printf("intst=%x\n", (uint32_t) _regs[Int_status]);
1.156 -
1.157 _buf = buf;
1.158 _total = total;
1.159 _pos = 0;
1.160 _reqpos = 0;
1.161 _fail = 0;
1.162 - _stop = 0;
1.163
1.164 set_read_threshold();
1.165 }
1.166
1.167 void
1.168 -I2c_jz4780_channel::set_read_threshold()
1.169 -{
1.170 - unsigned remaining = _total - _pos;
1.171 -
1.172 - if (!remaining)
1.173 - return;
1.174 -
1.175 - if (remaining <= Smb_fifo_limit)
1.176 - _regs[Rx_fifo_thold] = remaining - 1; // read all remaining
1.177 - else
1.178 - _regs[Rx_fifo_thold] = Smb_fifo_limit - 1; // read to limit
1.179 -
1.180 - //printf("rxthold=%d\n", (uint32_t) _regs[Rx_fifo_thold] + 1);
1.181 -}
1.182 -
1.183 -void
1.184 I2c_jz4780_channel::read()
1.185 {
1.186 if (read_failed() || write_failed())
1.187 {
1.188 +#if 0
1.189 printf("intst*=%x\n", (uint32_t) _regs[Int_status]);
1.190 printf("rxfifo=%d\n", (uint32_t) _regs[Rx_fifo_count] & 0x3f);
1.191 printf("smbabtsrc=%x\n", (uint32_t) _regs[Trans_abort_status0]);
1.192 +#endif
1.193 _fail = 1;
1.194 return;
1.195 }
1.196
1.197 - //printf("rxfifo=%d\n", (uint32_t) _regs[Rx_fifo_count]);
1.198 - //printf("intst=%x\n", (uint32_t) _regs[Int_status]);
1.199 -
1.200 if (_pos < _total)
1.201 {
1.202 if (_regs[Int_status] & Int_rx_full)
1.203 @@ -561,11 +556,6 @@
1.204 if (_regs[Int_status] & Int_tx_empty)
1.205 queue_reads();
1.206 }
1.207 - else
1.208 - {
1.209 - stop();
1.210 - _regs[Int_mask] = 0;
1.211 - }
1.212 }
1.213
1.214 int
1.215 @@ -589,9 +579,9 @@
1.216 // Write to the target device.
1.217
1.218 void
1.219 -I2c_jz4780_channel::write(uint8_t buf[], unsigned total)
1.220 +I2c_jz4780_channel::write(uint8_t buf[], unsigned int total)
1.221 {
1.222 - unsigned pos = 0;
1.223 + unsigned int pos = 0;
1.224
1.225 while ((pos < total) && !write_failed())
1.226 {
1.227 @@ -604,12 +594,7 @@
1.228 void
1.229 I2c_jz4780_channel::stop()
1.230 {
1.231 - if (_stop)
1.232 - return;
1.233 -
1.234 _regs[Smb_control] = _regs[Smb_control] & ~Smb_no_stop_empty;
1.235 - _stop = 1;
1.236 - printf("Stop sent.\n");
1.237 }
1.238
1.239
1.240 @@ -648,6 +633,11 @@
1.241 return (void *) new I2c_jz4780_chip(start, end, static_cast<Cpm_jz4780_chip *>(cpm), frequency);
1.242 }
1.243
1.244 +void jz4780_i2c_disable(void *i2c_channel)
1.245 +{
1.246 + static_cast<I2c_jz4780_channel *>(i2c_channel)->disable();
1.247 +}
1.248 +
1.249 void *jz4780_i2c_get_channel(void *i2c, uint8_t channel)
1.250 {
1.251 return static_cast<I2c_jz4780_chip *>(i2c)->get_channel(channel);
1.252 @@ -658,7 +648,7 @@
1.253 static_cast<I2c_jz4780_channel *>(i2c_channel)->set_target(addr);
1.254 }
1.255
1.256 -void jz4780_i2c_start_read(void *i2c_channel, uint8_t buf[], unsigned total)
1.257 +void jz4780_i2c_start_read(void *i2c_channel, uint8_t buf[], unsigned int total)
1.258 {
1.259 static_cast<I2c_jz4780_channel *>(i2c_channel)->start_read(buf, total);
1.260 }
1.261 @@ -673,7 +663,7 @@
1.262 return static_cast<I2c_jz4780_channel *>(i2c_channel)->read_done();
1.263 }
1.264
1.265 -unsigned jz4780_i2c_have_read(void *i2c_channel)
1.266 +unsigned int jz4780_i2c_have_read(void *i2c_channel)
1.267 {
1.268 return static_cast<I2c_jz4780_channel *>(i2c_channel)->have_read();
1.269 }
1.270 @@ -683,7 +673,7 @@
1.271 return static_cast<I2c_jz4780_channel *>(i2c_channel)->read_incomplete();
1.272 }
1.273
1.274 -void jz4780_i2c_write(void *i2c_channel, uint8_t buf[], unsigned total)
1.275 +void jz4780_i2c_write(void *i2c_channel, uint8_t buf[], unsigned int total)
1.276 {
1.277 static_cast<I2c_jz4780_channel *>(i2c_channel)->write(buf, total);
1.278 }