summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Anderson <dianders@chromium.org>2022-01-05 16:13:42 -0800
committerDouglas Anderson <dianders@chromium.org>2022-01-05 16:13:42 -0800
commit2b5f745c18b850734e1bb7b7e86510ea69698c71 (patch)
treed2ca25e858a14354fe3781e7c84e7c87627f793e
parentef1270e99460055ee7d66a4a22dd74bf61c17aa5 (diff)
parent506d9d7414cfbdce02b7126fc8644f04ef234680 (diff)
Merge remote-tracking branch 'drm-misc/drm-misc-next' into drm-tip
-rw-r--r--Documentation/devicetree/bindings/display/bridge/ti,sn65dsi83.yaml5
-rw-r--r--drivers/gpu/drm/bridge/analogix/anx7625.c41
-rw-r--r--drivers/gpu/drm/bridge/chipone-icn6211.c39
-rw-r--r--drivers/gpu/drm/bridge/nwl-dsi.c1
-rw-r--r--drivers/gpu/drm/bridge/parade-ps8640.c29
-rw-r--r--drivers/gpu/drm/bridge/sil-sii8620.c2
-rw-r--r--drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c6
-rw-r--r--drivers/gpu/drm/bridge/ti-sn65dsi83.c53
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c12
-rw-r--r--drivers/gpu/drm/drm_plane.c9
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dsi.c86
-rw-r--r--drivers/gpu/drm/ingenic/ingenic-drm-drv.c62
-rw-r--r--drivers/gpu/drm/ingenic/ingenic-drm.h38
-rw-r--r--drivers/gpu/drm/meson/meson_drv.c25
-rw-r--r--drivers/gpu/drm/meson/meson_osd_afbcd.c41
-rw-r--r--drivers/gpu/drm/meson/meson_osd_afbcd.h1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dp.c15
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c317
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h35
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c13
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/sorga102.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c14
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c18
-rw-r--r--drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c8
-rw-r--r--drivers/gpu/drm/selftests/test-drm_plane_helper.c4
-rw-r--r--drivers/gpu/drm/stm/drv.c5
-rw-r--r--drivers/gpu/drm/stm/dw_mipi_dsi-stm.c114
-rw-r--r--drivers/gpu/drm/stm/ltdc.c172
-rw-r--r--drivers/gpu/drm/stm/ltdc.h3
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.c4
-rw-r--r--include/drm/bridge/dw_mipi_dsi.h4
-rw-r--r--include/drm/drm_mipi_dbi.h2
-rw-r--r--include/drm/drm_plane.h2
33 files changed, 929 insertions, 255 deletions
diff --git a/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi83.yaml b/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi83.yaml
index b446d0f0f1b4..48a97bb3e2e0 100644
--- a/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi83.yaml
+++ b/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi83.yaml
@@ -32,6 +32,9 @@ properties:
maxItems: 1
description: GPIO specifier for bridge_en pin (active high).
+ vcc-supply:
+ description: A 1.8V power supply (see regulator/regulator.yaml).
+
ports:
$ref: /schemas/graph.yaml#/properties/ports
@@ -91,7 +94,6 @@ properties:
required:
- compatible
- reg
- - enable-gpios
- ports
allOf:
@@ -133,6 +135,7 @@ examples:
reg = <0x2d>;
enable-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>;
+ vcc-supply = <&reg_sn65dsi83_1v8>;
ports {
#address-cells = <1>;
diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c
index 2346dbcc505f..7b24213f7b13 100644
--- a/drivers/gpu/drm/bridge/analogix/anx7625.c
+++ b/drivers/gpu/drm/bridge/analogix/anx7625.c
@@ -1098,9 +1098,18 @@ static void anx7625_init_gpio(struct anx7625_data *platform)
/* Gpio for chip power enable */
platform->pdata.gpio_p_on =
devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW);
+ if (IS_ERR_OR_NULL(platform->pdata.gpio_p_on)) {
+ DRM_DEV_DEBUG_DRIVER(dev, "no enable gpio found\n");
+ platform->pdata.gpio_p_on = NULL;
+ }
+
/* Gpio for chip reset */
platform->pdata.gpio_reset =
devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR_OR_NULL(platform->pdata.gpio_reset)) {
+ DRM_DEV_DEBUG_DRIVER(dev, "no reset gpio found\n");
+ platform->pdata.gpio_reset = NULL;
+ }
if (platform->pdata.gpio_p_on && platform->pdata.gpio_reset) {
platform->pdata.low_power_mode = 1;
@@ -1962,40 +1971,54 @@ static const struct drm_bridge_funcs anx7625_bridge_funcs = {
static int anx7625_register_i2c_dummy_clients(struct anx7625_data *ctx,
struct i2c_client *client)
{
+ int err = 0;
+
ctx->i2c.tx_p0_client = i2c_new_dummy_device(client->adapter,
TX_P0_ADDR >> 1);
- if (!ctx->i2c.tx_p0_client)
- return -ENOMEM;
+ if (IS_ERR(ctx->i2c.tx_p0_client))
+ return PTR_ERR(ctx->i2c.tx_p0_client);
ctx->i2c.tx_p1_client = i2c_new_dummy_device(client->adapter,
TX_P1_ADDR >> 1);
- if (!ctx->i2c.tx_p1_client)
+ if (IS_ERR(ctx->i2c.tx_p1_client)) {
+ err = PTR_ERR(ctx->i2c.tx_p1_client);
goto free_tx_p0;
+ }
ctx->i2c.tx_p2_client = i2c_new_dummy_device(client->adapter,
TX_P2_ADDR >> 1);
- if (!ctx->i2c.tx_p2_client)
+ if (IS_ERR(ctx->i2c.tx_p2_client)) {
+ err = PTR_ERR(ctx->i2c.tx_p2_client);
goto free_tx_p1;
+ }
ctx->i2c.rx_p0_client = i2c_new_dummy_device(client->adapter,
RX_P0_ADDR >> 1);
- if (!ctx->i2c.rx_p0_client)
+ if (IS_ERR(ctx->i2c.rx_p0_client)) {
+ err = PTR_ERR(ctx->i2c.rx_p0_client);
goto free_tx_p2;
+ }
ctx->i2c.rx_p1_client = i2c_new_dummy_device(client->adapter,
RX_P1_ADDR >> 1);
- if (!ctx->i2c.rx_p1_client)
+ if (IS_ERR(ctx->i2c.rx_p1_client)) {
+ err = PTR_ERR(ctx->i2c.rx_p1_client);
goto free_rx_p0;
+ }
ctx->i2c.rx_p2_client = i2c_new_dummy_device(client->adapter,
RX_P2_ADDR >> 1);
- if (!ctx->i2c.rx_p2_client)
+ if (IS_ERR(ctx->i2c.rx_p2_client)) {
+ err = PTR_ERR(ctx->i2c.rx_p2_client);
goto free_rx_p1;
+ }
ctx->i2c.tcpc_client = i2c_new_dummy_device(client->adapter,
TCPC_INTERFACE_ADDR >> 1);
- if (!ctx->i2c.tcpc_client)
+ if (IS_ERR(ctx->i2c.tcpc_client)) {
+ err = PTR_ERR(ctx->i2c.tcpc_client);
goto free_rx_p2;
+ }
return 0;
@@ -2012,7 +2035,7 @@ free_tx_p1:
free_tx_p0:
i2c_unregister_device(ctx->i2c.tx_p0_client);
- return -ENOMEM;
+ return err;
}
static void anx7625_unregister_i2c_dummy_clients(struct anx7625_data *ctx)
diff --git a/drivers/gpu/drm/bridge/chipone-icn6211.c b/drivers/gpu/drm/bridge/chipone-icn6211.c
index a6151db95586..e8f36dca56b3 100644
--- a/drivers/gpu/drm/bridge/chipone-icn6211.c
+++ b/drivers/gpu/drm/bridge/chipone-icn6211.c
@@ -4,6 +4,7 @@
* Author: Jagan Teki <jagan@amarulasolutions.com>
*/
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_print.h>
#include <drm/drm_mipi_dsi.h>
@@ -30,6 +31,7 @@
struct chipone {
struct device *dev;
struct drm_bridge bridge;
+ struct drm_display_mode mode;
struct drm_bridge *panel_bridge;
struct gpio_desc *enable_gpio;
struct regulator *vdd1;
@@ -42,11 +44,6 @@ static inline struct chipone *bridge_to_chipone(struct drm_bridge *bridge)
return container_of(bridge, struct chipone, bridge);
}
-static struct drm_display_mode *bridge_to_mode(struct drm_bridge *bridge)
-{
- return &bridge->encoder->crtc->state->adjusted_mode;
-}
-
static inline int chipone_dsi_write(struct chipone *icn, const void *seq,
size_t len)
{
@@ -61,10 +58,11 @@ static inline int chipone_dsi_write(struct chipone *icn, const void *seq,
chipone_dsi_write(icn, d, ARRAY_SIZE(d)); \
}
-static void chipone_enable(struct drm_bridge *bridge)
+static void chipone_atomic_enable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
{
struct chipone *icn = bridge_to_chipone(bridge);
- struct drm_display_mode *mode = bridge_to_mode(bridge);
+ struct drm_display_mode *mode = &icn->mode;
ICN6211_DSI(icn, 0x7a, 0xc1);
@@ -114,7 +112,8 @@ static void chipone_enable(struct drm_bridge *bridge)
usleep_range(10000, 11000);
}
-static void chipone_pre_enable(struct drm_bridge *bridge)
+static void chipone_atomic_pre_enable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
{
struct chipone *icn = bridge_to_chipone(bridge);
int ret;
@@ -145,7 +144,8 @@ static void chipone_pre_enable(struct drm_bridge *bridge)
usleep_range(10000, 11000);
}
-static void chipone_post_disable(struct drm_bridge *bridge)
+static void chipone_atomic_post_disable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
{
struct chipone *icn = bridge_to_chipone(bridge);
@@ -161,6 +161,15 @@ static void chipone_post_disable(struct drm_bridge *bridge)
gpiod_set_value(icn->enable_gpio, 0);
}
+static void chipone_mode_set(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ const struct drm_display_mode *adjusted_mode)
+{
+ struct chipone *icn = bridge_to_chipone(bridge);
+
+ drm_mode_copy(&icn->mode, adjusted_mode);
+}
+
static int chipone_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags)
{
struct chipone *icn = bridge_to_chipone(bridge);
@@ -169,10 +178,14 @@ static int chipone_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flag
}
static const struct drm_bridge_funcs chipone_bridge_funcs = {
- .attach = chipone_attach,
- .post_disable = chipone_post_disable,
- .pre_enable = chipone_pre_enable,
- .enable = chipone_enable,
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+ .atomic_reset = drm_atomic_helper_bridge_reset,
+ .atomic_pre_enable = chipone_atomic_pre_enable,
+ .atomic_enable = chipone_atomic_enable,
+ .atomic_post_disable = chipone_atomic_post_disable,
+ .mode_set = chipone_mode_set,
+ .attach = chipone_attach,
};
static int chipone_parse_dt(struct chipone *icn)
diff --git a/drivers/gpu/drm/bridge/nwl-dsi.c b/drivers/gpu/drm/bridge/nwl-dsi.c
index a7389a0facfb..fc3ad9fab867 100644
--- a/drivers/gpu/drm/bridge/nwl-dsi.c
+++ b/drivers/gpu/drm/bridge/nwl-dsi.c
@@ -1206,6 +1206,7 @@ static int nwl_dsi_probe(struct platform_device *pdev)
ret = nwl_dsi_select_input(dsi);
if (ret < 0) {
+ pm_runtime_disable(dev);
mipi_dsi_host_unregister(&dsi->dsi_host);
return ret;
}
diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
index 818704bf5e86..54723f068884 100644
--- a/drivers/gpu/drm/bridge/parade-ps8640.c
+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
@@ -102,6 +102,7 @@ struct ps8640 {
struct regulator_bulk_data supplies[2];
struct gpio_desc *gpio_reset;
struct gpio_desc *gpio_powerdown;
+ struct device_link *link;
bool pre_enabled;
};
@@ -456,14 +457,36 @@ static int ps8640_bridge_attach(struct drm_bridge *bridge,
return ret;
}
+ ps_bridge->link = device_link_add(bridge->dev->dev, dev, DL_FLAG_STATELESS);
+ if (!ps_bridge->link) {
+ dev_err(dev, "failed to create device link");
+ ret = -EINVAL;
+ goto err_devlink;
+ }
+
/* Attach the panel-bridge to the dsi bridge */
- return drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge,
- &ps_bridge->bridge, flags);
+ ret = drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge,
+ &ps_bridge->bridge, flags);
+ if (ret)
+ goto err_bridge_attach;
+
+ return 0;
+
+err_bridge_attach:
+ device_link_del(ps_bridge->link);
+err_devlink:
+ drm_dp_aux_unregister(&ps_bridge->aux);
+
+ return ret;
}
static void ps8640_bridge_detach(struct drm_bridge *bridge)
{
- drm_dp_aux_unregister(&bridge_to_ps8640(bridge)->aux);
+ struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
+
+ drm_dp_aux_unregister(&ps_bridge->aux);
+ if (ps_bridge->link)
+ device_link_del(ps_bridge->link);
}
static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge,
diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c
index 843265d7f1b1..ec7745c31da0 100644
--- a/drivers/gpu/drm/bridge/sil-sii8620.c
+++ b/drivers/gpu/drm/bridge/sil-sii8620.c
@@ -2120,7 +2120,7 @@ static void sii8620_init_rcp_input_dev(struct sii8620 *ctx)
if (ret) {
dev_err(ctx->dev, "Failed to register RC device\n");
ctx->error = ret;
- rc_free_device(ctx->rc_dev);
+ rc_free_device(rc_dev);
return;
}
ctx->rc_dev = rc_dev;
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
index e44e18a0112a..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;
}
@@ -1199,6 +1202,7 @@ __dw_mipi_dsi_probe(struct platform_device *pdev,
ret = mipi_dsi_host_register(&dsi->dsi_host);
if (ret) {
dev_err(dev, "Failed to register MIPI host: %d\n", ret);
+ pm_runtime_disable(dev);
dw_mipi_dsi_debugfs_remove(dsi);
return ERR_PTR(ret);
}
diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c
index 945f08de45f1..19daaddd29a4 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c
@@ -33,6 +33,7 @@
#include <linux/of_device.h>
#include <linux/of_graph.h>
#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
@@ -143,6 +144,7 @@ struct sn65dsi83 {
struct mipi_dsi_device *dsi;
struct drm_bridge *panel_bridge;
struct gpio_desc *enable_gpio;
+ struct regulator *vcc;
int dsi_lanes;
bool lvds_dual_link;
bool lvds_dual_link_even_odd_swap;
@@ -337,6 +339,12 @@ static void sn65dsi83_atomic_enable(struct drm_bridge *bridge,
u16 val;
int ret;
+ ret = regulator_enable(ctx->vcc);
+ if (ret) {
+ dev_err(ctx->dev, "Failed to enable vcc: %d\n", ret);
+ return;
+ }
+
/* Deassert reset */
gpiod_set_value(ctx->enable_gpio, 1);
usleep_range(1000, 1100);
@@ -486,11 +494,16 @@ static void sn65dsi83_atomic_disable(struct drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
{
struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge);
+ int ret;
/* Put the chip in reset, pull EN line low, and assure 10ms reset low timing. */
gpiod_set_value(ctx->enable_gpio, 0);
usleep_range(10000, 11000);
+ ret = regulator_disable(ctx->vcc);
+ if (ret)
+ dev_err(ctx->dev, "Failed to disable vcc: %d\n", ret);
+
regcache_mark_dirty(ctx->regmap);
}
@@ -560,10 +573,14 @@ static int sn65dsi83_parse_dt(struct sn65dsi83 *ctx, enum sn65dsi83_model model)
ctx->host_node = of_graph_get_remote_port_parent(endpoint);
of_node_put(endpoint);
- if (ctx->dsi_lanes < 0 || ctx->dsi_lanes > 4)
- return -EINVAL;
- if (!ctx->host_node)
- return -ENODEV;
+ if (ctx->dsi_lanes < 0 || ctx->dsi_lanes > 4) {
+ ret = -EINVAL;
+ goto err_put_node;
+ }
+ if (!ctx->host_node) {
+ ret = -ENODEV;
+ goto err_put_node;
+ }
ctx->lvds_dual_link = false;
ctx->lvds_dual_link_even_odd_swap = false;
@@ -590,16 +607,27 @@ static int sn65dsi83_parse_dt(struct sn65dsi83 *ctx, enum sn65dsi83_model model)
ret = drm_of_find_panel_or_bridge(dev->of_node, 2, 0, &panel, &panel_bridge);
if (ret < 0)
- return ret;
+ goto err_put_node;
if (panel) {
panel_bridge = devm_drm_panel_bridge_add(dev, panel);
- if (IS_ERR(panel_bridge))
- return PTR_ERR(panel_bridge);
+ if (IS_ERR(panel_bridge)) {
+ ret = PTR_ERR(panel_bridge);
+ goto err_put_node;
+ }
}
ctx->panel_bridge = panel_bridge;
+ ctx->vcc = devm_regulator_get(dev, "vcc");
+ if (IS_ERR(ctx->vcc))
+ return dev_err_probe(dev, PTR_ERR(ctx->vcc),
+ "Failed to get supply 'vcc'\n");
+
return 0;
+
+err_put_node:
+ of_node_put(ctx->host_node);
+ return ret;
}
static int sn65dsi83_host_attach(struct sn65dsi83 *ctx)
@@ -662,7 +690,8 @@ static int sn65dsi83_probe(struct i2c_client *client,
}
/* Put the chip in reset, pull EN line low, and assure 10ms reset low timing. */
- ctx->enable_gpio = devm_gpiod_get(ctx->dev, "enable", GPIOD_OUT_LOW);
+ ctx->enable_gpio = devm_gpiod_get_optional(ctx->dev, "enable",
+ GPIOD_OUT_LOW);
if (IS_ERR(ctx->enable_gpio))
return PTR_ERR(ctx->enable_gpio);
@@ -673,8 +702,10 @@ static int sn65dsi83_probe(struct i2c_client *client,
return ret;
ctx->regmap = devm_regmap_init_i2c(client, &sn65dsi83_regmap_config);
- if (IS_ERR(ctx->regmap))
- return PTR_ERR(ctx->regmap);
+ if (IS_ERR(ctx->regmap)) {
+ ret = PTR_ERR(ctx->regmap);
+ goto err_put_node;
+ }
dev_set_drvdata(dev, ctx);
i2c_set_clientdata(client, ctx);
@@ -691,6 +722,8 @@ static int sn65dsi83_probe(struct i2c_client *client,
err_remove_bridge:
drm_bridge_remove(&ctx->bridge);
+err_put_node:
+ of_node_put(ctx->host_node);
return ret;
}
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index aef2fbd676e5..a7a05e1e26bb 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -828,8 +828,8 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state,
}
if (!crtc_state->enable && !can_update_disabled) {
- drm_dbg_kms(plane_state->crtc->dev,
- "Cannot update plane of a disabled CRTC.\n");
+ drm_dbg_kms(plane_state->plane->dev,
+ "Cannot update plane of a disabled CRTC.\n");
return -EINVAL;
}
@@ -839,8 +839,8 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state,
hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale);
vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale);
if (hscale < 0 || vscale < 0) {
- drm_dbg_kms(plane_state->crtc->dev,
- "Invalid scaling of plane\n");
+ drm_dbg_kms(plane_state->plane->dev,
+ "Invalid scaling of plane\n");
drm_rect_debug_print("src: ", &plane_state->src, true);
drm_rect_debug_print("dst: ", &plane_state->dst, false);
return -ERANGE;
@@ -864,8 +864,8 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state,
return 0;
if (!can_position && !drm_rect_equals(dst, &clip)) {
- drm_dbg_kms(plane_state->crtc->dev,
- "Plane must cover entire CRTC\n");
+ drm_dbg_kms(plane_state->plane->dev,
+ "Plane must cover entire CRTC\n");
drm_rect_debug_print("dst: ", dst, false);
drm_rect_debug_print("clip: ", &clip, false);
return -EINVAL;
diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c
index 82afb854141b..deeec60a3315 100644
--- a/drivers/gpu/drm/drm_plane.c
+++ b/drivers/gpu/drm/drm_plane.c
@@ -202,17 +202,13 @@ static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane
memcpy(formats_ptr(blob_data), plane->format_types, formats_size);
- /* If we can't determine support, just bail */
- if (!plane->funcs->format_mod_supported)
- goto done;
-
mod = modifiers_ptr(blob_data);
for (i = 0; i < plane->modifier_count; i++) {
for (j = 0; j < plane->format_count; j++) {
- if (plane->funcs->format_mod_supported(plane,
+ if (!plane->funcs->format_mod_supported ||
+ plane->funcs->format_mod_supported(plane,
plane->format_types[j],
plane->modifiers[i])) {
-
mod->formats |= 1ULL << j;
}
}
@@ -223,7 +219,6 @@ static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane
mod++;
}
-done:
drm_object_attach_property(&plane->base, config->modifiers_property,
blob->base.id);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 32a36572b894..fe2afd85b1fa 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -256,8 +256,10 @@ struct exynos_dsi {
struct drm_connector connector;
struct drm_panel *panel;
struct list_head bridge_chain;
+ struct drm_bridge bridge;
struct drm_bridge *out_bridge;
struct device *dev;
+ struct drm_display_mode mode;
void __iomem *reg_base;
struct phy *phy;
@@ -286,9 +288,9 @@ struct exynos_dsi {
#define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host)
#define connector_to_dsi(c) container_of(c, struct exynos_dsi, connector)
-static inline struct exynos_dsi *encoder_to_dsi(struct drm_encoder *e)
+static inline struct exynos_dsi *bridge_to_dsi(struct drm_bridge *b)
{
- return container_of(e, struct exynos_dsi, encoder);
+ return container_of(b, struct exynos_dsi, bridge);
}
enum reg_idx {
@@ -881,7 +883,7 @@ static int exynos_dsi_init_link(struct exynos_dsi *dsi)
static void exynos_dsi_set_display_mode(struct exynos_dsi *dsi)
{
- struct drm_display_mode *m = &dsi->encoder.crtc->state->adjusted_mode;
+ struct drm_display_mode *m = &dsi->mode;
unsigned int num_bits_resol = dsi->driver_data->num_bits_resol;
u32 reg;
@@ -1362,9 +1364,10 @@ static void exynos_dsi_unregister_te_irq(struct exynos_dsi *dsi)
}
}
-static void exynos_dsi_enable(struct drm_encoder *encoder)
+static void exynos_dsi_atomic_enable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
{
- struct exynos_dsi *dsi = encoder_to_dsi(encoder);
+ struct exynos_dsi *dsi = bridge_to_dsi(bridge);
struct drm_bridge *iter;
int ret;
@@ -1387,7 +1390,8 @@ static void exynos_dsi_enable(struct drm_encoder *encoder)
list_for_each_entry_reverse(iter, &dsi->bridge_chain,
chain_node) {
if (iter->funcs->pre_enable)
- iter->funcs->pre_enable(iter);
+ iter->funcs->atomic_pre_enable(iter,
+ old_bridge_state);
}
}
@@ -1401,7 +1405,7 @@ static void exynos_dsi_enable(struct drm_encoder *encoder)
} else {
list_for_each_entry(iter, &dsi->bridge_chain, chain_node) {
if (iter->funcs->enable)
- iter->funcs->enable(iter);
+ iter->funcs->atomic_enable(iter, old_bridge_state);
}
}
@@ -1417,9 +1421,10 @@ err_put_sync:
pm_runtime_put(dsi->dev);
}
-static void exynos_dsi_disable(struct drm_encoder *encoder)
+static void exynos_dsi_atomic_disable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
{
- struct exynos_dsi *dsi = encoder_to_dsi(encoder);
+ struct exynos_dsi *dsi = bridge_to_dsi(bridge);
struct drm_bridge *iter;
if (!(dsi->state & DSIM_STATE_ENABLED))
@@ -1431,7 +1436,7 @@ static void exynos_dsi_disable(struct drm_encoder *encoder)
list_for_each_entry_reverse(iter, &dsi->bridge_chain, chain_node) {
if (iter->funcs->disable)
- iter->funcs->disable(iter);
+ iter->funcs->atomic_disable(iter, old_bridge_state);
}
exynos_dsi_set_display_enable(dsi, false);
@@ -1439,7 +1444,7 @@ static void exynos_dsi_disable(struct drm_encoder *encoder)
list_for_each_entry(iter, &dsi->bridge_chain, chain_node) {
if (iter->funcs->post_disable)
- iter->funcs->post_disable(iter);
+ iter->funcs->atomic_post_disable(iter, old_bridge_state);
}
dsi->state &= ~DSIM_STATE_ENABLED;
@@ -1482,9 +1487,9 @@ static const struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs
.get_modes = exynos_dsi_get_modes,
};
-static int exynos_dsi_create_connector(struct drm_encoder *encoder)
+static int exynos_dsi_create_connector(struct exynos_dsi *dsi)
{
- struct exynos_dsi *dsi = encoder_to_dsi(encoder);
+ struct drm_encoder *encoder = &dsi->encoder;
struct drm_connector *connector = &dsi->connector;
struct drm_device *drm = encoder->dev;
int ret;
@@ -1510,9 +1515,31 @@ static int exynos_dsi_create_connector(struct drm_encoder *encoder)
return 0;
}
-static const struct drm_encoder_helper_funcs exynos_dsi_encoder_helper_funcs = {
- .enable = exynos_dsi_enable,
- .disable = exynos_dsi_disable,
+static void exynos_dsi_mode_set(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ const struct drm_display_mode *adjusted_mode)
+{
+ struct exynos_dsi *dsi = bridge_to_dsi(bridge);
+
+ drm_mode_copy(&dsi->mode, adjusted_mode);
+}
+
+static int exynos_dsi_attach(struct drm_bridge *bridge,
+ enum drm_bridge_attach_flags flags)
+{
+ struct exynos_dsi *dsi = bridge_to_dsi(bridge);
+
+ return drm_bridge_attach(bridge->encoder, dsi->out_bridge, NULL, 0);
+}
+
+static const struct drm_bridge_funcs exynos_dsi_bridge_funcs = {
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+ .atomic_reset = drm_atomic_helper_bridge_reset,
+ .atomic_enable = exynos_dsi_atomic_enable,
+ .atomic_disable = exynos_dsi_atomic_disable,
+ .mode_set = exynos_dsi_mode_set,
+ .attach = exynos_dsi_attach,
};
MODULE_DEVICE_TABLE(of, exynos_dsi_of_match);
@@ -1531,7 +1558,7 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
dsi->out_bridge = out_bridge;
list_splice_init(&encoder->bridge_chain, &dsi->bridge_chain);
} else {
- int ret = exynos_dsi_create_connector(encoder);
+ int ret = exynos_dsi_create_connector(dsi);
if (ret) {
DRM_DEV_ERROR(dsi->dev,
@@ -1584,7 +1611,7 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host *host,
if (dsi->panel) {
mutex_lock(&drm->mode_config.mutex);
- exynos_dsi_disable(&dsi->encoder);
+ exynos_dsi_atomic_disable(&dsi->bridge, NULL);
dsi->panel = NULL;
dsi->connector.status = connector_status_disconnected;
mutex_unlock(&drm->mode_config.mutex);
@@ -1690,12 +1717,16 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_TMDS);
- drm_encoder_helper_add(encoder, &exynos_dsi_encoder_helper_funcs);
-
ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_LCD);
if (ret < 0)
return ret;
+ ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, 0);
+ if (ret) {
+ drm_encoder_cleanup(&dsi->encoder);
+ return ret;
+ }
+
in_bridge_node = of_graph_get_remote_node(dev->of_node, DSI_PORT_IN, 0);
if (in_bridge_node) {
in_bridge = of_drm_find_bridge(in_bridge_node);
@@ -1711,10 +1742,9 @@ static void exynos_dsi_unbind(struct device *dev, struct device *master,
void *data)
{
struct exynos_dsi *dsi = dev_get_drvdata(dev);
- struct drm_encoder *encoder = &dsi->encoder;
-
- exynos_dsi_disable(encoder);
+ exynos_dsi_atomic_disable(&dsi->bridge, NULL);
+ drm_encoder_cleanup(&dsi->encoder);
mipi_dsi_host_unregister(&dsi->dsi_host);
}
@@ -1804,6 +1834,12 @@ static int exynos_dsi_probe(struct platform_device *pdev)
pm_runtime_enable(dev);
+ dsi->bridge.funcs = &exynos_dsi_bridge_funcs;
+ dsi->bridge.of_node = dev->of_node;
+ dsi->bridge.type = DRM_MODE_CONNECTOR_DSI;
+
+ drm_bridge_add(&dsi->bridge);
+
ret = component_add(dev, &exynos_dsi_component_ops);
if (ret)
goto err_disable_runtime;
@@ -1818,6 +1854,10 @@ err_disable_runtime:
static int exynos_dsi_remove(struct platform_device *pdev)
{
+ struct exynos_dsi *dsi = platform_get_drvdata(pdev);
+
+ drm_bridge_remove(&dsi->bridge);
+
pm_runtime_disable(&pdev->dev);
component_del(&pdev->dev, &exynos_dsi_component_ops);
diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
index b4943a56be09..542c4af70661 100644
--- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
+++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
@@ -6,6 +6,7 @@
#include "ingenic-drm.h"
+#include <linux/bitfield.h>
#include <linux/component.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
@@ -49,6 +50,11 @@ struct ingenic_dma_hwdesc {
u32 addr;
u32 id;
u32 cmd;
+ /* extended hw descriptor for jz4780 */
+ u32 offsize;
+ u32 pagewidth;
+ u32 cpos;
+ u32 dessize;
} __aligned(16);
struct ingenic_dma_hwdescs {
@@ -60,6 +66,7 @@ struct jz_soc_info {
bool needs_dev_clk;
bool has_osd;
bool map_noncoherent;
+ bool use_extended_hwdesc;
unsigned int max_width, max_height;
const u32 *formats_f0, *formats_f1;
unsigned int num_formats_f0, num_formats_f1;
@@ -173,7 +180,6 @@ static const struct regmap_config ingenic_drm_regmap_config = {
.val_bits = 32,
.reg_stride = 4,
- .max_register = JZ_REG_LCD_SIZE1,
.writeable_reg = ingenic_drm_writeable_reg,
};
@@ -447,6 +453,9 @@ static int ingenic_drm_plane_atomic_check(struct drm_plane *plane,
if (!crtc)
return 0;
+ if (plane == &priv->f0)
+ return -EINVAL;
+
crtc_state = drm_atomic_get_existing_crtc_state(state,
crtc);
if (WARN_ON(!crtc_state))
@@ -663,6 +672,33 @@ static void ingenic_drm_plane_atomic_update(struct drm_plane *plane,
hwdesc->cmd = JZ_LCD_CMD_EOF_IRQ | (width * height * cpp / 4);
hwdesc->next = dma_hwdesc_addr(priv, next_id);
+ if (priv->soc_info->use_extended_hwdesc) {
+ hwdesc->cmd |= JZ_LCD_CMD_FRM_ENABLE;
+
+ /* Extended 8-byte descriptor */
+ hwdesc->cpos = 0;
+ hwdesc->offsize = 0;
+ hwdesc->pagewidth = 0;
+
+ switch (newstate->fb->format->format) {
+ case DRM_FORMAT_XRGB1555:
+ hwdesc->cpos |= JZ_LCD_CPOS_RGB555;
+ fallthrough;
+ case DRM_FORMAT_RGB565:
+ hwdesc->cpos |= JZ_LCD_CPOS_BPP_15_16;
+ break;
+ case DRM_FORMAT_XRGB8888:
+ hwdesc->cpos |= JZ_LCD_CPOS_BPP_18_24;
+ break;
+ }
+ hwdesc->cpos |= (JZ_LCD_CPOS_COEFFICIENT_1 <<
+ JZ_LCD_CPOS_COEFFICIENT_OFFSET);
+ hwdesc->dessize =
+ (0xff << JZ_LCD_DESSIZE_ALPHA_OFFSET) |
+ FIELD_PREP(JZ_LCD_DESSIZE_HEIGHT_MASK, height - 1) |
+ FIELD_PREP(JZ_LCD_DESSIZE_WIDTH_MASK, width - 1);
+ }
+
if (drm_atomic_crtc_needs_modeset(crtc_state)) {
fourcc = newstate->fb->format->format;
@@ -694,6 +730,9 @@ static void ingenic_drm_encoder_atomic_mode_set(struct drm_encoder *encoder,
| JZ_LCD_CFG_SPL_DISABLE | JZ_LCD_CFG_REV_DISABLE;
}
+ if (priv->soc_info->use_extended_hwdesc)
+ cfg |= JZ_LCD_CFG_DESCRIPTOR_8;
+
if (mode->flags & DRM_MODE_FLAG_NHSYNC)
cfg |= JZ_LCD_CFG_HSYNC_ACTIVE_LOW;
if (mode->flags & DRM_MODE_FLAG_NVSYNC)
@@ -1011,6 +1050,8 @@ static int ingenic_drm_bind(struct device *dev, bool has_components)
struct ingenic_drm_bridge *ib;
struct drm_device *drm;
void __iomem *base;
+ struct resource *res;
+ struct regmap_config regmap_config;
long parent_rate;
unsigned int i, clone_mask = 0;
int ret, irq;
@@ -1056,14 +1097,16 @@ static int ingenic_drm_bind(struct device *dev, bool has_components)
drm->mode_config.funcs = &ingenic_drm_mode_config_funcs;
drm->mode_config.helper_private = &ingenic_drm_mode_config_helpers;
- base = devm_platform_ioremap_resource(pdev, 0);
+ base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(base)) {
dev_err(dev, "Failed to get memory resource\n");
return PTR_ERR(base);
}
+ regmap_config = ingenic_drm_regmap_config;
+ regmap_config.max_register = res->end - res->start;
priv->map = devm_regmap_init_mmio(dev, base,
- &ingenic_drm_regmap_config);
+ &regmap_config);
if (IS_ERR(priv->map)) {
dev_err(dev, "Failed to create regmap\n");
return PTR_ERR(priv->map);
@@ -1465,10 +1508,23 @@ static const struct jz_soc_info jz4770_soc_info = {
.num_formats_f0 = ARRAY_SIZE(jz4770_formats_f0),
};
+static const struct jz_soc_info jz4780_soc_info = {
+ .needs_dev_clk = true,
+ .has_osd = true,
+ .use_extended_hwdesc = true,
+ .max_width = 4096,
+ .max_height = 2048,
+ .formats_f1 = jz4770_formats_f1,
+ .num_formats_f1 = ARRAY_SIZE(jz4770_formats_f1),
+ .formats_f0 = jz4770_formats_f0,
+ .num_formats_f0 = ARRAY_SIZE(jz4770_formats_f0),
+};
+
static const struct of_device_id ingenic_drm_of_match[] = {
{ .compatible = "ingenic,jz4740-lcd", .data = &jz4740_soc_info },
{ .compatible = "ingenic,jz4725b-lcd", .data = &jz4725b_soc_info },
{ .compatible = "ingenic,jz4770-lcd", .data = &jz4770_soc_info },
+ { .compatible = "ingenic,jz4780-lcd", .data = &jz4780_soc_info },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, ingenic_drm_of_match);
diff --git a/drivers/gpu/drm/ingenic/ingenic-drm.h b/drivers/gpu/drm/ingenic/ingenic-drm.h
index 22654ac1dde1..cb1d09b62588 100644
--- a/drivers/gpu/drm/ingenic/ingenic-drm.h
+++ b/drivers/gpu/drm/ingenic/ingenic-drm.h
@@ -44,8 +44,11 @@
#define JZ_REG_LCD_XYP1 0x124
#define JZ_REG_LCD_SIZE0 0x128
#define JZ_REG_LCD_SIZE1 0x12c
+#define JZ_REG_LCD_PCFG 0x2c0
#define JZ_LCD_CFG_SLCD BIT(31)
+#define JZ_LCD_CFG_DESCRIPTOR_8 BIT(28)
+#define JZ_LCD_CFG_RECOVER_FIFO_UNDERRUN BIT(25)
#define JZ_LCD_CFG_PS_DISABLE BIT(23)
#define JZ_LCD_CFG_CLS_DISABLE BIT(22)
#define JZ_LCD_CFG_SPL_DISABLE BIT(21)
@@ -63,6 +66,7 @@
#define JZ_LCD_CFG_DE_ACTIVE_LOW BIT(9)
#define JZ_LCD_CFG_VSYNC_ACTIVE_LOW BIT(8)
#define JZ_LCD_CFG_18_BIT BIT(7)
+#define JZ_LCD_CFG_24_BIT BIT(6)
#define JZ_LCD_CFG_PDW (BIT(5) | BIT(4))
#define JZ_LCD_CFG_MODE_GENERIC_16BIT 0
@@ -132,6 +136,7 @@
#define JZ_LCD_CMD_SOF_IRQ BIT(31)
#define JZ_LCD_CMD_EOF_IRQ BIT(30)
#define JZ_LCD_CMD_ENABLE_PAL BIT(28)
+#define JZ_LCD_CMD_FRM_ENABLE BIT(26)
#define JZ_LCD_SYNC_MASK 0x3ff
@@ -153,6 +158,7 @@
#define JZ_LCD_RGBC_EVEN_BGR (0x5 << 0)
#define JZ_LCD_OSDC_OSDEN BIT(0)
+#define JZ_LCD_OSDC_ALPHAEN BIT(2)
#define JZ_LCD_OSDC_F0EN BIT(3)
#define JZ_LCD_OSDC_F1EN BIT(4)
@@ -176,6 +182,38 @@
#define JZ_LCD_SIZE01_WIDTH_LSB 0
#define JZ_LCD_SIZE01_HEIGHT_LSB 16
+#define JZ_LCD_DESSIZE_ALPHA_OFFSET 24
+#define JZ_LCD_DESSIZE_HEIGHT_MASK GENMASK(23, 12)
+#define JZ_LCD_DESSIZE_WIDTH_MASK GENMASK(11, 0)
+
+#define JZ_LCD_CPOS_BPP_15_16 (4 << 27)
+#define JZ_LCD_CPOS_BPP_18_24 (5 << 27)
+#define JZ_LCD_CPOS_BPP_30 (7 << 27)
+#define JZ_LCD_CPOS_RGB555 BIT(30)
+#define JZ_LCD_CPOS_PREMULTIPLY_LCD BIT(26)
+#define JZ_LCD_CPOS_COEFFICIENT_OFFSET 24
+#define JZ_LCD_CPOS_COEFFICIENT_0 0
+#define JZ_LCD_CPOS_COEFFICIENT_1 1
+#define JZ_LCD_CPOS_COEFFICIENT_ALPHA1 2
+#define JZ_LCD_CPOS_COEFFICIENT_1_ALPHA1 3
+
+#define JZ_LCD_RGBC_RGB_PADDING BIT(15)
+#define JZ_LCD_RGBC_RGB_PADDING_FIRST BIT(14)
+#define JZ_LCD_RGBC_422 BIT(8)
+#define JZ_LCD_RGBC_RGB_FORMAT_ENABLE BIT(7)
+
+#define JZ_LCD_PCFG_PRI_MODE BIT(31)
+#define JZ_LCD_PCFG_HP_BST_4 (0 << 28)
+#define JZ_LCD_PCFG_HP_BST_8 (1 << 28)
+#define JZ_LCD_PCFG_HP_BST_16 (2 << 28)
+#define JZ_LCD_PCFG_HP_BST_32 (3 << 28)
+#define JZ_LCD_PCFG_HP_BST_64 (4 << 28)
+#define JZ_LCD_PCFG_HP_BST_16_CONT (5 << 28)
+#define JZ_LCD_PCFG_HP_BST_DISABLE (7 << 28)
+#define JZ_LCD_PCFG_THRESHOLD2_OFFSET 18
+#define JZ_LCD_PCFG_THRESHOLD1_OFFSET 9
+#define JZ_LCD_PCFG_THRESHOLD0_OFFSET 0
+
struct device;
struct drm_plane;
struct drm_plane_state;
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
index 80f1d439841a..26aeaf0ab86e 100644
--- a/drivers/gpu/drm/meson/meson_drv.c
+++ b/drivers/gpu/drm/meson/meson_drv.c
@@ -302,42 +302,42 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
if (priv->afbcd.ops) {
ret = priv->afbcd.ops->init(priv);
if (ret)
- return ret;
+ goto free_drm;
}
/* Encoder Initialization */
ret = meson_encoder_cvbs_init(priv);
if (ret)
- goto free_drm;
+ goto exit_afbcd;
if (has_components) {
ret = component_bind_all(drm->dev, drm);
if (ret) {
dev_err(drm->dev, "Couldn't bind all components\n");
- goto free_drm;
+ goto exit_afbcd;
}
}
ret = meson_encoder_hdmi_init(priv);
if (ret)
- goto free_drm;
+ goto exit_afbcd;
ret = meson_plane_create(priv);
if (ret)
- goto free_drm;
+ goto exit_afbcd;
ret = meson_overlay_create(priv);
if (ret)
- goto free_drm;
+ goto exit_afbcd;
ret = meson_crtc_create(priv);
if (ret)
- goto free_drm;
+ goto exit_afbcd;
ret = request_irq(priv->vsync_irq, meson_irq, 0, drm->driver->name, drm);
if (ret)
- goto free_drm;
+ goto exit_afbcd;
drm_mode_config_reset(drm);
@@ -355,6 +355,9 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
uninstall_irq:
free_irq(priv->vsync_irq, drm);
+exit_afbcd:
+ if (priv->afbcd.ops)
+ priv->afbcd.ops->exit(priv);
free_drm:
drm_dev_put(drm);
@@ -385,10 +388,8 @@ static void meson_drv_unbind(struct device *dev)
free_irq(priv->vsync_irq, drm);
drm_dev_put(drm);
- if (priv->afbcd.ops) {
- priv->afbcd.ops->reset(priv);
- meson_rdma_free(priv);
- }
+ if (priv->afbcd.ops)
+ priv->afbcd.ops->exit(priv);
}
static const struct component_master_ops meson_drv_master_ops = {
diff --git a/drivers/gpu/drm/meson/meson_osd_afbcd.c b/drivers/gpu/drm/meson/meson_osd_afbcd.c
index ffc6b584dbf8..0cdbe899402f 100644
--- a/drivers/gpu/drm/meson/meson_osd_afbcd.c
+++ b/drivers/gpu/drm/meson/meson_osd_afbcd.c
@@ -79,11 +79,6 @@ static bool meson_gxm_afbcd_supported_fmt(u64 modifier, uint32_t format)
return meson_gxm_afbcd_pixel_fmt(modifier, format) >= 0;
}
-static int meson_gxm_afbcd_init(struct meson_drm *priv)
-{
- return 0;
-}
-
static int meson_gxm_afbcd_reset(struct meson_drm *priv)
{
writel_relaxed(VIU_SW_RESET_OSD1_AFBCD,
@@ -93,6 +88,16 @@ static int meson_gxm_afbcd_reset(struct meson_drm *priv)
return 0;
}
+static int meson_gxm_afbcd_init(struct meson_drm *priv)
+{
+ return 0;
+}
+
+static void meson_gxm_afbcd_exit(struct meson_drm *priv)
+{
+ meson_gxm_afbcd_reset(priv);
+}
+
static int meson_gxm_afbcd_enable(struct meson_drm *priv)
{
writel_relaxed(FIELD_PREP(OSD1_AFBCD_ID_FIFO_THRD, 0x40) |
@@ -172,6 +177,7 @@ static int meson_gxm_afbcd_setup(struct meson_drm *priv)
struct meson_afbcd_ops meson_afbcd_gxm_ops = {
.init = meson_gxm_afbcd_init,
+ .exit = meson_gxm_afbcd_exit,
.reset = meson_gxm_afbcd_reset,
.enable = meson_gxm_afbcd_enable,
.disable = meson_gxm_afbcd_disable,
@@ -269,6 +275,18 @@ static bool meson_g12a_afbcd_supported_fmt(u64 modifier, uint32_t format)
return meson_g12a_afbcd_pixel_fmt(modifier, format) >= 0;
}
+static int meson_g12a_afbcd_reset(struct meson_drm *priv)
+{
+ meson_rdma_reset(priv);
+
+ meson_rdma_writel_sync(priv, VIU_SW_RESET_G12A_AFBC_ARB |
+ VIU_SW_RESET_G12A_OSD1_AFBCD,
+ VIU_SW_RESET);
+ meson_rdma_writel_sync(priv, 0, VIU_SW_RESET);
+
+ return 0;
+}
+
static int meson_g12a_afbcd_init(struct meson_drm *priv)
{
int ret;
@@ -286,16 +304,10 @@ static int meson_g12a_afbcd_init(struct meson_drm *priv)
return 0;
}
-static int meson_g12a_afbcd_reset(struct meson_drm *priv)
+static void meson_g12a_afbcd_exit(struct meson_drm *priv)
{
- meson_rdma_reset(priv);
-
- meson_rdma_writel_sync(priv, VIU_SW_RESET_G12A_AFBC_ARB |
- VIU_SW_RESET_G12A_OSD1_AFBCD,
- VIU_SW_RESET);
- meson_rdma_writel_sync(priv, 0, VIU_SW_RESET);
-
- return 0;
+ meson_g12a_afbcd_reset(priv);
+ meson_rdma_free(priv);
}
static int meson_g12a_afbcd_enable(struct meson_drm *priv)
@@ -380,6 +392,7 @@ static int meson_g12a_afbcd_setup(struct meson_drm *priv)
struct meson_afbcd_ops meson_afbcd_g12a_ops = {
.init = meson_g12a_afbcd_init,
+ .exit = meson_g12a_afbcd_exit,
.reset = meson_g12a_afbcd_reset,
.enable = meson_g12a_afbcd_enable,
.disable = meson_g12a_afbcd_disable,
diff --git a/drivers/gpu/drm/meson/meson_osd_afbcd.h b/drivers/gpu/drm/meson/meson_osd_afbcd.h
index 5e5523304f42..e77ddeb6416f 100644
--- a/drivers/gpu/drm/meson/meson_osd_afbcd.h
+++ b/drivers/gpu/drm/meson/meson_osd_afbcd.h
@@ -14,6 +14,7 @@
struct meson_afbcd_ops {
int (*init)(struct meson_drm *priv);
+ void (*exit)(struct meson_drm *priv);
int (*reset)(struct meson_drm *priv);
int (*enable)(struct meson_drm *priv);
int (*disable)(struct meson_drm *priv);
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
index 040ed88d362d..3a288d0b848f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -147,6 +147,21 @@ nouveau_dp_detect(struct nouveau_connector *nv_connector,
nv_encoder->dp.link_nr =
dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK;
+ if (connector->connector_type == DRM_MODE_CONNECTOR_eDP && dpcd[DP_DPCD_REV] >= 0x13) {
+ struct drm_dp_aux *aux = &nv_connector->aux;
+ int ret, i;
+ u8 sink_rates[16];
+
+ ret = drm_dp_dpcd_read(aux, DP_SUPPORTED_LINK_RATES, sink_rates, sizeof(sink_rates));
+ if (ret == sizeof(sink_rates)) {
+ for (i = 0; i < ARRAY_SIZE(sink_rates); i += 2) {
+ int val = ((sink_rates[i + 1] << 8) | sink_rates[i]) * 200 / 10;
+ if (val && (i == 0 || val > nv_encoder->dp.link_bw))
+ nv_encoder->dp.link_bw = val;
+ }
+ }
+ }
+
NV_DEBUG(drm, "display: %dx%d dpcd 0x%02x\n",
nv_encoder->dp.link_nr, nv_encoder->dp.link_bw,
dpcd[DP_DPCD_REV]);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
index 9669472a2749..8e09315b8fb3 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
@@ -41,6 +41,10 @@
struct lt_state {
struct nvkm_dp *dp;
+
+ int repeaters;
+ int repeater;
+
u8 stat[6];
u8 conf[4];
bool pc2;
@@ -52,14 +56,26 @@ static int
nvkm_dp_train_sense(struct lt_state *lt, bool pc, u32 delay)
{
struct nvkm_dp *dp = lt->dp;
+ u32 addr;
int ret;
- if (dp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL])
- mdelay(dp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL] * 4);
+ usleep_range(delay, delay * 2);
+
+ if (lt->repeater)
+ addr = DPCD_LTTPR_LANE0_1_STATUS(lt->repeater);
+ else
+ addr = DPCD_LS02;
+
+ ret = nvkm_rdaux(dp->aux, addr, &lt->stat[0], 3);
+ if (ret)
+ return ret;
+
+ if (lt->repeater)
+ addr = DPCD_LTTPR_LANE0_1_ADJUST(lt->repeater);
else
- udelay(delay);
+ addr = DPCD_LS06;
- ret = nvkm_rdaux(dp->aux, DPCD_LS02, lt->stat, 6);
+ ret = nvkm_rdaux(dp->aux, addr, &lt->stat[4], 2);
if (ret)
return ret;
@@ -85,6 +101,7 @@ nvkm_dp_train_drive(struct lt_state *lt, bool pc)
struct nvbios_dpout info;
struct nvbios_dpcfg ocfg;
u8 ver, hdr, cnt, len;
+ u32 addr;
u32 data;
int ret, i;
@@ -113,6 +130,9 @@ nvkm_dp_train_drive(struct lt_state *lt, bool pc)
OUTP_TRACE(&dp->outp, "config lane %d %02x %02x",
i, lt->conf[i], lpc2);
+ if (lt->repeater != lt->repeaters)
+ continue;
+
data = nvbios_dpout_match(bios, dp->outp.info.hasht,
dp->outp.info.hashm,
&ver, &hdr, &cnt, &len, &info);
@@ -129,7 +149,12 @@ nvkm_dp_train_drive(struct lt_state *lt, bool pc)
ocfg.pe, ocfg.tx_pu);
}
- ret = nvkm_wraux(dp->aux, DPCD_LC03(0), lt->conf, 4);
+ if (lt->repeater)
+ addr = DPCD_LTTPR_LANE0_SET(lt->repeater);
+ else
+ addr = DPCD_LC03(0);
+
+ ret = nvkm_wraux(dp->aux, addr, lt->conf, 4);
if (ret)
return ret;
@@ -146,32 +171,59 @@ static void
nvkm_dp_train_pattern(struct lt_state *lt, u8 pattern)
{
struct nvkm_dp *dp = lt->dp;
+ u32 addr;
u8 sink_tp;
OUTP_TRACE(&dp->outp, "training pattern %d", pattern);
dp->outp.ior->func->dp.pattern(dp->outp.ior, pattern);
- nvkm_rdaux(dp->aux, DPCD_LC02, &sink_tp, 1);
+ if (lt->repeater)
+ addr = DPCD_LTTPR_PATTERN_SET(lt->repeater);
+ else
+ addr = DPCD_LC02;
+
+ nvkm_rdaux(dp->aux, addr, &sink_tp, 1);
sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET;
- sink_tp |= pattern;
- nvkm_wraux(dp->aux, DPCD_LC02, &sink_tp, 1);
+ sink_tp |= (pattern != 4) ? pattern : 7;
+
+ if (pattern != 0)
+ sink_tp |= DPCD_LC02_SCRAMBLING_DISABLE;
+ else
+ sink_tp &= ~DPCD_LC02_SCRAMBLING_DISABLE;
+ nvkm_wraux(dp->aux, addr, &sink_tp, 1);
}
static int
nvkm_dp_train_eq(struct lt_state *lt)
{
+ struct nvkm_i2c_aux *aux = lt->dp->aux;
bool eq_done = false, cr_done = true;
- int tries = 0, i;
+ int tries = 0, usec = 0, i;
+ u8 data;
- if (lt->dp->dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED)
- nvkm_dp_train_pattern(lt, 3);
- else
- nvkm_dp_train_pattern(lt, 2);
+ if (lt->repeater) {
+ if (!nvkm_rdaux(aux, DPCD_LTTPR_AUX_RD_INTERVAL(lt->repeater), &data, sizeof(data)))
+ usec = (data & DPCD_RC0E_AUX_RD_INTERVAL) * 4000;
+
+ nvkm_dp_train_pattern(lt, 4);
+ } else {
+ if (lt->dp->dpcd[DPCD_RC00_DPCD_REV] >= 0x14 &&
+ lt->dp->dpcd[DPCD_RC03] & DPCD_RC03_TPS4_SUPPORTED)
+ nvkm_dp_train_pattern(lt, 4);
+ else
+ if (lt->dp->dpcd[DPCD_RC00_DPCD_REV] >= 0x12 &&
+ lt->dp->dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED)
+ nvkm_dp_train_pattern(lt, 3);
+ else
+ nvkm_dp_train_pattern(lt, 2);
+
+ usec = (lt->dp->dpcd[DPCD_RC0E] & DPCD_RC0E_AUX_RD_INTERVAL) * 4000;
+ }
do {
if ((tries &&
nvkm_dp_train_drive(lt, lt->pc2)) ||
- nvkm_dp_train_sense(lt, lt->pc2, 400))
+ nvkm_dp_train_sense(lt, lt->pc2, usec ? usec : 400))
break;
eq_done = !!(lt->stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE);
@@ -193,13 +245,16 @@ nvkm_dp_train_cr(struct lt_state *lt)
{
bool cr_done = false, abort = false;
int voltage = lt->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET;
- int tries = 0, i;
+ int tries = 0, usec = 0, i;
nvkm_dp_train_pattern(lt, 1);
+ if (lt->dp->dpcd[DPCD_RC00_DPCD_REV] < 0x14 && !lt->repeater)
+ usec = (lt->dp->dpcd[DPCD_RC0E] & DPCD_RC0E_AUX_RD_INTERVAL) * 4000;
+
do {
if (nvkm_dp_train_drive(lt, false) ||
- nvkm_dp_train_sense(lt, false, 100))
+ nvkm_dp_train_sense(lt, false, usec ? usec : 100))
break;
cr_done = true;
@@ -223,7 +278,7 @@ nvkm_dp_train_cr(struct lt_state *lt)
}
static int
-nvkm_dp_train_links(struct nvkm_dp *dp)
+nvkm_dp_train_links(struct nvkm_dp *dp, int rate)
{
struct nvkm_ior *ior = dp->outp.ior;
struct nvkm_disp *disp = dp->outp.disp;
@@ -233,13 +288,15 @@ nvkm_dp_train_links(struct nvkm_dp *dp)
.dp = dp,
};
u32 lnkcmp;
- u8 sink[2];
+ u8 sink[2], data;
int ret;
OUTP_DBG(&dp->outp, "training %d x %d MB/s",
ior->dp.nr, ior->dp.bw * 27);
/* Intersect misc. capabilities of the OR and sink. */
+ if (disp->engine.subdev.device->chipset < 0x110)
+ dp->dpcd[DPCD_RC03] &= ~DPCD_RC03_TPS4_SUPPORTED;
if (disp->engine.subdev.device->chipset < 0xd0)
dp->dpcd[DPCD_RC02] &= ~DPCD_RC02_TPS3_SUPPORTED;
lt.pc2 = dp->dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED;
@@ -287,8 +344,22 @@ nvkm_dp_train_links(struct nvkm_dp *dp)
ior->func->dp.power(ior, ior->dp.nr);
+ /* Select LTTPR non-transparent mode if we have a valid configuration,
+ * use transparent mode otherwise.
+ */
+ if (dp->lttpr[0] >= 0x14) {
+ data = DPCD_LTTPR_MODE_TRANSPARENT;
+ nvkm_wraux(dp->aux, DPCD_LTTPR_MODE, &data, sizeof(data));
+
+ if (dp->lttprs) {
+ data = DPCD_LTTPR_MODE_NON_TRANSPARENT;
+ nvkm_wraux(dp->aux, DPCD_LTTPR_MODE, &data, sizeof(data));
+ lt.repeaters = dp->lttprs;
+ }
+ }
+
/* Set desired link configuration on the sink. */
- sink[0] = ior->dp.bw;
+ sink[0] = (dp->rate[rate].dpcd < 0) ? ior->dp.bw : 0;
sink[1] = ior->dp.nr;
if (ior->dp.ef)
sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN;
@@ -297,12 +368,33 @@ nvkm_dp_train_links(struct nvkm_dp *dp)
if (ret)
return ret;
+ if (dp->rate[rate].dpcd >= 0) {
+ ret = nvkm_rdaux(dp->aux, DPCD_LC15_LINK_RATE_SET, &sink[0], sizeof(sink[0]));
+ if (ret)
+ return ret;
+
+ sink[0] &= ~DPCD_LC15_LINK_RATE_SET_MASK;
+ sink[0] |= dp->rate[rate].dpcd;
+
+ ret = nvkm_wraux(dp->aux, DPCD_LC15_LINK_RATE_SET, &sink[0], sizeof(sink[0]));
+ if (ret)
+ return ret;
+ }
+
/* Attempt to train the link in this configuration. */
- memset(lt.stat, 0x00, sizeof(lt.stat));
- ret = nvkm_dp_train_cr(&lt);
- if (ret == 0)
- ret = nvkm_dp_train_eq(&lt);
- nvkm_dp_train_pattern(&lt, 0);
+ for (lt.repeater = lt.repeaters; lt.repeater >= 0; lt.repeater--) {
+ if (lt.repeater)
+ OUTP_DBG(&dp->outp, "training LTTPR%d", lt.repeater);
+ else
+ OUTP_DBG(&dp->outp, "training sink");
+
+ memset(lt.stat, 0x00, sizeof(lt.stat));
+ ret = nvkm_dp_train_cr(&lt);
+ if (ret == 0)
+ ret = nvkm_dp_train_eq(&lt);
+ nvkm_dp_train_pattern(&lt, 0);
+ }
+
return ret;
}
@@ -345,63 +437,13 @@ nvkm_dp_train_init(struct nvkm_dp *dp)
}
}
-static const struct dp_rates {
- u32 rate;
- u8 bw;
- u8 nr;
-} nvkm_dp_rates[] = {
- { 2160000, 0x14, 4 },
- { 1080000, 0x0a, 4 },
- { 1080000, 0x14, 2 },
- { 648000, 0x06, 4 },
- { 540000, 0x0a, 2 },
- { 540000, 0x14, 1 },
- { 324000, 0x06, 2 },
- { 270000, 0x0a, 1 },
- { 162000, 0x06, 1 },
- {}
-};
-
static int
nvkm_dp_train(struct nvkm_dp *dp, u32 dataKBps)
{
struct nvkm_ior *ior = dp->outp.ior;
- const u8 sink_nr = dp->dpcd[DPCD_RC02] & DPCD_RC02_MAX_LANE_COUNT;
- const u8 sink_bw = dp->dpcd[DPCD_RC01_MAX_LINK_RATE];
- const u8 outp_nr = dp->outp.info.dpconf.link_nr;
- const u8 outp_bw = dp->outp.info.dpconf.link_bw;
- const struct dp_rates *failsafe = NULL, *cfg;
- int ret = -EINVAL;
+ int ret = -EINVAL, nr, rate;
u8 pwr;
- /* Find the lowest configuration of the OR that can support
- * the required link rate.
- *
- * We will refuse to program the OR to lower rates, even if
- * link training fails at higher rates (or even if the sink
- * can't support the rate at all, though the DD is supposed
- * to prevent such situations from happening).
- *
- * Attempting to do so can cause the entire display to hang,
- * and it's better to have a failed modeset than that.
- */
- for (cfg = nvkm_dp_rates; cfg->rate; cfg++) {
- if (cfg->nr <= outp_nr && cfg->bw <= outp_bw) {
- /* Try to respect sink limits too when selecting
- * lowest link configuration.
- */
- if (!failsafe ||
- (cfg->nr <= sink_nr && cfg->bw <= sink_bw))
- failsafe = cfg;
- }
-
- if (failsafe && cfg[1].rate < dataKBps)
- break;
- }
-
- if (WARN_ON(!failsafe))
- return ret;
-
/* Ensure sink is not in a low-power state. */
if (!nvkm_rdaux(dp->aux, DPCD_SC00, &pwr, 1)) {
if ((pwr & DPCD_SC00_SET_POWER) != DPCD_SC00_SET_POWER_D0) {
@@ -411,25 +453,22 @@ nvkm_dp_train(struct nvkm_dp *dp, u32 dataKBps)
}
}
+ ior->dp.mst = dp->lt.mst;
+ ior->dp.ef = dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP;
+ ior->dp.nr = 0;
+
/* Link training. */
- OUTP_DBG(&dp->outp, "training (min: %d x %d MB/s)",
- failsafe->nr, failsafe->bw * 27);
+ OUTP_DBG(&dp->outp, "training");
nvkm_dp_train_init(dp);
- for (cfg = nvkm_dp_rates; ret < 0 && cfg <= failsafe; cfg++) {
- /* Skip configurations not supported by both OR and sink. */
- if ((cfg->nr > outp_nr || cfg->bw > outp_bw ||
- cfg->nr > sink_nr || cfg->bw > sink_bw)) {
- if (cfg != failsafe)
- continue;
- OUTP_ERR(&dp->outp, "link rate unsupported by sink");
+ for (nr = dp->links; ret < 0 && nr; nr >>= 1) {
+ for (rate = 0; ret < 0 && rate < dp->rates; rate++) {
+ if (dp->rate[rate].rate * nr >= dataKBps || WARN_ON(!ior->dp.nr)) {
+ /* Program selected link configuration. */
+ ior->dp.bw = dp->rate[rate].rate / 27000;
+ ior->dp.nr = nr;
+ ret = nvkm_dp_train_links(dp, rate);
+ }
}
- ior->dp.mst = dp->lt.mst;
- ior->dp.ef = dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP;
- ior->dp.bw = cfg->bw;
- ior->dp.nr = cfg->nr;
-
- /* Program selected link configuration. */
- ret = nvkm_dp_train_links(dp);
}
nvkm_dp_train_fini(dp);
if (ret < 0)
@@ -527,6 +566,47 @@ done:
}
static bool
+nvkm_dp_enable_supported_link_rates(struct nvkm_dp *dp)
+{
+ u8 sink_rates[DPCD_RC10_SUPPORTED_LINK_RATES__SIZE];
+ int i, j, k;
+
+ if (dp->outp.conn->info.type != DCB_CONNECTOR_eDP ||
+ dp->dpcd[DPCD_RC00_DPCD_REV] < 0x13 ||
+ nvkm_rdaux(dp->aux, DPCD_RC10_SUPPORTED_LINK_RATES(0), sink_rates, sizeof(sink_rates)))
+ return false;
+
+ for (i = 0; i < ARRAY_SIZE(sink_rates); i += 2) {
+ const u32 rate = ((sink_rates[i + 1] << 8) | sink_rates[i]) * 200 / 10;
+
+ if (!rate || WARN_ON(dp->rates == ARRAY_SIZE(dp->rate)))
+ break;
+
+ if (rate > dp->outp.info.dpconf.link_bw * 27000) {
+ OUTP_DBG(&dp->outp, "rate %d !outp", rate);
+ continue;
+ }
+
+ for (j = 0; j < dp->rates; j++) {
+ if (rate > dp->rate[j].rate) {
+ for (k = dp->rates; k > j; k--)
+ dp->rate[k] = dp->rate[k - 1];
+ break;
+ }
+ }
+
+ dp->rate[j].dpcd = i / 2;
+ dp->rate[j].rate = rate;
+ dp->rates++;
+ }
+
+ for (i = 0; i < dp->rates; i++)
+ OUTP_DBG(&dp->outp, "link_rate[%d] = %d", dp->rate[i].dpcd, dp->rate[i].rate);
+
+ return dp->rates != 0;
+}
+
+static bool
nvkm_dp_enable(struct nvkm_dp *dp, bool enable)
{
struct nvkm_i2c_aux *aux = dp->aux;
@@ -538,9 +618,60 @@ nvkm_dp_enable(struct nvkm_dp *dp, bool enable)
dp->present = true;
}
- if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, dp->dpcd,
- sizeof(dp->dpcd)))
+ /* Detect any LTTPRs before reading DPCD receiver caps. */
+ if (!nvkm_rdaux(aux, DPCD_LTTPR_REV, dp->lttpr, sizeof(dp->lttpr)) &&
+ dp->lttpr[0] >= 0x14 && dp->lttpr[2]) {
+ switch (dp->lttpr[2]) {
+ case 0x80: dp->lttprs = 1; break;
+ case 0x40: dp->lttprs = 2; break;
+ case 0x20: dp->lttprs = 3; break;
+ case 0x10: dp->lttprs = 4; break;
+ case 0x08: dp->lttprs = 5; break;
+ case 0x04: dp->lttprs = 6; break;
+ case 0x02: dp->lttprs = 7; break;
+ case 0x01: dp->lttprs = 8; break;
+ default:
+ /* Unknown LTTPR count, we'll switch to transparent mode. */
+ WARN_ON(1);
+ dp->lttprs = 0;
+ break;
+ }
+ } else {
+ /* No LTTPR support, or zero LTTPR count - don't touch it at all. */
+ memset(dp->lttpr, 0x00, sizeof(dp->lttpr));
+ }
+
+ if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, dp->dpcd, sizeof(dp->dpcd))) {
+ const u8 rates[] = { 0x1e, 0x14, 0x0a, 0x06, 0 };
+ const u8 *rate;
+ int rate_max;
+
+ dp->rates = 0;
+ dp->links = dp->dpcd[DPCD_RC02] & DPCD_RC02_MAX_LANE_COUNT;
+ dp->links = min(dp->links, dp->outp.info.dpconf.link_nr);
+ if (dp->lttprs && dp->lttpr[4])
+ dp->links = min_t(int, dp->links, dp->lttpr[4]);
+
+ rate_max = dp->dpcd[DPCD_RC01_MAX_LINK_RATE];
+ rate_max = min(rate_max, dp->outp.info.dpconf.link_bw);
+ if (dp->lttprs && dp->lttpr[1])
+ rate_max = min_t(int, rate_max, dp->lttpr[1]);
+
+ if (!nvkm_dp_enable_supported_link_rates(dp)) {
+ for (rate = rates; *rate; rate++) {
+ if (*rate <= rate_max) {
+ if (WARN_ON(dp->rates == ARRAY_SIZE(dp->rate)))
+ break;
+
+ dp->rate[dp->rates].dpcd = -1;
+ dp->rate[dp->rates].rate = *rate * 27000;
+ dp->rates++;
+ }
+ }
+ }
+
return true;
+ }
}
if (dp->present) {
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h
index e484d0c3b0d4..8e59dd469da6 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h
@@ -9,10 +9,7 @@
#include <subdev/bios/dp.h>
struct nvkm_dp {
- union {
- struct nvkm_outp base;
- struct nvkm_outp outp;
- };
+ struct nvkm_outp outp;
struct nvbios_dpout info;
u8 version;
@@ -21,8 +18,17 @@ struct nvkm_dp {
struct nvkm_notify hpd;
bool present;
+ u8 lttpr[6];
+ u8 lttprs;
u8 dpcd[16];
+ struct {
+ int dpcd; /* -1, or index into SUPPORTED_LINK_RATES table */
+ u32 rate;
+ } rate[8];
+ int rates;
+ int links;
+
struct mutex mutex;
struct {
atomic_t done;
@@ -42,8 +48,12 @@ void nvkm_dp_disable(struct nvkm_outp *, struct nvkm_ior *);
#define DPCD_RC02_TPS3_SUPPORTED 0x40
#define DPCD_RC02_MAX_LANE_COUNT 0x1f
#define DPCD_RC03 0x00003
+#define DPCD_RC03_TPS4_SUPPORTED 0x80
#define DPCD_RC03_MAX_DOWNSPREAD 0x01
-#define DPCD_RC0E_AUX_RD_INTERVAL 0x0000e
+#define DPCD_RC0E 0x0000e
+#define DPCD_RC0E_AUX_RD_INTERVAL 0x7f
+#define DPCD_RC10_SUPPORTED_LINK_RATES(i) 0x00010
+#define DPCD_RC10_SUPPORTED_LINK_RATES__SIZE 16
/* DPCD Link Configuration */
#define DPCD_LC00_LINK_BW_SET 0x00100
@@ -51,7 +61,8 @@ void nvkm_dp_disable(struct nvkm_outp *, struct nvkm_ior *);
#define DPCD_LC01_ENHANCED_FRAME_EN 0x80
#define DPCD_LC01_LANE_COUNT_SET 0x1f
#define DPCD_LC02 0x00102
-#define DPCD_LC02_TRAINING_PATTERN_SET 0x03
+#define DPCD_LC02_TRAINING_PATTERN_SET 0x0f
+#define DPCD_LC02_SCRAMBLING_DISABLE 0x20
#define DPCD_LC03(l) ((l) + 0x00103)
#define DPCD_LC03_MAX_PRE_EMPHASIS_REACHED 0x20
#define DPCD_LC03_PRE_EMPHASIS_SET 0x18
@@ -67,6 +78,8 @@ void nvkm_dp_disable(struct nvkm_outp *, struct nvkm_ior *);
#define DPCD_LC10_LANE3_POST_CURSOR2_SET 0x30
#define DPCD_LC10_LANE2_MAX_POST_CURSOR2_REACHED 0x04
#define DPCD_LC10_LANE2_POST_CURSOR2_SET 0x03
+#define DPCD_LC15_LINK_RATE_SET 0x00115
+#define DPCD_LC15_LINK_RATE_SET_MASK 0x07
/* DPCD Link/Sink Status */
#define DPCD_LS02 0x00202
@@ -108,4 +121,14 @@ void nvkm_dp_disable(struct nvkm_outp *, struct nvkm_ior *);
#define DPCD_SC00_SET_POWER 0x03
#define DPCD_SC00_SET_POWER_D0 0x01
#define DPCD_SC00_SET_POWER_D3 0x03
+
+#define DPCD_LTTPR_REV 0xf0000
+#define DPCD_LTTPR_MODE 0xf0003
+#define DPCD_LTTPR_MODE_TRANSPARENT 0x55
+#define DPCD_LTTPR_MODE_NON_TRANSPARENT 0xaa
+#define DPCD_LTTPR_PATTERN_SET(i) ((i - 1) * 0x50 + 0xf0010)
+#define DPCD_LTTPR_LANE0_SET(i) ((i - 1) * 0x50 + 0xf0011)
+#define DPCD_LTTPR_AUX_RD_INTERVAL(i) ((i - 1) * 0x50 + 0xf0020)
+#define DPCD_LTTPR_LANE0_1_STATUS(i) ((i - 1) * 0x50 + 0xf0030)
+#define DPCD_LTTPR_LANE0_1_ADJUST(i) ((i - 1) * 0x50 + 0xf0033)
#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c
index 4d59d02525d9..56b8f4411988 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c
@@ -77,7 +77,18 @@ g94_sor_dp_pattern(struct nvkm_ior *sor, int pattern)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 loff = nv50_sor_link(sor);
- nvkm_mask(device, 0x61c10c + loff, 0x0f000000, pattern << 24);
+ u32 data;
+
+ switch (pattern) {
+ case 0: data = 0x00001000; break;
+ case 1: data = 0x01000000; break;
+ case 2: data = 0x02000000; break;
+ default:
+ WARN_ON(1);
+ return;
+ }
+
+ nvkm_mask(device, 0x61c10c + loff, 0x0f001000, data);
}
void
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorga102.c
index 033827de9116..d2c05f5c4aa0 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorga102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorga102.c
@@ -37,6 +37,10 @@ ga102_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux)
case 0x0a: clksor |= 0x00040000; break;
case 0x14: clksor |= 0x00080000; break;
case 0x1e: clksor |= 0x000c0000; break;
+ case 0x08: clksor |= 0x00100000; break;
+ case 0x09: clksor |= 0x00140000; break;
+ case 0x0c: clksor |= 0x00180000; break;
+ case 0x10: clksor |= 0x001c0000; break;
default:
WARN_ON(1);
return -EINVAL;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c
index 3b3643fb1019..c431e0b9fc11 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c
@@ -92,7 +92,19 @@ gf119_sor_dp_pattern(struct nvkm_ior *sor, int pattern)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 soff = nv50_ior_base(sor);
- nvkm_mask(device, 0x61c110 + soff, 0x0f0f0f0f, 0x01010101 * pattern);
+ u32 data;
+
+ switch (pattern) {
+ case 0: data = 0x10101010; break;
+ case 1: data = 0x01010101; break;
+ case 2: data = 0x02020202; break;
+ case 3: data = 0x03030303; break;
+ default:
+ WARN_ON(1);
+ return;
+ }
+
+ nvkm_mask(device, 0x61c110 + soff, 0x1f1f1f1f, data);
}
int
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c
index 38045c92197f..3696bfd3bfd7 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c
@@ -28,11 +28,23 @@ gm107_sor_dp_pattern(struct nvkm_ior *sor, int pattern)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 soff = nv50_ior_base(sor);
- const u32 data = 0x01010101 * pattern;
+ u32 mask = 0x1f1f1f1f, data;
+
+ switch (pattern) {
+ case 0: data = 0x10101010; break;
+ case 1: data = 0x01010101; break;
+ case 2: data = 0x02020202; break;
+ case 3: data = 0x03030303; break;
+ case 4: data = 0x1b1b1b1b; break;
+ default:
+ WARN_ON(1);
+ return;
+ }
+
if (sor->asy.link & 1)
- nvkm_mask(device, 0x61c110 + soff, 0x0f0f0f0f, data);
+ nvkm_mask(device, 0x61c110 + soff, mask, data);
else
- nvkm_mask(device, 0x61c12c + soff, 0x0f0f0f0f, data);
+ nvkm_mask(device, 0x61c12c + soff, mask, data);
}
static const struct nvkm_ior_func
diff --git a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
index 5fcbde789ddb..1be150ac758f 100644
--- a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
+++ b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
@@ -86,7 +86,7 @@ static const struct panel_init_cmd boe_tv110c9m_init_cmd[] = {
_INIT_DCS_CMD(0x0F, 0x73),
_INIT_DCS_CMD(0x95, 0xE6),
_INIT_DCS_CMD(0x96, 0xF0),
- _INIT_DCS_CMD(0x30, 0x11),
+ _INIT_DCS_CMD(0x30, 0x00),
_INIT_DCS_CMD(0x6D, 0x66),
_INIT_DCS_CMD(0x75, 0xA2),
_INIT_DCS_CMD(0x77, 0x3B),
@@ -112,17 +112,17 @@ static const struct panel_init_cmd boe_tv110c9m_init_cmd[] = {
_INIT_DCS_CMD(0xB1, 0x00, 0xD2, 0x01, 0x0B, 0x01, 0x34, 0x01, 0x76, 0x01, 0xA3, 0x01, 0xEF, 0x02, 0x27, 0x02, 0x29),
_INIT_DCS_CMD(0xB2, 0x02, 0x5F, 0x02, 0x9E, 0x02, 0xC9, 0x03, 0x00, 0x03, 0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73),
- _INIT_DCS_CMD(0xB3, 0x03, 0x86, 0x03, 0x9A, 0x03, 0xA7, 0x03, 0xCF, 0x03, 0xDE, 0x03, 0xE0),
+ _INIT_DCS_CMD(0xB3, 0x03, 0x86, 0x03, 0x9A, 0x03, 0xAF, 0x03, 0xDF, 0x03, 0xF5, 0x03, 0xE0),
_INIT_DCS_CMD(0xB4, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x45, 0x00, 0x65, 0x00, 0x81, 0x00, 0x99, 0x00, 0xAE, 0x00, 0xC1),
_INIT_DCS_CMD(0xB5, 0x00, 0xD2, 0x01, 0x0B, 0x01, 0x34, 0x01, 0x76, 0x01, 0xA3, 0x01, 0xEF, 0x02, 0x27, 0x02, 0x29),
_INIT_DCS_CMD(0xB6, 0x02, 0x5F, 0x02, 0x9E, 0x02, 0xC9, 0x03, 0x00, 0x03, 0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73),
- _INIT_DCS_CMD(0xB7, 0x03, 0x86, 0x03, 0x9A, 0x03, 0xA7, 0x03, 0xCF, 0x03, 0xDE, 0x03, 0xE0),
+ _INIT_DCS_CMD(0xB7, 0x03, 0x86, 0x03, 0x9A, 0x03, 0xAF, 0x03, 0xDF, 0x03, 0xF5, 0x03, 0xE0),
_INIT_DCS_CMD(0xB8, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x45, 0x00, 0x65, 0x00, 0x81, 0x00, 0x99, 0x00, 0xAE, 0x00, 0xC1),
_INIT_DCS_CMD(0xB9, 0x00, 0xD2, 0x01, 0x0B, 0x01, 0x34, 0x01, 0x76, 0x01, 0xA3, 0x01, 0xEF, 0x02, 0x27, 0x02, 0x29),
_INIT_DCS_CMD(0xBA, 0x02, 0x5F, 0x02, 0x9E, 0x02, 0xC9, 0x03, 0x00, 0x03, 0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73),
- _INIT_DCS_CMD(0xBB, 0x03, 0x86, 0x03, 0x9A, 0x03, 0xA7, 0x03, 0xCF, 0x03, 0xDE, 0x03, 0xE0),
+ _INIT_DCS_CMD(0xBB, 0x03, 0x86, 0x03, 0x9A, 0x03, 0xAF, 0x03, 0xDF, 0x03, 0xF5, 0x03, 0xE0),
_INIT_DCS_CMD(0xFF, 0x24),
_INIT_DCS_CMD(0xFB, 0x01),
diff --git a/drivers/gpu/drm/selftests/test-drm_plane_helper.c b/drivers/gpu/drm/selftests/test-drm_plane_helper.c
index 0a9553f51796..ceebeede55ea 100644
--- a/drivers/gpu/drm/selftests/test-drm_plane_helper.c
+++ b/drivers/gpu/drm/selftests/test-drm_plane_helper.c
@@ -87,11 +87,15 @@ int igt_check_plane_state(void *ignored)
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC)
},
};
+ struct drm_plane plane = {
+ .dev = NULL
+ };
struct drm_framebuffer fb = {
.width = 2048,
.height = 2048
};
struct drm_plane_state plane_state = {
+ .plane = &plane,
.crtc = ZERO_SIZE_PTR,
.fb = &fb,
.rotation = DRM_MODE_ROTATE_0
diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c
index 222869b232ae..9f441aadf2d5 100644
--- a/drivers/gpu/drm/stm/drv.c
+++ b/drivers/gpu/drm/stm/drv.c
@@ -14,6 +14,7 @@
#include <linux/of_platform.h>
#include <linux/pm_runtime.h>
+#include <drm/drm_aperture.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
@@ -183,6 +184,10 @@ static int stm_drm_platform_probe(struct platform_device *pdev)
DRM_DEBUG("%s\n", __func__);
+ ret = drm_aperture_remove_framebuffers(false, &drv_driver);
+ if (ret)
+ return ret;
+
dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
ddev = drm_dev_alloc(&drv_driver, dev);
diff --git a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c
index 32cb41b2202f..89897d5f5c72 100644
--- a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c
+++ b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c
@@ -247,14 +247,6 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
int ret, bpp;
u32 val;
- /* Update lane capabilities according to hw version */
- dsi->lane_min_kbps = LANE_MIN_KBPS;
- dsi->lane_max_kbps = LANE_MAX_KBPS;
- if (dsi->hw_version == HWVER_131) {
- dsi->lane_min_kbps *= 2;
- dsi->lane_max_kbps *= 2;
- }
-
pll_in_khz = (unsigned int)(clk_get_rate(dsi->pllref_clk) / 1000);
/* Compute requested pll out */
@@ -330,6 +322,103 @@ dw_mipi_dsi_phy_get_timing(void *priv_data, unsigned int lane_mbps,
return 0;
}
+#define CLK_TOLERANCE_HZ 50
+
+static enum drm_mode_status
+dw_mipi_dsi_stm_mode_valid(void *priv_data,
+ const struct drm_display_mode *mode,
+ unsigned long mode_flags, u32 lanes, u32 format)
+{
+ struct dw_mipi_dsi_stm *dsi = priv_data;
+ unsigned int idf, ndiv, odf, pll_in_khz, pll_out_khz;
+ int ret, bpp;
+
+ bpp = mipi_dsi_pixel_format_to_bpp(format);
+ if (bpp < 0)
+ return MODE_BAD;
+
+ /* Compute requested pll out */
+ pll_out_khz = mode->clock * bpp / lanes;
+
+ if (pll_out_khz > dsi->lane_max_kbps)
+ return MODE_CLOCK_HIGH;
+
+ if (mode_flags & MIPI_DSI_MODE_VIDEO_BURST) {
+ /* Add 20% to pll out to be higher than pixel bw */
+ pll_out_khz = (pll_out_khz * 12) / 10;
+ } else {
+ if (pll_out_khz < dsi->lane_min_kbps)
+ return MODE_CLOCK_LOW;
+ }
+
+ /* Compute best pll parameters */
+ idf = 0;
+ ndiv = 0;
+ odf = 0;
+ pll_in_khz = clk_get_rate(dsi->pllref_clk) / 1000;
+ ret = dsi_pll_get_params(dsi, pll_in_khz, pll_out_khz, &idf, &ndiv, &odf);
+ if (ret) {
+ DRM_WARN("Warning dsi_pll_get_params(): bad params\n");
+ return MODE_ERROR;
+ }
+
+ if (!(mode_flags & MIPI_DSI_MODE_VIDEO_BURST)) {
+ unsigned int px_clock_hz, target_px_clock_hz, lane_mbps;
+ int dsi_short_packet_size_px, hfp, hsync, hbp, delay_to_lp;
+ struct dw_mipi_dsi_dphy_timing dphy_timing;
+
+ /* Get the adjusted pll out value */
+ pll_out_khz = dsi_pll_get_clkout_khz(pll_in_khz, idf, ndiv, odf);
+
+ px_clock_hz = DIV_ROUND_CLOSEST_ULL(1000ULL * pll_out_khz * lanes, bpp);
+ target_px_clock_hz = mode->clock * 1000;
+ /*
+ * Filter modes according to the clock value, particularly useful for
+ * hdmi modes that require precise pixel clocks.
+ */
+ if (px_clock_hz < target_px_clock_hz - CLK_TOLERANCE_HZ ||
+ px_clock_hz > target_px_clock_hz + CLK_TOLERANCE_HZ)
+ return MODE_CLOCK_RANGE;
+
+ /* sync packets are codes as DSI short packets (4 bytes) */
+ dsi_short_packet_size_px = DIV_ROUND_UP(4 * BITS_PER_BYTE, bpp);
+
+ hfp = mode->hsync_start - mode->hdisplay;
+ hsync = mode->hsync_end - mode->hsync_start;
+ hbp = mode->htotal - mode->hsync_end;
+
+ /* hsync must be longer than 4 bytes HSS packets */
+ if (hsync < dsi_short_packet_size_px)
+ return MODE_HSYNC_NARROW;
+
+ if (mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
+ /* HBP must be longer than 4 bytes HSE packets */
+ if (hbp < dsi_short_packet_size_px)
+ return MODE_HSYNC_NARROW;
+ hbp -= dsi_short_packet_size_px;
+ } else {
+ /* With sync events HBP extends in the hsync */
+ hbp += hsync - dsi_short_packet_size_px;
+ }
+
+ lane_mbps = pll_out_khz / 1000;
+ ret = dw_mipi_dsi_phy_get_timing(priv_data, lane_mbps, &dphy_timing);
+ if (ret)
+ return MODE_ERROR;
+ /*
+ * In non-burst mode DSI has to enter in LP during HFP
+ * (horizontal front porch) or HBP (horizontal back porch) to
+ * resync with LTDC pixel clock.
+ */
+ delay_to_lp = DIV_ROUND_UP((dphy_timing.data_hs2lp + dphy_timing.data_lp2hs) *
+ lanes * BITS_PER_BYTE, bpp);
+ if (hfp < delay_to_lp && hbp < delay_to_lp)
+ return MODE_HSYNC;
+ }
+
+ return MODE_OK;
+}
+
static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_stm_phy_ops = {
.init = dw_mipi_dsi_phy_init,
.power_on = dw_mipi_dsi_phy_power_on,
@@ -340,6 +429,7 @@ static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_stm_phy_ops = {
static struct dw_mipi_dsi_plat_data dw_mipi_dsi_stm_plat_data = {
.max_data_lanes = 2,
+ .mode_valid = dw_mipi_dsi_stm_mode_valid,
.phy_ops = &dw_mipi_dsi_stm_phy_ops,
};
@@ -417,6 +507,14 @@ static int dw_mipi_dsi_stm_probe(struct platform_device *pdev)
goto err_dsi_probe;
}
+ /* set lane capabilities according to hw version */
+ dsi->lane_min_kbps = LANE_MIN_KBPS;
+ dsi->lane_max_kbps = LANE_MAX_KBPS;
+ if (dsi->hw_version == HWVER_131) {
+ dsi->lane_min_kbps *= 2;
+ dsi->lane_max_kbps *= 2;
+ }
+
dw_mipi_dsi_stm_plat_data.base = dsi->base;
dw_mipi_dsi_stm_plat_data.priv_data = dsi;
diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c
index dbdee954692a..c0619f372630 100644
--- a/drivers/gpu/drm/stm/ltdc.c
+++ b/drivers/gpu/drm/stm/ltdc.c
@@ -46,15 +46,15 @@
#define HWVER_10200 0x010200
#define HWVER_10300 0x010300
#define HWVER_20101 0x020101
+#define HWVER_40100 0x040100
/*
* The address of some registers depends on the HW version: such registers have
- * an extra offset specified with reg_ofs.
+ * an extra offset specified with layer_ofs.
*/
-#define REG_OFS_NONE 0
-#define REG_OFS_4 4 /* Insertion of "Layer Conf. 2" reg */
-#define REG_OFS (ldev->caps.reg_ofs)
-#define LAY_OFS 0x80 /* Register Offset between 2 layers */
+#define LAY_OFS_0 0x80
+#define LAY_OFS_1 0x100
+#define LAY_OFS (ldev->caps.layer_ofs)
/* Global register offsets */
#define LTDC_IDR 0x0000 /* IDentification */
@@ -75,29 +75,34 @@
#define LTDC_LIPCR 0x0040 /* Line Interrupt Position Conf. */
#define LTDC_CPSR 0x0044 /* Current Position Status */
#define LTDC_CDSR 0x0048 /* Current Display Status */
+#define LTDC_FUT 0x0090 /* Fifo underrun Threshold */
/* Layer register offsets */
-#define LTDC_L1LC1R (0x80) /* L1 Layer Configuration 1 */
-#define LTDC_L1LC2R (0x84) /* L1 Layer Configuration 2 */
-#define LTDC_L1CR (0x84 + REG_OFS)/* L1 Control */
-#define LTDC_L1WHPCR (0x88 + REG_OFS)/* L1 Window Hor Position Config */
-#define LTDC_L1WVPCR (0x8C + REG_OFS)/* L1 Window Vert Position Config */
-#define LTDC_L1CKCR (0x90 + REG_OFS)/* L1 Color Keying Configuration */
-#define LTDC_L1PFCR (0x94 + REG_OFS)/* L1 Pixel Format Configuration */
-#define LTDC_L1CACR (0x98 + REG_OFS)/* L1 Constant Alpha Config */
-#define LTDC_L1DCCR (0x9C + REG_OFS)/* L1 Default Color Configuration */
-#define LTDC_L1BFCR (0xA0 + REG_OFS)/* L1 Blend Factors Configuration */
-#define LTDC_L1FBBCR (0xA4 + REG_OFS)/* L1 FrameBuffer Bus Control */
-#define LTDC_L1AFBCR (0xA8 + REG_OFS)/* L1 AuxFB Control */
-#define LTDC_L1CFBAR (0xAC + REG_OFS)/* L1 Color FrameBuffer Address */
-#define LTDC_L1CFBLR (0xB0 + REG_OFS)/* L1 Color FrameBuffer Length */
-#define LTDC_L1CFBLNR (0xB4 + REG_OFS)/* L1 Color FrameBuffer Line Nb */
-#define LTDC_L1AFBAR (0xB8 + REG_OFS)/* L1 AuxFB Address */
-#define LTDC_L1AFBLR (0xBC + REG_OFS)/* L1 AuxFB Length */
-#define LTDC_L1AFBLNR (0xC0 + REG_OFS)/* L1 AuxFB Line Number */
-#define LTDC_L1CLUTWR (0xC4 + REG_OFS)/* L1 CLUT Write */
-#define LTDC_L1YS1R (0xE0 + REG_OFS)/* L1 YCbCr Scale 1 */
-#define LTDC_L1YS2R (0xE4 + REG_OFS)/* L1 YCbCr Scale 2 */
+#define LTDC_L1C0R (ldev->caps.layer_regs[0]) /* L1 configuration 0 */
+#define LTDC_L1C1R (ldev->caps.layer_regs[1]) /* L1 configuration 1 */
+#define LTDC_L1RCR (ldev->caps.layer_regs[2]) /* L1 reload control */
+#define LTDC_L1CR (ldev->caps.layer_regs[3]) /* L1 control register */
+#define LTDC_L1WHPCR (ldev->caps.layer_regs[4]) /* L1 window horizontal position configuration */
+#define LTDC_L1WVPCR (ldev->caps.layer_regs[5]) /* L1 window vertical position configuration */
+#define LTDC_L1CKCR (ldev->caps.layer_regs[6]) /* L1 color keying configuration */
+#define LTDC_L1PFCR (ldev->caps.layer_regs[7]) /* L1 pixel format configuration */
+#define LTDC_L1CACR (ldev->caps.layer_regs[8]) /* L1 constant alpha configuration */
+#define LTDC_L1DCCR (ldev->caps.layer_regs[9]) /* L1 default color configuration */
+#define LTDC_L1BFCR (ldev->caps.layer_regs[10]) /* L1 blending factors configuration */
+#define LTDC_L1BLCR (ldev->caps.layer_regs[11]) /* L1 burst length configuration */
+#define LTDC_L1PCR (ldev->caps.layer_regs[12]) /* L1 planar configuration */
+#define LTDC_L1CFBAR (ldev->caps.layer_regs[13]) /* L1 color frame buffer address */
+#define LTDC_L1CFBLR (ldev->caps.layer_regs[14]) /* L1 color frame buffer length */
+#define LTDC_L1CFBLNR (ldev->caps.layer_regs[15]) /* L1 color frame buffer line number */
+#define LTDC_L1AFBA0R (ldev->caps.layer_regs[16]) /* L1 auxiliary frame buffer address 0 */
+#define LTDC_L1AFBA1R (ldev->caps.layer_regs[17]) /* L1 auxiliary frame buffer address 1 */
+#define LTDC_L1AFBLR (ldev->caps.layer_regs[18]) /* L1 auxiliary frame buffer length */
+#define LTDC_L1AFBLNR (ldev->caps.layer_regs[19]) /* L1 auxiliary frame buffer line number */
+#define LTDC_L1CLUTWR (ldev->caps.layer_regs[20]) /* L1 CLUT write */
+#define LTDC_L1CYR0R (ldev->caps.layer_regs[21]) /* L1 Conversion YCbCr RGB 0 */
+#define LTDC_L1CYR1R (ldev->caps.layer_regs[22]) /* L1 Conversion YCbCr RGB 1 */
+#define LTDC_L1FPF0R (ldev->caps.layer_regs[23]) /* L1 Flexible Pixel Format 0 */
+#define LTDC_L1FPF1R (ldev->caps.layer_regs[24]) /* L1 Flexible Pixel Format 1 */
/* Bit definitions */
#define SSCR_VSH GENMASK(10, 0) /* Vertical Synchronization Height */
@@ -208,7 +213,10 @@ enum ltdc_pix_fmt {
/* Indexed formats */
PF_L8, /* Indexed 8 bits [8 bits] */
PF_AL44, /* Alpha:4 bits + indexed 4 bits [8 bits] */
- PF_AL88 /* Alpha:8 bits + indexed 8 bits [16 bits] */
+ PF_AL88, /* Alpha:8 bits + indexed 8 bits [16 bits] */
+ PF_ABGR8888, /* ABGR [32 bits] */
+ PF_BGRA8888, /* BGRA [32 bits] */
+ PF_BGR565 /* RGB [16 bits] */
};
/* The index gives the encoding of the pixel format for an HW version */
@@ -234,6 +242,102 @@ static const enum ltdc_pix_fmt ltdc_pix_fmt_a1[NB_PF] = {
PF_ARGB4444 /* 0x07 */
};
+static const enum ltdc_pix_fmt ltdc_pix_fmt_a2[NB_PF] = {
+ PF_ARGB8888, /* 0x00 */
+ PF_ABGR8888, /* 0x01 */
+ PF_RGBA8888, /* 0x02 */
+ PF_BGRA8888, /* 0x03 */
+ PF_RGB565, /* 0x04 */
+ PF_BGR565, /* 0x05 */
+ PF_RGB888, /* 0x06 */
+ PF_ARGB1555 /* 0x07 */
+};
+
+/* Layer register offsets */
+static const u32 ltdc_layer_regs_a0[] = {
+ 0x80, /* L1 configuration 0 */
+ 0x00, /* not available */
+ 0x00, /* not available */
+ 0x84, /* L1 control register */
+ 0x88, /* L1 window horizontal position configuration */
+ 0x8c, /* L1 window vertical position configuration */
+ 0x90, /* L1 color keying configuration */
+ 0x94, /* L1 pixel format configuration */
+ 0x98, /* L1 constant alpha configuration */
+ 0x9c, /* L1 default color configuration */
+ 0xa0, /* L1 blending factors configuration */
+ 0x00, /* not available */
+ 0x00, /* not available */
+ 0xac, /* L1 color frame buffer address */
+ 0xb0, /* L1 color frame buffer length */
+ 0xb4, /* L1 color frame buffer line number */
+ 0x00, /* not available */
+ 0x00, /* not available */
+ 0x00, /* not available */
+ 0x00, /* not available */
+ 0xc4, /* L1 CLUT write */
+ 0x00, /* not available */
+ 0x00, /* not available */
+ 0x00, /* not available */
+ 0x00 /* not available */
+};
+
+static const u32 ltdc_layer_regs_a1[] = {
+ 0x80, /* L1 configuration 0 */
+ 0x84, /* L1 configuration 1 */
+ 0x00, /* L1 reload control */
+ 0x88, /* L1 control register */
+ 0x8c, /* L1 window horizontal position configuration */
+ 0x90, /* L1 window vertical position configuration */
+ 0x94, /* L1 color keying configuration */
+ 0x98, /* L1 pixel format configuration */
+ 0x9c, /* L1 constant alpha configuration */
+ 0xa0, /* L1 default color configuration */
+ 0xa4, /* L1 blending factors configuration */
+ 0xa8, /* L1 burst length configuration */
+ 0x00, /* not available */
+ 0xac, /* L1 color frame buffer address */
+ 0xb0, /* L1 color frame buffer length */
+ 0xb4, /* L1 color frame buffer line number */
+ 0xb8, /* L1 auxiliary frame buffer address 0 */
+ 0xbc, /* L1 auxiliary frame buffer address 1 */
+ 0xc0, /* L1 auxiliary frame buffer length */
+ 0xc4, /* L1 auxiliary frame buffer line number */
+ 0xc8, /* L1 CLUT write */
+ 0x00, /* not available */
+ 0x00, /* not available */
+ 0x00, /* not available */
+ 0x00 /* not available */
+};
+
+static const u32 ltdc_layer_regs_a2[] = {
+ 0x100, /* L1 configuration 0 */
+ 0x104, /* L1 configuration 1 */
+ 0x108, /* L1 reload control */
+ 0x10c, /* L1 control register */
+ 0x110, /* L1 window horizontal position configuration */
+ 0x114, /* L1 window vertical position configuration */
+ 0x118, /* L1 color keying configuration */
+ 0x11c, /* L1 pixel format configuration */
+ 0x120, /* L1 constant alpha configuration */
+ 0x124, /* L1 default color configuration */
+ 0x128, /* L1 blending factors configuration */
+ 0x12c, /* L1 burst length configuration */
+ 0x130, /* L1 planar configuration */
+ 0x134, /* L1 color frame buffer address */
+ 0x138, /* L1 color frame buffer length */
+ 0x13c, /* L1 color frame buffer line number */
+ 0x140, /* L1 auxiliary frame buffer address 0 */
+ 0x144, /* L1 auxiliary frame buffer address 1 */
+ 0x148, /* L1 auxiliary frame buffer length */
+ 0x14c, /* L1 auxiliary frame buffer line number */
+ 0x150, /* L1 CLUT write */
+ 0x16c, /* L1 Conversion YCbCr RGB 0 */
+ 0x170, /* L1 Conversion YCbCr RGB 1 */
+ 0x174, /* L1 Flexible Pixel Format 0 */
+ 0x178 /* L1 Flexible Pixel Format 1 */
+};
+
static const u64 ltdc_format_modifiers[] = {
DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_MOD_INVALID
@@ -1158,7 +1262,8 @@ static int ltdc_get_caps(struct drm_device *ddev)
switch (ldev->caps.hw_version) {
case HWVER_10200:
case HWVER_10300:
- ldev->caps.reg_ofs = REG_OFS_NONE;
+ ldev->caps.layer_ofs = LAY_OFS_0;
+ ldev->caps.layer_regs = ltdc_layer_regs_a0;
ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a0;
/*
* Hw older versions support non-alpha color formats derived
@@ -1174,12 +1279,21 @@ static int ltdc_get_caps(struct drm_device *ddev)
ldev->caps.nb_irq = 2;
break;
case HWVER_20101:
- ldev->caps.reg_ofs = REG_OFS_4;
+ ldev->caps.layer_ofs = LAY_OFS_0;
+ ldev->caps.layer_regs = ltdc_layer_regs_a1;
ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a1;
ldev->caps.non_alpha_only_l1 = false;
ldev->caps.pad_max_freq_hz = 150000000;
ldev->caps.nb_irq = 4;
break;
+ case HWVER_40100:
+ ldev->caps.layer_ofs = LAY_OFS_1;
+ ldev->caps.layer_regs = ltdc_layer_regs_a2;
+ ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a2;
+ ldev->caps.non_alpha_only_l1 = false;
+ ldev->caps.pad_max_freq_hz = 90000000;
+ ldev->caps.nb_irq = 2;
+ break;
default:
return -ENODEV;
}
diff --git a/drivers/gpu/drm/stm/ltdc.h b/drivers/gpu/drm/stm/ltdc.h
index f153b908c70e..55a125f89af6 100644
--- a/drivers/gpu/drm/stm/ltdc.h
+++ b/drivers/gpu/drm/stm/ltdc.h
@@ -14,7 +14,8 @@
struct ltdc_caps {
u32 hw_version; /* hardware version */
u32 nb_layers; /* number of supported layers */
- u32 reg_ofs; /* register offset for applicable regs */
+ u32 layer_ofs; /* layer offset for applicable regs */
+ const u32 *layer_regs; /* layer register offset */
u32 bus_width; /* bus width (32 or 64 bits) */
const u32 *pix_fmt_hw; /* supported pixel formats */
bool non_alpha_only_l1; /* non-native no-alpha formats on layer 1 */
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index 3ddb7c710a3d..cc567c87057d 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -60,8 +60,6 @@ void tilcdc_module_cleanup(struct tilcdc_module *mod)
list_del(&mod->list);
}
-static struct of_device_id tilcdc_of_match[];
-
static int tilcdc_atomic_check(struct drm_device *dev,
struct drm_atomic_state *state)
{
@@ -587,7 +585,7 @@ static int tilcdc_pdev_remove(struct platform_device *pdev)
return 0;
}
-static struct of_device_id tilcdc_of_match[] = {
+static const struct of_device_id tilcdc_of_match[] = {
{ .compatible = "ti,am33xx-tilcdc", },
{ .compatible = "ti,da850-tilcdc", },
{ },
diff --git a/include/drm/bridge/dw_mipi_dsi.h b/include/drm/bridge/dw_mipi_dsi.h
index bda8aa7c2280..5286a53a1875 100644
--- a/include/drm/bridge/dw_mipi_dsi.h
+++ b/include/drm/bridge/dw_mipi_dsi.h
@@ -51,7 +51,9 @@ struct dw_mipi_dsi_plat_data {
unsigned int max_data_lanes;
enum drm_mode_status (*mode_valid)(void *priv_data,
- const struct drm_display_mode *mode);
+ const struct drm_display_mode *mode,
+ unsigned long mode_flags,
+ u32 lanes, u32 format);
const struct dw_mipi_dsi_phy_ops *phy_ops;
const struct dw_mipi_dsi_host_ops *host_ops;
diff --git a/include/drm/drm_mipi_dbi.h b/include/drm/drm_mipi_dbi.h
index 05e194958265..6fe13cce2670 100644
--- a/include/drm/drm_mipi_dbi.h
+++ b/include/drm/drm_mipi_dbi.h
@@ -194,7 +194,7 @@ int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb,
#ifdef CONFIG_DEBUG_FS
void mipi_dbi_debugfs_init(struct drm_minor *minor);
#else
-#define mipi_dbi_debugfs_init NULL
+static inline void mipi_dbi_debugfs_init(struct drm_minor *minor) {}
#endif
#endif /* __LINUX_MIPI_DBI_H */
diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h
index 0c1102dc4d88..06759badf99f 100644
--- a/include/drm/drm_plane.h
+++ b/include/drm/drm_plane.h
@@ -516,7 +516,7 @@ struct drm_plane_funcs {
* This optional hook is used for the DRM to determine if the given
* format/modifier combination is valid for the plane. This allows the
* DRM to generate the correct format bitmask (which formats apply to
- * which modifier), and to valdiate modifiers at atomic_check time.
+ * which modifier), and to validate modifiers at atomic_check time.
*
* If not present, then any modifier in the plane's modifier
* list is allowed with any of the plane's formats.