1 /* 2 * LCD peripheral support for the JZ4740 and related SoCs. 3 * 4 * Copyright (C) Xiangfu Liu <xiangfu@sharism.cc> 5 * Copyright (C) 2015, 2016, 2017, 2018 Paul Boddie <paul@boddie.org.uk> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation; either version 2 of 10 * the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 * Boston, MA 02110-1301, USA 21 */ 22 23 #include <l4/devices/hw_mmio_register_block.h> 24 #include <l4/sys/cache.h> 25 #include <l4/sys/types.h> 26 27 #include "lcd-jz4740.h" 28 #include "lcd-jz4740-config.h" 29 30 #include <stdint.h> 31 32 enum Regs : unsigned 33 { 34 Lcd_config = 0x000, // LCD_CFG 35 Lcd_vsync = 0x004, // LCD_VSYNC 36 Lcd_hsync = 0x008, // LCD_HSYNC 37 Vertical_area = 0x00c, // LCD_VAT 38 Display_hlimits = 0x010, // LCD_DAH 39 Display_vlimits = 0x014, // LCD_DAV 40 Lcd_ps = 0x018, // LCD_PS 41 Lcd_cls = 0x01c, // LCD_CLS 42 Lcd_spl = 0x020, // LCD_SPL 43 Lcd_rev = 0x024, // LCD_REV 44 Lcd_control = 0x030, // LCD_CTRL 45 Lcd_status = 0x034, // LCD_STATE 46 Lcd_irq_id = 0x038, // LCD_IID 47 Desc_address_0 = 0x040, // LCD_DA0 48 Source_address_0 = 0x044, // LCD_SA0 49 Frame_id_0 = 0x048, // LCD_FID0 50 Command_0 = 0x04c, // LCD_CMD0 51 Desc_address_1 = 0x050, // LCD_DA1 52 Source_address_1 = 0x054, // LCD_SA1 53 Frame_id_1 = 0x058, // LCD_FID1 54 Command_1 = 0x05c, // LCD_CMD1 55 }; 56 57 // Lcd_config descriptions. 58 59 enum Config_values : unsigned 60 { 61 Config_stn_pins_mask = 0x3, 62 Config_mode_mask = 0xf, 63 }; 64 65 // Field positions for registers employing two values, with the first typically 66 // being the start value and the second being an end value. 67 68 enum Value_pair_bits : unsigned 69 { 70 Value_first = 16, 71 Value_second = 0, 72 }; 73 74 // Vertical_area bits. 75 76 enum Vertical_area_values : unsigned 77 { 78 Vertical_area_horizontal_size = Value_first, // sum of display and blank regions (dot/pixel clock periods) 79 Vertical_area_vertical_size = Value_second, // sum of display and blank regions (line periods) 80 }; 81 82 // Lcd_control descriptions. 83 84 enum Control_bits : unsigned 85 { 86 Control_burst_length = 28, // BST (burst length selection) 87 Control_rgb_mode = 27, // RGB (RGB mode) 88 Control_out_underrun = 26, // OFUP (output FIFO underrun protection) 89 Control_frc_algorithm = 24, // FRC (STN FRC algorithm selection) 90 Control_palette_delay = 16, // PDD (load palette delay counter) 91 Control_frame_end_irq_mask = 13, // EOFM (end of frame interrupt mask) 92 Control_frame_start_irq_mask = 12, // SOFM (start of frame interrupt mask) 93 Control_out_underrun_irq_mask = 11, // OFUM (output FIFO underrun interrupt mask) 94 Control_in0_underrun_irq_mask = 10, // IFUM0 (input FIFO 0 underrun interrupt mask) 95 Control_in1_underrun_irq_mask = 9, // IFUM1 (input FIFO 1 underrun interrupt mask) 96 Control_disabled_irq_mask = 8, // LDDM (LCD disable done interrupt mask) 97 Control_quick_disabled_irq_mask = 7, // QDM (LCD quick disable done interrupt mask) 98 Control_endian_select = 6, // BEDN (endian selection) 99 Control_bit_order = 5, // PEDN (bit order in bytes) 100 Control_disable = 4, // DIS (disable controller) 101 Control_enable = 3, // ENA (enable controller) 102 Control_bpp = 0, // BPP (bits per pixel) 103 }; 104 105 enum Burst_length_values : unsigned 106 { 107 Burst_length_4 = 0, // 4 word 108 Burst_length_8 = 1, // 8 word 109 Burst_length_16 = 2, // 16 word 110 111 // JZ4780 extensions. 112 113 Burst_length_32 = 3, // 32 word 114 Burst_length_64 = 4, // 64 word 115 Burst_length_mask = 0x7, 116 }; 117 118 enum Rgb_mode_values : unsigned 119 { 120 Rgb_mode_565 = 0, 121 Rgb_mode_555 = 1, 122 Rgb_mode_mask = 0x1, 123 }; 124 125 enum Frc_algorithm_values : unsigned 126 { 127 Frc_greyscales_16 = 0, 128 Frc_greyscales_4 = 1, 129 Frc_greyscales_2 = 2, 130 Frc_greyscales_mask = 0x3, 131 }; 132 133 enum Control_bpp_values : unsigned 134 { 135 Control_bpp_1bpp = 0, 136 Control_bpp_2bpp = 1, 137 Control_bpp_4bpp = 2, 138 Control_bpp_8bpp = 3, 139 Control_bpp_15bpp = 4, 140 Control_bpp_16bpp = 4, 141 Control_bpp_18bpp = 5, 142 Control_bpp_24bpp = 5, 143 Control_bpp_24bpp_comp = 6, 144 Control_bpp_30bpp = 7, 145 Control_bpp_32bpp = 7, 146 Control_bpp_mask = 0x7, 147 }; 148 149 // Command descriptions. 150 151 enum Command_bits : unsigned 152 { 153 Command_frame_start_irq = 31, // SOFINT (start of frame interrupt) 154 Command_frame_end_irq = 30, // EOFINT (end of frame interrupt) 155 Command_lcm_command = 29, // JZ4780: CMD (LCM command/data via DMA0) 156 Command_palette_buffer = 28, // PAL (descriptor references palette, not display data) 157 Command_frame_compressed = 27, // JZ4780: COMPEN (16/24bpp compression enabled) 158 Command_frame_enable = 26, // JZ4780: FRM_EN 159 Command_field_even = 25, // JZ4780: FIELD_SEL (interlace even field) 160 Command_16x16_block = 24, // JZ4780: 16x16BLOCK (fetch data by 16x16 block) 161 Command_buffer_length = 0, // LEN 162 }; 163 164 enum Command_values : unsigned 165 { 166 Command_buffer_length_mask = 0x00ffffff, 167 }; 168 169 170 171 // Utility functions. 172 173 // Round values up according to the resolution. 174 175 static uint32_t align(uint32_t value, uint32_t resolution) 176 { 177 return (value + (resolution - 1)) & ~(resolution - 1); 178 } 179 180 // Value pair encoding. 181 182 static uint32_t encode_pair(uint32_t start, uint32_t end) 183 { 184 return (start << Value_first) | (end << Value_second); 185 } 186 187 // RGB conversions. 188 189 static uint16_t rgb8_to_rgb16(uint8_t rgb) 190 { 191 return ((((rgb & 0xe0) >> 5) * 4) << 11) | ((((rgb & 0x1c) >> 2) * 9) << 6) | ((rgb & 0x03) * 10); 192 } 193 194 static uint16_t rgb4_to_rgb16(uint8_t rgb) 195 { 196 return ((((rgb & 8) >> 3) * 0x1f) << 11) | ((((rgb & 6) >> 1) * 0x15) << 5) | ((rgb & 1) * 0x1f); 197 } 198 199 200 201 202 // If implemented as a Hw::Device, various properties would be 203 // initialised in the constructor and obtained from the device tree 204 // definitions. 205 206 Lcd_jz4740_chip::Lcd_jz4740_chip(l4_addr_t addr, Jz4740_lcd_panel *panel) 207 : _panel(panel) 208 { 209 _regs = new Hw::Mmio_register_block<32>(addr); 210 _burst_size = 16; // 16-word burst size 211 212 // add_cid("lcd"); 213 // add_cid("lcd-jz4740"); 214 } 215 216 struct Jz4740_lcd_panel * 217 Lcd_jz4740_chip::get_panel() 218 { 219 return _panel; 220 } 221 222 void 223 Lcd_jz4740_chip::disable() 224 { 225 // Set the disable bit for normal shutdown. 226 227 _regs[Lcd_control] = _regs[Lcd_control] | (1 << Control_disable); 228 } 229 230 void 231 Lcd_jz4740_chip::disable_quick() 232 { 233 // Clear the enable bit for quick shutdown. 234 235 _regs[Lcd_control] = _regs[Lcd_control] & ~(1 << Control_enable); 236 } 237 238 void 239 Lcd_jz4740_chip::enable() 240 { 241 // Clear the disable bit and set the enable bit. 242 243 _regs[Lcd_control] = (_regs[Lcd_control] & ~(1 << Control_disable)) | (1 << Control_enable); 244 } 245 246 // Calculate and return the pixel clock frequency. 247 248 int 249 Lcd_jz4740_chip::get_pixel_clock() 250 { 251 int pclk, multiplier; 252 253 // Serial mode: 3 pixel clock cycles per pixel (one per channel). 254 // Parallel mode: 1 pixel clock cycle per pixel. 255 256 multiplier = have_serial_tft() ? 3 : 1; 257 258 // Derive pixel clock rate from frame rate. 259 // This multiplies the number of pixel periods in a line by the number of 260 // lines in a frame, thus obtaining the number of such periods in a frame. 261 // Multiplying this result with the frame rate yields the pixel frequency. 262 263 pclk = _panel->frame_rate * 264 (_panel->width * multiplier + 265 _panel->hsync + _panel->line_start + _panel->line_end) * 266 (_panel->height + 267 _panel->vsync + _panel->frame_start + _panel->frame_end); 268 269 // STN panel adjustments. 270 271 if (have_stn_panel()) 272 { 273 // Colour STN panels apparently need to be driven at three times the rate. 274 275 if (have_colour_stn()) pclk = (pclk * 3); 276 277 // Reduce the rate according to the width of the STN connection. 278 // Since the pins setting employs log2(pins), a shift by this value is 279 // equivalent to a division by the number of pins. 280 281 pclk = pclk >> ((_panel->config & Config_stn_pins_mask) >> Jz4740_lcd_config_stn_pins); 282 283 // Divide the rate by the number of panels. 284 285 pclk /= get_panels(); 286 } 287 288 return pclk; 289 } 290 291 292 293 // Return the panel mode. 294 295 uint32_t 296 Lcd_jz4740_chip::_mode() 297 { 298 return _panel->config & Config_mode_mask; 299 } 300 301 // Return the number of panels available. 302 303 int 304 Lcd_jz4740_chip::get_panels() 305 { 306 uint32_t mode = _mode(); 307 308 return (mode == Jz4740_lcd_mode_stn_dual_colour) || 309 (mode == Jz4740_lcd_mode_stn_dual_mono) ? 2 : 1; 310 } 311 312 // Return whether the panel is STN. 313 314 int 315 Lcd_jz4740_chip::have_stn_panel() 316 { 317 uint32_t mode = _mode(); 318 319 return ((mode == Jz4740_lcd_mode_stn_single_colour) || 320 (mode == Jz4740_lcd_mode_stn_dual_colour) || 321 (mode == Jz4740_lcd_mode_stn_single_mono) || 322 (mode == Jz4740_lcd_mode_stn_dual_mono)); 323 } 324 325 // Return whether the panel is colour STN. 326 327 int 328 Lcd_jz4740_chip::have_colour_stn() 329 { 330 uint32_t mode = _mode(); 331 332 return ((mode == Jz4740_lcd_mode_stn_single_colour) || 333 (mode == Jz4740_lcd_mode_stn_dual_colour)); 334 } 335 336 // Return whether the panel is colour STN. 337 338 int 339 Lcd_jz4740_chip::have_serial_tft() 340 { 341 return _mode() == Jz4740_lcd_mode_tft_serial; 342 } 343 344 345 346 // Return the line memory size. 347 348 l4_size_t 349 Lcd_jz4740_chip::get_line_size() 350 { 351 // Lines must be aligned to a word boundary. 352 353 return align((_panel->width * _panel->bpp) / 8, sizeof(uint32_t)); 354 } 355 356 // Return the screen memory size. 357 358 l4_size_t 359 Lcd_jz4740_chip::get_screen_size() 360 { 361 return get_line_size() * _panel->height; 362 } 363 364 // Return the aligned size for the DMA transfer. 365 366 l4_size_t 367 Lcd_jz4740_chip::get_aligned_size() 368 { 369 return align(get_screen_size(), _burst_size * sizeof(uint32_t)); 370 } 371 372 // Return the size of the palette. 373 374 l4_size_t 375 Lcd_jz4740_chip::get_palette_size() 376 { 377 // No palette for modes with more than eight bits per pixel. 378 379 if (_panel->bpp > 8) return 0; 380 381 // Get the size of a collection of two-byte entries, one per colour. 382 383 return (1 << (_panel->bpp)) * sizeof(uint16_t); 384 } 385 386 // Return the aligned size of the palette for the DMA transfer. 387 388 l4_size_t 389 Lcd_jz4740_chip::get_aligned_palette_size() 390 { 391 return align(get_palette_size(), _burst_size * sizeof(uint32_t)); 392 } 393 394 // Return the total memory requirements of the framebuffers and palette. 395 396 l4_size_t 397 Lcd_jz4740_chip::get_total_size() 398 { 399 return get_aligned_size() * get_panels() + get_aligned_palette_size(); 400 } 401 402 // Return the total memory requirements of any DMA descriptors. 403 404 l4_size_t 405 Lcd_jz4740_chip::get_descriptors_size() 406 { 407 return 3 * sizeof(struct Jz4740_lcd_descriptor); 408 } 409 410 411 412 // Functions returning addresses of each data region. 413 // The base parameter permits the retrieval of virtual or physical addresses. 414 415 l4_addr_t 416 Lcd_jz4740_chip::get_palette(l4_addr_t base) 417 { 418 // Use memory at the end of the allocated region for the palette. 419 420 return base + (get_panels() * get_aligned_size()) - get_aligned_palette_size(); 421 } 422 423 l4_addr_t 424 Lcd_jz4740_chip::get_framebuffer(int panel, l4_addr_t base) 425 { 426 // Framebuffers for panels are allocated at the start of the region. 427 428 return base + (panel * get_aligned_size()); 429 } 430 431 432 433 // Palette initialisation. 434 435 void 436 Lcd_jz4740_chip::init_palette(l4_addr_t palette) 437 { 438 uint8_t colours = 1 << (_panel->bpp); 439 uint16_t *entry = (uint16_t *) palette; 440 uint16_t *end = entry + colours; 441 uint8_t value = 0; 442 443 while (entry < end) 444 { 445 switch (_panel->bpp) 446 { 447 case 4: 448 *entry = rgb4_to_rgb16(value); 449 break; 450 451 case 8: 452 *entry = rgb8_to_rgb16(value); 453 break; 454 455 default: 456 break; 457 } 458 459 value++; 460 entry++; 461 } 462 } 463 464 465 466 // Return colour depth control value. 467 // NOTE: Not supporting JZ4780 options. 468 469 uint32_t 470 Lcd_jz4740_chip::_control_bpp() 471 { 472 switch (_panel->bpp) 473 { 474 case 1: return Control_bpp_1bpp; 475 case 2: return Control_bpp_2bpp; 476 case 3 ... 4: return Control_bpp_4bpp; 477 case 5 ... 8: return Control_bpp_8bpp; 478 case 9 ... 15: return Control_bpp_15bpp | (Rgb_mode_555 << Control_rgb_mode); 479 case 17 ... 18: return Control_bpp_18bpp; 480 case 19 ... 32: return Control_bpp_24bpp; 481 case 16: 482 default: return Control_bpp_16bpp; 483 } 484 } 485 486 // Return a panel-related control value. 487 488 uint32_t 489 Lcd_jz4740_chip::_control_panel() 490 { 491 if (have_stn_panel()) 492 return _control_stn_frc(); 493 else 494 return 0; 495 } 496 497 // Return a STN-related control value. 498 499 uint32_t 500 Lcd_jz4740_chip::_control_stn_frc() 501 { 502 if (_panel->bpp <= 2) 503 return Frc_greyscales_2; 504 if (_panel->bpp <= 4) 505 return Frc_greyscales_4; 506 return Frc_greyscales_16; 507 } 508 509 // Return a transfer-related control value. 510 511 uint32_t 512 Lcd_jz4740_chip::_control_transfer() 513 { 514 uint32_t length; 515 516 switch (_burst_size) 517 { 518 case 4: length = Burst_length_4; break; 519 case 8: length = Burst_length_8; break; 520 case 32: length = Burst_length_32; break; 521 case 64: length = Burst_length_64; break; 522 case 16: 523 default: length = Burst_length_16; break; 524 } 525 526 return (length << Control_burst_length) | (1 << Control_out_underrun); 527 } 528 529 // STN panel-specific initialisation. 530 531 void 532 Lcd_jz4740_chip::_init_stn() 533 { 534 // Divide the height by the number of panels. 535 536 uint32_t height = _panel->height / get_panels(); 537 538 // Since the value is log2(pins), 1 << value yields the number of pins. 539 540 int pins = 1 << ((_panel->config & Config_stn_pins_mask) >> Jz4740_lcd_config_stn_pins); 541 542 // Round parameters up to a multiple of the number of pins. 543 544 uint32_t hsync = align(_panel->hsync, pins); 545 uint32_t line_start = align(_panel->line_start, pins); 546 uint32_t line_end = align(_panel->line_end, pins); 547 548 // Define the start and end positions of visible data on a line and in a frame. 549 // Visible frame data is anchored at line zero, with the start region 550 // preceding this line (and thus appearing at the end of the preceding frame). 551 552 uint32_t line_start_pos = line_start; 553 uint32_t line_end_pos = line_start_pos + _panel->width; 554 uint32_t frame_start_pos = 0; 555 uint32_t frame_end_pos = frame_start_pos + height; 556 557 // Define sync pulse locations, with hsync occurring after the visible data. 558 559 _regs[Lcd_hsync] = encode_pair(line_end_pos, line_end_pos + hsync); 560 _regs[Lcd_vsync] = encode_pair(0, _panel->vsync); 561 562 // Set the display area and limits. 563 564 _regs[Vertical_area] = encode_pair(line_end_pos + hsync + line_end, 565 frame_end_pos + _panel->vsync + _panel->frame_end + _panel->frame_start); 566 567 _regs[Display_hlimits] = encode_pair(line_start_pos, line_end_pos); 568 _regs[Display_vlimits] = encode_pair(frame_start_pos, frame_end_pos); 569 570 // Set the AC bias signal. 571 572 _regs[Lcd_ps] = encode_pair(0, _panel->frame_start + height + _panel->vsync + _panel->frame_end); 573 } 574 575 // TFT panel-specific initialisation. 576 577 void 578 Lcd_jz4740_chip::_init_tft() 579 { 580 // Define the start and end positions of visible data on a line and in a frame. 581 582 uint32_t line_start_pos = _panel->line_start + _panel->hsync; 583 uint32_t line_end_pos = line_start_pos + _panel->width; 584 uint32_t frame_start_pos = _panel->frame_start + _panel->vsync; 585 uint32_t frame_end_pos = frame_start_pos + _panel->height; 586 587 // Define sync pulse locations, with pulses appearing before visible data. 588 589 _regs[Lcd_hsync] = encode_pair(0, _panel->hsync); 590 _regs[Lcd_vsync] = encode_pair(0, _panel->vsync); 591 592 // Set the display area and limits. 593 594 _regs[Vertical_area] = encode_pair(line_end_pos + _panel->line_end, 595 frame_end_pos + _panel->frame_end); 596 597 _regs[Display_hlimits] = encode_pair(line_start_pos, line_end_pos); 598 _regs[Display_vlimits] = encode_pair(frame_start_pos, frame_end_pos); 599 } 600 601 // Initialise the panel. 602 // NOTE: Only generic STN and TFT panels are supported. 603 604 void 605 Lcd_jz4740_chip::_init_panel() 606 { 607 if (have_stn_panel()) 608 _init_stn(); 609 else 610 switch (_mode()) 611 { 612 case Jz4740_lcd_mode_tft_generic: 613 case Jz4740_lcd_mode_tft_casio: 614 case Jz4740_lcd_mode_tft_serial: _init_tft(); 615 616 default: break; 617 } 618 } 619 620 // Initialise a DMA descriptor. 621 622 void 623 Lcd_jz4740_chip::_set_descriptor(struct Jz4740_lcd_descriptor &desc, 624 l4_addr_t source, l4_size_t size, 625 struct Jz4740_lcd_descriptor *next, 626 uint32_t flags) 627 { 628 // In the command, indicate the number of words from the source for transfer. 629 630 desc.next = next; 631 desc.source = source; 632 desc.identifier = 0; 633 desc.command = ((size / sizeof(uint32_t)) & Command_buffer_length_mask) | flags; 634 } 635 636 637 638 // Initialise the LCD controller with the memory, panel and framebuffer details. 639 // Any palette must be initialised separately using get_palette and init_palette. 640 641 void 642 Lcd_jz4740_chip::config(struct Jz4740_lcd_descriptor *desc_vaddr, 643 struct Jz4740_lcd_descriptor *desc_paddr, 644 l4_addr_t fb_paddr) 645 { 646 int have_palette = (_panel->bpp <= 8); 647 648 // Provide the first framebuffer descriptor in single and dual modes. 649 // Flip back and forth between any palette and the framebuffer. 650 651 _set_descriptor(desc_vaddr[0], get_framebuffer(0, fb_paddr), 652 get_screen_size(), 653 have_palette ? desc_paddr + 2 : desc_paddr); 654 655 // Provide the second framebuffer descriptor only in dual-panel mode. 656 // Only employ this descriptor in the second DMA channel. 657 658 if (get_panels() == 2) 659 _set_descriptor(desc_vaddr[1], get_framebuffer(1, fb_paddr), 660 get_screen_size(), 661 desc_paddr + 1); 662 663 // Initialise palette descriptor details for lower colour depths. 664 665 if (have_palette) 666 _set_descriptor(desc_vaddr[2], get_palette(fb_paddr), 667 get_palette_size(), 668 desc_paddr, 669 Command_palette_buffer); 670 671 // Flush cached structure data. 672 673 l4_cache_clean_data((unsigned long) desc_vaddr, 674 (unsigned long) desc_vaddr + get_descriptors_size()); 675 676 // Configure DMA by setting frame descriptor addresses. 677 678 // Provide the palette descriptor address first, if employed. 679 680 _regs[Desc_address_0] = (uint32_t) (have_palette ? desc_paddr + 2 : desc_paddr); 681 682 // Provide a descriptor for the second DMA channel in dual-panel mode. 683 684 if (get_panels() == 2) 685 _regs[Desc_address_1] = (uint32_t) (desc_paddr + 1); 686 687 // Initialise panel-related registers. 688 689 _init_panel(); 690 691 // Initialise the control and configuration registers. 692 693 _regs[Lcd_control] = _control_panel() | _control_bpp() | _control_transfer(); 694 _regs[Lcd_config] = _panel->config; 695 } 696 697 698 699 // C language interface functions. 700 701 void * 702 jz4740_lcd_init(l4_addr_t lcd_base, struct Jz4740_lcd_panel *panel) 703 { 704 return (void *) new Lcd_jz4740_chip(lcd_base, panel); 705 } 706 707 void 708 jz4740_lcd_config(void *lcd, struct Jz4740_lcd_descriptor *desc_vaddr, 709 struct Jz4740_lcd_descriptor *desc_paddr, 710 l4_addr_t fb_paddr) 711 { 712 static_cast<Lcd_jz4740_chip *>(lcd)->config(desc_vaddr, desc_paddr, fb_paddr); 713 } 714 715 void 716 jz4740_lcd_disable(void *lcd) 717 { 718 static_cast<Lcd_jz4740_chip *>(lcd)->disable(); 719 } 720 721 void 722 jz4740_lcd_disable_quick(void *lcd) 723 { 724 static_cast<Lcd_jz4740_chip *>(lcd)->disable_quick(); 725 } 726 727 void 728 jz4740_lcd_enable(void *lcd) 729 { 730 static_cast<Lcd_jz4740_chip *>(lcd)->enable(); 731 } 732 733 int 734 jz4740_lcd_get_pixel_clock(void *lcd) 735 { 736 return static_cast<Lcd_jz4740_chip *>(lcd)->get_pixel_clock(); 737 } 738 739 l4_addr_t 740 jz4740_lcd_get_palette(void *lcd, l4_addr_t base) 741 { 742 return static_cast<Lcd_jz4740_chip *>(lcd)->get_palette(base); 743 } 744 745 void 746 jz4740_lcd_init_palette(void *lcd, l4_addr_t palette) 747 { 748 static_cast<Lcd_jz4740_chip *>(lcd)->init_palette(palette); 749 }