1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/pkg/landfall-examples/ci20_hdmi_i2c/ci20_hdmi_i2c.c Fri May 22 00:17:25 2020 +0200
1.3 @@ -0,0 +1,241 @@
1.4 +/*
1.5 + * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>
1.6 + * economic rights: Technische Universität Dresden (Germany)
1.7 + * Copyright (C) 2017, 2018, 2019, 2020 Paul Boddie <paul@boddie.org.uk>
1.8 + *
1.9 + * This file is part of TUD:OS and distributed under the terms of the
1.10 + * GNU General Public License 2.
1.11 + * Please see the COPYING-GPL-2 file for details.
1.12 + */
1.13 +/*
1.14 + * Access the HDMI I2C peripheral on the MIPS Creator CI20 board.
1.15 + */
1.16 +
1.17 +#include <l4/devices/cpm-jz4780.h>
1.18 +#include <l4/devices/gpio-jz4780.h>
1.19 +#include <l4/devices/hdmi-jz4780.h>
1.20 +#include <l4/devices/memory.h>
1.21 +#include <l4/io/io.h>
1.22 +#include <l4/libedid/edid.h>
1.23 +#include <l4/re/env.h>
1.24 +#include <l4/re/c/util/cap_alloc.h>
1.25 +#include <l4/sys/factory.h>
1.26 +#include <l4/sys/icu.h>
1.27 +#include <l4/sys/ipc.h>
1.28 +#include <l4/sys/irq.h>
1.29 +#include <l4/sys/rcv_endpoint.h>
1.30 +#include <l4/vbus/vbus.h>
1.31 +#include <stdio.h>
1.32 +#include <unistd.h>
1.33 +#include <stdint.h>
1.34 +#include <string.h>
1.35 +
1.36 +
1.37 +
1.38 +enum {
1.39 + DDCSCL = 24, /* via PORTF */
1.40 + DDCSDA = 25, /* via PORTF */
1.41 +};
1.42 +
1.43 +
1.44 +
1.45 +/* Device and resource discovery. */
1.46 +
1.47 +static long item_in_range(long start, long end, long index)
1.48 +{
1.49 + if (start < end)
1.50 + return start + index;
1.51 + else
1.52 + return start - index;
1.53 +}
1.54 +
1.55 +static void show_timings(uint8_t *buf)
1.56 +{
1.57 + unsigned int width, height;
1.58 +
1.59 + /* Attempt to decode EDID information. */
1.60 +
1.61 + libedid_prefered_resolution(buf, &width, &height);
1.62 + printf("Preferred resolution: %d x %d\n", width, height);
1.63 +
1.64 + libedid_dump_standard_timings(buf);
1.65 +}
1.66 +
1.67 +int main(void)
1.68 +{
1.69 + long err;
1.70 +
1.71 + /* Buffer for EDID data. */
1.72 +
1.73 + uint8_t edid[128];
1.74 + unsigned int length = 0, i;
1.75 +
1.76 + /* Version details. */
1.77 +
1.78 + uint8_t hdmi_major;
1.79 + uint16_t hdmi_minor;
1.80 +
1.81 + /* Peripheral memory. */
1.82 +
1.83 + l4_addr_t cpm_base = 0, cpm_base_end = 0;
1.84 + l4_addr_t gpio_base = 0, gpio_base_end = 0;
1.85 + l4_addr_t hdmi_base = 0, hdmi_base_end = 0;
1.86 + l4_addr_t port_f, port_f_end;
1.87 +
1.88 + /* Peripheral abstractions. */
1.89 +
1.90 + void *cpm;
1.91 + void *gpio_port_f;
1.92 + void *hdmi;
1.93 +
1.94 + /* Access to IRQs. */
1.95 +
1.96 + l4_uint32_t hdmi_irq_start = 0, hdmi_irq_end = 0;
1.97 + l4_cap_idx_t icucap, irqcap;
1.98 +
1.99 + irqcap = l4re_util_cap_alloc();
1.100 + icucap = l4re_env_get_cap("icu");
1.101 +
1.102 + if (l4_is_invalid_cap(icucap))
1.103 + {
1.104 + printf("No 'icu' capability available in the virtual bus.\n");
1.105 + return 1;
1.106 + }
1.107 +
1.108 + if (l4_is_invalid_cap(irqcap))
1.109 + {
1.110 + printf("Capabilities not available for interrupts.\n");
1.111 + return 1;
1.112 + }
1.113 +
1.114 + /* Obtain resource details describing the interrupt for HDMI I2C. */
1.115 +
1.116 + printf("Access IRQ...\n");
1.117 +
1.118 + if (get_irq("jz4780-hdmi", &hdmi_irq_start, &hdmi_irq_end) < 0)
1.119 + return 1;
1.120 +
1.121 + printf("IRQ range at %d...%d.\n", hdmi_irq_start, hdmi_irq_end);
1.122 +
1.123 + /* Create interrupt objects. */
1.124 +
1.125 + err = l4_error(l4_factory_create_irq(l4re_global_env->factory, irqcap));
1.126 +
1.127 + if (err)
1.128 + {
1.129 + printf("Could not create IRQ object: %lx\n", err);
1.130 + return 1;
1.131 + }
1.132 +
1.133 + /* Bind interrupt objects to IRQ numbers. Here, the first HDMI interrupt is
1.134 + bound, this being the general HDMI interrupt. */
1.135 +
1.136 + err = l4_error(l4_icu_bind(icucap,
1.137 + item_in_range(hdmi_irq_start, hdmi_irq_end, 0),
1.138 + irqcap));
1.139 +
1.140 + if (err)
1.141 + {
1.142 + printf("Could not bind IRQ to the ICU: %ld\n", err);
1.143 + return 1;
1.144 + }
1.145 +
1.146 + /* Attach ourselves to the interrupt handler. */
1.147 +
1.148 + err = l4_error(l4_rcv_ep_bind_thread(irqcap, l4re_env()->main_thread, 0));
1.149 +
1.150 + if (err)
1.151 + {
1.152 + printf("Could not attach to IRQs: %ld\n", err);
1.153 + return 1;
1.154 + }
1.155 +
1.156 + /* Obtain resource details describing I/O memory. */
1.157 +
1.158 + printf("Access CPM...\n");
1.159 +
1.160 + if (get_memory("jz4780-cpm", &cpm_base, &cpm_base_end) < 0)
1.161 + return 1;
1.162 +
1.163 + printf("CPM at 0x%lx...0x%lx.\n", cpm_base, cpm_base_end);
1.164 +
1.165 + printf("Access GPIO...\n");
1.166 +
1.167 + if (get_memory("jz4780-gpio", &gpio_base, &gpio_base_end) < 0)
1.168 + return 1;
1.169 +
1.170 + printf("GPIO at 0x%lx...0x%lx.\n", gpio_base, gpio_base_end);
1.171 +
1.172 + printf("Access HDMI...\n");
1.173 +
1.174 + if (get_memory("jz4780-hdmi", &hdmi_base, &hdmi_base_end) < 0)
1.175 + return 1;
1.176 +
1.177 + printf("HDMI at 0x%lx...0x%lx.\n", hdmi_base, hdmi_base_end);
1.178 +
1.179 + /* Obtain CPM object. */
1.180 +
1.181 + cpm = jz4780_cpm_init(cpm_base);
1.182 +
1.183 + printf("VPLL frequency: %d\n", jz4780_cpm_get_vpll_frequency(cpm));
1.184 + printf("HDMI divider: %d\n", jz4780_cpm_get_hdmi_divider(cpm));
1.185 + printf("HDMI frequency: %d\n", jz4780_cpm_get_hdmi_frequency(cpm));
1.186 +
1.187 + jz4780_cpm_stop_hdmi(cpm);
1.188 + jz4780_cpm_set_hdmi_frequency(cpm, 27000000);
1.189 +
1.190 + printf("HDMI divider: %d\n", jz4780_cpm_get_hdmi_divider(cpm));
1.191 + printf("HDMI frequency: %d\n", jz4780_cpm_get_hdmi_frequency(cpm));
1.192 +
1.193 + jz4780_cpm_start_hdmi(cpm);
1.194 +
1.195 + /* Configure pins. */
1.196 +
1.197 + port_f = gpio_base + 0x500;
1.198 + port_f_end = port_f + 0x100;
1.199 +
1.200 + printf("PORTF at 0x%lx...0x%lx.\n", port_f, port_f_end);
1.201 +
1.202 + gpio_port_f = jz4780_gpio_init(port_f, port_f_end, 32, 0x7fa7f00f, 0x00580ff0);
1.203 +
1.204 + printf("Set up GPIO pins...\n");
1.205 +
1.206 + jz4780_gpio_config_pad(gpio_port_f, DDCSCL, Function_alt, 0);
1.207 + jz4780_gpio_config_pad(gpio_port_f, DDCSDA, Function_alt, 0);
1.208 +
1.209 + /* Obtain HDMI reference. */
1.210 +
1.211 + printf("Set up HDMI...\n");
1.212 +
1.213 + hdmi = jz4780_hdmi_init(hdmi_base, hdmi_base_end, irqcap);
1.214 +
1.215 + printf("Read version...\n");
1.216 +
1.217 + jz4780_hdmi_get_version(hdmi, &hdmi_major, &hdmi_minor);
1.218 +
1.219 + printf("HDMI version is %x.%03x\n", hdmi_major, hdmi_minor);
1.220 +
1.221 + printf("Read EDID...\n");
1.222 +
1.223 + jz4780_hdmi_i2c_set_address(hdmi, 0x50);
1.224 + length = jz4780_hdmi_i2c_read(hdmi, edid, 128);
1.225 +
1.226 + if (length)
1.227 + {
1.228 + for (i = 0; i < length; i++)
1.229 + printf("%02x%c", edid[i], ((i % 16) != 15) ? ' ' : '\n');
1.230 + }
1.231 +
1.232 + show_timings(edid);
1.233 +
1.234 + /* Detach from the interrupt. */
1.235 +
1.236 + err = l4_error(l4_irq_detach(irqcap));
1.237 +
1.238 + if (err)
1.239 + printf("Error detaching from IRQ: %ld\n", err);
1.240 +
1.241 + printf("Done.\n");
1.242 +
1.243 + return 0;
1.244 +}