# HG changeset patch # User Paul Boddie # Date 1717769809 -7200 # Node ID c729da7ceb33c1100d7bebfbc5784e05d6900568 # Parent b48a8e7ed6bd8704867af3788d0c93cb6d7c4004 Added a limited SPI-based LCD device component for the X1600 corresponding to the JZ4780-based component already used to drive the same ST7789-based display. diff -r b48a8e7ed6bd -r c729da7ceb33 pkg/devices/Control --- a/pkg/devices/Control Fri Jun 07 16:14:04 2024 +0200 +++ b/pkg/devices/Control Fri Jun 07 16:16:49 2024 +0200 @@ -21,6 +21,7 @@ provides: libdevice-lcd provides: libdevice-lcd-jz4740 provides: libdevice-lcd-jz4780-spi +provides: libdevice-lcd-x1600-spi provides: libdevice-util provides: libdrivers-aic provides: libdrivers-common diff -r b48a8e7ed6bd -r c729da7ceb33 pkg/devices/lcd/include/lcd-jz4780-spi-device.h --- a/pkg/devices/lcd/include/lcd-jz4780-spi-device.h Fri Jun 07 16:14:04 2024 +0200 +++ b/pkg/devices/lcd/include/lcd-jz4780-spi-device.h Fri Jun 07 16:16:49 2024 +0200 @@ -1,7 +1,7 @@ /* - * LCD device support for the JZ4740 and related SoCs. + * LCD device support for the JZ4780. * - * Copyright (C) 2018, 2023 Paul Boddie + * Copyright (C) 2018, 2023, 2024 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 diff -r b48a8e7ed6bd -r c729da7ceb33 pkg/devices/lcd/include/lcd-x1600-spi-device.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lcd/include/lcd-x1600-spi-device.h Fri Jun 07 16:16:49 2024 +0200 @@ -0,0 +1,71 @@ +/* + * LCD device support for the X1600. + * + * Copyright (C) 2018, 2023, 2024 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 + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include + +#include +#include +#include + + + +/* C++ language interface. */ + +#ifdef __cplusplus + +/* Support for specific JZ4780-based devices. */ + +class Lcd_x1600_spi_device : public Lcd_device +{ + /* DMA region providing the DMA descriptor virtual and physical addresses. */ + + struct dma_region _desc_region; + +protected: + /* Device-specific memory allocation. */ + + int _setup_memory(); + +public: + Lcd_x1600_spi_device(Activation *display) + : Lcd_device(display) + { + _setup_memory(); + } + + /* Device operations. */ + + void disable(); + void enable(); + + l4_size_t get_framebuffer_size(); + + void get_view_info(l4re_video_view_info_t *view_info); + + /* Common device instance. */ + + static Lcd_x1600_spi_device *device; +}; + +#endif diff -r b48a8e7ed6bd -r c729da7ceb33 pkg/devices/lcd/src/Makefile --- a/pkg/devices/lcd/src/Makefile Fri Jun 07 16:14:04 2024 +0200 +++ b/pkg/devices/lcd/src/Makefile Fri Jun 07 16:16:49 2024 +0200 @@ -1,9 +1,10 @@ PKGDIR ?= ../.. L4DIR ?= $(PKGDIR)/../.. -TARGET := common jz4740 jz4780 +TARGET := common jz4740 jz4780 x1600 include $(L4DIR)/mk/subdir.mk jz4740: common jz4780: common +x1600: common diff -r b48a8e7ed6bd -r c729da7ceb33 pkg/devices/lcd/src/jz4780/lcd-jz4780-spi-device.cc --- a/pkg/devices/lcd/src/jz4780/lcd-jz4780-spi-device.cc Fri Jun 07 16:14:04 2024 +0200 +++ b/pkg/devices/lcd/src/jz4780/lcd-jz4780-spi-device.cc Fri Jun 07 16:16:49 2024 +0200 @@ -1,5 +1,5 @@ /* - * Common SPI-based screen support for the JZ4780 and related SoCs. + * Common SPI-based screen support for the JZ4780. * * Copyright (C) 2018, 2020, 2021, 2023, 2024 Paul Boddie * @@ -64,7 +64,7 @@ static Dma_channel *dma_channel; static Spi_hybrid *spi_channel; -static Spi_jz4780_channel *spi_jz4780_channel; +static Spi_channel *spi_jz4780_channel; diff -r b48a8e7ed6bd -r c729da7ceb33 pkg/devices/lcd/src/x1600/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lcd/src/x1600/Makefile Fri Jun 07 16:16:49 2024 +0200 @@ -0,0 +1,41 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = liblcd_dev_x1600.o.a liblcd_dev_x1600.o.so +PC_FILENAME = libdevice-lcd-x1600-spi + +# Locations for interface input and generated output. + +IDL_DIR = $(PKGDIR)/idl +IDL_MK_DIR = $(L4DIR)/idl4re/mk +IDL_BUILD_DIR = . +IDL_EXPORT_DIR = $(OBJ_BASE)/include/l4/devices/lcd + +include $(IDL_MK_DIR)/idl.mk + +# Individual interfaces. + +CLIENT_INTERFACES_CC = activation + +# Generated and plain source files. + +CLIENT_INTERFACES_SRC_CC = $(call interfaces_to_client_cc,$(CLIENT_INTERFACES_CC)) + +PLAIN_SRC_CC = lcd-x1600-spi-device.cc + +# Normal definitions. + +SRC_CC = $(CLIENT_INTERFACES_SRC_CC) $(PLAIN_SRC_CC) + +REQUIRES_LIBS = \ + l4re_c l4re_c-util \ + libdevice-lcd \ + libdrivers-cpm libdrivers-dma libdrivers-gpio libdrivers-spi \ + libdevice-util + +PRIVATE_INCDIR = $(PKGDIR)/lcd/include $(IDL_BUILD_DIR) $(IDL_EXPORT_DIR) + +include $(L4DIR)/mk/lib.mk +include $(IDL_MK_DIR)/interface_rules.mk + +$(PLAIN_SRC_CC): $(CLIENT_INTERFACES_SRC_CC) diff -r b48a8e7ed6bd -r c729da7ceb33 pkg/devices/lcd/src/x1600/lcd-x1600-spi-device.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lcd/src/x1600/lcd-x1600-spi-device.cc Fri Jun 07 16:16:49 2024 +0200 @@ -0,0 +1,258 @@ +/* + * Common SPI-based screen support for the X1600. + * + * Copyright (C) 2018, 2020, 2021, 2023, 2024 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 + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include + +#include +#include +#include "lcd-x1600-spi-device.h" + +#include +#include +#include +#include + +#include +#include + +#include +#include + + + +/* Virtual addresses for the CPM, DMA, GPIO and SSI/SPI register blocks. + + NOTE: Should be able to use component abstractions for some of these + eventually. */ + +static l4_addr_t cpm_virt_base = 0, cpm_virt_base_end = 0; +static l4_addr_t dma_virt_base = 0, dma_virt_base_end = 0; +static l4_addr_t gpio_virt_base = 0, gpio_virt_base_end = 0; +static l4_addr_t spi_virt_base = 0, spi_virt_base_end = 0; +static l4_addr_t spi_phys_base = 0, spi_phys_base_end = 0; + +static l4_uint32_t dma_irq_start = 0, dma_irq_end = 0; + +// CPM, DMA, GPIO, SSI/SPI and display device abstractions. + +static Cpm_x1600_chip *cpm_chip; +static Dma_x1600_chip *dma_chip; +static Gpio_x1600_chip *gpio_chip_a, *gpio_chip_b, *gpio_chip_c; +static Spi_x1600_chip *spi_chip; + +static Dma_channel *dma_channel; +static Spi_hybrid *spi_channel; +static Spi_channel *spi_x1600_channel; + + + +// Disable the display. + +void +Lcd_x1600_spi_device::disable() +{ + // NOTE: Need to support cancelling the transfer or disabling the peripheral. + + //disable_display(); +} + +// Configure the peripheral and enable the display. + +void +Lcd_x1600_spi_device::enable() +{ + // Set up the GPIO pins for the peripheral. + // NOTE: Hard-coded pin usage! + + gpio_chip_c->setup(26, Hw::Gpio_chip::Output, 1); // backlight + gpio_chip_b->config_pad(16, Hw::Gpio_chip::Function_alt, 1); // CE1 + gpio_chip_a->config_pad(31, Hw::Gpio_chip::Function_alt, 0); // SCLK + gpio_chip_a->config_pad(30, Hw::Gpio_chip::Function_alt, 0); // MOSI + gpio_chip_a->setup(29, Hw::Gpio_chip::Output, 1); // GPC + + // Initialise the screen. + // NOTE: Specific to the ST7789. + + spi_channel->send_units(2, (const uint8_t []) {0x00, 0x01}, 2, 8); + usleep(120000); + spi_channel->send_units(2, (const uint8_t []) {0x00, 0x11}, 2, 8); + usleep(5000); + spi_channel->send_units(4, (const uint8_t []) {0x00, 0x36, 0x01, 0x00}, 2, 8); + usleep(5000); + spi_channel->send_units(10, (const uint8_t []) {0x00, 0x3a, 0x01, 0x05, 0x00, 0x13, 0x00, 0x29, 0x00, 0x21}, 2, 8); + usleep(5000); + spi_channel->send_units(22, (const uint8_t []) {0x00, 0x2a, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xef, + 0x00, 0x2b, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xef, + 0x00, 0x2c}, 2, 8); + usleep(5000); + + for (l4_addr_t addr = get_framebuffer(); addr < get_framebuffer() + get_framebuffer_size(); addr += sizeof(uint32_t)) + *((uint32_t *) addr) = 0; + + l4_cache_clean_data(get_framebuffer(), get_framebuffer() + get_framebuffer_size()); + + // Initialise the display transfer. + // NOTE: Asserting the data signal. + + spi_channel->acquire_control(true); + + spi_x1600_channel->transfer(_fb_region.vaddr, _fb_region.paddr, + get_framebuffer_size(), 2, 16, + _desc_region.vaddr, _desc_region.paddr); + + //enable_display(); +} + +// Set up memory addresses for the peripheral, initialising the framebuffer and +// descriptor members. + +int +Lcd_x1600_spi_device::_setup_memory() +{ + // Test for existing setup. + + if (_fb_region.vaddr) + return 0; + + // Framebuffer and descriptor sizes. + + unsigned long fb_size = get_framebuffer_size(), desc_size = 32; + + // Allocate memory for the framebuffer and descriptors with 2**5 = 32 byte == + // 8 word alignment, sufficient for the descriptors. + + long err = get_dma_region(fb_size, 5, &_fb_region); + + if (err) + return 1; + + err = get_dma_region(desc_size, 5, &_desc_region); + + if (err) + return 1; + + return 0; +} + +l4_size_t Lcd_x1600_spi_device::get_framebuffer_size() +{ + // NOTE: Hard-coded size. + + return 240 * 240 * 2; +} + +// Populate a view information structure. + +void Lcd_x1600_spi_device::get_view_info(l4re_video_view_info_t *view_info) +{ + // NOTE: Hard-coded properties. + + view_info->width = 240; + view_info->height = 240; + view_info->pixel_info.bytes_per_pixel = 2; + view_info->bytes_per_line = 480; + + view_info->pixel_info.r.shift = 11; view_info->pixel_info.r.size = 5; + view_info->pixel_info.g.shift = 5; view_info->pixel_info.g.size = 6; + view_info->pixel_info.b.shift = 0; view_info->pixel_info.b.size = 5; + + view_info->pixel_info.a.shift = 0; + view_info->pixel_info.a.size = 0; +} + +// Access to peripheral memory. + +static int setup_memory() +{ + if (get_memory("x1600-cpm", &cpm_virt_base, &cpm_virt_base_end)) + return 1; + + if (get_memory("x1600-dma", &dma_virt_base, &dma_virt_base_end)) + return 1; + + if (get_irq("x1600-dma", &dma_irq_start, &dma_irq_end) < 0) + return 1; + + if (get_memory("x1600-gpio", &gpio_virt_base, &gpio_virt_base_end)) + return 1; + + if (get_memory_complete("x1600-ssi", &spi_virt_base, &spi_virt_base_end, + &spi_phys_base, &spi_phys_base_end)) + return 1; + + // Initialise the abstractions. + // NOTE: Using a preset GPIO configuration. + + cpm_chip = new Cpm_x1600_chip(cpm_virt_base); + + dma_chip = new Dma_x1600_chip(dma_virt_base, dma_virt_base_end, cpm_chip); + + dma_chip->enable(); + + gpio_chip_a = new Gpio_x1600_chip(gpio_virt_base, 0); + gpio_chip_b = new Gpio_x1600_chip(gpio_virt_base, 1); + gpio_chip_c = new Gpio_x1600_chip(gpio_virt_base, 2); + + // Initialise the clocks for the SPI peripheral before obtaining the + // peripheral abstraction. + + /* NOTE: Set a suitably high but arbitrary frequency to support the SPI bit + clock. */ + + cpm_chip->set_frequency(Clock_ssi0, 100000000); + + spi_chip = new Spi_x1600_chip(spi_phys_base, spi_virt_base, + spi_virt_base_end, cpm_chip); + + // Obtain a DMA channel and an SPI channel for updating the display. + // NOTE: Using preset channels, frequency and pin configuration. + + dma_channel = dma_chip->get_channel(12); + + spi_x1600_channel = spi_chip->get_channel(0, dma_channel, 25000000); + + spi_channel = new Spi_hybrid(spi_x1600_channel, gpio_chip_a, 29, -1); + + return 0; +} + +// Device initialisation. + +Lcd_x1600_spi_device *Lcd_x1600_spi_device::device = 0; + +Lcd_device *Lcd_device::get_device() +{ + if (Lcd_x1600_spi_device::device) + return Lcd_x1600_spi_device::device; + + if (setup_memory()) + return 0; + + // Initialise the common device. + + Lcd_x1600_spi_device::device = new Lcd_x1600_spi_device(NULL /* display_device */); + + return Lcd_x1600_spi_device::device; +}