Landfall

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

254:a437381bd5f4
9 months ago Paul Boddie Employed get_channel to eliminate redundant code. cpm-library-improvements
paul@62 1
/*
paul@62 2
 * Access the HDMI I2C peripheral on the MIPS Creator CI20 board.
paul@65 3
 *
paul@150 4
 * Copyright (C) 2020, 2021, 2023 Paul Boddie <paul@boddie.org.uk>
paul@65 5
 *
paul@65 6
 * This program is free software; you can redistribute it and/or
paul@65 7
 * modify it under the terms of the GNU General Public License as
paul@65 8
 * published by the Free Software Foundation; either version 2 of
paul@65 9
 * the License, or (at your option) any later version.
paul@65 10
 *
paul@65 11
 * This program is distributed in the hope that it will be useful,
paul@65 12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
paul@65 13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
paul@65 14
 * GNU General Public License for more details.
paul@65 15
 *
paul@65 16
 * You should have received a copy of the GNU General Public License
paul@65 17
 * along with this program; if not, write to the Free Software
paul@65 18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
paul@65 19
 * Boston, MA  02110-1301, USA
paul@62 20
 */
paul@62 21
paul@62 22
#include <l4/devices/cpm-jz4780.h>
paul@62 23
#include <l4/devices/gpio-jz4780.h>
paul@62 24
#include <l4/devices/hdmi-jz4780.h>
paul@64 25
paul@75 26
#include <l4/devices/lcd-jz4780.h>
paul@64 27
#include <l4/devices/lcd-jz4740-config.h>
paul@64 28
#include <l4/devices/lcd-jz4740-panel.h>
paul@64 29
paul@62 30
#include <l4/devices/memory.h>
paul@74 31
paul@74 32
#include <l4/re/c/dataspace.h>
paul@142 33
#include <l4/re/c/dma_space.h>
paul@74 34
#include <l4/re/c/mem_alloc.h>
paul@74 35
#include <l4/re/c/rm.h>
paul@74 36
#include <l4/re/c/util/cap_alloc.h>
paul@62 37
#include <l4/re/env.h>
paul@142 38
#include <l4/re/protocols.h>
paul@74 39
paul@74 40
#include <l4/sys/cache.h>
paul@142 41
#include <l4/sys/err.h>
paul@62 42
#include <l4/sys/factory.h>
paul@62 43
#include <l4/sys/icu.h>
paul@62 44
#include <l4/sys/ipc.h>
paul@62 45
#include <l4/sys/irq.h>
paul@62 46
#include <l4/sys/rcv_endpoint.h>
paul@74 47
paul@74 48
#include <l4/io/io.h>
paul@74 49
#include <l4/libedid/edid.h>
paul@62 50
#include <l4/vbus/vbus.h>
paul@74 51
paul@62 52
#include <stdio.h>
paul@62 53
#include <unistd.h>
paul@62 54
#include <stdint.h>
paul@62 55
#include <string.h>
paul@74 56
#include <stdlib.h>
paul@62 57
paul@62 58
paul@62 59
paul@62 60
enum {
paul@62 61
  DDCSCL = 24,  /* via PORTF */
paul@62 62
  DDCSDA = 25,  /* via PORTF */
paul@62 63
};
paul@62 64
paul@62 65
paul@62 66
paul@64 67
/* Test panel. */
paul@64 68
paul@64 69
static struct Jz4740_lcd_panel panel = {
paul@64 70
  .config = (
paul@64 71
      Jz4740_lcd_mode_tft_generic
paul@74 72
    | Jz4740_lcd_bpp_24
paul@74 73
    | Jz4740_lcd_desc_8_word
paul@74 74
    | Jz4740_lcd_underrun_recover
paul@74 75
    | Jz4740_lcd_ps_disabled
paul@74 76
    | Jz4740_lcd_cls_disabled
paul@74 77
    | Jz4740_lcd_spl_disabled
paul@74 78
    | Jz4740_lcd_rev_disabled
paul@64 79
    | Jz4740_lcd_pclock_negative
paul@64 80
    | Jz4740_lcd_hsync_positive
paul@64 81
    | Jz4740_lcd_vsync_positive
paul@64 82
    | Jz4740_lcd_de_positive),
paul@64 83
paul@64 84
  .width = 1280,
paul@64 85
  .height = 1024,
paul@74 86
  .bpp = 24,
paul@64 87
  .frame_rate = 60,
paul@64 88
  .hsync = 112,
paul@64 89
  .vsync = 3,
paul@74 90
  .line_start = 248,  // back porch (blanking - hsync - offset)
paul@64 91
  .line_end = 48,     // front porch (sync offset)
paul@74 92
  .frame_start = 36,  // back porch (blanking - vsync - offset)
paul@64 93
  .frame_end = 3,     // front porch (sync offset)
paul@64 94
};
paul@64 95
paul@64 96
paul@64 97
paul@62 98
/* Device and resource discovery. */
paul@62 99
paul@62 100
static long item_in_range(long start, long end, long index)
paul@62 101
{
paul@62 102
  if (start < end)
paul@62 103
    return start + index;
paul@62 104
  else
paul@62 105
    return start - index;
paul@62 106
}
paul@62 107
paul@62 108
static void show_timings(uint8_t *buf)
paul@62 109
{
paul@62 110
  unsigned int width, height;
paul@62 111
paul@62 112
  /* Attempt to decode EDID information. */
paul@62 113
paul@62 114
  libedid_prefered_resolution(buf, &width, &height);
paul@62 115
  printf("Preferred resolution: %d x %d\n", width, height);
paul@62 116
paul@62 117
  libedid_dump_standard_timings(buf);
paul@62 118
}
paul@62 119
paul@62 120
int main(void)
paul@62 121
{
paul@62 122
  long err;
paul@62 123
paul@62 124
  /* Buffer for EDID data. */
paul@62 125
paul@62 126
  uint8_t edid[128];
paul@62 127
  unsigned int length = 0, i;
paul@62 128
paul@62 129
  /* Version details. */
paul@62 130
paul@62 131
  uint8_t hdmi_major;
paul@62 132
  uint16_t hdmi_minor;
paul@74 133
  const struct Phy_capabilities *phy_def;
paul@62 134
paul@62 135
  /* Peripheral memory. */
paul@62 136
paul@62 137
  l4_addr_t cpm_base = 0, cpm_base_end = 0;
paul@62 138
  l4_addr_t gpio_base = 0, gpio_base_end = 0;
paul@62 139
  l4_addr_t hdmi_base = 0, hdmi_base_end = 0;
paul@64 140
  l4_addr_t lcd_base = 0, lcd_base_end = 0;
paul@62 141
  l4_addr_t port_f, port_f_end;
paul@62 142
paul@62 143
  /* Peripheral abstractions. */
paul@62 144
paul@62 145
  void *cpm;
paul@62 146
  void *gpio_port_f;
paul@62 147
  void *hdmi;
paul@64 148
  void *lcd;
paul@62 149
paul@74 150
  /* Allocated memory. */
paul@74 151
paul@142 152
  l4_cap_idx_t desc_mem, fb_mem, dma, vbus;
paul@74 153
  l4_size_t desc_size, desc_psize, fb_size, fb_psize;
paul@142 154
  l4_addr_t desc_addr, fb_addr;
paul@142 155
  l4re_dma_space_dma_addr_t desc_paddr, fb_paddr;
paul@74 156
  unsigned char *picture;
paul@74 157
  unsigned char *fb_picture, *fb_picture_row;
paul@74 158
  unsigned int x, y;
paul@74 159
paul@62 160
  /* Access to IRQs. */
paul@62 161
paul@62 162
  l4_uint32_t hdmi_irq_start = 0, hdmi_irq_end = 0;
paul@64 163
  l4_uint32_t lcd_irq_start = 0, lcd_irq_end = 0;
paul@142 164
  l4_cap_idx_t icu, hdmi_irq, lcd_irq;
paul@62 165
paul@74 166
  /* Capability allocation. */
paul@74 167
paul@74 168
  desc_mem = l4re_util_cap_alloc();
paul@74 169
  fb_mem = l4re_util_cap_alloc();
paul@142 170
  dma = l4re_util_cap_alloc();
paul@64 171
  hdmi_irq = l4re_util_cap_alloc();
paul@64 172
  lcd_irq = l4re_util_cap_alloc();
paul@142 173
  icu = l4re_env_get_cap("icu");
paul@142 174
  vbus = l4re_env_get_cap("vbus");
paul@62 175
paul@142 176
  if (l4_is_invalid_cap(icu))
paul@62 177
  {
paul@62 178
    printf("No 'icu' capability available in the virtual bus.\n");
paul@62 179
    return 1;
paul@62 180
  }
paul@62 181
paul@74 182
  if (l4_is_invalid_cap(desc_mem) || l4_is_invalid_cap(fb_mem) ||
paul@74 183
      l4_is_invalid_cap(hdmi_irq) || l4_is_invalid_cap(lcd_irq))
paul@62 184
  {
paul@74 185
    printf("Capabilities could not be reserved.\n");
paul@62 186
    return 1;
paul@62 187
  }
paul@62 188
paul@62 189
  /* Obtain resource details describing the interrupt for HDMI I2C. */
paul@62 190
paul@62 191
  printf("Access IRQ...\n");
paul@62 192
paul@62 193
  if (get_irq("jz4780-hdmi", &hdmi_irq_start, &hdmi_irq_end) < 0)
paul@62 194
    return 1;
paul@62 195
paul@64 196
  printf("HDMI IRQ range at %d...%d.\n", hdmi_irq_start, hdmi_irq_end);
paul@64 197
paul@64 198
  if (get_irq("jz4780-lcd", &lcd_irq_start, &lcd_irq_end) < 0)
paul@64 199
    return 1;
paul@64 200
paul@64 201
  printf("LCD IRQ range at %d...%d.\n", lcd_irq_start, lcd_irq_end);
paul@62 202
paul@62 203
  /* Create interrupt objects. */
paul@62 204
paul@64 205
  err = l4_error(l4_factory_create_irq(l4re_global_env->factory, hdmi_irq)) ||
paul@64 206
        l4_error(l4_factory_create_irq(l4re_global_env->factory, lcd_irq));
paul@62 207
paul@62 208
  if (err)
paul@62 209
  {
paul@62 210
    printf("Could not create IRQ object: %lx\n", err);
paul@62 211
    return 1;
paul@62 212
  }
paul@62 213
paul@62 214
  /* Bind interrupt objects to IRQ numbers. Here, the first HDMI interrupt is
paul@62 215
     bound, this being the general HDMI interrupt. */
paul@62 216
paul@142 217
  err = l4_error(l4_icu_bind(icu,
paul@62 218
                             item_in_range(hdmi_irq_start, hdmi_irq_end, 0),
paul@64 219
                             hdmi_irq)) ||
paul@142 220
        l4_error(l4_icu_bind(icu,
paul@64 221
                             item_in_range(lcd_irq_start, lcd_irq_end, 0),
paul@64 222
                             lcd_irq));
paul@62 223
paul@62 224
  if (err)
paul@62 225
  {
paul@62 226
    printf("Could not bind IRQ to the ICU: %ld\n", err);
paul@62 227
    return 1;
paul@62 228
  }
paul@62 229
paul@74 230
  /* Attach ourselves to the interrupt handler with some arbitrary labels. */
paul@62 231
paul@74 232
  err = l4_error(l4_rcv_ep_bind_thread(hdmi_irq, l4re_env()->main_thread, 0x00)) ||
paul@74 233
        l4_error(l4_rcv_ep_bind_thread(lcd_irq, l4re_env()->main_thread, 0x10));
paul@62 234
paul@62 235
  if (err)
paul@62 236
  {
paul@62 237
    printf("Could not attach to IRQs: %ld\n", err);
paul@62 238
    return 1;
paul@62 239
  }
paul@62 240
paul@62 241
  /* Obtain resource details describing I/O memory. */
paul@62 242
paul@62 243
  printf("Access CPM...\n");
paul@62 244
paul@62 245
  if (get_memory("jz4780-cpm", &cpm_base, &cpm_base_end) < 0)
paul@62 246
    return 1;
paul@62 247
paul@62 248
  printf("CPM at 0x%lx...0x%lx.\n", cpm_base, cpm_base_end);
paul@62 249
paul@62 250
  printf("Access GPIO...\n");
paul@62 251
paul@62 252
  if (get_memory("jz4780-gpio", &gpio_base, &gpio_base_end) < 0)
paul@62 253
    return 1;
paul@62 254
paul@62 255
  printf("GPIO at 0x%lx...0x%lx.\n", gpio_base, gpio_base_end);
paul@62 256
paul@62 257
  printf("Access HDMI...\n");
paul@62 258
paul@62 259
  if (get_memory("jz4780-hdmi", &hdmi_base, &hdmi_base_end) < 0)
paul@62 260
    return 1;
paul@62 261
paul@62 262
  printf("HDMI at 0x%lx...0x%lx.\n", hdmi_base, hdmi_base_end);
paul@62 263
paul@64 264
  printf("Access LCD...\n");
paul@64 265
paul@64 266
  if (get_memory("jz4780-lcd", &lcd_base, &lcd_base_end) < 0)
paul@64 267
    return 1;
paul@64 268
paul@64 269
  printf("LCD at 0x%lx...0x%lx.\n", lcd_base, lcd_base_end);
paul@64 270
paul@62 271
  /* Obtain CPM object. */
paul@62 272
paul@62 273
  cpm = jz4780_cpm_init(cpm_base);
paul@62 274
paul@213 275
  printf("VPLL frequency: %lld\n", jz4780_cpm_get_frequency(cpm, Clock_pll_V));
paul@213 276
  printf("HDMI frequency: %lld\n", jz4780_cpm_get_frequency(cpm, Clock_hdmi));
paul@62 277
paul@133 278
  jz4780_cpm_stop_clock(cpm, Clock_hdmi);
paul@160 279
  jz4780_cpm_set_frequency(cpm, Clock_hdmi, 27000000);
paul@62 280
paul@213 281
  printf("HDMI frequency: %lld\n", jz4780_cpm_get_frequency(cpm, Clock_hdmi));
paul@62 282
paul@133 283
  jz4780_cpm_start_clock(cpm, Clock_hdmi);
paul@62 284
paul@62 285
  /* Configure pins. */
paul@62 286
paul@62 287
  port_f = gpio_base + 0x500;
paul@62 288
  port_f_end = port_f + 0x100;
paul@62 289
paul@62 290
  printf("PORTF at 0x%lx...0x%lx.\n", port_f, port_f_end);
paul@62 291
paul@62 292
  gpio_port_f = jz4780_gpio_init(port_f, port_f_end, 32, 0x7fa7f00f, 0x00580ff0);
paul@62 293
paul@62 294
  printf("Set up GPIO pins...\n");
paul@62 295
paul@62 296
  jz4780_gpio_config_pad(gpio_port_f, DDCSCL, Function_alt, 0);
paul@62 297
  jz4780_gpio_config_pad(gpio_port_f, DDCSDA, Function_alt, 0);
paul@62 298
paul@62 299
  /* Obtain HDMI reference. */
paul@62 300
paul@62 301
  printf("Set up HDMI...\n");
paul@62 302
paul@74 303
  hdmi = jz4780_hdmi_init(hdmi_base, hdmi_base_end, hdmi_irq, &panel);
paul@62 304
paul@62 305
  printf("Read version...\n");
paul@62 306
paul@62 307
  jz4780_hdmi_get_version(hdmi, &hdmi_major, &hdmi_minor);
paul@62 308
paul@62 309
  printf("HDMI version is %x.%03x\n", hdmi_major, hdmi_minor);
paul@62 310
paul@74 311
  jz4780_hdmi_get_phy_capabilities(hdmi, &phy_def);
paul@74 312
paul@74 313
  printf("PHY type: %s\n", phy_def->name);
paul@74 314
paul@65 315
  printf("Connected: %s\n", jz4780_hdmi_connected(hdmi) ? "yes" : "no");
paul@65 316
paul@65 317
  while (!jz4780_hdmi_connected(hdmi))
paul@65 318
    jz4780_hdmi_wait_for_connection(hdmi);
paul@65 319
paul@62 320
  printf("Read EDID...\n");
paul@62 321
paul@62 322
  jz4780_hdmi_i2c_set_address(hdmi, 0x50);
paul@62 323
  length = jz4780_hdmi_i2c_read(hdmi, edid, 128);
paul@62 324
paul@62 325
  if (length)
paul@62 326
  {
paul@62 327
    for (i = 0; i < length; i++)
paul@62 328
      printf("%02x%c", edid[i], ((i % 16) != 15) ? ' ' : '\n');
paul@62 329
  }
paul@62 330
paul@62 331
  show_timings(edid);
paul@62 332
paul@64 333
  /* Obtain LCD reference. */
paul@64 334
paul@64 335
  printf("Set up LCD...\n");
paul@64 336
paul@75 337
  lcd = jz4780_lcd_init(lcd_base, &panel);
paul@64 338
paul@64 339
  /* Test initialisation with a frequency appropriate for the test panel. */
paul@64 340
paul@211 341
  printf("LCD source: %d\n", jz4780_cpm_get_source(cpm, Clock_lcd));
paul@213 342
  printf("LCD frequency: %lld\n", jz4780_cpm_get_frequency(cpm, Clock_lcd_pixel0));
paul@64 343
  printf("Desired frequency: %d\n", jz4740_lcd_get_pixel_clock(lcd));
paul@62 344
paul@133 345
  jz4780_cpm_stop_clock(cpm, Clock_lcd);
paul@160 346
  jz4780_cpm_set_frequency(cpm, Clock_lcd, jz4740_lcd_get_pixel_clock(lcd) * 3);
paul@211 347
  jz4780_cpm_set_frequency(cpm, Clock_lcd_pixel0, jz4740_lcd_get_pixel_clock(lcd));
paul@64 348
paul@211 349
  printf("LCD source: %d\n", jz4780_cpm_get_source(cpm, Clock_lcd));
paul@213 350
  printf("LCD frequency: %lld\n", jz4780_cpm_get_frequency(cpm, Clock_lcd_pixel0));
paul@74 351
paul@74 352
  /* With the LCD pixel clock set up, bring up the HDMI. */
paul@74 353
paul@74 354
  printf("Enable HDMI output...\n");
paul@74 355
paul@211 356
  jz4780_hdmi_enable(hdmi, jz4780_cpm_get_frequency(cpm, Clock_lcd_pixel0));
paul@74 357
paul@142 358
  /* Create the DMA space. */
paul@142 359
paul@142 360
  err = l4_error(l4_factory_create(l4re_env()->mem_alloc, L4RE_PROTO_DMA_SPACE, dma));
paul@142 361
paul@142 362
  if (err)
paul@142 363
  {
paul@142 364
    printf("Could not create DMA space: %s\n", l4sys_errtostr(err));
paul@142 365
    return 1;
paul@142 366
  }
paul@142 367
paul@142 368
  l4vbus_device_handle_t device = L4VBUS_NULL;
paul@142 369
  l4vbus_resource_t dma_resource;
paul@142 370
paul@142 371
  if (!find_resource(&device, &dma_resource, L4VBUS_RESOURCE_DMA_DOMAIN))
paul@142 372
  {
paul@142 373
    printf("Could not find DMA domain.\n");
paul@142 374
    return 1;
paul@142 375
  }
paul@142 376
paul@142 377
  err = l4vbus_assign_dma_domain(vbus, dma_resource.start,
paul@142 378
                                 L4VBUS_DMAD_BIND | L4VBUS_DMAD_L4RE_DMA_SPACE,
paul@142 379
                                 dma);
paul@142 380
paul@142 381
  if (err)
paul@142 382
  {
paul@142 383
    printf("Could not assign DMA space: %s\n", l4sys_errtostr(err));
paul@142 384
    return 1;
paul@142 385
  }
paul@142 386
paul@74 387
  /* Allocate descriptors and framebuffer at 2**8 == 256 byte == 64 word alignment. */
paul@74 388
paul@74 389
  desc_size = jz4740_lcd_get_descriptors_size(lcd);
paul@74 390
  fb_size = jz4740_lcd_get_screen_size(lcd);
paul@74 391
paul@142 392
  err = l4re_ma_alloc_align(desc_size, desc_mem, L4RE_MA_CONTINUOUS | L4RE_MA_PINNED, 8) ||
paul@142 393
        l4re_ma_alloc_align(fb_size, fb_mem, L4RE_MA_CONTINUOUS | L4RE_MA_PINNED, 8);
paul@142 394
paul@142 395
  if (err)
paul@74 396
  {
paul@142 397
    printf("Could not allocate memory: %s\n", l4sys_errtostr(err));
paul@74 398
    return 1;
paul@74 399
  }
paul@74 400
paul@142 401
  err = l4re_rm_attach((void **) &desc_addr, desc_size,
paul@142 402
                       L4RE_RM_F_SEARCH_ADDR | L4RE_RM_F_EAGER_MAP | L4RE_RM_F_RW,
paul@142 403
                       desc_mem, 0, L4_PAGESHIFT) ||
paul@142 404
        l4re_rm_attach((void **) &fb_addr, fb_size,
paul@142 405
                       L4RE_RM_F_SEARCH_ADDR | L4RE_RM_F_EAGER_MAP | L4RE_RM_F_RW,
paul@142 406
                       fb_mem, 0, L4_PAGESHIFT);
paul@142 407
paul@142 408
  if (err)
paul@74 409
  {
paul@142 410
    printf("Could not map memory: %s\n", l4sys_errtostr(err));
paul@74 411
    return 1;
paul@74 412
  }
paul@74 413
paul@142 414
  err = l4re_dma_space_map(dma, desc_mem | L4_CAP_FPAGE_RW, 0, &desc_psize, 0,
paul@142 415
                           L4RE_DMA_SPACE_TO_DEVICE, &desc_paddr) ||
paul@142 416
        l4re_dma_space_map(dma, fb_mem | L4_CAP_FPAGE_RW, 0, &fb_psize, 0,
paul@142 417
                           L4RE_DMA_SPACE_TO_DEVICE, &fb_paddr);
paul@142 418
paul@142 419
  if (err)
paul@74 420
  {
paul@142 421
    printf("Could not get physical addresses for memory: %s\n", l4sys_errtostr(err));
paul@74 422
    return 1;
paul@74 423
  }
paul@74 424
paul@142 425
  printf("Descriptors at %lx/%llx, size %d/%d.\n", desc_addr, desc_paddr, desc_size, desc_psize);
paul@142 426
  printf("Framebuffer at %lx/%llx, size %d/%d.\n", fb_addr, fb_paddr, fb_size, fb_psize);
paul@74 427
paul@74 428
  //memset((void *) fb_addr, 0x7f, fb_size);
paul@74 429
paul@74 430
  picture = (unsigned char *) malloc(gimp_image.width * gimp_image.height * gimp_image.bytes_per_pixel);
paul@74 431
paul@74 432
  GIMP_IMAGE_RUN_LENGTH_DECODE(picture,
paul@74 433
                               gimp_image.rle_pixel_data,
paul@74 434
                               gimp_image.width * gimp_image.height,
paul@74 435
                               gimp_image.bytes_per_pixel);
paul@74 436
paul@74 437
  fb_picture_row = (unsigned char *) fb_addr;
paul@74 438
paul@74 439
  for (y = 0; y < gimp_image.height; y++)
paul@74 440
  {
paul@74 441
    fb_picture = fb_picture_row;
paul@74 442
paul@74 443
    for (x = 0; x < gimp_image.width; x++)
paul@74 444
    {
paul@74 445
      *(fb_picture + 2) = *picture++;
paul@74 446
      *(fb_picture + 1) = *picture++;
paul@74 447
      *fb_picture = *picture++;
paul@74 448
      *(fb_picture + 3) = 0;
paul@74 449
      fb_picture += 4;
paul@74 450
    }
paul@74 451
paul@74 452
    fb_picture_row += jz4740_lcd_get_line_size(lcd);
paul@74 453
  }
paul@74 454
paul@74 455
  l4_cache_clean_data((unsigned long) fb_addr, (unsigned long) fb_addr + fb_size);
paul@74 456
paul@74 457
  printf("Start LCD clock and initialise LCD...\n");
paul@64 458
paul@133 459
  jz4780_cpm_start_clock(cpm, Clock_lcd);
paul@74 460
  l4_sleep(1); // 1ms == 1000us
paul@74 461
paul@74 462
  jz4740_lcd_disable(lcd);
paul@74 463
paul@74 464
  jz4740_lcd_set_irq(lcd, lcd_irq, Lcd_irq_frame_end);
paul@74 465
paul@74 466
  jz4740_lcd_config(lcd, (struct Jz4740_lcd_descriptor *) desc_addr,
paul@160 467
                         (struct Jz4740_lcd_descriptor *) (l4_addr_t) desc_paddr,
paul@74 468
                         fb_paddr);
paul@74 469
paul@74 470
  jz4740_lcd_enable(lcd);
paul@74 471
paul@74 472
  printf("LCD enabled: %s\n", jz4740_lcd_enabled(lcd) ? "yes" : "no");
paul@74 473
paul@74 474
  printf("Wait for interrupt conditions...\n");
paul@74 475
paul@74 476
  for (i = 0; i < 30000; i++)
paul@74 477
  {
paul@74 478
    if (jz4740_lcd_wait_for_irq(lcd))
paul@74 479
      continue;
paul@74 480
paul@74 481
    if (!(i % 60))
paul@74 482
      printf("IRQ #%d\n", i);
paul@74 483
  }
paul@64 484
paul@64 485
  /* Detach from the interrupts. */
paul@64 486
paul@64 487
  err = l4_error(l4_irq_detach(hdmi_irq)) ||
paul@64 488
        l4_error(l4_irq_detach(lcd_irq));
paul@62 489
paul@62 490
  if (err)
paul@62 491
    printf("Error detaching from IRQ: %ld\n", err);
paul@62 492
paul@62 493
  printf("Done.\n");
paul@62 494
paul@62 495
  return 0;
paul@62 496
}