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