diff options
Diffstat (limited to 'drivers/gpu/drm/panel')
-rw-r--r-- | drivers/gpu/drm/panel/Kconfig | 26 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-elida-kd35t133.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-novatek-nt39016.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-raydium-rm67191.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-rocktech-jh057n00900.c | 423 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-simple.c | 80 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-sitronix-st7703.c | 654 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c | 4 |
11 files changed, 734 insertions, 469 deletions
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 39055c1f0e2f..de2f2a452be5 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -283,19 +283,6 @@ config DRM_PANEL_RAYDIUM_RM68200 Say Y here if you want to enable support for Raydium RM68200 720x1280 DSI video mode panel. -config DRM_PANEL_ROCKTECH_JH057N00900 - tristate "Rocktech JH057N00900 MIPI touchscreen panel" - depends on OF - depends on DRM_MIPI_DSI - depends on BACKLIGHT_CLASS_DEVICE - help - Say Y here if you want to enable support for Rocktech JH057N00900 - MIPI DSI panel as e.g. used in the Librem 5 devkit. It has a - resolution of 720x1440 pixels, a built in backlight and touch - controller. - Touch input support is provided by the goodix driver and needs to be - selected separately. - config DRM_PANEL_RONBO_RB070D30 tristate "Ronbo Electronics RB070D30 panel" depends on OF @@ -395,6 +382,19 @@ config DRM_PANEL_SITRONIX_ST7701 ST7701 controller for 480X864 LCD panels with MIPI/RGB/SPI system interfaces. +config DRM_PANEL_SITRONIX_ST7703 + tristate "Sitronix ST7703 based MIPI touchscreen panels" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for Sitronix ST7703 based + panels, souch as Rocktech JH057N00900 MIPI DSI panel as e.g. used in + the Librem 5 devkit. It has a resolution of 720x1440 pixels, a built + in backlight and touch controller. + Touch input support is provided by the goodix driver and needs to be + selected separately. + config DRM_PANEL_SITRONIX_ST7789V tristate "Sitronix ST7789V panel" depends on OF && SPI diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index de74f282c433..e45ceac6286f 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -27,7 +27,6 @@ obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o obj-$(CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN) += panel-raspberrypi-touchscreen.o obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM67191) += panel-raydium-rm67191.o obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM68200) += panel-raydium-rm68200.o -obj-$(CONFIG_DRM_PANEL_ROCKTECH_JH057N00900) += panel-rocktech-jh057n00900.o obj-$(CONFIG_DRM_PANEL_RONBO_RB070D30) += panel-ronbo-rb070d30.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D16D0) += panel-samsung-s6d16d0.o @@ -41,6 +40,7 @@ obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o obj-$(CONFIG_DRM_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7701) += panel-sitronix-st7701.o +obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7703) += panel-sitronix-st7703.o obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o obj-$(CONFIG_DRM_PANEL_SONY_ACX424AKP) += panel-sony-acx424akp.o obj-$(CONFIG_DRM_PANEL_SONY_ACX565AKM) += panel-sony-acx565akm.o diff --git a/drivers/gpu/drm/panel/panel-elida-kd35t133.c b/drivers/gpu/drm/panel/panel-elida-kd35t133.c index 2338d22e23b1..e9675514d77b 100644 --- a/drivers/gpu/drm/panel/panel-elida-kd35t133.c +++ b/drivers/gpu/drm/panel/panel-elida-kd35t133.c @@ -52,9 +52,9 @@ static inline struct kd35t133 *panel_to_kd35t133(struct drm_panel *panel) } #define dsi_dcs_write_seq(dsi, cmd, seq...) do { \ - static const u8 d[] = { seq }; \ + static const u8 b[] = { cmd, seq }; \ int ret; \ - ret = mipi_dsi_dcs_write(dsi, cmd, d, ARRAY_SIZE(d)); \ + ret = mipi_dsi_dcs_write_buffer(dsi, b, ARRAY_SIZE(b)); \ if (ret < 0) \ return ret; \ } while (0) diff --git a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c index 5a7a31c8513e..eaa9da3ebbea 100644 --- a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c +++ b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c @@ -246,9 +246,9 @@ struct ltk050h3146w *panel_to_ltk050h3146w(struct drm_panel *panel) } #define dsi_dcs_write_seq(dsi, cmd, seq...) do { \ - static const u8 d[] = { seq }; \ + static const u8 b[] = { cmd, seq }; \ int ret; \ - ret = mipi_dsi_dcs_write(dsi, cmd, d, ARRAY_SIZE(d)); \ + ret = mipi_dsi_dcs_write_buffer(dsi, b, ARRAY_SIZE(b)); \ if (ret < 0) \ return ret; \ } while (0) diff --git a/drivers/gpu/drm/panel/panel-novatek-nt39016.c b/drivers/gpu/drm/panel/panel-novatek-nt39016.c index 79be3dc4e817..91df050ba3f6 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt39016.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt39016.c @@ -357,7 +357,7 @@ static const struct nt39016_panel_info kd035g6_info = { .width_mm = 71, .height_mm = 53, .bus_format = MEDIA_BUS_FMT_RGB888_1X24, - .bus_flags = DRM_BUS_FLAG_PIXDATA_NEGEDGE, + .bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE, }; static const struct of_device_id nt39016_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c b/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c index 11b3d01aca56..83e5aa47f0d6 100644 --- a/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c +++ b/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com * Author: Peter Ujfalusi <peter.ujfalusi@ti.com> */ diff --git a/drivers/gpu/drm/panel/panel-raydium-rm67191.c b/drivers/gpu/drm/panel/panel-raydium-rm67191.c index d001c52e0ca9..57ff2b1f6361 100644 --- a/drivers/gpu/drm/panel/panel-raydium-rm67191.c +++ b/drivers/gpu/drm/panel/panel-raydium-rm67191.c @@ -192,7 +192,7 @@ static const u32 rad_bus_formats[] = { }; static const u32 rad_bus_flags = DRM_BUS_FLAG_DE_LOW | - DRM_BUS_FLAG_PIXDATA_NEGEDGE; + DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE; struct rad_panel { struct drm_panel panel; diff --git a/drivers/gpu/drm/panel/panel-rocktech-jh057n00900.c b/drivers/gpu/drm/panel/panel-rocktech-jh057n00900.c deleted file mode 100644 index da4e373291f9..000000000000 --- a/drivers/gpu/drm/panel/panel-rocktech-jh057n00900.c +++ /dev/null @@ -1,423 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Rockteck jh057n00900 5.5" MIPI-DSI panel driver - * - * Copyright (C) Purism SPC 2019 - */ - -#include <linux/debugfs.h> -#include <linux/delay.h> -#include <linux/gpio/consumer.h> -#include <linux/media-bus-format.h> -#include <linux/mod_devicetable.h> -#include <linux/module.h> -#include <linux/regulator/consumer.h> - -#include <video/display_timing.h> -#include <video/mipi_display.h> - -#include <drm/drm_mipi_dsi.h> -#include <drm/drm_modes.h> -#include <drm/drm_panel.h> -#include <drm/drm_print.h> - -#define DRV_NAME "panel-rocktech-jh057n00900" - -/* Manufacturer specific Commands send via DSI */ -#define ST7703_CMD_ALL_PIXEL_OFF 0x22 -#define ST7703_CMD_ALL_PIXEL_ON 0x23 -#define ST7703_CMD_SETDISP 0xB2 -#define ST7703_CMD_SETRGBIF 0xB3 -#define ST7703_CMD_SETCYC 0xB4 -#define ST7703_CMD_SETBGP 0xB5 -#define ST7703_CMD_SETVCOM 0xB6 -#define ST7703_CMD_SETOTP 0xB7 -#define ST7703_CMD_SETPOWER_EXT 0xB8 -#define ST7703_CMD_SETEXTC 0xB9 -#define ST7703_CMD_SETMIPI 0xBA -#define ST7703_CMD_SETVDC 0xBC -#define ST7703_CMD_UNKNOWN0 0xBF -#define ST7703_CMD_SETSCR 0xC0 -#define ST7703_CMD_SETPOWER 0xC1 -#define ST7703_CMD_SETPANEL 0xCC -#define ST7703_CMD_SETGAMMA 0xE0 -#define ST7703_CMD_SETEQ 0xE3 -#define ST7703_CMD_SETGIP1 0xE9 -#define ST7703_CMD_SETGIP2 0xEA - -struct jh057n { - struct device *dev; - struct drm_panel panel; - struct gpio_desc *reset_gpio; - struct regulator *vcc; - struct regulator *iovcc; - bool prepared; - - struct dentry *debugfs; -}; - -static inline struct jh057n *panel_to_jh057n(struct drm_panel *panel) -{ - return container_of(panel, struct jh057n, panel); -} - -#define dsi_generic_write_seq(dsi, seq...) do { \ - static const u8 d[] = { seq }; \ - int ret; \ - ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d)); \ - if (ret < 0) \ - return ret; \ - } while (0) - -static int jh057n_init_sequence(struct jh057n *ctx) -{ - struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); - struct device *dev = ctx->dev; - int ret; - - /* - * Init sequence was supplied by the panel vendor. Most of the commands - * resemble the ST7703 but the number of parameters often don't match - * so it's likely a clone. - */ - dsi_generic_write_seq(dsi, ST7703_CMD_SETEXTC, - 0xF1, 0x12, 0x83); - dsi_generic_write_seq(dsi, ST7703_CMD_SETRGBIF, - 0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00, - 0x00, 0x00); - dsi_generic_write_seq(dsi, ST7703_CMD_SETSCR, - 0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70, - 0x00); - dsi_generic_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E); - dsi_generic_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B); - dsi_generic_write_seq(dsi, ST7703_CMD_SETCYC, 0x80); - dsi_generic_write_seq(dsi, ST7703_CMD_SETDISP, 0xF0, 0x12, 0x30); - dsi_generic_write_seq(dsi, ST7703_CMD_SETEQ, - 0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10); - dsi_generic_write_seq(dsi, ST7703_CMD_SETBGP, 0x08, 0x08); - msleep(20); - - dsi_generic_write_seq(dsi, ST7703_CMD_SETVCOM, 0x3F, 0x3F); - dsi_generic_write_seq(dsi, ST7703_CMD_UNKNOWN0, 0x02, 0x11, 0x00); - dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP1, - 0x82, 0x10, 0x06, 0x05, 0x9E, 0x0A, 0xA5, 0x12, - 0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38, - 0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64, - 0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP2, - 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13, - 0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0A, - 0xA5, 0x00, 0x00, 0x00, 0x00); - dsi_generic_write_seq(dsi, ST7703_CMD_SETGAMMA, - 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41, 0x37, - 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10, 0x11, - 0x18, 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41, - 0x37, 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10, - 0x11, 0x18); - msleep(20); - - ret = mipi_dsi_dcs_exit_sleep_mode(dsi); - if (ret < 0) { - DRM_DEV_ERROR(dev, "Failed to exit sleep mode: %d\n", ret); - return ret; - } - /* Panel is operational 120 msec after reset */ - msleep(60); - ret = mipi_dsi_dcs_set_display_on(dsi); - if (ret) - return ret; - - DRM_DEV_DEBUG_DRIVER(dev, "Panel init sequence done\n"); - return 0; -} - -static int jh057n_enable(struct drm_panel *panel) -{ - struct jh057n *ctx = panel_to_jh057n(panel); - int ret; - - ret = jh057n_init_sequence(ctx); - if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n", - ret); - return ret; - } - - return 0; -} - -static int jh057n_disable(struct drm_panel *panel) -{ - struct jh057n *ctx = panel_to_jh057n(panel); - struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); - - return mipi_dsi_dcs_set_display_off(dsi); -} - -static int jh057n_unprepare(struct drm_panel *panel) -{ - struct jh057n *ctx = panel_to_jh057n(panel); - - if (!ctx->prepared) - return 0; - - regulator_disable(ctx->iovcc); - regulator_disable(ctx->vcc); - ctx->prepared = false; - - return 0; -} - -static int jh057n_prepare(struct drm_panel *panel) -{ - struct jh057n *ctx = panel_to_jh057n(panel); - int ret; - - if (ctx->prepared) - return 0; - - DRM_DEV_DEBUG_DRIVER(ctx->dev, "Resetting the panel\n"); - ret = regulator_enable(ctx->vcc); - if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, - "Failed to enable vcc supply: %d\n", ret); - return ret; - } - ret = regulator_enable(ctx->iovcc); - if (ret < 0) { - DRM_DEV_ERROR(ctx->dev, - "Failed to enable iovcc supply: %d\n", ret); - goto disable_vcc; - } - - gpiod_set_value_cansleep(ctx->reset_gpio, 1); - usleep_range(20, 40); - gpiod_set_value_cansleep(ctx->reset_gpio, 0); - msleep(20); - - ctx->prepared = true; - - return 0; - -disable_vcc: - regulator_disable(ctx->vcc); - return ret; -} - -static const struct drm_display_mode default_mode = { - .hdisplay = 720, - .hsync_start = 720 + 90, - .hsync_end = 720 + 90 + 20, - .htotal = 720 + 90 + 20 + 20, - .vdisplay = 1440, - .vsync_start = 1440 + 20, - .vsync_end = 1440 + 20 + 4, - .vtotal = 1440 + 20 + 4 + 12, - .clock = 75276, - .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, - .width_mm = 65, - .height_mm = 130, -}; - -static int jh057n_get_modes(struct drm_panel *panel, - struct drm_connector *connector) -{ - struct jh057n *ctx = panel_to_jh057n(panel); - struct drm_display_mode *mode; - - mode = drm_mode_duplicate(connector->dev, &default_mode); - if (!mode) { - DRM_DEV_ERROR(ctx->dev, "Failed to add mode %ux%u@%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; - connector->display_info.width_mm = mode->width_mm; - connector->display_info.height_mm = mode->height_mm; - drm_mode_probed_add(connector, mode); - - return 1; -} - -static const struct drm_panel_funcs jh057n_drm_funcs = { - .disable = jh057n_disable, - .unprepare = jh057n_unprepare, - .prepare = jh057n_prepare, - .enable = jh057n_enable, - .get_modes = jh057n_get_modes, -}; - -static int allpixelson_set(void *data, u64 val) -{ - struct jh057n *ctx = data; - struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); - - DRM_DEV_DEBUG_DRIVER(ctx->dev, "Setting all pixels on\n"); - dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON); - msleep(val * 1000); - /* Reset the panel to get video back */ - drm_panel_disable(&ctx->panel); - drm_panel_unprepare(&ctx->panel); - drm_panel_prepare(&ctx->panel); - drm_panel_enable(&ctx->panel); - - return 0; -} - -DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops, NULL, - allpixelson_set, "%llu\n"); - -static void jh057n_debugfs_init(struct jh057n *ctx) -{ - ctx->debugfs = debugfs_create_dir(DRV_NAME, NULL); - - debugfs_create_file("allpixelson", 0600, ctx->debugfs, ctx, - &allpixelson_fops); -} - -static void jh057n_debugfs_remove(struct jh057n *ctx) -{ - debugfs_remove_recursive(ctx->debugfs); - ctx->debugfs = NULL; -} - -static int jh057n_probe(struct mipi_dsi_device *dsi) -{ - struct device *dev = &dsi->dev; - struct jh057n *ctx; - int ret; - - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(ctx->reset_gpio)) { - DRM_DEV_ERROR(dev, "cannot get reset gpio\n"); - return PTR_ERR(ctx->reset_gpio); - } - - mipi_dsi_set_drvdata(dsi, ctx); - - ctx->dev = dev; - - dsi->lanes = 4; - dsi->format = MIPI_DSI_FMT_RGB888; - dsi->mode_flags = MIPI_DSI_MODE_VIDEO | - MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE; - - ctx->vcc = devm_regulator_get(dev, "vcc"); - if (IS_ERR(ctx->vcc)) { - ret = PTR_ERR(ctx->vcc); - if (ret != -EPROBE_DEFER) - DRM_DEV_ERROR(dev, - "Failed to request vcc regulator: %d\n", - ret); - return ret; - } - ctx->iovcc = devm_regulator_get(dev, "iovcc"); - if (IS_ERR(ctx->iovcc)) { - ret = PTR_ERR(ctx->iovcc); - if (ret != -EPROBE_DEFER) - DRM_DEV_ERROR(dev, - "Failed to request iovcc regulator: %d\n", - ret); - return ret; - } - - drm_panel_init(&ctx->panel, dev, &jh057n_drm_funcs, - DRM_MODE_CONNECTOR_DSI); - - ret = drm_panel_of_backlight(&ctx->panel); - if (ret) - return ret; - - drm_panel_add(&ctx->panel); - - ret = mipi_dsi_attach(dsi); - if (ret < 0) { - DRM_DEV_ERROR(dev, - "mipi_dsi_attach failed (%d). Is host ready?\n", - ret); - drm_panel_remove(&ctx->panel); - return ret; - } - - DRM_DEV_INFO(dev, "%ux%u@%u %ubpp dsi %udl - ready\n", - default_mode.hdisplay, default_mode.vdisplay, - drm_mode_vrefresh(&default_mode), - mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes); - - jh057n_debugfs_init(ctx); - return 0; -} - -static void jh057n_shutdown(struct mipi_dsi_device *dsi) -{ - struct jh057n *ctx = mipi_dsi_get_drvdata(dsi); - int ret; - - ret = drm_panel_unprepare(&ctx->panel); - if (ret < 0) - DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n", - ret); - - ret = drm_panel_disable(&ctx->panel); - if (ret < 0) - DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n", - ret); -} - -static int jh057n_remove(struct mipi_dsi_device *dsi) -{ - struct jh057n *ctx = mipi_dsi_get_drvdata(dsi); - int ret; - - jh057n_shutdown(dsi); - - ret = mipi_dsi_detach(dsi); - if (ret < 0) - DRM_DEV_ERROR(&dsi->dev, "Failed to detach from DSI host: %d\n", - ret); - - drm_panel_remove(&ctx->panel); - - jh057n_debugfs_remove(ctx); - - return 0; -} - -static const struct of_device_id jh057n_of_match[] = { - { .compatible = "rocktech,jh057n00900" }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, jh057n_of_match); - -static struct mipi_dsi_driver jh057n_driver = { - .probe = jh057n_probe, - .remove = jh057n_remove, - .shutdown = jh057n_shutdown, - .driver = { - .name = DRV_NAME, - .of_match_table = jh057n_of_match, - }, -}; -module_mipi_dsi_driver(jh057n_driver); - -MODULE_AUTHOR("Guido Günther <agx@sigxcpu.org>"); -MODULE_DESCRIPTION("DRM driver for Rocktech JH057N00900 MIPI DSI panel"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 95eb2122a767..f42249b72548 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -549,6 +549,23 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) panel_simple_parse_panel_timing_node(dev, panel, &dt); } + if (desc->connector_type == DRM_MODE_CONNECTOR_LVDS) { + /* Catch common mistakes for LVDS panels. */ + WARN_ON(desc->bus_flags & + ~(DRM_BUS_FLAG_DE_LOW | + DRM_BUS_FLAG_DE_HIGH | + DRM_BUS_FLAG_DATA_MSB_TO_LSB | + DRM_BUS_FLAG_DATA_LSB_TO_MSB)); + WARN_ON(desc->bus_format != MEDIA_BUS_FMT_RGB666_1X7X3_SPWG && + desc->bus_format != MEDIA_BUS_FMT_RGB888_1X7X4_SPWG && + desc->bus_format != MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA); + WARN_ON(desc->bus_format == MEDIA_BUS_FMT_RGB666_1X7X3_SPWG && + desc->bpc != 6); + WARN_ON((desc->bus_format == MEDIA_BUS_FMT_RGB888_1X7X4_SPWG || + desc->bus_format == MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA) && + desc->bpc != 8); + } + drm_panel_init(&panel->base, dev, &panel_simple_funcs, desc->connector_type); @@ -664,7 +681,7 @@ static const struct panel_desc armadeus_st0700_adapt = { .height = 86, }, .bus_format = MEDIA_BUS_FMT_RGB666_1X18, - .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE, + .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE, }; static const struct drm_display_mode auo_b101aw03_mode = { @@ -687,6 +704,8 @@ static const struct panel_desc auo_b101aw03 = { .width = 223, .height = 125, }, + .bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, + .bus_flags = DRM_BUS_FLAG_DE_HIGH, .connector_type = DRM_MODE_CONNECTOR_LVDS, }; @@ -773,6 +792,7 @@ static const struct drm_display_mode auo_b116xw03_mode = { .vsync_start = 768 + 10, .vsync_end = 768 + 10 + 12, .vtotal = 768 + 10 + 12 + 6, + .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, }; static const struct panel_desc auo_b116xw03 = { @@ -783,6 +803,12 @@ static const struct panel_desc auo_b116xw03 = { .width = 256, .height = 144, }, + .delay = { + .enable = 400, + }, + .bus_flags = DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE, + .bus_format = MEDIA_BUS_FMT_RGB666_1X18, + .connector_type = DRM_MODE_CONNECTOR_eDP, }; static const struct drm_display_mode auo_b133xtn01_mode = { @@ -1320,7 +1346,7 @@ static const struct panel_desc cdtech_s070pws19hp_fc21 = { .height = 86, }, .bus_format = MEDIA_BUS_FMT_RGB666_1X18, - .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE, + .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE, .connector_type = DRM_MODE_CONNECTOR_DPI, }; @@ -1347,7 +1373,7 @@ static const struct panel_desc cdtech_s070swv29hg_dc44 = { .height = 86, }, .bus_format = MEDIA_BUS_FMT_RGB666_1X18, - .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE, + .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE, .connector_type = DRM_MODE_CONNECTOR_DPI, }; @@ -1395,6 +1421,8 @@ static const struct panel_desc chunghwa_claa070wp03xg = { .width = 94, .height = 150, }, + .bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, + .bus_flags = DRM_BUS_FLAG_DE_HIGH, .connector_type = DRM_MODE_CONNECTOR_LVDS, }; @@ -1418,6 +1446,8 @@ static const struct panel_desc chunghwa_claa101wa01a = { .width = 220, .height = 120, }, + .bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, + .bus_flags = DRM_BUS_FLAG_DE_HIGH, .connector_type = DRM_MODE_CONNECTOR_LVDS, }; @@ -1441,6 +1471,8 @@ static const struct panel_desc chunghwa_claa101wb01 = { .width = 223, .height = 125, }, + .bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, + .bus_flags = DRM_BUS_FLAG_DE_HIGH, .connector_type = DRM_MODE_CONNECTOR_LVDS, }; @@ -1552,7 +1584,7 @@ static const struct panel_desc edt_et035012dm6 = { .height = 52, }, .bus_format = MEDIA_BUS_FMT_RGB888_1X24, - .bus_flags = DRM_BUS_FLAG_DE_LOW | DRM_BUS_FLAG_PIXDATA_NEGEDGE, + .bus_flags = DRM_BUS_FLAG_DE_LOW | DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE, }; static const struct drm_display_mode edt_etm043080dh6gp_mode = { @@ -1631,7 +1663,7 @@ static const struct panel_desc edt_et057090dhu = { }, .bus_format = MEDIA_BUS_FMT_RGB666_1X18, .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE, - .connector_type = DRM_MODE_CONNECTOR_LVDS, + .connector_type = DRM_MODE_CONNECTOR_DPI, }; static const struct drm_display_mode edt_etm0700g0dh6_mode = { @@ -1695,7 +1727,7 @@ static const struct panel_desc evervision_vgg804821 = { .height = 64, }, .bus_format = MEDIA_BUS_FMT_RGB888_1X24, - .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_NEGEDGE, + .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE, }; static const struct drm_display_mode foxlink_fl500wvr00_a0t_mode = { @@ -1743,7 +1775,7 @@ static const struct panel_desc frida_frd350h54004 = { .height = 64, }, .bus_format = MEDIA_BUS_FMT_RGB888_1X24, - .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE, + .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE, .connector_type = DRM_MODE_CONNECTOR_DPI, }; @@ -1814,7 +1846,7 @@ static const struct panel_desc giantplus_gpm940b0 = { .height = 45, }, .bus_format = MEDIA_BUS_FMT_RGB888_3X8, - .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_NEGEDGE, + .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE, }; static const struct display_timing hannstar_hsd070pww1_timing = { @@ -2114,6 +2146,8 @@ static const struct panel_desc innolux_n156bge_l21 = { .width = 344, .height = 193, }, + .bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, + .bus_flags = DRM_BUS_FLAG_DE_HIGH, .connector_type = DRM_MODE_CONNECTOR_LVDS, }; @@ -2246,7 +2280,7 @@ static const struct panel_desc koe_tx26d202vm0bwa = { .disable = 1000, }, .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, - .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE, + .bus_flags = DRM_BUS_FLAG_DE_HIGH, .connector_type = DRM_MODE_CONNECTOR_LVDS, }; @@ -2338,7 +2372,7 @@ static const struct drm_display_mode lg_lb070wv8_mode = { static const struct panel_desc lg_lb070wv8 = { .modes = &lg_lb070wv8_mode, .num_modes = 1, - .bpc = 16, + .bpc = 8, .size = { .width = 151, .height = 91, @@ -2487,9 +2521,7 @@ static const struct panel_desc logictechno_lt170410_2whc = { .height = 136, }, .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, - .bus_flags = DRM_BUS_FLAG_DE_HIGH | - DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE | - DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE, + .bus_flags = DRM_BUS_FLAG_DE_HIGH, .connector_type = DRM_MODE_CONNECTOR_LVDS, }; @@ -2860,7 +2892,7 @@ static const struct panel_desc ortustech_com37h3m = { .height = 75, /* 74.88mm */ }, .bus_format = MEDIA_BUS_FMT_RGB888_1X24, - .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE | + .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE | DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE, }; @@ -3061,6 +3093,8 @@ static const struct panel_desc samsung_ltn101nt05 = { .width = 223, .height = 125, }, + .bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, + .bus_flags = DRM_BUS_FLAG_DE_HIGH, .connector_type = DRM_MODE_CONNECTOR_LVDS, }; @@ -3106,7 +3140,7 @@ static const struct panel_desc satoz_sat050at40h12r2 = { .width = 108, .height = 65, }, - .bus_format = MEDIA_BUS_FMT_RGB888_1X24, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, .connector_type = DRM_MODE_CONNECTOR_LVDS, }; @@ -3157,7 +3191,7 @@ static const struct panel_desc sharp_lq070y3dg3b = { .height = 91, /* 91.4mm */ }, .bus_format = MEDIA_BUS_FMT_RGB888_1X24, - .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE | + .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE | DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE, }; @@ -3260,7 +3294,7 @@ static const struct panel_desc sharp_ls020b1dd01d = { }, .bus_format = MEDIA_BUS_FMT_RGB565_1X16, .bus_flags = DRM_BUS_FLAG_DE_HIGH - | DRM_BUS_FLAG_PIXDATA_NEGEDGE + | DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE | DRM_BUS_FLAG_SHARP_SIGNALS, }; @@ -3308,7 +3342,7 @@ static const struct panel_desc starry_kr070pe2t = { }, .bus_format = MEDIA_BUS_FMT_RGB888_1X24, .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE, - .connector_type = DRM_MODE_CONNECTOR_LVDS, + .connector_type = DRM_MODE_CONNECTOR_DPI, }; static const struct drm_display_mode starry_kr122ea0sra_mode = { @@ -3359,7 +3393,7 @@ static const struct panel_desc tfc_s9700rtwv43tr_01b = { .height = 90, }, .bus_format = MEDIA_BUS_FMT_RGB888_1X24, - .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE, + .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE, }; static const struct display_timing tianma_tm070jdhg30_timing = { @@ -3448,7 +3482,7 @@ static const struct panel_desc ti_nspire_cx_lcd_panel = { .height = 49, }, .bus_format = MEDIA_BUS_FMT_RGB888_1X24, - .bus_flags = DRM_BUS_FLAG_PIXDATA_NEGEDGE, + .bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE, }; static const struct drm_display_mode ti_nspire_classic_lcd_mode[] = { @@ -3477,7 +3511,7 @@ static const struct panel_desc ti_nspire_classic_lcd_panel = { }, /* This is the grayscale bus format */ .bus_format = MEDIA_BUS_FMT_Y8_1X8, - .bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE, + .bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE, }; static const struct drm_display_mode toshiba_lt089ac29000_mode = { @@ -3500,7 +3534,7 @@ static const struct panel_desc toshiba_lt089ac29000 = { .height = 116, }, .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, - .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE, + .bus_flags = DRM_BUS_FLAG_DE_HIGH, .connector_type = DRM_MODE_CONNECTOR_LVDS, }; @@ -3606,7 +3640,7 @@ static const struct panel_desc vl050_8048nt_c01 = { .height = 76, }, .bus_format = MEDIA_BUS_FMT_RGB888_1X24, - .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE, + .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE, }; static const struct drm_display_mode winstar_wf35ltiacd_mode = { diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7703.c b/drivers/gpu/drm/panel/panel-sitronix-st7703.c new file mode 100644 index 000000000000..8996ced2b721 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-sitronix-st7703.c @@ -0,0 +1,654 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for panels based on Sitronix ST7703 controller, souch as: + * + * - Rocktech jh057n00900 5.5" MIPI-DSI panel + * + * Copyright (C) Purism SPC 2019 + */ + +#include <linux/debugfs.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/media-bus-format.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/regulator/consumer.h> + +#include <video/display_timing.h> +#include <video/mipi_display.h> + +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> +#include <drm/drm_print.h> + +#define DRV_NAME "panel-sitronix-st7703" + +/* Manufacturer specific Commands send via DSI */ +#define ST7703_CMD_ALL_PIXEL_OFF 0x22 +#define ST7703_CMD_ALL_PIXEL_ON 0x23 +#define ST7703_CMD_SETDISP 0xB2 +#define ST7703_CMD_SETRGBIF 0xB3 +#define ST7703_CMD_SETCYC 0xB4 +#define ST7703_CMD_SETBGP 0xB5 +#define ST7703_CMD_SETVCOM 0xB6 +#define ST7703_CMD_SETOTP 0xB7 +#define ST7703_CMD_SETPOWER_EXT 0xB8 +#define ST7703_CMD_SETEXTC 0xB9 +#define ST7703_CMD_SETMIPI 0xBA +#define ST7703_CMD_SETVDC 0xBC +#define ST7703_CMD_UNKNOWN_BF 0xBF +#define ST7703_CMD_SETSCR 0xC0 +#define ST7703_CMD_SETPOWER 0xC1 +#define ST7703_CMD_SETPANEL 0xCC +#define ST7703_CMD_UNKNOWN_C6 0xC6 +#define ST7703_CMD_SETGAMMA 0xE0 +#define ST7703_CMD_SETEQ 0xE3 +#define ST7703_CMD_SETGIP1 0xE9 +#define ST7703_CMD_SETGIP2 0xEA + +struct st7703 { + struct device *dev; + struct drm_panel panel; + struct gpio_desc *reset_gpio; + struct regulator *vcc; + struct regulator *iovcc; + bool prepared; + + struct dentry *debugfs; + const struct st7703_panel_desc *desc; +}; + +struct st7703_panel_desc { + const struct drm_display_mode *mode; + unsigned int lanes; + unsigned long mode_flags; + enum mipi_dsi_pixel_format format; + int (*init_sequence)(struct st7703 *ctx); +}; + +static inline struct st7703 *panel_to_st7703(struct drm_panel *panel) +{ + return container_of(panel, struct st7703, panel); +} + +#define dsi_generic_write_seq(dsi, seq...) do { \ + static const u8 d[] = { seq }; \ + int ret; \ + ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d)); \ + if (ret < 0) \ + return ret; \ + } while (0) + +static int jh057n_init_sequence(struct st7703 *ctx) +{ + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + + /* + * Init sequence was supplied by the panel vendor. Most of the commands + * resemble the ST7703 but the number of parameters often don't match + * so it's likely a clone. + */ + dsi_generic_write_seq(dsi, ST7703_CMD_SETEXTC, + 0xF1, 0x12, 0x83); + dsi_generic_write_seq(dsi, ST7703_CMD_SETRGBIF, + 0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00, + 0x00, 0x00); + dsi_generic_write_seq(dsi, ST7703_CMD_SETSCR, + 0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70, + 0x00); + dsi_generic_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E); + dsi_generic_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B); + dsi_generic_write_seq(dsi, ST7703_CMD_SETCYC, 0x80); + dsi_generic_write_seq(dsi, ST7703_CMD_SETDISP, 0xF0, 0x12, 0x30); + dsi_generic_write_seq(dsi, ST7703_CMD_SETEQ, + 0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10); + dsi_generic_write_seq(dsi, ST7703_CMD_SETBGP, 0x08, 0x08); + msleep(20); + + dsi_generic_write_seq(dsi, ST7703_CMD_SETVCOM, 0x3F, 0x3F); + dsi_generic_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00); + dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP1, + 0x82, 0x10, 0x06, 0x05, 0x9E, 0x0A, 0xA5, 0x12, + 0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38, + 0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64, + 0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP2, + 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13, + 0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0A, + 0xA5, 0x00, 0x00, 0x00, 0x00); + dsi_generic_write_seq(dsi, ST7703_CMD_SETGAMMA, + 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41, 0x37, + 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10, 0x11, + 0x18, 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41, + 0x37, 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10, + 0x11, 0x18); + + return 0; +} + +static const struct drm_display_mode jh057n00900_mode = { + .hdisplay = 720, + .hsync_start = 720 + 90, + .hsync_end = 720 + 90 + 20, + .htotal = 720 + 90 + 20 + 20, + .vdisplay = 1440, + .vsync_start = 1440 + 20, + .vsync_end = 1440 + 20 + 4, + .vtotal = 1440 + 20 + 4 + 12, + .clock = 75276, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + .width_mm = 65, + .height_mm = 130, +}; + +struct st7703_panel_desc jh057n00900_panel_desc = { + .mode = &jh057n00900_mode, + .lanes = 4, + .mode_flags = MIPI_DSI_MODE_VIDEO | + MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE, + .format = MIPI_DSI_FMT_RGB888, + .init_sequence = jh057n_init_sequence, +}; + +#define dsi_dcs_write_seq(dsi, cmd, seq...) do { \ + static const u8 d[] = { seq }; \ + int ret; \ + ret = mipi_dsi_dcs_write(dsi, cmd, d, ARRAY_SIZE(d)); \ + if (ret < 0) \ + return ret; \ + } while (0) + + +static int xbd599_init_sequence(struct st7703 *ctx) +{ + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + + /* + * Init sequence was supplied by the panel vendor. + */ + + /* Magic sequence to unlock user commands below. */ + dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xF1, 0x12, 0x83); + + dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI, + 0x33, /* VC_main = 0, Lane_Number = 3 (4 lanes) */ + 0x81, /* DSI_LDO_SEL = 1.7V, RTERM = 90 Ohm */ + 0x05, /* IHSRX = x6 (Low High Speed driving ability) */ + 0xF9, /* TX_CLK_SEL = fDSICLK/16 */ + 0x0E, /* HFP_OSC (min. HFP number in DSI mode) */ + 0x0E, /* HBP_OSC (min. HBP number in DSI mode) */ + /* The rest is undocumented in ST7703 datasheet */ + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x44, 0x25, 0x00, 0x91, 0x0a, 0x00, 0x00, 0x02, + 0x4F, 0x11, 0x00, 0x00, 0x37); + + dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT, + 0x25, /* PCCS = 2, ECP_DC_DIV = 1/4 HSYNC */ + 0x22, /* DT = 15ms XDK_ECP = x2 */ + 0x20, /* PFM_DC_DIV = /1 */ + 0x03 /* ECP_SYNC_EN = 1, VGX_SYNC_EN = 1 */); + + /* RGB I/F porch timing */ + dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF, + 0x10, /* VBP_RGB_GEN */ + 0x10, /* VFP_RGB_GEN */ + 0x05, /* DE_BP_RGB_GEN */ + 0x05, /* DE_FP_RGB_GEN */ + /* The rest is undocumented in ST7703 datasheet */ + 0x03, 0xFF, + 0x00, 0x00, + 0x00, 0x00); + + /* Source driving settings. */ + dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR, + 0x73, /* N_POPON */ + 0x73, /* N_NOPON */ + 0x50, /* I_POPON */ + 0x50, /* I_NOPON */ + 0x00, /* SCR[31,24] */ + 0xC0, /* SCR[23,16] */ + 0x08, /* SCR[15,8] */ + 0x70, /* SCR[7,0] */ + 0x00 /* Undocumented */); + + /* NVDDD_SEL = -1.8V, VDDD_SEL = out of range (possibly 1.9V?) */ + dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E); + + /* + * SS_PANEL = 1 (reverse scan), GS_PANEL = 0 (normal scan) + * REV_PANEL = 1 (normally black panel), BGR_PANEL = 1 (BGR) + */ + dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B); + + /* Zig-Zag Type C column inversion. */ + dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80); + + /* Set display resolution. */ + dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP, + 0xF0, /* NL = 240 */ + 0x12, /* RES_V_LSB = 0, BLK_CON = VSSD, + * RESO_SEL = 720RGB + */ + 0xF0 /* WHITE_GND_EN = 1 (GND), + * WHITE_FRAME_SEL = 7 frames, + * ISC = 0 frames + */); + + dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ, + 0x00, /* PNOEQ */ + 0x00, /* NNOEQ */ + 0x0B, /* PEQGND */ + 0x0B, /* NEQGND */ + 0x10, /* PEQVCI */ + 0x10, /* NEQVCI */ + 0x00, /* PEQVCI1 */ + 0x00, /* NEQVCI1 */ + 0x00, /* reserved */ + 0x00, /* reserved */ + 0xFF, /* reserved */ + 0x00, /* reserved */ + 0xC0, /* ESD_DET_DATA_WHITE = 1, ESD_WHITE_EN = 1 */ + 0x10 /* SLPIN_OPTION = 1 (no need vsync after sleep-in) + * VEDIO_NO_CHECK_EN = 0 + * ESD_WHITE_GND_EN = 0 + * ESD_DET_TIME_SEL = 0 frames + */); + + /* Undocumented command. */ + dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_C6, 0x01, 0x00, 0xFF, 0xFF, 0x00); + + dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER, + 0x74, /* VBTHS, VBTLS: VGH = 17V, VBL = -11V */ + 0x00, /* FBOFF_VGH = 0, FBOFF_VGL = 0 */ + 0x32, /* VRP */ + 0x32, /* VRN */ + 0x77, /* reserved */ + 0xF1, /* APS = 1 (small), + * VGL_DET_EN = 1, VGH_DET_EN = 1, + * VGL_TURBO = 1, VGH_TURBO = 1 + */ + 0xFF, /* VGH1_L_DIV, VGL1_L_DIV (1.5MHz) */ + 0xFF, /* VGH1_R_DIV, VGL1_R_DIV (1.5MHz) */ + 0xCC, /* VGH2_L_DIV, VGL2_L_DIV (2.6MHz) */ + 0xCC, /* VGH2_R_DIV, VGL2_R_DIV (2.6MHz) */ + 0x77, /* VGH3_L_DIV, VGL3_L_DIV (4.5MHz) */ + 0x77 /* VGH3_R_DIV, VGL3_R_DIV (4.5MHz) */); + + /* Reference voltage. */ + dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP, + 0x07, /* VREF_SEL = 4.2V */ + 0x07 /* NVREF_SEL = 4.2V */); + msleep(20); + + dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM, + 0x2C, /* VCOMDC_F = -0.67V */ + 0x2C /* VCOMDC_B = -0.67V */); + + /* Undocumented command. */ + dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00); + + /* This command is to set forward GIP timing. */ + dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1, + 0x82, 0x10, 0x06, 0x05, 0xA2, 0x0A, 0xA5, 0x12, + 0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38, + 0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64, + 0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + + /* This command is to set backward GIP timing. */ + dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2, + 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13, + 0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0A, + 0xA5, 0x00, 0x00, 0x00, 0x00); + + /* Adjust the gamma characteristics of the panel. */ + dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA, + 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41, 0x35, + 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12, 0x12, + 0x18, 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41, + 0x35, 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12, + 0x12, 0x18); + + return 0; +} + +static const struct drm_display_mode xbd599_mode = { + .hdisplay = 720, + .hsync_start = 720 + 40, + .hsync_end = 720 + 40 + 40, + .htotal = 720 + 40 + 40 + 40, + .vdisplay = 1440, + .vsync_start = 1440 + 18, + .vsync_end = 1440 + 18 + 10, + .vtotal = 1440 + 18 + 10 + 17, + .clock = 69000, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + .width_mm = 68, + .height_mm = 136, +}; + +static const struct st7703_panel_desc xbd599_desc = { + .mode = &xbd599_mode, + .lanes = 4, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE, + .format = MIPI_DSI_FMT_RGB888, + .init_sequence = xbd599_init_sequence, +}; + +static int st7703_enable(struct drm_panel *panel) +{ + struct st7703 *ctx = panel_to_st7703(panel); + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + int ret; + + ret = ctx->desc->init_sequence(ctx); + if (ret < 0) { + DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n", + ret); + return ret; + } + + msleep(20); + + ret = mipi_dsi_dcs_exit_sleep_mode(dsi); + if (ret < 0) { + DRM_DEV_ERROR(ctx->dev, "Failed to exit sleep mode: %d\n", ret); + return ret; + } + + /* Panel is operational 120 msec after reset */ + msleep(60); + + ret = mipi_dsi_dcs_set_display_on(dsi); + if (ret) + return ret; + + DRM_DEV_DEBUG_DRIVER(ctx->dev, "Panel init sequence done\n"); + + return 0; +} + +static int st7703_disable(struct drm_panel *panel) +{ + struct st7703 *ctx = panel_to_st7703(panel); + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + int ret; + + ret = mipi_dsi_dcs_set_display_off(dsi); + if (ret < 0) + DRM_DEV_ERROR(ctx->dev, + "Failed to turn off the display: %d\n", ret); + + ret = mipi_dsi_dcs_enter_sleep_mode(dsi); + if (ret < 0) + DRM_DEV_ERROR(ctx->dev, + "Failed to enter sleep mode: %d\n", ret); + + return 0; +} + +static int st7703_unprepare(struct drm_panel *panel) +{ + struct st7703 *ctx = panel_to_st7703(panel); + + if (!ctx->prepared) + return 0; + + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_disable(ctx->iovcc); + regulator_disable(ctx->vcc); + ctx->prepared = false; + + return 0; +} + +static int st7703_prepare(struct drm_panel *panel) +{ + struct st7703 *ctx = panel_to_st7703(panel); + int ret; + + if (ctx->prepared) + return 0; + + DRM_DEV_DEBUG_DRIVER(ctx->dev, "Resetting the panel\n"); + ret = regulator_enable(ctx->vcc); + if (ret < 0) { + DRM_DEV_ERROR(ctx->dev, + "Failed to enable vcc supply: %d\n", ret); + return ret; + } + ret = regulator_enable(ctx->iovcc); + if (ret < 0) { + DRM_DEV_ERROR(ctx->dev, + "Failed to enable iovcc supply: %d\n", ret); + goto disable_vcc; + } + + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + usleep_range(20, 40); + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + msleep(20); + + ctx->prepared = true; + + return 0; + +disable_vcc: + regulator_disable(ctx->vcc); + return ret; +} + +static int st7703_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + struct st7703 *ctx = panel_to_st7703(panel); + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, ctx->desc->mode); + if (!mode) { + DRM_DEV_ERROR(ctx->dev, "Failed to add mode %ux%u@%u\n", + ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay, + drm_mode_vrefresh(ctx->desc->mode)); + return -ENOMEM; + } + + drm_mode_set_name(mode); + + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + connector->display_info.width_mm = mode->width_mm; + connector->display_info.height_mm = mode->height_mm; + drm_mode_probed_add(connector, mode); + + return 1; +} + +static const struct drm_panel_funcs st7703_drm_funcs = { + .disable = st7703_disable, + .unprepare = st7703_unprepare, + .prepare = st7703_prepare, + .enable = st7703_enable, + .get_modes = st7703_get_modes, +}; + +static int allpixelson_set(void *data, u64 val) +{ + struct st7703 *ctx = data; + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + + DRM_DEV_DEBUG_DRIVER(ctx->dev, "Setting all pixels on\n"); + dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON); + msleep(val * 1000); + /* Reset the panel to get video back */ + drm_panel_disable(&ctx->panel); + drm_panel_unprepare(&ctx->panel); + drm_panel_prepare(&ctx->panel); + drm_panel_enable(&ctx->panel); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops, NULL, + allpixelson_set, "%llu\n"); + +static void st7703_debugfs_init(struct st7703 *ctx) +{ + ctx->debugfs = debugfs_create_dir(DRV_NAME, NULL); + + debugfs_create_file("allpixelson", 0600, ctx->debugfs, ctx, + &allpixelson_fops); +} + +static void st7703_debugfs_remove(struct st7703 *ctx) +{ + debugfs_remove_recursive(ctx->debugfs); + ctx->debugfs = NULL; +} + +static int st7703_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct st7703 *ctx; + int ret; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(ctx->reset_gpio)) { + DRM_DEV_ERROR(dev, "cannot get reset gpio\n"); + return PTR_ERR(ctx->reset_gpio); + } + + mipi_dsi_set_drvdata(dsi, ctx); + + ctx->dev = dev; + ctx->desc = of_device_get_match_data(dev); + + dsi->mode_flags = ctx->desc->mode_flags; + dsi->format = ctx->desc->format; + dsi->lanes = ctx->desc->lanes; + + ctx->vcc = devm_regulator_get(dev, "vcc"); + if (IS_ERR(ctx->vcc)) { + ret = PTR_ERR(ctx->vcc); + if (ret != -EPROBE_DEFER) + DRM_DEV_ERROR(dev, + "Failed to request vcc regulator: %d\n", + ret); + return ret; + } + ctx->iovcc = devm_regulator_get(dev, "iovcc"); + if (IS_ERR(ctx->iovcc)) { + ret = PTR_ERR(ctx->iovcc); + if (ret != -EPROBE_DEFER) + DRM_DEV_ERROR(dev, + "Failed to request iovcc regulator: %d\n", + ret); + return ret; + } + + drm_panel_init(&ctx->panel, dev, &st7703_drm_funcs, + DRM_MODE_CONNECTOR_DSI); + + ret = drm_panel_of_backlight(&ctx->panel); + if (ret) + return ret; + + drm_panel_add(&ctx->panel); + + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + DRM_DEV_ERROR(dev, + "mipi_dsi_attach failed (%d). Is host ready?\n", + ret); + drm_panel_remove(&ctx->panel); + return ret; + } + + DRM_DEV_INFO(dev, "%ux%u@%u %ubpp dsi %udl - ready\n", + ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay, + drm_mode_vrefresh(ctx->desc->mode), + mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes); + + st7703_debugfs_init(ctx); + return 0; +} + +static void st7703_shutdown(struct mipi_dsi_device *dsi) +{ + struct st7703 *ctx = mipi_dsi_get_drvdata(dsi); + int ret; + + ret = drm_panel_unprepare(&ctx->panel); + if (ret < 0) + DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n", + ret); + + ret = drm_panel_disable(&ctx->panel); + if (ret < 0) + DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n", + ret); +} + +static int st7703_remove(struct mipi_dsi_device *dsi) +{ + struct st7703 *ctx = mipi_dsi_get_drvdata(dsi); + int ret; + + st7703_shutdown(dsi); + + ret = mipi_dsi_detach(dsi); + if (ret < 0) + DRM_DEV_ERROR(&dsi->dev, "Failed to detach from DSI host: %d\n", + ret); + + drm_panel_remove(&ctx->panel); + + st7703_debugfs_remove(ctx); + + return 0; +} + +static const struct of_device_id st7703_of_match[] = { + { .compatible = "rocktech,jh057n00900", .data = &jh057n00900_panel_desc }, + { .compatible = "xingbangda,xbd599", .data = &xbd599_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, st7703_of_match); + +static struct mipi_dsi_driver st7703_driver = { + .probe = st7703_probe, + .remove = st7703_remove, + .shutdown = st7703_shutdown, + .driver = { + .name = DRV_NAME, + .of_match_table = st7703_of_match, + }, +}; +module_mipi_dsi_driver(st7703_driver); + +MODULE_AUTHOR("Guido Günther <agx@sigxcpu.org>"); +MODULE_DESCRIPTION("DRM driver for Sitronix ST7703 based MIPI DSI panels"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c b/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c index 8a3b2f906e63..06341deb60ca 100644 --- a/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c +++ b/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c @@ -62,9 +62,9 @@ static inline struct xpp055c272 *panel_to_xpp055c272(struct drm_panel *panel) } #define dsi_generic_write_seq(dsi, cmd, seq...) do { \ - static const u8 d[] = { seq }; \ + static const u8 b[] = { cmd, seq }; \ int ret; \ - ret = mipi_dsi_dcs_write(dsi, cmd, d, ARRAY_SIZE(d)); \ + ret = mipi_dsi_dcs_write_buffer(dsi, b, ARRAY_SIZE(b)); \ if (ret < 0) \ return ret; \ } while (0) |