1.1 --- a/pkg/devices/lib/lcd/src/jz4740/lcd-jz4740.cc Mon Jun 01 15:43:34 2020 +0200
1.2 +++ b/pkg/devices/lib/lcd/src/jz4740/lcd-jz4740.cc Mon Jun 01 15:47:14 2020 +0200
1.3 @@ -23,19 +23,22 @@
1.4
1.5 #include <l4/devices/hw_mmio_register_block.h>
1.6 #include <l4/sys/cache.h>
1.7 +#include <l4/sys/irq.h>
1.8 #include <l4/sys/types.h>
1.9 +#include <l4/util/util.h>
1.10
1.11 #include "lcd-jz4740.h"
1.12 #include "lcd-jz4740-config.h"
1.13
1.14 #include <stdint.h>
1.15 +#include <stdio.h>
1.16
1.17 enum Regs : unsigned
1.18 {
1.19 Lcd_config = 0x000, // LCD_CFG
1.20 Lcd_vsync = 0x004, // LCD_VSYNC
1.21 Lcd_hsync = 0x008, // LCD_HSYNC
1.22 - Vertical_area = 0x00c, // LCD_VAT
1.23 + Virtual_area = 0x00c, // LCD_VAT
1.24 Display_hlimits = 0x010, // LCD_DAH
1.25 Display_vlimits = 0x014, // LCD_DAV
1.26 Lcd_ps = 0x018, // LCD_PS
1.27 @@ -53,6 +56,14 @@
1.28 Source_address_1 = 0x054, // LCD_SA1
1.29 Frame_id_1 = 0x058, // LCD_FID1
1.30 Command_1 = 0x05c, // LCD_CMD1
1.31 + Rgb_control = 0x090, // LCD_RGBC (JZ4780)
1.32 + Priority_level = 0x2c0, // LCD_PCFG
1.33 +
1.34 + // OSD registers.
1.35 +
1.36 + Osd_config = 0x100, // LCD_OSDC
1.37 + Osd_control = 0x104, // LCD_OSDCTRL
1.38 + Osd_status = 0x108, // LCD_OSDS
1.39 };
1.40
1.41 // Lcd_config descriptions.
1.42 @@ -72,12 +83,12 @@
1.43 Value_second = 0,
1.44 };
1.45
1.46 -// Vertical_area bits.
1.47 +// Virtual area bits.
1.48
1.49 -enum Vertical_area_values : unsigned
1.50 +enum Virtual_area_values : unsigned
1.51 {
1.52 - Vertical_area_horizontal_size = Value_first, // sum of display and blank regions (dot/pixel clock periods)
1.53 - Vertical_area_vertical_size = Value_second, // sum of display and blank regions (line periods)
1.54 + Virtual_area_horizontal_size = Value_first, // sum of display and blank regions (dot/pixel clock periods)
1.55 + Virtual_area_vertical_size = Value_second, // sum of display and blank regions (line periods)
1.56 };
1.57
1.58 // Lcd_control descriptions.
1.59 @@ -169,6 +180,102 @@
1.60 Command_buffer_length_mask = 0x00ffffff,
1.61 };
1.62
1.63 +// Status descriptions.
1.64 +
1.65 +enum Status_bits : unsigned
1.66 +{
1.67 + Status_frame_end_irq = 5,
1.68 + Status_frame_start_irq = 4,
1.69 + Status_disabled = 0,
1.70 +};
1.71 +
1.72 +// OSD configuration bits (JZ4780).
1.73 +
1.74 +enum Osd_config_bits : unsigned
1.75 +{
1.76 + Osd_config_fg1_frame_start_irq_enable = 15,
1.77 + Osd_config_fg1_frame_end_irq_enable = 14,
1.78 + Osd_config_fg0_frame_start_irq_enable = 11,
1.79 + Osd_config_fg0_frame_end_irq_enable = 10,
1.80 + Osd_config_enable = 0,
1.81 +};
1.82 +
1.83 +// RGB control (JZ4780).
1.84 +
1.85 +enum Rgb_control_bits : unsigned
1.86 +{
1.87 + Rgb_data_padded = 15, // RGBDM
1.88 + Rgb_padding_mode = 14, // DMM
1.89 + Rgb_422 = 8, // 422
1.90 + Rgb_format_enable = 7, // RGBFMT
1.91 + Rgb_odd_line = 4, // OddRGB
1.92 + Rgb_even_line = 0, // EvenRGB
1.93 +};
1.94 +
1.95 +enum Rgb_control_values : unsigned
1.96 +{
1.97 + Rgb_padding_end = 0U << Rgb_padding_mode,
1.98 + Rgb_padding_start = 1U << Rgb_padding_mode,
1.99 + Rgb_odd_line_rgb = 0U << Rgb_odd_line,
1.100 + Rgb_odd_line_rbg = 1U << Rgb_odd_line,
1.101 + Rgb_odd_line_grb = 2U << Rgb_odd_line,
1.102 + Rgb_odd_line_gbr = 3U << Rgb_odd_line,
1.103 + Rgb_odd_line_brg = 4U << Rgb_odd_line,
1.104 + Rgb_odd_line_bgr = 5U << Rgb_odd_line,
1.105 + Rgb_even_line_rgb = 0U << Rgb_even_line,
1.106 + Rgb_even_line_rbg = 1U << Rgb_even_line,
1.107 + Rgb_even_line_grb = 2U << Rgb_even_line,
1.108 + Rgb_even_line_gbr = 3U << Rgb_even_line,
1.109 + Rgb_even_line_brg = 4U << Rgb_even_line,
1.110 + Rgb_even_line_bgr = 5U << Rgb_even_line,
1.111 +};
1.112 +
1.113 +// Priority level.
1.114 +
1.115 +enum Priority_level_bits : unsigned
1.116 +{
1.117 + Priority_mode = 31,
1.118 + Priority_highest_burst = 28,
1.119 + Priority_threshold2 = 18,
1.120 + Priority_threshold1 = 9,
1.121 + Priority_threshold0 = 0,
1.122 +};
1.123 +
1.124 +enum Priority_level_values : unsigned
1.125 +{
1.126 + Priority_mode_dynamic = 0U << Priority_mode,
1.127 + Priority_mode_arbiter = 1U << Priority_mode,
1.128 +};
1.129 +
1.130 +enum Priority_burst_values : unsigned
1.131 +{
1.132 + Priority_burst_4 = 0,
1.133 + Priority_burst_8 = 1,
1.134 + Priority_burst_16 = 2,
1.135 + Priority_burst_32 = 3,
1.136 + Priority_burst_64 = 4,
1.137 + Priority_burst_16_cont = 5,
1.138 + Priority_burst_disable = 7,
1.139 +};
1.140 +
1.141 +// Position descriptor member.
1.142 +
1.143 +enum Position_bits : unsigned
1.144 +{
1.145 + Position_bpp = 27,
1.146 + Position_premultiply_lcd = 26,
1.147 + Position_coefficient = 24,
1.148 + Position_y_position = 12,
1.149 + Position_x_position = 0,
1.150 +};
1.151 +
1.152 +enum Position_values : unsigned
1.153 +{
1.154 + Position_bpp_15_16bpp = 4,
1.155 + Position_bpp_18_24bpp = 5,
1.156 + Position_bpp_30bpp = 7,
1.157 +};
1.158 +
1.159
1.160
1.161 // Utility functions.
1.162 @@ -210,6 +317,7 @@
1.163 : _panel(panel)
1.164 {
1.165 _regs = new Hw::Mmio_register_block<32>(addr);
1.166 + //_burst_size = 64; // 64-word burst size (JZ4780)
1.167 _burst_size = 16; // 16-word burst size
1.168
1.169 // add_cid("lcd");
1.170 @@ -227,7 +335,7 @@
1.171 {
1.172 // Set the disable bit for normal shutdown.
1.173
1.174 - _regs[Lcd_control] = _regs[Lcd_control] | (1 << Control_disable);
1.175 + _regs[Lcd_control] = _regs[Lcd_control] | (1U << Control_disable);
1.176 }
1.177
1.178 void
1.179 @@ -235,15 +343,25 @@
1.180 {
1.181 // Clear the enable bit for quick shutdown.
1.182
1.183 - _regs[Lcd_control] = _regs[Lcd_control] & ~(1 << Control_enable);
1.184 + _regs[Lcd_control] = _regs[Lcd_control] & ~(1U << Control_enable);
1.185 }
1.186
1.187 void
1.188 Lcd_jz4740_chip::enable()
1.189 {
1.190 // Clear the disable bit and set the enable bit.
1.191 + // JZ4780: OSD status set.
1.192
1.193 - _regs[Lcd_control] = (_regs[Lcd_control] & ~(1 << Control_disable)) | (1 << Control_enable);
1.194 + _regs[Osd_status] = 0;
1.195 + _regs[Lcd_status] = 0;
1.196 + _regs[Lcd_control] = (_regs[Lcd_control] & ~(1U << Control_disable)) | (1U << Control_enable);
1.197 + printf("LCD control: %x\n", (unsigned int) _regs[Lcd_control]);
1.198 +}
1.199 +
1.200 +bool
1.201 +Lcd_jz4740_chip::enabled()
1.202 +{
1.203 + return !(_regs[Lcd_status] & (1U << Status_disabled));
1.204 }
1.205
1.206 // Calculate and return the pixel clock frequency.
1.207 @@ -346,6 +464,19 @@
1.208
1.209
1.210
1.211 +// Return the pixel memory size in bits.
1.212 +
1.213 +l4_size_t
1.214 +Lcd_jz4740_chip::get_pixel_size()
1.215 +{
1.216 + if (_panel->bpp > 16)
1.217 + return 32;
1.218 + else if (_panel->bpp > 8)
1.219 + return 16;
1.220 + else
1.221 + return _panel->bpp;
1.222 +}
1.223 +
1.224 // Return the line memory size.
1.225
1.226 l4_size_t
1.227 @@ -353,7 +484,7 @@
1.228 {
1.229 // Lines must be aligned to a word boundary.
1.230
1.231 - return align((_panel->width * _panel->bpp) / 8, sizeof(uint32_t));
1.232 + return align((_panel->width * get_pixel_size()) / 8, sizeof(uint32_t));
1.233 }
1.234
1.235 // Return the screen memory size.
1.236 @@ -383,7 +514,7 @@
1.237
1.238 // Get the size of a collection of two-byte entries, one per colour.
1.239
1.240 - return (1 << (_panel->bpp)) * sizeof(uint16_t);
1.241 + return (1U << (_panel->bpp)) * sizeof(uint16_t);
1.242 }
1.243
1.244 // Return the aligned size of the palette for the DMA transfer.
1.245 @@ -438,7 +569,7 @@
1.246 void
1.247 Lcd_jz4740_chip::init_palette(l4_addr_t palette)
1.248 {
1.249 - uint8_t colours = 1 << (_panel->bpp);
1.250 + uint8_t colours = 1U << (_panel->bpp);
1.251 uint16_t *entry = (uint16_t *) palette;
1.252 uint16_t *end = entry + colours;
1.253 uint8_t value = 0;
1.254 @@ -486,13 +617,32 @@
1.255 }
1.256 }
1.257
1.258 +// Return colour depth control value.
1.259 +// JZ4780 position details only.
1.260 +
1.261 +uint32_t
1.262 +Lcd_jz4740_chip::_position_bpp()
1.263 +{
1.264 + uint32_t value;
1.265 +
1.266 + switch (_panel->bpp)
1.267 + {
1.268 + case 15: case 16: value = Position_bpp_15_16bpp; break;
1.269 + case 18: case 24: value = Position_bpp_18_24bpp; break;
1.270 + case 30: value = Position_bpp_30bpp; break;
1.271 + default: value = 0; break;
1.272 + }
1.273 +
1.274 + return value << Position_bpp;
1.275 +}
1.276 +
1.277 // Return a panel-related control value.
1.278
1.279 uint32_t
1.280 Lcd_jz4740_chip::_control_panel()
1.281 {
1.282 if (have_stn_panel())
1.283 - return _control_stn_frc();
1.284 + return _control_stn_frc() << Control_frc_algorithm;
1.285 else
1.286 return 0;
1.287 }
1.288 @@ -526,7 +676,65 @@
1.289 default: length = Burst_length_16; break;
1.290 }
1.291
1.292 - return (length << Control_burst_length) | (1 << Control_out_underrun);
1.293 + return (length << Control_burst_length) | (1U << Control_out_underrun);
1.294 +}
1.295 +
1.296 +// Return an interrupt-related control value.
1.297 +
1.298 +uint32_t
1.299 +Lcd_jz4740_chip::_control_irq()
1.300 +{
1.301 + return ((_irq_conditions & Lcd_irq_frame_start) ? (1U << Control_frame_start_irq_enable) : 0) |
1.302 + ((_irq_conditions & Lcd_irq_frame_end) ? (1U << Control_frame_end_irq_enable) : 0);
1.303 +}
1.304 +
1.305 +// Return an interrupt-related OSD configuration value.
1.306 +
1.307 +uint32_t
1.308 +Lcd_jz4740_chip::_osd_config_irq()
1.309 +{
1.310 + return ((_irq_conditions & Lcd_irq_frame_start) ? (1U << Osd_config_fg0_frame_start_irq_enable) : 0) |
1.311 + ((_irq_conditions & Lcd_irq_frame_end) ? (1U << Osd_config_fg0_frame_end_irq_enable) : 0);
1.312 +}
1.313 +
1.314 +// Return an interrupt-related command value.
1.315 +
1.316 +uint32_t
1.317 +Lcd_jz4740_chip::_command_irq()
1.318 +{
1.319 + return ((_irq_conditions & Lcd_irq_frame_start) ? (1U << Command_frame_start_irq) : 0) |
1.320 + ((_irq_conditions & Lcd_irq_frame_end) ? (1U << Command_frame_end_irq) : 0);
1.321 +}
1.322 +
1.323 +// Return an interrupt-related status value.
1.324 +
1.325 +uint32_t
1.326 +Lcd_jz4740_chip::_status_irq()
1.327 +{
1.328 + return ((_irq_conditions & Lcd_irq_frame_start) ? (1U << Status_frame_start_irq) : 0) |
1.329 + ((_irq_conditions & Lcd_irq_frame_end) ? (1U << Status_frame_end_irq) : 0);
1.330 +}
1.331 +
1.332 +uint32_t
1.333 +Lcd_jz4740_chip::_priority_transfer()
1.334 +{
1.335 + uint32_t length;
1.336 +
1.337 + switch (_burst_size)
1.338 + {
1.339 + case 4: length = Priority_burst_4; break;
1.340 + case 8: length = Priority_burst_8; break;
1.341 + case 32: length = Priority_burst_32; break;
1.342 + case 64: length = Priority_burst_64; break;
1.343 + case 16:
1.344 + default: length = Priority_burst_16; break;
1.345 + }
1.346 +
1.347 + return Priority_mode_arbiter |
1.348 + (length << Priority_highest_burst) |
1.349 + (511U << Priority_threshold2) |
1.350 + (400U << Priority_threshold1) |
1.351 + (256U << Priority_threshold0);
1.352 }
1.353
1.354 // STN panel-specific initialisation.
1.355 @@ -564,8 +772,8 @@
1.356
1.357 // Set the display area and limits.
1.358
1.359 - _regs[Vertical_area] = encode_pair(line_end_pos + hsync + line_end,
1.360 - frame_end_pos + _panel->vsync + _panel->frame_end + _panel->frame_start);
1.361 + _regs[Virtual_area] = encode_pair(line_end_pos + hsync + line_end,
1.362 + frame_end_pos + _panel->vsync + _panel->frame_end + _panel->frame_start);
1.363
1.364 _regs[Display_hlimits] = encode_pair(line_start_pos, line_end_pos);
1.365 _regs[Display_vlimits] = encode_pair(frame_start_pos, frame_end_pos);
1.366 @@ -594,8 +802,8 @@
1.367
1.368 // Set the display area and limits.
1.369
1.370 - _regs[Vertical_area] = encode_pair(line_end_pos + _panel->line_end,
1.371 - frame_end_pos + _panel->frame_end);
1.372 + _regs[Virtual_area] = encode_pair(line_end_pos + _panel->line_end,
1.373 + frame_end_pos + _panel->frame_end);
1.374
1.375 _regs[Display_hlimits] = encode_pair(line_start_pos, line_end_pos);
1.376 _regs[Display_vlimits] = encode_pair(frame_start_pos, frame_end_pos);
1.377 @@ -632,8 +840,24 @@
1.378
1.379 desc.next = next;
1.380 desc.source = source;
1.381 - desc.identifier = 0;
1.382 - desc.command = ((size / sizeof(uint32_t)) & Command_buffer_length_mask) | flags;
1.383 + desc.identifier = source;
1.384 + desc.command = ((size / sizeof(uint32_t)) & Command_buffer_length_mask) |
1.385 + (1U << Command_frame_enable) |
1.386 + flags;
1.387 +
1.388 + printf("next = %08x\n", desc.next);
1.389 + printf("source = %08x\n", desc.source);
1.390 + printf("identifier = %08x\n", desc.identifier);
1.391 + printf("command = %08x\n", desc.command);
1.392 +
1.393 + // Initialise "new" descriptor fields.
1.394 +
1.395 + desc.offset = 0;
1.396 + desc.page_width = 0;
1.397 + desc.command_position = (1UL << Position_premultiply_lcd) |
1.398 + (1UL << Position_coefficient) |
1.399 + _position_bpp();
1.400 + desc.fg_size = 0xff000000 | (1023 << 12) | (1279 << 0); // JZ4780 driver magic
1.401 }
1.402
1.403
1.404 @@ -646,28 +870,33 @@
1.405 struct Jz4740_lcd_descriptor *desc_paddr,
1.406 l4_addr_t fb_paddr)
1.407 {
1.408 + // NOTE: Remarks in the Ingenic Linux 3.0.8 driver suggest that the JZ4775 and
1.409 + // NOTE: JZ4780 do not support palettes.
1.410 +
1.411 int have_palette = (_panel->bpp <= 8);
1.412
1.413 // Provide the first framebuffer descriptor in single and dual modes.
1.414 // Flip back and forth between any palette and the framebuffer.
1.415
1.416 _set_descriptor(desc_vaddr[0], get_framebuffer(0, fb_paddr),
1.417 - get_screen_size(),
1.418 - have_palette ? desc_paddr + 2 : desc_paddr);
1.419 + get_aligned_size(),
1.420 + have_palette ? desc_paddr + 2 : desc_paddr,
1.421 + _command_irq());
1.422
1.423 // Provide the second framebuffer descriptor only in dual-panel mode.
1.424 // Only employ this descriptor in the second DMA channel.
1.425
1.426 if (get_panels() == 2)
1.427 _set_descriptor(desc_vaddr[1], get_framebuffer(1, fb_paddr),
1.428 - get_screen_size(),
1.429 - desc_paddr + 1);
1.430 + get_aligned_size(),
1.431 + desc_paddr + 1,
1.432 + _command_irq());
1.433
1.434 // Initialise palette descriptor details for lower colour depths.
1.435
1.436 if (have_palette)
1.437 _set_descriptor(desc_vaddr[2], get_palette(fb_paddr),
1.438 - get_palette_size(),
1.439 + get_aligned_palette_size(),
1.440 desc_paddr,
1.441 Command_palette_buffer);
1.442
1.443 @@ -681,6 +910,7 @@
1.444 // Provide the palette descriptor address first, if employed.
1.445
1.446 _regs[Desc_address_0] = (uint32_t) (have_palette ? desc_paddr + 2 : desc_paddr);
1.447 + printf("descriptor = %08x\n", (uint32_t) _regs[Desc_address_0]);
1.448
1.449 // Provide a descriptor for the second DMA channel in dual-panel mode.
1.450
1.451 @@ -692,9 +922,66 @@
1.452 _init_panel();
1.453
1.454 // Initialise the control and configuration registers.
1.455 + // NOTE: JZ4780 does not support bpp setting here.
1.456
1.457 - _regs[Lcd_control] = _control_panel() | _control_bpp() | _control_transfer();
1.458 + _regs[Lcd_control] = _control_panel() | _control_bpp() | _control_transfer() | _control_irq();
1.459 _regs[Lcd_config] = _panel->config;
1.460 +
1.461 + // NOTE: JZ4780 only.
1.462 +
1.463 + _regs[Rgb_control] = (1U << Rgb_format_enable) | Rgb_odd_line_rgb | Rgb_even_line_rgb;
1.464 + _regs[Priority_level] = _priority_transfer();
1.465 + _regs[Osd_config] = 0; // (1U << Osd_config_enable) | _osd_config_irq();
1.466 +
1.467 + printf("LCD control: %08x\n", (unsigned int) _regs[Lcd_control]);
1.468 + printf("LCD status: %08x\n", (unsigned int) _regs[Lcd_status]);
1.469 + printf("OSD config: %08x\n", (unsigned int) _regs[Osd_config]);
1.470 + printf("OSD status: %08x\n", (unsigned int) _regs[Osd_status]);
1.471 +}
1.472 +
1.473 +// Set the interrupt for controller-related events.
1.474 +
1.475 +void
1.476 +Lcd_jz4740_chip::set_irq(l4_cap_idx_t irq, enum Jz4740_lcd_irq_condition conditions)
1.477 +{
1.478 + _irq = irq;
1.479 + _irq_conditions = conditions;
1.480 +}
1.481 +
1.482 +// Wait for an interrupt condition.
1.483 +
1.484 +long
1.485 +Lcd_jz4740_chip::wait_for_irq()
1.486 +{
1.487 + long err;
1.488 + l4_msgtag_t tag;
1.489 +
1.490 + _regs[Lcd_status] = _regs[Lcd_status] & ~(_status_irq());
1.491 +
1.492 + // Wait for a condition.
1.493 +
1.494 + printf("Waiting for IRQ...\n");
1.495 + tag = l4_irq_receive(_irq, l4_timeout(L4_IPC_TIMEOUT_NEVER, l4util_micros2l4to(1000000)));
1.496 + printf("LCD status: %08x\n", (unsigned int) _regs[Lcd_status]);
1.497 + printf("OSD status: %08x\n", (unsigned int) _regs[Osd_status]);
1.498 + printf("LCD control: %08x\n", (unsigned int) _regs[Lcd_control]);
1.499 + printf("LCD command: %08x\n", (unsigned int) _regs[Command_0]);
1.500 + printf("LCD IRQ id: %08x\n", (unsigned int) _regs[Lcd_irq_id]);
1.501 + printf("LCD descriptor: %08x\n", (unsigned int) _regs[Desc_address_0]);
1.502 + printf("LCD source: %08x\n", (unsigned int) _regs[Source_address_0]);
1.503 + printf("LCD frame id: %08x\n", (unsigned int) _regs[Frame_id_0]);
1.504 +
1.505 + // Return errors immediately.
1.506 +
1.507 + err = l4_ipc_error(tag, l4_utcb());
1.508 + if (err)
1.509 + return err;
1.510 +
1.511 + // Acknowledge interrupts.
1.512 +
1.513 + _regs[Lcd_status] = _regs[Lcd_status] & ~(_status_irq());
1.514 +
1.515 + return L4_EOK;
1.516 }
1.517
1.518
1.519 @@ -716,6 +1003,18 @@
1.520 }
1.521
1.522 void
1.523 +jz4740_lcd_set_irq(void *lcd, l4_cap_idx_t irq, enum Jz4740_lcd_irq_condition conditions)
1.524 +{
1.525 + static_cast<Lcd_jz4740_chip *>(lcd)->set_irq(irq, conditions);
1.526 +}
1.527 +
1.528 +long
1.529 +jz4740_lcd_wait_for_irq(void *lcd)
1.530 +{
1.531 + return static_cast<Lcd_jz4740_chip *>(lcd)->wait_for_irq();
1.532 +}
1.533 +
1.534 +void
1.535 jz4740_lcd_disable(void *lcd)
1.536 {
1.537 static_cast<Lcd_jz4740_chip *>(lcd)->disable();
1.538 @@ -734,11 +1033,29 @@
1.539 }
1.540
1.541 int
1.542 +jz4740_lcd_enabled(void *lcd)
1.543 +{
1.544 + return (int) static_cast<Lcd_jz4740_chip *>(lcd)->enabled();
1.545 +}
1.546 +
1.547 +int
1.548 jz4740_lcd_get_pixel_clock(void *lcd)
1.549 {
1.550 return static_cast<Lcd_jz4740_chip *>(lcd)->get_pixel_clock();
1.551 }
1.552
1.553 +l4_size_t
1.554 +jz4740_lcd_get_descriptors_size(void *lcd)
1.555 +{
1.556 + return static_cast<Lcd_jz4740_chip *>(lcd)->get_descriptors_size();
1.557 +}
1.558 +
1.559 +l4_size_t
1.560 +jz4740_lcd_get_screen_size(void *lcd)
1.561 +{
1.562 + return static_cast<Lcd_jz4740_chip *>(lcd)->get_screen_size();
1.563 +}
1.564 +
1.565 l4_addr_t
1.566 jz4740_lcd_get_palette(void *lcd, l4_addr_t base)
1.567 {