# HG changeset patch # User Paul Boddie # Date 1590242722 -7200 # Node ID 992d837eb2447b4606829125e0e58bdde0433ab8 # Parent 0097292940cac004aad72453ae4cf8b1e86f4ff1 Introduced tentative support for, and testing of, the JZ4780 LCD controller. diff -r 0097292940ca -r 992d837eb244 pkg/devices/lib/cpm/include/cpm-jz4780.h --- a/pkg/devices/lib/cpm/include/cpm-jz4780.h Fri May 22 00:25:28 2020 +0200 +++ b/pkg/devices/lib/cpm/include/cpm-jz4780.h Sat May 23 16:05:22 2020 +0200 @@ -215,6 +215,7 @@ void jz4780_cpm_set_hdmi_frequency(void *cpm, uint32_t pclk); void jz4780_cpm_set_lcd_pixel_frequency(void *cpm, uint32_t pclk); +void jz4780_cpm_set_lcd_frequencies(void *cpm, uint32_t pclk, uint8_t ratio); void jz4780_cpm_set_mpll_parameters(void *cpm, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider); EXTERN_C_END diff -r 0097292940ca -r 992d837eb244 pkg/devices/lib/cpm/src/jz4780.cc --- a/pkg/devices/lib/cpm/src/jz4780.cc Fri May 22 00:25:28 2020 +0200 +++ b/pkg/devices/lib/cpm/src/jz4780.cc Sat May 23 16:05:22 2020 +0200 @@ -796,6 +796,7 @@ } // NOTE: Compatibility method. Probably needs reviewing. +// NOTE: HCLK/AHB0 must be 1.5 (for TFT) or 3 (for STN) times the pixel clock. void Cpm_jz4780_chip::set_lcd_frequencies(uint32_t pclk, uint8_t ratio) @@ -805,6 +806,7 @@ } // NOTE: Empty method for compatibility. +// NOTE: It could potentially be combined with start_lcd. void Cpm_jz4780_chip::update_output_frequency() @@ -1083,6 +1085,12 @@ } void +jz4780_cpm_set_lcd_frequencies(void *cpm, uint32_t pclk, uint8_t ratio) +{ + static_cast(cpm)->set_lcd_frequencies(pclk, ratio); +} + +void jz4780_cpm_set_mpll_parameters(void *cpm, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider) { static_cast(cpm)->set_pll_parameters(Pll_control_M, multiplier, in_divider, out_divider); diff -r 0097292940ca -r 992d837eb244 pkg/devices/lib/lcd/src/jz4740/lcd-jz4740.cc --- a/pkg/devices/lib/lcd/src/jz4740/lcd-jz4740.cc Fri May 22 00:25:28 2020 +0200 +++ b/pkg/devices/lib/lcd/src/jz4740/lcd-jz4740.cc Sat May 23 16:05:22 2020 +0200 @@ -2,7 +2,8 @@ * LCD peripheral support for the JZ4740 and related SoCs. * * Copyright (C) Xiangfu Liu - * Copyright (C) 2015, 2016, 2017, 2018 Paul Boddie + * Copyright (C) 2015, 2016, 2017, 2018, + * 2020 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -83,23 +84,25 @@ enum Control_bits : unsigned { - Control_burst_length = 28, // BST (burst length selection) - Control_rgb_mode = 27, // RGB (RGB mode) - Control_out_underrun = 26, // OFUP (output FIFO underrun protection) - Control_frc_algorithm = 24, // FRC (STN FRC algorithm selection) - Control_palette_delay = 16, // PDD (load palette delay counter) - Control_frame_end_irq_mask = 13, // EOFM (end of frame interrupt mask) - Control_frame_start_irq_mask = 12, // SOFM (start of frame interrupt mask) - Control_out_underrun_irq_mask = 11, // OFUM (output FIFO underrun interrupt mask) - Control_in0_underrun_irq_mask = 10, // IFUM0 (input FIFO 0 underrun interrupt mask) - Control_in1_underrun_irq_mask = 9, // IFUM1 (input FIFO 1 underrun interrupt mask) - Control_disabled_irq_mask = 8, // LDDM (LCD disable done interrupt mask) - Control_quick_disabled_irq_mask = 7, // QDM (LCD quick disable done interrupt mask) - Control_endian_select = 6, // BEDN (endian selection) - Control_bit_order = 5, // PEDN (bit order in bytes) - Control_disable = 4, // DIS (disable controller) - Control_enable = 3, // ENA (enable controller) - Control_bpp = 0, // BPP (bits per pixel) + Control_pin_modify = 31, // PINMD (change pin usage from 15..0 to 17..10, 8..1) + Control_burst_length = 28, // BST (burst length selection) + Control_rgb_mode = 27, // RGB (RGB mode) + Control_out_underrun = 26, // OFUP (output FIFO underrun protection) + Control_frc_algorithm = 24, // FRC (STN FRC algorithm selection) + Control_palette_delay = 16, // PDD (load palette delay counter) + Control_dac_loopback_test = 14, // DACTE (DAC loopback test) + Control_frame_end_irq_enable = 13, // EOFM (end of frame interrupt enable) + Control_frame_start_irq_enable = 12, // SOFM (start of frame interrupt enable) + Control_out_underrun_irq_enable = 11, // OFUM (output FIFO underrun interrupt enable) + Control_in0_underrun_irq_enable = 10, // IFUM0 (input FIFO 0 underrun interrupt enable) + Control_in1_underrun_irq_enable = 9, // IFUM1 (input FIFO 1 underrun interrupt enable) + Control_disabled_irq_enable = 8, // LDDM (LCD disable done interrupt enable) + Control_quick_disabled_irq_enable = 7, // QDM (LCD quick disable done interrupt enable) + Control_endian_select = 6, // BEDN (endian selection) + Control_bit_order = 5, // PEDN (bit order in bytes) + Control_disable = 4, // DIS (disable controller) + Control_enable = 3, // ENA (enable controller) + Control_bpp = 0, // BPP (bits per pixel) }; enum Burst_length_values : unsigned diff -r 0097292940ca -r 992d837eb244 pkg/landfall-examples/ci20_hdmi_i2c/Makefile --- a/pkg/landfall-examples/ci20_hdmi_i2c/Makefile Fri May 22 00:25:28 2020 +0200 +++ b/pkg/landfall-examples/ci20_hdmi_i2c/Makefile Sat May 23 16:05:22 2020 +0200 @@ -3,6 +3,6 @@ TARGET = ex_ci20_hdmi_i2c SRC_C = ci20_hdmi_i2c.c -REQUIRES_LIBS = libio l4re_c-util libdevice-util libdrivers-cpm libdrivers-hdmi libdrivers-gpio libedid +REQUIRES_LIBS = libio l4re_c-util libdevice-util libdrivers-cpm libdrivers-hdmi libdrivers-lcd-jz4740 libdrivers-gpio libedid include $(L4DIR)/mk/prog.mk diff -r 0097292940ca -r 992d837eb244 pkg/landfall-examples/ci20_hdmi_i2c/ci20_hdmi_i2c.c --- a/pkg/landfall-examples/ci20_hdmi_i2c/ci20_hdmi_i2c.c Fri May 22 00:25:28 2020 +0200 +++ b/pkg/landfall-examples/ci20_hdmi_i2c/ci20_hdmi_i2c.c Sat May 23 16:05:22 2020 +0200 @@ -14,6 +14,11 @@ #include #include #include + +#include +#include +#include + #include #include #include @@ -39,6 +44,30 @@ +/* Test panel. */ + +static struct Jz4740_lcd_panel panel = { + .config = ( + Jz4740_lcd_mode_tft_generic + | Jz4740_lcd_pclock_negative + | Jz4740_lcd_hsync_positive + | Jz4740_lcd_vsync_positive + | Jz4740_lcd_de_positive), + + .width = 1280, + .height = 1024, + .bpp = 32, + .frame_rate = 60, + .hsync = 112, + .vsync = 3, + .line_start = 248, // back porch (blanking - vsyn - offset) + .line_end = 48, // front porch (sync offset) + .frame_start = 36, // back porch (blanking - vsyn - offset) + .frame_end = 3, // front porch (sync offset) +}; + + + /* Device and resource discovery. */ static long item_in_range(long start, long end, long index) @@ -80,6 +109,7 @@ l4_addr_t cpm_base = 0, cpm_base_end = 0; l4_addr_t gpio_base = 0, gpio_base_end = 0; l4_addr_t hdmi_base = 0, hdmi_base_end = 0; + l4_addr_t lcd_base = 0, lcd_base_end = 0; l4_addr_t port_f, port_f_end; /* Peripheral abstractions. */ @@ -87,13 +117,16 @@ void *cpm; void *gpio_port_f; void *hdmi; + void *lcd; /* Access to IRQs. */ l4_uint32_t hdmi_irq_start = 0, hdmi_irq_end = 0; - l4_cap_idx_t icucap, irqcap; + l4_uint32_t lcd_irq_start = 0, lcd_irq_end = 0; + l4_cap_idx_t icucap, hdmi_irq, lcd_irq; - irqcap = l4re_util_cap_alloc(); + hdmi_irq = l4re_util_cap_alloc(); + lcd_irq = l4re_util_cap_alloc(); icucap = l4re_env_get_cap("icu"); if (l4_is_invalid_cap(icucap)) @@ -102,7 +135,7 @@ return 1; } - if (l4_is_invalid_cap(irqcap)) + if (l4_is_invalid_cap(hdmi_irq) || l4_is_invalid_cap(lcd_irq)) { printf("Capabilities not available for interrupts.\n"); return 1; @@ -115,11 +148,17 @@ if (get_irq("jz4780-hdmi", &hdmi_irq_start, &hdmi_irq_end) < 0) return 1; - printf("IRQ range at %d...%d.\n", hdmi_irq_start, hdmi_irq_end); + printf("HDMI IRQ range at %d...%d.\n", hdmi_irq_start, hdmi_irq_end); + + if (get_irq("jz4780-lcd", &lcd_irq_start, &lcd_irq_end) < 0) + return 1; + + printf("LCD IRQ range at %d...%d.\n", lcd_irq_start, lcd_irq_end); /* Create interrupt objects. */ - err = l4_error(l4_factory_create_irq(l4re_global_env->factory, irqcap)); + err = l4_error(l4_factory_create_irq(l4re_global_env->factory, hdmi_irq)) || + l4_error(l4_factory_create_irq(l4re_global_env->factory, lcd_irq)); if (err) { @@ -132,7 +171,10 @@ err = l4_error(l4_icu_bind(icucap, item_in_range(hdmi_irq_start, hdmi_irq_end, 0), - irqcap)); + hdmi_irq)) || + l4_error(l4_icu_bind(icucap, + item_in_range(lcd_irq_start, lcd_irq_end, 0), + lcd_irq)); if (err) { @@ -142,7 +184,8 @@ /* Attach ourselves to the interrupt handler. */ - err = l4_error(l4_rcv_ep_bind_thread(irqcap, l4re_env()->main_thread, 0)); + err = l4_error(l4_rcv_ep_bind_thread(hdmi_irq, l4re_env()->main_thread, 0)) || + l4_error(l4_rcv_ep_bind_thread(lcd_irq, l4re_env()->main_thread, 0)); if (err) { @@ -173,6 +216,13 @@ printf("HDMI at 0x%lx...0x%lx.\n", hdmi_base, hdmi_base_end); + printf("Access LCD...\n"); + + if (get_memory("jz4780-lcd", &lcd_base, &lcd_base_end) < 0) + return 1; + + printf("LCD at 0x%lx...0x%lx.\n", lcd_base, lcd_base_end); + /* Obtain CPM object. */ cpm = jz4780_cpm_init(cpm_base); @@ -207,7 +257,7 @@ printf("Set up HDMI...\n"); - hdmi = jz4780_hdmi_init(hdmi_base, hdmi_base_end, irqcap); + hdmi = jz4780_hdmi_init(hdmi_base, hdmi_base_end, hdmi_irq); printf("Read version...\n"); @@ -228,9 +278,31 @@ show_timings(edid); - /* Detach from the interrupt. */ + /* Obtain LCD reference. */ + + printf("Set up LCD...\n"); + + lcd = jz4740_lcd_init(lcd_base, &panel); + + /* Test initialisation with a frequency appropriate for the test panel. */ + + printf("LCD divider: %d\n", jz4780_cpm_get_lcd_pixel_divider(cpm)); + printf("LCD frequency: %d\n", jz4780_cpm_get_lcd_pixel_frequency(cpm)); + printf("Desired frequency: %d\n", jz4740_lcd_get_pixel_clock(lcd)); - err = l4_error(l4_irq_detach(irqcap)); + jz4780_cpm_stop_lcd(cpm); + + jz4780_cpm_set_lcd_frequencies(cpm, jz4740_lcd_get_pixel_clock(lcd), 3); + + printf("LCD divider: %d\n", jz4780_cpm_get_lcd_pixel_divider(cpm)); + printf("LCD frequency: %d\n", jz4780_cpm_get_lcd_pixel_frequency(cpm)); + + jz4780_cpm_start_lcd(cpm); + + /* Detach from the interrupts. */ + + err = l4_error(l4_irq_detach(hdmi_irq)) || + l4_error(l4_irq_detach(lcd_irq)); if (err) printf("Error detaching from IRQ: %ld\n", err);