Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion boards/nxp/frdm_mcxn947/frdm_mcxn947.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ nxp_8080_touch_panel_i2c: &flexcomm2_lpi2c2 {
pinctrl-names = "default";
};

nxp_flexio_lcd: &flexio0_lcd {
zephyr_mipi_dbi_parallel: &flexio0_lcd {
/* DMA channels 0, muxed to FlexIO TX */
dmas = <&edma0 0 61>;
dma-names = "tx";
Expand Down
53 changes: 53 additions & 0 deletions boards/nxp/rd_rw612_bga/doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,59 @@ The default configuration can be found in the defconfig file:

Other hardware features are not currently supported


Display Support
***************

The rd_rw612_bga board supports several in-tree display modules. Setup for
each module is described below:

GoWorld 16880 LCM
=================

This module does not connect directly to the board, and must be connected
via an adapter board and jumper wires. Connections are described in
:zephyr_file:`boards/nxp/rd_rw612_bga/dts/goworld_16880_lcm.overlay`. The
display sample can be built for this board like so:

.. zephyr-app-commands::
:board: rd_rw612_bga
:gen-args: -DDTC_OVERLAY_FILE=goworld_16880_lcm.overlay
:zephyr-app: samples/drivers/display
:goals: build
:compact:

Adafruit 2.8 TFT
================

The :ref:`adafruit_2_8_tft_touch_v2` connects to the board's Arduino headers
directly, but some modifications are required (see
:zephyr_file:`boards/shields/adafruit_2_8_tft_touch_v2/boards/rd_rw612_bga.overlay`
for a list). The display sample can be built for this module like so:

.. zephyr-app-commands::
:board: rd_rw612_bga
:shield: adafruit_2_8_tft_touch_v2
:zephyr-app: samples/drivers/display
:goals: build
:compact:

NXP LCD_PAR_S035
================

The :ref:`lcd_par_s035` does not connect directly to the board, and must be
connected via jumper wires. Connections and required board changes are
described in
:zephyr_file:`boards/shields/lcd_par_s035/boards/rd_rw612_bga.overlay`. The
display sample can be built for the module like so:

.. zephyr-app-commands::
:board: rd_rw612_bga
:shield: lcd_par_s035_8080
:zephyr-app: samples/drivers/display
:goals: build
:compact:

Fetch Binary Blobs
******************

Expand Down
28 changes: 27 additions & 1 deletion boards/nxp/rd_rw612_bga/rd_rw612_bga.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,22 @@
<20 0 &hsgpio0 16 0>, /* D14 */
<21 0 &hsgpio0 17 0>; /* D15 */
};


/*
* The pins for this interface are chosen arbitrarily- the RD-RW612
* board does not have the NXP 8080 interface, but can support displays
* using it by connecting signals directly with jumper wires.
*/
nxp_lcd_8080_connector: lcd-8080-connector {
compatible = "nxp,lcd-8080";
#gpio-cells = <2>;
gpio-map-mask = <0xffffffff 0xffffffc0>;
gpio-map-pass-thru = <0 0x3f>;
gpio-map = <9 0 &hsgpio0 3 0>, /* Pin 9, LCD touch INT */
<10 0 &hsgpio0 2 0>, /* Pin 10, LCD backlight control */
<11 0 &hsgpio0 4 0>; /* Pin 11, LCD and touch reset */
};
};

