On Mon, 22 May 2023 at 12:08, Neil Armstrong <neil.armstr...@linaro.org> wrote:
>
> On 22/05/2023 03:23, Dmitry Baryshkov wrote:
> > On 22/05/2023 00:23, Marijn Suijten wrote:
> >> The SOFEF03-M Display-IC paired with an unknown panel in the Sony Xperia
> >> 5 II always uses Display Stream Compression 1.1 and features a 60hz and
> >> 120hz refresh-rate mode.
> >>
> >> Co-developed-by: Konrad Dybcio <konrad.dyb...@somainline.org>
> >
> > Konrad's S-o-b is also required then
> >
> >> Signed-off-by: Marijn Suijten <marijn.suij...@somainline.org>
> >> ---
> >>   drivers/gpu/drm/panel/Kconfig                 |  14 +
> >>   drivers/gpu/drm/panel/Makefile                |   1 +
> >>   drivers/gpu/drm/panel/panel-samsung-sofef03.c | 423 
> >> ++++++++++++++++++++++++++
> >>   3 files changed, 438 insertions(+)
> >>
> >> diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
> >> index 3f11e9906f2cb..8e2668153bce2 100644
> >> --- a/drivers/gpu/drm/panel/Kconfig
> >> +++ b/drivers/gpu/drm/panel/Kconfig
> >> @@ -630,6 +630,20 @@ config DRM_PANEL_SAMSUNG_SOFEF01
> >>         This panel features a fixed mode of 1080x2520@60.
> >> +config DRM_PANEL_SAMSUNG_SOFEF03
> >> +    tristate "Samsung sofef03 Sony Xperia 5 II DSI cmd mode panel"
> >> +    depends on GPIOLIB
> >> +    depends on OF
> >> +    depends on DRM_MIPI_DSI
> >> +    depends on BACKLIGHT_CLASS_DEVICE
> >> +    help
> >> +      Say Y or M here if you want to enable support for the Samsung AMOLED
> >> +      command mode panel found in the Sony Xperia 5 II smartphone.
> >> +
> >> +      This panel uses Display Stream Compression 1.1.
> >> +
> >> +      The panel features a 1080x2520@60 and 1080x2520@120 mode.
> >> +
> >>   config DRM_PANEL_SEIKO_43WVF1G
> >>       tristate "Seiko 43WVF1G panel"
> >>       depends on OF
> >> diff --git a/drivers/gpu/drm/panel/Makefile 
> >> b/drivers/gpu/drm/panel/Makefile
> >> index a4039d0fc9cfb..52dcd82e33120 100644
> >> --- a/drivers/gpu/drm/panel/Makefile
> >> +++ b/drivers/gpu/drm/panel/Makefile
> >> @@ -63,6 +63,7 @@ obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01) += 
> >> panel-samsung-s6e88a0-ams4
> >>   obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o
> >>   obj-$(CONFIG_DRM_PANEL_SAMSUNG_SOFEF00) += panel-samsung-sofef00.o
> >>   obj-$(CONFIG_DRM_PANEL_SAMSUNG_SOFEF01) += panel-samsung-sofef01.o
> >> +obj-$(CONFIG_DRM_PANEL_SAMSUNG_SOFEF03) += panel-samsung-sofef03.o
> >>   obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o
> >>   obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o
> >>   obj-$(CONFIG_DRM_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
> >> diff --git a/drivers/gpu/drm/panel/panel-samsung-sofef03.c 
> >> b/drivers/gpu/drm/panel/panel-samsung-sofef03.c
> >> new file mode 100644
> >> index 0000000000000..2763e1c56b37b
> >> --- /dev/null
> >> +++ b/drivers/gpu/drm/panel/panel-samsung-sofef03.c
> >> @@ -0,0 +1,423 @@
> >> +// SPDX-License-Identifier: GPL-2.0-only
> >> +/*
> >> + * Copyright (c) 2022 Konrad Dybcio <konrad.dyb...@linaro.org>
> >> + * Copyright (c) 2023 Marijn Suijten <marijn.suij...@somainline.org>
> >> + */
> >> +
> >> +#include <linux/backlight.h>
> >> +#include <linux/delay.h>
> >> +#include <linux/gpio/consumer.h>
> >> +#include <linux/module.h>
> >> +#include <linux/of.h>
> >> +#include <linux/regulator/consumer.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_probe_helper.h>
> >> +#include <drm/display/drm_dsc.h>
> >> +#include <drm/display/drm_dsc_helper.h>
> >> +
> >> +static const bool enable_120hz = true;
>
> Maybe this can be a module parameter ? Can you explain why this can't be 
> dynamically changed by a modeset ?
>
> >> +
> >> +struct samsung_sofef03_m {
> >> +    struct drm_panel panel;
> >> +    struct mipi_dsi_device *dsi;
> >> +    struct regulator *vddio, *vci;
> >> +    struct gpio_desc *reset_gpio;
> >> +    bool prepared;
> >> +};
> >> +
> >> +static inline struct samsung_sofef03_m *to_samsung_sofef03_m(struct 
> >> drm_panel *panel)
> >> +{
> >> +    return container_of(panel, struct samsung_sofef03_m, panel);
> >> +}
> >> +
> >> +static void samsung_sofef03_m_reset(struct samsung_sofef03_m *ctx)
> >> +{
> >> +    gpiod_set_value_cansleep(ctx->reset_gpio, 0);
> >> +    usleep_range(10000, 11000);
> >> +}
> >> +
> >> +static int samsung_sofef03_m_on(struct samsung_sofef03_m *ctx)
> >> +{
> >> +    struct mipi_dsi_device *dsi = ctx->dsi;
> >> +    struct device *dev = &dsi->dev;
> >> +    int ret;
> >> +
> >> +    dsi->mode_flags |= MIPI_DSI_MODE_LPM;
> >> +
> >> +    mipi_dsi_dcs_write_seq(dsi, 0x9d, 0x01);
> >> +
> >> +    ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
> >> +    if (ret < 0) {
> >> +        dev_err(dev, "Failed to exit sleep mode: %d\n", ret);
> >> +        return ret;
> >> +    }
> >> +    usleep_range(10000, 11000);
> >> +
> >> +    mipi_dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a);
> >> +    mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x09);
> >> +    mipi_dsi_dcs_write_seq(dsi, 0xd5, 0x00, 0x00, 0x00);
> >> +    mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x08);
> >> +    mipi_dsi_dcs_write_seq(dsi, 0xee, 0x00, 0x00);
> >> +    mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5);
> >> +
> >> +    ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
> >> +    if (ret < 0) {
> >> +        dev_err(dev, "Failed to set tear on: %d\n", ret);
> >> +        return ret;
> >> +    }
> >> +
> >> +    ret = mipi_dsi_dcs_set_column_address(dsi, 0, 1080 - 1);
> >> +    if (ret < 0) {
> >> +        dev_err(dev, "Failed to set column address: %d\n", ret);
> >> +        return ret;
> >> +    }
> >> +
> >> +    ret = mipi_dsi_dcs_set_page_address(dsi, 0, 2520 - 1);
> >> +    if (ret < 0) {
> >> +        dev_err(dev, "Failed to set page address: %d\n", ret);
> >> +        return ret;
> >> +    }
> >> +
> >> +    ret = mipi_dsi_dcs_set_display_brightness_large(dsi, 100);
> >> +    if (ret < 0) {
> >> +        dev_err(dev, "Failed to set display brightness: %d\n", ret);
> >> +        return ret;
> >> +    }
> >> +
> >> +    mipi_dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a);
> >> +    mipi_dsi_dcs_write_seq(dsi, 0xdf, 0x83);
> >> +    mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x01);
> >> +    mipi_dsi_dcs_write_seq(dsi, 0xe6, 0x01);
> >> +    mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x02);
> >> +    mipi_dsi_dcs_write_seq(dsi, 0xec, 0x02, 0x00, 0x1c, 0x1c);
> >> +    mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x0c);
> >> +    mipi_dsi_dcs_write_seq(dsi, 0xec, 0x01, 0x19);
> >> +    mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5);
> >> +    mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, BIT(5));
> >> +    mipi_dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a);
> >> +    mipi_dsi_dcs_write_seq(dsi, 0xc2, 0x2d, 0x27);
> >> +    mipi_dsi_dcs_write_seq(dsi, 0x60, enable_120hz ? 0x10 : 0x00);
> >> +    mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5);
> >> +    msleep(110);
> >> +
> >> +    ret = mipi_dsi_dcs_set_display_on(dsi);
> >> +    if (ret < 0) {
> >> +        dev_err(dev, "Failed to turn display on: %d\n", ret);
> >> +        return ret;
> >> +    }
> >> +
> >> +    return 0;
> >> +}
> >> +
> >> +static int samsung_sofef03_m_off(struct samsung_sofef03_m *ctx)
> >> +{
> >> +    struct mipi_dsi_device *dsi = ctx->dsi;
> >> +    struct device *dev = &dsi->dev;
> >> +    int ret;
> >> +
> >> +    dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
> >> +
> >> +    ret = mipi_dsi_dcs_set_display_off(dsi);
> >> +    if (ret < 0) {
> >> +        dev_err(dev, "Failed to turn display off: %d\n", ret);
> >> +        return ret;
> >> +    }
> >> +    msleep(20);
> >> +
> >> +    ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
> >> +    if (ret < 0) {
> >> +        dev_err(dev, "Failed to enter sleep mode: %d\n", ret);
> >> +        return ret;
> >> +    }
> >> +    msleep(100);
> >> +
> >> +    return 0;
> >> +}
> >> +
> >> +static int samsung_sofef03_m_prepare(struct drm_panel *panel)
> >> +{
> >> +    struct samsung_sofef03_m *ctx = to_samsung_sofef03_m(panel);
> >> +    struct drm_dsc_picture_parameter_set pps;
> >> +    struct device *dev = &ctx->dsi->dev;
> >> +    int ret;
> >> +
> >> +    if (ctx->prepared)
> >> +        return 0;
> >> +
> >> +    ret = regulator_enable(ctx->vddio);
> >> +    if (ret < 0) {
> >> +        dev_err(dev, "Failed to enable vddio regulator: %d\n", ret);
> >> +        return ret;
> >> +    }
> >> +
> >> +    ret = regulator_enable(ctx->vci);
> >> +    if (ret < 0) {
> >> +        dev_err(dev, "Failed to enable vci regulator: %d\n", ret);
> >> +        regulator_disable(ctx->vddio);
> >> +        return ret;
> >> +    }
> >> +
> >> +    samsung_sofef03_m_reset(ctx);
> >> +
> >> +    ret = samsung_sofef03_m_on(ctx);
> >> +    if (ret < 0) {
> >> +        dev_err(dev, "Failed to initialize panel: %d\n", ret);
> >> +        goto fail;
> >> +    }
> >> +
> >> +    if (ctx->dsi->dsc) {
> >
> > Always true
> >
> >> +        drm_dsc_pps_payload_pack(&pps, ctx->dsi->dsc);
> >> +
> >> +        ret = mipi_dsi_picture_parameter_set(ctx->dsi, &pps);
> >> +        if (ret < 0) {
> >> +            dev_err(dev, "failed to transmit PPS: %d\n", ret);
> >> +            goto fail;
> >> +        }
> >> +
> >> +        ret = mipi_dsi_compression_mode(ctx->dsi, true);
> >> +        if (ret < 0) {
> >> +            dev_err(dev, "Failed to enable compression mode: %d\n", ret);
> >> +            goto fail;
> >> +        }
> >> +
> >> +        msleep(28);
> >> +    }
> >> +
> >> +    ctx->prepared = true;
> >> +    return 0;
> >> +
> >> +fail:
> >> +    gpiod_set_value_cansleep(ctx->reset_gpio, 1);
> >> +    regulator_disable(ctx->vci);
> >> +    regulator_disable(ctx->vddio);
> >> +    return ret;
> >> +}
> >> +
> >> +static int samsung_sofef03_m_unprepare(struct drm_panel *panel)
> >> +{
> >> +    struct samsung_sofef03_m *ctx = to_samsung_sofef03_m(panel);
> >> +    struct device *dev = &ctx->dsi->dev;
> >> +    int ret;
> >> +
> >> +    if (!ctx->prepared)
> >> +        return 0;
> >> +
> >> +    ret = samsung_sofef03_m_off(ctx);
> >> +    if (ret < 0)
> >> +        dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
> >> +
> >> +    gpiod_set_value_cansleep(ctx->reset_gpio, 1);
> >> +    regulator_disable(ctx->vci);
> >> +    regulator_disable(ctx->vddio);
> >> +
> >> +    ctx->prepared = false;
> >> +    return 0;
> >> +}
> >> +
> >> +static const struct drm_display_mode samsung_sofef03_m_60hz_mode = {
> >> +    .clock = (1080 + 156 + 8 + 8) * (2520 + 2393 + 8 + 8) * 60 / 1000,
> >> +    .hdisplay = 1080,
> >> +    .hsync_start = 1080 + 156,
> >> +    .hsync_end = 1080 + 156 + 8,
> >> +    .htotal = 1080 + 156 + 8 + 8,
> >> +    .vdisplay = 2520,
> >> +    .vsync_start = 2520 + 2393,
> >> +    .vsync_end = 2520 + 2393 + 8,
> >> +    .vtotal = 2520 + 2393 + 8 + 8,
> >> +    .width_mm = 61,
> >> +    .height_mm = 142,
> >> +};
> >> +
> >> +static const struct drm_display_mode samsung_sofef03_m_120hz_mode = {
> >> +    .clock = (1080 + 56 + 8 + 8) * (2520 + 499 + 8 + 8) * 120 / 1000,
> >> +    .hdisplay = 1080,
> >> +    .hsync_start = 1080 + 56,
> >> +    .hsync_end = 1080 + 56 + 8,
> >> +    .htotal = 1080 + 56 + 8 + 8,
> >> +    .vdisplay = 2520,
> >> +    .vsync_start = 2520 + 499,
> >> +    .vsync_end = 2520 + 499 + 8,
> >> +    .vtotal = 2520 + 499 + 8 + 8,
> >> +    .width_mm = 61,
> >> +    .height_mm = 142,
> >> +};
> >> +
> >> +static int samsung_sofef03_m_get_modes(struct drm_panel *panel,
> >> +                   struct drm_connector *connector)
> >> +{
> >> +    if (enable_120hz)
> >
> > Is it possible to switch between these modes at runtime? It might be 
> > logical to define 60 Hz mode as preferred, while allowing users to switch 
> > to 120 Hz when required for some reason.

Current panel API does not have a way to handle modesetting. All
callbacks only get the panel as an input, state is left aside.
Probably it's time to add atomic_*() versions of these callbacks, so
that one can pass the state and maybe a connector?
Or maybe the panel should get lightweight state too, like bridges do.

> >
> >> +        return drm_connector_helper_get_modes_fixed(connector,
> >> +                                &samsung_sofef03_m_120hz_mode);
> >> +    else
> >> +        return drm_connector_helper_get_modes_fixed(connector,
> >> +                                &samsung_sofef03_m_60hz_mode);
> >> +}

-- 
With best wishes
Dmitry

Reply via email to