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/irq.h> 27 #include <l4/sys/types.h> 28 #include <l4/util/util.h> 29 30 #include "lcd-jz4740.h" 31 #include "lcd-jz4740-config.h" 32 #include "lcd-jz4740-regs.h" 33 34 #include <stdint.h> 35 36 37 38 // Utility functions. 39 40 // Round values up according to the resolution. 41 42 static uint32_t align(uint32_t value, uint32_t resolution) 43 { 44 return (value + (resolution - 1)) & ~(resolution - 1); 45 } 46 47 // Value pair encoding. 48 49 static uint32_t encode_pair(uint32_t start, uint32_t end) 50 { 51 return (start << Value_first) | (end << Value_second); 52 } 53 54 // RGB conversions. 55 56 static uint16_t rgb8_to_rgb16(uint8_t rgb) 57 { 58 return ((((rgb & 0xe0) >> 5) * 4) << 11) | ((((rgb & 0x1c) >> 2) * 9) << 6) | ((rgb & 0x03) * 10); 59 } 60 61 static uint16_t rgb4_to_rgb16(uint8_t rgb) 62 { 63 return ((((rgb & 8) >> 3) * 0x1f) << 11) | ((((rgb & 6) >> 1) * 0x15) << 5) | ((rgb & 1) * 0x1f); 64 } 65 66 67 68 69 // If implemented as a Hw::Device, various properties would be 70 // initialised in the constructor and obtained from the device tree 71 // definitions. 72 73 Lcd_jz4740_chip::Lcd_jz4740_chip(l4_addr_t addr, Jz4740_lcd_panel *panel) 74 : _panel(panel) 75 { 76 _regs = new Hw::Mmio_register_block<32>(addr); 77 _burst_size = 16; // 16-word burst size 78 } 79 80 struct Jz4740_lcd_panel * 81 Lcd_jz4740_chip::get_panel() 82 { 83 return _panel; 84 } 85 86 void 87 Lcd_jz4740_chip::disable() 88 { 89 // Set the disable bit for normal shutdown. 90 91 _regs[Lcd_control] = _regs[Lcd_control] | (1U << Control_disable); 92 } 93 94 void 95 Lcd_jz4740_chip::disable_quick() 96 { 97 // Clear the enable bit for quick shutdown. 98 99 _regs[Lcd_control] = _regs[Lcd_control] & ~(1U << Control_enable); 100 } 101 102 void 103 Lcd_jz4740_chip::enable() 104 { 105 // Clear the disable bit and set the enable bit. 106 // JZ4780: OSD status set. 107 108 _regs[Osd_status] = 0; 109 _regs[Lcd_status] = 0; 110 _regs[Lcd_control] = (_regs[Lcd_control] & ~(1U << Control_disable)) | (1U << Control_enable); 111 } 112 113 bool 114 Lcd_jz4740_chip::enabled() 115 { 116 return !(_regs[Lcd_status] & (1U << Status_disabled)); 117 } 118 119 // Calculate and return the pixel clock frequency. 120 121 int 122 Lcd_jz4740_chip::get_pixel_clock() 123 { 124 int pclk, multiplier; 125 126 // Serial mode: 3 pixel clock cycles per pixel (one per channel). 127 // Parallel mode: 1 pixel clock cycle per pixel. 128 129 multiplier = have_serial_tft() ? 3 : 1; 130 131 // Derive pixel clock rate from frame rate. 132 // This multiplies the number of pixel periods in a line by the number of 133 // lines in a frame, thus obtaining the number of such periods in a frame. 134 // Multiplying this result with the frame rate yields the pixel frequency. 135 136 pclk = _panel->frame_rate * 137 (_panel->width * multiplier + 138 _panel->hsync + _panel->line_start + _panel->line_end) * 139 (_panel->height + 140 _panel->vsync + _panel->frame_start + _panel->frame_end); 141 142 // STN panel adjustments. 143 144 if (have_stn_panel()) 145 { 146 // Colour STN panels apparently need to be driven at three times the rate. 147 148 if (have_colour_stn()) pclk = (pclk * 3); 149 150 // Reduce the rate according to the width of the STN connection. 151 // Since the pins setting employs log2(pins), a shift by this value is 152 // equivalent to a division by the number of pins. 153 154 pclk = pclk >> ((_panel->config & Config_stn_pins_mask) >> Jz4740_lcd_config_stn_pins); 155 156 // Divide the rate by the number of panels. 157 158 pclk /= get_panels(); 159 } 160 161 return pclk; 162 } 163 164 165 166 // Return the panel mode. 167 168 uint32_t 169 Lcd_jz4740_chip::_mode() 170 { 171 return _panel->config & Config_mode_mask; 172 } 173 174 // Return the number of panels available. 175 176 int 177 Lcd_jz4740_chip::get_panels() 178 { 179 uint32_t mode = _mode(); 180 181 return (mode == Jz4740_lcd_mode_stn_dual_colour) || 182 (mode == Jz4740_lcd_mode_stn_dual_mono) ? 2 : 1; 183 } 184 185 // Return whether the panel is STN. 186 187 int 188 Lcd_jz4740_chip::have_stn_panel() 189 { 190 uint32_t mode = _mode(); 191 192 return ((mode == Jz4740_lcd_mode_stn_single_colour) || 193 (mode == Jz4740_lcd_mode_stn_dual_colour) || 194 (mode == Jz4740_lcd_mode_stn_single_mono) || 195 (mode == Jz4740_lcd_mode_stn_dual_mono)); 196 } 197 198 // Return whether the panel is colour STN. 199 200 int 201 Lcd_jz4740_chip::have_colour_stn() 202 { 203 uint32_t mode = _mode(); 204 205 return ((mode == Jz4740_lcd_mode_stn_single_colour) || 206 (mode == Jz4740_lcd_mode_stn_dual_colour)); 207 } 208 209 // Return whether the panel is colour STN. 210 211 int 212 Lcd_jz4740_chip::have_serial_tft() 213 { 214 return _mode() == Jz4740_lcd_mode_tft_serial; 215 } 216 217 218 219 // Return the pixel memory size in bits. 220 221 l4_size_t 222 Lcd_jz4740_chip::get_pixel_size() 223 { 224 if (_panel->bpp > 16) 225 return 32; 226 else if (_panel->bpp > 8) 227 return 16; 228 else 229 return _panel->bpp; 230 } 231 232 // Return the line memory size. 233 234 l4_size_t 235 Lcd_jz4740_chip::get_line_size() 236 { 237 // Lines must be aligned to a word boundary. 238 239 return align((_panel->width * get_pixel_size()) / 8, sizeof(uint32_t)); 240 } 241 242 // Return the screen memory size. 243 244 l4_size_t 245 Lcd_jz4740_chip::get_screen_size() 246 { 247 return get_line_size() * _panel->height; 248 } 249 250 // Return the aligned size for the DMA transfer. 251 252 l4_size_t 253 Lcd_jz4740_chip::get_aligned_size() 254 { 255 return align(get_screen_size(), _burst_size * sizeof(uint32_t)); 256 } 257 258 // Return the size of the palette. 259 260 l4_size_t 261 Lcd_jz4740_chip::get_palette_size() 262 { 263 // No palette for modes with more than eight bits per pixel. 264 265 if (_panel->bpp > 8) return 0; 266 267 // Get the size of a collection of two-byte entries, one per colour. 268 269 return (1U << (_panel->bpp)) * sizeof(uint16_t); 270 } 271 272 // Return the aligned size of the palette for the DMA transfer. 273 274 l4_size_t 275 Lcd_jz4740_chip::get_aligned_palette_size() 276 { 277 return align(get_palette_size(), _burst_size * sizeof(uint32_t)); 278 } 279 280 // Return the total memory requirements of the framebuffers and palette. 281 282 l4_size_t 283 Lcd_jz4740_chip::get_total_size() 284 { 285 return get_aligned_size() * get_panels() + get_aligned_palette_size(); 286 } 287 288 // Return the total memory requirements of any DMA descriptors. 289 290 l4_size_t 291 Lcd_jz4740_chip::get_descriptors_size() 292 { 293 return 3 * sizeof(struct Jz4740_lcd_descriptor); 294 } 295 296 297 298 // Functions returning addresses of each data region. 299 // The base parameter permits the retrieval of virtual or physical addresses. 300 301 l4_addr_t 302 Lcd_jz4740_chip::get_palette(l4_addr_t base) 303 { 304 // Use memory at the end of the allocated region for the palette. 305 306 return base + (get_panels() * get_aligned_size()) - get_aligned_palette_size(); 307 } 308 309 l4_addr_t 310 Lcd_jz4740_chip::get_framebuffer(int panel, l4_addr_t base) 311 { 312 // Framebuffers for panels are allocated at the start of the region. 313 314 return base + (panel * get_aligned_size()); 315 } 316 317 318 319 // Palette initialisation. 320 321 void 322 Lcd_jz4740_chip::init_palette(l4_addr_t palette) 323 { 324 uint8_t colours = 1U << (_panel->bpp); 325 uint16_t *entry = (uint16_t *) palette; 326 uint16_t *end = entry + colours; 327 uint8_t value = 0; 328 329 while (entry < end) 330 { 331 switch (_panel->bpp) 332 { 333 case 4: 334 *entry = rgb4_to_rgb16(value); 335 break; 336 337 case 8: 338 *entry = rgb8_to_rgb16(value); 339 break; 340 341 default: 342 break; 343 } 344 345 value++; 346 entry++; 347 } 348 } 349 350 351 352 // Return colour depth control value. 353 // NOTE: Not supporting JZ4780 options. 354 355 uint32_t 356 Lcd_jz4740_chip::_control_bpp() 357 { 358 switch (_panel->bpp) 359 { 360 case 1: return Control_bpp_1bpp; 361 case 2: return Control_bpp_2bpp; 362 case 3 ... 4: return Control_bpp_4bpp; 363 case 5 ... 8: return Control_bpp_8bpp; 364 case 9 ... 15: return Control_bpp_15bpp | (Rgb_mode_555 << Control_rgb_mode); 365 case 17 ... 18: return Control_bpp_18bpp; 366 case 19 ... 32: return Control_bpp_24bpp; 367 case 16: 368 default: return Control_bpp_16bpp; 369 } 370 } 371 372 // Return a panel-related control value. 373 374 uint32_t 375 Lcd_jz4740_chip::_control_panel() 376 { 377 if (have_stn_panel()) 378 return _control_stn_frc() << Control_frc_algorithm; 379 else 380 return 0; 381 } 382 383 // Return a STN-related control value. 384 385 uint32_t 386 Lcd_jz4740_chip::_control_stn_frc() 387 { 388 if (_panel->bpp <= 2) 389 return Frc_greyscales_2; 390 if (_panel->bpp <= 4) 391 return Frc_greyscales_4; 392 return Frc_greyscales_16; 393 } 394 395 // Return a transfer-related control value. 396 397 uint32_t 398 Lcd_jz4740_chip::_control_transfer() 399 { 400 uint32_t length; 401 402 switch (_burst_size) 403 { 404 case 4: length = Burst_length_4; break; 405 case 8: length = Burst_length_8; break; 406 case 32: length = Burst_length_32; break; 407 case 64: length = Burst_length_64; break; 408 case 16: 409 default: length = Burst_length_16; break; 410 } 411 412 return (length << Control_burst_length) | (1U << Control_out_underrun); 413 } 414 415 // Return an interrupt-related control value. 416 417 uint32_t 418 Lcd_jz4740_chip::_control_irq() 419 { 420 return ((_irq_conditions & Lcd_irq_frame_start) ? (1U << Control_frame_start_irq_enable) : 0) | 421 ((_irq_conditions & Lcd_irq_frame_end) ? (1U << Control_frame_end_irq_enable) : 0); 422 } 423 424 // Return an interrupt-related OSD configuration value. 425 426 uint32_t 427 Lcd_jz4740_chip::_osd_config_irq() 428 { 429 return ((_irq_conditions & Lcd_irq_frame_start) ? (1U << Osd_config_fg0_frame_start_irq_enable) : 0) | 430 ((_irq_conditions & Lcd_irq_frame_end) ? (1U << Osd_config_fg0_frame_end_irq_enable) : 0); 431 } 432 433 // Return an interrupt-related command value. 434 435 uint32_t 436 Lcd_jz4740_chip::_command_irq() 437 { 438 return ((_irq_conditions & Lcd_irq_frame_start) ? (1U << Command_frame_start_irq) : 0) | 439 ((_irq_conditions & Lcd_irq_frame_end) ? (1U << Command_frame_end_irq) : 0); 440 } 441 442 // Return an interrupt-related status value. 443 444 uint32_t 445 Lcd_jz4740_chip::_status_irq() 446 { 447 return ((_irq_conditions & Lcd_irq_frame_start) ? (1U << Status_frame_start_irq) : 0) | 448 ((_irq_conditions & Lcd_irq_frame_end) ? (1U << Status_frame_end_irq) : 0); 449 } 450 451 // STN panel-specific initialisation. 452 453 void 454 Lcd_jz4740_chip::_init_stn() 455 { 456 // Divide the height by the number of panels. 457 458 uint32_t height = _panel->height / get_panels(); 459 460 // Since the value is log2(pins), 1 << value yields the number of pins. 461 462 int pins = 1 << ((_panel->config & Config_stn_pins_mask) >> Jz4740_lcd_config_stn_pins); 463 464 // Round parameters up to a multiple of the number of pins. 465 466 uint32_t hsync = align(_panel->hsync, pins); 467 uint32_t line_start = align(_panel->line_start, pins); 468 uint32_t line_end = align(_panel->line_end, pins); 469 470 // Define the start and end positions of visible data on a line and in a frame. 471 // Visible frame data is anchored at line zero, with the start region 472 // preceding this line (and thus appearing at the end of the preceding frame). 473 474 uint32_t line_start_pos = line_start; 475 uint32_t line_end_pos = line_start_pos + _panel->width; 476 uint32_t frame_start_pos = 0; 477 uint32_t frame_end_pos = frame_start_pos + height; 478 479 // Define sync pulse locations, with hsync occurring after the visible data. 480 481 _regs[Lcd_hsync] = encode_pair(line_end_pos, line_end_pos + hsync); 482 _regs[Lcd_vsync] = encode_pair(0, _panel->vsync); 483 484 // Set the display area and limits. 485 486 _regs[Virtual_area] = encode_pair(line_end_pos + hsync + line_end, 487 frame_end_pos + _panel->vsync + _panel->frame_end + _panel->frame_start); 488 489 _regs[Display_hlimits] = encode_pair(line_start_pos, line_end_pos); 490 _regs[Display_vlimits] = encode_pair(frame_start_pos, frame_end_pos); 491 492 // Set the AC bias signal. 493 494 _regs[Lcd_ps] = encode_pair(0, _panel->frame_start + height + _panel->vsync + _panel->frame_end); 495 } 496 497 // TFT panel-specific initialisation. 498 499 void 500 Lcd_jz4740_chip::_init_tft() 501 { 502 // Define the start and end positions of visible data on a line and in a frame. 503 504 uint32_t line_start_pos = _panel->line_start + _panel->hsync; 505 uint32_t line_end_pos = line_start_pos + _panel->width; 506 uint32_t frame_start_pos = _panel->frame_start + _panel->vsync; 507 uint32_t frame_end_pos = frame_start_pos + _panel->height; 508 509 // Define sync pulse locations, with pulses appearing before visible data. 510 511 _regs[Lcd_hsync] = encode_pair(0, _panel->hsync); 512 _regs[Lcd_vsync] = encode_pair(0, _panel->vsync); 513 514 // Set the display area and limits. 515 516 _regs[Virtual_area] = encode_pair(line_end_pos + _panel->line_end, 517 frame_end_pos + _panel->frame_end); 518 519 _regs[Display_hlimits] = encode_pair(line_start_pos, line_end_pos); 520 _regs[Display_vlimits] = encode_pair(frame_start_pos, frame_end_pos); 521 } 522 523 // Initialise the panel. 524 // NOTE: Only generic STN and TFT panels are supported. 525 526 void 527 Lcd_jz4740_chip::_init_panel() 528 { 529 if (have_stn_panel()) 530 _init_stn(); 531 else 532 switch (_mode()) 533 { 534 case Jz4740_lcd_mode_tft_generic: 535 case Jz4740_lcd_mode_tft_casio: 536 case Jz4740_lcd_mode_tft_serial: _init_tft(); 537 538 default: break; 539 } 540 } 541 542 // Initialise a DMA descriptor. 543 544 void 545 Lcd_jz4740_chip::_set_descriptor(struct Jz4740_lcd_descriptor &desc, 546 l4_addr_t source, l4_size_t size, 547 struct Jz4740_lcd_descriptor *next, 548 uint32_t flags) 549 { 550 // In the command, indicate the number of words from the source for transfer. 551 552 desc.next = next; 553 desc.source = source; 554 desc.identifier = source; 555 desc.command = ((size / sizeof(uint32_t)) & Command_buffer_length_mask) | 556 flags; 557 } 558 559 // Initialise the LCD controller with the memory, panel and framebuffer details. 560 // Any palette must be initialised separately using get_palette and init_palette. 561 562 void 563 Lcd_jz4740_chip::config(struct Jz4740_lcd_descriptor *desc_vaddr, 564 struct Jz4740_lcd_descriptor *desc_paddr, 565 l4_addr_t fb_paddr) 566 { 567 int have_palette = (_panel->bpp <= 8); 568 569 // Provide the first framebuffer descriptor in single and dual modes. 570 // Flip back and forth between any palette and the framebuffer. 571 572 _set_descriptor(desc_vaddr[0], get_framebuffer(0, fb_paddr), 573 get_aligned_size(), 574 have_palette ? desc_paddr + 2 : desc_paddr, 575 _command_irq()); 576 577 // Provide the second framebuffer descriptor only in dual-panel mode. 578 // Only employ this descriptor in the second DMA channel. 579 580 if (get_panels() == 2) 581 _set_descriptor(desc_vaddr[1], get_framebuffer(1, fb_paddr), 582 get_aligned_size(), 583 desc_paddr + 1, 584 _command_irq()); 585 586 // Initialise palette descriptor details for lower colour depths. 587 588 if (have_palette) 589 _set_descriptor(desc_vaddr[2], get_palette(fb_paddr), 590 get_aligned_palette_size(), 591 desc_paddr, 592 Command_palette_buffer); 593 594 // Flush cached structure data. 595 596 l4_cache_clean_data((unsigned long) desc_vaddr, 597 (unsigned long) desc_vaddr + get_descriptors_size()); 598 599 // Configure DMA by setting frame descriptor addresses. 600 601 // Provide the palette descriptor address first, if employed. 602 603 _regs[Desc_address_0] = (uint32_t) (have_palette ? desc_paddr + 2 : desc_paddr); 604 605 // Provide a descriptor for the second DMA channel in dual-panel mode. 606 607 if (get_panels() == 2) 608 _regs[Desc_address_1] = (uint32_t) (desc_paddr + 1); 609 610 // Initialise panel-related registers. 611 612 _init_panel(); 613 614 // Initialise the control and configuration registers. 615 616 _regs[Lcd_control] = _control_panel() | _control_bpp() | _control_transfer() | _control_irq(); 617 _regs[Lcd_config] = _panel->config; 618 } 619 620 // Set the interrupt for controller-related events. 621 622 void 623 Lcd_jz4740_chip::set_irq(l4_cap_idx_t irq, enum Jz4740_lcd_irq_condition conditions) 624 { 625 _irq = irq; 626 _irq_conditions = conditions; 627 } 628 629 // Wait for an interrupt condition. 630 631 long 632 Lcd_jz4740_chip::wait_for_irq() 633 { 634 l4_msgtag_t tag; 635 636 _regs[Lcd_status] = _regs[Lcd_status] & ~(_status_irq()); 637 638 // Wait for a condition. 639 640 tag = l4_irq_receive(_irq, l4_timeout(L4_IPC_TIMEOUT_NEVER, l4util_micros2l4to(2000000))); 641 642 // Acknowledge interrupts. 643 644 _regs[Lcd_status] = 0; 645 646 // Return errors. 647 648 return l4_error(tag); 649 } 650 651 652 653 // C language interface functions. 654 655 void * 656 jz4740_lcd_init(l4_addr_t lcd_base, struct Jz4740_lcd_panel *panel) 657 { 658 return (void *) new Lcd_jz4740_chip(lcd_base, panel); 659 } 660 661 void 662 jz4740_lcd_config(void *lcd, struct Jz4740_lcd_descriptor *desc_vaddr, 663 struct Jz4740_lcd_descriptor *desc_paddr, 664 l4_addr_t fb_paddr) 665 { 666 static_cast<Lcd_jz4740_chip *>(lcd)->config(desc_vaddr, desc_paddr, fb_paddr); 667 } 668 669 void 670 jz4740_lcd_set_irq(void *lcd, l4_cap_idx_t irq, enum Jz4740_lcd_irq_condition conditions) 671 { 672 static_cast<Lcd_jz4740_chip *>(lcd)->set_irq(irq, conditions); 673 } 674 675 long 676 jz4740_lcd_wait_for_irq(void *lcd) 677 { 678 return static_cast<Lcd_jz4740_chip *>(lcd)->wait_for_irq(); 679 } 680 681 void 682 jz4740_lcd_disable(void *lcd) 683 { 684 static_cast<Lcd_jz4740_chip *>(lcd)->disable(); 685 } 686 687 void 688 jz4740_lcd_disable_quick(void *lcd) 689 { 690 static_cast<Lcd_jz4740_chip *>(lcd)->disable_quick(); 691 } 692 693 void 694 jz4740_lcd_enable(void *lcd) 695 { 696 static_cast<Lcd_jz4740_chip *>(lcd)->enable(); 697 } 698 699 int 700 jz4740_lcd_enabled(void *lcd) 701 { 702 return (int) static_cast<Lcd_jz4740_chip *>(lcd)->enabled(); 703 } 704 705 int 706 jz4740_lcd_get_pixel_clock(void *lcd) 707 { 708 return static_cast<Lcd_jz4740_chip *>(lcd)->get_pixel_clock(); 709 } 710 711 l4_size_t 712 jz4740_lcd_get_descriptors_size(void *lcd) 713 { 714 return static_cast<Lcd_jz4740_chip *>(lcd)->get_descriptors_size(); 715 } 716 717 l4_size_t 718 jz4740_lcd_get_line_size(void *lcd) 719 { 720 return static_cast<Lcd_jz4740_chip *>(lcd)->get_line_size(); 721 } 722 723 l4_size_t 724 jz4740_lcd_get_screen_size(void *lcd) 725 { 726 return static_cast<Lcd_jz4740_chip *>(lcd)->get_screen_size(); 727 } 728 729 l4_addr_t 730 jz4740_lcd_get_palette(void *lcd, l4_addr_t base) 731 { 732 return static_cast<Lcd_jz4740_chip *>(lcd)->get_palette(base); 733 } 734 735 void 736 jz4740_lcd_init_palette(void *lcd, l4_addr_t palette) 737 { 738 static_cast<Lcd_jz4740_chip *>(lcd)->init_palette(palette); 739 }