Message ID | 20200809215104.1830206-3-linus.walleij@linaro.org |
---|---|
State | Accepted |
Commit | 435e06c06cb2e3bd2f650a52641ddb13a95a1624 |
Headers | show |
Series | drm/panel: s6e63m0: Add DSI transport | expand |
On Sun, Aug 09, 2020 at 11:51:02PM +0200, Linus Walleij wrote: > This makes it possible to use the s6e63m0 panel with a > DSI host, such as in the Samsung GT-I8190 (Golden) mobile > phone. > > Cc: Stephan Gerhold <stephan@gerhold.net> > Cc: Paweł Chmiel <pawel.mikolaj.chmiel@gmail.com> > Signed-off-by: Linus Walleij <linus.walleij@linaro.org> > --- > drivers/gpu/drm/panel/Kconfig | 8 ++ > drivers/gpu/drm/panel/Makefile | 1 + > .../gpu/drm/panel/panel-samsung-s6e63m0-dsi.c | 128 ++++++++++++++++++ > .../gpu/drm/panel/panel-samsung-s6e63m0-spi.c | 2 +- > drivers/gpu/drm/panel/panel-samsung-s6e63m0.c | 4 +- > drivers/gpu/drm/panel/panel-samsung-s6e63m0.h | 4 +- > 6 files changed, 144 insertions(+), 3 deletions(-) > create mode 100644 drivers/gpu/drm/panel/panel-samsung-s6e63m0-dsi.c > > diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig > index 96e1548e475f..731e84c5a13b 100644 > --- a/drivers/gpu/drm/panel/Kconfig > +++ b/drivers/gpu/drm/panel/Kconfig > @@ -343,6 +343,14 @@ config DRM_PANEL_SAMSUNG_S6E63M0_SPI > Say Y here if you want to be able to access the Samsung > S6E63M0 panel using SPI. > > +config DRM_PANEL_SAMSUNG_S6E63M0_DSI > + tristate "Samsung S6E63M0 RGB DSI interface" > + depends on DRM_MIPI_DSI > + depends on DRM_PANEL_SAMSUNG_S6E63M0 > + help > + Say Y here if you want to be able to access the Samsung > + S6E63M0 panel using DSI. > + > config DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01 > tristate "Samsung AMS452EF01 panel with S6E88A0 DSI video mode controller" > depends on OF > diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile > index 9cf71adfa794..14212cae3c29 100644 > --- a/drivers/gpu/drm/panel/Makefile > +++ b/drivers/gpu/drm/panel/Makefile > @@ -35,6 +35,7 @@ obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o > obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o > obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0) += panel-samsung-s6e63m0.o > obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0_SPI) += panel-samsung-s6e63m0-spi.o > +obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0_DSI) += panel-samsung-s6e63m0-dsi.o > obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01) += panel-samsung-s6e88a0-ams452ef01.o > obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o > obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o > diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63m0-dsi.c b/drivers/gpu/drm/panel/panel-samsung-s6e63m0-dsi.c > new file mode 100644 > index 000000000000..f4927a6ce26d > --- /dev/null > +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63m0-dsi.c > @@ -0,0 +1,128 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * DSI interface to the Samsung S6E63M0 panel. > + * (C) 2019 Linus Walleij > + */ > + > +#include <linux/module.h> > +#include <linux/delay.h> > +#include <linux/of_device.h> > + > +#include <drm/drm_mipi_dsi.h> > +#include <drm/drm_print.h> > + > +#include "panel-samsung-s6e63m0.h" > + > +#define MCS_GLOBAL_PARAM 0xb0 > +#define S6E63M0_DSI_MAX_CHUNK 15 /* CMD + 15 bytes max */ > + > +static int s6e63m0_dsi_dcs_write(struct device *dev, const u8 *data, size_t len) > +{ > + struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); > + const u8 *seqp = data; > + u8 cmd; > + u8 cmdwritten; > + int remain; > + int chunk; > + int ret; > + > + DRM_DEV_INFO(dev, "DSI writing dcs seq: %*ph\n", (int)len, data); > + We should probably remove these or demote them to debug. It's quite verbose. > + /* Pick out and skip past the DCS command */ > + cmd = *seqp; > + seqp++; > + cmdwritten = 0; > + remain = len - 1; > + chunk = remain; > + > + /* Send max S6E63M0_DSI_MAX_CHUNK bytes at a time */ > + if (chunk > S6E63M0_DSI_MAX_CHUNK) > + chunk = S6E63M0_DSI_MAX_CHUNK; > + ret = mipi_dsi_dcs_write(dsi, cmd, seqp, chunk); > + if (ret < 0) { > + DRM_DEV_ERROR(dev, > + "error sending DCS command seq cmd %02x\n", > + cmd); > + return ret; > + } > + cmdwritten += chunk; > + seqp += chunk; > + > + while (cmdwritten < remain) { > + chunk = remain - cmdwritten; > + if (chunk > S6E63M0_DSI_MAX_CHUNK) > + chunk = S6E63M0_DSI_MAX_CHUNK; > + ret = mipi_dsi_dcs_write(dsi, MCS_GLOBAL_PARAM, &cmdwritten, 1); > + if (ret < 0) { > + DRM_DEV_ERROR(dev, > + "error sending CMD %02x global param %02x\n", > + cmd, cmdwritten); > + return ret; > + } > + ret = mipi_dsi_dcs_write(dsi, cmd, seqp, chunk); > + if (ret < 0) { > + DRM_DEV_ERROR(dev, > + "error sending CMD %02x chunk\n", > + cmd); > + return ret; > + } > + cmdwritten += chunk; > + seqp += chunk; > + } > + DRM_DEV_INFO(dev, "sent command %02x %02x bytes\n", > + cmd, cmdwritten); Here as well. However, otherwise it seems to work fine on my samsung-golden, so for the entire series: Tested-by: Stephan Gerhold <stephan@gerhold.net> I think it would be great to get a Tested-by from someone using the SPI transport as well. It seems to be used in s5pv210-aries.dtsi. Thanks! Stephan > + > + usleep_range(8000, 9000); > + > + return 0; > +} > + > +static int s6e63m0_dsi_probe(struct mipi_dsi_device *dsi) > +{ > + struct device *dev = &dsi->dev; > + int ret; > + > + dsi->lanes = 2; > + dsi->format = MIPI_DSI_FMT_RGB888; > + dsi->hs_rate = 349440000; > + dsi->lp_rate = 9600000; > + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | > + MIPI_DSI_MODE_EOT_PACKET | > + MIPI_DSI_MODE_VIDEO_BURST; > + > + ret = s6e63m0_probe(dev, s6e63m0_dsi_dcs_write, true); > + if (ret) > + return ret; > + > + ret = mipi_dsi_attach(dsi); > + if (ret < 0) > + s6e63m0_remove(dev); > + > + return ret; > +} > + > +static int s6e63m0_dsi_remove(struct mipi_dsi_device *dsi) > +{ > + mipi_dsi_detach(dsi); > + return s6e63m0_remove(&dsi->dev); > +} > + > +static const struct of_device_id s6e63m0_dsi_of_match[] = { > + { .compatible = "samsung,s6e63m0" }, > + { /* sentinel */ } > +}; > +MODULE_DEVICE_TABLE(of, s6e63m0_dsi_of_match); > + > +static struct mipi_dsi_driver s6e63m0_dsi_driver = { > + .probe = s6e63m0_dsi_probe, > + .remove = s6e63m0_dsi_remove, > + .driver = { > + .name = "panel-samsung-s6e63m0", > + .of_match_table = s6e63m0_dsi_of_match, > + }, > +}; > +module_mipi_dsi_driver(s6e63m0_dsi_driver); > + > +MODULE_AUTHOR("Linus Walleij <linusw@kernel.org>"); > +MODULE_DESCRIPTION("s6e63m0 LCD DSI Driver"); > +MODULE_LICENSE("GPL v2"); > diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63m0-spi.c b/drivers/gpu/drm/panel/panel-samsung-s6e63m0-spi.c > index 4082fbd75b79..0587eac52f2a 100644 > --- a/drivers/gpu/drm/panel/panel-samsung-s6e63m0-spi.c > +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63m0-spi.c > @@ -60,7 +60,7 @@ static int s6e63m0_spi_probe(struct spi_device *spi) > DRM_DEV_ERROR(dev, "spi setup failed.\n"); > return ret; > } > - return s6e63m0_probe(dev, s6e63m0_spi_dcs_write); > + return s6e63m0_probe(dev, s6e63m0_spi_dcs_write, false); > } > > static int s6e63m0_spi_remove(struct spi_device *spi) > diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c b/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c > index 610676ef8a75..c6d17e938955 100644 > --- a/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c > +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c > @@ -403,7 +403,8 @@ static int s6e63m0_backlight_register(struct s6e63m0 *ctx) > } > > int s6e63m0_probe(struct device *dev, > - int (*dcs_write)(struct device *dev, const u8 *data, size_t len)) > + int (*dcs_write)(struct device *dev, const u8 *data, size_t len), > + bool dsi_mode) > { > struct s6e63m0 *ctx; > int ret; > @@ -436,6 +437,7 @@ int s6e63m0_probe(struct device *dev, > } > > drm_panel_init(&ctx->panel, dev, &s6e63m0_drm_funcs, > + dsi_mode ? DRM_MODE_CONNECTOR_DSI : > DRM_MODE_CONNECTOR_DPI); > > ret = s6e63m0_backlight_register(ctx); > diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63m0.h b/drivers/gpu/drm/panel/panel-samsung-s6e63m0.h > index 44e31f39f211..229e23b0c97a 100644 > --- a/drivers/gpu/drm/panel/panel-samsung-s6e63m0.h > +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63m0.h > @@ -4,7 +4,9 @@ > #define _PANEL_SAMSUNG_S6E63M0_H > > int s6e63m0_probe(struct device *dev, > - int (*dcs_write)(struct device *dev, const u8 *data, size_t len)); > + int (*dcs_write)(struct device *dev, const u8 *data, > + size_t len), > + bool dsi_mode); > int s6e63m0_remove(struct device *dev); > > #endif /* _PANEL_SAMSUNG_S6E63M0_H */ > -- > 2.26.2 >
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 96e1548e475f..731e84c5a13b 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -343,6 +343,14 @@ config DRM_PANEL_SAMSUNG_S6E63M0_SPI Say Y here if you want to be able to access the Samsung S6E63M0 panel using SPI. +config DRM_PANEL_SAMSUNG_S6E63M0_DSI + tristate "Samsung S6E63M0 RGB DSI interface" + depends on DRM_MIPI_DSI + depends on DRM_PANEL_SAMSUNG_S6E63M0 + help + Say Y here if you want to be able to access the Samsung + S6E63M0 panel using DSI. + config DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01 tristate "Samsung AMS452EF01 panel with S6E88A0 DSI video mode controller" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 9cf71adfa794..14212cae3c29 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0) += panel-samsung-s6e63m0.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0_SPI) += panel-samsung-s6e63m0-spi.o +obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0_DSI) += panel-samsung-s6e63m0-dsi.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01) += panel-samsung-s6e88a0-ams452ef01.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63m0-dsi.c b/drivers/gpu/drm/panel/panel-samsung-s6e63m0-dsi.c new file mode 100644 index 000000000000..f4927a6ce26d --- /dev/null +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63m0-dsi.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DSI interface to the Samsung S6E63M0 panel. + * (C) 2019 Linus Walleij + */ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/of_device.h> + +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_print.h> + +#include "panel-samsung-s6e63m0.h" + +#define MCS_GLOBAL_PARAM 0xb0 +#define S6E63M0_DSI_MAX_CHUNK 15 /* CMD + 15 bytes max */ + +static int s6e63m0_dsi_dcs_write(struct device *dev, const u8 *data, size_t len) +{ + struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); + const u8 *seqp = data; + u8 cmd; + u8 cmdwritten; + int remain; + int chunk; + int ret; + + DRM_DEV_INFO(dev, "DSI writing dcs seq: %*ph\n", (int)len, data); + + /* Pick out and skip past the DCS command */ + cmd = *seqp; + seqp++; + cmdwritten = 0; + remain = len - 1; + chunk = remain; + + /* Send max S6E63M0_DSI_MAX_CHUNK bytes at a time */ + if (chunk > S6E63M0_DSI_MAX_CHUNK) + chunk = S6E63M0_DSI_MAX_CHUNK; + ret = mipi_dsi_dcs_write(dsi, cmd, seqp, chunk); + if (ret < 0) { + DRM_DEV_ERROR(dev, + "error sending DCS command seq cmd %02x\n", + cmd); + return ret; + } + cmdwritten += chunk; + seqp += chunk; + + while (cmdwritten < remain) { + chunk = remain - cmdwritten; + if (chunk > S6E63M0_DSI_MAX_CHUNK) + chunk = S6E63M0_DSI_MAX_CHUNK; + ret = mipi_dsi_dcs_write(dsi, MCS_GLOBAL_PARAM, &cmdwritten, 1); + if (ret < 0) { + DRM_DEV_ERROR(dev, + "error sending CMD %02x global param %02x\n", + cmd, cmdwritten); + return ret; + } + ret = mipi_dsi_dcs_write(dsi, cmd, seqp, chunk); + if (ret < 0) { + DRM_DEV_ERROR(dev, + "error sending CMD %02x chunk\n", + cmd); + return ret; + } + cmdwritten += chunk; + seqp += chunk; + } + DRM_DEV_INFO(dev, "sent command %02x %02x bytes\n", + cmd, cmdwritten); + + usleep_range(8000, 9000); + + return 0; +} + +static int s6e63m0_dsi_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + int ret; + + dsi->lanes = 2; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->hs_rate = 349440000; + dsi->lp_rate = 9600000; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | + MIPI_DSI_MODE_EOT_PACKET | + MIPI_DSI_MODE_VIDEO_BURST; + + ret = s6e63m0_probe(dev, s6e63m0_dsi_dcs_write, true); + if (ret) + return ret; + + ret = mipi_dsi_attach(dsi); + if (ret < 0) + s6e63m0_remove(dev); + + return ret; +} + +static int s6e63m0_dsi_remove(struct mipi_dsi_device *dsi) +{ + mipi_dsi_detach(dsi); + return s6e63m0_remove(&dsi->dev); +} + +static const struct of_device_id s6e63m0_dsi_of_match[] = { + { .compatible = "samsung,s6e63m0" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, s6e63m0_dsi_of_match); + +static struct mipi_dsi_driver s6e63m0_dsi_driver = { + .probe = s6e63m0_dsi_probe, + .remove = s6e63m0_dsi_remove, + .driver = { + .name = "panel-samsung-s6e63m0", + .of_match_table = s6e63m0_dsi_of_match, + }, +}; +module_mipi_dsi_driver(s6e63m0_dsi_driver); + +MODULE_AUTHOR("Linus Walleij <linusw@kernel.org>"); +MODULE_DESCRIPTION("s6e63m0 LCD DSI Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63m0-spi.c b/drivers/gpu/drm/panel/panel-samsung-s6e63m0-spi.c index 4082fbd75b79..0587eac52f2a 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e63m0-spi.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63m0-spi.c @@ -60,7 +60,7 @@ static int s6e63m0_spi_probe(struct spi_device *spi) DRM_DEV_ERROR(dev, "spi setup failed.\n"); return ret; } - return s6e63m0_probe(dev, s6e63m0_spi_dcs_write); + return s6e63m0_probe(dev, s6e63m0_spi_dcs_write, false); } static int s6e63m0_spi_remove(struct spi_device *spi) diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c b/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c index 610676ef8a75..c6d17e938955 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c @@ -403,7 +403,8 @@ static int s6e63m0_backlight_register(struct s6e63m0 *ctx) } int s6e63m0_probe(struct device *dev, - int (*dcs_write)(struct device *dev, const u8 *data, size_t len)) + int (*dcs_write)(struct device *dev, const u8 *data, size_t len), + bool dsi_mode) { struct s6e63m0 *ctx; int ret; @@ -436,6 +437,7 @@ int s6e63m0_probe(struct device *dev, } drm_panel_init(&ctx->panel, dev, &s6e63m0_drm_funcs, + dsi_mode ? DRM_MODE_CONNECTOR_DSI : DRM_MODE_CONNECTOR_DPI); ret = s6e63m0_backlight_register(ctx); diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63m0.h b/drivers/gpu/drm/panel/panel-samsung-s6e63m0.h index 44e31f39f211..229e23b0c97a 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e63m0.h +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63m0.h @@ -4,7 +4,9 @@ #define _PANEL_SAMSUNG_S6E63M0_H int s6e63m0_probe(struct device *dev, - int (*dcs_write)(struct device *dev, const u8 *data, size_t len)); + int (*dcs_write)(struct device *dev, const u8 *data, + size_t len), + bool dsi_mode); int s6e63m0_remove(struct device *dev); #endif /* _PANEL_SAMSUNG_S6E63M0_H */
This makes it possible to use the s6e63m0 panel with a DSI host, such as in the Samsung GT-I8190 (Golden) mobile phone. Cc: Stephan Gerhold <stephan@gerhold.net> Cc: Paweł Chmiel <pawel.mikolaj.chmiel@gmail.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> --- drivers/gpu/drm/panel/Kconfig | 8 ++ drivers/gpu/drm/panel/Makefile | 1 + .../gpu/drm/panel/panel-samsung-s6e63m0-dsi.c | 128 ++++++++++++++++++ .../gpu/drm/panel/panel-samsung-s6e63m0-spi.c | 2 +- drivers/gpu/drm/panel/panel-samsung-s6e63m0.c | 4 +- drivers/gpu/drm/panel/panel-samsung-s6e63m0.h | 4 +- 6 files changed, 144 insertions(+), 3 deletions(-) create mode 100644 drivers/gpu/drm/panel/panel-samsung-s6e63m0-dsi.c