1 /* 2 * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de> 3 * economic rights: Technische Universit??t Dresden (Germany) 4 * Copyright (C) 2017, 2018, 2023 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This file is part of TUD:OS and distributed under the terms of the 7 * GNU General Public License 2. 8 * Please see the COPYING-GPL-2 file for details. 9 */ 10 /* 11 * Access the LED and other GPIOs on the MIPS Creator CI20 board. 12 * This example shows how to use the following GPIOs: 13 * 14 * PD17 - SW1 button 15 * PF15 - blue/red LED (high -> red, low -> blue) 16 */ 17 18 #include <l4/devices/gpio-jz4780.h> 19 #include <l4/io/io.h> 20 #include <l4/re/env.h> 21 #include <l4/re/c/util/cap_alloc.h> 22 #include <l4/sys/factory.h> 23 #include <l4/sys/icu.h> 24 #include <l4/sys/ipc.h> 25 #include <l4/sys/irq.h> 26 #include <l4/sys/rcv_endpoint.h> 27 #include <l4/vbus/vbus.h> 28 #include <stdio.h> 29 #include <unistd.h> 30 #include <stdint.h> 31 32 enum { 33 LED = 15, // via PORTF 34 SW1 = 17, // via PORTD 35 }; 36 37 38 39 /* Device and resource discovery. */ 40 41 static char const *resource_type(enum l4io_resource_types_t type) 42 { 43 switch (type) 44 { 45 case L4VBUS_RESOURCE_INVALID: 46 return "INVALID"; 47 48 case L4VBUS_RESOURCE_IRQ: 49 return "IRQ"; 50 51 case L4VBUS_RESOURCE_MEM: 52 return "MEMORY"; 53 54 default: 55 return "OTHER"; 56 } 57 } 58 59 static int gpio_get_device(char const *hid, l4io_device_handle_t *dh, l4io_resource_handle_t *rh) 60 { 61 int result = l4io_lookup_device(hid, dh, 0, rh); 62 63 if (result < 0) 64 printf("Could not access '%s': %s\n", hid, result == -L4_ENOENT ? "no such device" : "no device"); 65 66 return result; 67 } 68 69 static int gpio_get_resource(l4io_device_handle_t dh, l4io_resource_t *res, 70 enum l4io_resource_types_t type) 71 { 72 int current = 0, result = 0; 73 l4_cap_idx_t vbus = l4re_env_get_cap("vbus"); 74 75 do 76 { 77 result = l4vbus_get_resource(vbus, dh, current, res); 78 79 if (result) 80 printf("Could not access resource of type %s.\n", resource_type(type)); 81 else 82 printf("Resource %d: type %s, start=%lx, end=%lx\n", res->id, 83 resource_type(res->type), res->start, res->end); 84 85 current++; 86 } 87 while ((!result) && (res->type != type)); 88 89 return result; 90 } 91 92 static int gpio_get_irq(char const *hid, l4_uint32_t *start, l4_uint32_t *end) 93 { 94 l4io_device_handle_t dh; 95 l4io_resource_handle_t rh; 96 l4io_resource_t res; 97 int result; 98 99 result = gpio_get_device(hid, &dh, &rh); 100 101 if (result < 0) 102 return result; 103 104 result = gpio_get_resource(dh, &res, L4IO_RESOURCE_IRQ); 105 106 if (result) 107 return result; 108 109 *start = res.start; 110 *end = res.end; 111 112 return result; 113 } 114 115 static int gpio_get_memory(char const *hid, l4_addr_t *start, l4_addr_t *end) 116 { 117 l4io_device_handle_t dh; 118 l4io_resource_handle_t rh; 119 l4io_resource_t res; 120 int result; 121 122 result = gpio_get_device(hid, &dh, &rh); 123 124 if (result < 0) 125 return result; 126 127 result = gpio_get_resource(dh, &res, L4IO_RESOURCE_MEM); 128 129 if (result) 130 return result; 131 132 if ((result = l4io_request_iomem(res.start, res.end - res.start + 1, 133 L4IO_MEM_NONCACHED, start))) 134 { 135 printf("Could not get address for '%s'.\n", hid); 136 return result; 137 } 138 139 printf("Resource at 0x%lx...0x%lx.\n", res.start, res.end); 140 141 *end = *start + (res.end - res.start + 1); 142 143 return 0; 144 } 145 146 static long item_in_range(long start, long end, long index) 147 { 148 if (start < end) 149 return start + index; 150 else 151 return start - index; 152 } 153 154 int main(void) 155 { 156 l4_addr_t gpio_base = 0, gpio_base_end = 0, port_d, port_d_end, port_f, port_f_end; 157 l4_uint32_t gpio_irq_start = 0, gpio_irq_end = 0, gpio_irq; 158 l4_cap_idx_t irqcap, icucap; 159 l4_msgtag_t tag; 160 long err; 161 void *gpio_port_d, *gpio_port_f, *gpio_irq_pin; 162 int result = 0; 163 int led = 0; 164 165 /* Obtain capabilities for the interrupt controller and an interrupt. */ 166 167 irqcap = l4re_util_cap_alloc(); 168 icucap = l4re_env_get_cap("icu"); 169 170 if (l4_is_invalid_cap(icucap)) 171 { 172 printf("No 'icu' capability available in the virtual bus.\n"); 173 return 1; 174 } 175 176 if (l4_is_invalid_cap(irqcap)) 177 { 178 printf("No capability available for the interrupt.\n"); 179 return 1; 180 } 181 182 /* Obtain resource details describing the interrupt and I/O memory. */ 183 184 printf("Access IRQ...\n"); 185 186 if ((result = gpio_get_irq("jz4780-gpio", &gpio_irq_start, &gpio_irq_end)) < 0) 187 return 1; 188 189 gpio_irq = item_in_range(gpio_irq_start, gpio_irq_end, 3); 190 printf("IRQ range at %d...%d.\n", gpio_irq_start, gpio_irq_end); 191 printf("PORTD IRQ at %d.\n", gpio_irq); 192 193 printf("Access GPIO...\n"); 194 195 if ((result = gpio_get_memory("jz4780-gpio", &gpio_base, &gpio_base_end)) < 0) 196 return 1; 197 198 port_d = gpio_base + 0x300; 199 port_d_end = port_d + 0x100; 200 port_f = gpio_base + 0x500; 201 port_f_end = port_f + 0x100; 202 203 printf("GPIO at 0x%lx...0x%lx.\n", gpio_base, gpio_base_end); 204 printf("PORTD at 0x%lx...0x%lx.\n", port_d, port_d_end); 205 printf("PORTF at 0x%lx...0x%lx.\n", port_f, port_f_end); 206 207 gpio_port_d = jz4780_gpio_init(port_d, port_d_end, 32, 0xffff4fff, 0x0000b000); 208 gpio_port_f = jz4780_gpio_init(port_f, port_f_end, 32, 0xffa7f00f, 0x00580ff0); 209 210 /* Create an interrupt object. */ 211 212 if ((err = l4_error(tag = l4_factory_create_irq(l4re_global_env->factory, irqcap)))) 213 { 214 printf("Could not create IRQ object: %lx\n", err); 215 return 1; 216 } 217 218 /* Bind the interrupt object to the IRQ number. */ 219 220 if ((err = l4_error(l4_icu_bind(icucap, gpio_irq, irqcap)))) 221 { 222 printf("Could not bind IRQ %d to the ICU: %ld\n", gpio_irq, err); 223 return 1; 224 } 225 226 /* Attach ourselves to the interrupt handler. */ 227 228 tag = l4_rcv_ep_bind_thread(irqcap, l4re_env()->main_thread, 0xDEAD); 229 230 if ((err = l4_error(tag))) 231 { 232 printf("Could not attach to IRQ %d: %ld\n", gpio_irq, err); 233 return 1; 234 } 235 236 /* Set the GPIO pins up. */ 237 238 printf("Set up GPIO pins...\n"); 239 240 jz4780_gpio_setup(gpio_port_d, SW1, L4VBUS_GPIO_SETUP_IRQ, 1); 241 jz4780_gpio_setup(gpio_port_f, LED, L4VBUS_GPIO_SETUP_OUTPUT, 0); 242 243 gpio_irq_pin = jz4780_gpio_get_irq(gpio_port_d, SW1); 244 jz4780_gpio_irq_set_mode(gpio_irq_pin, L4_IRQ_F_LEVEL_HIGH); 245 246 printf("Press SW1 to invert LED.\n"); 247 248 while (1) 249 { 250 tag = l4_irq_receive(irqcap, L4_IPC_NEVER); 251 252 if ((err = l4_ipc_error(tag, l4_utcb()))) 253 { 254 printf("Error on IRQ receive: %ld\n", err); 255 continue; 256 } 257 258 printf("SW1: %x\n", jz4780_gpio_get(gpio_port_d, SW1)); 259 260 if (jz4780_gpio_get(gpio_port_d, SW1)) 261 { 262 printf("Invert LED\n"); 263 jz4780_gpio_set(gpio_port_f, LED, led); 264 led = 1 - led; 265 } 266 } 267 268 /* Detach from the interrupt. */ 269 270 tag = l4_irq_detach(irqcap); 271 272 if ((err = l4_error(tag))) 273 printf("Error detaching from IRQ: %ld\n", err); 274 275 return 0; 276 }