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