Skip to content

Commit

Permalink
drivers: display: gc9x01: convert to MIPI DBI API
Browse files Browse the repository at this point in the history
Convert galaxycore GC9X01 to MIPI DBI API. In tree boards and tests
using this display have also had their devicetrees updated to use the
new MIPI DBI SPI emulated device.

(cherry picked from commit be23e70)

Original-Signed-off-by: Daniel DeGrasse <daniel.degrasse@nxp.com>
GitOrigin-RevId: be23e70
Change-Id: I2c6a1f6ef43c98c8fe162f4e58235b53bd2f9a15
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/zephyr/+/5635336
Commit-Queue: Dawid Niedźwiecki <dawidn@google.com>
Tested-by: ChromeOS Prod (Robot) <chromeos-ci-prod@chromeos-bot.iam.gserviceaccount.com>
Tested-by: Dawid Niedźwiecki <dawidn@google.com>
Reviewed-by: Dawid Niedźwiecki <dawidn@google.com>
  • Loading branch information
danieldegrasse authored and Chromeos LUCI committed Jun 17, 2024
1 parent bf0c429 commit efc03d4
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 147 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,26 @@
aliases {
rtc = &pcf8563_xiao_round_display;
};

xiao_round_display_mipi_dbi {
compatible = "zephyr,mipi-dbi-spi";
spi-dev = <&xiao_spi>;
dc-gpios = <&xiao_d 3 GPIO_ACTIVE_HIGH>;
write-only;
#address-cells = <1>;
#size-cells = <0>;

gc9a01_xiao_round_display: gc9a01@0 {
status = "okay";
compatible = "galaxycore,gc9x01x";
reg = <0>;
mipi-max-frequency = <DT_FREQ_M(100)>;
pixel-format = <PANEL_PIXEL_FORMAT_RGB_565>;
width = <240>;
height = <240>;
display-inversion;
};
};
};

&xiao_adc {
Expand Down Expand Up @@ -62,18 +82,6 @@
status = "okay";
cs-gpios = <&xiao_d 1 GPIO_ACTIVE_LOW>, <&xiao_d 2 GPIO_ACTIVE_LOW>;

gc9a01_xiao_round_display: gc9a01@0 {
status = "okay";
compatible = "galaxycore,gc9x01x";
reg = <0>;
spi-max-frequency = <DT_FREQ_M(100)>;
cmd-data-gpios = <&xiao_d 3 GPIO_ACTIVE_HIGH>;
pixel-format = <PANEL_PIXEL_FORMAT_RGB_565>;
width = <240>;
height = <240>;
display-inversion;
};

sdhc_xiao_round_display: sdhc@1 {
compatible = "zephyr,sdhc-spi-slot";
reg = <1>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,28 @@
pwms = <&ledc0 0 PWM_HZ(250) PWM_POLARITY_NORMAL>;
};
};

/* MIPI DBI */
mipi_dbi {
compatible = "zephyr,mipi-dbi-spi";
spi-dev = <&spi2>;
dc-gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio0 14 GPIO_ACTIVE_LOW>;
write-only;
#address-cells = <1>;
#size-cells = <0>;

gc9a01: gc9a01@0 {
status = "okay";
compatible = "galaxycore,gc9x01x";
reg = <0>;
mipi-max-frequency = <100000000>;
pixel-format = <PANEL_PIXEL_FORMAT_RGB_888>;
display-inversion;
width = <240>;
height = <240>;
};
};
};

&flash0 {
Expand Down Expand Up @@ -146,19 +168,6 @@
pinctrl-0 = <&spim2_default>;
pinctrl-names = "default";
cs-gpios = <&gpio0 9 GPIO_ACTIVE_LOW>;

gc9a01: gc9a01@0 {
status = "okay";
compatible = "galaxycore,gc9x01x";
reg = <0>;
spi-max-frequency = <100000000>;
cmd-data-gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio0 14 GPIO_ACTIVE_LOW>;
pixel-format = <PANEL_PIXEL_FORMAT_RGB_888>;
display-inversion;
width = <240>;
height = <240>;
};
};

