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, 6 * 2020 Paul Boddie <paul@boddie.org.uk> 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as 10 * published by the Free Software Foundation; either version 2 of 11 * the License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 * Boston, MA 02110-1301, USA 22 */ 23 24 #include <l4/devices/hw_mmio_register_block.h> 25 #include <l4/sys/cache.h> 26 #include <l4/sys/err.h> 27 #include <l4/sys/irq.h> 28 #include <l4/sys/types.h> 29 #include <l4/util/util.h> 30 31 #include "lcd-jz4740.h" 32 #include "lcd-jz4740-config.h" 33 34 #include <stdint.h> 35 #include <stdio.h> 36 37 enum Regs : unsigned 38 { 39 Lcd_config = 0x000, // LCD_CFG 40 Lcd_vsync = 0x004, // LCD_VSYNC 41 Lcd_hsync = 0x008, // LCD_HSYNC 42 Virtual_area = 0x00c, // LCD_VAT 43 Display_hlimits = 0x010, // LCD_DAH 44 Display_vlimits = 0x014, // LCD_DAV 45 Lcd_ps = 0x018, // LCD_PS 46 Lcd_cls = 0x01c, // LCD_CLS 47 Lcd_spl = 0x020, // LCD_SPL 48 Lcd_rev = 0x024, // LCD_REV 49 Lcd_control = 0x030, // LCD_CTRL 50 Lcd_status = 0x034, // LCD_STATE 51 Lcd_irq_id = 0x038, // LCD_IID 52 Desc_address_0 = 0x040, // LCD_DA0 53 Source_address_0 = 0x044, // LCD_SA0 54 Frame_id_0 = 0x048, // LCD_FID0 55 Command_0 = 0x04c, // LCD_CMD0 56 Counter_position_0 = 0x068, // LCD_CPOS0 57 Foreground_size_0 = 0x06c, // LCD_DESSIZE0 58 Desc_address_1 = 0x050, // LCD_DA1 59 Source_address_1 = 0x054, // LCD_SA1 60 Frame_id_1 = 0x058, // LCD_FID1 61 Command_1 = 0x05c, // LCD_CMD1 62 Counter_position_1 = 0x078, // LCD_CPOS1 63 Foreground_size_1 = 0x07c, // LCD_DESSIZE1 64 Rgb_control = 0x090, // LCD_RGBC (JZ4780) 65 Alpha_levels = 0x108, // LCD_ALPHA (JZ4780) 66 Priority_level = 0x2c0, // LCD_PCFG 67 68 // OSD registers. 69 70 Osd_config = 0x100, // LCD_OSDC 71 Osd_control = 0x104, // LCD_OSDCTRL 72 Osd_status = 0x108, // LCD_OSDS 73 }; 74 75 // Lcd_config descriptions. 76 77 enum Config_values : unsigned 78 { 79 Config_stn_pins_mask = 0x3, 80 Config_mode_mask = 0xf, 81 }; 82 83 // Field positions for registers employing two values, with the first typically 84 // being the start value and the second being an end value. 85 86 enum Value_pair_bits : unsigned 87 { 88 Value_first = 16, 89 Value_second = 0, 90 }; 91 92 // Virtual area bits. 93 94 enum Virtual_area_values : unsigned 95 { 96 Virtual_area_horizontal_size = Value_first, // sum of display and blank regions (dot/pixel clock periods) 97 Virtual_area_vertical_size = Value_second, // sum of display and blank regions (line periods) 98 }; 99 100 // Lcd_control descriptions. 101 102 enum Control_bits : unsigned 103 { 104 Control_pin_modify = 31, // PINMD (change pin usage from 15..0 to 17..10, 8..1) 105 Control_burst_length = 28, // BST (burst length selection) 106 Control_rgb_mode = 27, // RGB (RGB mode) 107 Control_out_underrun = 26, // OFUP (output FIFO underrun protection) 108 Control_frc_algorithm = 24, // FRC (STN FRC algorithm selection) 109 Control_palette_delay = 16, // PDD (load palette delay counter) 110 Control_dac_loopback_test = 14, // DACTE (DAC loopback test) 111 Control_frame_end_irq_enable = 13, // EOFM (end of frame interrupt enable) 112 Control_frame_start_irq_enable = 12, // SOFM (start of frame interrupt enable) 113 Control_out_underrun_irq_enable = 11, // OFUM (output FIFO underrun interrupt enable) 114 Control_in0_underrun_irq_enable = 10, // IFUM0 (input FIFO 0 underrun interrupt enable) 115 Control_in1_underrun_irq_enable = 9, // IFUM1 (input FIFO 1 underrun interrupt enable) 116 Control_disabled_irq_enable = 8, // LDDM (LCD disable done interrupt enable) 117 Control_quick_disabled_irq_enable = 7, // QDM (LCD quick disable done interrupt enable) 118 Control_endian_select = 6, // BEDN (endian selection) 119 Control_bit_order = 5, // PEDN (bit order in bytes) 120 Control_disable = 4, // DIS (disable controller) 121 Control_enable = 3, // ENA (enable controller) 122 Control_bpp = 0, // BPP (bits per pixel) 123 }; 124 125 enum Burst_length_values : unsigned 126 { 127 Burst_length_4 = 0, // 4 word 128 Burst_length_8 = 1, // 8 word 129 Burst_length_16 = 2, // 16 word 130 131 // JZ4780 extensions. 132 133 Burst_length_32 = 3, // 32 word 134 Burst_length_64 = 4, // 64 word 135 Burst_length_mask = 0x7, 136 }; 137 138 enum Rgb_mode_values : unsigned 139 { 140 Rgb_mode_565 = 0, 141 Rgb_mode_555 = 1, 142 Rgb_mode_mask = 0x1, 143 }; 144 145 enum Frc_algorithm_values : unsigned 146 { 147 Frc_greyscales_16 = 0, 148 Frc_greyscales_4 = 1, 149 Frc_greyscales_2 = 2, 150 Frc_greyscales_mask = 0x3, 151 }; 152 153 enum Control_bpp_values : unsigned 154 { 155 Control_bpp_1bpp = 0, 156 Control_bpp_2bpp = 1, 157 Control_bpp_4bpp = 2, 158 Control_bpp_8bpp = 3, 159 Control_bpp_15bpp = 4, 160 Control_bpp_16bpp = 4, 161 Control_bpp_18bpp = 5, 162 Control_bpp_24bpp = 5, 163 Control_bpp_24bpp_comp = 6, 164 Control_bpp_30bpp = 7, 165 Control_bpp_32bpp = 7, 166 Control_bpp_mask = 0x7, 167 }; 168 169 // Command descriptions. 170 171 enum Command_bits : unsigned 172 { 173 Command_frame_start_irq = 31, // SOFINT (start of frame interrupt) 174 Command_frame_end_irq = 30, // EOFINT (end of frame interrupt) 175 Command_lcm_command = 29, // JZ4780: CMD (LCM command/data via DMA0) 176 Command_palette_buffer = 28, // PAL (descriptor references palette, not display data) 177 Command_frame_compressed = 27, // JZ4780: COMPEN (16/24bpp compression enabled) 178 Command_frame_enable = 26, // JZ4780: FRM_EN 179 Command_field_even = 25, // JZ4780: FIELD_SEL (interlace even field) 180 Command_16x16_block = 24, // JZ4780: 16x16BLOCK (fetch data by 16x16 block) 181 Command_buffer_length = 0, // LEN 182 }; 183 184 enum Command_values : unsigned 185 { 186 Command_buffer_length_mask = 0x00ffffff, 187 }; 188 189 // Status descriptions. 190 191 enum Status_bits : unsigned 192 { 193 Status_frame_end_irq = 5, 194 Status_frame_start_irq = 4, 195 Status_out_underrun_irq = 3, 196 Status_in0_underrun_irq = 2, 197 Status_in1_underrun_irq = 1, 198 Status_disabled = 0, 199 }; 200 201 // OSD configuration bits (JZ4780). 202 203 enum Osd_config_bits : unsigned 204 { 205 Osd_config_fg1_pixel_alpha_enable = 17, 206 Osd_config_fg1_frame_start_irq_enable = 15, 207 Osd_config_fg1_frame_end_irq_enable = 14, 208 Osd_config_fg0_frame_start_irq_enable = 11, 209 Osd_config_fg0_frame_end_irq_enable = 10, 210 Osd_config_fg1_enable = 4, 211 Osd_config_fg0_enable = 3, 212 Osd_config_alpha_enable = 2, 213 Osd_config_fg0_pixel_alpha_enable = 1, 214 Osd_config_enable = 0, 215 }; 216 217 enum Osd_control_bits : unsigned 218 { 219 Osd_control_ipu_clock_enable = 15, 220 }; 221 222 // RGB control (JZ4780). 223 224 enum Rgb_control_bits : unsigned 225 { 226 Rgb_data_padded = 15, // RGBDM 227 Rgb_padding_mode = 14, // DMM 228 Rgb_422 = 8, // 422 229 Rgb_format_enable = 7, // RGBFMT 230 Rgb_odd_line = 4, // OddRGB 231 Rgb_even_line = 0, // EvenRGB 232 }; 233 234 enum Rgb_control_values : unsigned 235 { 236 Rgb_padding_end = 0U << Rgb_padding_mode, 237 Rgb_padding_start = 1U << Rgb_padding_mode, 238 Rgb_odd_line_rgb = 0U << Rgb_odd_line, 239 Rgb_odd_line_rbg = 1U << Rgb_odd_line, 240 Rgb_odd_line_grb = 2U << Rgb_odd_line, 241 Rgb_odd_line_gbr = 3U << Rgb_odd_line, 242 Rgb_odd_line_brg = 4U << Rgb_odd_line, 243 Rgb_odd_line_bgr = 5U << Rgb_odd_line, 244 Rgb_even_line_rgb = 0U << Rgb_even_line, 245 Rgb_even_line_rbg = 1U << Rgb_even_line, 246 Rgb_even_line_grb = 2U << Rgb_even_line, 247 Rgb_even_line_gbr = 3U << Rgb_even_line, 248 Rgb_even_line_brg = 4U << Rgb_even_line, 249 Rgb_even_line_bgr = 5U << Rgb_even_line, 250 }; 251 252 // Alpha levels (JZ4780). 253 254 enum Alpha_levels_bits : unsigned 255 { 256 Alpha_level_fg1 = 8, 257 Alpha_level_fg0 = 0, 258 }; 259 260 enum Alpha_levels_values : unsigned 261 { 262 Alpha_level_fg1_mask = 0x0000ff00, 263 Alpha_level_fg0_mask = 0x000000ff, 264 }; 265 266 // Priority level. 267 268 enum Priority_level_bits : unsigned 269 { 270 Priority_mode = 31, 271 Priority_highest_burst = 28, 272 Priority_threshold2 = 18, 273 Priority_threshold1 = 9, 274 Priority_threshold0 = 0, 275 }; 276 277 enum Priority_level_values : unsigned 278 { 279 Priority_mode_dynamic = 0U << Priority_mode, 280 Priority_mode_arbiter = 1U << Priority_mode, 281 }; 282 283 enum Priority_burst_values : unsigned 284 { 285 Priority_burst_4 = 0, 286 Priority_burst_8 = 1, 287 Priority_burst_16 = 2, 288 Priority_burst_32 = 3, 289 Priority_burst_64 = 4, 290 Priority_burst_16_cont = 5, 291 Priority_burst_disable = 7, 292 }; 293 294 // Position descriptor member. 295 296 enum Position_bits : unsigned 297 { 298 Position_bpp = 27, 299 Position_premultiply_lcd = 26, 300 Position_coefficient = 24, 301 Position_y_position = 12, 302 Position_x_position = 0, 303 }; 304 305 enum Position_values : unsigned 306 { 307 Position_bpp_15_16bpp = 4, 308 Position_bpp_18_24bpp = 5, 309 Position_bpp_30bpp = 7, 310 }; 311 312 313 314 // Utility functions. 315 316 // Round values up according to the resolution. 317 318 static uint32_t align(uint32_t value, uint32_t resolution) 319 { 320 return (value + (resolution - 1)) & ~(resolution - 1); 321 } 322 323 // Value pair encoding. 324 325 static uint32_t encode_pair(uint32_t start, uint32_t end) 326 { 327 return (start << Value_first) | (end << Value_second); 328 } 329 330 // RGB conversions. 331 332 static uint16_t rgb8_to_rgb16(uint8_t rgb) 333 { 334 return ((((rgb & 0xe0) >> 5) * 4) << 11) | ((((rgb & 0x1c) >> 2) * 9) << 6) | ((rgb & 0x03) * 10); 335 } 336 337 static uint16_t rgb4_to_rgb16(uint8_t rgb) 338 { 339 return ((((rgb & 8) >> 3) * 0x1f) << 11) | ((((rgb & 6) >> 1) * 0x15) << 5) | ((rgb & 1) * 0x1f); 340 } 341 342 343 344 345 // If implemented as a Hw::Device, various properties would be 346 // initialised in the constructor and obtained from the device tree 347 // definitions. 348 349 Lcd_jz4740_chip::Lcd_jz4740_chip(l4_addr_t addr, Jz4740_lcd_panel *panel) 350 : _panel(panel) 351 { 352 _regs = new Hw::Mmio_register_block<32>(addr); 353 _burst_size = 64; // 64-word burst size (JZ4780) 354 //_burst_size = 16; // 16-word burst size 355 356 // add_cid("lcd"); 357 // add_cid("lcd-jz4740"); 358 } 359 360 struct Jz4740_lcd_panel * 361 Lcd_jz4740_chip::get_panel() 362 { 363 return _panel; 364 } 365 366 void 367 Lcd_jz4740_chip::disable() 368 { 369 // Set the disable bit for normal shutdown. 370 371 _regs[Lcd_control] = _regs[Lcd_control] | (1U << Control_disable); 372 } 373 374 void 375 Lcd_jz4740_chip::disable_quick() 376 { 377 // Clear the enable bit for quick shutdown. 378 379 _regs[Lcd_control] = _regs[Lcd_control] & ~(1U << Control_enable); 380 } 381 382 void 383 Lcd_jz4740_chip::enable() 384 { 385 // Clear the disable bit and set the enable bit. 386 // JZ4780: OSD status set. 387 388 _regs[Osd_status] = 0; 389 _regs[Lcd_status] = 0; 390 _regs[Lcd_control] = (_regs[Lcd_control] & ~(1U << Control_disable)) | (1U << Control_enable); 391 printf("LCD control: %x\n", (unsigned int) _regs[Lcd_control]); 392 } 393 394 bool 395 Lcd_jz4740_chip::enabled() 396 { 397 return !(_regs[Lcd_status] & (1U << Status_disabled)); 398 } 399 400 // Calculate and return the pixel clock frequency. 401 402 int 403 Lcd_jz4740_chip::get_pixel_clock() 404 { 405 int pclk, multiplier; 406 407 // Serial mode: 3 pixel clock cycles per pixel (one per channel). 408 // Parallel mode: 1 pixel clock cycle per pixel. 409 410 multiplier = have_serial_tft() ? 3 : 1; 411 412 // Derive pixel clock rate from frame rate. 413 // This multiplies the number of pixel periods in a line by the number of 414 // lines in a frame, thus obtaining the number of such periods in a frame. 415 // Multiplying this result with the frame rate yields the pixel frequency. 416 417 pclk = _panel->frame_rate * 418 (_panel->width * multiplier + 419 _panel->hsync + _panel->line_start + _panel->line_end) * 420 (_panel->height + 421 _panel->vsync + _panel->frame_start + _panel->frame_end); 422 423 // STN panel adjustments. 424 425 if (have_stn_panel()) 426 { 427 // Colour STN panels apparently need to be driven at three times the rate. 428 429 if (have_colour_stn()) pclk = (pclk * 3); 430 431 // Reduce the rate according to the width of the STN connection. 432 // Since the pins setting employs log2(pins), a shift by this value is 433 // equivalent to a division by the number of pins. 434 435 pclk = pclk >> ((_panel->config & Config_stn_pins_mask) >> Jz4740_lcd_config_stn_pins); 436 437 // Divide the rate by the number of panels. 438 439 pclk /= get_panels(); 440 } 441 442 return pclk; 443 } 444 445 446 447 // Return the panel mode. 448 449 uint32_t 450 Lcd_jz4740_chip::_mode() 451 { 452 return _panel->config & Config_mode_mask; 453 } 454 455 // Return the number of panels available. 456 457 int 458 Lcd_jz4740_chip::get_panels() 459 { 460 uint32_t mode = _mode(); 461 462 return (mode == Jz4740_lcd_mode_stn_dual_colour) || 463 (mode == Jz4740_lcd_mode_stn_dual_mono) ? 2 : 1; 464 } 465 466 // Return whether the panel is STN. 467 468 int 469 Lcd_jz4740_chip::have_stn_panel() 470 { 471 uint32_t mode = _mode(); 472 473 return ((mode == Jz4740_lcd_mode_stn_single_colour) || 474 (mode == Jz4740_lcd_mode_stn_dual_colour) || 475 (mode == Jz4740_lcd_mode_stn_single_mono) || 476 (mode == Jz4740_lcd_mode_stn_dual_mono)); 477 } 478 479 // Return whether the panel is colour STN. 480 481 int 482 Lcd_jz4740_chip::have_colour_stn() 483 { 484 uint32_t mode = _mode(); 485 486 return ((mode == Jz4740_lcd_mode_stn_single_colour) || 487 (mode == Jz4740_lcd_mode_stn_dual_colour)); 488 } 489 490 // Return whether the panel is colour STN. 491 492 int 493 Lcd_jz4740_chip::have_serial_tft() 494 { 495 return _mode() == Jz4740_lcd_mode_tft_serial; 496 } 497 498 499 500 // Return the pixel memory size in bits. 501 502 l4_size_t 503 Lcd_jz4740_chip::get_pixel_size() 504 { 505 if (_panel->bpp > 16) 506 return 32; 507 else if (_panel->bpp > 8) 508 return 16; 509 else 510 return _panel->bpp; 511 } 512 513 // Return the line memory size. 514 515 l4_size_t 516 Lcd_jz4740_chip::get_line_size() 517 { 518 // Lines must be aligned to a word boundary. 519 520 return align((_panel->width * get_pixel_size()) / 8, sizeof(uint32_t)); 521 } 522 523 // Return the screen memory size. 524 525 l4_size_t 526 Lcd_jz4740_chip::get_screen_size() 527 { 528 return get_line_size() * _panel->height; 529 } 530 531 // Return the aligned size for the DMA transfer. 532 533 l4_size_t 534 Lcd_jz4740_chip::get_aligned_size() 535 { 536 return align(get_screen_size(), _burst_size * sizeof(uint32_t)); 537 } 538 539 // Return the size of the palette. 540 541 l4_size_t 542 Lcd_jz4740_chip::get_palette_size() 543 { 544 // No palette for modes with more than eight bits per pixel. 545 546 if (_panel->bpp > 8) return 0; 547 548 // Get the size of a collection of two-byte entries, one per colour. 549 550 return (1U << (_panel->bpp)) * sizeof(uint16_t); 551 } 552 553 // Return the aligned size of the palette for the DMA transfer. 554 555 l4_size_t 556 Lcd_jz4740_chip::get_aligned_palette_size() 557 { 558 return align(get_palette_size(), _burst_size * sizeof(uint32_t)); 559 } 560 561 // Return the total memory requirements of the framebuffers and palette. 562 563 l4_size_t 564 Lcd_jz4740_chip::get_total_size() 565 { 566 return get_aligned_size() * get_panels() + get_aligned_palette_size(); 567 } 568 569 // Return the total memory requirements of any DMA descriptors. 570 571 l4_size_t 572 Lcd_jz4740_chip::get_descriptors_size() 573 { 574 return 3 * sizeof(struct Jz4740_lcd_descriptor); 575 } 576 577 578 579 // Functions returning addresses of each data region. 580 // The base parameter permits the retrieval of virtual or physical addresses. 581 582 l4_addr_t 583 Lcd_jz4740_chip::get_palette(l4_addr_t base) 584 { 585 // Use memory at the end of the allocated region for the palette. 586 587 return base + (get_panels() * get_aligned_size()) - get_aligned_palette_size(); 588 } 589 590 l4_addr_t 591 Lcd_jz4740_chip::get_framebuffer(int panel, l4_addr_t base) 592 { 593 // Framebuffers for panels are allocated at the start of the region. 594 595 return base + (panel * get_aligned_size()); 596 } 597 598 599 600 // Palette initialisation. 601 602 void 603 Lcd_jz4740_chip::init_palette(l4_addr_t palette) 604 { 605 uint8_t colours = 1U << (_panel->bpp); 606 uint16_t *entry = (uint16_t *) palette; 607 uint16_t *end = entry + colours; 608 uint8_t value = 0; 609 610 while (entry < end) 611 { 612 switch (_panel->bpp) 613 { 614 case 4: 615 *entry = rgb4_to_rgb16(value); 616 break; 617 618 case 8: 619 *entry = rgb8_to_rgb16(value); 620 break; 621 622 default: 623 break; 624 } 625 626 value++; 627 entry++; 628 } 629 } 630 631 632 633 // Return colour depth control value. 634 // NOTE: Not supporting JZ4780 options. 635 636 uint32_t 637 Lcd_jz4740_chip::_control_bpp() 638 { 639 switch (_panel->bpp) 640 { 641 case 1: return Control_bpp_1bpp; 642 case 2: return Control_bpp_2bpp; 643 case 3 ... 4: return Control_bpp_4bpp; 644 case 5 ... 8: return Control_bpp_8bpp; 645 case 9 ... 15: return Control_bpp_15bpp | (Rgb_mode_555 << Control_rgb_mode); 646 case 17 ... 18: return Control_bpp_18bpp; 647 case 19 ... 32: return Control_bpp_24bpp; 648 case 16: 649 default: return Control_bpp_16bpp; 650 } 651 } 652 653 // Return colour depth control value. 654 // JZ4780 position details only. 655 656 uint32_t 657 Lcd_jz4740_chip::_position_bpp() 658 { 659 uint32_t value; 660 661 switch (_panel->bpp) 662 { 663 case 15: case 16: value = Position_bpp_15_16bpp; break; 664 case 18: case 24: value = Position_bpp_18_24bpp; break; 665 case 30: value = Position_bpp_30bpp; break; 666 default: value = 0; break; 667 } 668 669 return value << Position_bpp; 670 } 671 672 // Return a panel-related control value. 673 674 uint32_t 675 Lcd_jz4740_chip::_control_panel() 676 { 677 if (have_stn_panel()) 678 return _control_stn_frc() << Control_frc_algorithm; 679 else 680 return 0; 681 } 682 683 // Return a STN-related control value. 684 685 uint32_t 686 Lcd_jz4740_chip::_control_stn_frc() 687 { 688 if (_panel->bpp <= 2) 689 return Frc_greyscales_2; 690 if (_panel->bpp <= 4) 691 return Frc_greyscales_4; 692 return Frc_greyscales_16; 693 } 694 695 // Return a transfer-related control value. 696 697 uint32_t 698 Lcd_jz4740_chip::_control_transfer() 699 { 700 uint32_t length; 701 702 switch (_burst_size) 703 { 704 case 4: length = Burst_length_4; break; 705 case 8: length = Burst_length_8; break; 706 case 32: length = Burst_length_32; break; 707 case 64: length = Burst_length_64; break; 708 case 16: 709 default: length = Burst_length_16; break; 710 } 711 712 return (length << Control_burst_length) | (1U << Control_out_underrun); 713 } 714 715 // Return an interrupt-related control value. 716 717 uint32_t 718 Lcd_jz4740_chip::_control_irq() 719 { 720 return // (1U << Control_out_underrun_irq_enable) | 721 ((_irq_conditions & Lcd_irq_frame_start) ? (1U << Control_frame_start_irq_enable) : 0) | 722 ((_irq_conditions & Lcd_irq_frame_end) ? (1U << Control_frame_end_irq_enable) : 0); 723 } 724 725 // Return an interrupt-related OSD configuration value. 726 727 uint32_t 728 Lcd_jz4740_chip::_osd_config_irq() 729 { 730 return ((_irq_conditions & Lcd_irq_frame_start) ? (1U << Osd_config_fg0_frame_start_irq_enable) : 0) | 731 ((_irq_conditions & Lcd_irq_frame_end) ? (1U << Osd_config_fg0_frame_end_irq_enable) : 0); 732 } 733 734 // Return an interrupt-related command value. 735 736 uint32_t 737 Lcd_jz4740_chip::_command_irq() 738 { 739 return ((_irq_conditions & Lcd_irq_frame_start) ? (1U << Command_frame_start_irq) : 0) | 740 ((_irq_conditions & Lcd_irq_frame_end) ? (1U << Command_frame_end_irq) : 0); 741 } 742 743 // Return an interrupt-related status value. 744 745 uint32_t 746 Lcd_jz4740_chip::_status_irq() 747 { 748 return // (1U << Status_out_underrun_irq) | 749 ((_irq_conditions & Lcd_irq_frame_start) ? (1U << Status_frame_start_irq) : 0) | 750 ((_irq_conditions & Lcd_irq_frame_end) ? (1U << Status_frame_end_irq) : 0); 751 } 752 753 uint32_t 754 Lcd_jz4740_chip::_priority_transfer() 755 { 756 uint32_t length; 757 758 switch (_burst_size) 759 { 760 case 4: length = Priority_burst_4; break; 761 case 8: length = Priority_burst_8; break; 762 case 32: length = Priority_burst_32; break; 763 case 64: length = Priority_burst_64; break; 764 case 16: 765 default: length = Priority_burst_16; break; 766 } 767 768 return Priority_mode_arbiter | 769 (length << Priority_highest_burst) | 770 (511U << Priority_threshold2) | 771 (400U << Priority_threshold1) | 772 (256U << Priority_threshold0); 773 } 774 775 // STN panel-specific initialisation. 776 777 void 778 Lcd_jz4740_chip::_init_stn() 779 { 780 // Divide the height by the number of panels. 781 782 uint32_t height = _panel->height / get_panels(); 783 784 // Since the value is log2(pins), 1 << value yields the number of pins. 785 786 int pins = 1 << ((_panel->config & Config_stn_pins_mask) >> Jz4740_lcd_config_stn_pins); 787 788 // Round parameters up to a multiple of the number of pins. 789 790 uint32_t hsync = align(_panel->hsync, pins); 791 uint32_t line_start = align(_panel->line_start, pins); 792 uint32_t line_end = align(_panel->line_end, pins); 793 794 // Define the start and end positions of visible data on a line and in a frame. 795 // Visible frame data is anchored at line zero, with the start region 796 // preceding this line (and thus appearing at the end of the preceding frame). 797 798 uint32_t line_start_pos = line_start; 799 uint32_t line_end_pos = line_start_pos + _panel->width; 800 uint32_t frame_start_pos = 0; 801 uint32_t frame_end_pos = frame_start_pos + height; 802 803 // Define sync pulse locations, with hsync occurring after the visible data. 804 805 _regs[Lcd_hsync] = encode_pair(line_end_pos, line_end_pos + hsync); 806 _regs[Lcd_vsync] = encode_pair(0, _panel->vsync); 807 808 // Set the display area and limits. 809 810 _regs[Virtual_area] = encode_pair(line_end_pos + hsync + line_end, 811 frame_end_pos + _panel->vsync + _panel->frame_end + _panel->frame_start); 812 813 _regs[Display_hlimits] = encode_pair(line_start_pos, line_end_pos); 814 _regs[Display_vlimits] = encode_pair(frame_start_pos, frame_end_pos); 815 816 // Set the AC bias signal. 817 818 _regs[Lcd_ps] = encode_pair(0, _panel->frame_start + height + _panel->vsync + _panel->frame_end); 819 } 820 821 // TFT panel-specific initialisation. 822 823 void 824 Lcd_jz4740_chip::_init_tft() 825 { 826 // Define the start and end positions of visible data on a line and in a frame. 827 828 uint32_t line_start_pos = _panel->line_start + _panel->hsync; 829 uint32_t line_end_pos = line_start_pos + _panel->width; 830 uint32_t frame_start_pos = _panel->frame_start + _panel->vsync; 831 uint32_t frame_end_pos = frame_start_pos + _panel->height; 832 833 // Define sync pulse locations, with pulses appearing before visible data. 834 835 _regs[Lcd_hsync] = encode_pair(0, _panel->hsync); 836 _regs[Lcd_vsync] = encode_pair(0, _panel->vsync); 837 838 // Set the display area and limits. 839 840 _regs[Virtual_area] = encode_pair(line_end_pos + _panel->line_end, 841 frame_end_pos + _panel->frame_end); 842 843 _regs[Display_hlimits] = encode_pair(line_start_pos, line_end_pos); 844 _regs[Display_vlimits] = encode_pair(frame_start_pos, frame_end_pos); 845 } 846 847 // Initialise the panel. 848 // NOTE: Only generic STN and TFT panels are supported. 849 850 void 851 Lcd_jz4740_chip::_init_panel() 852 { 853 if (have_stn_panel()) 854 _init_stn(); 855 else 856 switch (_mode()) 857 { 858 case Jz4740_lcd_mode_tft_generic: 859 case Jz4740_lcd_mode_tft_casio: 860 case Jz4740_lcd_mode_tft_serial: _init_tft(); 861 862 default: break; 863 } 864 } 865 866 // Initialise a DMA descriptor. 867 868 void 869 Lcd_jz4740_chip::_set_descriptor(struct Jz4740_lcd_descriptor &desc, 870 l4_addr_t source, l4_size_t size, 871 struct Jz4740_lcd_descriptor *next, 872 uint32_t flags, 873 bool frame_enable) 874 { 875 // In the command, indicate the number of words from the source for transfer. 876 877 desc.next = next; 878 desc.source = frame_enable ? source : 0; 879 desc.identifier = source; 880 desc.command = ((size / sizeof(uint32_t)) & Command_buffer_length_mask) | 881 (frame_enable ? (1U << Command_frame_enable) : 0) | 882 flags; 883 884 // Initialise "new" descriptor fields. 885 886 desc.offset = 0; 887 desc.page_width = 0; 888 desc.command_position = (1U << Position_premultiply_lcd) | 889 ((frame_enable ? 1U : 3U) << Position_coefficient) | 890 _position_bpp(); 891 desc.fg_size = 0xff000000 | 892 ((_panel->height - 1) << 12) | 893 ((_panel->width - 1) << 0); 894 } 895 896 897 898 // Initialise the LCD controller with the memory, panel and framebuffer details. 899 // Any palette must be initialised separately using get_palette and init_palette. 900 901 void 902 Lcd_jz4740_chip::config(struct Jz4740_lcd_descriptor *desc_vaddr, 903 struct Jz4740_lcd_descriptor *desc_paddr, 904 l4_addr_t fb_paddr) 905 { 906 // NOTE: Remarks in the Ingenic Linux 3.0.8 driver suggest that the JZ4775 and 907 // NOTE: JZ4780 do not support palettes. 908 909 int have_palette = (_panel->bpp <= 8); 910 911 bool _have_fg1 = true; // NOTE: To be formalised! 912 913 // Provide the first framebuffer descriptor in single and dual modes. 914 // Flip back and forth between any palette and the framebuffer. 915 916 _set_descriptor(desc_vaddr[0], get_framebuffer(0, fb_paddr), 917 get_aligned_size(), 918 have_palette ? desc_paddr + 2 : desc_paddr, 919 _command_irq()); 920 921 // Provide the second framebuffer descriptor only in dual-panel mode. 922 // Only employ this descriptor in the second DMA channel. 923 924 if ((get_panels() == 2) || _have_fg1) 925 _set_descriptor(desc_vaddr[1], get_framebuffer(1, fb_paddr), 926 get_aligned_size(), 927 desc_paddr + 1, 928 _command_irq(), 929 false); 930 931 // Initialise palette descriptor details for lower colour depths. 932 933 if (have_palette) 934 _set_descriptor(desc_vaddr[2], get_palette(fb_paddr), 935 get_aligned_palette_size(), 936 desc_paddr, 937 Command_palette_buffer); 938 939 // Flush cached structure data. 940 941 l4_cache_clean_data((unsigned long) desc_vaddr, 942 (unsigned long) desc_vaddr + get_descriptors_size()); 943 944 // Configure DMA by setting frame descriptor addresses. 945 946 // Provide the palette descriptor address first, if employed. 947 948 _regs[Desc_address_0] = (uint32_t) (have_palette ? desc_paddr + 2 : desc_paddr); 949 950 // Provide a descriptor for the second DMA channel in dual-panel mode. 951 952 if ((get_panels() == 2) || _have_fg1) 953 _regs[Desc_address_1] = (uint32_t) (desc_paddr + 1); 954 955 // Initialise panel-related registers. 956 957 _init_panel(); 958 959 // Initialise the control and configuration registers. 960 // NOTE: JZ4780 does not support bpp setting here. 961 962 _regs[Lcd_control] = _control_panel() | _control_bpp() | _control_transfer() | _control_irq(); 963 _regs[Lcd_config] = _panel->config; 964 965 // NOTE: JZ4780 only. 966 967 _regs[Rgb_control] = (1U << Rgb_format_enable) | Rgb_odd_line_rgb | Rgb_even_line_rgb; 968 _regs[Priority_level] = _priority_transfer(); 969 _regs[Osd_config] = //_osd_config_irq() | 970 (1U << Osd_config_enable) | 971 (1U << Osd_config_alpha_enable); 972 _regs[Alpha_levels] = ((255U << Alpha_level_fg1) & Alpha_level_fg1_mask) | 973 ((255U << Alpha_level_fg0) & Alpha_level_fg0_mask); 974 975 printf("LCD control: %08x\n", (unsigned int) _regs[Lcd_control]); 976 printf("LCD status: %08x\n", (unsigned int) _regs[Lcd_status]); 977 printf("OSD control: %08x\n", (unsigned int) _regs[Osd_control]); 978 printf("OSD config: %08x\n", (unsigned int) _regs[Osd_config]); 979 printf("OSD status: %08x\n", (unsigned int) _regs[Osd_status]); 980 } 981 982 // Set the interrupt for controller-related events. 983 984 void 985 Lcd_jz4740_chip::set_irq(l4_cap_idx_t irq, enum Jz4740_lcd_irq_condition conditions) 986 { 987 _irq = irq; 988 _irq_conditions = conditions; 989 } 990 991 // Wait for an interrupt condition. 992 993 long 994 Lcd_jz4740_chip::wait_for_irq() 995 { 996 l4_msgtag_t tag; 997 998 _regs[Lcd_status] = _regs[Lcd_status] & ~(_status_irq()); 999 1000 // Wait for a condition. 1001 1002 //printf("Waiting for IRQ...\n"); 1003 tag = l4_irq_receive(_irq, l4_timeout(L4_IPC_TIMEOUT_NEVER, l4util_micros2l4to(2000000))); 1004 1005 //if (_regs[Lcd_status] & (1U << Status_out_underrun_irq)) 1006 // enable(); 1007 1008 #if 0 1009 printf("LCD config: %08x\n", (unsigned int) _regs[Lcd_config]); 1010 printf("LCD control: %08x\n", (unsigned int) _regs[Lcd_control]); 1011 printf("LCD status: %08x\n", (unsigned int) _regs[Lcd_status]); 1012 printf("OSD config: %08x\n", (unsigned int) _regs[Osd_config]); 1013 printf("OSD control: %08x\n", (unsigned int) _regs[Osd_control]); 1014 printf("OSD status: %08x\n", (unsigned int) _regs[Osd_status]); 1015 printf("LCD command: %08x\n", (unsigned int) _regs[Command_0]); 1016 printf("LCD IRQ id: %08x\n", (unsigned int) _regs[Lcd_irq_id]); 1017 printf("LCD descriptor: %08x\n", (unsigned int) _regs[Desc_address_0]); 1018 printf("LCD source: %08x\n", (unsigned int) _regs[Source_address_0]); 1019 printf("LCD frame id: %08x\n", (unsigned int) _regs[Frame_id_0]); 1020 printf("LCD counter/position: %08x\n", (unsigned int) _regs[Counter_position_0]); 1021 printf("LCD foreground size: %08x\n", (unsigned int) _regs[Foreground_size_0]); 1022 #endif 1023 1024 // Acknowledge interrupts. 1025 1026 _regs[Lcd_status] = 0; 1027 1028 // Return errors. 1029 1030 //printf("Error: %s\n", l4sys_errtostr(l4_error(tag))); 1031 return l4_error(tag); 1032 } 1033 1034 1035 1036 // C language interface functions. 1037 1038 void * 1039 jz4740_lcd_init(l4_addr_t lcd_base, struct Jz4740_lcd_panel *panel) 1040 { 1041 return (void *) new Lcd_jz4740_chip(lcd_base, panel); 1042 } 1043 1044 void 1045 jz4740_lcd_config(void *lcd, struct Jz4740_lcd_descriptor *desc_vaddr, 1046 struct Jz4740_lcd_descriptor *desc_paddr, 1047 l4_addr_t fb_paddr) 1048 { 1049 static_cast<Lcd_jz4740_chip *>(lcd)->config(desc_vaddr, desc_paddr, fb_paddr); 1050 } 1051 1052 void 1053 jz4740_lcd_set_irq(void *lcd, l4_cap_idx_t irq, enum Jz4740_lcd_irq_condition conditions) 1054 { 1055 static_cast<Lcd_jz4740_chip *>(lcd)->set_irq(irq, conditions); 1056 } 1057 1058 long 1059 jz4740_lcd_wait_for_irq(void *lcd) 1060 { 1061 return static_cast<Lcd_jz4740_chip *>(lcd)->wait_for_irq(); 1062 } 1063 1064 void 1065 jz4740_lcd_disable(void *lcd) 1066 { 1067 static_cast<Lcd_jz4740_chip *>(lcd)->disable(); 1068 } 1069 1070 void 1071 jz4740_lcd_disable_quick(void *lcd) 1072 { 1073 static_cast<Lcd_jz4740_chip *>(lcd)->disable_quick(); 1074 } 1075 1076 void 1077 jz4740_lcd_enable(void *lcd) 1078 { 1079 static_cast<Lcd_jz4740_chip *>(lcd)->enable(); 1080 } 1081 1082 int 1083 jz4740_lcd_enabled(void *lcd) 1084 { 1085 return (int) static_cast<Lcd_jz4740_chip *>(lcd)->enabled(); 1086 } 1087 1088 int 1089 jz4740_lcd_get_pixel_clock(void *lcd) 1090 { 1091 return static_cast<Lcd_jz4740_chip *>(lcd)->get_pixel_clock(); 1092 } 1093 1094 l4_size_t 1095 jz4740_lcd_get_descriptors_size(void *lcd) 1096 { 1097 return static_cast<Lcd_jz4740_chip *>(lcd)->get_descriptors_size(); 1098 } 1099 1100 l4_size_t 1101 jz4740_lcd_get_line_size(void *lcd) 1102 { 1103 return static_cast<Lcd_jz4740_chip *>(lcd)->get_line_size(); 1104 } 1105 1106 l4_size_t 1107 jz4740_lcd_get_screen_size(void *lcd) 1108 { 1109 return static_cast<Lcd_jz4740_chip *>(lcd)->get_screen_size(); 1110 } 1111 1112 l4_addr_t 1113 jz4740_lcd_get_palette(void *lcd, l4_addr_t base) 1114 { 1115 return static_cast<Lcd_jz4740_chip *>(lcd)->get_palette(base); 1116 } 1117 1118 void 1119 jz4740_lcd_init_palette(void *lcd, l4_addr_t palette) 1120 { 1121 static_cast<Lcd_jz4740_chip *>(lcd)->init_palette(palette); 1122 }