From b18398c16e176513502f962b642f89225039ef1f Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 7 Jan 2020 12:30:31 +0100 Subject: [PATCH 01/38] drm/bridge: Fix a NULL pointer dereference in drm_atomic_bridge_chain_check() drm_atomic_bridge_chain_check() callers can pass a NULL bridge. Let's bail out before dereferencing the bridge pointer when that happens. Reported-by: Chris Wilson Fixes: b86d895524ab ("drm/bridge: Add an ->atomic_check() hook") Signed-off-by: Boris Brezillon Reviewed-by: Laurent Pinchart Reviewed-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20200107113031.435604-1-boris.brezillon@collabora.com --- drivers/gpu/drm/drm_bridge.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 37400607e9b7..32d43bfeeca1 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -938,15 +938,19 @@ int drm_atomic_bridge_chain_check(struct drm_bridge *bridge, struct drm_connector_state *conn_state) { struct drm_connector *conn = conn_state->connector; - struct drm_encoder *encoder = bridge->encoder; + struct drm_encoder *encoder; struct drm_bridge *iter; int ret; + if (!bridge) + return 0; + ret = drm_atomic_bridge_chain_select_bus_fmts(bridge, crtc_state, conn_state); if (ret) return ret; + encoder = bridge->encoder; list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { int ret; From bb9d681b2508bb46e83307e61e299254eaea1233 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 2 Jan 2020 14:22:57 +0100 Subject: [PATCH 02/38] drm/tegra: Provide ddc symlink in output connector sysfs directory Use the ddc pointer provided by the generic connector. Signed-off-by: Andrzej Pietrasiewicz Acked-by: Sam Ravnborg Reviewed-by: Emil Velikov Link: https://patchwork.freedesktop.org/patch/msgid/20200102132300.24309-2-andrzej.p@collabora.com --- drivers/gpu/drm/tegra/hdmi.c | 7 ++++--- drivers/gpu/drm/tegra/sor.c | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index 50269ffbcb6b..21a629adcb51 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -1430,9 +1430,10 @@ static int tegra_hdmi_init(struct host1x_client *client) hdmi->output.dev = client->dev; - drm_connector_init(drm, &hdmi->output.connector, - &tegra_hdmi_connector_funcs, - DRM_MODE_CONNECTOR_HDMIA); + drm_connector_init_with_ddc(drm, &hdmi->output.connector, + &tegra_hdmi_connector_funcs, + DRM_MODE_CONNECTOR_HDMIA, + hdmi->output.ddc); drm_connector_helper_add(&hdmi->output.connector, &tegra_hdmi_connector_helper_funcs); hdmi->output.connector.dpms = DRM_MODE_DPMS_OFF; diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index a68d3b36b972..1b8087d2dafe 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -3086,9 +3086,10 @@ static int tegra_sor_init(struct host1x_client *client) sor->output.dev = sor->dev; - drm_connector_init(drm, &sor->output.connector, - &tegra_sor_connector_funcs, - connector); + drm_connector_init_with_ddc(drm, &sor->output.connector, + &tegra_sor_connector_funcs, + connector, + sor->output.ddc); drm_connector_helper_add(&sor->output.connector, &tegra_sor_connector_helper_funcs); sor->output.connector.dpms = DRM_MODE_DPMS_OFF; From 04a880fb06b90708b692c11a4fd2b3761514b811 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 2 Jan 2020 14:22:58 +0100 Subject: [PATCH 03/38] drm/vc4: Provide ddc symlink in connector sysfs directory Use the ddc pointer provided by the generic connector. Signed-off-by: Andrzej Pietrasiewicz Acked-by: Sam Ravnborg Reviewed-by: Emil Velikov Link: https://patchwork.freedesktop.org/patch/msgid/20200102132300.24309-3-andrzej.p@collabora.com --- drivers/gpu/drm/vc4/vc4_hdmi.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 1c62c6c9244b..cea18dc15f77 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -267,7 +267,8 @@ static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs = }; static struct drm_connector *vc4_hdmi_connector_init(struct drm_device *dev, - struct drm_encoder *encoder) + struct drm_encoder *encoder, + struct i2c_adapter *ddc) { struct drm_connector *connector; struct vc4_hdmi_connector *hdmi_connector; @@ -281,8 +282,10 @@ static struct drm_connector *vc4_hdmi_connector_init(struct drm_device *dev, hdmi_connector->encoder = encoder; - drm_connector_init(dev, connector, &vc4_hdmi_connector_funcs, - DRM_MODE_CONNECTOR_HDMIA); + drm_connector_init_with_ddc(dev, connector, + &vc4_hdmi_connector_funcs, + DRM_MODE_CONNECTOR_HDMIA, + ddc); drm_connector_helper_add(connector, &vc4_hdmi_connector_helper_funcs); /* Create and attach TV margin props to this connector. */ @@ -1395,7 +1398,8 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) DRM_MODE_ENCODER_TMDS, NULL); drm_encoder_helper_add(hdmi->encoder, &vc4_hdmi_encoder_helper_funcs); - hdmi->connector = vc4_hdmi_connector_init(drm, hdmi->encoder); + hdmi->connector = + vc4_hdmi_connector_init(drm, hdmi->encoder, hdmi->ddc); if (IS_ERR(hdmi->connector)) { ret = PTR_ERR(hdmi->connector); goto err_destroy_encoder; From a339fa5de0f3d328c3bbc489b8999f98cc3b318e Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 2 Jan 2020 14:22:59 +0100 Subject: [PATCH 04/38] drm: zte: Provide ddc symlink in hdmi connector sysfs directory Use the ddc pointer provided by the generic connector. Signed-off-by: Andrzej Pietrasiewicz Acked-by: Sam Ravnborg Reviewed-by: Emil Velikov Link: https://patchwork.freedesktop.org/patch/msgid/20200102132300.24309-4-andrzej.p@collabora.com --- drivers/gpu/drm/zte/zx_hdmi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/zte/zx_hdmi.c b/drivers/gpu/drm/zte/zx_hdmi.c index a50f5a1f09b8..b98a1420dcd3 100644 --- a/drivers/gpu/drm/zte/zx_hdmi.c +++ b/drivers/gpu/drm/zte/zx_hdmi.c @@ -319,8 +319,10 @@ static int zx_hdmi_register(struct drm_device *drm, struct zx_hdmi *hdmi) hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD; - drm_connector_init(drm, &hdmi->connector, &zx_hdmi_connector_funcs, - DRM_MODE_CONNECTOR_HDMIA); + drm_connector_init_with_ddc(drm, &hdmi->connector, + &zx_hdmi_connector_funcs, + DRM_MODE_CONNECTOR_HDMIA, + &hdmi->ddc->adap); drm_connector_helper_add(&hdmi->connector, &zx_hdmi_connector_helper_funcs); From c35a024f8eecc34c37ba73fa095e39dabfe5ee75 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 2 Jan 2020 14:23:00 +0100 Subject: [PATCH 05/38] drm: zte: Provide ddc symlink in vga connector sysfs directory Use the ddc pointer provided by the generic connector. Signed-off-by: Andrzej Pietrasiewicz Acked-by: Sam Ravnborg Reviewed-by: Emil Velikov Link: https://patchwork.freedesktop.org/patch/msgid/20200102132300.24309-5-andrzej.p@collabora.com --- drivers/gpu/drm/zte/zx_vga.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/zte/zx_vga.c b/drivers/gpu/drm/zte/zx_vga.c index 9b67e419280c..c4fa3bbaba78 100644 --- a/drivers/gpu/drm/zte/zx_vga.c +++ b/drivers/gpu/drm/zte/zx_vga.c @@ -165,8 +165,10 @@ static int zx_vga_register(struct drm_device *drm, struct zx_vga *vga) vga->connector.polled = DRM_CONNECTOR_POLL_HPD; - ret = drm_connector_init(drm, connector, &zx_vga_connector_funcs, - DRM_MODE_CONNECTOR_VGA); + ret = drm_connector_init_with_ddc(drm, connector, + &zx_vga_connector_funcs, + DRM_MODE_CONNECTOR_VGA, + &vga->ddc->adap); if (ret) { DRM_DEV_ERROR(dev, "failed to init connector: %d\n", ret); goto clean_encoder; From 72a848f5c46bab4c921edc9cbffd1ab273b2be17 Mon Sep 17 00:00:00 2001 From: Dingchen Zhang Date: Mon, 10 Jun 2019 09:47:51 -0400 Subject: [PATCH 06/38] drm: remove the newline for CRC source name. userspace may transfer a newline, and this terminating newline is replaced by a '\0' to avoid followup issues. 'len-1' is the index to replace the newline of CRC source name. v3: typo fix (Sam) v2: update patch subject, body and format. (Sam) Cc: Leo Li Cc: Harry Wentland Cc: Sam Ravnborg Signed-off-by: Dingchen Zhang Reviewed-by: Sam Ravnborg Signed-off-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20190610134751.14356-1-dingchen.zhang@amd.com --- drivers/gpu/drm/drm_debugfs_crc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_debugfs_crc.c b/drivers/gpu/drm/drm_debugfs_crc.c index ca3c55c6b815..2ece2957da1a 100644 --- a/drivers/gpu/drm/drm_debugfs_crc.c +++ b/drivers/gpu/drm/drm_debugfs_crc.c @@ -140,8 +140,8 @@ static ssize_t crc_control_write(struct file *file, const char __user *ubuf, if (IS_ERR(source)) return PTR_ERR(source); - if (source[len] == '\n') - source[len] = '\0'; + if (source[len - 1] == '\n') + source[len - 1] = '\0'; ret = crtc->funcs->verify_crc_source(crtc, source, &values_cnt); if (ret) From 292f3e496be0cac933dfa86e9d0bea5d96224c14 Mon Sep 17 00:00:00 2001 From: Dingchen Zhang Date: Fri, 26 Jul 2019 13:37:43 -0400 Subject: [PATCH 07/38] drm: Set crc->opened to false before setting crc source to NULL. to terminate the while-loop in drm_dp_aux_crc_work when drm_dp_start/stop_crc are called in the hook to set crc source. v3: set crc->opened to false without checking (Nick) v2: Move spin_lock around entire crc->opened use (Daniel) Cc: Daniel Vetter Cc: Harry Wentland Cc: Nick Kazlauskas Signed-off-by: Dingchen Zhang Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20190726173743.11641-1-dingchen.zhang@amd.com --- drivers/gpu/drm/drm_debugfs_crc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/drm_debugfs_crc.c b/drivers/gpu/drm/drm_debugfs_crc.c index 2ece2957da1a..e22b812c4b80 100644 --- a/drivers/gpu/drm/drm_debugfs_crc.c +++ b/drivers/gpu/drm/drm_debugfs_crc.c @@ -258,6 +258,11 @@ static int crtc_crc_release(struct inode *inode, struct file *filep) struct drm_crtc *crtc = filep->f_inode->i_private; struct drm_crtc_crc *crc = &crtc->crc; + /* terminate the infinite while loop if 'drm_dp_aux_crc_work' running */ + spin_lock_irq(&crc->lock); + crc->opened = false; + spin_unlock_irq(&crc->lock); + crtc->funcs->set_crc_source(crtc, NULL); spin_lock_irq(&crc->lock); From 6ae1a4bbe1138e883c34ea78ef29986d9f420bd7 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 7 Jan 2020 19:58:03 +0100 Subject: [PATCH 08/38] Revert "drm/bridge: Fix a NULL pointer dereference in drm_atomic_bridge_chain_check()" This reverts commit b18398c16e17 ("drm/bridge: Fix a NULL pointer dereference in drm_atomic_bridge_chain_check()"). Commit 6ed7e9625fa6 ("drm/bridge: Add a drm_bridge_state object") introduced a circular dependency between drm.ko and drm_kms_helper.ko which uncovered a misdesign in how the whole thing was implemented. Let's revert all patches depending on the bridge_state infrastructure for now. Signed-off-by: Boris Brezillon Acked-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20200107185807.606999-2-boris.brezillon@collabora.com --- drivers/gpu/drm/drm_bridge.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 32d43bfeeca1..37400607e9b7 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -938,19 +938,15 @@ int drm_atomic_bridge_chain_check(struct drm_bridge *bridge, struct drm_connector_state *conn_state) { struct drm_connector *conn = conn_state->connector; - struct drm_encoder *encoder; + struct drm_encoder *encoder = bridge->encoder; struct drm_bridge *iter; int ret; - if (!bridge) - return 0; - ret = drm_atomic_bridge_chain_select_bus_fmts(bridge, crtc_state, conn_state); if (ret) return ret; - encoder = bridge->encoder; list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { int ret; From 3dfbf2d3d05eccb0d4ffb4f30467519e601a5db6 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 7 Jan 2020 19:58:04 +0100 Subject: [PATCH 09/38] Revert "drm/bridge: Add the necessary bits to support bus format negotiation" This reverts commit e351e4d5eaec ("drm/bridge: Add the necessary bits to support bus format negotiation"). Commit 6ed7e9625fa6 ("drm/bridge: Add a drm_bridge_state object") introduced a circular dependency between drm.ko and drm_kms_helper.ko which uncovered a misdesign in how the whole thing was implemented. Let's revert all patches depending on the bridge_state infrastructure for now. Signed-off-by: Boris Brezillon Acked-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20200107185807.606999-3-boris.brezillon@collabora.com --- drivers/gpu/drm/drm_bridge.c | 267 +---------------------------------- include/drm/drm_bridge.h | 124 ---------------- 2 files changed, 1 insertion(+), 390 deletions(-) diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 37400607e9b7..8e4b799150b0 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -671,261 +671,13 @@ static int drm_atomic_bridge_check(struct drm_bridge *bridge, return 0; } -/** - * drm_atomic_helper_bridge_propagate_bus_fmt() - Propagate output format to - * the input end of a bridge - * @bridge: bridge control structure - * @bridge_state: new bridge state - * @crtc_state: new CRTC state - * @conn_state: new connector state - * @output_fmt: tested output bus format - * @num_input_fmts: will contain the size of the returned array - * - * This helper is a pluggable implementation of the - * &drm_bridge_funcs.atomic_get_input_bus_fmts operation for bridges that don't - * modify the bus configuration between their input and their output. It - * returns an array of input formats with a single element set to @output_fmt. - * - * RETURNS: - * a valid format array of size @num_input_fmts, or NULL if the allocation - * failed - */ -u32 * -drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge, - struct drm_bridge_state *bridge_state, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state, - u32 output_fmt, - unsigned int *num_input_fmts) -{ - u32 *input_fmts; - - input_fmts = kzalloc(sizeof(*input_fmts), GFP_KERNEL); - if (!input_fmts) { - *num_input_fmts = 0; - return NULL; - } - - *num_input_fmts = 1; - input_fmts[0] = output_fmt; - return input_fmts; -} -EXPORT_SYMBOL(drm_atomic_helper_bridge_propagate_bus_fmt); - -static int select_bus_fmt_recursive(struct drm_bridge *first_bridge, - struct drm_bridge *cur_bridge, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state, - u32 out_bus_fmt) -{ - struct drm_bridge_state *cur_state; - unsigned int num_in_bus_fmts, i; - struct drm_bridge *prev_bridge; - u32 *in_bus_fmts; - int ret; - - prev_bridge = drm_bridge_get_prev_bridge(cur_bridge); - cur_state = drm_atomic_get_new_bridge_state(crtc_state->state, - cur_bridge); - if (WARN_ON(!cur_state)) - return -EINVAL; - - /* - * If bus format negotiation is not supported by this bridge, let's - * pass MEDIA_BUS_FMT_FIXED to the previous bridge in the chain and - * hope that it can handle this situation gracefully (by providing - * appropriate default values). - */ - if (!cur_bridge->funcs->atomic_get_input_bus_fmts) { - if (cur_bridge != first_bridge) { - ret = select_bus_fmt_recursive(first_bridge, - prev_bridge, crtc_state, - conn_state, - MEDIA_BUS_FMT_FIXED); - if (ret) - return ret; - } - - cur_state->input_bus_cfg.format = MEDIA_BUS_FMT_FIXED; - cur_state->output_bus_cfg.format = out_bus_fmt; - return 0; - } - - in_bus_fmts = cur_bridge->funcs->atomic_get_input_bus_fmts(cur_bridge, - cur_state, - crtc_state, - conn_state, - out_bus_fmt, - &num_in_bus_fmts); - if (!num_in_bus_fmts) - return -ENOTSUPP; - else if (!in_bus_fmts) - return -ENOMEM; - - if (first_bridge == cur_bridge) { - cur_state->input_bus_cfg.format = in_bus_fmts[0]; - cur_state->output_bus_cfg.format = out_bus_fmt; - kfree(in_bus_fmts); - return 0; - } - - for (i = 0; i < num_in_bus_fmts; i++) { - ret = select_bus_fmt_recursive(first_bridge, prev_bridge, - crtc_state, conn_state, - in_bus_fmts[i]); - if (ret != -ENOTSUPP) - break; - } - - if (!ret) { - cur_state->input_bus_cfg.format = in_bus_fmts[i]; - cur_state->output_bus_cfg.format = out_bus_fmt; - } - - kfree(in_bus_fmts); - return ret; -} - -/* - * This function is called by &drm_atomic_bridge_chain_check() just before - * calling &drm_bridge_funcs.atomic_check() on all elements of the chain. - * It performs bus format negotiation between bridge elements. The negotiation - * happens in reverse order, starting from the last element in the chain up to - * @bridge. - * - * Negotiation starts by retrieving supported output bus formats on the last - * bridge element and testing them one by one. The test is recursive, meaning - * that for each tested output format, the whole chain will be walked backward, - * and each element will have to choose an input bus format that can be - * transcoded to the requested output format. When a bridge element does not - * support transcoding into a specific output format -ENOTSUPP is returned and - * the next bridge element will have to try a different format. If none of the - * combinations worked, -ENOTSUPP is returned and the atomic modeset will fail. - * - * This implementation is relying on - * &drm_bridge_funcs.atomic_get_output_bus_fmts() and - * &drm_bridge_funcs.atomic_get_input_bus_fmts() to gather supported - * input/output formats. - * - * When &drm_bridge_funcs.atomic_get_output_bus_fmts() is not implemented by - * the last element of the chain, &drm_atomic_bridge_chain_select_bus_fmts() - * tries a single format: &drm_connector.display_info.bus_formats[0] if - * available, MEDIA_BUS_FMT_FIXED otherwise. - * - * When &drm_bridge_funcs.atomic_get_input_bus_fmts() is not implemented, - * &drm_atomic_bridge_chain_select_bus_fmts() skips the negotiation on the - * bridge element that lacks this hook and asks the previous element in the - * chain to try MEDIA_BUS_FMT_FIXED. It's up to bridge drivers to decide what - * to do in that case (fail if they want to enforce bus format negotiation, or - * provide a reasonable default if they need to support pipelines where not - * all elements support bus format negotiation). - */ -static int -drm_atomic_bridge_chain_select_bus_fmts(struct drm_bridge *bridge, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) -{ - struct drm_connector *conn = conn_state->connector; - struct drm_encoder *encoder = bridge->encoder; - struct drm_bridge_state *last_bridge_state; - unsigned int i, num_out_bus_fmts; - struct drm_bridge *last_bridge; - u32 *out_bus_fmts; - int ret = 0; - - last_bridge = list_last_entry(&encoder->bridge_chain, - struct drm_bridge, chain_node); - last_bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state, - last_bridge); - if (WARN_ON(!last_bridge_state)) - return -EINVAL; - - if (last_bridge->funcs->atomic_get_output_bus_fmts) { - const struct drm_bridge_funcs *funcs = last_bridge->funcs; - - out_bus_fmts = funcs->atomic_get_output_bus_fmts(last_bridge, - last_bridge_state, - crtc_state, - conn_state, - &num_out_bus_fmts); - if (!num_out_bus_fmts) - return -ENOTSUPP; - else if (!out_bus_fmts) - return -ENOMEM; - } else { - num_out_bus_fmts = 1; - out_bus_fmts = kmalloc(sizeof(*out_bus_fmts), GFP_KERNEL); - if (!out_bus_fmts) - return -ENOMEM; - - if (conn->display_info.num_bus_formats && - conn->display_info.bus_formats) - out_bus_fmts[0] = conn->display_info.bus_formats[0]; - else - out_bus_fmts[0] = MEDIA_BUS_FMT_FIXED; - } - - for (i = 0; i < num_out_bus_fmts; i++) { - ret = select_bus_fmt_recursive(bridge, last_bridge, crtc_state, - conn_state, out_bus_fmts[i]); - if (ret != -ENOTSUPP) - break; - } - - kfree(out_bus_fmts); - - return ret; -} - -static void -drm_atomic_bridge_propagate_bus_flags(struct drm_bridge *bridge, - struct drm_connector *conn, - struct drm_atomic_state *state) -{ - struct drm_bridge_state *bridge_state, *next_bridge_state; - struct drm_bridge *next_bridge; - u32 output_flags; - - bridge_state = drm_atomic_get_new_bridge_state(state, bridge); - next_bridge = drm_bridge_get_next_bridge(bridge); - - /* - * Let's try to apply the most common case here, that is, propagate - * display_info flags for the last bridge, and propagate the input - * flags of the next bridge element to the output end of the current - * bridge when the bridge is not the last one. - * There are exceptions to this rule, like when signal inversion is - * happening at the board level, but that's something drivers can deal - * with from their &drm_bridge_funcs.atomic_check() implementation by - * simply overriding the flags value we've set here. - */ - if (!next_bridge) { - output_flags = conn->display_info.bus_flags; - } else { - next_bridge_state = drm_atomic_get_new_bridge_state(state, - next_bridge); - output_flags = next_bridge_state->input_bus_cfg.flags; - } - - bridge_state->output_bus_cfg.flags = output_flags; - - /* - * Propage the output flags to the input end of the bridge. Again, it's - * not necessarily what all bridges want, but that's what most of them - * do, and by doing that by default we avoid forcing drivers to - * duplicate the "dummy propagation" logic. - */ - bridge_state->input_bus_cfg.flags = output_flags; -} - /** * drm_atomic_bridge_chain_check() - Do an atomic check on the bridge chain * @bridge: bridge control structure * @crtc_state: new CRTC state * @conn_state: new connector state * - * First trigger a bus format negotiation before calling - * &drm_bridge_funcs.atomic_check() (falls back on + * Calls &drm_bridge_funcs.atomic_check() (falls back on * &drm_bridge_funcs.mode_fixup()) op for all the bridges in the encoder chain, * starting from the last bridge to the first. These are called before calling * &drm_encoder_helper_funcs.atomic_check() @@ -937,29 +689,12 @@ int drm_atomic_bridge_chain_check(struct drm_bridge *bridge, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { - struct drm_connector *conn = conn_state->connector; struct drm_encoder *encoder = bridge->encoder; struct drm_bridge *iter; - int ret; - - ret = drm_atomic_bridge_chain_select_bus_fmts(bridge, crtc_state, - conn_state); - if (ret) - return ret; list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { int ret; - /* - * Bus flags are propagated by default. If a bridge needs to - * tweak the input bus flags for any reason, it should happen - * in its &drm_bridge_funcs.atomic_check() implementation such - * that preceding bridges in the chain can propagate the new - * bus flags. - */ - drm_atomic_bridge_propagate_bus_flags(iter, conn, - crtc_state->state); - ret = drm_atomic_bridge_check(iter, crtc_state, conn_state); if (ret) return ret; diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 46e15526b087..ae0595c70132 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -35,38 +35,6 @@ struct drm_bridge; struct drm_bridge_timings; struct drm_panel; -/** - * struct drm_bus_cfg - bus configuration - * - * This structure stores the configuration of a physical bus between two - * components in an output pipeline, usually between two bridges, an encoder - * and a bridge, or a bridge and a connector. - * - * The bus configuration is stored in &drm_bridge_state separately for the - * input and output buses, as seen from the point of view of each bridge. The - * bus configuration of a bridge output is usually identical to the - * configuration of the next bridge's input, but may differ if the signals are - * modified between the two bridges, for instance by an inverter on the board. - * The input and output configurations of a bridge may differ if the bridge - * modifies the signals internally, for instance by performing format - * conversion, or modifying signals polarities. - */ -struct drm_bus_cfg { - /** - * @format: format used on this bus (one of the MEDIA_BUS_FMT_* format) - * - * This field should not be directly modified by drivers - * (&drm_atomic_bridge_chain_select_bus_fmts() takes care of the bus - * format negotiation). - */ - u32 format; - - /** - * @flags: DRM_BUS_* flags used on this bus - */ - u32 flags; -}; - /** * struct drm_bridge_state - Atomic bridge state object * @base: inherit from &drm_private_state @@ -76,16 +44,6 @@ struct drm_bridge_state { struct drm_private_state base; struct drm_bridge *bridge; - - /** - * @input_bus_cfg: input bus configuration - */ - struct drm_bus_cfg input_bus_cfg; - - /** - * @output_bus_cfg: input bus configuration - */ - struct drm_bus_cfg output_bus_cfg; }; static inline struct drm_bridge_state * @@ -429,72 +387,6 @@ struct drm_bridge_funcs { void (*atomic_destroy_state)(struct drm_bridge *bridge, struct drm_bridge_state *state); - /** - * @atomic_get_output_bus_fmts: - * - * Return the supported bus formats on the output end of a bridge. - * The returned array must be allocated with kmalloc() and will be - * freed by the caller. If the allocation fails, NULL should be - * returned. num_output_fmts must be set to the returned array size. - * Formats listed in the returned array should be listed in decreasing - * preference order (the core will try all formats until it finds one - * that works). - * - * This method is only called on the last element of the bridge chain - * as part of the bus format negotiation process that happens in - * &drm_atomic_bridge_chain_select_bus_fmts(). - * This method is optional. When not implemented, the core will - * fall back to &drm_connector.display_info.bus_formats[0] if - * &drm_connector.display_info.num_bus_formats > 0, - * or to MEDIA_BUS_FMT_FIXED otherwise. - */ - u32 *(*atomic_get_output_bus_fmts)(struct drm_bridge *bridge, - struct drm_bridge_state *bridge_state, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state, - unsigned int *num_output_fmts); - - /** - * @atomic_get_input_bus_fmts: - * - * Return the supported bus formats on the input end of a bridge for - * a specific output bus format. - * - * The returned array must be allocated with kmalloc() and will be - * freed by the caller. If the allocation fails, NULL should be - * returned. num_output_fmts must be set to the returned array size. - * Formats listed in the returned array should be listed in decreasing - * preference order (the core will try all formats until it finds one - * that works). When the format is not supported NULL should be - * returned and *num_output_fmts should be set to 0. - * - * This method is called on all elements of the bridge chain as part of - * the bus format negotiation process that happens in - * &drm_atomic_bridge_chain_select_bus_fmts(). - * This method is optional. When not implemented, the core will bypass - * bus format negotiation on this element of the bridge without - * failing, and the previous element in the chain will be passed - * MEDIA_BUS_FMT_FIXED as its output bus format. - * - * Bridge drivers that need to support being linked to bridges that are - * not supporting bus format negotiation should handle the - * output_fmt == MEDIA_BUS_FMT_FIXED case appropriately, by selecting a - * sensible default value or extracting this information from somewhere - * else (FW property, &drm_display_mode, &drm_display_info, ...) - * - * Note: Even if input format selection on the first bridge has no - * impact on the negotiation process (bus format negotiation stops once - * we reach the first element of the chain), drivers are expected to - * return accurate input formats as the input format may be used to - * configure the CRTC output appropriately. - */ - u32 *(*atomic_get_input_bus_fmts)(struct drm_bridge *bridge, - struct drm_bridge_state *bridge_state, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state, - u32 output_fmt, - unsigned int *num_input_fmts); - /** * @atomic_check: * @@ -509,14 +401,6 @@ struct drm_bridge_funcs { * called when &drm_bridge_funcs.atomic_check() is implemented, so only * one of them should be provided. * - * If drivers need to tweak &drm_bridge_state.input_bus_cfg.flags or - * &drm_bridge_state.output_bus_cfg.flags it should should happen in - * this function. By default the &drm_bridge_state.output_bus_cfg.flags - * field is set to the next bridge - * &drm_bridge_state.input_bus_cfg.flags value or - * &drm_connector.display_info.bus_flags if the bridge is the last - * element in the chain. - * * RETURNS: * zero if the check passed, a negative error code otherwise. */ @@ -704,14 +588,6 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, struct drm_atomic_state *state); -u32 * -drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge, - struct drm_bridge_state *bridge_state, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state, - u32 output_fmt, - unsigned int *num_input_fmts); - void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge, struct drm_bridge_state *state); void __drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge, From 8de679abc8ae81463d3fec495a21a6ca0a65bade Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 7 Jan 2020 19:58:05 +0100 Subject: [PATCH 10/38] Revert "drm/bridge: Add an ->atomic_check() hook" This reverts commit b86d895524ab ("drm/bridge: Add an ->atomic_check() hook"). Commit 6ed7e9625fa6 ("drm/bridge: Add a drm_bridge_state object") introduced a circular dependency between drm.ko and drm_kms_helper.ko which uncovered a misdesign in how the whole thing was implemented. Let's revert all patches depending on the bridge_state infrastructure for now. Signed-off-by: Boris Brezillon Acked-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20200107185807.606999-4-boris.brezillon@collabora.com --- drivers/gpu/drm/drm_atomic_helper.c | 12 +++--- drivers/gpu/drm/drm_bridge.c | 62 ----------------------------- include/drm/drm_bridge.h | 29 +------------- 3 files changed, 7 insertions(+), 96 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index afe14f72a824..ad8eae98d9e8 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -437,12 +437,12 @@ mode_fixup(struct drm_atomic_state *state) funcs = encoder->helper_private; bridge = drm_bridge_chain_get_first_bridge(encoder); - ret = drm_atomic_bridge_chain_check(bridge, - new_crtc_state, - new_conn_state); - if (ret) { - DRM_DEBUG_ATOMIC("Bridge atomic check failed\n"); - return ret; + ret = drm_bridge_chain_mode_fixup(bridge, + &new_crtc_state->mode, + &new_crtc_state->adjusted_mode); + if (!ret) { + DRM_DEBUG_ATOMIC("Bridge fixup failed\n"); + return -EINVAL; } if (funcs && funcs->atomic_check) { diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 8e4b799150b0..872e159fcb42 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -645,68 +645,6 @@ void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, } EXPORT_SYMBOL(drm_atomic_bridge_chain_enable); -static int drm_atomic_bridge_check(struct drm_bridge *bridge, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) -{ - if (bridge->funcs->atomic_check) { - struct drm_bridge_state *bridge_state; - int ret; - - bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state, - bridge); - if (WARN_ON(!bridge_state)) - return -EINVAL; - - ret = bridge->funcs->atomic_check(bridge, bridge_state, - crtc_state, conn_state); - if (ret) - return ret; - } else if (bridge->funcs->mode_fixup) { - if (!bridge->funcs->mode_fixup(bridge, &crtc_state->mode, - &crtc_state->adjusted_mode)) - return -EINVAL; - } - - return 0; -} - -/** - * drm_atomic_bridge_chain_check() - Do an atomic check on the bridge chain - * @bridge: bridge control structure - * @crtc_state: new CRTC state - * @conn_state: new connector state - * - * Calls &drm_bridge_funcs.atomic_check() (falls back on - * &drm_bridge_funcs.mode_fixup()) op for all the bridges in the encoder chain, - * starting from the last bridge to the first. These are called before calling - * &drm_encoder_helper_funcs.atomic_check() - * - * RETURNS: - * 0 on success, a negative error code on failure - */ -int drm_atomic_bridge_chain_check(struct drm_bridge *bridge, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) -{ - struct drm_encoder *encoder = bridge->encoder; - struct drm_bridge *iter; - - list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { - int ret; - - ret = drm_atomic_bridge_check(iter, crtc_state, conn_state); - if (ret) - return ret; - - if (iter == bridge) - break; - } - - return 0; -} -EXPORT_SYMBOL(drm_atomic_bridge_chain_check); - /** * __drm_atomic_helper_bridge_reset() - Initialize a bridge state to its * default diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index ae0595c70132..52d3ed150618 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -128,9 +128,7 @@ struct drm_bridge_funcs { * this function passes all other callbacks must succeed for this * configuration. * - * The mode_fixup callback is optional. &drm_bridge_funcs.mode_fixup() - * is not called when &drm_bridge_funcs.atomic_check() is implemented, - * so only one of them should be provided. + * The @mode_fixup callback is optional. * * NOTE: * @@ -387,28 +385,6 @@ struct drm_bridge_funcs { void (*atomic_destroy_state)(struct drm_bridge *bridge, struct drm_bridge_state *state); - /** - * @atomic_check: - * - * This method is responsible for checking bridge state correctness. - * It can also check the state of the surrounding components in chain - * to make sure the whole pipeline can work properly. - * - * &drm_bridge_funcs.atomic_check() hooks are called in reverse - * order (from the last to the first bridge). - * - * This method is optional. &drm_bridge_funcs.mode_fixup() is not - * called when &drm_bridge_funcs.atomic_check() is implemented, so only - * one of them should be provided. - * - * RETURNS: - * zero if the check passed, a negative error code otherwise. - */ - int (*atomic_check)(struct drm_bridge *bridge, - struct drm_bridge_state *bridge_state, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state); - /** * @atomic_reset: * @@ -576,9 +552,6 @@ void drm_bridge_chain_mode_set(struct drm_bridge *bridge, void drm_bridge_chain_pre_enable(struct drm_bridge *bridge); void drm_bridge_chain_enable(struct drm_bridge *bridge); -int drm_atomic_bridge_chain_check(struct drm_bridge *bridge, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state); void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge, struct drm_atomic_state *state); void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, From b470743bedbacc7552763c0d973abe958aa0ff87 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 7 Jan 2020 19:58:06 +0100 Subject: [PATCH 11/38] Revert "drm/bridge: Patch atomic hooks to take a drm_bridge_state" This reverts commit f7619a58ef92 ("drm/bridge: Patch atomic hooks to take a drm_bridge_state"). Commit 6ed7e9625fa6 ("drm/bridge: Add a drm_bridge_state object") introduced a circular dependency between drm.ko and drm_kms_helper.ko which uncovered a misdesign in how the whole thing was implemented. Let's revert all patches depending on the bridge_state infrastructure for now. Signed-off-by: Boris Brezillon Acked-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20200107185807.606999-5-boris.brezillon@collabora.com --- .../drm/bridge/analogix/analogix_dp_core.c | 41 ++++++------- drivers/gpu/drm/drm_bridge.c | 61 ++++--------------- drivers/gpu/drm/rcar-du/rcar_lvds.c | 8 +-- include/drm/drm_bridge.h | 8 +-- 4 files changed, 36 insertions(+), 82 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 6fab71985cd4..6effe532f820 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1289,21 +1289,19 @@ struct drm_crtc *analogix_dp_get_new_crtc(struct analogix_dp_device *dp, return conn_state->crtc; } -static void -analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state) +static void analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge, + struct drm_atomic_state *state) { - struct drm_atomic_state *old_state = old_bridge_state->base.state; struct analogix_dp_device *dp = bridge->driver_private; struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state; int ret; - crtc = analogix_dp_get_new_crtc(dp, old_state); + crtc = analogix_dp_get_new_crtc(dp, state); if (!crtc) return; - old_crtc_state = drm_atomic_get_old_crtc_state(old_state, crtc); + old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc); /* Don't touch the panel if we're coming back from PSR */ if (old_crtc_state && old_crtc_state->self_refresh_active) return; @@ -1368,22 +1366,20 @@ out_dp_clk_pre: return ret; } -static void -analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state) +static void analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge, + struct drm_atomic_state *state) { - struct drm_atomic_state *old_state = old_bridge_state->base.state; struct analogix_dp_device *dp = bridge->driver_private; struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state; int timeout_loop = 0; int ret; - crtc = analogix_dp_get_new_crtc(dp, old_state); + crtc = analogix_dp_get_new_crtc(dp, state); if (!crtc) return; - old_crtc_state = drm_atomic_get_old_crtc_state(old_state, crtc); + old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc); /* Not a full enable, just disable PSR and continue */ if (old_crtc_state && old_crtc_state->self_refresh_active) { ret = analogix_dp_disable_psr(dp); @@ -1444,20 +1440,18 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge) dp->dpms_mode = DRM_MODE_DPMS_OFF; } -static void -analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state) +static void analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge, + struct drm_atomic_state *state) { - struct drm_atomic_state *old_state = old_bridge_state->base.state; struct analogix_dp_device *dp = bridge->driver_private; struct drm_crtc *crtc; struct drm_crtc_state *new_crtc_state = NULL; - crtc = analogix_dp_get_new_crtc(dp, old_state); + crtc = analogix_dp_get_new_crtc(dp, state); if (!crtc) goto out; - new_crtc_state = drm_atomic_get_new_crtc_state(old_state, crtc); + new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); if (!new_crtc_state) goto out; @@ -1469,21 +1463,20 @@ out: analogix_dp_bridge_disable(bridge); } -static void -analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state) +static +void analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge, + struct drm_atomic_state *state) { - struct drm_atomic_state *old_state = old_bridge_state->base.state; struct analogix_dp_device *dp = bridge->driver_private; struct drm_crtc *crtc; struct drm_crtc_state *new_crtc_state; int ret; - crtc = analogix_dp_get_new_crtc(dp, old_state); + crtc = analogix_dp_get_new_crtc(dp, state); if (!crtc) return; - new_crtc_state = drm_atomic_get_new_crtc_state(old_state, crtc); + new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); if (!new_crtc_state || !new_crtc_state->self_refresh_active) return; diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 872e159fcb42..a213c9042f2c 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -501,19 +501,10 @@ void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge, encoder = bridge->encoder; list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { - if (iter->funcs->atomic_disable) { - struct drm_bridge_state *old_bridge_state; - - old_bridge_state = - drm_atomic_get_old_bridge_state(old_state, - iter); - if (WARN_ON(!old_bridge_state)) - return; - - iter->funcs->atomic_disable(iter, old_bridge_state); - } else if (iter->funcs->disable) { + if (iter->funcs->atomic_disable) + iter->funcs->atomic_disable(iter, old_state); + else if (iter->funcs->disable) iter->funcs->disable(iter); - } if (iter == bridge) break; @@ -544,20 +535,10 @@ void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, encoder = bridge->encoder; list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { - if (bridge->funcs->atomic_post_disable) { - struct drm_bridge_state *old_bridge_state; - - old_bridge_state = - drm_atomic_get_old_bridge_state(old_state, - bridge); - if (WARN_ON(!old_bridge_state)) - return; - - bridge->funcs->atomic_post_disable(bridge, - old_bridge_state); - } else if (bridge->funcs->post_disable) { + if (bridge->funcs->atomic_post_disable) + bridge->funcs->atomic_post_disable(bridge, old_state); + else if (bridge->funcs->post_disable) bridge->funcs->post_disable(bridge); - } } } EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable); @@ -586,19 +567,10 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, encoder = bridge->encoder; list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { - if (iter->funcs->atomic_pre_enable) { - struct drm_bridge_state *old_bridge_state; - - old_bridge_state = - drm_atomic_get_old_bridge_state(old_state, - iter); - if (WARN_ON(!old_bridge_state)) - return; - - iter->funcs->atomic_pre_enable(iter, old_bridge_state); - } else if (iter->funcs->pre_enable) { + if (iter->funcs->atomic_pre_enable) + iter->funcs->atomic_pre_enable(iter, old_state); + else if (iter->funcs->pre_enable) iter->funcs->pre_enable(iter); - } if (iter == bridge) break; @@ -628,19 +600,10 @@ void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, encoder = bridge->encoder; list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { - if (bridge->funcs->atomic_enable) { - struct drm_bridge_state *old_bridge_state; - - old_bridge_state = - drm_atomic_get_old_bridge_state(old_state, - bridge); - if (WARN_ON(!old_bridge_state)) - return; - - bridge->funcs->atomic_enable(bridge, old_bridge_state); - } else if (bridge->funcs->enable) { + if (bridge->funcs->atomic_enable) + bridge->funcs->atomic_enable(bridge, old_state); + else if (bridge->funcs->enable) bridge->funcs->enable(bridge); - } } } EXPORT_SYMBOL(drm_atomic_bridge_chain_enable); diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c index 961519ce6634..8ffa4fbbdeb3 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c @@ -590,9 +590,8 @@ static void __rcar_lvds_atomic_enable(struct drm_bridge *bridge, } static void rcar_lvds_atomic_enable(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state) + struct drm_atomic_state *state) { - struct drm_atomic_state *state = old_bridge_state->base.state; struct drm_connector *connector; struct drm_crtc *crtc; @@ -604,7 +603,7 @@ static void rcar_lvds_atomic_enable(struct drm_bridge *bridge, } static void rcar_lvds_atomic_disable(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state) + struct drm_atomic_state *state) { struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); @@ -619,8 +618,7 @@ static void rcar_lvds_atomic_disable(struct drm_bridge *bridge, /* Disable the companion LVDS encoder in dual-link mode. */ if (lvds->link_type != RCAR_LVDS_SINGLE_LINK && lvds->companion) - lvds->companion->funcs->atomic_disable(lvds->companion, - old_bridge_state); + lvds->companion->funcs->atomic_disable(lvds->companion, state); clk_disable_unprepare(lvds->clocks.mod); } diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 52d3ed150618..fc7c71f4de55 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -282,7 +282,7 @@ struct drm_bridge_funcs { * The @atomic_pre_enable callback is optional. */ void (*atomic_pre_enable)(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state); + struct drm_atomic_state *old_state); /** * @atomic_enable: @@ -307,7 +307,7 @@ struct drm_bridge_funcs { * The @atomic_enable callback is optional. */ void (*atomic_enable)(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state); + struct drm_atomic_state *old_state); /** * @atomic_disable: * @@ -330,7 +330,7 @@ struct drm_bridge_funcs { * The @atomic_disable callback is optional. */ void (*atomic_disable)(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state); + struct drm_atomic_state *old_state); /** * @atomic_post_disable: @@ -356,7 +356,7 @@ struct drm_bridge_funcs { * The @atomic_post_disable callback is optional. */ void (*atomic_post_disable)(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state); + struct drm_atomic_state *old_state); /** * @atomic_duplicate_state: From 09912635230374bdca2aca620d183f1834b3140c Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 7 Jan 2020 19:58:07 +0100 Subject: [PATCH 12/38] Revert "drm/bridge: Add a drm_bridge_state object" This reverts commit 6ed7e9625fa6 ("drm/bridge: Add a drm_bridge_state object") which introduced a circular dependency between drm.ko and drm_kms_helper.ko. Looks like the helper/core split is not appropriate and fixing that is not simple. Signed-off-by: Boris Brezillon Acked-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20200107185807.606999-6-boris.brezillon@collabora.com --- drivers/gpu/drm/drm_atomic.c | 39 -------- drivers/gpu/drm/drm_atomic_helper.c | 20 ---- drivers/gpu/drm/drm_bridge.c | 139 ++-------------------------- include/drm/drm_atomic.h | 3 - include/drm/drm_bridge.h | 114 ----------------------- 5 files changed, 6 insertions(+), 309 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index bf1b9c37d515..d33691512a8e 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -30,7 +30,6 @@ #include #include -#include #include #include #include @@ -1018,44 +1017,6 @@ static void drm_atomic_connector_print_state(struct drm_printer *p, connector->funcs->atomic_print_state(p, state); } -/** - * drm_atomic_add_encoder_bridges - add bridges attached to an encoder - * @state: atomic state - * @encoder: DRM encoder - * - * This function adds all bridges attached to @encoder. This is needed to add - * bridge states to @state and make them available when - * &bridge_funcs.atomic_{check,pre_enable,enable,disable_post_disable}() are - * called - * - * Returns: - * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK - * then the w/w mutex code has detected a deadlock and the entire atomic - * sequence must be restarted. All other errors are fatal. - */ -int -drm_atomic_add_encoder_bridges(struct drm_atomic_state *state, - struct drm_encoder *encoder) -{ - struct drm_bridge_state *bridge_state; - struct drm_bridge *bridge; - - if (!encoder) - return 0; - - DRM_DEBUG_ATOMIC("Adding all bridges for [encoder:%d:%s] to %p\n", - encoder->base.id, encoder->name, state); - - drm_for_each_bridge_in_chain(encoder, bridge) { - bridge_state = drm_atomic_get_bridge_state(state, bridge); - if (IS_ERR(bridge_state)) - return PTR_ERR(bridge_state); - } - - return 0; -} -EXPORT_SYMBOL(drm_atomic_add_encoder_bridges); - /** * drm_atomic_add_affected_connectors - add connectors for CRTC * @state: atomic state diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index ad8eae98d9e8..4511c2e07bb9 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -730,26 +730,6 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, return ret; } - /* - * Iterate over all connectors again, and add all affected bridges to - * the state. - */ - for_each_oldnew_connector_in_state(state, connector, - old_connector_state, - new_connector_state, i) { - struct drm_encoder *encoder; - - encoder = old_connector_state->best_encoder; - ret = drm_atomic_add_encoder_bridges(state, encoder); - if (ret) - return ret; - - encoder = new_connector_state->best_encoder; - ret = drm_atomic_add_encoder_bridges(state, encoder); - if (ret) - return ret; - } - ret = mode_valid(state); if (ret) return ret; diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index a213c9042f2c..c2cf0c90fa26 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -25,7 +25,6 @@ #include #include -#include #include #include @@ -90,74 +89,6 @@ void drm_bridge_remove(struct drm_bridge *bridge) } EXPORT_SYMBOL(drm_bridge_remove); -static struct drm_bridge_state * -drm_atomic_default_bridge_duplicate_state(struct drm_bridge *bridge) -{ - struct drm_bridge_state *new; - - if (WARN_ON(!bridge->base.state)) - return NULL; - - new = kzalloc(sizeof(*new), GFP_KERNEL); - if (new) - __drm_atomic_helper_bridge_duplicate_state(bridge, new); - - return new; -} - -static struct drm_private_state * -drm_bridge_atomic_duplicate_priv_state(struct drm_private_obj *obj) -{ - struct drm_bridge *bridge = drm_priv_to_bridge(obj); - struct drm_bridge_state *state; - - if (bridge->funcs->atomic_duplicate_state) - state = bridge->funcs->atomic_duplicate_state(bridge); - else - state = drm_atomic_default_bridge_duplicate_state(bridge); - - return state ? &state->base : NULL; -} - -static void -drm_atomic_default_bridge_destroy_state(struct drm_bridge *bridge, - struct drm_bridge_state *state) -{ - /* Just a simple kfree() for now */ - kfree(state); -} - -static void -drm_bridge_atomic_destroy_priv_state(struct drm_private_obj *obj, - struct drm_private_state *s) -{ - struct drm_bridge_state *state = drm_priv_to_bridge_state(s); - struct drm_bridge *bridge = drm_priv_to_bridge(obj); - - if (bridge->funcs->atomic_destroy_state) - bridge->funcs->atomic_destroy_state(bridge, state); - else - drm_atomic_default_bridge_destroy_state(bridge, state); -} - -static const struct drm_private_state_funcs drm_bridge_priv_state_funcs = { - .atomic_duplicate_state = drm_bridge_atomic_duplicate_priv_state, - .atomic_destroy_state = drm_bridge_atomic_destroy_priv_state, -}; - -static struct drm_bridge_state * -drm_atomic_default_bridge_reset(struct drm_bridge *bridge) -{ - struct drm_bridge_state *bridge_state; - - bridge_state = kzalloc(sizeof(*bridge_state), GFP_KERNEL); - if (!bridge_state) - return ERR_PTR(-ENOMEM); - - __drm_atomic_helper_bridge_reset(bridge, bridge_state); - return bridge_state; -} - /** * drm_bridge_attach - attach the bridge to an encoder's chain * @@ -183,7 +114,6 @@ drm_atomic_default_bridge_reset(struct drm_bridge *bridge) int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, struct drm_bridge *previous) { - struct drm_bridge_state *state; int ret; if (!encoder || !bridge) @@ -205,35 +135,15 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, if (bridge->funcs->attach) { ret = bridge->funcs->attach(bridge); - if (ret < 0) - goto err_reset_bridge; + if (ret < 0) { + list_del(&bridge->chain_node); + bridge->dev = NULL; + bridge->encoder = NULL; + return ret; + } } - if (bridge->funcs->atomic_reset) - state = bridge->funcs->atomic_reset(bridge); - else - state = drm_atomic_default_bridge_reset(bridge); - - if (IS_ERR(state)) { - ret = PTR_ERR(state); - goto err_detach_bridge; - } - - drm_atomic_private_obj_init(bridge->dev, &bridge->base, - &state->base, - &drm_bridge_priv_state_funcs); - return 0; - -err_detach_bridge: - if (bridge->funcs->detach) - bridge->funcs->detach(bridge); - -err_reset_bridge: - bridge->dev = NULL; - bridge->encoder = NULL; - list_del(&bridge->chain_node); - return ret; } EXPORT_SYMBOL(drm_bridge_attach); @@ -245,8 +155,6 @@ void drm_bridge_detach(struct drm_bridge *bridge) if (WARN_ON(!bridge->dev)) return; - drm_atomic_private_obj_fini(&bridge->base); - if (bridge->funcs->detach) bridge->funcs->detach(bridge); @@ -608,41 +516,6 @@ void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, } EXPORT_SYMBOL(drm_atomic_bridge_chain_enable); -/** - * __drm_atomic_helper_bridge_reset() - Initialize a bridge state to its - * default - * @bridge: the bridge this state is refers to - * @state: bridge state to initialize - * - * Initialize the bridge state to default values. This is meant to be* called - * by the bridge &drm_plane_funcs.reset hook for bridges that subclass the - * bridge state. - */ -void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge, - struct drm_bridge_state *state) -{ - memset(state, 0, sizeof(*state)); - state->bridge = bridge; -} -EXPORT_SYMBOL(__drm_atomic_helper_bridge_reset); - -/** - * __drm_atomic_helper_bridge_duplicate_state() - Copy atomic bridge state - * @bridge: bridge object - * @state: atomic bridge state - * - * Copies atomic state from a bridge's current state and resets inferred values. - * This is useful for drivers that subclass the bridge state. - */ -void __drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge, - struct drm_bridge_state *state) -{ - __drm_atomic_helper_private_obj_duplicate_state(&bridge->base, - &state->base); - state->bridge = bridge; -} -EXPORT_SYMBOL(__drm_atomic_helper_bridge_duplicate_state); - #ifdef CONFIG_OF /** * of_drm_find_bridge - find the bridge corresponding to the device node in diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index ccce65e14917..951dfb15c27b 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -669,9 +669,6 @@ __drm_atomic_get_current_plane_state(struct drm_atomic_state *state, return plane->state; } -int __must_check -drm_atomic_add_encoder_bridges(struct drm_atomic_state *state, - struct drm_encoder *encoder); int __must_check drm_atomic_add_affected_connectors(struct drm_atomic_state *state, struct drm_crtc *crtc); diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index fc7c71f4de55..694e153a7531 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -25,8 +25,6 @@ #include #include - -#include #include #include #include @@ -35,23 +33,6 @@ struct drm_bridge; struct drm_bridge_timings; struct drm_panel; -/** - * struct drm_bridge_state - Atomic bridge state object - * @base: inherit from &drm_private_state - * @bridge: the bridge this state refers to - */ -struct drm_bridge_state { - struct drm_private_state base; - - struct drm_bridge *bridge; -}; - -static inline struct drm_bridge_state * -drm_priv_to_bridge_state(struct drm_private_state *priv) -{ - return container_of(priv, struct drm_bridge_state, base); -} - /** * struct drm_bridge_funcs - drm_bridge control functions */ @@ -357,49 +338,6 @@ struct drm_bridge_funcs { */ void (*atomic_post_disable)(struct drm_bridge *bridge, struct drm_atomic_state *old_state); - - /** - * @atomic_duplicate_state: - * - * Duplicate the current bridge state object (which is guaranteed to be - * non-NULL). - * - * The atomic_duplicate_state() is optional. When not implemented the - * core allocates a drm_bridge_state object and calls - * &__drm_atomic_helper_bridge_duplicate_state() to initialize it. - * - * RETURNS: - * A valid drm_bridge_state object or NULL if the allocation fails. - */ - struct drm_bridge_state *(*atomic_duplicate_state)(struct drm_bridge *bridge); - - /** - * @atomic_destroy_state: - * - * Destroy a bridge state object previously allocated by - * &drm_bridge_funcs.atomic_duplicate_state(). - * - * The atomic_destroy_state hook is optional. When not implemented the - * core calls kfree() on the state. - */ - void (*atomic_destroy_state)(struct drm_bridge *bridge, - struct drm_bridge_state *state); - - /** - * @atomic_reset: - * - * Reset the bridge to a predefined state (or retrieve its current - * state) and return a &drm_bridge_state object matching this state. - * This function is called at attach time. - * - * The atomic_reset hook is optional. When not implemented the core - * allocates a new state and calls &__drm_atomic_helper_bridge_reset(). - * - * RETURNS: - * A valid drm_bridge_state object in case of success, an ERR_PTR() - * giving the reason of the failure otherwise. - */ - struct drm_bridge_state *(*atomic_reset)(struct drm_bridge *bridge); }; /** @@ -442,8 +380,6 @@ struct drm_bridge_timings { * struct drm_bridge - central DRM bridge control structure */ struct drm_bridge { - /** @base: inherit from &drm_private_object */ - struct drm_private_obj base; /** @dev: DRM device this bridge belongs to */ struct drm_device *dev; /** @encoder: encoder to which this bridge is connected */ @@ -468,12 +404,6 @@ struct drm_bridge { void *driver_private; }; -static inline struct drm_bridge * -drm_priv_to_bridge(struct drm_private_obj *priv) -{ - return container_of(priv, struct drm_bridge, base); -} - void drm_bridge_add(struct drm_bridge *bridge); void drm_bridge_remove(struct drm_bridge *bridge); struct drm_bridge *of_drm_find_bridge(struct device_node *np); @@ -561,50 +491,6 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, struct drm_atomic_state *state); -void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge, - struct drm_bridge_state *state); -void __drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge, - struct drm_bridge_state *new); - -static inline struct drm_bridge_state * -drm_atomic_get_bridge_state(struct drm_atomic_state *state, - struct drm_bridge *bridge) -{ - struct drm_private_state *obj_state; - - obj_state = drm_atomic_get_private_obj_state(state, &bridge->base); - if (IS_ERR(obj_state)) - return ERR_CAST(obj_state); - - return drm_priv_to_bridge_state(obj_state); -} - -static inline struct drm_bridge_state * -drm_atomic_get_old_bridge_state(struct drm_atomic_state *state, - struct drm_bridge *bridge) -{ - struct drm_private_state *obj_state; - - obj_state = drm_atomic_get_old_private_obj_state(state, &bridge->base); - if (!obj_state) - return NULL; - - return drm_priv_to_bridge_state(obj_state); -} - -static inline struct drm_bridge_state * -drm_atomic_get_new_bridge_state(struct drm_atomic_state *state, - struct drm_bridge *bridge) -{ - struct drm_private_state *obj_state; - - obj_state = drm_atomic_get_new_private_obj_state(state, &bridge->base); - if (!obj_state) - return NULL; - - return drm_priv_to_bridge_state(obj_state); -} - #ifdef CONFIG_DRM_PANEL_BRIDGE struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel); struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel, From 2ec1431ffac9f891a11ac955a9ee914e0547215e Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Sat, 4 Jan 2020 21:43:31 +0100 Subject: [PATCH 13/38] video: fbdev: mmp: fix platform_get_irq.cocci warnings Remove dev_err() messages after platform_get_irq*() failures. Line 450 is redundant because platform_get_irq() already prints an error. Generated by: scripts/coccinelle/api/platform_get_irq.cocci Fixes: dd90e9ae55a1 ("video: fbdev: mmp: add COMPILE_TEST support") Signed-off-by: kbuild test robot Signed-off-by: Julia Lawall Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/alpine.DEB.2.21.2001042140310.6944@hadrien --- drivers/video/fbdev/mmp/hw/mmp_ctrl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/video/fbdev/mmp/hw/mmp_ctrl.c b/drivers/video/fbdev/mmp/hw/mmp_ctrl.c index b877a606ce26..88c137f5c729 100644 --- a/drivers/video/fbdev/mmp/hw/mmp_ctrl.c +++ b/drivers/video/fbdev/mmp/hw/mmp_ctrl.c @@ -456,7 +456,6 @@ static int mmphw_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(&pdev->dev, "%s: no IRQ defined\n", __func__); ret = -ENOENT; goto failed; } From 033bfe7538a1523f36dd434eaff7c754a555c458 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 27 Dec 2019 15:41:23 +0100 Subject: [PATCH 14/38] drm/vc4: dsi: Fix bridge chain handling Commit 05193dc38197 ("drm/bridge: Make the bridge chain a double-linked list") patched the bridge chain logic to use a double-linked list instead of a single-linked list. This change induced changes to the VC4 driver which was manually resetting the encoder->bridge element to NULL to control the enable/disable sequence of the bridge chain. During this conversion, 2 bugs were introduced: 1/ list_splice() was used to move chain elements to our own internal chain, but list_splice() does not reset the source list to an empty state, leading to unexpected bridge hook calls when drm_bridge_chain_xxx() helpers were called by the core. Replacing those list_splice() calls by list_splice_init() ones fixes this problem. 2/ drm_bridge_chain_xxx() helpers operate on the bridge->encoder->bridge_chain list, which is now empty. When the helper uses list_for_each_entry_reverse() we end up with no operation done which is not what we want. But that's even worse when the helper uses list_for_each_entry_from(), because in that case we end up in an infinite loop searching for the list head element which is no longer encoder->bridge_chain but vc4_dsi->bridge_chain. To address that problem we stop using the bridge chain helpers and call the hooks directly. Reported-by: Marek Szyprowski Cc: Eric Anholt Fixes: 05193dc38197 ("drm/bridge: Make the bridge chain a double-linked list") Signed-off-by: Boris Brezillon Reviewed-by: Andrzej Hajda Acked-by: Eric Anholt Link: https://patchwork.freedesktop.org/patch/msgid/20191227144124.210294-2-boris.brezillon@collabora.com --- drivers/gpu/drm/vc4/vc4_dsi.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c index 6c5b80ad6154..fd8a2eb60505 100644 --- a/drivers/gpu/drm/vc4/vc4_dsi.c +++ b/drivers/gpu/drm/vc4/vc4_dsi.c @@ -753,10 +753,19 @@ static void vc4_dsi_encoder_disable(struct drm_encoder *encoder) struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder); struct vc4_dsi *dsi = vc4_encoder->dsi; struct device *dev = &dsi->pdev->dev; + struct drm_bridge *iter; + + list_for_each_entry_reverse(iter, &dsi->bridge_chain, chain_node) { + if (iter->funcs->disable) + iter->funcs->disable(iter); + } - drm_bridge_chain_disable(dsi->bridge); vc4_dsi_ulps(dsi, true); - drm_bridge_chain_post_disable(dsi->bridge); + + list_for_each_entry_from(iter, &dsi->bridge_chain, chain_node) { + if (iter->funcs->post_disable) + iter->funcs->post_disable(iter); + } clk_disable_unprepare(dsi->pll_phy_clock); clk_disable_unprepare(dsi->escape_clock); @@ -824,6 +833,7 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) struct vc4_dsi *dsi = vc4_encoder->dsi; struct device *dev = &dsi->pdev->dev; bool debug_dump_regs = false; + struct drm_bridge *iter; unsigned long hs_clock; u32 ui_ns; /* Minimum LP state duration in escape clock cycles. */ @@ -1056,7 +1066,10 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) vc4_dsi_ulps(dsi, false); - drm_bridge_chain_pre_enable(dsi->bridge); + list_for_each_entry_reverse(iter, &dsi->bridge_chain, chain_node) { + if (iter->funcs->pre_enable) + iter->funcs->pre_enable(iter); + } if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { DSI_PORT_WRITE(DISP0_CTRL, @@ -1073,7 +1086,10 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) DSI_DISP0_ENABLE); } - drm_bridge_chain_enable(dsi->bridge); + list_for_each_entry(iter, &dsi->bridge_chain, chain_node) { + if (iter->funcs->enable) + iter->funcs->enable(iter); + } if (debug_dump_regs) { struct drm_printer p = drm_info_printer(&dsi->pdev->dev); @@ -1613,7 +1629,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) * from our driver, since we need to sequence them within the * encoder's enable/disable paths. */ - list_splice(&dsi->encoder->bridge_chain, &dsi->bridge_chain); + list_splice_init(&dsi->encoder->bridge_chain, &dsi->bridge_chain); if (dsi->port == 0) vc4_debugfs_add_regset32(drm, "dsi0_regs", &dsi->regset); @@ -1639,7 +1655,7 @@ static void vc4_dsi_unbind(struct device *dev, struct device *master, * Restore the bridge_chain so the bridge detach procedure can happen * normally. */ - list_splice(&dsi->bridge_chain, &dsi->encoder->bridge_chain); + list_splice_init(&dsi->bridge_chain, &dsi->encoder->bridge_chain); vc4_dsi_encoder_destroy(dsi->encoder); if (dsi->port == 1) From f66ff55a9bd06855f9c6b8f29d8760f77bfe43c2 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 27 Dec 2019 15:41:24 +0100 Subject: [PATCH 15/38] drm/exynos: dsi: Fix bridge chain handling Commit 05193dc38197 ("drm/bridge: Make the bridge chain a double-linked list") patched the bridge chain logic to use a double-linked list instead of a single-linked list. This change induced changes to the Exynos driver which was manually resetting the encoder->bridge element to NULL to control the enable/disable sequence of the bridge chain. During this conversion, 2 bugs were introduced: 1/ list_splice() was used to move chain elements to our own internal chain, but list_splice() does not reset the source list to an empty state, leading to unexpected bridge hook calls when drm_bridge_chain_xxx() helpers were called by the core. Replacing the list_splice() call by list_splice_init() fixes this problem. 2/ drm_bridge_chain_xxx() helpers operate on the bridge->encoder->bridge_chain list, which is now empty. When the helper uses list_for_each_entry_reverse() we end up with no operation done which is not what we want. But that's even worse when the helper uses list_for_each_entry_from(), because in that case we end up in an infinite loop searching for the list head element which is no longer encoder->bridge_chain but exynos_dsi->bridge_chain. To address that problem we stop using the bridge chain helpers and call the hooks directly. Reported-by: Marek Szyprowski Fixes: 05193dc38197 ("drm/bridge: Make the bridge chain a double-linked list") Signed-off-by: Boris Brezillon Tested-by: Marek Szyprowski Reviewed-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20191227144124.210294-3-boris.brezillon@collabora.com --- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 29 ++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 3955f84dc893..33628d85edad 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1378,6 +1378,7 @@ static void exynos_dsi_unregister_te_irq(struct exynos_dsi *dsi) static void exynos_dsi_enable(struct drm_encoder *encoder) { struct exynos_dsi *dsi = encoder_to_dsi(encoder); + struct drm_bridge *iter; int ret; if (dsi->state & DSIM_STATE_ENABLED) @@ -1391,7 +1392,11 @@ static void exynos_dsi_enable(struct drm_encoder *encoder) if (ret < 0) goto err_put_sync; } else { - drm_bridge_chain_pre_enable(dsi->out_bridge); + list_for_each_entry_reverse(iter, &dsi->bridge_chain, + chain_node) { + if (iter->funcs->pre_enable) + iter->funcs->pre_enable(iter); + } } exynos_dsi_set_display_mode(dsi); @@ -1402,7 +1407,10 @@ static void exynos_dsi_enable(struct drm_encoder *encoder) if (ret < 0) goto err_display_disable; } else { - drm_bridge_chain_enable(dsi->out_bridge); + list_for_each_entry(iter, &dsi->bridge_chain, chain_node) { + if (iter->funcs->enable) + iter->funcs->enable(iter); + } } dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE; @@ -1420,6 +1428,7 @@ err_put_sync: static void exynos_dsi_disable(struct drm_encoder *encoder) { struct exynos_dsi *dsi = encoder_to_dsi(encoder); + struct drm_bridge *iter; if (!(dsi->state & DSIM_STATE_ENABLED)) return; @@ -1427,10 +1436,20 @@ static void exynos_dsi_disable(struct drm_encoder *encoder) dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE; drm_panel_disable(dsi->panel); - drm_bridge_chain_disable(dsi->out_bridge); + + list_for_each_entry_reverse(iter, &dsi->bridge_chain, chain_node) { + if (iter->funcs->disable) + iter->funcs->disable(iter); + } + exynos_dsi_set_display_enable(dsi, false); drm_panel_unprepare(dsi->panel); - drm_bridge_chain_post_disable(dsi->out_bridge); + + list_for_each_entry(iter, &dsi->bridge_chain, chain_node) { + if (iter->funcs->post_disable) + iter->funcs->post_disable(iter); + } + dsi->state &= ~DSIM_STATE_ENABLED; pm_runtime_put_sync(dsi->dev); } @@ -1523,7 +1542,7 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host, if (out_bridge) { drm_bridge_attach(encoder, out_bridge, NULL); dsi->out_bridge = out_bridge; - list_splice(&encoder->bridge_chain, &dsi->bridge_chain); + list_splice_init(&encoder->bridge_chain, &dsi->bridge_chain); } else { int ret = exynos_dsi_create_connector(encoder); From 451debe55715acafdcacba6a879e6ccb8eca23ce Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jan 2020 17:59:56 +0100 Subject: [PATCH 16/38] drm/sun4i: backend: Make sure we enforce the clock rate The backend needs to run at 300MHz to be functional. This was done so far using assigned-clocks in the device tree, but that is easy to forget, and doesn't provide any other guarantee than the rate is going to be roughly the one requested at probe time. Therefore it's pretty fragile, so let's just use the exclusive clock API to enforce it. Reviewed-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20200107165957.672435-1-maxime@cerno.tech --- drivers/gpu/drm/sun4i/sun4i_backend.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index 4e29f4fe4a05..072ea113e6be 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -856,6 +856,13 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, ret = PTR_ERR(backend->mod_clk); goto err_disable_bus_clk; } + + ret = clk_set_rate_exclusive(backend->mod_clk, 300000000); + if (ret) { + dev_err(dev, "Couldn't set the module clock frequency\n"); + goto err_disable_bus_clk; + } + clk_prepare_enable(backend->mod_clk); backend->ram_clk = devm_clk_get(dev, "ram"); @@ -932,6 +939,7 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, err_disable_ram_clk: clk_disable_unprepare(backend->ram_clk); err_disable_mod_clk: + clk_rate_exclusive_put(backend->mod_clk); clk_disable_unprepare(backend->mod_clk); err_disable_bus_clk: clk_disable_unprepare(backend->bus_clk); @@ -952,6 +960,7 @@ static void sun4i_backend_unbind(struct device *dev, struct device *master, sun4i_backend_free_sat(dev); clk_disable_unprepare(backend->ram_clk); + clk_rate_exclusive_put(backend->mod_clk); clk_disable_unprepare(backend->mod_clk); clk_disable_unprepare(backend->bus_clk); reset_control_assert(backend->reset); From 6fe082b0fbe5a8ce9b16998fc4cb885a9b52f976 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jan 2020 17:59:57 +0100 Subject: [PATCH 17/38] drm/sun4i: drc: Make sure we enforce the clock rate The DRC needs to run at 300MHz to be functional. This was done so far using assigned-clocks in the device tree, but that is easy to forget, and doesn't provide any other guarantee than the rate is going to be roughly the one requested at probe time. Therefore it's pretty fragile, so let's just use the exclusive clock API to enforce it. Reviewed-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20200107165957.672435-2-maxime@cerno.tech --- drivers/gpu/drm/sun4i/sun6i_drc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/sun4i/sun6i_drc.c b/drivers/gpu/drm/sun4i/sun6i_drc.c index f7ab72244796..4fbe9a6b5182 100644 --- a/drivers/gpu/drm/sun4i/sun6i_drc.c +++ b/drivers/gpu/drm/sun4i/sun6i_drc.c @@ -56,6 +56,13 @@ static int sun6i_drc_bind(struct device *dev, struct device *master, ret = PTR_ERR(drc->mod_clk); goto err_disable_bus_clk; } + + ret = clk_set_rate_exclusive(drc->mod_clk, 300000000); + if (ret) { + dev_err(dev, "Couldn't set the module clock frequency\n"); + goto err_disable_bus_clk; + } + clk_prepare_enable(drc->mod_clk); return 0; @@ -72,6 +79,7 @@ static void sun6i_drc_unbind(struct device *dev, struct device *master, { struct sun6i_drc *drc = dev_get_drvdata(dev); + clk_rate_exclusive_put(drc->mod_clk); clk_disable_unprepare(drc->mod_clk); clk_disable_unprepare(drc->bus_clk); reset_control_assert(drc->reset); From 72f775611daf3ce20358388facbaf11f22899fa2 Mon Sep 17 00:00:00 2001 From: Chen Zhou Date: Fri, 27 Dec 2019 19:48:11 +0800 Subject: [PATCH 18/38] drm/gma500: remove set but not used variables 'hist_reg' Fixes gcc '-Wunused-but-set-variable' warning: drivers/gpu/drm/gma500/psb_irq.c: In function psb_irq_turn_off_dpst: drivers/gpu/drm/gma500/psb_irq.c:473:6: warning: variable hist_reg set but not used [-Wunused-but-set-variable] Reported-by: Hulk Robot Signed-off-by: Chen Zhou Signed-off-by: Patrik Jakobsson Link: https://patchwork.freedesktop.org/patch/msgid/20191227114811.14907-1-chenzhou10@huawei.com --- drivers/gpu/drm/gma500/psb_irq.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/gma500/psb_irq.c b/drivers/gpu/drm/gma500/psb_irq.c index 40a37e400b02..91f90016dba9 100644 --- a/drivers/gpu/drm/gma500/psb_irq.c +++ b/drivers/gpu/drm/gma500/psb_irq.c @@ -470,12 +470,11 @@ void psb_irq_turn_off_dpst(struct drm_device *dev) { struct drm_psb_private *dev_priv = (struct drm_psb_private *) dev->dev_private; - u32 hist_reg; u32 pwm_reg; if (gma_power_begin(dev, false)) { PSB_WVDC32(0x00000000, HISTOGRAM_INT_CONTROL); - hist_reg = PSB_RVDC32(HISTOGRAM_INT_CONTROL); + PSB_RVDC32(HISTOGRAM_INT_CONTROL); psb_disable_pipestat(dev_priv, 0, PIPE_DPST_EVENT_ENABLE); From 50b81d77be31a95ba036e6403b921dc918328956 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 7 Jan 2020 22:46:37 +0100 Subject: [PATCH 19/38] drm: meson: fix address type confusion Casting a pointer to dma_addr_t produces a warning: drivers/gpu/drm/meson/meson_rdma.c: In function 'meson_rdma_free': drivers/gpu/drm/meson/meson_rdma.c:59:25: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast] priv->rdma.addr_phys = (dma_addr_t)NULL; In this case, it's worse because the variable name has the suffix '_phys', which often indicates a phys_addr_t rather than dma_addr_t, i.e. yet another incompatible type. Change it to use consistent naming and avoid NULL. Fixes: 63fba242c464 ("drm/meson: add RDMA module driver") Signed-off-by: Arnd Bergmann Acked-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20200107214653.1173199-1-arnd@arndb.de --- drivers/gpu/drm/meson/meson_drv.h | 2 +- drivers/gpu/drm/meson/meson_rdma.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h index f9a0c8e9d4d0..04fdf3826643 100644 --- a/drivers/gpu/drm/meson/meson_drv.h +++ b/drivers/gpu/drm/meson/meson_drv.h @@ -135,7 +135,7 @@ struct meson_drm { } venc; struct { - dma_addr_t addr_phys; + dma_addr_t addr_dma; uint32_t *addr; unsigned int offset; } rdma; diff --git a/drivers/gpu/drm/meson/meson_rdma.c b/drivers/gpu/drm/meson/meson_rdma.c index 25b34b1e72a7..130382178c63 100644 --- a/drivers/gpu/drm/meson/meson_rdma.c +++ b/drivers/gpu/drm/meson/meson_rdma.c @@ -27,7 +27,7 @@ int meson_rdma_init(struct meson_drm *priv) /* Allocate a PAGE buffer */ priv->rdma.addr = dma_alloc_coherent(priv->dev, SZ_4K, - &priv->rdma.addr_phys, + &priv->rdma.addr_dma, GFP_KERNEL); if (!priv->rdma.addr) return -ENOMEM; @@ -47,16 +47,16 @@ int meson_rdma_init(struct meson_drm *priv) void meson_rdma_free(struct meson_drm *priv) { - if (!priv->rdma.addr && !priv->rdma.addr_phys) + if (!priv->rdma.addr && !priv->rdma.addr_dma) return; meson_rdma_stop(priv); dma_free_coherent(priv->dev, SZ_4K, - priv->rdma.addr, priv->rdma.addr_phys); + priv->rdma.addr, priv->rdma.addr_dma); priv->rdma.addr = NULL; - priv->rdma.addr_phys = (dma_addr_t)NULL; + priv->rdma.addr_dma = (dma_addr_t)0; } void meson_rdma_setup(struct meson_drm *priv) @@ -118,11 +118,11 @@ void meson_rdma_flush(struct meson_drm *priv) meson_rdma_stop(priv); /* Start of Channel 1 register writes buffer */ - writel(priv->rdma.addr_phys, + writel(priv->rdma.addr_dma, priv->io_base + _REG(RDMA_AHB_START_ADDR_1)); /* Last byte on Channel 1 register writes buffer */ - writel(priv->rdma.addr_phys + (priv->rdma.offset * RDMA_DESC_SIZE) - 1, + writel(priv->rdma.addr_dma + (priv->rdma.offset * RDMA_DESC_SIZE) - 1, priv->io_base + _REG(RDMA_AHB_END_ADDR_1)); /* Trigger Channel 1 on VSYNC event */ From 8b185cf7ebaa1f390ba25368ce9ae387eb1a8b63 Mon Sep 17 00:00:00 2001 From: Wambui Karuga Date: Thu, 2 Jan 2020 12:55:15 +0300 Subject: [PATCH 20/38] drm/omapdrm: use BUG_ON macro for error debugging. Since the if statement only checks for the value of the `id` variable, it can be replaced by the more concise BUG_ON() macro for error reporting. Issue found using coccinelle. Signed-off-by: Wambui Karuga Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20200102095515.7106-1-wambui.karugax@gmail.com --- drivers/gpu/drm/omapdrm/dss/dispc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index 413dbdd1771e..dbb90f2d2ccd 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -393,8 +393,7 @@ static void dispc_get_reg_field(struct dispc_device *dispc, enum dispc_feat_reg_field id, u8 *start, u8 *end) { - if (id >= dispc->feat->num_reg_fields) - BUG(); + BUG_ON(id >= dispc->feat->num_reg_fields); *start = dispc->feat->reg_fields[id].start; *end = dispc->feat->reg_fields[id].end; From 5b99cad6966b92f757863ff9b6688051633fde9a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 8 Jan 2020 08:43:12 +0300 Subject: [PATCH 21/38] gpu/drm: clean up white space in drm_legacy_lock_master_cleanup() We moved this code to a different file and accidentally deleted a newline. Signed-off-by: Dan Carpenter Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20200108054312.yzlj5wmbdktejgob@kili.mountain --- drivers/gpu/drm/drm_lock.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_lock.c b/drivers/gpu/drm/drm_lock.c index 2e8ce99d0baa..2c79e8199e3c 100644 --- a/drivers/gpu/drm/drm_lock.c +++ b/drivers/gpu/drm/drm_lock.c @@ -360,7 +360,8 @@ void drm_legacy_lock_master_cleanup(struct drm_device *dev, struct drm_master *m /* * Since the master is disappearing, so is the * possibility to lock. - */ mutex_lock(&dev->struct_mutex); + */ + mutex_lock(&dev->struct_mutex); if (master->lock.hw_lock) { if (dev->sigdata.lock == master->lock.hw_lock) dev->sigdata.lock = NULL; From 6ab2b3d9dc602230624afa8170f746c59d7fabde Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Thu, 2 Jan 2020 11:17:11 +0100 Subject: [PATCH 22/38] dt-bindings: one binding file for all simple panels There is an increasing number of new simple panels. Common for many of these simple panels are that they have one mandatory power-supply and some of them have backlight and / or an enable gpio. The binding file to describe these panels adds overhead that really do not add value. The binding are known and there is nothing gained from a dedicated binding file nor for any dedicated example. The following patch introduces a single panel-simple.yaml and converts two ampire bindings over to the new file. The conversion - if applied will have following effects: - The maintainer for the individual file will change There is no need for many different maintainers for a simple binding. We have the same situation with the panel-simple driver in the kernel. - The license will change to (GPL-2.0-only OR BSD-2-Clause) There is usually only a single line copied from the original file, a line that is often copied from a datasheet. This license change should be acceptable considered what little is copied. If the license change is not OK we can use a dedicated binding file in these cases. This is a follow-up on Rob's big patch converting a lot of panel bindings to individual files: "dt-bindings: display: Convert a bunch of panels to DT schema" https://patchwork.ozlabs.org/patch/1197683/ The objectives with one file for the relevant simple panels are: - Make it simpler to add bindings for simple panels - Keep the number of bindings file lower and thus easier to find a relevant file to copy from when adding new panels. - Keep the binding documentation for simple panels more consistent - Make it simpler to add support for new panels v3: - Whitespace fix (checkpatch) - Indent compatible (Rob h) - Indent comments to give compatible more visibility (Rob h) v2: - spelling fixes (imirkin via irc, Rob) - updated description (Rob) - list properires in alphabetical order - added power-supply to example (Rob) - updated title - reworded changelog a little Signed-off-by: Sam Ravnborg Reviewed-by: Rob Herring Benjamin Gaignard Cc: Thierry Reding Cc: Maxime Ripard Cc: Yannick Fertre Cc: Mark Rutland Cc: Daniel Vetter Cc: dri-devel@lists.freedesktop.org Cc: devicetree@vger.kernel.org Link: https://patchwork.freedesktop.org/patch/msgid/20200102101712.5085-2-sam@ravnborg.org --- .../panel/ampire,am-480272h3tmqw-t01h.yaml | 42 ------------- .../panel/ampire,am800480r3tmqwa1h.txt | 7 --- .../bindings/display/panel/panel-simple.yaml | 59 +++++++++++++++++++ 3 files changed, 59 insertions(+), 49 deletions(-) delete mode 100644 Documentation/devicetree/bindings/display/panel/ampire,am-480272h3tmqw-t01h.yaml delete mode 100644 Documentation/devicetree/bindings/display/panel/ampire,am800480r3tmqwa1h.txt create mode 100644 Documentation/devicetree/bindings/display/panel/panel-simple.yaml diff --git a/Documentation/devicetree/bindings/display/panel/ampire,am-480272h3tmqw-t01h.yaml b/Documentation/devicetree/bindings/display/panel/ampire,am-480272h3tmqw-t01h.yaml deleted file mode 100644 index c6e33e7f36d0..000000000000 --- a/Documentation/devicetree/bindings/display/panel/ampire,am-480272h3tmqw-t01h.yaml +++ /dev/null @@ -1,42 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/display/panel/ampire,am-480272h3tmqw-t01h.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Ampire AM-480272H3TMQW-T01H 4.3" WQVGA TFT LCD panel - -maintainers: - - Yannick Fertre - - Thierry Reding - -allOf: - - $ref: panel-common.yaml# - -properties: - compatible: - const: ampire,am-480272h3tmqw-t01h - - power-supply: true - enable-gpios: true - backlight: true - port: true - -required: - - compatible - -additionalProperties: false - -examples: - - | - panel_rgb: panel { - compatible = "ampire,am-480272h3tmqw-t01h"; - enable-gpios = <&gpioa 8 1>; - port { - panel_in_rgb: endpoint { - remote-endpoint = <&controller_out_rgb>; - }; - }; - }; - -... diff --git a/Documentation/devicetree/bindings/display/panel/ampire,am800480r3tmqwa1h.txt b/Documentation/devicetree/bindings/display/panel/ampire,am800480r3tmqwa1h.txt deleted file mode 100644 index 83e2cae1cc1b..000000000000 --- a/Documentation/devicetree/bindings/display/panel/ampire,am800480r3tmqwa1h.txt +++ /dev/null @@ -1,7 +0,0 @@ -Ampire AM-800480R3TMQW-A1H 7.0" WVGA TFT LCD panel - -Required properties: -- compatible: should be "ampire,am800480r3tmqwa1h" - -This binding is compatible with the simple-panel binding, which is specified -in simple-panel.txt in this directory. diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml new file mode 100644 index 000000000000..090866260f4f --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/panel-simple.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Simple panels with one power supply + +maintainers: + - Thierry Reding + - Sam Ravnborg + +description: | + This binding file is a collection of the simple (dumb) panels that + requires only a single power-supply. + There are optionally a backlight and an enable GPIO. + The panel may use an OF graph binding for the association to the display, + or it may be a direct child node of the display. + + If the panel is more advanced a dedicated binding file is required. + +allOf: + - $ref: panel-common.yaml# + +properties: + + compatible: + enum: + # compatible must be listed in alphabetical order, ordered by compatible. + # The description in the comment is mandatory for each compatible. + + # Ampire AM-480272H3TMQW-T01H 4.3" WQVGA TFT LCD panel + - ampire,am-480272h3tmqw-t01h + # Ampire AM-800480R3TMQW-A1H 7.0" WVGA TFT LCD panel + - ampire,am800480r3tmqwa1h + + backlight: true + enable-gpios: true + port: true + power-supply: true + +additionalProperties: false + +required: + - compatible + - power-supply + +examples: + - | + panel_rgb: panel-rgb { + compatible = "ampire,am-480272h3tmqw-t01h"; + power-supply = <&vcc_lcd_reg>; + + port { + panel_in_rgb: endpoint { + remote-endpoint = <<dc_out_rgb>; + }; + }; + }; From c00481d072506b471102e485d8b8bf324b11efdc Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 6 Jan 2020 16:18:25 +0100 Subject: [PATCH 23/38] dt-bindings: Add vendor prefix for Satoz Satoz is a Chinese TFT manufacturer. Website: http://www.sat-sz.com/English/index.html Signed-off-by: Miquel Raynal Acked-by: Rob Herring Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20200106151827.31511-1-miquel.raynal@bootlin.com --- Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 4e6248ec5ed9..835579edc971 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -825,6 +825,8 @@ patternProperties: description: Sancloud Ltd "^sandisk,.*": description: Sandisk Corporation + "^satoz,.*": + description: Satoz International Co., Ltd "^sbs,.*": description: Smart Battery System "^schindler,.*": From eb0201e600311b07a7593f0794b3801e26dba589 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 8 Jan 2020 15:53:55 -0800 Subject: [PATCH 24/38] dt-bindings: display: panel: Add AUO B116XAK01 panel bindings Signed-off-by: Rob Clark Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20200108235356.918189-1-robdclark@gmail.com --- .../devicetree/bindings/display/panel/panel-simple.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml index 090866260f4f..5f1d765447bc 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml @@ -33,6 +33,8 @@ properties: - ampire,am-480272h3tmqw-t01h # Ampire AM-800480R3TMQW-A1H 7.0" WVGA TFT LCD panel - ampire,am800480r3tmqwa1h + # AUO B116XAK01 eDP TFT LCD panel + - auo,b116xa01 backlight: true enable-gpios: true From da458286a5e288ad18500f89ae28cbbc7512b3e1 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 8 Jan 2020 15:53:56 -0800 Subject: [PATCH 25/38] drm/panel: Add support for AUO B116XAK01 panel Signed-off-by: Rob Clark Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20200108235356.918189-2-robdclark@gmail.com --- drivers/gpu/drm/panel/panel-simple.c | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index ba3f85f36c2f..0c3444c62014 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -629,6 +629,35 @@ static const struct panel_desc auo_b101xtn01 = { }, }; +static const struct drm_display_mode auo_b116xak01_mode = { + .clock = 69300, + .hdisplay = 1366, + .hsync_start = 1366 + 48, + .hsync_end = 1366 + 48 + 32, + .htotal = 1366 + 48 + 32 + 10, + .vdisplay = 768, + .vsync_start = 768 + 4, + .vsync_end = 768 + 4 + 6, + .vtotal = 768 + 4 + 6 + 15, + .vrefresh = 60, + .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, +}; + +static const struct panel_desc auo_b116xak01 = { + .modes = &auo_b116xak01_mode, + .num_modes = 1, + .bpc = 6, + .size = { + .width = 256, + .height = 144, + }, + .delay = { + .hpd_absent_delay = 200, + }, + .bus_format = MEDIA_BUS_FMT_RGB666_1X18, + .connector_type = DRM_MODE_CONNECTOR_eDP, +}; + static const struct drm_display_mode auo_b116xw03_mode = { .clock = 70589, .hdisplay = 1366, @@ -3125,6 +3154,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "auo,b101xtn01", .data = &auo_b101xtn01, + }, { + .compatible = "auo,b116xa01", + .data = &auo_b116xak01, }, { .compatible = "auo,b116xw03", .data = &auo_b116xw03, From 5c544dafc0722daa41b57cbd7c245186645474d5 Mon Sep 17 00:00:00 2001 From: Qiang Yu Date: Wed, 1 Jan 2020 18:38:31 +0800 Subject: [PATCH 26/38] drm/lima: use drm_sched_fault for error task handling drm_sched_job_timedout works with drm_sched_stop as a pair, so we'd better use the drm_sched_fault helper to make the error and timeout handling go the same path. This also fixes application hang when task error. Reviewed-by: Vasily Khoruzhick Tested-by: Andreas Baierl Signed-off-by: Qiang Yu Link: https://patchwork.freedesktop.org/patch/msgid/20200101103831.22429-1-yuq825@gmail.com --- drivers/gpu/drm/lima/lima_sched.c | 35 ++++++++----------------------- drivers/gpu/drm/lima/lima_sched.h | 2 -- 2 files changed, 9 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c index f522c5f99729..a31a90c380b6 100644 --- a/drivers/gpu/drm/lima/lima_sched.c +++ b/drivers/gpu/drm/lima/lima_sched.c @@ -255,13 +255,17 @@ static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job) return task->fence; } -static void lima_sched_handle_error_task(struct lima_sched_pipe *pipe, - struct lima_sched_task *task) +static void lima_sched_timedout_job(struct drm_sched_job *job) { + struct lima_sched_pipe *pipe = to_lima_pipe(job->sched); + struct lima_sched_task *task = to_lima_task(job); + + if (!pipe->error) + DRM_ERROR("lima job timeout\n"); + drm_sched_stop(&pipe->base, &task->base); - if (task) - drm_sched_increase_karma(&task->base); + drm_sched_increase_karma(&task->base); pipe->task_error(pipe); @@ -284,16 +288,6 @@ static void lima_sched_handle_error_task(struct lima_sched_pipe *pipe, drm_sched_start(&pipe->base, true); } -static void lima_sched_timedout_job(struct drm_sched_job *job) -{ - struct lima_sched_pipe *pipe = to_lima_pipe(job->sched); - struct lima_sched_task *task = to_lima_task(job); - - DRM_ERROR("lima job timeout\n"); - - lima_sched_handle_error_task(pipe, task); -} - static void lima_sched_free_job(struct drm_sched_job *job) { struct lima_sched_task *task = to_lima_task(job); @@ -318,15 +312,6 @@ static const struct drm_sched_backend_ops lima_sched_ops = { .free_job = lima_sched_free_job, }; -static void lima_sched_error_work(struct work_struct *work) -{ - struct lima_sched_pipe *pipe = - container_of(work, struct lima_sched_pipe, error_work); - struct lima_sched_task *task = pipe->current_task; - - lima_sched_handle_error_task(pipe, task); -} - int lima_sched_pipe_init(struct lima_sched_pipe *pipe, const char *name) { unsigned int timeout = lima_sched_timeout_ms > 0 ? @@ -335,8 +320,6 @@ int lima_sched_pipe_init(struct lima_sched_pipe *pipe, const char *name) pipe->fence_context = dma_fence_context_alloc(1); spin_lock_init(&pipe->fence_lock); - INIT_WORK(&pipe->error_work, lima_sched_error_work); - return drm_sched_init(&pipe->base, &lima_sched_ops, 1, 0, msecs_to_jiffies(timeout), name); } @@ -349,7 +332,7 @@ void lima_sched_pipe_fini(struct lima_sched_pipe *pipe) void lima_sched_pipe_task_done(struct lima_sched_pipe *pipe) { if (pipe->error) - schedule_work(&pipe->error_work); + drm_sched_fault(&pipe->base); else { struct lima_sched_task *task = pipe->current_task; diff --git a/drivers/gpu/drm/lima/lima_sched.h b/drivers/gpu/drm/lima/lima_sched.h index 928af91c1118..1d814fecbcc0 100644 --- a/drivers/gpu/drm/lima/lima_sched.h +++ b/drivers/gpu/drm/lima/lima_sched.h @@ -68,8 +68,6 @@ struct lima_sched_pipe { void (*task_fini)(struct lima_sched_pipe *pipe); void (*task_error)(struct lima_sched_pipe *pipe); void (*task_mmu_error)(struct lima_sched_pipe *pipe); - - struct work_struct error_work; }; int lima_sched_task_init(struct lima_sched_task *task, From 2ae4829d222e9ad066b1bcbdabefc3e5d039d46c Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 8 Jan 2020 21:29:59 -0300 Subject: [PATCH 27/38] dt-bindings: panel-simple: Add compatible for GiantPlus GPM940B0 Add a compatible string for the GiantPlus GPM740B0 3" QVGA TFT LCD panel, and remove the old giantplus,gpm740b0.txt documentation which is now obsolete. Signed-off-by: Paul Cercueil Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20200109003000.119516-1-paul@crapouillou.net --- .../bindings/display/panel/giantplus,gpm940b0.txt | 12 ------------ .../bindings/display/panel/panel-simple.yaml | 2 ++ 2 files changed, 2 insertions(+), 12 deletions(-) delete mode 100644 Documentation/devicetree/bindings/display/panel/giantplus,gpm940b0.txt diff --git a/Documentation/devicetree/bindings/display/panel/giantplus,gpm940b0.txt b/Documentation/devicetree/bindings/display/panel/giantplus,gpm940b0.txt deleted file mode 100644 index 3dab52f92c26..000000000000 --- a/Documentation/devicetree/bindings/display/panel/giantplus,gpm940b0.txt +++ /dev/null @@ -1,12 +0,0 @@ -GiantPlus 3.0" (320x240 pixels) 24-bit TFT LCD panel - -Required properties: -- compatible: should be "giantplus,gpm940b0" -- power-supply: as specified in the base binding - -Optional properties: -- backlight: as specified in the base binding -- enable-gpios: as specified in the base binding - -This binding is compatible with the simple-panel binding, which is specified -in simple-panel.txt in this directory. diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml index 5f1d765447bc..cbcd3d7e4591 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml @@ -35,6 +35,8 @@ properties: - ampire,am800480r3tmqwa1h # AUO B116XAK01 eDP TFT LCD panel - auo,b116xa01 + # GiantPlus GPM940B0 3.0" QVGA TFT LCD panel + - giantplus,gpm940b0 backlight: true enable-gpios: true From 240a25720925b5033a27863fb051a2c384a4dd64 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 8 Jan 2020 21:30:00 -0300 Subject: [PATCH 28/38] dt-bindings: panel-simple: Add compatible for Sharp LS020B1DD01D Add a compatible string for the Sharp LS020B1DD01D 2" HQVGA TFT LCD panel, and remove the old sharp,ls020b1dd01d.txt documentation which is now obsolete. Signed-off-by: Paul Cercueil Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20200109003000.119516-2-paul@crapouillou.net --- .../bindings/display/panel/panel-simple.yaml | 2 ++ .../bindings/display/panel/sharp,ls020b1dd01d.txt | 12 ------------ 2 files changed, 2 insertions(+), 12 deletions(-) delete mode 100644 Documentation/devicetree/bindings/display/panel/sharp,ls020b1dd01d.txt diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml index cbcd3d7e4591..ddc00480b6fe 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml @@ -37,6 +37,8 @@ properties: - auo,b116xa01 # GiantPlus GPM940B0 3.0" QVGA TFT LCD panel - giantplus,gpm940b0 + # Sharp LS020B1DD01D 2.0" HQVGA TFT LCD panel + - sharp,ls020b1dd01d backlight: true enable-gpios: true diff --git a/Documentation/devicetree/bindings/display/panel/sharp,ls020b1dd01d.txt b/Documentation/devicetree/bindings/display/panel/sharp,ls020b1dd01d.txt deleted file mode 100644 index e45edbc565a3..000000000000 --- a/Documentation/devicetree/bindings/display/panel/sharp,ls020b1dd01d.txt +++ /dev/null @@ -1,12 +0,0 @@ -Sharp 2.0" (240x160 pixels) 16-bit TFT LCD panel - -Required properties: -- compatible: should be "sharp,ls020b1dd01d" -- power-supply: as specified in the base binding - -Optional properties: -- backlight: as specified in the base binding -- enable-gpios: as specified in the base binding - -This binding is compatible with the simple-panel binding, which is specified -in simple-panel.txt in this directory. From 539bbf31887ececa50532ccfc5086f0c18818601 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 6 Dec 2019 12:26:08 +0100 Subject: [PATCH 29/38] drm/Kconfig: add missing 'depends on DRM' for DRM_DP_CEC Add a missing 'depends on DRM' for the DRM_DP_CEC config option. Without that enabling DRM_DP_CEC will force CEC_CORE to =y instead of =m if DRM=m as well. Signed-off-by: Hans Verkuil Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/489bdaae-9b05-2d70-12e1-4fda7899dfc1@xs4all.nl --- drivers/gpu/drm/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 7041323a7bff..d0aa6cff2e02 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -168,6 +168,7 @@ config DRM_LOAD_EDID_FIRMWARE config DRM_DP_CEC bool "Enable DisplayPort CEC-Tunneling-over-AUX HDMI support" + depends on DRM select CEC_CORE help Choose this option if you want to enable HDMI CEC support for From 5d50bd440bc2ff815e9837e4a270fd0c5f3c6f73 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 6 Jan 2020 15:10:16 +0100 Subject: [PATCH 30/38] drm/udl: Make udl driver depend on CONFIG_USB The udl driver for DisplayLink devices depends on support for host-side USB controllers, which is enabled with CONFIG_USB. Plain USB support as given by CONFIG_USB_SUPPORT is not sufficient. This patch changes dependencies for udl to depend on CONFIG_USB, instead of CONFIG_USB_SUPPORT. Users will have to enable CONFIG_USB and select a USB host controller. With this change udl dependencies work the same way as dependencies for PCI drivers. Signed-off-by: Thomas Zimmermann Acked-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20200106141016.9562-1-tzimmermann@suse.de --- drivers/gpu/drm/udl/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/udl/Kconfig b/drivers/gpu/drm/udl/Kconfig index 065974bf010e..1f497d8f1ae5 100644 --- a/drivers/gpu/drm/udl/Kconfig +++ b/drivers/gpu/drm/udl/Kconfig @@ -2,9 +2,8 @@ config DRM_UDL tristate "DisplayLink" depends on DRM - depends on USB_SUPPORT + depends on USB depends on USB_ARCH_HAS_HCD - select USB select DRM_GEM_SHMEM_HELPER select DRM_KMS_HELPER help From 8152c2bfd780398773435bf6eb1e3841f83de209 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 9 Jan 2020 08:28:15 +0100 Subject: [PATCH 31/38] drm/panel: Add driver for Sony ACX424AKP panel The Sony ACX424AKP is a command/videomode DSI panel for mobile devices. It is used on the ST-Ericsson HREF520 reference design. We support video mode by default, but it is possible to switch the panel into command mode by using the bool property "dsi-command-mode". Cc: Stephan Gerhold Signed-off-by: Linus Walleij Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20200109072815.334867-1-linus.walleij@linaro.org --- MAINTAINERS | 6 + drivers/gpu/drm/panel/Kconfig | 11 + drivers/gpu/drm/panel/Makefile | 1 + drivers/gpu/drm/panel/panel-sony-acx424akp.c | 550 +++++++++++++++++++ 4 files changed, 568 insertions(+) create mode 100644 drivers/gpu/drm/panel/panel-sony-acx424akp.c diff --git a/MAINTAINERS b/MAINTAINERS index bfebe689ea7e..aa9add598b7d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5357,6 +5357,12 @@ S: Maintained F: drivers/gpu/drm/tiny/st7735r.c F: Documentation/devicetree/bindings/display/sitronix,st7735r.txt +DRM DRIVER FOR SONY ACX424AKP PANELS +M: Linus Walleij +T: git git://anongit.freedesktop.org/drm/drm-misc +S: Maintained +F: drivers/gpu/drm/panel/panel-sony-acx424akp.c + DRM DRIVER FOR ST-ERICSSON MCDE M: Linus Walleij T: git git://anongit.freedesktop.org/drm/drm-misc diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 41f796b28dd5..ae44ac2ec106 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -338,6 +338,17 @@ config DRM_PANEL_SITRONIX_ST7789V Say Y here if you want to enable support for the Sitronix ST7789V controller for 240x320 LCD panels +config DRM_PANEL_SONY_ACX424AKP + tristate "Sony ACX424AKP DSI command mode panel" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + select VIDEOMODE_HELPERS + help + Say Y here if you want to enable the Sony ACX424 display + panel. This panel supports DSI in both command and video + mode. + config DRM_PANEL_SONY_ACX565AKM tristate "Sony ACX565AKM panel" depends on GPIOLIB && OF && SPI diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 4dc7acff21b9..7c4d3c581fd4 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_DRM_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7701) += panel-sitronix-st7701.o obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o +obj-$(CONFIG_DRM_PANEL_SONY_ACX424AKP) += panel-sony-acx424akp.o obj-$(CONFIG_DRM_PANEL_SONY_ACX565AKM) += panel-sony-acx565akm.o obj-$(CONFIG_DRM_PANEL_TPO_TD028TTEC1) += panel-tpo-td028ttec1.o obj-$(CONFIG_DRM_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o diff --git a/drivers/gpu/drm/panel/panel-sony-acx424akp.c b/drivers/gpu/drm/panel/panel-sony-acx424akp.c new file mode 100644 index 000000000000..de0abf76ae6f --- /dev/null +++ b/drivers/gpu/drm/panel/panel-sony-acx424akp.c @@ -0,0 +1,550 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * MIPI-DSI Sony ACX424AKP panel driver. This is a 480x864 + * AMOLED panel with a command-only DSI interface. + * + * Copyright (C) Linaro Ltd. 2019 + * Author: Linus Walleij + * Based on code and know-how from Marcus Lorentzon + * Copyright (C) ST-Ericsson SA 2010 + */ +#include +#include +#include +#include +#include +#include + +#include