&wwdt {
Expand Down Expand Up @@ -241,12 +257,22 @@ zephyr_udc0: &usb_otg {
status = "okay";
};

&lcdic {
zephyr_mipi_dbi_parallel: &lcdic {
status = "okay";
pinctrl-0 = <&pinmux_lcdic>;
pinctrl-names = "default";
};

/*
* Similar to the flexio connection, these pins are not
* broken out in the format required to connect directly to
* an NXP 8080 display, but they can be connected with jumper
* wires.
*/
nxp_8080_touch_panel_i2c: &arduino_i2c {
status = "okay";
};

&mrt0_channel0 {
status = "okay";
};
Expand Down
9 changes: 9 additions & 0 deletions boards/shields/lcd_par_s035/Kconfig.defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,13 @@ config INPUT_GT911_INTERRUPT

endif # LVGL

if INPUT

# GT911 driver drives reset pin low, so it needs to initialize before
# the display driver but after the MIPI DBI driver
config INPUT_INIT_PRIORITY
default 82

endif # INPUT

endif # SHIELD_LCD_PAR_S035
95 changes: 95 additions & 0 deletions boards/shields/lcd_par_s035/boards/rd_rw612_bga.overlay
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright 2024 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/dt-bindings/mipi_dbi/mipi_dbi.h>

/*
* To use this board with this display, perform the following modifications:
* - Depopulate resistors R78, R604, R598, R15, R245, R243, R11, R20, R237,
* R235, R431, R447, R420, R459, R485, and R486
* - Populate resistors R286, R19, R246, R242, R123, R239, R124, R125, R236,
* R233, and R12
* - Remove jumper JP30
* - Set jumper JP40 to postion 1-2, JP38 to 1-2, and JP16 to position 2-3
*/

/*
* To connect the display configure SW1 on the display to
* ON-ON-OFF (8 bit 8080 mode), and connect the following pins
* | Board Pin | Display Pin | Function |
* |-----------|-------------|----------|
* | HD2.8 | D0 | D[0] |
* | HD2.16 | D1 | D[1] |
* | J5.2 | TE | TE |
* | J5.4 | D2 | D[2] |
* | J5.1 | D3 | D[3] |
* | J5.6 | RD | RDX |
* | J5.3 | D4 | D[4] |
* | HD2.7 | D5 | D[5] |
* | HD2.6 | D6 | D[6] |
* | HD2.1 | D7 | D[7] |
* | HD2.2 | WR | WR |
* | HD8.1 | CS | CS |
* | HD8.2 | D/C | DC |
* | J13.8 | GND | GND |
* | J13.7 | VDD | 3V3 |
* | J5.10 | SCL | IC2_SCL |
* | J5.9 | SDA | IC2_SDA |
* | HD2.4 | INT | INT |
* | HD2.5 | RST | RESET |
*/

/* Expand the LCDIC pinmux to cover all 8080 mode pins */
&pinmux_lcdic {
group0 {
pinmux = <IO_MUX_LCD_8080_IO42>,
<IO_MUX_LCD_8080_IO43>,
<IO_MUX_LCD_8080_IO44>,
<IO_MUX_LCD_8080_IO45>,
<IO_MUX_LCD_8080_IO46>,
<IO_MUX_LCD_8080_IO47>,
<IO_MUX_LCD_8080_IO48>,
<IO_MUX_LCD_8080_IO49>,
<IO_MUX_LCD_8080_IO51>,
<IO_MUX_LCD_8080_IO52>,
<IO_MUX_LCD_8080_IO53>,
<IO_MUX_LCD_8080_IO54>,
<IO_MUX_LCD_8080_IO56>,
<IO_MUX_LCD_8080_IO57>;
slew-rate = "ultra";
};
};

&st7796s {
mipi-mode = <MIPI_DBI_MODE_8080_BUS_8_BIT>;
/*
* Display supports minimum write cycle time of 66ns. This
* means we can clock the LCDIC module at 30MHz, as
* the minimum write duration will be 2x the module
* clock. Note that this frequency is too fast for reading
* from the display module
*/
mipi-max-frequency = <30000000>;
/*
* Note that this display is *not* buggy- we use rgb-is-inverted
* as a workaround here to get the display to report an inverted
* color format. This is because the "nxp,swap-bytes" setting
* on the LCDIC will apply byte swapping in hardware, so the
* display should report an inverted color format to account
* for this. This results in better performance for applications
* like LVGL, which would otherwise have to swap RGB565 data in
* software
*/
rgb-is-inverted;
};

&lcdic {
/* Enable byte swapping */
nxp,swap-bytes;
/* Set pulse width for write active and write inactive to min value */
nxp,write-active-cycles = <1>;
nxp,write-inactive-cycles = <1>;
};
4 changes: 2 additions & 2 deletions boards/shields/lcd_par_s035/lcd_par_s035_8080.overlay
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@
gt911_lcd_par_s035: gt911-lcd_par_s035@5d {
compatible = "goodix,gt911";
reg = <0x5d>;
alt-addr = <0x14>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this deleted? might want to mention in commit message

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a blurb in the commit message. For anyone interested, the best I can tell this was working because the FRDM-MCXN947 board (previously the only in tree board using this display) was configuring the INT pin for the display in the MIPI-DBI pincontrol node. The pin control setting was such that when the RESET pin for the display (and touch screen) controller is toggled low, the touch screen controller will select the 0x14 alternate I2C address. This workaround wasn't working on the RW612 board, so I opted to properly set initialization order, thereby making sure the GT911 driver is able to pull the reset pin low and set the INT pin properly as needed to get the GT911 IC to select the standard 0x5D I2C address.

irq-gpios = <&nxp_lcd_8080_connector 9 GPIO_ACTIVE_HIGH>;
reset-gpios = <&nxp_lcd_8080_connector 11 GPIO_ACTIVE_LOW>;
};
};

&nxp_flexio_lcd {
&zephyr_mipi_dbi_parallel {
status = "okay";
#address-cells = <1>;
#size-cells = <0>;
Expand Down
11 changes: 9 additions & 2 deletions drivers/display/display_st7796s.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,13 @@ static int st7796s_get_pixelfmt(const struct device *dev)
* and vice versa.
*/
if (config->dbi_config.mode == MIPI_DBI_MODE_8080_BUS_8_BIT) {
if (config->madctl & ST7796S_MADCTL_BGR) {
/*
* Similar to the handling for other interface modes,
* invert the reported pixel format if "rgb_is_inverted"
* is enabled
*/
if (((bool)(config->madctl & ST7796S_MADCTL_BGR)) !=
config->rgb_is_inverted) {
return PIXEL_FORMAT_RGB_565;
} else {
return PIXEL_FORMAT_BGR_565;
Expand All @@ -133,7 +139,8 @@ static int st7796s_get_pixelfmt(const struct device *dev)
* if rgb_is_inverted is enabled.
* It is a workaround for supporting buggy modules that display RGB as BGR.
*/
if (!(config->madctl & ST7796S_MADCTL_BGR) != !config->rgb_is_inverted) {
if (((bool)(config->madctl & ST7796S_MADCTL_BGR)) !=
config->rgb_is_inverted) {
return PIXEL_FORMAT_BGR_565;
} else {
return PIXEL_FORMAT_RGB_565;
Expand Down
42 changes: 33 additions & 9 deletions drivers/mipi_dbi/mipi_dbi_nxp_lcdic.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ struct mipi_dbi_lcdic_config {
const struct device *clock_dev;
clock_control_subsys_t clock_subsys;
bool swap_bytes;
uint8_t write_active_min;
uint8_t write_inactive_min;
};

#ifdef CONFIG_MIPI_DBI_NXP_LCDIC_DMA
Expand Down Expand Up @@ -249,10 +251,6 @@ static int mipi_dbi_lcdic_configure(const struct device *dev,
LOG_ERR("Invalid clock frequency %d", spi_cfg->frequency);
return ret;
}
if (!(spi_cfg->operation & SPI_HALF_DUPLEX)) {
LOG_ERR("LCDIC only supports half duplex operation");
return -ENOTSUP;
}
if (spi_cfg->slave != 0) {
/* Only one slave select line */
return -ENOTSUP;
Expand All @@ -265,13 +263,26 @@ static int mipi_dbi_lcdic_configure(const struct device *dev,
reg = base->CTRL;
/* Disable LCD module during configuration */
reg &= ~LCDIC_CTRL_LCDIC_EN_MASK;
/* Select SPI mode */
reg &= ~LCDIC_CTRL_LCDIC_MD_MASK;
/* Select 3 or 4 wire mode based on config selection */
if (dbi_config->mode == MIPI_DBI_MODE_SPI_4WIRE) {
if (dbi_config->mode == MIPI_DBI_MODE_8080_BUS_8_BIT) {
/* Enable 8080 Mode */
reg |= LCDIC_CTRL_LCDIC_MD_MASK;
} else if (dbi_config->mode == MIPI_DBI_MODE_SPI_4WIRE) {
/* Select SPI 4 wire mode */
reg |= LCDIC_CTRL_SPI_MD_MASK;
reg &= ~LCDIC_CTRL_LCDIC_MD_MASK;
} else if (dbi_config->mode == MIPI_DBI_MODE_SPI_3WIRE) {
/* Select SPI 3 wire mode */
reg &= ~(LCDIC_CTRL_LCDIC_MD_MASK |
LCDIC_CTRL_SPI_MD_MASK);
} else {
reg &= ~LCDIC_CTRL_SPI_MD_MASK;
/* Unsupported mode */
return -ENOTSUP;
}
/* If using SPI mode, validate that half-duplex was requested */
if ((!(reg & LCDIC_CTRL_LCDIC_MD_MASK)) &&
(!(spi_cfg->operation & SPI_HALF_DUPLEX))) {
LOG_ERR("LCDIC only supports half duplex operation");
return -ENOTSUP;
}
/* Enable byte swapping if user requested it */
reg = (reg & ~LCDIC_CTRL_DAT_ENDIAN_MASK) |
Expand All @@ -292,6 +303,15 @@ static int mipi_dbi_lcdic_configure(const struct device *dev,
LCDIC_SPI_CTRL_CPOL((spi_cfg->operation & SPI_MODE_CPOL) ? 1 : 0);
base->SPI_CTRL = reg;

/*
* Set 8080 control based on module properties. TRIW and TRAW are
* set to their reset values
*/
base->I8080_CTRL1 = LCDIC_I8080_CTRL1_TRIW(0xf) |
LCDIC_I8080_CTRL1_TRAW(0xf) |
LCDIC_I8080_CTRL1_TWIW(config->write_inactive_min) |
LCDIC_I8080_CTRL1_TWAW(config->write_active_min);

/* Enable the module */
base->CTRL |= LCDIC_CTRL_LCDIC_EN_MASK;
mipi_dbi_lcdic_reset_delay();
Expand Down Expand Up @@ -783,6 +803,10 @@ static void mipi_dbi_lcdic_isr(const struct device *dev)
DT_INST_CLOCKS_CELL(n, name), \
.irq_config_func = mipi_dbi_lcdic_config_func_##n, \
.swap_bytes = DT_INST_PROP(n, nxp_swap_bytes), \
.write_active_min = \
DT_INST_PROP(n, nxp_write_active_cycles), \
.write_inactive_min = \
DT_INST_PROP(n, nxp_write_inactive_cycles), \
}; \
static struct mipi_dbi_lcdic_data mipi_dbi_lcdic_data_##n = { \
LCDIC_DMA_CHANNELS(n) \
Expand Down
25 changes: 24 additions & 1 deletion dts/bindings/mipi-dbi/nxp,lcdic.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

description: |
NXP LCDIC Controller. This controller implements 8080 and SPI mode MIPI-DBI
compliant transfers. Only SPI mode is currently supported.
compliant transfers.
compatible: "nxp,lcdic"

include: ["mipi-dbi-controller.yaml", "pinctrl-device.yaml"]
Expand All @@ -23,3 +23,26 @@ properties:
description: |
Swap bytes while transferring on LCDIC. When set, the LCDIC will send
the most significant byte first when using multibyte pixel formats.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to remove "Only SPI mode is currently supported."(L:6)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we should. I'll update this PR, thanks for catching that

reset-gpios:
type: phandle-array
description: |
Reset GPIO pin. The controller will set this pin to logic high to reset
the display. If not provided, the LCDIC module's reset pin will be used
to reset attached displays.

nxp,write-inactive-cycles:
type: int
default: 6
description: |
Set minimum count of write inactive cycles, as a multiple of the module
clock frequency. This controls the length of the inactive period of the
WRX signal. Default is IP reset value. Only valid in 8080 mode.

nxp,write-active-cycles:
type: int
default: 6
description: |
Set minimum count of write active cycles, as a multiple of the module
clock frequency. This controls the length of the active period of the
WRX signal. Default is IP reset value. Only valid in 8080 mode.