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.
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
-- Sebastian
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 | 5 +-
.../devicetree/bindings/vendor-prefixes.yaml | 2 +
.../gpu/drm/panel/panel-sitronix-st7789v.c | 148 ++++++++++++++----
3 files changed, 120 insertions(+), 35 deletions(-)
--
2.39.2
The reset pin might not be software controllable from the SoC,
so make it optional.
Signed-off-by: Sebastian Reichel <[email protected]>
---
drivers/gpu/drm/panel/panel-sitronix-st7789v.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
index f7566551b5e2..1d43b8cc1647 100644
--- a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
+++ b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
@@ -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);
--
2.39.2
Add 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.
Signed-off-by: Sebastian Reichel <[email protected]>
---
.../gpu/drm/panel/panel-sitronix-st7789v.c | 26 ++++++++++++++++---
1 file changed, 23 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
index 0e1839e6da73..6d155c6262f3 100644
--- a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
+++ b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
@@ -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 = {
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));
--
2.39.2
Improve error handling in the probe routine, so that probe
defer errors are captured in /sys/kernel/debug/devices_deferred
Signed-off-by: Sebastian Reichel <[email protected]>
---
.../gpu/drm/panel/panel-sitronix-st7789v.c | 23 ++++++++++---------
1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
index 6290bd49d055..a6d6155ef45c 100644
--- a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
+++ b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
@@ -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);
--
2.39.2
While the default panel uses invert mode, some panels
require non-invert mode instead.
Signed-off-by: Sebastian Reichel <[email protected]>
---
drivers/gpu/drm/panel/panel-sitronix-st7789v.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
index 6d155c6262f3..158623a8dfb7 100644
--- a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
+++ b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
@@ -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 = {
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 |
--
2.39.2
Shenzhen INANBO Electronic Technology Co., Ltd. manufacturers TFT/OLED
LCD panels.
Acked-by: Krzysztof Kozlowski <[email protected]>
Signed-off-by: Sebastian Reichel <[email protected]>
---
Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index ed64e06ecca4..33e1d65cf4b2 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -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,.*":
--
2.39.2
Add compatible value for Inanbo t28cp45tn89 and make reset GPIO non
mandatory, since it might not be connected to the CPU.
Signed-off-by: Sebastian Reichel <[email protected]>
---
.../devicetree/bindings/display/panel/sitronix,st7789v.yaml | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/display/panel/sitronix,st7789v.yaml b/Documentation/devicetree/bindings/display/panel/sitronix,st7789v.yaml
index d984b59daa4a..7c5e4313db1d 100644
--- a/Documentation/devicetree/bindings/display/panel/sitronix,st7789v.yaml
+++ b/Documentation/devicetree/bindings/display/panel/sitronix,st7789v.yaml
@@ -15,7 +15,9 @@ allOf:
properties:
compatible:
- const: sitronix,st7789v
+ enum:
+ - inanbo,t28cp45tn89-v17
+ - sitronix,st7789v
reg: true
reset-gpios: true
@@ -29,7 +31,6 @@ properties:
required:
- compatible
- reg
- - reset-gpios
- power-supply
unevaluatedProperties: false
--
2.39.2
Add 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.
Signed-off-by: Sebastian Reichel <[email protected]>
---
.../gpu/drm/panel/panel-sitronix-st7789v.c | 22 +++++++++++++++----
1 file changed, 18 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
index 158623a8dfb7..f3b1bf7ef996 100644
--- a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
+++ b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
@@ -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,
};
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)));
--
2.39.2
st7789v_spi_write initializes a message with just
a single transfer, spi_sync_transfer can be used
for that.
Signed-off-by: Sebastian Reichel <[email protected]>
---
drivers/gpu/drm/panel/panel-sitronix-st7789v.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
index 1d43b8cc1647..6290bd49d055 100644
--- a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
+++ b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
@@ -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)
--
2.39.2
Avoid 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.
Signed-off-by: Sebastian Reichel <[email protected]>
---
.../gpu/drm/panel/panel-sitronix-st7789v.c | 24 ++++++++++++++-----
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
index a6d6155ef45c..29c2a91f8299 100644
--- a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
+++ b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
@@ -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,
};
+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);
--
2.39.2
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(+)
diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
index bbc4569cbcdc..e4d8dea1db36 100644
--- a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
+++ b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
@@ -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,
--
2.39.2
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.
Signed-off-by: Sebastian Reichel <[email protected]>
---
.../gpu/drm/panel/panel-sitronix-st7789v.c | 25 +++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
index f3b1bf7ef996..172c6c1fc090 100644
--- a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
+++ b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
@@ -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,
+};
+
struct st7789_panel_info default_panel = {
.mode = &default_mode,
.invert_mode = true,
@@ -181,6 +196,14 @@ struct st7789_panel_info default_panel = {
DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE,
};
+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);
--
2.39.2
Move the panel size information to the mode struct, so
that different panel sizes can be specified depending
on the panel type.
Signed-off-by: Sebastian Reichel <[email protected]>
---
drivers/gpu/drm/panel/panel-sitronix-st7789v.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
index 29c2a91f8299..0e1839e6da73 100644
--- a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
+++ b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
@@ -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,
};
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;
}
--
2.39.2
On Sat, 22 Apr 2023 22:50:01 +0200, Sebastian Reichel wrote:
> Add compatible value for Inanbo t28cp45tn89 and make reset GPIO non
> mandatory, since it might not be connected to the CPU.
>
> Signed-off-by: Sebastian Reichel <[email protected]>
> ---
> .../devicetree/bindings/display/panel/sitronix,st7789v.yaml | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
Acked-by: Rob Herring <[email protected]>
Hi Sebastian,
Thanks for the v2 of your series. Looks great!
One nitpick though: you seem to wrap the patch message lines at ~50
characters sometimes, which is awfully short.
Another comment below:
On 4/22/23 22:50, Sebastian Reichel wrote:
> Avoid 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.
>
> Signed-off-by: Sebastian Reichel <[email protected]>
> ---
> .../gpu/drm/panel/panel-sitronix-st7789v.c | 24 ++++++++++++++-----
> 1 file changed, 18 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
> index a6d6155ef45c..29c2a91f8299 100644
> --- a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
> +++ b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
> @@ -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,
> };
>
> +struct st7789_panel_info default_panel = {
> + .mode = &default_mode,
> +};
Shouldn't this be "static const struct st7789_panel_info default_panel"?
(Same holds for "struct st7789_panel_info t28cp45tn89_panel" in patch
13/13.)
With the comments above addressed, feel free to add my
Reviewed-by: Michael Riesch <[email protected]>
to the whole v3 of your series.
Thanks and best regards,
Michael
> +
> 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);
Hi Sebastian,
+ Thomas
[email protected] wrote on Sat, 22 Apr 2023 22:49:59 +0200:
> 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 haven't seen another version for this series so I assume it is still
the one to look at. As you already know, I also want to add support for
a panel based on the st7789 display controller. As discussed, I rebased
my changes on top of yours as you actually sent them upstream
much earlier than I did.
As a single minor comment was made to this version of the series, I
would like to know if you wanted to send a new version soon? Or if it
would make sense to send a bigger series with all our common patches in
one single shot (mine should apply cleanly without further work on
yours). Let me know how we can move forward.
For the record, here are my patches.
Link: https://lore.kernel.org/all/[email protected]/
Thanks a lot,
Miquèl
>
> 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
>
> -- Sebastian
>
> 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 | 5 +-
> .../devicetree/bindings/vendor-prefixes.yaml | 2 +
> .../gpu/drm/panel/panel-sitronix-st7789v.c | 148 ++++++++++++++----
> 3 files changed, 120 insertions(+), 35 deletions(-)
>