1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/pkg/devices/lib/lcd/src/jz4740/lcd-jz4740.cc Sun May 13 01:34:16 2018 +0200
1.3 @@ -0,0 +1,749 @@
1.4 +/*
1.5 + * LCD peripheral support for the JZ4740 and related SoCs.
1.6 + *
1.7 + * Copyright (C) Xiangfu Liu <xiangfu@sharism.cc>
1.8 + * Copyright (C) 2015, 2016, 2017, 2018 Paul Boddie <paul@boddie.org.uk>
1.9 + *
1.10 + * This program is free software; you can redistribute it and/or
1.11 + * modify it under the terms of the GNU General Public License as
1.12 + * published by the Free Software Foundation; either version 2 of
1.13 + * the License, or (at your option) any later version.
1.14 + *
1.15 + * This program is distributed in the hope that it will be useful,
1.16 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.17 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.18 + * GNU General Public License for more details.
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License
1.21 + * along with this program; if not, write to the Free Software
1.22 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
1.23 + * Boston, MA 02110-1301, USA
1.24 + */
1.25 +
1.26 +#include <l4/devices/hw_mmio_register_block.h>
1.27 +#include <l4/sys/cache.h>
1.28 +#include <l4/sys/types.h>
1.29 +
1.30 +#include "lcd-jz4740.h"
1.31 +#include "lcd-jz4740-config.h"
1.32 +
1.33 +#include <stdint.h>
1.34 +
1.35 +enum Regs : unsigned
1.36 +{
1.37 + Lcd_config = 0x000, // LCD_CFG
1.38 + Lcd_vsync = 0x004, // LCD_VSYNC
1.39 + Lcd_hsync = 0x008, // LCD_HSYNC
1.40 + Vertical_area = 0x00c, // LCD_VAT
1.41 + Display_hlimits = 0x010, // LCD_DAH
1.42 + Display_vlimits = 0x014, // LCD_DAV
1.43 + Lcd_ps = 0x018, // LCD_PS
1.44 + Lcd_cls = 0x01c, // LCD_CLS
1.45 + Lcd_spl = 0x020, // LCD_SPL
1.46 + Lcd_rev = 0x024, // LCD_REV
1.47 + Lcd_control = 0x030, // LCD_CTRL
1.48 + Lcd_status = 0x034, // LCD_STATE
1.49 + Lcd_irq_id = 0x038, // LCD_IID
1.50 + Desc_address_0 = 0x040, // LCD_DA0
1.51 + Source_address_0 = 0x044, // LCD_SA0
1.52 + Frame_id_0 = 0x048, // LCD_FID0
1.53 + Command_0 = 0x04c, // LCD_CMD0
1.54 + Desc_address_1 = 0x050, // LCD_DA1
1.55 + Source_address_1 = 0x054, // LCD_SA1
1.56 + Frame_id_1 = 0x058, // LCD_FID1
1.57 + Command_1 = 0x05c, // LCD_CMD1
1.58 +};
1.59 +
1.60 +// Lcd_config descriptions.
1.61 +
1.62 +enum Config_values : unsigned
1.63 +{
1.64 + Config_stn_pins_mask = 0x3,
1.65 + Config_mode_mask = 0xf,
1.66 +};
1.67 +
1.68 +// Field positions for registers employing two values, with the first typically
1.69 +// being the start value and the second being an end value.
1.70 +
1.71 +enum Value_pair_bits : unsigned
1.72 +{
1.73 + Value_first = 16,
1.74 + Value_second = 0,
1.75 +};
1.76 +
1.77 +// Vertical_area bits.
1.78 +
1.79 +enum Vertical_area_values : unsigned
1.80 +{
1.81 + Vertical_area_horizontal_size = Value_first, // sum of display and blank regions (dot/pixel clock periods)
1.82 + Vertical_area_vertical_size = Value_second, // sum of display and blank regions (line periods)
1.83 +};
1.84 +
1.85 +// Lcd_control descriptions.
1.86 +
1.87 +enum Control_bits : unsigned
1.88 +{
1.89 + Control_burst_length = 28, // BST (burst length selection)
1.90 + Control_rgb_mode = 27, // RGB (RGB mode)
1.91 + Control_out_underrun = 26, // OFUP (output FIFO underrun protection)
1.92 + Control_frc_algorithm = 24, // FRC (STN FRC algorithm selection)
1.93 + Control_palette_delay = 16, // PDD (load palette delay counter)
1.94 + Control_frame_end_irq_mask = 13, // EOFM (end of frame interrupt mask)
1.95 + Control_frame_start_irq_mask = 12, // SOFM (start of frame interrupt mask)
1.96 + Control_out_underrun_irq_mask = 11, // OFUM (output FIFO underrun interrupt mask)
1.97 + Control_in0_underrun_irq_mask = 10, // IFUM0 (input FIFO 0 underrun interrupt mask)
1.98 + Control_in1_underrun_irq_mask = 9, // IFUM1 (input FIFO 1 underrun interrupt mask)
1.99 + Control_disabled_irq_mask = 8, // LDDM (LCD disable done interrupt mask)
1.100 + Control_quick_disabled_irq_mask = 7, // QDM (LCD quick disable done interrupt mask)
1.101 + Control_endian_select = 6, // BEDN (endian selection)
1.102 + Control_bit_order = 5, // PEDN (bit order in bytes)
1.103 + Control_disable = 4, // DIS (disable controller)
1.104 + Control_enable = 3, // ENA (enable controller)
1.105 + Control_bpp = 0, // BPP (bits per pixel)
1.106 +};
1.107 +
1.108 +enum Burst_length_values : unsigned
1.109 +{
1.110 + Burst_length_4 = 0, // 4 word
1.111 + Burst_length_8 = 1, // 8 word
1.112 + Burst_length_16 = 2, // 16 word
1.113 +
1.114 + // JZ4780 extensions.
1.115 +
1.116 + Burst_length_32 = 3, // 32 word
1.117 + Burst_length_64 = 4, // 64 word
1.118 + Burst_length_mask = 0x7,
1.119 +};
1.120 +
1.121 +enum Rgb_mode_values : unsigned
1.122 +{
1.123 + Rgb_mode_565 = 0,
1.124 + Rgb_mode_555 = 1,
1.125 + Rgb_mode_mask = 0x1,
1.126 +};
1.127 +
1.128 +enum Frc_algorithm_values : unsigned
1.129 +{
1.130 + Frc_greyscales_16 = 0,
1.131 + Frc_greyscales_4 = 1,
1.132 + Frc_greyscales_2 = 2,
1.133 + Frc_greyscales_mask = 0x3,
1.134 +};
1.135 +
1.136 +enum Control_bpp_values : unsigned
1.137 +{
1.138 + Control_bpp_1bpp = 0,
1.139 + Control_bpp_2bpp = 1,
1.140 + Control_bpp_4bpp = 2,
1.141 + Control_bpp_8bpp = 3,
1.142 + Control_bpp_15bpp = 4,
1.143 + Control_bpp_16bpp = 4,
1.144 + Control_bpp_18bpp = 5,
1.145 + Control_bpp_24bpp = 5,
1.146 + Control_bpp_24bpp_comp = 6,
1.147 + Control_bpp_30bpp = 7,
1.148 + Control_bpp_32bpp = 7,
1.149 + Control_bpp_mask = 0x7,
1.150 +};
1.151 +
1.152 +// Command descriptions.
1.153 +
1.154 +enum Command_bits : unsigned
1.155 +{
1.156 + Command_frame_start_irq = 31, // SOFINT (start of frame interrupt)
1.157 + Command_frame_end_irq = 30, // EOFINT (end of frame interrupt)
1.158 + Command_lcm_command = 29, // JZ4780: CMD (LCM command/data via DMA0)
1.159 + Command_palette_buffer = 28, // PAL (descriptor references palette, not display data)
1.160 + Command_frame_compressed = 27, // JZ4780: COMPEN (16/24bpp compression enabled)
1.161 + Command_frame_enable = 26, // JZ4780: FRM_EN
1.162 + Command_field_even = 25, // JZ4780: FIELD_SEL (interlace even field)
1.163 + Command_16x16_block = 24, // JZ4780: 16x16BLOCK (fetch data by 16x16 block)
1.164 + Command_buffer_length = 0, // LEN
1.165 +};
1.166 +
1.167 +enum Command_values : unsigned
1.168 +{
1.169 + Command_buffer_length_mask = 0x00ffffff,
1.170 +};
1.171 +
1.172 +
1.173 +
1.174 +// Utility functions.
1.175 +
1.176 +// Round values up according to the resolution.
1.177 +
1.178 +static uint32_t align(uint32_t value, uint32_t resolution)
1.179 +{
1.180 + return (value + (resolution - 1)) & ~(resolution - 1);
1.181 +}
1.182 +
1.183 +// Value pair encoding.
1.184 +
1.185 +static uint32_t encode_pair(uint32_t start, uint32_t end)
1.186 +{
1.187 + return (start << Value_first) | (end << Value_second);
1.188 +}
1.189 +
1.190 +// RGB conversions.
1.191 +
1.192 +static uint16_t rgb8_to_rgb16(uint8_t rgb)
1.193 +{
1.194 + return ((((rgb & 0xe0) >> 5) * 4) << 11) | ((((rgb & 0x1c) >> 2) * 9) << 6) | ((rgb & 0x03) * 10);
1.195 +}
1.196 +
1.197 +static uint16_t rgb4_to_rgb16(uint8_t rgb)
1.198 +{
1.199 + return ((((rgb & 8) >> 3) * 0x1f) << 11) | ((((rgb & 6) >> 1) * 0x15) << 5) | ((rgb & 1) * 0x1f);
1.200 +}
1.201 +
1.202 +
1.203 +
1.204 +
1.205 +// If implemented as a Hw::Device, various properties would be
1.206 +// initialised in the constructor and obtained from the device tree
1.207 +// definitions.
1.208 +
1.209 +Lcd_jz4740_chip::Lcd_jz4740_chip(l4_addr_t addr, Jz4740_lcd_panel *panel)
1.210 +: _panel(panel)
1.211 +{
1.212 + _regs = new Hw::Mmio_register_block<32>(addr);
1.213 + _burst_size = 16; // 16-word burst size
1.214 +
1.215 + // add_cid("lcd");
1.216 + // add_cid("lcd-jz4740");
1.217 +}
1.218 +
1.219 +struct Jz4740_lcd_panel *
1.220 +Lcd_jz4740_chip::get_panel()
1.221 +{
1.222 + return _panel;
1.223 +}
1.224 +
1.225 +void
1.226 +Lcd_jz4740_chip::disable()
1.227 +{
1.228 + // Set the disable bit for normal shutdown.
1.229 +
1.230 + _regs[Lcd_control] = _regs[Lcd_control] | (1 << Control_disable);
1.231 +}
1.232 +
1.233 +void
1.234 +Lcd_jz4740_chip::disable_quick()
1.235 +{
1.236 + // Clear the enable bit for quick shutdown.
1.237 +
1.238 + _regs[Lcd_control] = _regs[Lcd_control] & ~(1 << Control_enable);
1.239 +}
1.240 +
1.241 +void
1.242 +Lcd_jz4740_chip::enable()
1.243 +{
1.244 + // Clear the disable bit and set the enable bit.
1.245 +
1.246 + _regs[Lcd_control] = (_regs[Lcd_control] & ~(1 << Control_disable)) | (1 << Control_enable);
1.247 +}
1.248 +
1.249 +// Calculate and return the pixel clock frequency.
1.250 +
1.251 +int
1.252 +Lcd_jz4740_chip::get_pixel_clock()
1.253 +{
1.254 + int pclk, multiplier;
1.255 +
1.256 + // Serial mode: 3 pixel clock cycles per pixel (one per channel).
1.257 + // Parallel mode: 1 pixel clock cycle per pixel.
1.258 +
1.259 + multiplier = have_serial_tft() ? 3 : 1;
1.260 +
1.261 + // Derive pixel clock rate from frame rate.
1.262 + // This multiplies the number of pixel periods in a line by the number of
1.263 + // lines in a frame, thus obtaining the number of such periods in a frame.
1.264 + // Multiplying this result with the frame rate yields the pixel frequency.
1.265 +
1.266 + pclk = _panel->frame_rate *
1.267 + (_panel->width * multiplier +
1.268 + _panel->hsync + _panel->line_start + _panel->line_end) *
1.269 + (_panel->height +
1.270 + _panel->vsync + _panel->frame_start + _panel->frame_end);
1.271 +
1.272 + // STN panel adjustments.
1.273 +
1.274 + if (have_stn_panel())
1.275 + {
1.276 + // Colour STN panels apparently need to be driven at three times the rate.
1.277 +
1.278 + if (have_colour_stn()) pclk = (pclk * 3);
1.279 +
1.280 + // Reduce the rate according to the width of the STN connection.
1.281 + // Since the pins setting employs log2(pins), a shift by this value is
1.282 + // equivalent to a division by the number of pins.
1.283 +
1.284 + pclk = pclk >> ((_panel->config & Config_stn_pins_mask) >> Jz4740_lcd_config_stn_pins);
1.285 +
1.286 + // Divide the rate by the number of panels.
1.287 +
1.288 + pclk /= get_panels();
1.289 + }
1.290 +
1.291 + return pclk;
1.292 +}
1.293 +
1.294 +
1.295 +
1.296 +// Return the panel mode.
1.297 +
1.298 +uint32_t
1.299 +Lcd_jz4740_chip::_mode()
1.300 +{
1.301 + return _panel->config & Config_mode_mask;
1.302 +}
1.303 +
1.304 +// Return the number of panels available.
1.305 +
1.306 +int
1.307 +Lcd_jz4740_chip::get_panels()
1.308 +{
1.309 + uint32_t mode = _mode();
1.310 +
1.311 + return (mode == Jz4740_lcd_mode_stn_dual_colour) ||
1.312 + (mode == Jz4740_lcd_mode_stn_dual_mono) ? 2 : 1;
1.313 +}
1.314 +
1.315 +// Return whether the panel is STN.
1.316 +
1.317 +int
1.318 +Lcd_jz4740_chip::have_stn_panel()
1.319 +{
1.320 + uint32_t mode = _mode();
1.321 +
1.322 + return ((mode == Jz4740_lcd_mode_stn_single_colour) ||
1.323 + (mode == Jz4740_lcd_mode_stn_dual_colour) ||
1.324 + (mode == Jz4740_lcd_mode_stn_single_mono) ||
1.325 + (mode == Jz4740_lcd_mode_stn_dual_mono));
1.326 +}
1.327 +
1.328 +// Return whether the panel is colour STN.
1.329 +
1.330 +int
1.331 +Lcd_jz4740_chip::have_colour_stn()
1.332 +{
1.333 + uint32_t mode = _mode();
1.334 +
1.335 + return ((mode == Jz4740_lcd_mode_stn_single_colour) ||
1.336 + (mode == Jz4740_lcd_mode_stn_dual_colour));
1.337 +}
1.338 +
1.339 +// Return whether the panel is colour STN.
1.340 +
1.341 +int
1.342 +Lcd_jz4740_chip::have_serial_tft()
1.343 +{
1.344 + return _mode() == Jz4740_lcd_mode_tft_serial;
1.345 +}
1.346 +
1.347 +
1.348 +
1.349 +// Return the line memory size.
1.350 +
1.351 +l4_size_t
1.352 +Lcd_jz4740_chip::get_line_size()
1.353 +{
1.354 + // Lines must be aligned to a word boundary.
1.355 +
1.356 + return align((_panel->width * _panel->bpp) / 8, sizeof(uint32_t));
1.357 +}
1.358 +
1.359 +// Return the screen memory size.
1.360 +
1.361 +l4_size_t
1.362 +Lcd_jz4740_chip::get_screen_size()
1.363 +{
1.364 + return get_line_size() * _panel->height;
1.365 +}
1.366 +
1.367 +// Return the aligned size for the DMA transfer.
1.368 +
1.369 +l4_size_t
1.370 +Lcd_jz4740_chip::get_aligned_size()
1.371 +{
1.372 + return align(get_screen_size(), _burst_size * sizeof(uint32_t));
1.373 +}
1.374 +
1.375 +// Return the size of the palette.
1.376 +
1.377 +l4_size_t
1.378 +Lcd_jz4740_chip::get_palette_size()
1.379 +{
1.380 + // No palette for modes with more than eight bits per pixel.
1.381 +
1.382 + if (_panel->bpp > 8) return 0;
1.383 +
1.384 + // Get the size of a collection of two-byte entries, one per colour.
1.385 +
1.386 + return (1 << (_panel->bpp)) * sizeof(uint16_t);
1.387 +}
1.388 +
1.389 +// Return the aligned size of the palette for the DMA transfer.
1.390 +
1.391 +l4_size_t
1.392 +Lcd_jz4740_chip::get_aligned_palette_size()
1.393 +{
1.394 + return align(get_palette_size(), _burst_size * sizeof(uint32_t));
1.395 +}
1.396 +
1.397 +// Return the total memory requirements of the framebuffers and palette.
1.398 +
1.399 +l4_size_t
1.400 +Lcd_jz4740_chip::get_total_size()
1.401 +{
1.402 + return get_aligned_size() * get_panels() + get_aligned_palette_size();
1.403 +}
1.404 +
1.405 +// Return the total memory requirements of any DMA descriptors.
1.406 +
1.407 +l4_size_t
1.408 +Lcd_jz4740_chip::get_descriptors_size()
1.409 +{
1.410 + return 3 * sizeof(struct Jz4740_lcd_descriptor);
1.411 +}
1.412 +
1.413 +
1.414 +
1.415 +// Functions returning addresses of each data region.
1.416 +// The base parameter permits the retrieval of virtual or physical addresses.
1.417 +
1.418 +l4_addr_t
1.419 +Lcd_jz4740_chip::get_palette(l4_addr_t base)
1.420 +{
1.421 + // Use memory at the end of the allocated region for the palette.
1.422 +
1.423 + return base + (get_panels() * get_aligned_size()) - get_aligned_palette_size();
1.424 +}
1.425 +
1.426 +l4_addr_t
1.427 +Lcd_jz4740_chip::get_framebuffer(int panel, l4_addr_t base)
1.428 +{
1.429 + // Framebuffers for panels are allocated at the start of the region.
1.430 +
1.431 + return base + (panel * get_aligned_size());
1.432 +}
1.433 +
1.434 +
1.435 +
1.436 +// Palette initialisation.
1.437 +
1.438 +void
1.439 +Lcd_jz4740_chip::init_palette(l4_addr_t palette)
1.440 +{
1.441 + uint8_t colours = 1 << (_panel->bpp);
1.442 + uint16_t *entry = (uint16_t *) palette;
1.443 + uint16_t *end = entry + colours;
1.444 + uint8_t value = 0;
1.445 +
1.446 + while (entry < end)
1.447 + {
1.448 + switch (_panel->bpp)
1.449 + {
1.450 + case 4:
1.451 + *entry = rgb4_to_rgb16(value);
1.452 + break;
1.453 +
1.454 + case 8:
1.455 + *entry = rgb8_to_rgb16(value);
1.456 + break;
1.457 +
1.458 + default:
1.459 + break;
1.460 + }
1.461 +
1.462 + value++;
1.463 + entry++;
1.464 + }
1.465 +}
1.466 +
1.467 +
1.468 +
1.469 +// Return colour depth control value.
1.470 +// NOTE: Not supporting JZ4780 options.
1.471 +
1.472 +uint32_t
1.473 +Lcd_jz4740_chip::_control_bpp()
1.474 +{
1.475 + switch (_panel->bpp)
1.476 + {
1.477 + case 1: return Control_bpp_1bpp;
1.478 + case 2: return Control_bpp_2bpp;
1.479 + case 3 ... 4: return Control_bpp_4bpp;
1.480 + case 5 ... 8: return Control_bpp_8bpp;
1.481 + case 9 ... 15: return Control_bpp_15bpp | (Rgb_mode_555 << Control_rgb_mode);
1.482 + case 17 ... 18: return Control_bpp_18bpp;
1.483 + case 19 ... 32: return Control_bpp_24bpp;
1.484 + case 16:
1.485 + default: return Control_bpp_16bpp;
1.486 + }
1.487 +}
1.488 +
1.489 +// Return a panel-related control value.
1.490 +
1.491 +uint32_t
1.492 +Lcd_jz4740_chip::_control_panel()
1.493 +{
1.494 + if (have_stn_panel())
1.495 + return _control_stn_frc();
1.496 + else
1.497 + return 0;
1.498 +}
1.499 +
1.500 +// Return a STN-related control value.
1.501 +
1.502 +uint32_t
1.503 +Lcd_jz4740_chip::_control_stn_frc()
1.504 +{
1.505 + if (_panel->bpp <= 2)
1.506 + return Frc_greyscales_2;
1.507 + if (_panel->bpp <= 4)
1.508 + return Frc_greyscales_4;
1.509 + return Frc_greyscales_16;
1.510 +}
1.511 +
1.512 +// Return a transfer-related control value.
1.513 +
1.514 +uint32_t
1.515 +Lcd_jz4740_chip::_control_transfer()
1.516 +{
1.517 + uint32_t length;
1.518 +
1.519 + switch (_burst_size)
1.520 + {
1.521 + case 4: length = Burst_length_4; break;
1.522 + case 8: length = Burst_length_8; break;
1.523 + case 32: length = Burst_length_32; break;
1.524 + case 64: length = Burst_length_64; break;
1.525 + case 16:
1.526 + default: length = Burst_length_16; break;
1.527 + }
1.528 +
1.529 + return (length << Control_burst_length) | (1 << Control_out_underrun);
1.530 +}
1.531 +
1.532 +// STN panel-specific initialisation.
1.533 +
1.534 +void
1.535 +Lcd_jz4740_chip::_init_stn()
1.536 +{
1.537 + // Divide the height by the number of panels.
1.538 +
1.539 + uint32_t height = _panel->height / get_panels();
1.540 +
1.541 + // Since the value is log2(pins), 1 << value yields the number of pins.
1.542 +
1.543 + int pins = 1 << ((_panel->config & Config_stn_pins_mask) >> Jz4740_lcd_config_stn_pins);
1.544 +
1.545 + // Round parameters up to a multiple of the number of pins.
1.546 +
1.547 + uint32_t hsync = align(_panel->hsync, pins);
1.548 + uint32_t line_start = align(_panel->line_start, pins);
1.549 + uint32_t line_end = align(_panel->line_end, pins);
1.550 +
1.551 + // Define the start and end positions of visible data on a line and in a frame.
1.552 + // Visible frame data is anchored at line zero, with the start region
1.553 + // preceding this line (and thus appearing at the end of the preceding frame).
1.554 +
1.555 + uint32_t line_start_pos = line_start;
1.556 + uint32_t line_end_pos = line_start_pos + _panel->width;
1.557 + uint32_t frame_start_pos = 0;
1.558 + uint32_t frame_end_pos = frame_start_pos + height;
1.559 +
1.560 + // Define sync pulse locations, with hsync occurring after the visible data.
1.561 +
1.562 + _regs[Lcd_hsync] = encode_pair(line_end_pos, line_end_pos + hsync);
1.563 + _regs[Lcd_vsync] = encode_pair(0, _panel->vsync);
1.564 +
1.565 + // Set the display area and limits.
1.566 +
1.567 + _regs[Vertical_area] = encode_pair(line_end_pos + hsync + line_end,
1.568 + frame_end_pos + _panel->vsync + _panel->frame_end + _panel->frame_start);
1.569 +
1.570 + _regs[Display_hlimits] = encode_pair(line_start_pos, line_end_pos);
1.571 + _regs[Display_vlimits] = encode_pair(frame_start_pos, frame_end_pos);
1.572 +
1.573 + // Set the AC bias signal.
1.574 +
1.575 + _regs[Lcd_ps] = encode_pair(0, _panel->frame_start + height + _panel->vsync + _panel->frame_end);
1.576 +}
1.577 +
1.578 +// TFT panel-specific initialisation.
1.579 +
1.580 +void
1.581 +Lcd_jz4740_chip::_init_tft()
1.582 +{
1.583 + // Define the start and end positions of visible data on a line and in a frame.
1.584 +
1.585 + uint32_t line_start_pos = _panel->line_start + _panel->hsync;
1.586 + uint32_t line_end_pos = line_start_pos + _panel->width;
1.587 + uint32_t frame_start_pos = _panel->frame_start + _panel->vsync;
1.588 + uint32_t frame_end_pos = frame_start_pos + _panel->height;
1.589 +
1.590 + // Define sync pulse locations, with pulses appearing before visible data.
1.591 +
1.592 + _regs[Lcd_hsync] = encode_pair(0, _panel->hsync);
1.593 + _regs[Lcd_vsync] = encode_pair(0, _panel->vsync);
1.594 +
1.595 + // Set the display area and limits.
1.596 +
1.597 + _regs[Vertical_area] = encode_pair(line_end_pos + _panel->line_end,
1.598 + frame_end_pos + _panel->frame_end);
1.599 +
1.600 + _regs[Display_hlimits] = encode_pair(line_start_pos, line_end_pos);
1.601 + _regs[Display_vlimits] = encode_pair(frame_start_pos, frame_end_pos);
1.602 +}
1.603 +
1.604 +// Initialise the panel.
1.605 +// NOTE: Only generic STN and TFT panels are supported.
1.606 +
1.607 +void
1.608 +Lcd_jz4740_chip::_init_panel()
1.609 +{
1.610 + if (have_stn_panel())
1.611 + _init_stn();
1.612 + else
1.613 + switch (_mode())
1.614 + {
1.615 + case Jz4740_lcd_mode_tft_generic:
1.616 + case Jz4740_lcd_mode_tft_casio:
1.617 + case Jz4740_lcd_mode_tft_serial: _init_tft();
1.618 +
1.619 + default: break;
1.620 + }
1.621 +}
1.622 +
1.623 +// Initialise a DMA descriptor.
1.624 +
1.625 +void
1.626 +Lcd_jz4740_chip::_set_descriptor(struct Jz4740_lcd_descriptor &desc,
1.627 + l4_addr_t source, l4_size_t size,
1.628 + struct Jz4740_lcd_descriptor *next,
1.629 + uint32_t flags)
1.630 +{
1.631 + // In the command, indicate the number of words from the source for transfer.
1.632 +
1.633 + desc.next = next;
1.634 + desc.source = source;
1.635 + desc.identifier = 0;
1.636 + desc.command = ((size / sizeof(uint32_t)) & Command_buffer_length_mask) | flags;
1.637 +}
1.638 +
1.639 +
1.640 +
1.641 +// Initialise the LCD controller with the memory, panel and framebuffer details.
1.642 +// Any palette must be initialised separately using get_palette and init_palette.
1.643 +
1.644 +void
1.645 +Lcd_jz4740_chip::config(struct Jz4740_lcd_descriptor *desc_vaddr,
1.646 + struct Jz4740_lcd_descriptor *desc_paddr,
1.647 + l4_addr_t fb_paddr)
1.648 +{
1.649 + int have_palette = (_panel->bpp <= 8);
1.650 +
1.651 + // Provide the first framebuffer descriptor in single and dual modes.
1.652 + // Flip back and forth between any palette and the framebuffer.
1.653 +
1.654 + _set_descriptor(desc_vaddr[0], get_framebuffer(0, fb_paddr),
1.655 + get_screen_size(),
1.656 + have_palette ? desc_paddr + 2 : desc_paddr);
1.657 +
1.658 + // Provide the second framebuffer descriptor only in dual-panel mode.
1.659 + // Only employ this descriptor in the second DMA channel.
1.660 +
1.661 + if (get_panels() == 2)
1.662 + _set_descriptor(desc_vaddr[1], get_framebuffer(1, fb_paddr),
1.663 + get_screen_size(),
1.664 + desc_paddr + 1);
1.665 +
1.666 + // Initialise palette descriptor details for lower colour depths.
1.667 +
1.668 + if (have_palette)
1.669 + _set_descriptor(desc_vaddr[2], get_palette(fb_paddr),
1.670 + get_palette_size(),
1.671 + desc_paddr,
1.672 + Command_palette_buffer);
1.673 +
1.674 + // Flush cached structure data.
1.675 +
1.676 + l4_cache_clean_data((unsigned long) desc_vaddr,
1.677 + (unsigned long) desc_vaddr + get_descriptors_size());
1.678 +
1.679 + // Configure DMA by setting frame descriptor addresses.
1.680 +
1.681 + // Provide the palette descriptor address first, if employed.
1.682 +
1.683 + _regs[Desc_address_0] = (uint32_t) (have_palette ? desc_paddr + 2 : desc_paddr);
1.684 +
1.685 + // Provide a descriptor for the second DMA channel in dual-panel mode.
1.686 +
1.687 + if (get_panels() == 2)
1.688 + _regs[Desc_address_1] = (uint32_t) (desc_paddr + 1);
1.689 +
1.690 + // Initialise panel-related registers.
1.691 +
1.692 + _init_panel();
1.693 +
1.694 + // Initialise the control and configuration registers.
1.695 +
1.696 + _regs[Lcd_control] = _control_panel() | _control_bpp() | _control_transfer();
1.697 + _regs[Lcd_config] = _panel->config;
1.698 +}
1.699 +
1.700 +
1.701 +
1.702 +// C language interface functions.
1.703 +
1.704 +void *
1.705 +jz4740_lcd_init(l4_addr_t lcd_base, struct Jz4740_lcd_panel *panel)
1.706 +{
1.707 + return (void *) new Lcd_jz4740_chip(lcd_base, panel);
1.708 +}
1.709 +
1.710 +void
1.711 +jz4740_lcd_config(void *lcd, struct Jz4740_lcd_descriptor *desc_vaddr,
1.712 + struct Jz4740_lcd_descriptor *desc_paddr,
1.713 + l4_addr_t fb_paddr)
1.714 +{
1.715 + static_cast<Lcd_jz4740_chip *>(lcd)->config(desc_vaddr, desc_paddr, fb_paddr);
1.716 +}
1.717 +
1.718 +void
1.719 +jz4740_lcd_disable(void *lcd)
1.720 +{
1.721 + static_cast<Lcd_jz4740_chip *>(lcd)->disable();
1.722 +}
1.723 +
1.724 +void
1.725 +jz4740_lcd_disable_quick(void *lcd)
1.726 +{
1.727 + static_cast<Lcd_jz4740_chip *>(lcd)->disable_quick();
1.728 +}
1.729 +
1.730 +void
1.731 +jz4740_lcd_enable(void *lcd)
1.732 +{
1.733 + static_cast<Lcd_jz4740_chip *>(lcd)->enable();
1.734 +}
1.735 +
1.736 +int
1.737 +jz4740_lcd_get_pixel_clock(void *lcd)
1.738 +{
1.739 + return static_cast<Lcd_jz4740_chip *>(lcd)->get_pixel_clock();
1.740 +}
1.741 +
1.742 +l4_addr_t
1.743 +jz4740_lcd_get_palette(void *lcd, l4_addr_t base)
1.744 +{
1.745 + return static_cast<Lcd_jz4740_chip *>(lcd)->get_palette(base);
1.746 +}
1.747 +
1.748 +void
1.749 +jz4740_lcd_init_palette(void *lcd, l4_addr_t palette)
1.750 +{
1.751 + static_cast<Lcd_jz4740_chip *>(lcd)->init_palette(palette);
1.752 +}