1.1 --- a/pkg/devices/lib/i2c/include/i2c-common.h Mon Oct 30 17:21:26 2023 +0100
1.2 +++ b/pkg/devices/lib/i2c/include/i2c-common.h Mon Oct 30 17:22:43 2023 +0100
1.3 @@ -37,6 +37,7 @@
1.4 {
1.5 protected:
1.6 Hw::Register_block<32> _regs;
1.7 + enum Clock_identifiers _clock;
1.8 Cpm_chip *_cpm;
1.9 uint32_t _frequency;
1.10
1.11 @@ -68,6 +69,13 @@
1.12 void queue_writes();
1.13 void store_reads();
1.14
1.15 + // Behaviour adaptations.
1.16 +
1.17 + virtual bool high_speed_mode() = 0;
1.18 + virtual bool hold_enable() = 0;
1.19 + virtual bool stop_hold() = 0;
1.20 + uint32_t stop_command();
1.21 +
1.22 public:
1.23 explicit I2c_channel(l4_addr_t start, enum Clock_identifiers clock,
1.24 Cpm_chip *cpm, uint32_t frequency);
1.25 @@ -113,6 +121,9 @@
1.26
1.27 virtual unsigned int num_channels() = 0;
1.28
1.29 + virtual I2c_channel *_get_channel(l4_addr_t addr, enum Clock_identifiers clock,
1.30 + Cpm_chip *cpm, uint32_t frequency) = 0;
1.31 +
1.32 public:
1.33 explicit I2c_chip(l4_addr_t start, l4_addr_t end, Cpm_chip *cpm,
1.34 uint32_t frequency);
2.1 --- a/pkg/devices/lib/i2c/include/i2c-jz4780.h Mon Oct 30 17:21:26 2023 +0100
2.2 +++ b/pkg/devices/lib/i2c/include/i2c-jz4780.h Mon Oct 30 17:22:43 2023 +0100
2.3 @@ -34,6 +34,16 @@
2.4
2.5 class I2c_jz4780_channel : public I2c_channel
2.6 {
2.7 +protected:
2.8 + bool high_speed_mode()
2.9 + { return false; }
2.10 +
2.11 + bool hold_enable()
2.12 + { return true; }
2.13 +
2.14 + bool stop_hold()
2.15 + { return true; }
2.16 +
2.17 public:
2.18 explicit I2c_jz4780_channel(l4_addr_t start, enum Clock_identifiers clock,
2.19 Cpm_chip *cpm, uint32_t frequency);
2.20 @@ -47,6 +57,10 @@
2.21 unsigned int num_channels()
2.22 { return 5; }
2.23
2.24 + I2c_channel *_get_channel(l4_addr_t addr, enum Clock_identifiers clock,
2.25 + Cpm_chip *cpm, uint32_t frequency)
2.26 + { return new I2c_jz4780_channel(addr, clock, cpm, frequency); }
2.27 +
2.28 public:
2.29 explicit I2c_jz4780_chip(l4_addr_t start, l4_addr_t end, Cpm_chip *cpm,
2.30 uint32_t frequency);
2.31 @@ -89,4 +103,6 @@
2.32
2.33 int jz4780_i2c_failed(void *i2c_channel);
2.34
2.35 +void jz4780_i2c_stop(void *i2c_channel);
2.36 +
2.37 EXTERN_C_END
3.1 --- a/pkg/devices/lib/i2c/include/i2c-x1600.h Mon Oct 30 17:21:26 2023 +0100
3.2 +++ b/pkg/devices/lib/i2c/include/i2c-x1600.h Mon Oct 30 17:22:43 2023 +0100
3.3 @@ -34,6 +34,16 @@
3.4
3.5 class I2c_x1600_channel : public I2c_channel
3.6 {
3.7 +protected:
3.8 + bool high_speed_mode()
3.9 + { return true; }
3.10 +
3.11 + bool hold_enable()
3.12 + { return false; }
3.13 +
3.14 + bool stop_hold()
3.15 + { return false; }
3.16 +
3.17 public:
3.18 explicit I2c_x1600_channel(l4_addr_t start, enum Clock_identifiers clock,
3.19 Cpm_chip *cpm, uint32_t frequency);
3.20 @@ -47,6 +57,10 @@
3.21 unsigned int num_channels()
3.22 { return 2; }
3.23
3.24 + I2c_channel *_get_channel(l4_addr_t addr, enum Clock_identifiers clock,
3.25 + Cpm_chip *cpm, uint32_t frequency)
3.26 + { return new I2c_x1600_channel(addr, clock, cpm, frequency); }
3.27 +
3.28 public:
3.29 explicit I2c_x1600_chip(l4_addr_t start, l4_addr_t end, Cpm_chip *cpm,
3.30 uint32_t frequency);
3.31 @@ -89,4 +103,6 @@
3.32
3.33 int x1600_i2c_failed(void *i2c_channel);
3.34
3.35 +void x1600_i2c_stop(void *i2c_channel);
3.36 +
3.37 EXTERN_C_END
4.1 --- a/pkg/devices/lib/i2c/src/common.cc Mon Oct 30 17:21:26 2023 +0100
4.2 +++ b/pkg/devices/lib/i2c/src/common.cc Mon Oct 30 17:22:43 2023 +0100
4.3 @@ -25,6 +25,8 @@
4.4 #include <l4/util/util.h>
4.5 #include <sys/time.h>
4.6
4.7 +
4.8 +
4.9 /* NOTE: The X1600 is very similar to the JZ4780 with the registers
4.10 renamed to I2C from SMB, with a few high speed registers, the
4.11 I2C_RINTST, I2C_TXFLR and I2C_RXFLR registers, and a few other
4.12 @@ -67,6 +69,10 @@
4.13 I2c_ack_call = 0x098, // I2C_ACKGC
4.14 I2c_enable_status = 0x09c, // I2C_ENBST (read-only)
4.15
4.16 + // JZ4780 variation...
4.17 +
4.18 + I2c_sda_hold_time_jz4780 = 0x0d0, // I2C_SDAHD
4.19 +
4.20 // X1600 only...
4.21
4.22 High_high_count = 0x024, // I2C_HHCNT
4.23 @@ -84,6 +90,9 @@
4.24
4.25 enum I2c_control_bits : unsigned
4.26 {
4.27 + I2c_stop_hold = 0x80, // STPHLD (JZ4780 only)
4.28 + I2c_no_stop_hold = 0x00, // absent STPHLD field
4.29 +
4.30 I2c_disable_slave = 0x40, // SLVDIS (slave disabled)
4.31 I2c_enable_restart = 0x20, // RESTART
4.32 I2c_master_10bit = 0x10, // MATP (read-only)
4.33 @@ -97,6 +106,9 @@
4.34 {
4.35 I2c_speed_standard = 1,
4.36 I2c_speed_fast = 2,
4.37 +
4.38 + // X1600 only...
4.39 +
4.40 I2c_speed_high = 3,
4.41 };
4.42
4.43 @@ -125,8 +137,13 @@
4.44
4.45 enum I2c_hold_control_bits : unsigned
4.46 {
4.47 - /* The hold enable flag has been removed since the JZ4780 and the hold time
4.48 - field widened. */
4.49 + // JZ4780...
4.50 +
4.51 + I2c_hold_enable = 0x100, // HDENB
4.52 + I2c_hold_disable = 0x000, // HDENB
4.53 + I2c_hold_mask_jz4780 = 0xff,
4.54 +
4.55 + // The X1600 loses the hold enable flag and widens the hold time field.
4.56
4.57 I2c_hold_mask = 0xffff,
4.58 };
4.59 @@ -138,9 +155,14 @@
4.60
4.61 enum I2c_command_bits : unsigned
4.62 {
4.63 + // X1600 only...
4.64 +
4.65 I2c_command_restart = 0x400, // RESTART: explicit restart before next byte
4.66 I2c_command_stop = 0x200, // STOP: explicit stop after next byte
4.67 I2c_command_no_stop = 0x000,
4.68 +
4.69 + // Common fields.
4.70 +
4.71 I2c_command_read = 0x100, // CMD
4.72 I2c_command_write = 0x000, // CMD
4.73 };
4.74 @@ -174,7 +196,7 @@
4.75 enum Clock_identifiers clock,
4.76 Cpm_chip *cpm,
4.77 uint32_t frequency)
4.78 -: _cpm(cpm), _frequency(frequency)
4.79 +: _clock(clock), _cpm(cpm), _frequency(frequency)
4.80 {
4.81 _regs = new Hw::Mmio_register_block<32>(start);
4.82 _cpm->start_clock(clock);
4.83 @@ -211,12 +233,10 @@
4.84 void
4.85 I2c_channel::set_frequency()
4.86 {
4.87 - // The APB clock (PCLK) is used to drive I2C transfers. Its value must be
4.88 - // obtained from the CPM unit. It is known as I2C_DEV_CLK here and is scaled
4.89 - // to kHz in order to keep the numbers easily representable, as is the bus
4.90 - // frequency.
4.91 + // The I2C device clock is known as I2C_DEV_CLK here and is scaled to kHz in
4.92 + // order to keep the numbers easily representable, as is the bus frequency.
4.93
4.94 - uint32_t i2c_dev_clk = _cpm->get_frequency(Clock_pclock) / 1000;
4.95 + uint32_t i2c_dev_clk = _cpm->get_frequency(_clock) / 1000;
4.96
4.97 // Note that this is not I2C_DEV_CLK but the actual I2C bus frequency.
4.98
4.99 @@ -224,19 +244,20 @@
4.100
4.101 // Select the appropriate speed.
4.102
4.103 - unsigned int speed = (i2c_clk <= 100) ? I2c_speed_standard
4.104 - : (i2c_clk <= 400 ? I2c_speed_fast
4.105 - : I2c_speed_high);
4.106 + unsigned int speed = (i2c_clk <= 100) ? I2c_speed_standard :
4.107 + (!high_speed_mode() || (i2c_clk <= 400)) ? I2c_speed_fast :
4.108 + I2c_speed_high;
4.109
4.110 // NOTE: Permit broader configuration elsewhere.
4.111
4.112 _regs[I2c_control] = (speed << I2c_speed_bit) |
4.113 I2c_disable_slave |
4.114 I2c_enable_restart |
4.115 - I2c_enable_master;
4.116 + I2c_enable_master |
4.117 + (stop_hold() ? I2c_stop_hold : I2c_no_stop_hold);
4.118
4.119 - // According to the programming manual, if the PCLK period is T{I2C_DEV_CLK}
4.120 - // then the I2C clock period is...
4.121 + // According to the programming manual, if the device clock period is
4.122 + // T{I2C_DEV_CLK} then the I2C clock period is...
4.123
4.124 // T{SCL} = T{SCL_high} + T{SCL_low}
4.125
4.126 @@ -294,8 +315,6 @@
4.127
4.128 uint32_t high_reg, low_reg;
4.129 uint32_t high_count, low_count;
4.130 - int32_t hold_count;
4.131 - uint32_t setup_count;
4.132
4.133 // Level hold times:
4.134
4.135 @@ -314,7 +333,7 @@
4.136 low_reg = Std_low_count;
4.137 high_reg = Std_high_count;
4.138 }
4.139 - else if (i2c_clk <= 400) // 400 kHz
4.140 + else if (!high_speed_mode() || (i2c_clk <= 400)) // 400 kHz
4.141 {
4.142 low_count = (i2c_dev_clk * 13) / (i2c_clk * 19) - 1;
4.143 high_count = (i2c_dev_clk * 6) / (i2c_clk * 19) - 8;
4.144 @@ -353,12 +372,13 @@
4.145 // Since the device clock is in kHz (scaled down by 1000) and the times are
4.146 // given in ns (scaled up by 1000000000), a division of 1000000 is introduced.
4.147
4.148 - hold_count = (i2c_dev_clk * 300) / 1000000 - 1;
4.149 + int32_t hold_count = (i2c_dev_clk * 300) / 1000000 - 1;
4.150 + uint32_t hold_mask = (uint32_t) (hold_enable() ? I2c_hold_mask_jz4780 : I2c_hold_mask);
4.151 + uint32_t hold_reg = hold_enable() ? I2c_sda_hold_time_jz4780 : I2c_sda_hold_time;
4.152
4.153 - _regs[I2c_sda_hold_time] = (_regs[I2c_sda_hold_time] & ~I2c_hold_mask) |
4.154 - (hold_count < 0 ? 0
4.155 - : (hold_count < (int) I2c_hold_mask ? (uint32_t) hold_count
4.156 - : I2c_hold_mask));
4.157 + _regs[hold_reg] = ((hold_count >= 0) && hold_enable() ? I2c_hold_enable : I2c_hold_disable) |
4.158 + (hold_count < 0 ? 0 :
4.159 + (uint32_t) hold_count < hold_mask ? (uint32_t) hold_count : hold_mask);
4.160
4.161 // I2C_SDASU is apparently not used in master mode.
4.162
4.163 @@ -366,15 +386,16 @@
4.164 // I2CSDASU = T{delay} / T{I2C_DEV_CLK} + 1
4.165 // I2CSDASU = I2C_DEV_CLK * T{delay} + 1
4.166
4.167 + uint32_t setup_count;
4.168 +
4.169 if (i2c_clk <= 100)
4.170 setup_count = (i2c_dev_clk * 250) / 1000000 + 1;
4.171 - else if (i2c_clk <= 400)
4.172 + else if (!high_speed_mode() || (i2c_clk <= 400))
4.173 setup_count = (i2c_dev_clk * 100) / 1000000 + 1;
4.174 else
4.175 setup_count = (i2c_dev_clk * 50) / 1000000 + 1;
4.176
4.177 - _regs[I2c_sda_setup_time] = (_regs[I2c_sda_setup_time] & ~I2c_setup_mask) |
4.178 - (setup_count < I2c_setup_mask ? setup_count : I2c_setup_mask);
4.179 + _regs[I2c_sda_setup_time] = (setup_count < I2c_setup_mask ? setup_count : I2c_setup_mask);
4.180 }
4.181
4.182 // Set the target address and enable transfer.
4.183 @@ -501,6 +522,18 @@
4.184
4.185
4.186
4.187 +// Handle differences in stop condition management, producing the stop command
4.188 +// field for the X1600.
4.189 +
4.190 +uint32_t
4.191 +I2c_channel::stop_command()
4.192 +{
4.193 + if (stop_hold())
4.194 + return 0;
4.195 +
4.196 + return _stop && (_reqpos == _total - 1) ? I2c_command_stop : I2c_command_no_stop;
4.197 +}
4.198 +
4.199 // Send read commands for empty queue entries.
4.200
4.201 void
4.202 @@ -524,13 +557,16 @@
4.203
4.204 while (can_queue && can_send())
4.205 {
4.206 - uint32_t stop = _stop && (_reqpos == _total - 1) ? I2c_command_stop : I2c_command_no_stop;
4.207 -
4.208 - _regs[I2c_data_command] = I2c_command_read | stop;
4.209 + _regs[I2c_data_command] = I2c_command_read | stop_command();
4.210 _reqpos++;
4.211 can_queue--;
4.212 }
4.213
4.214 + /* Extra read request on JZ4780. */
4.215 +
4.216 + if (stop_hold() && _stop)
4.217 + stop();
4.218 +
4.219 // Update the threshold to be notified of any reduced remaining amount.
4.220
4.221 set_read_threshold();
4.222 @@ -551,9 +587,7 @@
4.223
4.224 while (can_queue && can_send())
4.225 {
4.226 - uint32_t stop = _stop && (_reqpos == _total - 1) ? I2c_command_stop : I2c_command_no_stop;
4.227 -
4.228 - _regs[I2c_data_command] = I2c_command_write | _buf[_reqpos] | stop;
4.229 + _regs[I2c_data_command] = I2c_command_write | _buf[_reqpos] | stop_command();
4.230 _reqpos++;
4.231 can_queue--;
4.232 }
4.233 @@ -675,6 +709,7 @@
4.234 void
4.235 I2c_channel::stop()
4.236 {
4.237 + _regs[I2c_control] = _regs[I2c_control] & ~I2c_stop_hold;
4.238 }
4.239
4.240
4.241 @@ -700,7 +735,7 @@
4.242 enum Clock_identifiers clocks[] = {Clock_i2c0, Clock_i2c1, Clock_i2c2, Clock_i2c3, Clock_i2c4};
4.243
4.244 if (channel < num_channels())
4.245 - return new I2c_channel(block, clocks[channel], _cpm, _frequency);
4.246 + return _get_channel(block, clocks[channel], _cpm, _frequency);
4.247 else
4.248 throw -L4_EINVAL;
4.249 }
5.1 --- a/pkg/devices/lib/i2c/src/jz4780.cc Mon Oct 30 17:21:26 2023 +0100
5.2 +++ b/pkg/devices/lib/i2c/src/jz4780.cc Mon Oct 30 17:22:43 2023 +0100
5.3 @@ -128,3 +128,8 @@
5.4 {
5.5 return static_cast<I2c_jz4780_channel *>(i2c_channel)->failed();
5.6 }
5.7 +
5.8 +void jz4780_i2c_stop(void *i2c_channel)
5.9 +{
5.10 + static_cast<I2c_jz4780_channel *>(i2c_channel)->stop();
5.11 +}
6.1 --- a/pkg/devices/lib/i2c/src/x1600.cc Mon Oct 30 17:21:26 2023 +0100
6.2 +++ b/pkg/devices/lib/i2c/src/x1600.cc Mon Oct 30 17:22:43 2023 +0100
6.3 @@ -114,3 +114,8 @@
6.4 {
6.5 return static_cast<I2c_x1600_channel *>(i2c_channel)->failed();
6.6 }
6.7 +
6.8 +void x1600_i2c_stop(void *i2c_channel)
6.9 +{
6.10 + static_cast<I2c_x1600_channel *>(i2c_channel)->stop();
6.11 +}
7.1 --- a/pkg/landfall-examples/ci20_i2c/ci20_i2c.c Mon Oct 30 17:21:26 2023 +0100
7.2 +++ b/pkg/landfall-examples/ci20_i2c/ci20_i2c.c Mon Oct 30 17:22:43 2023 +0100
7.3 @@ -62,7 +62,7 @@
7.4 return start - index;
7.5 }
7.6
7.7 -static long i2c_read(void *i2c_channel, uint8_t *buf, unsigned length,
7.8 +static int i2c_read(void *i2c_channel, uint8_t *buf, unsigned length,
7.9 int stop, l4_cap_idx_t irqcap)
7.10 {
7.11 l4_msgtag_t tag;
7.12 @@ -74,18 +74,21 @@
7.13 tag = l4_irq_receive(irqcap, l4_timeout(L4_IPC_TIMEOUT_NEVER, l4_timeout_from_us(1000)));
7.14
7.15 if (l4_ipc_error(tag, l4_utcb()))
7.16 - return 0;
7.17 + break;
7.18
7.19 if (jz4780_i2c_failed(i2c_channel))
7.20 - return 0;
7.21 + break;
7.22
7.23 jz4780_i2c_read(i2c_channel);
7.24 }
7.25
7.26 + if (stop)
7.27 + jz4780_i2c_stop(i2c_channel);
7.28 +
7.29 return jz4780_i2c_have_read(i2c_channel);
7.30 }
7.31
7.32 -static long i2c_write(void *i2c_channel, uint8_t *buf, unsigned length,
7.33 +static int i2c_write(void *i2c_channel, uint8_t *buf, unsigned length,
7.34 int stop, l4_cap_idx_t irqcap)
7.35 {
7.36 l4_msgtag_t tag;
7.37 @@ -98,14 +101,17 @@
7.38 tag = l4_irq_receive(irqcap, l4_timeout(L4_IPC_TIMEOUT_NEVER, l4_timeout_from_us(1000)));
7.39
7.40 if ((err = l4_ipc_error(tag, l4_utcb())))
7.41 - return 0;
7.42 + break;
7.43
7.44 if (jz4780_i2c_failed(i2c_channel))
7.45 - return 0;
7.46 + break;
7.47
7.48 jz4780_i2c_write(i2c_channel);
7.49 }
7.50
7.51 + if (stop)
7.52 + jz4780_i2c_stop(i2c_channel);
7.53 +
7.54 return jz4780_i2c_have_written(i2c_channel);
7.55 }
7.56