Add Inanbo T28CP45TN89 panel support
Subsystems (4)
cover Add Inanbo T28CP45TN89 panel support
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.
The series conflicts with [0] ("Add timing override to sitronix,st7789v"). I can rebase, but did not want to delay getting some review feedback :)
[0] https://lore.kernel.org/all/[email protected]/
-- Sebastian
Sebastian Reichel (7):
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: prepare for additional panels drm/panel: sitronix-st7789v: add Inanbo T28CP45TN89 support
.../display/panel/sitronix,st7789v.yaml | 5 +- .../devicetree/bindings/vendor-prefixes.yaml | 2 + .../gpu/drm/panel/panel-sitronix-st7789v.c | 251 +++++++++++++++--- 3 files changed, 213 insertions(+), 45 deletions(-)
Signature · 1 line
2.39.2
PATCH 1/7 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
@@ -609,6 +609,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 "^inet-tek,.*":
Signature · 1 line
2.39.2
Re: [PATCHv1 1/7] dt-bindings: vendor-prefixes: add Inanbo
Quoted 4 lines · Sebastian Reichel
Shenzhen INANBO Electronic Technology Co., Ltd. manufacturers TFT/OLED LCD panels.
Signed-off-by Sebastian Reichel <[email protected]>
Best regards,
Krzysztof
PATCH 2/7 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: + - sitronix,st7789v + - inanbo,t28cp45tn89-v17 reg: true reset-gpios: true
@@ -29,7 +31,6 @@ properties: required: - compatible - reg - - reset-gpios - power-supply unevaluatedProperties: false
Signature · 1 line
2.39.2
Re: [PATCHv1 2/7] dt-bindings: display: st7789v: add Inanbo T28CP45TN89
Quoted 3 lines · Sebastian Reichel
Add compatible value for Inanbo t28cp45tn89 and
make reset GPIO non mandatory, since it might not
be connected to the CPU.
Please wrap commit message according to Linux coding style / submission process (neither too early nor over the limit):
https://elixir.bootlin.com/linux/v5.18-rc4/source/Documentation/process/submitting-patches.rst#L586
Quoted 11 lines
Signed-off-by Sebastian Reichel <[email protected]>--- .../devicetree/bindings/display/panel/sitronix,st7789v.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)Documentation/devicetree/bindings/display/panel/sitronix,st7789v.yaml +0
-0
Documentation/devicetree/bindings/display/panel/sitronix,st7789v.yaml allOf: · line 20
Quoted 7 lines
Documentation/devicetree/bindings/display/panel/sitronix,st7789v.yaml +3
-1@@ -15,7 +15,9 @@ allOf: properties: compatible: - const: sitronix,st7789v + enum: + - sitronix,st7789v + - inanbo,t28cp45tn89-v17
Keep them ordered by name.
Best regards,
Krzysztof
PATCH 3/7 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.39.2
Re: [PATCHv1 3/7] drm/panel: sitronix-st7789v: add SPI ID table
Hi Sebastian,
Quoted 12 lines · Sebastian Reichel
SPI device drivers should also have a SPI ID table.
Signed-off-by Sebastian Reichel <[email protected]>--- drivers/gpu/drm/panel/panel-sitronix-st7789v.c | 7 +++++++ 1 file changed, 7 insertions(+)drivers/gpu/drm/panel/panel-sitronix-st7789v.c +0
-0
drivers/gpu/drm/panel/panel-sitronix-st7789v.c static void st7789v_remove(struct spi_device *spi) · line 398
Quoted 5 lines
drivers/gpu/drm/panel/panel-sitronix-st7789v.c +2
-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" },
Minor suggestion: The format
static const struct spi_device_id st7789v_spi_id[] = {
{
.name = "st7789v",
},
{ }
};is more verbose, but can be extended easily.
drivers/gpu/drm/panel/panel-sitronix-st7789v.c static void st7789v_remove(struct spi_device *spi) · line 405
Quoted 7 lines
drivers/gpu/drm/panel/panel-sitronix-st7789v.c +4
-0+ { } +}; +MODULE_DEVICE_TABLE (spi, st7789v_spi_id); +static const struct of_device_id st7789v_of_match[] = { { .compatible ="sitronix,st7789v" }, { }
The same holds for this structure here (you may want to consider this when adding the .data field in patch 6/7.
Best regards,
Michael
Quoted 8 lines
drivers/gpu/drm/panel/panel-sitronix-st7789v.c +1
-0@@ -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,
PATCH 4/7 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.39.2
PATCH 5/7 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.39.2
PATCH 6/7 drm/panel: sitronix-st7789v: prepare for additional panels
In reply to Sebastian ReichelPrepare the driver for additional panels with different initialization.
--- .../gpu/drm/panel/panel-sitronix-st7789v.c | 110 +++++++++++------- 1 file changed, 67 insertions(+), 43 deletions(-)
drivers/gpu/drm/panel/panel-sitronix-st7789v.c +67 -43
@@ -108,8 +108,16 @@return val; \ }while (0 ) +struct st7789v; + +struct st7789_panel_info { +const struct drm_display_mode *mode; +int (*init_sequence)(struct st7789v *ctx); +}; +struct st7789v {struct drm_panel panel; +const struct st7789_panel_info *info;struct spi_device *spi;struct gpio_desc *reset;struct regulator *power;
@@ -162,51 +170,13 @@ 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 int st7789v_get_modes (struct drm_panel *panel, -struct drm_connector *connector) -{ -struct drm_display_mode *mode; - - mode =drm_mode_duplicate (connector->dev, &default_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)); -return -ENOMEM ; - } - -drm_mode_set_name (mode); - - 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 ; - -return 1 ; -} - -static int st7789v_prepare (struct drm_panel *panel) -{ -struct st7789v *ctx =panel_to_st7789v (panel); +static int init_sequence_default (struct st7789v *ctx) {int ret; - ret =regulator_enable (ctx->power); -if (ret) -return ret; - -gpiod_set_value (ctx->reset,1 ); -msleep (30 ); -gpiod_set_value (ctx->reset,0 ); -msleep (120 ); - -ST7789V_TEST (ret,st7789v_write_command (ctx,MIPI_DCS_EXIT_SLEEP_MODE )); - -/* We need to wait 120ms after a sleep out command */ -msleep (120 ); -ST7789V_TEST (ret,st7789v_write_command (ctx,MIPI_DCS_SET_ADDRESS_MODE ));ST7789V_TEST (ret,st7789v_write_data (ctx,0 ));
@@ -313,6 +283,58 @@ static int st7789v_prepare(struct drm_panel *panel)return 0 ; } +struct st7789_panel_info default_panel = { + .mode = &default_mode, + .init_sequence = init_sequence_default, +}; + +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, ctx->info->mode); +if (!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 ; + } + +drm_mode_set_name (mode); + + mode->type =DRM_MODE_TYPE_DRIVER |DRM_MODE_TYPE_PREFERRED ; +drm_mode_probed_add (connector, mode); + + connector->display_info.width_mm = ctx->info->mode->width_mm; + connector->display_info.height_mm = ctx->info->mode->height_mm; + +return 1 ; +} + +static int st7789v_prepare (struct drm_panel *panel) +{ +struct st7789v *ctx =panel_to_st7789v (panel); +int ret; + + ret =regulator_enable (ctx->power); +if (ret) +return ret; + +gpiod_set_value (ctx->reset,1 ); +msleep (30 ); +gpiod_set_value (ctx->reset,0 ); +msleep (120 ); + +ST7789V_TEST (ret,st7789v_write_command (ctx,MIPI_DCS_EXIT_SLEEP_MODE )); + +/* We need to wait 120ms after a sleep out command */ +msleep (120 ); + +return ctx->info->init_sequence (ctx); +} +static int st7789v_enable (struct drm_panel *panel) {struct st7789v *ctx =panel_to_st7789v (panel);
@@ -362,6 +384,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, &spi->dev, &st7789v_drm_funcs,DRM_MODE_CONNECTOR_DPI );
@@ -392,13 +416,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.39.2
PATCH 7/7 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 | 137 ++++++++++++++++++ 1 file changed, 137 insertions(+)
drivers/gpu/drm/panel/panel-sitronix-st7789v.c +137 -0
@@ -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>
@@ -113,6 +114,8 @@ struct st7789v;struct st7789_panel_info {const struct drm_display_mode *mode;int (*init_sequence)(struct st7789v *ctx); +unsigned int bpc; +u32 bus_format; };struct st7789v {
@@ -174,6 +177,20 @@ static const struct drm_display_mode default_mode = { .height_mm = 103, }; +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 , +}; +static int init_sequence_default (struct st7789v *ctx) {int ret;
@@ -283,11 +300,125 @@ static int init_sequence_default(struct st7789v *ctx) {return 0 ; } +static int init_sequence_t28cp45tn89 (struct st7789v *ctx) { +int ret; + +ST7789V_TEST (ret,st7789v_write_command (ctx, +MIPI_DCS_SET_ADDRESS_MODE )); +ST7789V_TEST (ret,st7789v_write_data (ctx,0 )); + +ST7789V_TEST (ret,st7789v_write_command (ctx, +MIPI_DCS_SET_PIXEL_FORMAT )); +ST7789V_TEST (ret,st7789v_write_data (ctx, + (MIPI_DCS_PIXEL_FMT_16BIT <<4 ) | + (MIPI_DCS_PIXEL_FMT_16BIT ))); + +ST7789V_TEST (ret,st7789v_write_command (ctx,ST7789V_PORCTRL_CMD )); +ST7789V_TEST (ret,st7789v_write_data (ctx,0xc )); +ST7789V_TEST (ret,st7789v_write_data (ctx,0xc )); +ST7789V_TEST (ret,st7789v_write_data (ctx,0 )); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PORCTRL_IDLE_BP (3 ) | +ST7789V_PORCTRL_IDLE_FP (3 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx, +ST7789V_PORCTRL_PARTIAL_BP (3 ) | +ST7789V_PORCTRL_PARTIAL_FP (3 ))); + +ST7789V_TEST (ret,st7789v_write_command (ctx,ST7789V_GCTRL_CMD )); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_GCTRL_VGLS (5 ) | +ST7789V_GCTRL_VGHS (3 ))); + +ST7789V_TEST (ret,st7789v_write_command (ctx,ST7789V_VCOMS_CMD )); +ST7789V_TEST (ret,st7789v_write_data (ctx,0x2b )); + +ST7789V_TEST (ret,st7789v_write_command (ctx,ST7789V_LCMCTRL_CMD )); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_LCMCTRL_XMH | +ST7789V_LCMCTRL_XMX | +ST7789V_LCMCTRL_XBGR )); + +ST7789V_TEST (ret,st7789v_write_command (ctx,ST7789V_VDVVRHEN_CMD )); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_VDVVRHEN_CMDEN )); + +ST7789V_TEST (ret,st7789v_write_command (ctx,ST7789V_VRHS_CMD )); +ST7789V_TEST (ret,st7789v_write_data (ctx,0xf )); + +ST7789V_TEST (ret,st7789v_write_command (ctx,ST7789V_VDVS_CMD )); +ST7789V_TEST (ret,st7789v_write_data (ctx,0x20 )); + +ST7789V_TEST (ret,st7789v_write_command (ctx,ST7789V_FRCTRL2_CMD )); +ST7789V_TEST (ret,st7789v_write_data (ctx,0xf )); + +ST7789V_TEST (ret,st7789v_write_command (ctx,ST7789V_PWCTRL1_CMD )); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PWCTRL1_MAGIC )); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PWCTRL1_AVDD (2 ) | +ST7789V_PWCTRL1_AVCL (2 ) | +ST7789V_PWCTRL1_VDS (1 ))); + +ST7789V_TEST (ret,st7789v_write_command (ctx,ST7789V_PVGAMCTRL_CMD )); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_VP63 (0xd ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_VP1 (0xca ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_VP2 (0xe ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_VP4 (8 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_VP6 (9 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_VP13 (7 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_VP20 (0x2d ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_VP27 (0xb ) | +ST7789V_PVGAMCTRL_VP36 (3 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_VP43 (0x3d ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_JP1 (3 ) | +ST7789V_PVGAMCTRL_VP50 (4 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_VP57 (0xa ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_VP59 (0xa ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_VP61 (0x1b ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_VP62 (0x28 ))); + +ST7789V_TEST (ret,st7789v_write_command (ctx,ST7789V_NVGAMCTRL_CMD )); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_NVGAMCTRL_VN63 (0xd ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_NVGAMCTRL_VN1 (0xca ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_NVGAMCTRL_VN2 (0xf ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_NVGAMCTRL_VN4 (8 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_NVGAMCTRL_VN6 (8 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_NVGAMCTRL_VN13 (7 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_NVGAMCTRL_VN20 (0x2e ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_NVGAMCTRL_VN27 (0xc ) | +ST7789V_NVGAMCTRL_VN36 (5 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_NVGAMCTRL_VN43 (0x40 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_NVGAMCTRL_JN1 (3 ) | +ST7789V_NVGAMCTRL_VN50 (4 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_NVGAMCTRL_VN57 (9 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_NVGAMCTRL_VN59 (0xb ))); +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_EXIT_INVERT_MODE )); + +ST7789V_TEST (ret,st7789v_write_command (ctx,ST7789V_RAMCTRL_CMD )); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_RAMCTRL_DM_RGB | +ST7789V_RAMCTRL_RM_RGB )); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_RAMCTRL_EPF (3 ) | +ST7789V_RAMCTRL_MAGIC )); + +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_TEST (ret,st7789v_write_data (ctx,ST7789V_RGBCTRL_VBP (8 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_RGBCTRL_HBP (20 ))); + +return 0 ; +} +struct st7789_panel_info default_panel = { .mode = &default_mode, .init_sequence = init_sequence_default, }; +struct st7789_panel_info t28cp45tn89_panel = { + .mode = &t28cp45tn89_mode, + .init_sequence = init_sequence_t28cp45tn89, + .bpc =6 , + .bus_format =MEDIA_BUS_FMT_RGB565_1X16 , +}; +static int st7789v_get_modes (struct drm_panel *panel,struct drm_connector *connector) {
@@ -307,8 +438,12 @@ 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 = ctx->info->bpc; connector->display_info.width_mm = ctx->info->mode->width_mm; connector->display_info.height_mm = ctx->info->mode->height_mm; +if (ctx->info->bus_format) +drm_display_info_set_bus_formats (&connector->display_info, + &ctx->info->bus_format,1 );return 1 ; }
@@ -417,12 +552,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.39.2
Re: [PATCHv1 7/7] drm/panel: sitronix-st7789v: add Inanbo T28CP45TN89 support
Hi Sebastian,
Thanks for your work and for the beautiful timing :-)
Quoted 5 lines · Sebastian Reichel
UNI-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.
I can spot only a few differences:
- bits per pixel: 18 (RGB666) vs. 16 (RGB565)
- invert mode
- sync/clk signal polarity
The init sequences are largely the same, which leads to vast code duplication. Instead, the st7789v_prepare could be adjusted to consider the st7789v_panel_info and apply the required settings accordingly.
For example, the polarities could be embedded into the drm_display_mode structure...
Quoted 18 lines
Signed-off-by Sebastian Reichel <[email protected]>--- .../gpu/drm/panel/panel-sitronix-st7789v.c | 137 ++++++++++++++++++ 1 file changed, 137 insertions(+)drivers/gpu/drm/panel/panel-sitronix-st7789v.c +1
-0@@ -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>
drivers/gpu/drm/panel/panel-sitronix-st7789v.c struct st7789v; · line 118
Quoted 5 lines
drivers/gpu/drm/panel/panel-sitronix-st7789v.c +2
-0@@ -113,6 +114,8 @@ struct st7789v;struct st7789_panel_info {const struct drm_display_mode *mode;int (*init_sequence)(struct st7789v *ctx); +unsigned int bpc; +u32 bus_format;
... and here you introduce fields for the bits per pixel. Just a field for the invert mode is missing.
BTW, I would introduce these fields in the previous patch. This patch should be only about filling out the already existing fields for the new panel.
Quoted 151 lines
drivers/gpu/drm/panel/panel-sitronix-st7789v.c +128
-0};struct st7789v {@@ -174,6 +177,20 @@ static const struct drm_display_mode default_mode = { .height_mm = 103, }; +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 , +}; +static int init_sequence_default (struct st7789v *ctx) {int ret;@@ -283,11 +300,125 @@ static int init_sequence_default(struct st7789v *ctx) {return 0 ; } +static int init_sequence_t28cp45tn89 (struct st7789v *ctx) { +int ret; + +ST7789V_TEST (ret,st7789v_write_command (ctx, +MIPI_DCS_SET_ADDRESS_MODE )); +ST7789V_TEST (ret,st7789v_write_data (ctx,0 )); + +ST7789V_TEST (ret,st7789v_write_command (ctx, +MIPI_DCS_SET_PIXEL_FORMAT )); +ST7789V_TEST (ret,st7789v_write_data (ctx, + (MIPI_DCS_PIXEL_FMT_16BIT <<4 ) | + (MIPI_DCS_PIXEL_FMT_16BIT ))); + +ST7789V_TEST (ret,st7789v_write_command (ctx,ST7789V_PORCTRL_CMD )); +ST7789V_TEST (ret,st7789v_write_data (ctx,0xc )); +ST7789V_TEST (ret,st7789v_write_data (ctx,0xc )); +ST7789V_TEST (ret,st7789v_write_data (ctx,0 )); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PORCTRL_IDLE_BP (3 ) | +ST7789V_PORCTRL_IDLE_FP (3 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx, +ST7789V_PORCTRL_PARTIAL_BP (3 ) | +ST7789V_PORCTRL_PARTIAL_FP (3 ))); + +ST7789V_TEST (ret,st7789v_write_command (ctx,ST7789V_GCTRL_CMD )); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_GCTRL_VGLS (5 ) | +ST7789V_GCTRL_VGHS (3 ))); + +ST7789V_TEST (ret,st7789v_write_command (ctx,ST7789V_VCOMS_CMD )); +ST7789V_TEST (ret,st7789v_write_data (ctx,0x2b )); + +ST7789V_TEST (ret,st7789v_write_command (ctx,ST7789V_LCMCTRL_CMD )); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_LCMCTRL_XMH | +ST7789V_LCMCTRL_XMX | +ST7789V_LCMCTRL_XBGR )); + +ST7789V_TEST (ret,st7789v_write_command (ctx,ST7789V_VDVVRHEN_CMD )); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_VDVVRHEN_CMDEN )); + +ST7789V_TEST (ret,st7789v_write_command (ctx,ST7789V_VRHS_CMD )); +ST7789V_TEST (ret,st7789v_write_data (ctx,0xf )); + +ST7789V_TEST (ret,st7789v_write_command (ctx,ST7789V_VDVS_CMD )); +ST7789V_TEST (ret,st7789v_write_data (ctx,0x20 )); + +ST7789V_TEST (ret,st7789v_write_command (ctx,ST7789V_FRCTRL2_CMD )); +ST7789V_TEST (ret,st7789v_write_data (ctx,0xf )); + +ST7789V_TEST (ret,st7789v_write_command (ctx,ST7789V_PWCTRL1_CMD )); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PWCTRL1_MAGIC )); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PWCTRL1_AVDD (2 ) | +ST7789V_PWCTRL1_AVCL (2 ) | +ST7789V_PWCTRL1_VDS (1 ))); + +ST7789V_TEST (ret,st7789v_write_command (ctx,ST7789V_PVGAMCTRL_CMD )); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_VP63 (0xd ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_VP1 (0xca ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_VP2 (0xe ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_VP4 (8 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_VP6 (9 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_VP13 (7 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_VP20 (0x2d ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_VP27 (0xb ) | +ST7789V_PVGAMCTRL_VP36 (3 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_VP43 (0x3d ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_JP1 (3 ) | +ST7789V_PVGAMCTRL_VP50 (4 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_VP57 (0xa ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_VP59 (0xa ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_VP61 (0x1b ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_PVGAMCTRL_VP62 (0x28 ))); + +ST7789V_TEST (ret,st7789v_write_command (ctx,ST7789V_NVGAMCTRL_CMD )); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_NVGAMCTRL_VN63 (0xd ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_NVGAMCTRL_VN1 (0xca ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_NVGAMCTRL_VN2 (0xf ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_NVGAMCTRL_VN4 (8 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_NVGAMCTRL_VN6 (8 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_NVGAMCTRL_VN13 (7 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_NVGAMCTRL_VN20 (0x2e ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_NVGAMCTRL_VN27 (0xc ) | +ST7789V_NVGAMCTRL_VN36 (5 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_NVGAMCTRL_VN43 (0x40 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_NVGAMCTRL_JN1 (3 ) | +ST7789V_NVGAMCTRL_VN50 (4 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_NVGAMCTRL_VN57 (9 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_NVGAMCTRL_VN59 (0xb ))); +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_EXIT_INVERT_MODE )); + +ST7789V_TEST (ret,st7789v_write_command (ctx,ST7789V_RAMCTRL_CMD )); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_RAMCTRL_DM_RGB | +ST7789V_RAMCTRL_RM_RGB )); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_RAMCTRL_EPF (3 ) | +ST7789V_RAMCTRL_MAGIC )); + +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_TEST (ret,st7789v_write_data (ctx,ST7789V_RGBCTRL_VBP (8 ))); +ST7789V_TEST (ret,st7789v_write_data (ctx,ST7789V_RGBCTRL_HBP (20 ))); + +return 0 ; +} +struct st7789_panel_info default_panel = { .mode = &default_mode, .init_sequence = init_sequence_default, }; +struct st7789_panel_info t28cp45tn89_panel = { + .mode = &t28cp45tn89_mode, + .init_sequence = init_sequence_t28cp45tn89, + .bpc =6 , + .bus_format =MEDIA_BUS_FMT_RGB565_1X16 , +}; +static int st7789v_get_modes (struct drm_panel *panel,struct drm_connector *connector) {
drivers/gpu/drm/panel/panel-sitronix-st7789v.c static int st7789v_get_modes(struct drm_panel *panel, · line 446
Quoted 9 lines
drivers/gpu/drm/panel/panel-sitronix-st7789v.c +4
-0@@ -307,8 +438,12 @@ 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 = ctx->info->bpc; connector->display_info.width_mm = ctx->info->mode->width_mm; connector->display_info.height_mm = ctx->info->mode->height_mm; +if (ctx->info->bus_format) +drm_display_info_set_bus_formats (&connector->display_info, + &ctx->info->bus_format,1 );
This should also be in a previous patch.
Best regards,
Michael
Quoted 18 lines
drivers/gpu/drm/panel/panel-sitronix-st7789v.c +2
-0return 1 ; }@@ -417,12 +552,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);