diff options
Diffstat (limited to 'drivers/gpu/drm/panel')
-rw-r--r-- | drivers/gpu/drm/panel/Kconfig | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-ld9040.c | 21 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-s6e8aa0.c | 29 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-simple.c | 203 |
4 files changed, 231 insertions, 29 deletions
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 4ec874da5668..bee9f72b3a93 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,11 @@ config DRM_PANEL_SIMPLE config DRM_PANEL_LD9040 tristate "LD9040 RGB/SPI panel" - depends on DRM && DRM_PANEL - depends on OF - select SPI + depends on OF && 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 diff --git a/drivers/gpu/drm/panel/panel-ld9040.c b/drivers/gpu/drm/panel/panel-ld9040.c index db1601fdbe29..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) { @@ -216,6 +219,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); msleep(120); @@ -228,7 +236,7 @@ static int ld9040_disable(struct drm_panel *panel) return ld9040_power_off(ctx); } -static int ld9040_enable(struct drm_panel *panel) +static int ld9040_prepare(struct drm_panel *panel) { struct ld9040 *ctx = panel_to_ld9040(panel); int ret; @@ -242,11 +250,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; @@ -273,6 +286,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, }; diff --git a/drivers/gpu/drm/panel/panel-s6e8aa0.c b/drivers/gpu/drm/panel/panel-s6e8aa0.c index 06e57a26db7a..b5217fe37f02 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) { @@ -133,14 +136,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); + ret = mipi_dsi_dcs_write(dsi, 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; } @@ -154,7 +157,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; @@ -889,6 +892,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); s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_ENTER_SLEEP_MODE); @@ -900,7 +908,7 @@ static int s6e8aa0_disable(struct drm_panel *panel) return s6e8aa0_power_off(ctx); } -static int s6e8aa0_enable(struct drm_panel *panel) +static int s6e8aa0_prepare(struct drm_panel *panel) { struct s6e8aa0 *ctx = panel_to_s6e8aa0(panel); int ret; @@ -913,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; @@ -944,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, }; diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index a25136132c31..4ce1db0a68ff 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -37,14 +37,35 @@ struct panel_desc { const struct drm_display_mode *modes; unsigned int num_modes; + unsigned int bpc; + struct { 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 { struct drm_panel base; + bool prepared; bool enabled; const struct panel_desc *desc; @@ -87,6 +108,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; @@ -105,21 +127,40 @@ 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; +} + +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->enabled = false; + + if (p->desc->delay.unprepare) + msleep(p->desc->delay.unprepare); + + p->prepared = false; return 0; } -static int panel_simple_enable(struct drm_panel *panel) +static int panel_simple_prepare(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); @@ -131,6 +172,24 @@ static int panel_simple_enable(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; +} + +static int panel_simple_enable(struct drm_panel *panel) +{ + struct panel_simple *p = to_panel_simple(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); @@ -164,6 +223,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, }; @@ -179,22 +240,21 @@ 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"); 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); @@ -285,6 +345,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,12 +368,40 @@ 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, }, }; +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, @@ -329,6 +418,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 +441,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 +465,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,12 +489,82 @@ 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, }, }; +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 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, + .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, + .bpc = 6, + .size = { + .width = 344, + .height = 193, + }, +}; + static const struct drm_display_mode lg_lp129qe_mode = { .clock = 285250, .hdisplay = 2560, @@ -419,6 +581,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, @@ -441,6 +604,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, @@ -452,6 +616,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, }, { @@ -470,14 +637,21 @@ static const struct of_device_id platform_of_match[] = { .compatible = "edt,etm0700g0dh6", .data = &edt_etm0700g0dh6, }, { + .compatible = "foxlink,fl500wvr00-a0t", + .data = &foxlink_fl500wvr00_a0t, + }, { + .compatible = "innolux,n116bge", + .data = &innolux_n116bge, + }, { + .compatible = "innolux,n156bge-l21", + .data = &innolux_n156bge_l21, + }, { .compatible = "lg,lp129qe", .data = &lg_lp129qe, }, { .compatible = "samsung,ltn101nt05", .data = &samsung_ltn101nt05, }, { - .compatible = "simple-panel", - }, { /* sentinel */ } }; @@ -545,7 +719,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 +773,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, }; |