Landfall

Annotated pkg/landfall-examples/ci20_leds/ci20_leds.c

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