Sitronix ST7789V improvements
Subsystems (4)
v3 cover Sitronix ST7789V improvements
Hi,
This adds panel support for Inanbo T28CP45TN89, which I found inside of a handheld thermal camera. The panel is based on the st7789v controller. All information is based on reverse engineering. I also appended the series from Miquel Raynal adding EDT ET028013DMA panel support, so that I could easily test it with my SPI_NO_RX setup. They are slightly different due to rebasing.
Changes since PATCHv2:
* https://lore.kernel.org/all/[email protected]/
* https://lore.kernel.org/all/[email protected]/
* Add Rob Herring's R-b for the DT binding
* Make panel info "static const"
* Add Michael Riesch's R-b to all my patches
* Rebase to 6.5-rc1
* Append Miquel's series
Changes since PATCHv1:
* https://lore.kernel.org/all/[email protected]/
* Apply DT binding changes requested by Krzysztof Kozlowski and his Ack
* I changed the driver patches to avoid code duplication and splitted the code a bit more
Greetings,
-- Sebastian
Miquel Raynal (6):
dt-bindings: display: st7789v: Add the edt,et028013dma panel
compatible
dt-bindings: display: st7789v: bound the number of Rx data lines drm/panel: sitronix-st7789v: Use 9 bits per spi word by default drm/panel: sitronix-st7789v: Clarify a definition drm/panel: sitronix-st7789v: Add EDT ET028013DMA panel support drm/panel: sitronix-st7789v: Check display ID
Sebastian Reichel (13):
dt-bindings: vendor-prefixes: add Inanbo
dt-bindings: display: st7789v: add Inanbo T28CP45TN89 drm/panel: sitronix-st7789v: add SPI ID table drm/panel: sitronix-st7789v: remove unused constants drm/panel: sitronix-st7789v: make reset GPIO optional drm/panel: sitronix-st7789v: simplify st7789v_spi_write drm/panel: sitronix-st7789v: improve error handling drm/panel: sitronix-st7789v: avoid hardcoding mode info drm/panel: sitronix-st7789v: avoid hardcoding panel size drm/panel: sitronix-st7789v: add media bus format drm/panel: sitronix-st7789v: avoid hardcoding invert mode drm/panel: sitronix-st7789v: avoid hardcoding polarity info drm/panel: sitronix-st7789v: add Inanbo T28CP45TN89 support
.../display/panel/sitronix,st7789v.yaml | 10 +- .../devicetree/bindings/vendor-prefixes.yaml | 2 + .../gpu/drm/panel/panel-sitronix-st7789v.c | 262 +++++++++++++++--- 3 files changed, 237 insertions(+), 37 deletions(-)
Signature · 1 line
2.40.1
PATCH v3 1/19 dt-bindings: vendor-prefixes: add Inanbo
Shenzhen INANBO Electronic Technology Co., Ltd. manufacturers TFT/OLED LCD panels.
--- Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+)
Documentation/devicetree/bindings/vendor-prefixes.yaml +2 -0
@@ -617,6 +617,8 @@ patternProperties: description: Imagination Technologies Ltd. "^imi,.*": description: Integrated Micro-Electronics Inc. + "^inanbo,.*": + description: Shenzhen INANBO Electronic Technology Co., Ltd. "^incircuit,.*": description: In-Circuit GmbH "^indiedroid,.*":
Signature · 1 line
2.40.1
PATCH v3 2/19 dt-bindings: display: st7789v: add Inanbo T28CP45TN89
In reply to Sebastian ReichelAdd compatible value for Inanbo t28cp45tn89 and make reset GPIO non mandatory, since it might not be connected to the CPU.
--- .../devicetree/bindings/display/panel/sitronix,st7789v.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
Documentation/devicetree/bindings/display/panel/sitronix,st7789v.yaml +3 -2
@@ -15,7 +15,9 @@ allOf: properties: compatible: - const: sitronix,st7789v + enum: + - inanbo,t28cp45tn89-v17 + - sitronix,st7789v reg: true reset-gpios: true
@@ -33,7 +35,6 @@ properties: required: - compatible - reg - - reset-gpios - power-supply unevaluatedProperties: false
Signature · 1 line
2.40.1
PATCH v3 3/19 drm/panel: sitronix-st7789v: add SPI ID table
In reply to Sebastian ReichelSPI device drivers should also have a SPI ID table.
--- drivers/gpu/drm/panel/panel-sitronix-st7789v.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/gpu/drm/panel/panel-sitronix-st7789v.c +7 -0
@@ -394,6 +394,12 @@ static void st7789v_remove(struct spi_device *spi)drm_panel_remove (&ctx->panel); } +static const struct spi_device_id st7789v_spi_id[] = { + {"st7789v" }, + { } +}; +MODULE_DEVICE_TABLE (spi, st7789v_spi_id); +static const struct of_device_id st7789v_of_match[] = { { .compatible ="sitronix,st7789v" }, { }
@@ -403,6 +409,7 @@ MODULE_DEVICE_TABLE(of, st7789v_of_match);static struct spi_driver st7789v_driver = { .probe = st7789v_probe, .remove = st7789v_remove, + .id_table = st7789v_spi_id, .driver = { .name ="st7789v" , .of_match_table = st7789v_of_match,
Signature · 1 line
2.40.1
PATCH v3 4/19 drm/panel: sitronix-st7789v: remove unused constants
In reply to Sebastian ReichelST7789V_COLMOD_RGB_FMT_18BITS and ST7789V_COLMOD_CTRL_FMT_18BITS are unused in favour of MIPI_DCS_PIXEL_FMT_18BIT, remove them.
--- drivers/gpu/drm/panel/panel-sitronix-st7789v.c | 3 --- 1 file changed, 3 deletions(-)
drivers/gpu/drm/panel/panel-sitronix-st7789v.c +0 -3
@@ -15,9 +15,6 @@#include <drm/drm_modes.h> #include <drm/drm_panel.h> -#define ST7789V_COLMOD_RGB_FMT_18BITS (6 << 4) -#define ST7789V_COLMOD_CTRL_FMT_18BITS (6 << 0) -#define ST7789V_RAMCTRL_CMD 0xb0#define ST7789V_RAMCTRL_RM_RGB BIT(4)#define ST7789V_RAMCTRL_DM_RGB BIT(0)
Signature · 1 line
2.40.1
PATCH v3 5/19 drm/panel: sitronix-st7789v: make reset GPIO optional
In reply to Sebastian ReichelThe reset pin might not be software controllable from the SoC, so make it optional.
--- drivers/gpu/drm/panel/panel-sitronix-st7789v.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/panel/panel-sitronix-st7789v.c +1 -1
@@ -369,7 +369,7 @@ static int st7789v_probe(struct spi_device *spi)if (IS_ERR (ctx->power))return PTR_ERR (ctx->power); - ctx->reset =devm_gpiod_get (&spi->dev,"reset" ,GPIOD_OUT_LOW ); + ctx->reset =devm_gpiod_get_optional (&spi->dev,"reset" ,GPIOD_OUT_LOW );if (IS_ERR (ctx->reset)) {dev_err (&spi->dev,"Couldn't get our reset line\n" );return PTR_ERR (ctx->reset);
Signature · 1 line
2.40.1
PATCH v3 6/19 drm/panel: sitronix-st7789v: simplify st7789v_spi_write
In reply to Sebastian Reichelst7789v_spi_write initializes a message with just
a single transfer, spi_sync_transfer can be used
for that.
--- drivers/gpu/drm/panel/panel-sitronix-st7789v.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-)
drivers/gpu/drm/panel/panel-sitronix-st7789v.c +1 -5
@@ -129,17 +129,13 @@ static int st7789v_spi_write(struct st7789v *ctx, enum st7789v_prefix prefix, u8 data) {struct spi_transfer xfer = { }; -struct spi_message msg;u16 txbuf = ((prefix &1 ) <<8 ) | data; -spi_message_init (&msg); - xfer.tx_buf = &txbuf; xfer.bits_per_word =9 ; xfer.len =sizeof (txbuf); -spi_message_add_tail (&xfer, &msg); -return spi_sync (ctx->spi, &msg); +return spi_sync_transfer (ctx->spi, &xfer,1 ); }static int st7789v_write_command (struct st7789v *ctx,u8 cmd)
Signature · 1 line
2.40.1
PATCH v3 7/19 drm/panel: sitronix-st7789v: improve error handling
In reply to Sebastian ReichelImprove error handling in the probe routine, so that probe defer errors are captured in /sys/kernel/debug/devices_deferred
--- .../gpu/drm/panel/panel-sitronix-st7789v.c | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-)
drivers/gpu/drm/panel/panel-sitronix-st7789v.c +12 -11
@@ -348,32 +348,33 @@ static const struct drm_panel_funcs st7789v_drm_funcs = {static int st7789v_probe (struct spi_device *spi) { +struct device *dev = &spi->dev;struct st7789v *ctx;int ret; - ctx =devm_kzalloc (&spi->dev,sizeof (*ctx),GFP_KERNEL ); + ctx =devm_kzalloc (dev,sizeof (*ctx),GFP_KERNEL );if (!ctx)return -ENOMEM ;spi_set_drvdata (spi, ctx); ctx->spi = spi; -drm_panel_init (&ctx->panel, &spi->dev, &st7789v_drm_funcs, +drm_panel_init (&ctx->panel, dev, &st7789v_drm_funcs,DRM_MODE_CONNECTOR_DPI ); - ctx->power =devm_regulator_get (&spi->dev,"power" ); -if (IS_ERR (ctx->power)) -return PTR_ERR (ctx->power); + ctx->power =devm_regulator_get (dev,"power" ); + ret =PTR_ERR_OR_ZERO (ctx->power); +if (ret) +return dev_err_probe (dev, ret,"Failed to get regulator\n" ); - ctx->reset =devm_gpiod_get_optional (&spi->dev,"reset" ,GPIOD_OUT_LOW ); -if (IS_ERR (ctx->reset)) { -dev_err (&spi->dev,"Couldn't get our reset line\n" ); -return PTR_ERR (ctx->reset); - } + ctx->reset =devm_gpiod_get_optional (dev,"reset" ,GPIOD_OUT_LOW ); + ret =PTR_ERR_OR_ZERO (ctx->reset); +if (ret) +return dev_err_probe (dev, ret,"Failed to get reset line\n" ); ret =drm_panel_of_backlight (&ctx->panel);if (ret) -return ret; +return dev_err_probe (dev, ret,"Failed to get backlight\n" );drm_panel_add (&ctx->panel);
Signature · 1 line
2.40.1
PATCH v3 8/19 drm/panel: sitronix-st7789v: avoid hardcoding mode info
In reply to Sebastian ReichelAvoid hard-coding the default_mode and supply it from match data. One additional layer of abstraction has been introduced, which will be needed for specifying other panel information (e.g. bus flags) in the next steps.
--- .../gpu/drm/panel/panel-sitronix-st7789v.c | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-)
drivers/gpu/drm/panel/panel-sitronix-st7789v.c +18 -6
@@ -108,8 +108,13 @@return val; \ }while (0 ) +struct st7789_panel_info { +const struct drm_display_mode *mode; +}; +struct st7789v {struct drm_panel panel; +const struct st7789_panel_info *info;struct spi_device *spi;struct gpio_desc *reset;struct regulator *power;
@@ -160,16 +165,21 @@ static const struct drm_display_mode default_mode = { .vtotal = 320 + 8 + 4 + 4, }; +static const struct st7789_panel_info default_panel = { + .mode = &default_mode, +}; +static int st7789v_get_modes (struct drm_panel *panel,struct drm_connector *connector) { +struct st7789v *ctx =panel_to_st7789v (panel);struct drm_display_mode *mode; - mode =drm_mode_duplicate (connector->dev, &default_mode); + mode =drm_mode_duplicate (connector->dev, ctx->info->mode);if (!mode) { -dev_err (panel->dev,"failed to add mode %ux%ux@%u\n" , - default_mode.hdisplay, default_mode.vdisplay, -drm_mode_vrefresh (&default_mode)); +dev_err (panel->dev,"failed to add mode %ux%u@%u\n" , + ctx->info->mode->hdisplay, ctx->info->mode->vdisplay, +drm_mode_vrefresh (ctx->info->mode));return -ENOMEM ; }
@@ -359,6 +369,8 @@ static int st7789v_probe(struct spi_device *spi)spi_set_drvdata (spi, ctx); ctx->spi = spi; + ctx->info =device_get_match_data (&spi->dev); +drm_panel_init (&ctx->panel, dev, &st7789v_drm_funcs,DRM_MODE_CONNECTOR_DPI );
@@ -389,13 +401,13 @@ static void st7789v_remove(struct spi_device *spi) }static const struct spi_device_id st7789v_spi_id[] = { - {"st7789v" }, + {"st7789v" , (unsigned long ) &default_panel }, { } };MODULE_DEVICE_TABLE (spi, st7789v_spi_id);static const struct of_device_id st7789v_of_match[] = { - { .compatible ="sitronix,st7789v" }, + { .compatible ="sitronix,st7789v" , .data = &default_panel }, { } };MODULE_DEVICE_TABLE (of, st7789v_of_match);
Signature · 1 line
2.40.1
PATCH v3 9/19 drm/panel: sitronix-st7789v: avoid hardcoding panel size
In reply to Sebastian ReichelMove the panel size information to the mode struct, so that different panel sizes can be specified depending on the panel type.
--- drivers/gpu/drm/panel/panel-sitronix-st7789v.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/gpu/drm/panel/panel-sitronix-st7789v.c +4 -2
@@ -163,6 +163,8 @@ static const struct drm_display_mode default_mode = { .vsync_start = 320 + 8, .vsync_end = 320 + 8 + 4, .vtotal = 320 + 8 + 4 + 4, + .width_mm = 61, + .height_mm = 103, };static const struct st7789_panel_info default_panel = {
@@ -188,8 +190,8 @@ static int st7789v_get_modes(struct drm_panel *panel, mode->type =DRM_MODE_TYPE_DRIVER |DRM_MODE_TYPE_PREFERRED ;drm_mode_probed_add (connector, mode); - connector->display_info.width_mm =61 ; - connector->display_info.height_mm =103 ; + connector->display_info.width_mm = ctx->info->mode->width_mm; + connector->display_info.height_mm = ctx->info->mode->height_mm;return 1 ; }
Signature · 1 line
2.40.1
PATCH v3 10/19 drm/panel: sitronix-st7789v: add media bus format
In reply to Sebastian ReichelAdd support for describing the media bus format in the panel configuration and expose that to userspace. Since both supported formats (RGB565 and RGB666) are using 6 bits per color also hardcode that information.
--- .../gpu/drm/panel/panel-sitronix-st7789v.c | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-)
drivers/gpu/drm/panel/panel-sitronix-st7789v.c +23 -3
@@ -10,6 +10,7 @@#include <linux/spi/spi.h> #include <video/mipi_display.h> +#include <linux/media-bus-format.h> #include <drm/drm_device.h> #include <drm/drm_modes.h>
@@ -110,6 +111,7 @@struct st7789_panel_info {const struct drm_display_mode *mode; +u32 bus_format; };struct st7789v {
@@ -169,6 +171,7 @@ static const struct drm_display_mode default_mode = {static const struct st7789_panel_info default_panel = { .mode = &default_mode, + .bus_format =MEDIA_BUS_FMT_RGB666_1X18 , }; static int st7789v_get_modes(struct drm_panel *panel,
@@ -190,8 +193,11 @@ static int st7789v_get_modes(struct drm_panel *panel, mode->type =DRM_MODE_TYPE_DRIVER |DRM_MODE_TYPE_PREFERRED ;drm_mode_probed_add (connector, mode); + connector->display_info.bpc =6 ; connector->display_info.width_mm = ctx->info->mode->width_mm; connector->display_info.height_mm = ctx->info->mode->height_mm; +drm_display_info_set_bus_formats (&connector->display_info, + &ctx->info->bus_format,1 );return 1 ; }
@@ -199,8 +205,24 @@ static int st7789v_get_modes(struct drm_panel *panel,static int st7789v_prepare (struct drm_panel *panel) {struct st7789v *ctx =panel_to_st7789v (panel); +u8 pixel_fmt;int ret; +switch (ctx->info->bus_format) { +case MEDIA_BUS_FMT_RGB666_1X18 : + pixel_fmt =MIPI_DCS_PIXEL_FMT_18BIT ; +break ; +case MEDIA_BUS_FMT_RGB565_1X16 : + pixel_fmt =MIPI_DCS_PIXEL_FMT_16BIT ; +break ; +default : +dev_err (panel->dev,"unsupported bus format: %d\n" , + ctx->info->bus_format); +return -EINVAL ; + } + + pixel_fmt = (pixel_fmt <<4 ) | pixel_fmt; + ret =regulator_enable (ctx->power);if (ret)return ret;
@@ -221,9 +243,7 @@ static int st7789v_prepare(struct drm_panel *panel)ST7789V_TEST (ret,st7789v_write_command (ctx,MIPI_DCS_SET_PIXEL_FORMAT )); -ST7789V_TEST (ret,st7789v_write_data (ctx, - (MIPI_DCS_PIXEL_FMT_18BIT <<4 ) | - (MIPI_DCS_PIXEL_FMT_18BIT ))); +ST7789V_TEST (ret,st7789v_write_data (ctx, pixel_fmt));ST7789V_TEST (ret,st7789v_write_command (ctx,ST7789V_PORCTRL_CMD ));ST7789V_TEST (ret,st7789v_write_data (ctx,0xc ));
Signature · 1 line
2.40.1
PATCH v3 11/19 drm/panel: sitronix-st7789v: avoid hardcoding invert mode
In reply to Sebastian ReichelWhile the default panel uses invert mode, some panels require non-invert mode instead.
--- drivers/gpu/drm/panel/panel-sitronix-st7789v.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
drivers/gpu/drm/panel/panel-sitronix-st7789v.c +9 -1
@@ -112,6 +112,7 @@struct st7789_panel_info {const struct drm_display_mode *mode;u32 bus_format; +bool invert_mode; };struct st7789v {
@@ -171,6 +172,7 @@ static const struct drm_display_mode default_mode = {static const struct st7789_panel_info default_panel = { .mode = &default_mode, + .invert_mode = true, .bus_format =MEDIA_BUS_FMT_RGB666_1X18 , };
@@ -321,7 +323,13 @@ static int st7789v_prepare(struct drm_panel *panel)ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_NVGAMCTRL_VN61 (0x1b )));ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_NVGAMCTRL_VN62 (0x28 ))); -ST7789V_TEST (ret,st7789v_write_command (ctx,MIPI_DCS_ENTER_INVERT_MODE )); +if (ctx->info->invert_mode) { +ST7789V_TEST (ret,st7789v_write_command (ctx, +MIPI_DCS_ENTER_INVERT_MODE )); + }else { +ST7789V_TEST (ret,st7789v_write_command (ctx, +MIPI_DCS_EXIT_INVERT_MODE )); + }ST7789V_TEST (ret,st7789v_write_command (ctx,ST7789V_RAMCTRL_CMD )); ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_RAMCTRL_DM_RGB |
Signature · 1 line
2.40.1
PATCH v3 12/19 drm/panel: sitronix-st7789v: avoid hardcoding polarity info
In reply to Sebastian ReichelAdd polarity information via mode and bus flags, so that they are no longer hardcoded and forward the information to the DRM stack. This is required for adding panels with different settings.
--- .../gpu/drm/panel/panel-sitronix-st7789v.c | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-)
drivers/gpu/drm/panel/panel-sitronix-st7789v.c +18 -4
@@ -28,6 +28,7 @@#define ST7789V_RGBCTRL_VSYNC_HIGH BIT(3)#define ST7789V_RGBCTRL_HSYNC_HIGH BIT(2)#define ST7789V_RGBCTRL_PCLK_HIGH BIT(1) +#define ST7789V_RGBCTRL_DE_LOW BIT(0)#define ST7789V_RGBCTRL_VBP (n) ((n) & 0x7f)#define ST7789V_RGBCTRL_HBP (n) ((n) & 0x1f)
@@ -112,6 +113,7 @@struct st7789_panel_info {const struct drm_display_mode *mode;u32 bus_format; +u32 bus_flags;bool invert_mode; };
@@ -168,12 +170,15 @@ static const struct drm_display_mode default_mode = { .vtotal = 320 + 8 + 4 + 4, .width_mm = 61, .height_mm = 103, + .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, };static const struct st7789_panel_info default_panel = { .mode = &default_mode, .invert_mode = true, .bus_format =MEDIA_BUS_FMT_RGB666_1X18 , + .bus_flags =DRM_BUS_FLAG_DE_HIGH | +DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE , }; static int st7789v_get_modes(struct drm_panel *panel,
@@ -198,6 +203,7 @@ static int st7789v_get_modes(struct drm_panel *panel, connector->display_info.bpc =6 ; connector->display_info.width_mm = ctx->info->mode->width_mm; connector->display_info.height_mm = ctx->info->mode->height_mm; + connector->display_info.bus_flags = ctx->info->bus_flags;drm_display_info_set_bus_formats (&connector->display_info, &ctx->info->bus_format,1 );
@@ -207,7 +213,7 @@ static int st7789v_get_modes(struct drm_panel *panel,static int st7789v_prepare (struct drm_panel *panel) {struct st7789v *ctx =panel_to_st7789v (panel); -u8 pixel_fmt; +u8 pixel_fmt, polarity;int ret;switch (ctx->info->bus_format) {
@@ -225,6 +231,16 @@ static int st7789v_prepare(struct drm_panel *panel) pixel_fmt = (pixel_fmt <<4 ) | pixel_fmt; + polarity =0 ; +if (ctx->info->mode->flags &DRM_MODE_FLAG_PVSYNC ) + polarity |=ST7789V_RGBCTRL_VSYNC_HIGH ; +if (ctx->info->mode->flags &DRM_MODE_FLAG_PHSYNC ) + polarity |=ST7789V_RGBCTRL_HSYNC_HIGH ; +if (ctx->info->bus_flags &DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE ) + polarity |=ST7789V_RGBCTRL_PCLK_HIGH ; +if (ctx->info->bus_flags &DRM_BUS_FLAG_DE_LOW ) + polarity |=ST7789V_RGBCTRL_DE_LOW ; + ret =regulator_enable (ctx->power);if (ret)return ret;
@@ -340,9 +356,7 @@ static int st7789v_prepare(struct drm_panel *panel)ST7789V_TEST (ret,st7789v_write_command (ctx,ST7789V_RGBCTRL_CMD ));ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_RGBCTRL_WO |ST7789V_RGBCTRL_RCM (2 ) | -ST7789V_RGBCTRL_VSYNC_HIGH | -ST7789V_RGBCTRL_HSYNC_HIGH | -ST7789V_RGBCTRL_PCLK_HIGH )); + polarity));ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_RGBCTRL_VBP (8 )));ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_RGBCTRL_HBP (20 )));
Signature · 1 line
2.40.1
PATCH v3 13/19 drm/panel: sitronix-st7789v: add Inanbo T28CP45TN89 support
In reply to Sebastian ReichelUNI-T UTi260b has a Inanbo T28CP45TN89 v17 panel. I could not find proper documentation for the panel apart from a technical drawing, but according to the vendor U-Boot it is based on a Sitronix st7789v chip. I generated the init sequence by modifying the default one until proper graphics output has been seen on the device.
--- .../gpu/drm/panel/panel-sitronix-st7789v.c | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+)
drivers/gpu/drm/panel/panel-sitronix-st7789v.c +25 -0
@@ -173,6 +173,21 @@ static const struct drm_display_mode default_mode = { .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, }; +static const struct drm_display_mode t28cp45tn89_mode = { + .clock =6008 , + .hdisplay =240 , + .hsync_start =240 +38 , + .hsync_end =240 +38 +10 , + .htotal =240 +38 +10 +10 , + .vdisplay =320 , + .vsync_start =320 +8 , + .vsync_end =320 +8 +4 , + .vtotal =320 +8 +4 +4 , + .width_mm =43 , + .height_mm =57 , + .flags =DRM_MODE_FLAG_PVSYNC |DRM_MODE_FLAG_NVSYNC , +}; +static const struct st7789_panel_info default_panel = { .mode = &default_mode, .invert_mode = true,
@@ -181,6 +196,14 @@ static const struct st7789_panel_info default_panel = { DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE, }; +static const struct st7789_panel_info t28cp45tn89_panel = { + .mode = &t28cp45tn89_mode, + .invert_mode = false, + .bus_format =MEDIA_BUS_FMT_RGB565_1X16 , + .bus_flags =DRM_BUS_FLAG_DE_HIGH | +DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE , +}; +static int st7789v_get_modes (struct drm_panel *panel,struct drm_connector *connector) {
@@ -446,12 +469,14 @@ static void st7789v_remove(struct spi_device *spi)static const struct spi_device_id st7789v_spi_id[] = { {"st7789v" , (unsigned long ) &default_panel }, + {"t28cp45tn89-v17" , (unsigned long ) &t28cp45tn89_panel }, { } };MODULE_DEVICE_TABLE (spi, st7789v_spi_id);static const struct of_device_id st7789v_of_match[] = { { .compatible ="sitronix,st7789v" , .data = &default_panel }, + { .compatible ="inanbo,t28cp45tn89-v17" , .data = &t28cp45tn89_panel }, { } };MODULE_DEVICE_TABLE (of, st7789v_of_match);
Signature · 1 line
2.40.1
PATCH v3 14/19 dt-bindings: display: st7789v: Add the edt,et028013dma panel compatible
In reply to Sebastian ReichelFrom: Miquel Raynal <[email protected]>
The ST7789V LCD controller is also embedded in the ET028013DMA panel. Add a compatible string to describe this other panel.
--- .../devicetree/bindings/display/panel/sitronix,st7789v.yaml | 1 + 1 file changed, 1 insertion(+)
Documentation/devicetree/bindings/display/panel/sitronix,st7789v.yaml +1 -0
@@ -16,6 +16,7 @@ allOf: properties: compatible: enum: + - edt,et028013dma - inanbo,t28cp45tn89-v17 - sitronix,st7789v
Signature · 1 line
2.40.1
PATCH v3 15/19 dt-bindings: display: st7789v: bound the number of Rx data lines
In reply to Sebastian ReichelFrom: Miquel Raynal <[email protected]>
The ST7789V LCD controller supports regular SPI wiring, as well as no Rx data line at all. The operating system needs to know whether it can read registers from the device or not. Let's detail this specific design possibility by bounding the spi-rx-bus-width property.
--- .../devicetree/bindings/display/panel/sitronix,st7789v.yaml | 4 ++++ 1 file changed, 4 insertions(+)
Documentation/devicetree/bindings/display/panel/sitronix,st7789v.yaml +4 -0
@@ -29,6 +29,10 @@ properties: spi-cpha: true spi-cpol: true + spi-rx-bus-width: + minimum: 0 + maximum: 1 + dc-gpios: maxItems: 1 description: DCX pin, Display data/command selection pin in parallel interface
Signature · 1 line
2.40.1
PATCH v3 16/19 drm/panel: sitronix-st7789v: Use 9 bits per spi word by default
In reply to Sebastian ReichelFrom: Miquel Raynal <[email protected]>
The Sitronix controller expects 9-bit words, provide this as default at probe time rather than specifying this in each and every access.
--- drivers/gpu/drm/panel/panel-sitronix-st7789v.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/gpu/drm/panel/panel-sitronix-st7789v.c +5 -1
@@ -142,7 +142,6 @@ static int st7789v_spi_write(struct st7789v *ctx, enum st7789v_prefix prefix,u16 txbuf = ((prefix &1 ) <<8 ) | data; xfer.tx_buf = &txbuf; - xfer.bits_per_word =9 ; xfer.len =sizeof (txbuf);return spi_sync_transfer (ctx->spi, &xfer,1 );
@@ -436,6 +435,11 @@ static int st7789v_probe(struct spi_device *spi)spi_set_drvdata (spi, ctx); ctx->spi = spi; + spi->bits_per_word =9 ; + ret =spi_setup (spi); +if (ret <0 ) +return dev_err_probe (&spi->dev, ret,"Failed to setup spi\n" ); + ctx->info =device_get_match_data (&spi->dev); drm_panel_init(&ctx->panel, dev, &st7789v_drm_funcs,
Signature · 1 line
2.40.1
PATCH v3 17/19 drm/panel: sitronix-st7789v: Clarify a definition
In reply to Sebastian ReichelFrom: Miquel Raynal <[email protected]>
The Sitronix datasheet explains BIT(1) of the RGBCTRL register as the DOTCLK/PCLK edge used to sample the data lines:
“0” The data is input on the positive edge of DOTCLK “1” The data is input on the negative edge of DOTCLK
IOW, this bit implies a falling edge and not a high state. Correct the definition to ease the comparison with the datasheet.
--- drivers/gpu/drm/panel/panel-sitronix-st7789v.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/panel/panel-sitronix-st7789v.c +2 -2
@@ -27,7 +27,7 @@#define ST7789V_RGBCTRL_RCM (n) (((n) & 3) << 5)#define ST7789V_RGBCTRL_VSYNC_HIGH BIT(3)#define ST7789V_RGBCTRL_HSYNC_HIGH BIT(2) -#define ST7789V_RGBCTRL_PCLK_HIGH BIT(1) +#define ST7789V_RGBCTRL_PCLK_FALLING BIT(1)#define ST7789V_RGBCTRL_DE_LOW BIT(0)#define ST7789V_RGBCTRL_VBP (n) ((n) & 0x7f)#define ST7789V_RGBCTRL_HBP (n) ((n) & 0x1f)
@@ -259,7 +259,7 @@ static int st7789v_prepare(struct drm_panel *panel)if (ctx->info->mode->flags &DRM_MODE_FLAG_PHSYNC ) polarity |=ST7789V_RGBCTRL_HSYNC_HIGH ;if (ctx->info->bus_flags &DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE ) - polarity |=ST7789V_RGBCTRL_PCLK_HIGH ; + polarity |=ST7789V_RGBCTRL_PCLK_FALLING ;if (ctx->info->bus_flags &DRM_BUS_FLAG_DE_LOW ) polarity |=ST7789V_RGBCTRL_DE_LOW ;
Signature · 1 line
2.40.1
PATCH v3 18/19 drm/panel: sitronix-st7789v: Add EDT ET028013DMA panel support
In reply to Sebastian ReichelFrom: Miquel Raynal <[email protected]>
This panel from Emerging Display Technologies Corporation features an ST7789V2 LCD controller panel inside which is almost identical to what the Sitronix panel driver supports.
In practice, the module physical size is specific, and experiments show that the display will malfunction if any of the following situation occurs:
* Pixel clock is above 3MHz
* Pixel clock is not inverted
I could not properly identify the reasons behind these failures, scope captures show valid input signals.
--- .../gpu/drm/panel/panel-sitronix-st7789v.c | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+)
drivers/gpu/drm/panel/panel-sitronix-st7789v.c +25 -0
@@ -187,6 +187,21 @@ static const struct drm_display_mode t28cp45tn89_mode = { .flags = DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC, }; +static const struct drm_display_mode et028013dma_mode = { + .clock =3000 , + .hdisplay =240 , + .hsync_start =240 +38 , + .hsync_end =240 +38 +10 , + .htotal =240 +38 +10 +10 , + .vdisplay =320 , + .vsync_start =320 +8 , + .vsync_end =320 +8 +4 , + .vtotal =320 +8 +4 +4 , + .width_mm =43 , + .height_mm =58 , + .flags =DRM_MODE_FLAG_PHSYNC |DRM_MODE_FLAG_PVSYNC , +}; +static const struct st7789_panel_info default_panel = { .mode = &default_mode, .invert_mode = true,
@@ -203,6 +218,14 @@ static const struct st7789_panel_info t28cp45tn89_panel = { DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE, }; +static const struct st7789_panel_info et028013dma_panel = { + .mode = &et028013dma_mode, + .invert_mode = true, + .bus_format =MEDIA_BUS_FMT_RGB666_1X18 , + .bus_flags =DRM_BUS_FLAG_DE_HIGH | +DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE , +}; +static int st7789v_get_modes (struct drm_panel *panel,struct drm_connector *connector) {
@@ -474,6 +497,7 @@ static void st7789v_remove(struct spi_device *spi)static const struct spi_device_id st7789v_spi_id[] = { {"st7789v" , (unsigned long ) &default_panel }, {"t28cp45tn89-v17" , (unsigned long ) &t28cp45tn89_panel }, + {"et028013dma" , (unsigned long ) &et028013dma_panel }, { } };MODULE_DEVICE_TABLE (spi, st7789v_spi_id);
@@ -481,6 +505,7 @@ MODULE_DEVICE_TABLE(spi, st7789v_spi_id);static const struct of_device_id st7789v_of_match[] = { { .compatible ="sitronix,st7789v" , .data = &default_panel }, { .compatible ="inanbo,t28cp45tn89-v17" , .data = &t28cp45tn89_panel }, + { .compatible ="edt,et028013dma" , .data = &et028013dma_panel }, { } };MODULE_DEVICE_TABLE (of, st7789v_of_match);
Signature · 1 line
2.40.1
PATCH v3 19/19 drm/panel: sitronix-st7789v: Check display ID
In reply to Sebastian ReichelFrom: Miquel Raynal <[email protected]>
A very basic debugging rule when a device is connected for the first time is to access a read-only register which contains known data in order to ensure the communication protocol is properly working. This driver lacked any read helper which is often a critical piece for speeding-up bring-ups.
Add a read helper and use it to verify the communication with the panel is working as soon as possible in order to inform the user early if this is not the case.
As this panel may work with no MISO line, the check is discarded in this case. Upon error, we do not fail probing but just warn the user, in case the DT description would be lacking the Rx bus width (which is likely on old descriptions) in order to avoid breaking existing devices.
--- .../gpu/drm/panel/panel-sitronix-st7789v.c | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+)
drivers/gpu/drm/panel/panel-sitronix-st7789v.c +81 -0
@@ -110,6 +110,9 @@return val; \ } while (0) +#define ST7789V_IDS { 0x85, 0x85, 0x52 } +#define ST7789V_IDS_SIZE 3 +struct st7789_panel_info {const struct drm_display_mode *mode;u32 bus_format;
@@ -157,6 +160,76 @@ static int st7789v_write_data(struct st7789v *ctx, u8 cmd)return st7789v_spi_write (ctx,ST7789V_DATA , cmd); } +static int st7789v_read_data (struct st7789v *ctx,u8 cmd,u8 *buf, +unsigned int len) +{ +struct spi_transfer xfer[2 ] = { }; +struct spi_message msg; +u16 txbuf = ((ST7789V_COMMAND &1 ) <<8 ) | cmd; +u16 rxbuf[4 ] = {}; +u8 bit9 =0 ; +int ret, i; + +switch (len) { +case 1 : +case 3 : +case 4 : +break ; +default : +return -EOPNOTSUPP ; + } + +spi_message_init (&msg); + + xfer[0 ].tx_buf = &txbuf; + xfer[0 ].len =sizeof (txbuf); +spi_message_add_tail (&xfer[0 ], &msg); + + xfer[1 ].rx_buf = rxbuf; + xfer[1 ].len = len *2 ; +spi_message_add_tail (&xfer[1 ], &msg); + + ret =spi_sync (ctx->spi, &msg); +if (ret) +return ret; + +for (i =0 ; i < len; i++) { + buf[i] = rxbuf[i] >> i | (bit9 << (9 - i)); +if (i) + bit9 = rxbuf[i] &GENMASK (i -1 ,0 ); + } + +return 0 ; +} + +static int st7789v_check_id (struct drm_panel *panel) +{ +const u8 st7789v_ids[ST7789V_IDS_SIZE ] =ST7789V_IDS ; +struct st7789v *ctx =panel_to_st7789v (panel); +bool invalid_ids = false; +int ret, i; +u8 ids[3 ]; + +if (ctx->spi->mode &SPI_NO_RX ) +return 0 ; + + ret =st7789v_read_data (ctx,MIPI_DCS_GET_DISPLAY_ID , ids,ST7789V_IDS_SIZE ); +if (ret) +return ret; + +for (i =0 ; i <ST7789V_IDS_SIZE ; i++) { +if (ids[i] != st7789v_ids[i]) { + invalid_ids = true; +break ; + } + } + +if (invalid_ids) +return -EIO ; + +return 0 ; +} +static const struct drm_display_mode default_mode = { .clock =7000 , .hdisplay =240 ,
@@ -295,6 +368,14 @@ static int st7789v_prepare(struct drm_panel *panel)gpiod_set_value (ctx->reset,0 );msleep (120 ); +/* +* Avoid failing if the IDs are invalid in case the Rx bus width +* description is missing. +*/ + ret =st7789v_check_id (panel); +if (ret) +dev_warn (panel->dev,"Unrecognized panel IDs" ); +ST7789V_TEST (ret,st7789v_write_command (ctx,MIPI_DCS_EXIT_SLEEP_MODE ));/* We need to wait 120ms after a sleep out command */
Signature · 1 line
2.40.1
Hi Sebastian,
+ Thomas
[email protected] wrote on Fri, 14 Jul 2023 03:37:37 +0200:
Quoted 8 lines
Hi,
This adds panel support for Inanbo T28CP45TN89, which I found inside of a handheld thermal camera. The panel is based on the st7789v controller. All information is based on reverse engineering. I also appended the series from Miquel Raynal adding EDT ET028013DMA panel support, so that I could easily test it with my
SPI_NO_RXsetup. They are slightly different due to rebasing.
Thanks a lot! I'll continue following the series and provide my help when required.
Cheers,
Miquèl
Quoted 49 lines
Changes since PATCHv2:
* https://lore.kernel.org/all/[email protected]/
* https://lore.kernel.org/all/[email protected]/
* Add Rob Herring's R-b for the DT binding
* Make panel info "static const"
* Add Michael Riesch's R-b to all my patches
* Rebase to 6.5-rc1
* Append Miquel's seriesChanges since PATCHv1:
* https://lore.kernel.org/all/[email protected]/
* Apply DT binding changes requested by Krzysztof Kozlowski and his Ack
* I changed the driver patches to avoid code duplication and splitted the code a bit moreGreetings,
-- Sebastian
Miquel Raynal (6):
dt-bindings: display: st7789v: Add the edt,et028013dma panel
compatible
dt-bindings: display: st7789v: bound the number of Rx data lines drm/panel: sitronix-st7789v: Use 9 bits per spi word by default drm/panel: sitronix-st7789v: Clarify a definition drm/panel: sitronix-st7789v: Add EDT ET028013DMA panel support drm/panel: sitronix-st7789v: Check display IDSebastian Reichel (13):
dt-bindings: vendor-prefixes: add Inanbo
dt-bindings: display: st7789v: add Inanbo T28CP45TN89 drm/panel: sitronix-st7789v: add SPI ID table drm/panel: sitronix-st7789v: remove unused constants drm/panel: sitronix-st7789v: make reset GPIO optional drm/panel: sitronix-st7789v: simplifyst7789v_spi_writedrm/panel: sitronix-st7789v: improve error handling drm/panel: sitronix-st7789v: avoid hardcoding mode info drm/panel: sitronix-st7789v: avoid hardcoding panel size drm/panel: sitronix-st7789v: add media bus format drm/panel: sitronix-st7789v: avoid hardcoding invert mode drm/panel: sitronix-st7789v: avoid hardcoding polarity info drm/panel: sitronix-st7789v: add Inanbo T28CP45TN89 support.../display/panel/sitronix,st7789v.yaml | 10 +- .../devicetree/bindings/vendor-prefixes.yaml | 2 + .../gpu/drm/panel/panel-sitronix-st7789v.c | 262 +++++++++++++++--- 3 files changed, 237 insertions(+), 37 deletions(-)
Hi,
Each patch in the series has at least one Reviewed-by tag and the DT binding changes have an Acked-by from at least one of the DT binding maintainers. It has been pending on the mailing list for two weeks now, so can it be applied?
P.S.: Looks like I missed Neil in the original recipients list. Sorry about that. If you are not subscribed to dri-devel and need the full thread it's available here:
https://lore.kernel.org/all/[email protected]/
Greetings,
-- Sebastian
Neil Armstrong
maintainerHi Sebastian,
Quoted 10 lines · Sebastian Reichel
Hi,
Each patch in the series has at least one Reviewed-by tag and the DT binding changes have an Acked-by from at least one of the DT binding maintainers. It has been pending on the mailing list for two weeks now, so can it be applied?
P.S.: Looks like I missed Neil in the original recipients list. Sorry about that. If you are not subscribed to dri-devel and need the full thread it's available here:
Indeed I wasn't in CC and missed the thread.
Quoted 2 lines
Applying it now,
Thanks.
Neil
Quoted 4 lines
Greetings,
-- Sebastian
Hi,
Quoted 8 lines · Sebastian Reichel
This adds panel support for Inanbo T28CP45TN89, which I found inside of a handheld thermal camera. The panel is based on the st7789v controller. All information is based on reverse engineering. I also appended the series from Miquel Raynal adding EDT ET028013DMA panel support, so that I could easily test it with my
SPI_NO_RXsetup. They are slightly different due to rebasing.[...]
Thanks, Applied to https://anongit.freedesktop.org/git/drm/drm-misc.git (drm-misc-next)
[01/19] dt-bindings: vendor-prefixes: add Inanbo
https://cgit.freedesktop.org/drm/drm-misc/commit/?id=b93e0e203e27492a2277169e05ac59afb9bf7fcd [02/19] dt-bindings: display: st7789v: add Inanbo T28CP45TN89 https://cgit.freedesktop.org/drm/drm-misc/commit/?id=ff984a81cf601a68ba99a9c3264145f4d931783d [03/19] drm/panel: sitronix-st7789v: add SPI ID table https://cgit.freedesktop.org/drm/drm-misc/commit/?id=11649154ec46f1c7f7c58bac22e2c5927ca6b6a2 [04/19] drm/panel: sitronix-st7789v: remove unused constants https://cgit.freedesktop.org/drm/drm-misc/commit/?id=c2974f43b1237e0c985760156bc3ca4dccbb5243 [05/19] drm/panel: sitronix-st7789v: make reset GPIO optional https://cgit.freedesktop.org/drm/drm-misc/commit/?id=b6b65e45e09a2e940e48722fa0bfdf16e6f4edf8 [06/19] drm/panel: sitronix-st7789v: simplify st7789v_spi_write https://cgit.freedesktop.org/drm/drm-misc/commit/?id=fbad26dcb657830e59ba2ca5eaba6be0019b97f9 [07/19] drm/panel: sitronix-st7789v: improve error handling https://cgit.freedesktop.org/drm/drm-misc/commit/?id=bc2aa99b2306bc9d91586bc9187bfef4e61d3882 [08/19] drm/panel: sitronix-st7789v: avoid hardcoding mode info https://cgit.freedesktop.org/drm/drm-misc/commit/?id=9b4454fa2528c617b5986517c9c73e50e30d237d [09/19] drm/panel: sitronix-st7789v: avoid hardcoding panel size https://cgit.freedesktop.org/drm/drm-misc/commit/?id=4098d1867f27de2443c33e116b064ad3082aecb9 [10/19] drm/panel: sitronix-st7789v: add media bus format https://cgit.freedesktop.org/drm/drm-misc/commit/?id=a4b563b1d19dea9de366f81cae6342d80b663a45 [11/19] drm/panel: sitronix-st7789v: avoid hardcoding invert mode https://cgit.freedesktop.org/drm/drm-misc/commit/?id=7a6288726cf6bc0fa1bca0f24922a06425b84bf1 [12/19] drm/panel: sitronix-st7789v: avoid hardcoding polarity info https://cgit.freedesktop.org/drm/drm-misc/commit/?id=e4572f99f8a7dfd8a081c9135943ab82abe6f692 [13/19] drm/panel: sitronix-st7789v: add Inanbo T28CP45TN89 support https://cgit.freedesktop.org/drm/drm-misc/commit/?id=a411558cc14309073616e72d259083602585b296 [14/19] dt-bindings: display: st7789v: Add the edt,et028013dma panel compatible https://cgit.freedesktop.org/drm/drm-misc/commit/?id=893cfba7c56aa3fed34935b6fbc14a008c3b8172 [15/19] dt-bindings: display: st7789v: bound the number of Rx data lines https://cgit.freedesktop.org/drm/drm-misc/commit/?id=9943981aa3ab7841186827fce2177279c766b6df [16/19] drm/panel: sitronix-st7789v: Use 9 bits per spi word by default https://cgit.freedesktop.org/drm/drm-misc/commit/?id=6b00e72e4bee08048379a6365251b195b8a946d1 [17/19] drm/panel: sitronix-st7789v: Clarify a definition https://cgit.freedesktop.org/drm/drm-misc/commit/?id=a368b40836e7fc4f24dbb0fcfb9dedcde1dcaa38 [18/19] drm/panel: sitronix-st7789v: Add EDT ET028013DMA panel support https://cgit.freedesktop.org/drm/drm-misc/commit/?id=71f739082160b5e4def3a7083dc25583cc195d04 [19/19] drm/panel: sitronix-st7789v: Check display ID https://cgit.freedesktop.org/drm/drm-misc/commit/?id=290cdd7959a734a0ef20ec096af7810177c4b9f8
Signature · 1 line
Neil