1.1 --- a/pkg/devices/lib/i2c/src/common.cc Mon Oct 30 17:21:26 2023 +0100
1.2 +++ b/pkg/devices/lib/i2c/src/common.cc Mon Oct 30 17:22:43 2023 +0100
1.3 @@ -25,6 +25,8 @@
1.4 #include <l4/util/util.h>
1.5 #include <sys/time.h>
1.6
1.7 +
1.8 +
1.9 /* NOTE: The X1600 is very similar to the JZ4780 with the registers
1.10 renamed to I2C from SMB, with a few high speed registers, the
1.11 I2C_RINTST, I2C_TXFLR and I2C_RXFLR registers, and a few other
1.12 @@ -67,6 +69,10 @@
1.13 I2c_ack_call = 0x098, // I2C_ACKGC
1.14 I2c_enable_status = 0x09c, // I2C_ENBST (read-only)
1.15
1.16 + // JZ4780 variation...
1.17 +
1.18 + I2c_sda_hold_time_jz4780 = 0x0d0, // I2C_SDAHD
1.19 +
1.20 // X1600 only...
1.21
1.22 High_high_count = 0x024, // I2C_HHCNT
1.23 @@ -84,6 +90,9 @@
1.24
1.25 enum I2c_control_bits : unsigned
1.26 {
1.27 + I2c_stop_hold = 0x80, // STPHLD (JZ4780 only)
1.28 + I2c_no_stop_hold = 0x00, // absent STPHLD field
1.29 +
1.30 I2c_disable_slave = 0x40, // SLVDIS (slave disabled)
1.31 I2c_enable_restart = 0x20, // RESTART
1.32 I2c_master_10bit = 0x10, // MATP (read-only)
1.33 @@ -97,6 +106,9 @@
1.34 {
1.35 I2c_speed_standard = 1,
1.36 I2c_speed_fast = 2,
1.37 +
1.38 + // X1600 only...
1.39 +
1.40 I2c_speed_high = 3,
1.41 };
1.42
1.43 @@ -125,8 +137,13 @@
1.44
1.45 enum I2c_hold_control_bits : unsigned
1.46 {
1.47 - /* The hold enable flag has been removed since the JZ4780 and the hold time
1.48 - field widened. */
1.49 + // JZ4780...
1.50 +
1.51 + I2c_hold_enable = 0x100, // HDENB
1.52 + I2c_hold_disable = 0x000, // HDENB
1.53 + I2c_hold_mask_jz4780 = 0xff,
1.54 +
1.55 + // The X1600 loses the hold enable flag and widens the hold time field.
1.56
1.57 I2c_hold_mask = 0xffff,
1.58 };
1.59 @@ -138,9 +155,14 @@
1.60
1.61 enum I2c_command_bits : unsigned
1.62 {
1.63 + // X1600 only...
1.64 +
1.65 I2c_command_restart = 0x400, // RESTART: explicit restart before next byte
1.66 I2c_command_stop = 0x200, // STOP: explicit stop after next byte
1.67 I2c_command_no_stop = 0x000,
1.68 +
1.69 + // Common fields.
1.70 +
1.71 I2c_command_read = 0x100, // CMD
1.72 I2c_command_write = 0x000, // CMD
1.73 };
1.74 @@ -174,7 +196,7 @@
1.75 enum Clock_identifiers clock,
1.76 Cpm_chip *cpm,
1.77 uint32_t frequency)
1.78 -: _cpm(cpm), _frequency(frequency)
1.79 +: _clock(clock), _cpm(cpm), _frequency(frequency)
1.80 {
1.81 _regs = new Hw::Mmio_register_block<32>(start);
1.82 _cpm->start_clock(clock);
1.83 @@ -211,12 +233,10 @@
1.84 void
1.85 I2c_channel::set_frequency()
1.86 {
1.87 - // The APB clock (PCLK) is used to drive I2C transfers. Its value must be
1.88 - // obtained from the CPM unit. It is known as I2C_DEV_CLK here and is scaled
1.89 - // to kHz in order to keep the numbers easily representable, as is the bus
1.90 - // frequency.
1.91 + // The I2C device clock is known as I2C_DEV_CLK here and is scaled to kHz in
1.92 + // order to keep the numbers easily representable, as is the bus frequency.
1.93
1.94 - uint32_t i2c_dev_clk = _cpm->get_frequency(Clock_pclock) / 1000;
1.95 + uint32_t i2c_dev_clk = _cpm->get_frequency(_clock) / 1000;
1.96
1.97 // Note that this is not I2C_DEV_CLK but the actual I2C bus frequency.
1.98
1.99 @@ -224,19 +244,20 @@
1.100
1.101 // Select the appropriate speed.
1.102
1.103 - unsigned int speed = (i2c_clk <= 100) ? I2c_speed_standard
1.104 - : (i2c_clk <= 400 ? I2c_speed_fast
1.105 - : I2c_speed_high);
1.106 + unsigned int speed = (i2c_clk <= 100) ? I2c_speed_standard :
1.107 + (!high_speed_mode() || (i2c_clk <= 400)) ? I2c_speed_fast :
1.108 + I2c_speed_high;
1.109
1.110 // NOTE: Permit broader configuration elsewhere.
1.111
1.112 _regs[I2c_control] = (speed << I2c_speed_bit) |
1.113 I2c_disable_slave |
1.114 I2c_enable_restart |
1.115 - I2c_enable_master;
1.116 + I2c_enable_master |
1.117 + (stop_hold() ? I2c_stop_hold : I2c_no_stop_hold);
1.118
1.119 - // According to the programming manual, if the PCLK period is T{I2C_DEV_CLK}
1.120 - // then the I2C clock period is...
1.121 + // According to the programming manual, if the device clock period is
1.122 + // T{I2C_DEV_CLK} then the I2C clock period is...
1.123
1.124 // T{SCL} = T{SCL_high} + T{SCL_low}
1.125
1.126 @@ -294,8 +315,6 @@
1.127
1.128 uint32_t high_reg, low_reg;
1.129 uint32_t high_count, low_count;
1.130 - int32_t hold_count;
1.131 - uint32_t setup_count;
1.132
1.133 // Level hold times:
1.134
1.135 @@ -314,7 +333,7 @@
1.136 low_reg = Std_low_count;
1.137 high_reg = Std_high_count;
1.138 }
1.139 - else if (i2c_clk <= 400) // 400 kHz
1.140 + else if (!high_speed_mode() || (i2c_clk <= 400)) // 400 kHz
1.141 {
1.142 low_count = (i2c_dev_clk * 13) / (i2c_clk * 19) - 1;
1.143 high_count = (i2c_dev_clk * 6) / (i2c_clk * 19) - 8;
1.144 @@ -353,12 +372,13 @@
1.145 // Since the device clock is in kHz (scaled down by 1000) and the times are
1.146 // given in ns (scaled up by 1000000000), a division of 1000000 is introduced.
1.147
1.148 - hold_count = (i2c_dev_clk * 300) / 1000000 - 1;
1.149 + int32_t hold_count = (i2c_dev_clk * 300) / 1000000 - 1;
1.150 + uint32_t hold_mask = (uint32_t) (hold_enable() ? I2c_hold_mask_jz4780 : I2c_hold_mask);
1.151 + uint32_t hold_reg = hold_enable() ? I2c_sda_hold_time_jz4780 : I2c_sda_hold_time;
1.152
1.153 - _regs[I2c_sda_hold_time] = (_regs[I2c_sda_hold_time] & ~I2c_hold_mask) |
1.154 - (hold_count < 0 ? 0
1.155 - : (hold_count < (int) I2c_hold_mask ? (uint32_t) hold_count
1.156 - : I2c_hold_mask));
1.157 + _regs[hold_reg] = ((hold_count >= 0) && hold_enable() ? I2c_hold_enable : I2c_hold_disable) |
1.158 + (hold_count < 0 ? 0 :
1.159 + (uint32_t) hold_count < hold_mask ? (uint32_t) hold_count : hold_mask);
1.160
1.161 // I2C_SDASU is apparently not used in master mode.
1.162
1.163 @@ -366,15 +386,16 @@
1.164 // I2CSDASU = T{delay} / T{I2C_DEV_CLK} + 1
1.165 // I2CSDASU = I2C_DEV_CLK * T{delay} + 1
1.166
1.167 + uint32_t setup_count;
1.168 +
1.169 if (i2c_clk <= 100)
1.170 setup_count = (i2c_dev_clk * 250) / 1000000 + 1;
1.171 - else if (i2c_clk <= 400)
1.172 + else if (!high_speed_mode() || (i2c_clk <= 400))
1.173 setup_count = (i2c_dev_clk * 100) / 1000000 + 1;
1.174 else
1.175 setup_count = (i2c_dev_clk * 50) / 1000000 + 1;
1.176
1.177 - _regs[I2c_sda_setup_time] = (_regs[I2c_sda_setup_time] & ~I2c_setup_mask) |
1.178 - (setup_count < I2c_setup_mask ? setup_count : I2c_setup_mask);
1.179 + _regs[I2c_sda_setup_time] = (setup_count < I2c_setup_mask ? setup_count : I2c_setup_mask);
1.180 }
1.181
1.182 // Set the target address and enable transfer.
1.183 @@ -501,6 +522,18 @@
1.184
1.185
1.186
1.187 +// Handle differences in stop condition management, producing the stop command
1.188 +// field for the X1600.
1.189 +
1.190 +uint32_t
1.191 +I2c_channel::stop_command()
1.192 +{
1.193 + if (stop_hold())
1.194 + return 0;
1.195 +
1.196 + return _stop && (_reqpos == _total - 1) ? I2c_command_stop : I2c_command_no_stop;
1.197 +}
1.198 +
1.199 // Send read commands for empty queue entries.
1.200
1.201 void
1.202 @@ -524,13 +557,16 @@
1.203
1.204 while (can_queue && can_send())
1.205 {
1.206 - uint32_t stop = _stop && (_reqpos == _total - 1) ? I2c_command_stop : I2c_command_no_stop;
1.207 -
1.208 - _regs[I2c_data_command] = I2c_command_read | stop;
1.209 + _regs[I2c_data_command] = I2c_command_read | stop_command();
1.210 _reqpos++;
1.211 can_queue--;
1.212 }
1.213
1.214 + /* Extra read request on JZ4780. */
1.215 +
1.216 + if (stop_hold() && _stop)
1.217 + stop();
1.218 +
1.219 // Update the threshold to be notified of any reduced remaining amount.
1.220
1.221 set_read_threshold();
1.222 @@ -551,9 +587,7 @@
1.223
1.224 while (can_queue && can_send())
1.225 {
1.226 - uint32_t stop = _stop && (_reqpos == _total - 1) ? I2c_command_stop : I2c_command_no_stop;
1.227 -
1.228 - _regs[I2c_data_command] = I2c_command_write | _buf[_reqpos] | stop;
1.229 + _regs[I2c_data_command] = I2c_command_write | _buf[_reqpos] | stop_command();
1.230 _reqpos++;
1.231 can_queue--;
1.232 }
1.233 @@ -675,6 +709,7 @@
1.234 void
1.235 I2c_channel::stop()
1.236 {
1.237 + _regs[I2c_control] = _regs[I2c_control] & ~I2c_stop_hold;
1.238 }
1.239
1.240
1.241 @@ -700,7 +735,7 @@
1.242 enum Clock_identifiers clocks[] = {Clock_i2c0, Clock_i2c1, Clock_i2c2, Clock_i2c3, Clock_i2c4};
1.243
1.244 if (channel < num_channels())
1.245 - return new I2c_channel(block, clocks[channel], _cpm, _frequency);
1.246 + return _get_channel(block, clocks[channel], _cpm, _frequency);
1.247 else
1.248 throw -L4_EINVAL;
1.249 }