2.1 --- a/pkg/landfall-examples/ci20_i2c/ci20_i2c.c Sun Jul 21 21:10:24 2019 +0200
2.2 +++ b/pkg/landfall-examples/ci20_i2c/ci20_i2c.c Sun Jul 21 21:14:36 2019 +0200
2.3 @@ -1,7 +1,7 @@
2.4 /*
2.5 * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>
2.6 * economic rights: Technische Universität Dresden (Germany)
2.7 - * Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk>
2.8 + * Copyright (C) 2017, 2018, 2019 Paul Boddie <paul@boddie.org.uk>
2.9 *
2.10 * This file is part of TUD:OS and distributed under the terms of the
2.11 * GNU General Public License 2.
2.12 @@ -14,6 +14,7 @@
2.13 #include <l4/devices/cpm-jz4780.h>
2.14 #include <l4/devices/gpio-jz4780.h>
2.15 #include <l4/devices/i2c-jz4780.h>
2.16 +#include <l4/devices/memory.h>
2.17 #include <l4/io/io.h>
2.18 #include <l4/libedid/edid.h>
2.19 #include <l4/re/env.h>
2.20 @@ -22,6 +23,7 @@
2.21 #include <l4/sys/icu.h>
2.22 #include <l4/sys/ipc.h>
2.23 #include <l4/sys/irq.h>
2.24 +#include <l4/sys/rcv_endpoint.h>
2.25 #include <l4/vbus/vbus.h>
2.26 #include <stdio.h>
2.27 #include <unistd.h>
2.28 @@ -30,6 +32,12 @@
2.29
2.30
2.31 enum {
2.32 + PMSDA = 30, /* via PORTD */
2.33 + PMSCL = 31, /* via PORTD */
2.34 + PWM3 = 3, /* via PORTE */
2.35 + PWM4 = 4, /* via PORTE */
2.36 + RTCSDA = 12, /* via PORTE */
2.37 + RTCSCL = 13, /* via PORTE */
2.38 DDCSCL = 24, /* via PORTF */
2.39 DDCSDA = 25, /* via PORTF */
2.40 };
2.41 @@ -38,111 +46,6 @@
2.42
2.43 /* Device and resource discovery. */
2.44
2.45 -static char const *resource_type(enum l4io_resource_types_t type)
2.46 -{
2.47 - switch (type)
2.48 - {
2.49 - case L4VBUS_RESOURCE_INVALID:
2.50 - return "INVALID";
2.51 -
2.52 - case L4VBUS_RESOURCE_IRQ:
2.53 - return "IRQ";
2.54 -
2.55 - case L4VBUS_RESOURCE_MEM:
2.56 - return "MEMORY";
2.57 -
2.58 - default:
2.59 - return "OTHER";
2.60 - }
2.61 -}
2.62 -
2.63 -static int vbus_get_device(char const *hid, l4io_device_handle_t *dh, l4io_resource_handle_t *rh)
2.64 -{
2.65 - int result = l4io_lookup_device(hid, dh, 0, rh);
2.66 -
2.67 - if (result < 0)
2.68 - printf("Could not access '%s': %s\n", hid, result == -L4_ENOENT ? "no such device" : "no device");
2.69 -
2.70 - return result;
2.71 -}
2.72 -
2.73 -static int vbus_get_resource(l4io_device_handle_t dh, l4io_resource_t *res,
2.74 - enum l4io_resource_types_t type)
2.75 -{
2.76 - int current = 0, result = 0;
2.77 - l4_cap_idx_t vbus = l4re_env_get_cap("vbus");
2.78 -
2.79 - do
2.80 - {
2.81 - result = l4vbus_get_resource(vbus, dh, current, res);
2.82 -
2.83 - if (result)
2.84 - printf("Could not access resource of type %s.\n", resource_type(type));
2.85 - else
2.86 - printf("Resource %d: type %s, start=%lx, end=%lx\n", res->id,
2.87 - resource_type(res->type), res->start, res->end);
2.88 -
2.89 - current++;
2.90 - }
2.91 - while ((!result) && (res->type != type));
2.92 -
2.93 - return result;
2.94 -}
2.95 -
2.96 -static int vbus_get_irq(char const *hid, l4_uint32_t *start, l4_uint32_t *end)
2.97 -{
2.98 - l4io_device_handle_t dh;
2.99 - l4io_resource_handle_t rh;
2.100 - l4io_resource_t res;
2.101 - int result;
2.102 -
2.103 - result = vbus_get_device(hid, &dh, &rh);
2.104 -
2.105 - if (result < 0)
2.106 - return result;
2.107 -
2.108 - result = vbus_get_resource(dh, &res, L4IO_RESOURCE_IRQ);
2.109 -
2.110 - if (result)
2.111 - return result;
2.112 -
2.113 - *start = res.start;
2.114 - *end = res.end;
2.115 -
2.116 - return result;
2.117 -}
2.118 -
2.119 -static int vbus_get_memory(char const *hid, l4_addr_t *start, l4_addr_t *end)
2.120 -{
2.121 - l4io_device_handle_t dh;
2.122 - l4io_resource_handle_t rh;
2.123 - l4io_resource_t res;
2.124 - int result;
2.125 -
2.126 - result = vbus_get_device(hid, &dh, &rh);
2.127 -
2.128 - if (result < 0)
2.129 - return result;
2.130 -
2.131 - result = vbus_get_resource(dh, &res, L4IO_RESOURCE_MEM);
2.132 -
2.133 - if (result)
2.134 - return result;
2.135 -
2.136 - if ((result = l4io_request_iomem(res.start, res.end - res.start + 1,
2.137 - L4IO_MEM_NONCACHED, start)))
2.138 - {
2.139 - printf("Could not get address for '%s'.\n", hid);
2.140 - return result;
2.141 - }
2.142 -
2.143 - printf("Resource at 0x%lx...0x%lx.\n", res.start, res.end);
2.144 -
2.145 - *end = *start + (res.end - res.start + 1);
2.146 -
2.147 - return 0;
2.148 -}
2.149 -
2.150 static long item_in_range(long start, long end, long index)
2.151 {
2.152 if (start < end)
2.153 @@ -174,25 +77,180 @@
2.154 printf("No reply from bus.\n");
2.155 }
2.156
2.157 +static unsigned int i2c_read(void *i2c_channel, uint8_t *buf, unsigned length,
2.158 + l4_cap_idx_t irqcap)
2.159 +{
2.160 + l4_msgtag_t tag;
2.161 + long err;
2.162 +
2.163 + jz4780_i2c_start_read(i2c_channel, buf, length);
2.164 +
2.165 + while (!jz4780_i2c_read_done(i2c_channel))
2.166 + {
2.167 + if (jz4780_i2c_read_incomplete(i2c_channel))
2.168 + {
2.169 + printf("Failed\n");
2.170 + break;
2.171 + }
2.172 +
2.173 + tag = l4_irq_receive(irqcap, l4_timeout(L4_IPC_TIMEOUT_NEVER, l4_timeout_rel(1, 20)));
2.174 +
2.175 + if ((err = l4_ipc_error(tag, l4_utcb())))
2.176 + {
2.177 + printf("Error on IRQ receive: %ld\n", err);
2.178 + break;
2.179 + }
2.180 +
2.181 + jz4780_i2c_read(i2c_channel);
2.182 + }
2.183 +
2.184 + jz4780_i2c_stop(i2c_channel);
2.185 + return jz4780_i2c_have_read(i2c_channel);
2.186 +}
2.187 +
2.188 +static void i2c_scan(void *i2c_channel, l4_cap_idx_t irqcap)
2.189 +{
2.190 + l4_msgtag_t tag;
2.191 + uint8_t buf[1];
2.192 + unsigned int address;
2.193 +
2.194 + for (address = 0; address < 0x20; address++)
2.195 + printf("%02x ", address);
2.196 + printf("\n");
2.197 +
2.198 + for (address = 0; address < 0x20; address++)
2.199 + printf("-- ");
2.200 +
2.201 + for (address = 0; address < 0x80; address++)
2.202 + {
2.203 + if ((address % 32) == 0)
2.204 + printf("\n");
2.205 +
2.206 + jz4780_i2c_set_target(i2c_channel, address);
2.207 + buf[0] = 0;
2.208 + jz4780_i2c_write(i2c_channel, buf, 1);
2.209 + jz4780_i2c_start_read(i2c_channel, buf, 1);
2.210 +
2.211 + while (!jz4780_i2c_read_done(i2c_channel))
2.212 + {
2.213 + if (jz4780_i2c_read_incomplete(i2c_channel))
2.214 + break;
2.215 +
2.216 + tag = l4_irq_receive(irqcap, l4_timeout(L4_IPC_TIMEOUT_NEVER, l4_timeout_rel(2, 10)));
2.217 +
2.218 + if (l4_ipc_error(tag, l4_utcb()))
2.219 + break;
2.220 +
2.221 + jz4780_i2c_read(i2c_channel);
2.222 + }
2.223 +
2.224 + jz4780_i2c_stop(i2c_channel);
2.225 +
2.226 + if (jz4780_i2c_have_read(i2c_channel))
2.227 + printf("%02x ", address);
2.228 + else
2.229 + printf("?? ");
2.230 + }
2.231 +
2.232 + printf("\n");
2.233 + for (address = 0; address < 0x20; address++)
2.234 + printf("-- ");
2.235 + printf("\n\n");
2.236 +}
2.237 +
2.238 +static void ddc_read(void *i2c_channel, l4_cap_idx_t irqcap)
2.239 +{
2.240 + /* Buffer for reading. */
2.241 +
2.242 + uint8_t buf[128];
2.243 + unsigned int pos;
2.244 +
2.245 + /* DDC EDID details. */
2.246 +
2.247 + unsigned width = 0, height = 0;
2.248 +
2.249 + printf("Trying DDC on I2C4...\n");
2.250 +
2.251 + /* Attempt to read from address 0x50 for DDC.
2.252 + See: drivers/video/fbdev/core/fb_ddc.c */
2.253 +
2.254 + jz4780_i2c_set_target(i2c_channel, 0x50);
2.255 + buf[0] = 0;
2.256 + jz4780_i2c_write(i2c_channel, buf, 1);
2.257 +
2.258 + printf("Waiting...\n");
2.259 +
2.260 + pos = i2c_read(i2c_channel, buf, 128, irqcap);
2.261 + show_data(buf, pos);
2.262 +
2.263 + /* Attempt to decode EDID information. */
2.264 +
2.265 + libedid_prefered_resolution(buf, &width, &height);
2.266 + printf("Preferred resolution: %d x %d\n", width, height);
2.267 +
2.268 + libedid_dump_standard_timings(buf);
2.269 +}
2.270 +
2.271 +static void pmic_out3_control(void *i2c_channel, l4_cap_idx_t irqcap)
2.272 +{
2.273 + /* Buffer for communicating. */
2.274 +
2.275 + uint8_t buf[2];
2.276 +
2.277 + /* Attempt to read from address 0x5a for PMIC OUT3. */
2.278 +
2.279 + jz4780_i2c_set_target(i2c_channel, 0x5a);
2.280 + buf[0] = 0x32;
2.281 + jz4780_i2c_write(i2c_channel, buf, 1);
2.282 + i2c_read(i2c_channel, buf, 1, irqcap);
2.283 + printf("Read %02x\n", buf[0]);
2.284 +
2.285 +#if 0
2.286 + /* Disable the regulator. */
2.287 +
2.288 + printf("Updating...\n");
2.289 + buf[1] = buf[0] & ~0x80;
2.290 + buf[0] = 0x32;
2.291 + jz4780_i2c_write(i2c_channel, buf, 2);
2.292 +
2.293 + /* Read back from the register. Seemed to give 0xff, which makes no real
2.294 + sense, although the regulator did bring the voltage level low. */
2.295 +
2.296 + buf[0] = 0x32;
2.297 + jz4780_i2c_write(i2c_channel, buf, 1);
2.298 + i2c_read(i2c_channel, buf, 1, irqcap);
2.299 + printf("Read %02x\n", buf[0]);
2.300 +#endif
2.301 +}
2.302 +
2.303 int main(void)
2.304 {
2.305 + long err;
2.306 +
2.307 + /* Peripheral memory. */
2.308 +
2.309 l4_addr_t gpio_base = 0, gpio_base_end = 0;
2.310 + l4_addr_t i2c_base = 0, i2c_base_end = 0;
2.311 + l4_addr_t cpm_base = 0, cpm_base_end = 0;
2.312 + l4_addr_t port_d, port_d_end;
2.313 + l4_addr_t port_e, port_e_end;
2.314 l4_addr_t port_f, port_f_end;
2.315 - l4_addr_t i2c_base = 0, i2c_base_end = 0, cpm_base = 0, cpm_base_end;
2.316 - void *gpio_port_f;
2.317 - void *i2c, *i2c_channel, *cpm;
2.318 - l4_uint32_t i2c_irq_start = 0, i2c_irq_end = 0, i2c_irq;
2.319 - l4_cap_idx_t irqcap, icucap;
2.320 - l4_msgtag_t tag;
2.321 - long err;
2.322 - int result = 0;
2.323 - uint8_t buf[256];
2.324 - unsigned pos;
2.325 - unsigned width = 0, height = 0;
2.326 +
2.327 + /* Peripheral abstractions. */
2.328 +
2.329 + void *gpio_port_d, *gpio_port_e, *gpio_port_f;
2.330 + void *i2c, *cpm;
2.331 + void *i2c0, *i2c4;
2.332 +
2.333 + /* IRQ resources. */
2.334 +
2.335 + l4_uint32_t i2c_irq_start = 0, i2c_irq_end = 0;
2.336 + l4_cap_idx_t icucap, irq0cap, irq4cap;
2.337
2.338 /* Obtain capabilities for the interrupt controller and an interrupt. */
2.339
2.340 - irqcap = l4re_util_cap_alloc();
2.341 + irq0cap = l4re_util_cap_alloc();
2.342 + irq4cap = l4re_util_cap_alloc();
2.343 icucap = l4re_env_get_cap("icu");
2.344
2.345 if (l4_is_invalid_cap(icucap))
2.346 @@ -201,9 +259,9 @@
2.347 return 1;
2.348 }
2.349
2.350 - if (l4_is_invalid_cap(irqcap))
2.351 + if (l4_is_invalid_cap(irq0cap) || l4_is_invalid_cap(irq4cap))
2.352 {
2.353 - printf("No capability available for the interrupt.\n");
2.354 + printf("Capabilities not available for interrupts.\n");
2.355 return 1;
2.356 }
2.357
2.358 @@ -211,73 +269,96 @@
2.359
2.360 printf("Access IRQ...\n");
2.361
2.362 - if ((result = vbus_get_irq("jz4780-i2c", &i2c_irq_start, &i2c_irq_end)) < 0)
2.363 + if (get_irq("jz4780-i2c", &i2c_irq_start, &i2c_irq_end) < 0)
2.364 return 1;
2.365
2.366 - i2c_irq = item_in_range(i2c_irq_start, i2c_irq_end, 4);
2.367 printf("IRQ range at %d...%d.\n", i2c_irq_start, i2c_irq_end);
2.368 - printf("I2C IRQ at %d.\n", i2c_irq);
2.369
2.370 /* Obtain resource details describing I/O memory. */
2.371
2.372 printf("Access GPIO...\n");
2.373
2.374 - if ((result = vbus_get_memory("jz4780-gpio", &gpio_base, &gpio_base_end)) < 0)
2.375 + if (get_memory("jz4780-gpio", &gpio_base, &gpio_base_end) < 0)
2.376 return 1;
2.377
2.378 printf("GPIO at 0x%lx...0x%lx.\n", gpio_base, gpio_base_end);
2.379
2.380 printf("Access CPM...\n");
2.381
2.382 - if ((result = vbus_get_memory("jz4780-cpm", &cpm_base, &cpm_base_end)) < 0)
2.383 + if (get_memory("jz4780-cpm", &cpm_base, &cpm_base_end) < 0)
2.384 return 1;
2.385
2.386 printf("CPM at 0x%lx...0x%lx.\n", cpm_base, cpm_base_end);
2.387
2.388 printf("Access I2C...\n");
2.389
2.390 - if ((result = vbus_get_memory("jz4780-i2c", &i2c_base, &i2c_base_end)) < 0)
2.391 + if (get_memory("jz4780-i2c", &i2c_base, &i2c_base_end) < 0)
2.392 return 1;
2.393
2.394 printf("I2C at 0x%lx...0x%lx.\n", i2c_base, i2c_base_end);
2.395
2.396 - /* Create an interrupt object. */
2.397 + /* Create interrupt objects. */
2.398
2.399 - if ((err = l4_error(tag = l4_factory_create_irq(l4re_global_env->factory, irqcap))))
2.400 + err = l4_error(l4_factory_create_irq(l4re_global_env->factory, irq0cap)) ||
2.401 + l4_error(l4_factory_create_irq(l4re_global_env->factory, irq4cap));
2.402 +
2.403 + if (err)
2.404 {
2.405 printf("Could not create IRQ object: %lx\n", err);
2.406 return 1;
2.407 }
2.408
2.409 - /* Bind the interrupt object to the IRQ number. */
2.410 + /* Bind interrupt objects to IRQ numbers. */
2.411
2.412 - if ((err = l4_error(l4_icu_bind(icucap, i2c_irq, irqcap))))
2.413 + err = l4_error(l4_icu_bind(icucap,
2.414 + item_in_range(i2c_irq_start, i2c_irq_end, 0),
2.415 + irq0cap)) ||
2.416 + l4_error(l4_icu_bind(icucap,
2.417 + item_in_range(i2c_irq_start, i2c_irq_end, 4),
2.418 + irq4cap));
2.419 +
2.420 + if (err)
2.421 {
2.422 - printf("Could not bind IRQ %d to the ICU: %ld\n", i2c_irq, err);
2.423 + printf("Could not bind IRQ to the ICU: %ld\n", err);
2.424 return 1;
2.425 }
2.426
2.427 /* Attach ourselves to the interrupt handler. */
2.428
2.429 - tag = l4_irq_attach(irqcap, 0xDEAD, l4re_env()->main_thread);
2.430 + err = l4_error(l4_rcv_ep_bind_thread(irq0cap, l4re_env()->main_thread, 0)) ||
2.431 + l4_error(l4_rcv_ep_bind_thread(irq4cap, l4re_env()->main_thread, 4));
2.432
2.433 - if ((err = l4_error(tag)))
2.434 + if (err)
2.435 {
2.436 - printf("Could not attach to IRQ %d: %ld\n", i2c_irq, err);
2.437 + printf("Could not attach to IRQs: %ld\n", err);
2.438 return 1;
2.439 }
2.440
2.441 /* Configure pins. */
2.442
2.443 + port_d = gpio_base + 0x300;
2.444 + port_d_end = port_d + 0x100;
2.445 + port_e = gpio_base + 0x400;
2.446 + port_e_end = port_e + 0x100;
2.447 port_f = gpio_base + 0x500;
2.448 port_f_end = port_f + 0x100;
2.449
2.450 + printf("PORTD at 0x%lx...0x%lx.\n", port_d, port_d_end);
2.451 + printf("PORTE at 0x%lx...0x%lx.\n", port_e, port_e_end);
2.452 printf("PORTF at 0x%lx...0x%lx.\n", port_f, port_f_end);
2.453
2.454 - gpio_port_f = jz4780_gpio_init(port_f, port_f_end, 32, 0xffa7f00f, 0x00580ff0);
2.455 + gpio_port_d = jz4780_gpio_init(port_d, port_d_end, 32, 0xffff4fff, 0x0000b000);
2.456 + gpio_port_e = jz4780_gpio_init(port_e, port_e_end, 32, 0xfffff37c, 0x00000483);
2.457 + gpio_port_f = jz4780_gpio_init(port_f, port_f_end, 32, 0x7fa7f00f, 0x00580ff0);
2.458
2.459 printf("Set up GPIO pins...\n");
2.460
2.461 + jz4780_gpio_config_pad(gpio_port_d, PMSCL, Function_alt, 0);
2.462 + jz4780_gpio_config_pad(gpio_port_d, PMSDA, Function_alt, 0);
2.463 +
2.464 + jz4780_gpio_config_pad(gpio_port_e, RTCSCL, Function_alt, 1);
2.465 + jz4780_gpio_config_pad(gpio_port_e, RTCSDA, Function_alt, 1);
2.466 +
2.467 jz4780_gpio_config_pad(gpio_port_f, DDCSCL, Function_alt, 1);
2.468 jz4780_gpio_config_pad(gpio_port_f, DDCSDA, Function_alt, 1);
2.469
2.470 @@ -293,56 +374,30 @@
2.471 /* Obtain I2C reference. */
2.472
2.473 i2c = jz4780_i2c_init(i2c_base, i2c_base_end, cpm, 100000); /* 100 kHz */
2.474 -
2.475 - printf("Trying DDC on I2C4...\n");
2.476 -
2.477 - i2c_channel = jz4780_i2c_get_channel(i2c, 4);
2.478 + i2c0 = jz4780_i2c_get_channel(i2c, 0);
2.479 + i2c4 = jz4780_i2c_get_channel(i2c, 4);
2.480
2.481 - /* Attempt to read from address 0x50 for DDC.
2.482 - See: drivers/video/fbdev/core/fb_ddc.c */
2.483 -
2.484 - jz4780_i2c_set_target(i2c_channel, 0x50);
2.485 - buf[0] = 0;
2.486 - jz4780_i2c_write(i2c_channel, buf, 1);
2.487 - jz4780_i2c_start_read(i2c_channel, buf, 128);
2.488 -
2.489 - printf("Waiting\n");
2.490 + printf("Scan I2C0...\n");
2.491 + i2c_scan(i2c0, irq0cap);
2.492
2.493 - while (!jz4780_i2c_read_done(i2c_channel))
2.494 - {
2.495 - if (jz4780_i2c_read_incomplete(i2c_channel))
2.496 - {
2.497 - printf("Failed\n");
2.498 - break;
2.499 - }
2.500 + printf("Scan I2C4...\n");
2.501 + i2c_scan(i2c4, irq4cap);
2.502 +
2.503 + pmic_out3_control(i2c0, irq0cap);
2.504
2.505 - tag = l4_irq_receive(irqcap, L4_IPC_NEVER);
2.506 -
2.507 - if ((err = l4_ipc_error(tag, l4_utcb())))
2.508 - {
2.509 - printf("Error on IRQ receive: %ld\n", err);
2.510 - continue;
2.511 - }
2.512 + ddc_read(i2c4, irq4cap);
2.513
2.514 - jz4780_i2c_read(i2c_channel);
2.515 - }
2.516 -
2.517 - pos = jz4780_i2c_have_read(i2c_channel);
2.518 - show_data(buf, pos);
2.519 -
2.520 - /* Attempt to decode EDID information. */
2.521 -
2.522 - libedid_prefered_resolution(buf, &width, &height);
2.523 - printf("Preferred resolution: %d x %d\n", width, height);
2.524 -
2.525 - libedid_dump_standard_timings(buf);
2.526 + jz4780_i2c_disable(i2c0);
2.527 + jz4780_i2c_disable(i2c4);
2.528
2.529 /* Detach from the interrupt. */
2.530
2.531 - tag = l4_irq_detach(irqcap);
2.532 + err = l4_error(l4_irq_detach(irq0cap)) || l4_error(l4_irq_detach(irq4cap));
2.533
2.534 - if ((err = l4_error(tag)))
2.535 - printf("Error detaching from IRQ: %ld\n", err);
2.536 + if (err)
2.537 + printf("Error detaching from IRQ objects: %ld\n", err);
2.538 +
2.539 + printf("Done.\n");
2.540
2.541 return 0;
2.542 }