From 884d6a0b558c9c31fdf0d950bd07a2c804876445 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Tue, 8 Jul 2014 21:32:11 +0900 Subject: [PATCH 01/30] drm/dsi: Flag for non-continuous clock behavior As per section 5.6.1 of the DSI specification, all DSI transmitters must support continuous clock behavior on the clock lane, while non-continuous mode support is only optional. Add a flag that allows devices to indicate that they support non-continuous clock mode so host drivers can adapt their behavior accordingly. Signed-off-by: Alexandre Courbot Signed-off-by: Thierry Reding --- include/drm/drm_mipi_dsi.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 944f33f8ba38..efa1b552adc5 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -94,6 +94,8 @@ void mipi_dsi_host_unregister(struct mipi_dsi_host *host); #define MIPI_DSI_MODE_VSYNC_FLUSH BIT(8) /* disable EoT packets in HS mode */ #define MIPI_DSI_MODE_EOT_PACKET BIT(9) +/* device supports non-continuous clock behavior (DSI spec 5.6.1) */ +#define MIPI_DSI_CLOCK_NON_CONTINUOUS BIT(10) enum mipi_dsi_pixel_format { MIPI_DSI_FMT_RGB888, From 937ca28445644cb9a5baf95b60b3482f2b751023 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 13 Jun 2014 14:06:11 +0100 Subject: [PATCH 02/30] drm/panel: consolidate unnecessary explicit dependencies DRM_PANEL_LD9040 and DRM_PANEL_S6E8AA0 both explicitly depended on DRM_PANEL && DRM, whereas DRM_PANEL_SIMPLE relies upon the dependency on the menu. We do not need to use explicit dependencies if we make the menu depend on DRM_PANEL && DRM - this will implicitly make each entry in the menu depend on DRM_PANEL && DRM without this needing to be explicitly stated against every entry. Signed-off-by: Russell King Acked-by: Arnd Bergmann Signed-off-by: Thierry Reding --- drivers/gpu/drm/panel/Kconfig | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 4ec874da5668..d83958d39f43 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -5,7 +5,7 @@ config DRM_PANEL Panel registration and lookup framework. menu "Display Panels" - depends on DRM_PANEL + depends on DRM && DRM_PANEL config DRM_PANEL_SIMPLE tristate "support for simple panels" @@ -18,14 +18,12 @@ config DRM_PANEL_SIMPLE config DRM_PANEL_LD9040 tristate "LD9040 RGB/SPI panel" - depends on DRM && DRM_PANEL depends on OF select SPI select VIDEOMODE_HELPERS config DRM_PANEL_S6E8AA0 tristate "S6E8AA0 DSI video mode panel" - depends on DRM && DRM_PANEL depends on OF select DRM_MIPI_DSI select VIDEOMODE_HELPERS From 50d5ed399262f066f07daf3b6ab20be5d5b56ba7 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 13 Jun 2014 14:06:16 +0100 Subject: [PATCH 03/30] drm/panel: make DRM_PANEL_LD9040 depend on SPI Rather than DRM_PANEL_LD9040 selecting SPI, which then results in an increase in the probability of Kconf reporting circular dependencies (we're one "select" away from that right now), make this depend on SPI instead. This is akin to having some driver select DRM. Having some drivers depend on a subsystem, and other drivers select a subsystem is a recipe for circular dependencies, and there's really no need for it. The potential circular dependency (which can be caused today by the addition of selecting DRM_PANEL from DRM_IMX_LDB) is: symbol DMADEVICES is selected by SAMSUNG_DMADEV symbol SAMSUNG_DMADEV is selected by S3C64XX_PL080 symbol S3C64XX_PL080 is selected by SPI_S3C64XX symbol SPI_S3C64XX depends on SPI symbol SPI is selected by DRM_PANEL_LD9040 symbol DRM_PANEL_LD9040 depends on DRM_PANEL symbol DRM_PANEL is selected by DRM_IMX_LDB symbol DRM_IMX_LDB depends on MFD_SYSCON symbol MFD_SYSCON is selected by POWER_RESET_KEYSTONE symbol POWER_RESET_KEYSTONE depends on POWER_SUPPLY symbol POWER_SUPPLY is selected by HID_SONY symbol HID_SONY depends on NEW_LEDS symbol NEW_LEDS is selected by BACKLIGHT_ADP8860 symbol BACKLIGHT_ADP8860 depends on BACKLIGHT_CLASS_DEVICE symbol BACKLIGHT_CLASS_DEVICE is selected by FB_MX3 symbol FB_MX3 depends on MX3_IPU symbol MX3_IPU depends on DMADEVICES Acked-by: Arnd Bergmann Signed-off-by: Russell King Signed-off-by: Thierry Reding --- drivers/gpu/drm/panel/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index d83958d39f43..bee9f72b3a93 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -18,8 +18,7 @@ config DRM_PANEL_SIMPLE config DRM_PANEL_LD9040 tristate "LD9040 RGB/SPI panel" - depends on OF - select SPI + depends on OF && SPI select VIDEOMODE_HELPERS config DRM_PANEL_S6E8AA0 From 5e4cc278625d789b72a3a74f6b90362d2436f6a5 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Tue, 8 Jul 2014 21:32:12 +0900 Subject: [PATCH 04/30] drm/panel: Set non-continuous clock flag on supporting panels The LG LD070WX3-SL01 and Panasonic VVX10F004B00 are DSI support non-continuous clock mode. Set the MIPI_DSI_CLOCK_NON_CONTINUOUS to their definition so host drivers become aware of this capability. Signed-off-by: Alexandre Courbot Signed-off-by: Thierry Reding --- drivers/gpu/drm/panel/panel-simple.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index a25136132c31..869a84e31ddd 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -545,7 +545,7 @@ static const struct panel_desc_dsi lg_ld070wx3_sl01 = { .height = 151, }, }, - .flags = MIPI_DSI_MODE_VIDEO, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_CLOCK_NON_CONTINUOUS, .format = MIPI_DSI_FMT_RGB888, .lanes = 4, }; @@ -599,7 +599,8 @@ static const struct panel_desc_dsi panasonic_vvx10f004b00 = { .height = 136, }, }, - .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | + MIPI_DSI_CLOCK_NON_CONTINUOUS, .format = MIPI_DSI_FMT_RGB888, .lanes = 4, }; From 102932b0e474bb33061e88bcf5d83e66f10c1da2 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Thu, 5 Jun 2014 15:53:32 +0200 Subject: [PATCH 05/30] drm/panel: add support for Foxlink FL500WVR00-A0T panel This panel is used by Atmel's SAMA5D3 Evaluation Kits (sama5d3xek) and supported by the simple-panel driver. Signed-off-by: Boris BREZILLON Signed-off-by: Thierry Reding --- .../bindings/panel/foxlink,fl500wvr00-a0t.txt | 7 ++++++ drivers/gpu/drm/panel/panel-simple.c | 25 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 Documentation/devicetree/bindings/panel/foxlink,fl500wvr00-a0t.txt diff --git a/Documentation/devicetree/bindings/panel/foxlink,fl500wvr00-a0t.txt b/Documentation/devicetree/bindings/panel/foxlink,fl500wvr00-a0t.txt new file mode 100644 index 000000000000..b47f9d87bc19 --- /dev/null +++ b/Documentation/devicetree/bindings/panel/foxlink,fl500wvr00-a0t.txt @@ -0,0 +1,7 @@ +Foxlink Group 5" WVGA TFT LCD panel + +Required properties: +- compatible: should be "foxlink,fl500wvr00-a0t" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 869a84e31ddd..9961d4408430 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -403,6 +403,28 @@ static const struct panel_desc edt_etm0700g0dh6 = { }, }; +static const struct drm_display_mode foxlink_fl500wvr00_a0t_mode = { + .clock = 32260, + .hdisplay = 800, + .hsync_start = 800 + 168, + .hsync_end = 800 + 168 + 64, + .htotal = 800 + 168 + 64 + 88, + .vdisplay = 480, + .vsync_start = 480 + 37, + .vsync_end = 480 + 37 + 2, + .vtotal = 480 + 37 + 2 + 8, + .vrefresh = 60, +}; + +static const struct panel_desc foxlink_fl500wvr00_a0t = { + .modes = &foxlink_fl500wvr00_a0t_mode, + .num_modes = 1, + .size = { + .width = 108, + .height = 65, + }, +}; + static const struct drm_display_mode lg_lp129qe_mode = { .clock = 285250, .hdisplay = 2560, @@ -469,6 +491,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "edt,etm0700g0dh6", .data = &edt_etm0700g0dh6, + }, { + .compatible = "foxlink,fl500wvr00-a0t", + .data = &foxlink_fl500wvr00_a0t, }, { .compatible = "lg,lp129qe", .data = &lg_lp129qe, From 371c359f83b4d19d2688e975a07dc44add307e24 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 21 Jul 2014 12:22:26 +0200 Subject: [PATCH 06/30] drm/dsi: Make mipi_dsi_dcs_write() return ssize_t This function returns the value of the struct mipi_dsi_host_ops' .transfer() so make sure the return types are consistent. Acked-by: Andrzej Hajda Signed-off-by: Thierry Reding --- drivers/gpu/drm/drm_mipi_dsi.c | 4 ++-- drivers/gpu/drm/panel/panel-s6e8aa0.c | 4 ++-- include/drm/drm_mipi_dsi.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index e633df2f68d8..6d2fd2077dae 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -205,8 +205,8 @@ EXPORT_SYMBOL(mipi_dsi_detach); * @data: pointer to the command followed by parameters * @len: length of @data */ -int mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, unsigned int channel, - const void *data, size_t len) +ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, unsigned int channel, + const void *data, size_t len) { const struct mipi_dsi_host_ops *ops = dsi->host->ops; struct mipi_dsi_msg msg = { diff --git a/drivers/gpu/drm/panel/panel-s6e8aa0.c b/drivers/gpu/drm/panel/panel-s6e8aa0.c index 06e57a26db7a..beb43492b649 100644 --- a/drivers/gpu/drm/panel/panel-s6e8aa0.c +++ b/drivers/gpu/drm/panel/panel-s6e8aa0.c @@ -133,14 +133,14 @@ static int s6e8aa0_clear_error(struct s6e8aa0 *ctx) static void s6e8aa0_dcs_write(struct s6e8aa0 *ctx, const void *data, size_t len) { struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); - int ret; + ssize_t ret; if (ctx->error < 0) return; ret = mipi_dsi_dcs_write(dsi, dsi->channel, data, len); if (ret < 0) { - dev_err(ctx->dev, "error %d writing dcs seq: %*ph\n", ret, len, + dev_err(ctx->dev, "error %zd writing dcs seq: %*ph\n", ret, len, data); ctx->error = ret; } diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index efa1b552adc5..4b0112781910 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -127,8 +127,8 @@ struct mipi_dsi_device { int mipi_dsi_attach(struct mipi_dsi_device *dsi); int mipi_dsi_detach(struct mipi_dsi_device *dsi); -int mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, unsigned int channel, - const void *data, size_t len); +ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, unsigned int channel, + const void *data, size_t len); ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, unsigned int channel, u8 cmd, void *data, size_t len); From 3c523d7d38a17b17371a9ea952c04a9b65c8a357 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 21 Jul 2014 12:28:25 +0200 Subject: [PATCH 07/30] drm/dsi: Use peripheral's channel for DCS commands When executing DCS commands, use the channel associated with the DSI peripheral rather than one explicitly specified in the function call. Devices shouldn't be able to step on each others' toes like this. Acked-by: Andrzej Hajda Signed-off-by: Thierry Reding --- drivers/gpu/drm/drm_mipi_dsi.c | 14 ++++++-------- drivers/gpu/drm/panel/panel-s6e8aa0.c | 4 ++-- include/drm/drm_mipi_dsi.h | 8 ++++---- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 6d2fd2077dae..6aa6a9e95570 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -201,16 +201,15 @@ EXPORT_SYMBOL(mipi_dsi_detach); /** * mipi_dsi_dcs_write - send DCS write command * @dsi: DSI device - * @channel: virtual channel * @data: pointer to the command followed by parameters * @len: length of @data */ -ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, unsigned int channel, - const void *data, size_t len) +ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, const void *data, + size_t len) { const struct mipi_dsi_host_ops *ops = dsi->host->ops; struct mipi_dsi_msg msg = { - .channel = channel, + .channel = dsi->channel, .tx_buf = data, .tx_len = len }; @@ -239,19 +238,18 @@ EXPORT_SYMBOL(mipi_dsi_dcs_write); /** * mipi_dsi_dcs_read - send DCS read request command * @dsi: DSI device - * @channel: virtual channel * @cmd: DCS read command * @data: pointer to read buffer * @len: length of @data * * Function returns number of read bytes or error code. */ -ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, unsigned int channel, - u8 cmd, void *data, size_t len) +ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data, + size_t len) { const struct mipi_dsi_host_ops *ops = dsi->host->ops; struct mipi_dsi_msg msg = { - .channel = channel, + .channel = dsi->channel, .type = MIPI_DSI_DCS_READ, .tx_buf = &cmd, .tx_len = 1, diff --git a/drivers/gpu/drm/panel/panel-s6e8aa0.c b/drivers/gpu/drm/panel/panel-s6e8aa0.c index beb43492b649..5502ef6bc074 100644 --- a/drivers/gpu/drm/panel/panel-s6e8aa0.c +++ b/drivers/gpu/drm/panel/panel-s6e8aa0.c @@ -138,7 +138,7 @@ static void s6e8aa0_dcs_write(struct s6e8aa0 *ctx, const void *data, size_t len) if (ctx->error < 0) return; - ret = mipi_dsi_dcs_write(dsi, dsi->channel, data, len); + ret = mipi_dsi_dcs_write(dsi, data, len); if (ret < 0) { dev_err(ctx->dev, "error %zd writing dcs seq: %*ph\n", ret, len, data); @@ -154,7 +154,7 @@ static int s6e8aa0_dcs_read(struct s6e8aa0 *ctx, u8 cmd, void *data, size_t len) if (ctx->error < 0) return ctx->error; - ret = mipi_dsi_dcs_read(dsi, dsi->channel, cmd, data, len); + ret = mipi_dsi_dcs_read(dsi, cmd, data, len); if (ret < 0) { dev_err(ctx->dev, "error %d reading dcs seq(%#x)\n", ret, cmd); ctx->error = ret; diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 4b0112781910..7b5e1a9244e1 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -127,10 +127,10 @@ struct mipi_dsi_device { int mipi_dsi_attach(struct mipi_dsi_device *dsi); int mipi_dsi_detach(struct mipi_dsi_device *dsi); -ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, unsigned int channel, - const void *data, size_t len); -ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, unsigned int channel, - u8 cmd, void *data, size_t len); +ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, const void *data, + size_t len); +ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data, + size_t len); /** * struct mipi_dsi_driver - DSI driver From 9d90ce5c1002928d3bbc1f6014b04bf36c94d803 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 21 Jul 2014 15:51:17 +0200 Subject: [PATCH 08/30] drm/panel: s6e8aa0: Use static inline for upcasting Use a static inline function for upcasting a struct drm_panel to the driver-specific structure. The advantage over using a macro is that it gives us additional type checking. Acked-by: Andrzej Hajda Signed-off-by: Thierry Reding --- drivers/gpu/drm/panel/panel-s6e8aa0.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/panel/panel-s6e8aa0.c b/drivers/gpu/drm/panel/panel-s6e8aa0.c index 5502ef6bc074..4fe0bbb03230 100644 --- a/drivers/gpu/drm/panel/panel-s6e8aa0.c +++ b/drivers/gpu/drm/panel/panel-s6e8aa0.c @@ -120,7 +120,10 @@ struct s6e8aa0 { int error; }; -#define panel_to_s6e8aa0(p) container_of(p, struct s6e8aa0, panel) +static inline struct s6e8aa0 *panel_to_s6e8aa0(struct drm_panel *panel) +{ + return container_of(panel, struct s6e8aa0, panel); +} static int s6e8aa0_clear_error(struct s6e8aa0 *ctx) { From ea44739db37f7e187a2e684c1f9d5662b9dba94a Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Tue, 22 Jul 2014 08:38:55 +0200 Subject: [PATCH 09/30] drm/panel: simple: add support for InnoLux N156BGE-L21 panel This panel is used by the Medcom Wide and supported by the simple-panel driver. Signed-off-by: Alban Bedel Signed-off-by: Thierry Reding --- .../bindings/panel/innolux,n156bge-l21.txt | 7 ++++++ drivers/gpu/drm/panel/panel-simple.c | 25 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 Documentation/devicetree/bindings/panel/innolux,n156bge-l21.txt diff --git a/Documentation/devicetree/bindings/panel/innolux,n156bge-l21.txt b/Documentation/devicetree/bindings/panel/innolux,n156bge-l21.txt new file mode 100644 index 000000000000..7825844aafdf --- /dev/null +++ b/Documentation/devicetree/bindings/panel/innolux,n156bge-l21.txt @@ -0,0 +1,7 @@ +InnoLux 15.6" WXGA TFT LCD panel + +Required properties: +- compatible: should be "innolux,n156bge-l21" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 9961d4408430..357712c4446f 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -425,6 +425,28 @@ static const struct panel_desc foxlink_fl500wvr00_a0t = { }, }; +static const struct drm_display_mode innolux_n156bge_l21_mode = { + .clock = 69300, + .hdisplay = 1366, + .hsync_start = 1366 + 16, + .hsync_end = 1366 + 16 + 34, + .htotal = 1366 + 16 + 34 + 50, + .vdisplay = 768, + .vsync_start = 768 + 2, + .vsync_end = 768 + 2 + 6, + .vtotal = 768 + 2 + 6 + 12, + .vrefresh = 60, +}; + +static const struct panel_desc innolux_n156bge_l21 = { + .modes = &innolux_n156bge_l21_mode, + .num_modes = 1, + .size = { + .width = 344, + .height = 193, + }, +}; + static const struct drm_display_mode lg_lp129qe_mode = { .clock = 285250, .hdisplay = 2560, @@ -494,6 +516,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "foxlink,fl500wvr00-a0t", .data = &foxlink_fl500wvr00_a0t, + }, { + .compatible = "innolux,n156bge-l21", + .data = &innolux_n156bge_l21, }, { .compatible = "lg,lp129qe", .data = &lg_lp129qe, From 0208d51112b65e27490bc21ab6872358903f7d61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Marchesin?= Date: Thu, 19 Jun 2014 18:18:28 -0700 Subject: [PATCH 10/30] drm/panel: simple: Add bits-per-color support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bits-per-color is provided by the EDID normally, but if we're using panels, we need to store it somewhere. So we add a field to the panel descriptor for it. Signed-off-by: Stéphane Marchesin Signed-off-by: Thierry Reding --- drivers/gpu/drm/panel/panel-simple.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 357712c4446f..fa2aea0981a1 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -37,6 +37,8 @@ struct panel_desc { const struct drm_display_mode *modes; unsigned int num_modes; + unsigned int bpc; + struct { unsigned int width; unsigned int height; @@ -87,6 +89,7 @@ static int panel_simple_get_fixed_modes(struct panel_simple *panel) num++; } + connector->display_info.bpc = panel->desc->bpc; connector->display_info.width_mm = panel->desc->size.width; connector->display_info.height_mm = panel->desc->size.height; @@ -285,6 +288,7 @@ static const struct drm_display_mode auo_b101aw03_mode = { static const struct panel_desc auo_b101aw03 = { .modes = &auo_b101aw03_mode, .num_modes = 1, + .bpc = 6, .size = { .width = 223, .height = 125, @@ -307,6 +311,7 @@ static const struct drm_display_mode auo_b133xtn01_mode = { static const struct panel_desc auo_b133xtn01 = { .modes = &auo_b133xtn01_mode, .num_modes = 1, + .bpc = 6, .size = { .width = 293, .height = 165, @@ -329,6 +334,7 @@ static const struct drm_display_mode chunghwa_claa101wa01a_mode = { static const struct panel_desc chunghwa_claa101wa01a = { .modes = &chunghwa_claa101wa01a_mode, .num_modes = 1, + .bpc = 6, .size = { .width = 220, .height = 120, @@ -351,6 +357,7 @@ static const struct drm_display_mode chunghwa_claa101wb01_mode = { static const struct panel_desc chunghwa_claa101wb01 = { .modes = &chunghwa_claa101wb01_mode, .num_modes = 1, + .bpc = 6, .size = { .width = 223, .height = 125, @@ -374,6 +381,7 @@ static const struct drm_display_mode edt_et057090dhu_mode = { static const struct panel_desc edt_et057090dhu = { .modes = &edt_et057090dhu_mode, .num_modes = 1, + .bpc = 6, .size = { .width = 115, .height = 86, @@ -397,6 +405,7 @@ static const struct drm_display_mode edt_etm0700g0dh6_mode = { static const struct panel_desc edt_etm0700g0dh6 = { .modes = &edt_etm0700g0dh6_mode, .num_modes = 1, + .bpc = 6, .size = { .width = 152, .height = 91, @@ -441,6 +450,7 @@ static const struct drm_display_mode innolux_n156bge_l21_mode = { static const struct panel_desc innolux_n156bge_l21 = { .modes = &innolux_n156bge_l21_mode, .num_modes = 1, + .bpc = 6, .size = { .width = 344, .height = 193, @@ -463,6 +473,7 @@ static const struct drm_display_mode lg_lp129qe_mode = { static const struct panel_desc lg_lp129qe = { .modes = &lg_lp129qe_mode, .num_modes = 1, + .bpc = 8, .size = { .width = 272, .height = 181, @@ -485,6 +496,7 @@ static const struct drm_display_mode samsung_ltn101nt05_mode = { static const struct panel_desc samsung_ltn101nt05 = { .modes = &samsung_ltn101nt05_mode, .num_modes = 1, + .bpc = 6, .size = { .width = 1024, .height = 600, From 0a2288c06aab73c966e82045c8f20b0e713baf2a Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 3 Jul 2014 14:02:59 +0200 Subject: [PATCH 11/30] drm/panel: simple: Add Innolux N116BGE panel support The Innolux N116BGE is an 11.6" WXGA TFT LCD panel connecting to an eDP interface and with an integrated LED backlight unit. It is used in the Tegra132 Norrin reference design. Signed-off-by: Thierry Reding --- .../bindings/panel/innolux,n116bge.txt | 7 +++++ drivers/gpu/drm/panel/panel-simple.c | 27 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 Documentation/devicetree/bindings/panel/innolux,n116bge.txt diff --git a/Documentation/devicetree/bindings/panel/innolux,n116bge.txt b/Documentation/devicetree/bindings/panel/innolux,n116bge.txt new file mode 100644 index 000000000000..081bb939ed31 --- /dev/null +++ b/Documentation/devicetree/bindings/panel/innolux,n116bge.txt @@ -0,0 +1,7 @@ +Innolux Corporation 11.6" WXGA (1366x768) TFT LCD panel + +Required properties: +- compatible: should be "innolux,n116bge" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index fa2aea0981a1..755dd5a4c229 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -434,6 +434,30 @@ static const struct panel_desc foxlink_fl500wvr00_a0t = { }, }; +static const struct drm_display_mode innolux_n116bge_mode = { + .clock = 71000, + .hdisplay = 1366, + .hsync_start = 1366 + 64, + .hsync_end = 1366 + 64 + 6, + .htotal = 1366 + 64 + 6 + 64, + .vdisplay = 768, + .vsync_start = 768 + 8, + .vsync_end = 768 + 8 + 4, + .vtotal = 768 + 8 + 4 + 8, + .vrefresh = 60, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, +}; + +static const struct panel_desc innolux_n116bge = { + .modes = &innolux_n116bge_mode, + .num_modes = 1, + .bpc = 6, + .size = { + .width = 256, + .height = 144, + }, +}; + static const struct drm_display_mode innolux_n156bge_l21_mode = { .clock = 69300, .hdisplay = 1366, @@ -528,6 +552,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "foxlink,fl500wvr00-a0t", .data = &foxlink_fl500wvr00_a0t, + }, { + .compatible = "innolux,n116bge", + .data = &innolux_n116bge, }, { .compatible = "innolux,n156bge-l21", .data = &innolux_n156bge_l21, From 81cf32b239b2788353a79606fc6f713ec87abc35 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 29 Jul 2014 13:38:56 +0200 Subject: [PATCH 12/30] drm/panel: simple: Remove simple-panel compatible simple-panel is not a valid panel model, so there is no data (video timings, etc.) associated with it. Therefore drivers can't do anything useful with it, so it should not appear in the table of OF matches. Device trees will always need to specify the exact model of the panel. Signed-off-by: Thierry Reding --- drivers/gpu/drm/panel/panel-simple.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 755dd5a4c229..c31b645813a7 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -564,8 +564,6 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "samsung,ltn101nt05", .data = &samsung_ltn101nt05, - }, { - .compatible = "simple-panel", }, { /* sentinel */ } From 45527d435c5e39b6eec4aa0065a562e7cf05d503 Mon Sep 17 00:00:00 2001 From: Ajay Kumar Date: Fri, 18 Jul 2014 02:13:48 +0530 Subject: [PATCH 13/30] drm/panel: add .prepare() and .unprepare() functions Panels often require an initialization sequence that consists of three steps: a) powering up the panel, b) starting transmission of video data and c) enabling the panel (e.g. turn on backlight). This is usually necessary to avoid visual glitches at the beginning of video data transmission. Similarly, the shutdown sequence is typically done in three steps as well: a) disable the panel (e.g. turn off backlight), b) cease video data transmission and c) power down the panel. Currently drivers can only implement .enable() and .disable() functions, which is not enough to implement the above sequences. This commit adds a second pair of functions, .prepare() and .unprepare() to allow more fine-grained control over when the above steps are performed. Signed-off-by: Ajay Kumar [treding: rewrite changelog, add kerneldoc] Signed-off-by: Thierry Reding --- include/drm/drm_panel.h | 50 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h index c2ab77add67c..29e3daf1b25d 100644 --- a/include/drm/drm_panel.h +++ b/include/drm/drm_panel.h @@ -30,8 +30,42 @@ struct drm_connector; struct drm_device; struct drm_panel; +/** + * struct drm_panel_funcs - perform operations on a given panel + * @disable: disable panel (turn off back light, etc.) + * @unprepare: turn off panel + * @prepare: turn on panel and perform set up + * @enable: enable panel (turn on back light, etc.) + * @get_modes: add modes to the connector that the panel is attached to and + * return the number of modes added + * + * The .prepare() function is typically called before the display controller + * starts to transmit video data. Panel drivers can use this to turn the panel + * on and wait for it to become ready. If additional configuration is required + * (via a control bus such as I2C, SPI or DSI for example) this is a good time + * to do that. + * + * After the display controller has started transmitting video data, it's safe + * to call the .enable() function. This will typically enable the backlight to + * make the image on screen visible. Some panels require a certain amount of + * time or frames before the image is displayed. This function is responsible + * for taking this into account before enabling the backlight to avoid visual + * glitches. + * + * Before stopping video transmission from the display controller it can be + * necessary to turn off the panel to avoid visual glitches. This is done in + * the .disable() function. Analogously to .enable() this typically involves + * turning off the backlight and waiting for some time to make sure no image + * is visible on the panel. It is then safe for the display controller to + * cease transmission of video data. + * + * To save power when no video data is transmitted, a driver can power down + * the panel. This is the job of the .unprepare() function. + */ struct drm_panel_funcs { int (*disable)(struct drm_panel *panel); + int (*unprepare)(struct drm_panel *panel); + int (*prepare)(struct drm_panel *panel); int (*enable)(struct drm_panel *panel); int (*get_modes)(struct drm_panel *panel); }; @@ -46,6 +80,14 @@ struct drm_panel { struct list_head list; }; +static inline int drm_panel_unprepare(struct drm_panel *panel) +{ + if (panel && panel->funcs && panel->funcs->unprepare) + return panel->funcs->unprepare(panel); + + return panel ? -ENOSYS : -EINVAL; +} + static inline int drm_panel_disable(struct drm_panel *panel) { if (panel && panel->funcs && panel->funcs->disable) @@ -54,6 +96,14 @@ static inline int drm_panel_disable(struct drm_panel *panel) return panel ? -ENOSYS : -EINVAL; } +static inline int drm_panel_prepare(struct drm_panel *panel) +{ + if (panel && panel->funcs && panel->funcs->prepare) + return panel->funcs->prepare(panel); + + return panel ? -ENOSYS : -EINVAL; +} + static inline int drm_panel_enable(struct drm_panel *panel) { if (panel && panel->funcs && panel->funcs->enable) From 7bf93c73adb28d8db6b34c27d3edd96337a2d366 Mon Sep 17 00:00:00 2001 From: Ajay Kumar Date: Wed, 30 Jul 2014 12:02:15 +0200 Subject: [PATCH 14/30] drm/panel: Provide convenience wrapper for .get_modes() Add a convenience wrapper for the struct drm_panel_funcs' .get_modes() function so that not every driver needs to check that the panel driver implements the function before calling it. Signed-off-by: Ajay Kumar [treding: extract from larger patch, commit message] Signed-off-by: Thierry Reding --- include/drm/drm_panel.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h index 29e3daf1b25d..1fbcc96063a7 100644 --- a/include/drm/drm_panel.h +++ b/include/drm/drm_panel.h @@ -112,6 +112,14 @@ static inline int drm_panel_enable(struct drm_panel *panel) return panel ? -ENOSYS : -EINVAL; } +static inline int drm_panel_get_modes(struct drm_panel *panel) +{ + if (panel && panel->funcs && panel->funcs->get_modes) + return panel->funcs->get_modes(panel); + + return panel ? -ENOSYS : -EINVAL; +} + void drm_panel_init(struct drm_panel *panel); int drm_panel_add(struct drm_panel *panel); From 099b3e8699322efb7229913d2c1651588205f182 Mon Sep 17 00:00:00 2001 From: Ajay Kumar Date: Thu, 31 Jul 2014 23:12:02 +0530 Subject: [PATCH 15/30] drm/panel: ld9040: Add dummy prepare and unprepare routines This patch adds dummy definition for prepare and unprepare routines to ld9040 panel driver. Signed-off-by: Ajay Kumar Signed-off-by: Thierry Reding --- drivers/gpu/drm/panel/panel-ld9040.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-ld9040.c b/drivers/gpu/drm/panel/panel-ld9040.c index db1601fdbe29..9b40bd05d64d 100644 --- a/drivers/gpu/drm/panel/panel-ld9040.c +++ b/drivers/gpu/drm/panel/panel-ld9040.c @@ -228,6 +228,16 @@ static int ld9040_disable(struct drm_panel *panel) return ld9040_power_off(ctx); } +static int ld9040_unprepare(struct drm_panel *panel) +{ + return 0; +} + +static int ld9040_prepare(struct drm_panel *panel) +{ + return 0; +} + static int ld9040_enable(struct drm_panel *panel) { struct ld9040 *ctx = panel_to_ld9040(panel); @@ -273,6 +283,8 @@ static int ld9040_get_modes(struct drm_panel *panel) static const struct drm_panel_funcs ld9040_drm_funcs = { .disable = ld9040_disable, + .unprepare = ld9040_unprepare, + .prepare = ld9040_prepare, .enable = ld9040_enable, .get_modes = ld9040_get_modes, }; From f99a23bd492cf3bcee59ef23b7a405e81fdfc2db Mon Sep 17 00:00:00 2001 From: Ajay Kumar Date: Thu, 31 Jul 2014 23:12:03 +0530 Subject: [PATCH 16/30] drm/panel: s6e8aa0: Add dummy prepare and unprepare routines This patch adds dummy definition for prepare and unprepare routines to s6e8aa0 panel driver. Signed-off-by: Ajay Kumar Signed-off-by: Thierry Reding --- drivers/gpu/drm/panel/panel-s6e8aa0.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-s6e8aa0.c b/drivers/gpu/drm/panel/panel-s6e8aa0.c index 4fe0bbb03230..31f2c87eadf6 100644 --- a/drivers/gpu/drm/panel/panel-s6e8aa0.c +++ b/drivers/gpu/drm/panel/panel-s6e8aa0.c @@ -903,6 +903,16 @@ static int s6e8aa0_disable(struct drm_panel *panel) return s6e8aa0_power_off(ctx); } +static int s6e8aa0_unprepare(struct drm_panel *panel) +{ + return 0; +} + +static int s6e8aa0_prepare(struct drm_panel *panel) +{ + return 0; +} + static int s6e8aa0_enable(struct drm_panel *panel) { struct s6e8aa0 *ctx = panel_to_s6e8aa0(panel); @@ -947,6 +957,8 @@ static int s6e8aa0_get_modes(struct drm_panel *panel) static const struct drm_panel_funcs s6e8aa0_drm_funcs = { .disable = s6e8aa0_disable, + .unprepare = s6e8aa0_unprepare, + .prepare = s6e8aa0_prepare, .enable = s6e8aa0_enable, .get_modes = s6e8aa0_get_modes, }; From c0e1d1706a1dabd9811602bda3b6b265050a9566 Mon Sep 17 00:00:00 2001 From: Ajay Kumar Date: Thu, 31 Jul 2014 23:12:04 +0530 Subject: [PATCH 17/30] drm/panel: simple: Add dummy prepare and unprepare routines This patch adds dummy definition for prepare and unprepare routines to simple panel driver. Signed-off-by: Ajay Kumar Signed-off-by: Thierry Reding --- drivers/gpu/drm/panel/panel-simple.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index c31b645813a7..4bf33c6b42f0 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -117,6 +117,16 @@ static int panel_simple_disable(struct drm_panel *panel) return 0; } +static int panel_simple_unprepare(struct drm_panel *panel) +{ + return 0; +} + +static int panel_simple_prepare(struct drm_panel *panel) +{ + return 0; +} + static int panel_simple_enable(struct drm_panel *panel) { struct panel_simple *p = to_panel_simple(panel); @@ -167,6 +177,8 @@ static int panel_simple_get_modes(struct drm_panel *panel) static const struct drm_panel_funcs panel_simple_funcs = { .disable = panel_simple_disable, + .unprepare = panel_simple_unprepare, + .prepare = panel_simple_prepare, .enable = panel_simple_enable, .get_modes = panel_simple_get_modes, }; From 39bbde9cc0bb0891b470a6ce919d09843f5473e2 Mon Sep 17 00:00:00 2001 From: Ajay Kumar Date: Thu, 31 Jul 2014 23:12:05 +0530 Subject: [PATCH 18/30] drm/exynos: dpi: Add support for panel prepare and unprepare routines Modify exynos_dpi driver to support the new panel calls: prepare and unprepare. Signed-off-by: Ajay Kumar Acked-by: Inki Dae Signed-off-by: Thierry Reding --- drivers/gpu/drm/exynos/exynos_drm_dpi.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c index 482127f633c5..f8531533fbf3 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c @@ -125,14 +125,18 @@ static int exynos_dpi_create_connector(struct exynos_drm_display *display, static void exynos_dpi_poweron(struct exynos_dpi *ctx) { - if (ctx->panel) + if (ctx->panel) { + drm_panel_prepare(ctx->panel); drm_panel_enable(ctx->panel); + } } static void exynos_dpi_poweroff(struct exynos_dpi *ctx) { - if (ctx->panel) + if (ctx->panel) { drm_panel_disable(ctx->panel); + drm_panel_unprepare(ctx->panel); + } } static void exynos_dpi_dpms(struct exynos_drm_display *display, int mode) From cdfb8694dc107c3b004b67dfbb392ae62d358e77 Mon Sep 17 00:00:00 2001 From: Ajay Kumar Date: Thu, 31 Jul 2014 23:12:06 +0530 Subject: [PATCH 19/30] drm/exynos: dsi: Add support for panel prepare and unprepare routines Modify exynos_dsi driver to support the new panel calls: prepare and unprepare. Signed-off-by: Ajay Kumar Acked-by: Inki Dae Signed-off-by: Thierry Reding --- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 6302aa64f6c1..abb5f6199200 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1115,7 +1115,7 @@ static int exynos_dsi_enable(struct exynos_dsi *dsi) if (ret < 0) return ret; - ret = drm_panel_enable(dsi->panel); + ret = drm_panel_prepare(dsi->panel); if (ret < 0) { exynos_dsi_poweroff(dsi); return ret; @@ -1124,6 +1124,14 @@ static int exynos_dsi_enable(struct exynos_dsi *dsi) exynos_dsi_set_display_mode(dsi); exynos_dsi_set_display_enable(dsi, true); + ret = drm_panel_enable(dsi->panel); + if (ret < 0) { + exynos_dsi_set_display_enable(dsi, false); + drm_panel_unprepare(dsi->panel); + exynos_dsi_poweroff(dsi); + return ret; + } + dsi->state |= DSIM_STATE_ENABLED; return 0; @@ -1134,8 +1142,9 @@ static void exynos_dsi_disable(struct exynos_dsi *dsi) if (!(dsi->state & DSIM_STATE_ENABLED)) return; - exynos_dsi_set_display_enable(dsi, false); drm_panel_disable(dsi->panel); + exynos_dsi_set_display_enable(dsi, false); + drm_panel_unprepare(dsi->panel); exynos_dsi_poweroff(dsi); dsi->state &= ~DSIM_STATE_ENABLED; From 0407ed8afe0cada72b0c28fd35c821fe3b235593 Mon Sep 17 00:00:00 2001 From: Ajay Kumar Date: Thu, 31 Jul 2014 23:12:07 +0530 Subject: [PATCH 20/30] drm/tegra: Add support for panel prepare and unprepare routines Modify tegra output driver to support the new panel calls: prepare and unprepare. Signed-off-by: Ajay Kumar Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/output.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c index a3e4f1eca6f7..9609bc3e2443 100644 --- a/drivers/gpu/drm/tegra/output.c +++ b/drivers/gpu/drm/tegra/output.c @@ -140,7 +140,9 @@ static void tegra_encoder_dpms(struct drm_encoder *encoder, int mode) if (mode != DRM_MODE_DPMS_ON) { drm_panel_disable(panel); tegra_output_disable(output); + drm_panel_unprepare(panel); } else { + drm_panel_prepare(panel); tegra_output_enable(output); drm_panel_enable(panel); } From 8141028278c2eac32a70d2c5a5178c84a4d0963e Mon Sep 17 00:00:00 2001 From: Ajay Kumar Date: Thu, 31 Jul 2014 23:12:08 +0530 Subject: [PATCH 21/30] drm/panel: ld9040: Add proper definition for prepare and unprepare Move out code from enable and disable routines to prepare and unprepare routines, so that functionality is properly distributed across all the panel functions. Signed-off-by: Ajay Kumar Signed-off-by: Thierry Reding --- drivers/gpu/drm/panel/panel-ld9040.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-ld9040.c b/drivers/gpu/drm/panel/panel-ld9040.c index 9b40bd05d64d..c6aa7f717fa4 100644 --- a/drivers/gpu/drm/panel/panel-ld9040.c +++ b/drivers/gpu/drm/panel/panel-ld9040.c @@ -215,6 +215,11 @@ static int ld9040_power_off(struct ld9040 *ctx) } static int ld9040_disable(struct drm_panel *panel) +{ + return 0; +} + +static int ld9040_unprepare(struct drm_panel *panel) { struct ld9040 *ctx = panel_to_ld9040(panel); @@ -228,17 +233,7 @@ static int ld9040_disable(struct drm_panel *panel) return ld9040_power_off(ctx); } -static int ld9040_unprepare(struct drm_panel *panel) -{ - return 0; -} - static int ld9040_prepare(struct drm_panel *panel) -{ - return 0; -} - -static int ld9040_enable(struct drm_panel *panel) { struct ld9040 *ctx = panel_to_ld9040(panel); int ret; @@ -252,11 +247,16 @@ static int ld9040_enable(struct drm_panel *panel) ret = ld9040_clear_error(ctx); if (ret < 0) - ld9040_disable(panel); + ld9040_unprepare(panel); return ret; } +static int ld9040_enable(struct drm_panel *panel) +{ + return 0; +} + static int ld9040_get_modes(struct drm_panel *panel) { struct drm_connector *connector = panel->connector; From 1a670e7b8c4227bcff5119802ef04bbf5916cabb Mon Sep 17 00:00:00 2001 From: Ajay Kumar Date: Thu, 31 Jul 2014 23:12:09 +0530 Subject: [PATCH 22/30] drm/panel: s6e8aa0: Add proper definition for prepare and unprepare Move out code from enable and disable routines to prepare and unprepare routines, so that functionality is properly distributed across all the panel functions. Signed-off-by: Ajay Kumar Signed-off-by: Thierry Reding --- drivers/gpu/drm/panel/panel-s6e8aa0.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-s6e8aa0.c b/drivers/gpu/drm/panel/panel-s6e8aa0.c index 31f2c87eadf6..b5217fe37f02 100644 --- a/drivers/gpu/drm/panel/panel-s6e8aa0.c +++ b/drivers/gpu/drm/panel/panel-s6e8aa0.c @@ -891,6 +891,11 @@ static int s6e8aa0_power_off(struct s6e8aa0 *ctx) } static int s6e8aa0_disable(struct drm_panel *panel) +{ + return 0; +} + +static int s6e8aa0_unprepare(struct drm_panel *panel) { struct s6e8aa0 *ctx = panel_to_s6e8aa0(panel); @@ -903,17 +908,7 @@ static int s6e8aa0_disable(struct drm_panel *panel) return s6e8aa0_power_off(ctx); } -static int s6e8aa0_unprepare(struct drm_panel *panel) -{ - return 0; -} - static int s6e8aa0_prepare(struct drm_panel *panel) -{ - return 0; -} - -static int s6e8aa0_enable(struct drm_panel *panel) { struct s6e8aa0 *ctx = panel_to_s6e8aa0(panel); int ret; @@ -926,11 +921,16 @@ static int s6e8aa0_enable(struct drm_panel *panel) ret = ctx->error; if (ret < 0) - s6e8aa0_disable(panel); + s6e8aa0_unprepare(panel); return ret; } +static int s6e8aa0_enable(struct drm_panel *panel) +{ + return 0; +} + static int s6e8aa0_get_modes(struct drm_panel *panel) { struct drm_connector *connector = panel->connector; From 613a633e7a567593efc03dc2357b6d25cd365c10 Mon Sep 17 00:00:00 2001 From: Ajay Kumar Date: Thu, 31 Jul 2014 23:12:10 +0530 Subject: [PATCH 23/30] drm/panel: simple: Add proper definition for prepare and unprepare Move out code from enable and disable routines to prepare and unprepare routines, so that functionality is properly distributed across all the panel functions. Signed-off-by: Ajay Kumar Signed-off-by: Thierry Reding --- drivers/gpu/drm/panel/panel-simple.c | 37 ++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 4bf33c6b42f0..806beae77938 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -47,6 +47,7 @@ struct panel_desc { struct panel_simple { struct drm_panel base; + bool prepared; bool enabled; const struct panel_desc *desc; @@ -108,10 +109,6 @@ static int panel_simple_disable(struct drm_panel *panel) backlight_update_status(p->backlight); } - if (p->enable_gpio) - gpiod_set_value_cansleep(p->enable_gpio, 0); - - regulator_disable(p->supply); p->enabled = false; return 0; @@ -119,20 +116,27 @@ static int panel_simple_disable(struct drm_panel *panel) static int panel_simple_unprepare(struct drm_panel *panel) { + struct panel_simple *p = to_panel_simple(panel); + + if (!p->prepared) + return 0; + + if (p->enable_gpio) + gpiod_set_value_cansleep(p->enable_gpio, 0); + + regulator_disable(p->supply); + + p->prepared = false; + return 0; } static int panel_simple_prepare(struct drm_panel *panel) -{ - return 0; -} - -static int panel_simple_enable(struct drm_panel *panel) { struct panel_simple *p = to_panel_simple(panel); int err; - if (p->enabled) + if (p->prepared) return 0; err = regulator_enable(p->supply); @@ -144,6 +148,18 @@ static int panel_simple_enable(struct drm_panel *panel) if (p->enable_gpio) gpiod_set_value_cansleep(p->enable_gpio, 1); + p->prepared = true; + + return 0; +} + +static int panel_simple_enable(struct drm_panel *panel) +{ + struct panel_simple *p = to_panel_simple(panel); + + if (p->enabled) + return 0; + if (p->backlight) { p->backlight->props.power = FB_BLANK_UNBLANK; backlight_update_status(p->backlight); @@ -194,6 +210,7 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) return -ENOMEM; panel->enabled = false; + panel->prepared = false; panel->desc = desc; panel->supply = devm_regulator_get(dev, "power"); From f673c37ec453ee7fe12cd55d90301cf843ab97f6 Mon Sep 17 00:00:00 2001 From: Ajay Kumar Date: Thu, 31 Jul 2014 23:12:11 +0530 Subject: [PATCH 24/30] drm/panel: simple: Support delays in panel functions For most of the panels, we need to provide delays during various stages of panel power up and power down. Add a structure to hold those delay values and use them in corresponding functions. Signed-off-by: Ajay Kumar Signed-off-by: Thierry Reding --- drivers/gpu/drm/panel/panel-simple.c | 30 ++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 806beae77938..7798bdc9da54 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -43,6 +43,24 @@ struct panel_desc { unsigned int width; unsigned int height; } size; + + /** + * @prepare: the time (in milliseconds) that it takes for the panel to + * become ready and start receiving video data + * @enable: the time (in milliseconds) that it takes for the panel to + * display the first valid frame after starting to receive + * video data + * @disable: the time (in milliseconds) that it takes for the panel to + * turn the display off (no content is visible) + * @unprepare: the time (in milliseconds) that it takes for the panel + * to power itself down completely + */ + struct { + unsigned int prepare; + unsigned int enable; + unsigned int disable; + unsigned int unprepare; + } delay; }; struct panel_simple { @@ -109,6 +127,9 @@ static int panel_simple_disable(struct drm_panel *panel) backlight_update_status(p->backlight); } + if (p->desc->delay.disable) + msleep(p->desc->delay.disable); + p->enabled = false; return 0; @@ -126,6 +147,9 @@ static int panel_simple_unprepare(struct drm_panel *panel) regulator_disable(p->supply); + if (p->desc->delay.unprepare) + msleep(p->desc->delay.unprepare); + p->prepared = false; return 0; @@ -148,6 +172,9 @@ static int panel_simple_prepare(struct drm_panel *panel) if (p->enable_gpio) gpiod_set_value_cansleep(p->enable_gpio, 1); + if (p->desc->delay.prepare) + msleep(p->desc->delay.prepare); + p->prepared = true; return 0; @@ -160,6 +187,9 @@ static int panel_simple_enable(struct drm_panel *panel) if (p->enabled) return 0; + if (p->desc->delay.enable) + msleep(p->desc->delay.enable); + if (p->backlight) { p->backlight->props.power = FB_BLANK_UNBLANK; backlight_update_status(p->backlight); From 3e51d609321601627fb571bdc403c330f416d1af Mon Sep 17 00:00:00 2001 From: Ajay Kumar Date: Thu, 31 Jul 2014 23:12:12 +0530 Subject: [PATCH 25/30] drm/panel: simple: Add AUO B133HTN01 panel support The AUO B133HTN01 is a 13.6" FHD TFT LCD panel connecting to an eDP interface and with an integrated LED backlight unit. This panel is used on the Samsung Chromebook 2 (XE503C32). Signed-off-by: Ajay Kumar Signed-off-by: Thierry Reding --- .../bindings/panel/auo,b133htn01.txt | 7 +++++ drivers/gpu/drm/panel/panel-simple.c | 30 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 Documentation/devicetree/bindings/panel/auo,b133htn01.txt diff --git a/Documentation/devicetree/bindings/panel/auo,b133htn01.txt b/Documentation/devicetree/bindings/panel/auo,b133htn01.txt new file mode 100644 index 000000000000..302226b5bb55 --- /dev/null +++ b/Documentation/devicetree/bindings/panel/auo,b133htn01.txt @@ -0,0 +1,7 @@ +AU Optronics Corporation 13.3" FHD (1920x1080) color TFT-LCD panel + +Required properties: +- compatible: should be "auo,b133htn01" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 7798bdc9da54..6ae1aada6373 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -377,6 +377,33 @@ static const struct panel_desc auo_b133xtn01 = { }, }; +static const struct drm_display_mode auo_b133htn01_mode = { + .clock = 150660, + .hdisplay = 1920, + .hsync_start = 1920 + 172, + .hsync_end = 1920 + 172 + 80, + .htotal = 1920 + 172 + 80 + 60, + .vdisplay = 1080, + .vsync_start = 1080 + 25, + .vsync_end = 1080 + 25 + 10, + .vtotal = 1080 + 25 + 10 + 10, + .vrefresh = 60, +}; + +static const struct panel_desc auo_b133htn01 = { + .modes = &auo_b133htn01_mode, + .num_modes = 1, + .size = { + .width = 293, + .height = 165, + }, + .delay = { + .prepare = 105, + .enable = 20, + .unprepare = 50, + }, +}; + static const struct drm_display_mode chunghwa_claa101wa01a_mode = { .clock = 72070, .hdisplay = 1366, @@ -590,6 +617,9 @@ static const struct of_device_id platform_of_match[] = { { .compatible = "auo,b101aw03", .data = &auo_b101aw03, + }, { + .compatible = "auo,b133htn01", + .data = &auo_b133htn01, }, { .compatible = "auo,b133xtn01", .data = &auo_b133xtn01, From 4deabfa00049465cc1e4ed6fe0b5082bcff98d57 Mon Sep 17 00:00:00 2001 From: Ajay Kumar Date: Thu, 31 Jul 2014 23:12:13 +0530 Subject: [PATCH 26/30] drm/exynos: Move DP setup into commit() Add commit callback for exynos_dp, and move the DP link training, video configuration code from the hotplug handler into commit(). Signed-off-by: Sean Paul Signed-off-by: Ajay Kumar Acked-by: Inki Dae Signed-off-by: Thierry Reding --- drivers/gpu/drm/exynos/exynos_dp_core.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index a8ffc8c1477b..c33a9d0a87c1 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -875,10 +875,18 @@ static irqreturn_t exynos_dp_irq_handler(int irq, void *arg) static void exynos_dp_hotplug(struct work_struct *work) { struct exynos_dp_device *dp; - int ret; dp = container_of(work, struct exynos_dp_device, hotplug_work); + if (dp->drm_dev) + drm_helper_hpd_irq_event(dp->drm_dev); +} + +static void exynos_dp_commit(struct exynos_drm_display *display) +{ + struct exynos_dp_device *dp = display->ctx; + int ret; + ret = exynos_dp_detect_hpd(dp); if (ret) { /* Cable has been disconnected, we're done */ @@ -1050,8 +1058,10 @@ static void exynos_dp_phy_exit(struct exynos_dp_device *dp) } } -static void exynos_dp_poweron(struct exynos_dp_device *dp) +static void exynos_dp_poweron(struct exynos_drm_display *display) { + struct exynos_dp_device *dp = display->ctx; + if (dp->dpms_mode == DRM_MODE_DPMS_ON) return; @@ -1059,10 +1069,13 @@ static void exynos_dp_poweron(struct exynos_dp_device *dp) exynos_dp_phy_init(dp); exynos_dp_init_dp(dp); enable_irq(dp->irq); + exynos_dp_commit(display); } -static void exynos_dp_poweroff(struct exynos_dp_device *dp) +static void exynos_dp_poweroff(struct exynos_drm_display *display) { + struct exynos_dp_device *dp = display->ctx; + if (dp->dpms_mode != DRM_MODE_DPMS_ON) return; @@ -1078,12 +1091,12 @@ static void exynos_dp_dpms(struct exynos_drm_display *display, int mode) switch (mode) { case DRM_MODE_DPMS_ON: - exynos_dp_poweron(dp); + exynos_dp_poweron(display); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: - exynos_dp_poweroff(dp); + exynos_dp_poweroff(display); break; default: break; @@ -1094,6 +1107,7 @@ static void exynos_dp_dpms(struct exynos_drm_display *display, int mode) static struct exynos_drm_display_ops exynos_dp_display_ops = { .create_connector = exynos_dp_create_connector, .dpms = exynos_dp_dpms, + .commit = exynos_dp_commit, }; static struct exynos_drm_display exynos_dp_display = { From 5f1dcd8b7ec8189c2b147cdaa1589d5644c3cef3 Mon Sep 17 00:00:00 2001 From: Ajay Kumar Date: Thu, 31 Jul 2014 23:12:14 +0530 Subject: [PATCH 27/30] drm/exynos: dp: Modify driver to support drm_panel Add drm_panel controls to support powerup/down of the eDP panel, if one is present at the sink side. Signed-off-by: Ajay Kumar Acked-by: Inki Dae Signed-off-by: Thierry Reding --- drivers/gpu/drm/exynos/Kconfig | 1 + drivers/gpu/drm/exynos/exynos_dp_core.c | 88 +++++++++++++++++++------ drivers/gpu/drm/exynos/exynos_dp_core.h | 3 +- 3 files changed, 71 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 178d2a9672a8..fd1c070f0297 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -52,6 +52,7 @@ config DRM_EXYNOS_DP bool "EXYNOS DRM DP driver support" depends on DRM_EXYNOS_FIMD && ARCH_EXYNOS && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS) default DRM_EXYNOS + select DRM_PANEL help This enables support for DP device. diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index c33a9d0a87c1..0d3f88bfeca5 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -28,6 +27,7 @@ #include #include #include +#include #include #include "exynos_drm_drv.h" @@ -41,7 +41,7 @@ struct bridge_init { struct device_node *node; }; -static int exynos_dp_init_dp(struct exynos_dp_device *dp) +static void exynos_dp_init_dp(struct exynos_dp_device *dp) { exynos_dp_reset(dp); @@ -58,8 +58,6 @@ static int exynos_dp_init_dp(struct exynos_dp_device *dp) exynos_dp_init_hpd(dp); exynos_dp_init_aux(dp); - - return 0; } static int exynos_dp_detect_hpd(struct exynos_dp_device *dp) @@ -887,6 +885,12 @@ static void exynos_dp_commit(struct exynos_drm_display *display) struct exynos_dp_device *dp = display->ctx; int ret; + /* Keep the panel disabled while we configure video */ + if (dp->panel) { + if (drm_panel_disable(dp->panel)) + DRM_ERROR("failed to disable the panel\n"); + } + ret = exynos_dp_detect_hpd(dp); if (ret) { /* Cable has been disconnected, we're done */ @@ -917,6 +921,12 @@ static void exynos_dp_commit(struct exynos_drm_display *display) ret = exynos_dp_config_video(dp); if (ret) dev_err(dp->dev, "unable to config video\n"); + + /* Safe to enable the panel now */ + if (dp->panel) { + if (drm_panel_enable(dp->panel)) + DRM_ERROR("failed to enable the panel\n"); + } } static enum drm_connector_status exynos_dp_detect( @@ -941,15 +951,18 @@ static int exynos_dp_get_modes(struct drm_connector *connector) struct exynos_dp_device *dp = ctx_from_connector(connector); struct drm_display_mode *mode; + if (dp->panel) + return drm_panel_get_modes(dp->panel); + mode = drm_mode_create(connector->dev); if (!mode) { DRM_ERROR("failed to create a new display mode.\n"); return 0; } - drm_display_mode_from_videomode(&dp->panel.vm, mode); - mode->width_mm = dp->panel.width_mm; - mode->height_mm = dp->panel.height_mm; + drm_display_mode_from_videomode(&dp->priv.vm, mode); + mode->width_mm = dp->priv.width_mm; + mode->height_mm = dp->priv.height_mm; connector->display_info.width_mm = mode->width_mm; connector->display_info.height_mm = mode->height_mm; @@ -1029,7 +1042,10 @@ static int exynos_dp_create_connector(struct exynos_drm_display *display, drm_sysfs_connector_add(connector); drm_mode_connector_attach_encoder(connector, encoder); - return 0; + if (dp->panel) + ret = drm_panel_attach(dp->panel, &dp->connector); + + return ret; } static void exynos_dp_phy_init(struct exynos_dp_device *dp) @@ -1065,6 +1081,13 @@ static void exynos_dp_poweron(struct exynos_drm_display *display) if (dp->dpms_mode == DRM_MODE_DPMS_ON) return; + if (dp->panel) { + if (drm_panel_prepare(dp->panel)) { + DRM_ERROR("failed to setup the panel\n"); + return; + } + } + clk_prepare_enable(dp->clock); exynos_dp_phy_init(dp); exynos_dp_init_dp(dp); @@ -1079,10 +1102,22 @@ static void exynos_dp_poweroff(struct exynos_drm_display *display) if (dp->dpms_mode != DRM_MODE_DPMS_ON) return; + if (dp->panel) { + if (drm_panel_disable(dp->panel)) { + DRM_ERROR("failed to disable the panel\n"); + return; + } + } + disable_irq(dp->irq); flush_work(&dp->hotplug_work); exynos_dp_phy_exit(dp); clk_disable_unprepare(dp->clock); + + if (dp->panel) { + if (drm_panel_unprepare(dp->panel)) + DRM_ERROR("failed to turnoff the panel\n"); + } } static void exynos_dp_dpms(struct exynos_drm_display *display, int mode) @@ -1215,7 +1250,7 @@ static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp) { int ret; - ret = of_get_videomode(dp->dev->of_node, &dp->panel.vm, + ret = of_get_videomode(dp->dev->of_node, &dp->priv.vm, OF_USE_NATIVE_MODE); if (ret) { DRM_ERROR("failed: of_get_videomode() : %d\n", ret); @@ -1229,16 +1264,10 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) struct platform_device *pdev = to_platform_device(dev); struct drm_device *drm_dev = data; struct resource *res; - struct exynos_dp_device *dp; + struct exynos_dp_device *dp = exynos_dp_display.ctx; unsigned int irq_flags; - int ret = 0; - dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device), - GFP_KERNEL); - if (!dp) - return -ENOMEM; - dp->dev = &pdev->dev; dp->dpms_mode = DRM_MODE_DPMS_OFF; @@ -1250,9 +1279,11 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) if (ret) return ret; - ret = exynos_dp_dt_parse_panel(dp); - if (ret) - return ret; + if (!dp->panel) { + ret = exynos_dp_dt_parse_panel(dp); + if (ret) + return ret; + } dp->clock = devm_clk_get(&pdev->dev, "dp"); if (IS_ERR(dp->clock)) { @@ -1312,7 +1343,6 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) disable_irq(dp->irq); dp->drm_dev = drm_dev; - exynos_dp_display.ctx = dp; platform_set_drvdata(pdev, &exynos_dp_display); @@ -1339,6 +1369,9 @@ static const struct component_ops exynos_dp_ops = { static int exynos_dp_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; + struct device_node *panel_node; + struct exynos_dp_device *dp; int ret; ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR, @@ -1346,6 +1379,21 @@ static int exynos_dp_probe(struct platform_device *pdev) if (ret) return ret; + dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device), + GFP_KERNEL); + if (!dp) + return -ENOMEM; + + panel_node = of_parse_phandle(dev->of_node, "panel", 0); + if (panel_node) { + dp->panel = of_drm_find_panel(panel_node); + of_node_put(panel_node); + if (!dp->panel) + return -EPROBE_DEFER; + } + + exynos_dp_display.ctx = dp; + ret = component_add(&pdev->dev, &exynos_dp_ops); if (ret) exynos_drm_component_del(&pdev->dev, diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.h b/drivers/gpu/drm/exynos/exynos_dp_core.h index 02cc4f9ab903..a1aee6931bd7 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.h +++ b/drivers/gpu/drm/exynos/exynos_dp_core.h @@ -149,6 +149,7 @@ struct exynos_dp_device { struct drm_device *drm_dev; struct drm_connector connector; struct drm_encoder *encoder; + struct drm_panel *panel; struct clk *clock; unsigned int irq; void __iomem *reg_base; @@ -162,7 +163,7 @@ struct exynos_dp_device { int dpms_mode; int hpd_gpio; - struct exynos_drm_panel_info panel; + struct exynos_drm_panel_info priv; }; /* exynos_dp_reg.c */ From dff2ed275454b5a69b785949be73e2dcbb686e3f Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 5 Aug 2014 08:59:01 +0200 Subject: [PATCH 28/30] drm/panel: ld9040: Replace upcasting macro by function Using a function instead of a macro provides proper type checking. Signed-off-by: Thierry Reding --- drivers/gpu/drm/panel/panel-ld9040.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/panel/panel-ld9040.c b/drivers/gpu/drm/panel/panel-ld9040.c index c6aa7f717fa4..42ac67b21e9f 100644 --- a/drivers/gpu/drm/panel/panel-ld9040.c +++ b/drivers/gpu/drm/panel/panel-ld9040.c @@ -110,7 +110,10 @@ struct ld9040 { int error; }; -#define panel_to_ld9040(p) container_of(p, struct ld9040, panel) +static inline struct ld9040 *panel_to_ld9040(struct drm_panel *panel) +{ + return container_of(panel, struct ld9040, panel); +} static int ld9040_clear_error(struct ld9040 *ctx) { From 77df01dcd3040a7d664d85d085d4a21533824bc1 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 5 Aug 2014 09:01:32 +0200 Subject: [PATCH 29/30] drm/dsi: Replace upcasting macro by function Using a function instead of a macro provides proper type checking. Signed-off-by: Thierry Reding --- include/drm/drm_mipi_dsi.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 7b5e1a9244e1..2bb55b8b9031 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -123,7 +123,10 @@ struct mipi_dsi_device { unsigned long mode_flags; }; -#define to_mipi_dsi_device(d) container_of(d, struct mipi_dsi_device, dev) +static inline struct mipi_dsi_device *to_mipi_dsi_device(struct device *dev) +{ + return container_of(dev, struct mipi_dsi_device, dev); +} int mipi_dsi_attach(struct mipi_dsi_device *dsi); int mipi_dsi_detach(struct mipi_dsi_device *dsi); @@ -146,7 +149,11 @@ struct mipi_dsi_driver { void (*shutdown)(struct mipi_dsi_device *dsi); }; -#define to_mipi_dsi_driver(d) container_of(d, struct mipi_dsi_driver, driver) +static inline struct mipi_dsi_driver * +to_mipi_dsi_driver(struct device_driver *driver) +{ + return container_of(driver, struct mipi_dsi_driver, driver); +} static inline void *mipi_dsi_get_drvdata(const struct mipi_dsi_device *dsi) { From 9746c61960b63d2cea41333bca00c60f032052bb Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 25 Jul 2014 23:47:25 +0900 Subject: [PATCH 30/30] drm/panel: simple: Use devm_gpiod_get_optional() Use the new devm_gpiod_get_optional() to simplify the probe code. Signed-off-by: Alexandre Courbot Signed-off-by: Thierry Reding --- drivers/gpu/drm/panel/panel-simple.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 6ae1aada6373..4ce1db0a68ff 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -247,16 +247,14 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) if (IS_ERR(panel->supply)) return PTR_ERR(panel->supply); - panel->enable_gpio = devm_gpiod_get(dev, "enable"); + panel->enable_gpio = devm_gpiod_get_optional(dev, "enable"); if (IS_ERR(panel->enable_gpio)) { err = PTR_ERR(panel->enable_gpio); - if (err != -ENOENT) { - dev_err(dev, "failed to request GPIO: %d\n", err); - return err; - } + dev_err(dev, "failed to request GPIO: %d\n", err); + return err; + } - panel->enable_gpio = NULL; - } else { + if (panel->enable_gpio) { err = gpiod_direction_output(panel->enable_gpio, 0); if (err < 0) { dev_err(dev, "failed to setup GPIO: %d\n", err);