From 6c74d8a9e9dd425dc13d45fcd0c95e0b7dda589b Mon Sep 17 00:00:00 2001 From: Romuald Jeanne Date: Tue, 25 Jul 2023 10:40:32 +0200 Subject: [PATCH 07/22] v5.15-stm32mp-r2.1 DRM Signed-off-by: Romuald Jeanne --- drivers/gpu/drm/bridge/sii902x.c | 100 +- drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 5 +- drivers/gpu/drm/drm_atomic_uapi.c | 4 + drivers/gpu/drm/drm_bridge.c | 10 +- drivers/gpu/drm/drm_connector.c | 62 + drivers/gpu/drm/panel/Kconfig | 9 + drivers/gpu/drm/panel/Makefile | 1 + .../gpu/drm/panel/panel-orisetech-otm8009a.c | 163 ++- drivers/gpu/drm/panel/panel-raydium-rm68200.c | 76 +- drivers/gpu/drm/panel/panel-rocktech-hx8394.c | 432 +++++++ drivers/gpu/drm/panel/panel-simple.c | 16 + drivers/gpu/drm/stm/drv.c | 6 + drivers/gpu/drm/stm/dw_mipi_dsi-stm.c | 118 +- drivers/gpu/drm/stm/ltdc.c | 1143 ++++++++++++++--- drivers/gpu/drm/stm/ltdc.h | 25 +- drivers/video/backlight/gpio_backlight.c | 7 +- drivers/video/fbdev/simplefb.c | 21 +- include/drm/bridge/dw_mipi_dsi.h | 4 +- include/drm/drm_connector.h | 14 + 19 files changed, 1918 insertions(+), 298 deletions(-) create mode 100644 drivers/gpu/drm/panel/panel-rocktech-hx8394.c diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c index 89558e581530..69208ead5384 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -162,6 +163,11 @@ #define SII902X_AUDIO_PORT_INDEX 3 +/* CEC device */ +#define SII902X_CEC_I2C_ADDR 0x30 + +#define SII902X_CEC_SETUP 0x8e + struct sii902x { struct i2c_client *i2c; struct regmap *regmap; @@ -170,6 +176,7 @@ struct sii902x { struct gpio_desc *reset_gpio; struct i2c_mux_core *i2cmux; struct regulator_bulk_data supplies[2]; + struct edid *edid; /* * Mutex protects audio and video functions from interfering * each other, by keeping their i2c command sequences atomic. @@ -280,6 +287,8 @@ static int sii902x_get_modes(struct drm_connector *connector) mutex_lock(&sii902x->mutex); + kfree(sii902x->edid); + sii902x->edid = NULL; edid = drm_get_edid(connector, sii902x->i2cmux->adapter[0]); drm_connector_update_edid_property(connector, edid); if (edid) { @@ -287,7 +296,7 @@ static int sii902x_get_modes(struct drm_connector *connector) output_mode = SII902X_SYS_CTRL_OUTPUT_HDMI; num = drm_add_edid_modes(connector, edid); - kfree(edid); + sii902x->edid = edid; } ret = drm_display_info_set_bus_formats(&connector->display_info, @@ -337,6 +346,7 @@ static void sii902x_bridge_disable(struct drm_bridge *bridge) static void sii902x_bridge_enable(struct drm_bridge *bridge) { struct sii902x *sii902x = bridge_to_sii902x(bridge); + u8 output_mode = SII902X_SYS_CTRL_OUTPUT_DVI; mutex_lock(&sii902x->mutex); @@ -346,6 +356,14 @@ static void sii902x_bridge_enable(struct drm_bridge *bridge) regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, SII902X_SYS_CTRL_PWR_DWN, 0); + if (sii902x->edid) { + if (drm_detect_hdmi_monitor(sii902x->edid)) + output_mode = SII902X_SYS_CTRL_OUTPUT_HDMI; + } + + regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, + SII902X_SYS_CTRL_OUTPUT_MODE, output_mode); + mutex_unlock(&sii902x->mutex); } @@ -960,6 +978,13 @@ static int sii902x_init(struct sii902x *sii902x) { struct device *dev = &sii902x->i2c->dev; unsigned int status = 0; + unsigned char data[2] = { SII902X_CEC_SETUP, 0}; + struct i2c_msg msg = { + .addr = SII902X_CEC_I2C_ADDR << 1, + .flags = 0, + .len = 2, + .buf = data, + }; u8 chipid[4]; int ret; @@ -982,13 +1007,22 @@ static int sii902x_init(struct sii902x *sii902x) return -EINVAL; } + /* + * By default, CEC must be disabled to allow other CEC devives + * to bypass the bridge. + */ + ret = i2c_transfer(sii902x->i2c->adapter, &msg, 1); + if (ret < 0) + dev_warn(&sii902x->i2c->dev, "Failed to disable CEC device!\n"); + /* Clear all pending interrupts */ regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status); regmap_write(sii902x->regmap, SII902X_INT_STATUS, status); if (sii902x->i2c->irq > 0) { - regmap_write(sii902x->regmap, SII902X_INT_ENABLE, - SII902X_HOTPLUG_EVENT); + regmap_update_bits(sii902x->regmap, SII902X_INT_ENABLE, + SII902X_HOTPLUG_EVENT, + SII902X_HOTPLUG_EVENT); ret = devm_request_threaded_irq(dev, sii902x->i2c->irq, NULL, sii902x_interrupt, @@ -1087,6 +1121,65 @@ static int sii902x_remove(struct i2c_client *client) return 0; } +static int sii902x_pm_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sii902x *sii902x = i2c_get_clientdata(client); + + DRM_DEBUG_DRIVER("\n"); + + if (sii902x->reset_gpio) + gpiod_set_value(sii902x->reset_gpio, 1); + + regulator_bulk_disable(ARRAY_SIZE(sii902x->supplies), + sii902x->supplies); + + return 0; +} + +static int sii902x_pm_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sii902x *sii902x = i2c_get_clientdata(client); + unsigned char data[2] = { SII902X_CEC_SETUP, 0}; + struct i2c_msg msg = { + .addr = SII902X_CEC_I2C_ADDR << 1, + .flags = 0, + .len = 2, + .buf = data, + }; + int ret; + + DRM_DEBUG_DRIVER("\n"); + + ret = regulator_bulk_enable(ARRAY_SIZE(sii902x->supplies), + sii902x->supplies); + if (ret) { + DRM_ERROR("regulator_bulk_enable failed\n"); + return ret; + } + + if (sii902x->reset_gpio) + gpiod_set_value(sii902x->reset_gpio, 0); + + regmap_write(sii902x->regmap, SII902X_REG_TPI_RQB, 0x00); + + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret < 0) + DRM_ERROR("Failed to disable CEC device!\n"); + + if (client->irq > 0) + regmap_update_bits(sii902x->regmap, SII902X_INT_ENABLE, + SII902X_HOTPLUG_EVENT, + SII902X_HOTPLUG_EVENT); + + return 0; +} + +static const struct dev_pm_ops sii902x_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(sii902x_pm_suspend, sii902x_pm_resume) +}; + static const struct of_device_id sii902x_dt_ids[] = { { .compatible = "sil,sii9022", }, { } @@ -1105,6 +1198,7 @@ static struct i2c_driver sii902x_driver = { .driver = { .name = "sii902x", .of_match_table = sii902x_dt_ids, + .pm = &sii902x_pm_ops, }, .id_table = sii902x_i2c_ids, }; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c index 56c3fd08c6a0..2a58b0b7ace5 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c @@ -998,7 +998,10 @@ dw_mipi_dsi_bridge_mode_valid(struct drm_bridge *bridge, enum drm_mode_status mode_status = MODE_OK; if (pdata->mode_valid) - mode_status = pdata->mode_valid(pdata->priv_data, mode); + mode_status = pdata->mode_valid(pdata->priv_data, mode, + dsi->mode_flags, + dw_mipi_dsi_get_lanes(dsi), + dsi->format); return mode_status; } diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index f195c7013137..9301aa72e6cb 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -773,6 +773,8 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector, state->content_type = val; } else if (property == connector->scaling_mode_property) { state->scaling_mode = val; + } else if (property == connector->dithering_property) { + state->dithering = val; } else if (property == config->content_protection_property) { if (val == DRM_MODE_CONTENT_PROTECTION_ENABLED) { DRM_DEBUG_KMS("only drivers can set CP Enabled\n"); @@ -862,6 +864,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector, *val = state->colorspace; } else if (property == connector->scaling_mode_property) { *val = state->scaling_mode; + } else if (property == connector->dithering_property) { + *val = state->dithering; } else if (property == config->hdr_output_metadata_property) { *val = state->hdr_output_metadata ? state->hdr_output_metadata->base.id : 0; diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 78bc315b0b73..f240af91d401 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -227,11 +227,13 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, list_del(&bridge->chain_node); #ifdef CONFIG_OF - DRM_ERROR("failed to attach bridge %pOF to encoder %s: %d\n", - bridge->of_node, encoder->name, ret); + if (ret != -EPROBE_DEFER) + DRM_ERROR("failed to attach bridge %pOF to encoder %s: %d\n", + bridge->of_node, encoder->name, ret); #else - DRM_ERROR("failed to attach bridge to encoder %s: %d\n", - encoder->name, ret); + if (ret != -EPROBE_DEFER) + DRM_ERROR("failed to attach bridge to encoder %s: %d\n", + encoder->name, ret); #endif return ret; diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index cfe163103cfd..185df70e94b9 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -827,6 +827,12 @@ static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = { { DRM_MODE_SCALE_ASPECT, "Full aspect" }, }; +static const struct drm_prop_enum_list drm_dithering_enum_list[] = { + { DRM_MODE_DITHERING_OFF, "Off" }, + { DRM_MODE_DITHERING_ON, "On" }, + { DRM_MODE_DITHERING_AUTO, "Automatic" }, +}; + static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = { { DRM_MODE_PICTURE_ASPECT_NONE, "Automatic" }, { DRM_MODE_PICTURE_ASPECT_4_3, "4:3" }, @@ -1779,6 +1785,62 @@ int drm_connector_attach_scaling_mode_property(struct drm_connector *connector, } EXPORT_SYMBOL(drm_connector_attach_scaling_mode_property); +/** + * drm_connector_attach_dithering_property - attach atomic dithering property + * @connector: connector to attach dithering property on. + * @dithering_mask: or'ed mask of BIT(%DRM_MODE_DITHERING_\*). + * + * This is used to add support for dithering to atomic drivers. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_connector_attach_dithering_property(struct drm_connector *connector, + u32 dithering_mask) +{ + struct drm_device *dev = connector->dev; + struct drm_property *dithering_property; + int i; + const unsigned int valid_dithering_mask = + (1U << ARRAY_SIZE(drm_dithering_enum_list)) - 1; + + if (WARN_ON(hweight32(dithering_mask) < 2 || + dithering_mask & ~valid_dithering_mask)) + return -EINVAL; + + dithering_property = + drm_property_create(dev, DRM_MODE_PROP_ENUM, "dithering", + hweight32(dithering_mask)); + + if (!dithering_property) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(drm_dithering_enum_list); i++) { + int ret; + + if (!(BIT(i) & dithering_mask)) + continue; + + ret = drm_property_add_enum(dithering_property, + drm_dithering_enum_list[i].type, + drm_dithering_enum_list[i].name); + + if (ret) { + drm_property_destroy(dev, dithering_property); + + return ret; + } + } + + drm_object_attach_property(&connector->base, + dithering_property, 0); + + connector->dithering_property = dithering_property; + + return 0; +} +EXPORT_SYMBOL(drm_connector_attach_dithering_property); + /** * drm_mode_create_aspect_ratio_property - create aspect ratio property * @dev: DRM device diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 479ffdb64486..c49fb01b1ce5 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -359,6 +359,15 @@ 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_HX8394 + tristate "Rocktech HX8394 720x1280 DSI video mode 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 HX8394 + 720x1280 DSI video mode panel. + config DRM_PANEL_RONBO_RB070D30 tristate "Ronbo Electronics RB070D30 panel" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index c8132050bcec..57d7948975c2 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o obj-$(CONFIG_DRM_PANEL_ELIDA_KD35T133) += panel-elida-kd35t133.o obj-$(CONFIG_DRM_PANEL_FEIXIN_K101_IM2BA02) += panel-feixin-k101-im2ba02.o obj-$(CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D) += panel-feiyang-fy07024di26a30d.o +obj-$(CONFIG_DRM_PANEL_ROCKTECH_HX8394) += panel-rocktech-hx8394.o obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9341) += panel-ilitek-ili9341.o obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c index f8dbccd55033..e75d2fdc678f 100644 --- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c +++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include