&trng0 {
Expand Down
2 changes: 1 addition & 1 deletion drivers/display/Kconfig.gc9x01x
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ config GC9X01X
bool "GC9X01X display driver"
default y
depends on DT_HAS_GALAXYCORE_GC9X01X_ENABLED
select SPI
select MIPI_DBI
help
Enable driver for GC9X01X display driver.
129 changes: 37 additions & 92 deletions drivers/display/display_gc9x01x.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,14 @@

#include <zephyr/dt-bindings/display/panel.h>
#include <zephyr/drivers/display.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/drivers/mipi_dbi.h>
#include <zephyr/pm/device.h>
#include <zephyr/sys/util.h>
#include <zephyr/sys/byteorder.h>

#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(display_gc9x01x, CONFIG_DISPLAY_LOG_LEVEL);

/* Command/data GPIO level for commands. */
#define GC9X01X_GPIO_LEVEL_CMD 0U

/* Command/data GPIO level for data. */
#define GC9X01X_GPIO_LEVEL_DATA 1U

/* Maximum number of default init registers */
#define GC9X01X_NUM_DEFAULT_INIT_REGS 12U

Expand All @@ -37,9 +30,8 @@ struct gc9x01x_data {

/* Configuration data struct.*/
struct gc9x01x_config {
struct spi_dt_spec spi;
struct gpio_dt_spec cmd_data;
struct gpio_dt_spec reset;
const struct device *mipi_dev;
struct mipi_dbi_config dbi_config;
uint8_t pixel_format;
uint16_t orientation;
uint16_t x_resolution;
Expand Down Expand Up @@ -229,35 +221,9 @@ static int gc9x01x_transmit(const struct device *dev, uint8_t cmd, const void *t
size_t tx_len)
{
const struct gc9x01x_config *config = dev->config;
int ret;
struct spi_buf tx_buf = {.buf = &cmd, .len = 1U};
struct spi_buf_set tx_bufs = {.buffers = &tx_buf, .count = 1U};

ret = gpio_pin_set_dt(&config->cmd_data, GC9X01X_GPIO_LEVEL_CMD);
if (ret < 0) {
return ret;
}
ret = spi_write_dt(&config->spi, &tx_bufs);
if (ret < 0) {
return ret;
}

/* send data (if any) */
if (tx_data != NULL) {
tx_buf.buf = (void *)tx_data;
tx_buf.len = tx_len;

ret = gpio_pin_set_dt(&config->cmd_data, GC9X01X_GPIO_LEVEL_DATA);
if (ret < 0) {
return ret;
}
ret = spi_write_dt(&config->spi, &tx_bufs);
if (ret < 0) {
return ret;
}
}

return 0;
return mipi_dbi_command_write(config->mipi_dev, &config->dbi_config,
cmd, tx_data, tx_len);
}

static int gc9x01x_regs_init(const struct device *dev)
Expand All @@ -266,6 +232,10 @@ static int gc9x01x_regs_init(const struct device *dev)
const struct gc9x01x_regs *regs = config->regs;
int ret;

if (!device_is_ready(config->mipi_dev)) {
return -ENODEV;
}

/* Enable inter-command mode */
ret = gc9x01x_transmit(dev, GC9X01X_CMD_INREGEN1, NULL, 0);
if (ret < 0) {
Expand Down Expand Up @@ -371,17 +341,15 @@ static int gc9x01x_enter_sleep(const struct device *dev)
static int gc9x01x_hw_reset(const struct device *dev)
{
const struct gc9x01x_config *config = dev->config;
int ret;

if (config->reset.port == NULL) {
return -ENODEV;
ret = mipi_dbi_reset(config->mipi_dev, 100);
if (ret < 0) {
return ret;
}

gpio_pin_set_dt(&config->reset, 1U);
k_msleep(100);
gpio_pin_set_dt(&config->reset, 0U);
k_msleep(10);

return 0;
return ret;
}

static int gc9x01x_display_blanking_off(const struct device *dev)
Expand Down Expand Up @@ -492,38 +460,8 @@ static int gc9x01x_configure(const struct device *dev)

static int gc9x01x_init(const struct device *dev)
{
const struct gc9x01x_config *config = dev->config;
int ret;

if (!spi_is_ready_dt(&config->spi)) {
LOG_ERR("SPI device is not ready");
return -ENODEV;
}

if (!gpio_is_ready_dt(&config->cmd_data)) {
LOG_ERR("Command/Data GPIO device not ready");
return -ENODEV;
}

ret = gpio_pin_configure_dt(&config->cmd_data, GPIO_OUTPUT);
if (ret < 0) {
LOG_ERR("Could not configure command/data GPIO (%d)", ret);
return ret;
}

if (config->reset.port != NULL) {
if (!device_is_ready(config->reset.port)) {
LOG_ERR("Reset GPIO device not ready");
return -ENODEV;
}

ret = gpio_pin_configure_dt(&config->reset, GPIO_OUTPUT_INACTIVE);
if (ret < 0) {
LOG_ERR("Could not configure reset GPIO (%d)", ret);
return ret;
}
}

gc9x01x_hw_reset(dev);

gc9x01x_display_blanking_on(dev);
Expand Down Expand Up @@ -573,8 +511,7 @@ static int gc9x01x_write(const struct device *dev, const uint16_t x, const uint1
struct gc9x01x_data *data = dev->data;
int ret;
const uint8_t *write_data_start = (const uint8_t *)buf;
struct spi_buf tx_buf;
struct spi_buf_set tx_bufs;
struct display_buffer_descriptor mipi_desc;
uint16_t write_cnt;
uint16_t nbr_of_writes;
uint16_t write_h;
Expand All @@ -592,26 +529,30 @@ static int gc9x01x_write(const struct device *dev, const uint16_t x, const uint1
if (desc->pitch > desc->width) {
write_h = 1U;
nbr_of_writes = desc->height;
mipi_desc.height = 1;
mipi_desc.buf_size = desc->pitch * data->bytes_per_pixel;
} else {
write_h = desc->height;
mipi_desc.height = desc->height;
mipi_desc.buf_size = desc->width * data->bytes_per_pixel * write_h;
nbr_of_writes = 1U;
}

ret = gc9x01x_transmit(dev, GC9X01X_CMD_MEMWR, write_data_start,
desc->width * data->bytes_per_pixel * write_h);
mipi_desc.width = desc->width;
/* Per MIPI API, pitch must always match width */
mipi_desc.pitch = desc->width;

ret = gc9x01x_transmit(dev, GC9X01X_CMD_MEMWR, NULL, 0);
if (ret < 0) {
return ret;
}

tx_bufs.buffers = &tx_buf;
tx_bufs.count = 1U;

write_data_start += desc->pitch * data->bytes_per_pixel;
for (write_cnt = 1U; write_cnt < nbr_of_writes; ++write_cnt) {
tx_buf.buf = (void *)write_data_start;
tx_buf.len = desc->width * data->bytes_per_pixel * write_h;

ret = spi_write_dt(&config->spi, &tx_bufs);
for (write_cnt = 0U; write_cnt < nbr_of_writes; ++write_cnt) {
ret = mipi_dbi_write_display(config->mipi_dev,
&config->dbi_config,
write_data_start,
&mipi_desc,
data->pixel_format);
if (ret < 0) {
return ret;
}
Expand Down Expand Up @@ -679,9 +620,13 @@ static const struct display_driver_api gc9x01x_api = {
#define GC9X01X_INIT(inst) \
GC9X01X_REGS_INIT(inst); \
static const struct gc9x01x_config gc9x01x_config_##inst = { \
.spi = SPI_DT_SPEC_INST_GET(inst, SPI_OP_MODE_MASTER | SPI_WORD_SET(8), 0), \
.cmd_data = GPIO_DT_SPEC_INST_GET(inst, cmd_data_gpios), \
.reset = GPIO_DT_SPEC_INST_GET_OR(inst, reset_gpios, {0}), \
.mipi_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)), \
.dbi_config = { \
.mode = MIPI_DBI_MODE_SPI_4WIRE, \
.config = MIPI_DBI_SPI_CONFIG_DT_INST(inst, \
SPI_OP_MODE_MASTER | \
SPI_WORD_SET(8), 0), \
}, \
.pixel_format = DT_INST_PROP(inst, pixel_format), \
.orientation = DT_INST_ENUM_IDX(inst, orientation), \
.x_resolution = DT_INST_PROP(inst, width), \
Expand Down
16 changes: 1 addition & 15 deletions dts/bindings/display/galaxycore,gc9x01x.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,9 @@ description: |
compatible: "galaxycore,gc9x01x"

include: [spi-device.yaml, display-controller.yaml, lcd-controller.yaml]
include: [mipi-dbi-spi-device.yaml, display-controller.yaml, lcd-controller.yaml]

properties:
reset-gpios:
type: phandle-array
description: |
RESET pin of the GC9X01X.
If connected directly the MCU pin should be configured
as active low.
cmd-data-gpios:
type: phandle-array
required: true
description: |
Data/Command pin of the GC9X01X is to be configured
high(1) for data, low(0) for command.
orientation:
type: string
default: "normal"
Expand Down
29 changes: 15 additions & 14 deletions tests/drivers/build_all/display/app.overlay
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,16 @@
tcon = <0x22>;
};
};

test_spi_gc9x01x: gc9x01x@6 {
compatible = "galaxycore,gc9x01x";
reg = <6>;
mipi-max-frequency = <100000000>;
pixel-format = <16>;

width = <240>;
height = <240>;
};
};


Expand All @@ -136,21 +146,12 @@
status = "okay";
clock-frequency = <2000000>;

/* one entry for every devices at spi.dtsi */
/* one entry for every device. Note that this must
* include MIPI DBI devices as well.
*/
cs-gpios = <&test_gpio 0 0 &test_gpio 0 1 &test_gpio 0 2
&test_gpio 0 3 &test_gpio 0 4 &test_gpio 0 5>;

test_spi_gc9x01x: gc9x01x@1 {
compatible = "galaxycore,gc9x01x";
reg = <1>;
spi-max-frequency = <100000000>;
cmd-data-gpios = <&test_gpio 1 0>;
reset-gpios = <&test_gpio 2 0>;
pixel-format = <16>;

width = <240>;
height = <240>;
};
&test_gpio 0 3 &test_gpio 0 4 &test_gpio 0 5
&test_gpio 0 6>;

test_led_strip_0: lpd8806@2 {
compatible = "greeled,lpd8806";
Expand Down

0 comments on commit efc03d4

Please sign in to comment.