1.1 --- a/pkg/devices/lib/i2c/include/i2c-jz4730.h Sun Jan 03 17:53:56 2021 +0100
1.2 +++ b/pkg/devices/lib/i2c/include/i2c-jz4730.h Wed Jan 06 00:46:51 2021 +0100
1.3 @@ -39,10 +39,11 @@
1.4 Hw::Register_block<32> _regs;
1.5 Cpm_jz4730_chip *_cpm;
1.6 uint32_t _frequency;
1.7 + l4_cap_idx_t _irq=L4_INVALID_CAP;
1.8
1.9 public:
1.10 I2c_jz4730_channel(l4_addr_t start, Cpm_jz4730_chip *cpm,
1.11 - uint32_t frequency);
1.12 + uint32_t frequency, l4_cap_idx_t irq);
1.13
1.14 void disable();
1.15 void enable();
1.16 @@ -55,20 +56,24 @@
1.17
1.18 // Transaction control.
1.19
1.20 - void set_address(uint8_t address, bool read);
1.21 + bool set_address(uint8_t address, bool read);
1.22
1.23 - void request_next();
1.24 + void clear_next();
1.25 void send_next();
1.26 void signal_last();
1.27
1.28 void start();
1.29 void stop();
1.30
1.31 + bool wait_for_irq(unsigned int timeout);
1.32 +
1.33 // Specific status conditions.
1.34
1.35 + bool busy();
1.36 bool data_valid();
1.37 bool nack();
1.38 bool transferred();
1.39 + bool transferring();
1.40 };
1.41
1.42 // I2C device control.
1.43 @@ -84,7 +89,7 @@
1.44 I2c_jz4730_chip(l4_addr_t start, l4_addr_t end, Cpm_jz4730_chip *cpm,
1.45 uint32_t frequency);
1.46
1.47 - I2c_jz4730_channel *get_channel(uint8_t channel);
1.48 + I2c_jz4730_channel *get_channel(uint8_t channel, l4_cap_idx_t irq);
1.49 };
1.50
1.51 #endif /* __cplusplus */
1.52 @@ -98,7 +103,7 @@
1.53 void *jz4730_i2c_init(l4_addr_t start, l4_addr_t end, void *cpm,
1.54 uint32_t frequency);
1.55
1.56 -void *jz4730_i2c_get_channel(void *i2c, uint8_t channel);
1.57 +void *jz4730_i2c_get_channel(void *i2c, uint8_t channel, l4_cap_idx_t irq);
1.58
1.59 void jz4730_i2c_disable(void *i2c_channel);
1.60
2.1 --- a/pkg/devices/lib/i2c/src/jz4730.cc Sun Jan 03 17:53:56 2021 +0100
2.2 +++ b/pkg/devices/lib/i2c/src/jz4730.cc Wed Jan 06 00:46:51 2021 +0100
2.3 @@ -23,6 +23,8 @@
2.4 #include <l4/devices/hw_mmio_register_block.h>
2.5
2.6 #include <l4/sys/icu.h>
2.7 +#include <l4/sys/ipc.h>
2.8 +#include <l4/sys/irq.h>
2.9 #include <l4/util/util.h>
2.10
2.11 #include <cstdio>
2.12 @@ -73,8 +75,9 @@
2.13
2.14 I2c_jz4730_channel::I2c_jz4730_channel(l4_addr_t start,
2.15 Cpm_jz4730_chip *cpm,
2.16 - uint32_t frequency)
2.17 -: _cpm(cpm), _frequency(frequency)
2.18 + uint32_t frequency,
2.19 + l4_cap_idx_t irq)
2.20 +: _cpm(cpm), _frequency(frequency), _irq(irq)
2.21 {
2.22 _regs = new Hw::Mmio_register_block<32>(start);
2.23 }
2.24 @@ -132,20 +135,34 @@
2.25
2.26 // Present the address on the bus.
2.27
2.28 -void
2.29 +bool
2.30 I2c_jz4730_channel::set_address(uint8_t address, bool read)
2.31 {
2.32 + unsigned int limit = 10;
2.33 +
2.34 + do
2.35 + {
2.36 + if (!wait_for_irq(1000) && !(--limit))
2.37 + return false;
2.38 + }
2.39 + while (busy());
2.40 +
2.41 start();
2.42
2.43 _regs[I2c_data] = (address << 1) | (read ? 1 : 0);
2.44 - while (nack());
2.45
2.46 send_next();
2.47
2.48 - if (read)
2.49 - while ((data_valid() || !transferred()) && !nack());
2.50 - else
2.51 - while (data_valid() && !nack());
2.52 + return true;
2.53 +}
2.54 +
2.55 +// Wait up to the given timeout (in microseconds) for an interrupt request,
2.56 +// returning true if one was delivered.
2.57 +
2.58 +bool
2.59 +I2c_jz4730_channel::wait_for_irq(unsigned int timeout)
2.60 +{
2.61 + return !l4_error(l4_irq_receive(_irq, l4_timeout(L4_IPC_TIMEOUT_NEVER, l4util_micros2l4to(timeout))));
2.62 }
2.63
2.64 // Read data from the bus.
2.65 @@ -155,27 +172,39 @@
2.66 {
2.67 unsigned int nread = 0;
2.68
2.69 - set_address(address, true);
2.70 + if (!set_address(address, true))
2.71 + return 0;
2.72 +
2.73 + do
2.74 + {
2.75 + if (!wait_for_irq(1000000))
2.76 + printf("start (no irq): status = %x\n", (uint32_t) _regs[I2c_status]);
2.77 + }
2.78 + while (transferring() || (!data_valid() && !nack()));
2.79
2.80 - if (!nack())
2.81 + while (nread < length)
2.82 {
2.83 - if (length == 1)
2.84 + do
2.85 + {
2.86 + if (!wait_for_irq(1000000))
2.87 + {
2.88 + stop();
2.89 + return nread;
2.90 + }
2.91 + }
2.92 + while (!data_valid() && !nack());
2.93 +
2.94 + if (nack())
2.95 + break;
2.96 +
2.97 + if ((!nread && (length == 1)) || (nread == length - 2))
2.98 signal_last();
2.99
2.100 - while (nread < length)
2.101 - {
2.102 - while (!data_valid());
2.103 -
2.104 - if (nread == length - 2)
2.105 - signal_last();
2.106 -
2.107 - buf[nread++] = _regs[I2c_data];
2.108 - request_next();
2.109 - }
2.110 + buf[nread++] = _regs[I2c_data];
2.111 + clear_next();
2.112 }
2.113
2.114 stop();
2.115 -
2.116 return nread;
2.117 }
2.118
2.119 @@ -186,18 +215,44 @@
2.120 {
2.121 unsigned int nwritten = 0;
2.122
2.123 - set_address(address, false);
2.124 + if (!set_address(address, false))
2.125 + return 0;
2.126 +
2.127 + do
2.128 + {
2.129 + if (!wait_for_irq(1000000))
2.130 + {
2.131 + printf("write (no irq): status = %x\n", (uint32_t) _regs[I2c_status]);
2.132 + stop();
2.133 + return nwritten;
2.134 + }
2.135 + }
2.136 + while (data_valid() && !nack());
2.137
2.138 while ((nwritten < length) && !nack())
2.139 {
2.140 _regs[I2c_data] = buf[nwritten++];
2.141 send_next();
2.142
2.143 + do
2.144 + {
2.145 + if (!wait_for_irq(1000000))
2.146 + {
2.147 + printf("write (no irq): status = %x\n", (uint32_t) _regs[I2c_status]);
2.148 + stop();
2.149 + return nwritten;
2.150 + }
2.151 + }
2.152 while (data_valid() && !nack());
2.153 }
2.154
2.155 stop();
2.156
2.157 + do
2.158 + {
2.159 + if (!wait_for_irq(1000000))
2.160 + break;
2.161 + }
2.162 while (!transferred());
2.163
2.164 return nwritten;
2.165 @@ -214,7 +269,7 @@
2.166 // Request the next byte by clearing the data validity flag.
2.167
2.168 void
2.169 -I2c_jz4730_channel::request_next()
2.170 +I2c_jz4730_channel::clear_next()
2.171 {
2.172 _regs[I2c_status] = _regs[I2c_status] & ~I2c_status_data_valid;
2.173 }
2.174 @@ -243,6 +298,22 @@
2.175 _regs[I2c_control] = _regs[I2c_control] | I2c_control_nack;
2.176 }
2.177
2.178 +// Test for bus activity.
2.179 +
2.180 +bool
2.181 +I2c_jz4730_channel::busy()
2.182 +{
2.183 + return (_regs[I2c_status] & I2c_status_busy) ? true : false;
2.184 +}
2.185 +
2.186 +// Test for transfer activity.
2.187 +
2.188 +bool
2.189 +I2c_jz4730_channel::transferring()
2.190 +{
2.191 + return (_regs[I2c_status] & I2c_status_buffer_nempty) ? true : false;
2.192 +}
2.193 +
2.194 // Test for write transfer completion.
2.195
2.196 bool
2.197 @@ -281,10 +352,10 @@
2.198 // Obtain a channel object. Only one channel is supported.
2.199
2.200 I2c_jz4730_channel *
2.201 -I2c_jz4730_chip::get_channel(uint8_t channel)
2.202 +I2c_jz4730_chip::get_channel(uint8_t channel, l4_cap_idx_t irq)
2.203 {
2.204 if (channel == 0)
2.205 - return new I2c_jz4730_channel(_start, _cpm, _frequency);
2.206 + return new I2c_jz4730_channel(_start, _cpm, _frequency, irq);
2.207 else
2.208 throw -L4_EINVAL;
2.209 }
2.210 @@ -298,9 +369,9 @@
2.211 return (void *) new I2c_jz4730_chip(start, end, static_cast<Cpm_jz4730_chip *>(cpm), frequency);
2.212 }
2.213
2.214 -void *jz4730_i2c_get_channel(void *i2c, uint8_t channel)
2.215 +void *jz4730_i2c_get_channel(void *i2c, uint8_t channel, l4_cap_idx_t irq)
2.216 {
2.217 - return static_cast<I2c_jz4730_chip *>(i2c)->get_channel(channel);
2.218 + return static_cast<I2c_jz4730_chip *>(i2c)->get_channel(channel, irq);
2.219 }
2.220
2.221 void jz4730_i2c_disable(void *i2c_channel)
3.1 --- a/pkg/landfall-examples/letux400_i2c/letux400_i2c.cc Sun Jan 03 17:53:56 2021 +0100
3.2 +++ b/pkg/landfall-examples/letux400_i2c/letux400_i2c.cc Wed Jan 06 00:46:51 2021 +0100
3.3 @@ -23,10 +23,27 @@
3.4 #include <l4/devices/i2c-jz4730.h>
3.5 #include <l4/devices/memory.h>
3.6
3.7 +#include <l4/re/c/util/cap_alloc.h>
3.8 +#include <l4/sys/factory.h>
3.9 +#include <l4/sys/icu.h>
3.10 +#include <l4/sys/irq.h>
3.11 +#include <l4/sys/rcv_endpoint.h>
3.12 +
3.13 #include <stdio.h>
3.14 +#include <unistd.h>
3.15
3.16
3.17
3.18 +/* Device and resource discovery. */
3.19 +
3.20 +static long item_in_range(long start, long end, long index)
3.21 +{
3.22 + if (start < end)
3.23 + return start + index;
3.24 + else
3.25 + return start - index;
3.26 +}
3.27 +
3.28 /* Scan the I2C bus by performing speculative reads from each device address. */
3.29
3.30 static void i2c_scan(void *i2c_channel)
3.31 @@ -87,6 +104,71 @@
3.32 void *cpm;
3.33 void *i2c, *i2c0;
3.34
3.35 + /* Interrupts. */
3.36 +
3.37 + l4_uint32_t i2c_irq_start = 0, i2c_irq_end = 0;
3.38 + l4_cap_idx_t icucap, irq0cap;
3.39 +
3.40 + /* Obtain resource details describing the interrupt for I2C channel 0. */
3.41 +
3.42 + printf("Access IRQ...\n");
3.43 +
3.44 + if (get_irq("jz4730-i2c", &i2c_irq_start, &i2c_irq_end) < 0)
3.45 + return 1;
3.46 +
3.47 + printf("IRQ range at %d...%d.\n", i2c_irq_start, i2c_irq_end);
3.48 +
3.49 + /* Obtain capabilities for the interrupt controller and an interrupt. */
3.50 +
3.51 + irq0cap = l4re_util_cap_alloc();
3.52 + icucap = l4re_env_get_cap("icu");
3.53 +
3.54 + if (l4_is_invalid_cap(icucap))
3.55 + {
3.56 + printf("No 'icu' capability available in the virtual bus.\n");
3.57 + return 1;
3.58 + }
3.59 +
3.60 + if (l4_is_invalid_cap(irq0cap))
3.61 + {
3.62 + printf("Capabilities not available for interrupts.\n");
3.63 + return 1;
3.64 + }
3.65 +
3.66 + /* Create interrupt objects. */
3.67 +
3.68 + long err;
3.69 +
3.70 + err = l4_error(l4_factory_create_irq(l4re_global_env->factory, irq0cap));
3.71 +
3.72 + if (err)
3.73 + {
3.74 + printf("Could not create IRQ object: %lx\n", err);
3.75 + return 1;
3.76 + }
3.77 +
3.78 + /* Bind interrupt objects to IRQ numbers. */
3.79 +
3.80 + err = l4_error(l4_icu_bind(icucap,
3.81 + item_in_range(i2c_irq_start, i2c_irq_end, 0),
3.82 + irq0cap));
3.83 +
3.84 + if (err)
3.85 + {
3.86 + printf("Could not bind IRQ to the ICU: %ld\n", err);
3.87 + return 1;
3.88 + }
3.89 +
3.90 + /* Attach ourselves to the interrupt handler. */
3.91 +
3.92 + err = l4_error(l4_rcv_ep_bind_thread(irq0cap, l4re_env()->main_thread, 0));
3.93 +
3.94 + if (err)
3.95 + {
3.96 + printf("Could not attach to IRQs: %ld\n", err);
3.97 + return 1;
3.98 + }
3.99 +
3.100 /* Peripheral memory. */
3.101
3.102 l4_addr_t cpm_base = 0, cpm_base_end = 0;
3.103 @@ -112,7 +194,7 @@
3.104
3.105 cpm = jz4730_cpm_init(cpm_base);
3.106 i2c = jz4730_i2c_init(i2c_base, i2c_base_end, cpm, 100000); /* 100 kHz */
3.107 - i2c0 = jz4730_i2c_get_channel(i2c, 0);
3.108 + i2c0 = jz4730_i2c_get_channel(i2c, 0, irq0cap);
3.109
3.110 /* Enable I2C. */
3.111
3.112 @@ -128,30 +210,43 @@
3.113
3.114 printf("Written: %d\n", nwritten);
3.115
3.116 - /* Issue selection of device register 0. */
3.117 + do
3.118 + {
3.119 + /* Issue selection of device register 0. */
3.120
3.121 - buf[0] = 0;
3.122 - nwritten = jz4730_i2c_write(i2c0, 0x51, buf, 1);
3.123 + buf[0] = 0;
3.124 + nwritten = jz4730_i2c_write(i2c0, 0x51, buf, 1);
3.125 +
3.126 + printf("Written: %d\n", nwritten);
3.127
3.128 - printf("Written: %d\n", nwritten);
3.129 + /* Read the contents of 16 registers. */
3.130 +
3.131 + unsigned int nread = jz4730_i2c_read(i2c0, 0x51, buf, 16);
3.132
3.133 - /* Read the contents of 16 registers. */
3.134 -
3.135 - unsigned int nread = jz4730_i2c_read(i2c0, 0x51, buf, 16);
3.136 + printf("Read: %d\n", nread);
3.137 + for (unsigned int i = 0; i < nread; i++)
3.138 + printf("%02x ", buf[i]);
3.139 + printf("\n");
3.140
3.141 - printf("Read: %d\n", nread);
3.142 - for (unsigned int i = 0; i < nread; i++)
3.143 - printf("%02x ", buf[i]);
3.144 - printf("\n");
3.145 + /* Show the interpreted date and time. */
3.146 +
3.147 + rtc_datetime(buf);
3.148
3.149 - /* Show the interpreted date and time. */
3.150 + /* Scan the bus. */
3.151 +
3.152 + printf("Scan I2C0...\n");
3.153 + i2c_scan(i2c0);
3.154
3.155 - rtc_datetime(buf);
3.156 + sleep(5);
3.157 + }
3.158 + while(1);
3.159
3.160 - /* Scan the bus. */
3.161 + /* Detach from the interrupt. */
3.162
3.163 - printf("Scan I2C0...\n");
3.164 - i2c_scan(i2c0);
3.165 + err = l4_error(l4_irq_detach(irq0cap));
3.166 +
3.167 + if (err)
3.168 + printf("Error detaching from IRQ objects: %ld\n", err);
3.169
3.170 return 0;
3.171 }