From f0d2e86c1b9ecd9cbe967b94e2f0d197f30cb3e7 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 27 Sep 2017 10:35:31 +0200 Subject: drm/atomic: Remove unneeded null check for private objects It can be seen in drm_atomic_get_private_obj_state() that ptr will never be NULL, so skip the check for that case. Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/20170927083532.5756-1-maarten.lankhorst@linux.intel.com Reviewed-by: Daniel Vetter --- include/drm/drm_atomic.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'include/drm') diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 5834580d75bc..6fae95f28e10 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -768,8 +768,7 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); ((obj) = (__state)->private_objs[__i].ptr, \ (old_obj_state) = (__state)->private_objs[__i].old_state, \ (new_obj_state) = (__state)->private_objs[__i].new_state, 1); \ - (__i)++) \ - for_each_if (obj) + (__i)++) /** * for_each_old_private_obj_in_state - iterate over all private objects in an atomic update @@ -787,8 +786,7 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i) < (__state)->num_private_objs && \ ((obj) = (__state)->private_objs[__i].ptr, \ (old_obj_state) = (__state)->private_objs[__i].old_state, 1); \ - (__i)++) \ - for_each_if (obj) + (__i)++) /** * for_each_new_private_obj_in_state - iterate over all private objects in an atomic update @@ -806,8 +804,7 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i) < (__state)->num_private_objs && \ ((obj) = (__state)->private_objs[__i].ptr, \ (new_obj_state) = (__state)->private_objs[__i].new_state, 1); \ - (__i)++) \ - for_each_if (obj) + (__i)++) /** * drm_atomic_crtc_needs_modeset - compute combined modeset need -- cgit v1.2.3 From 331494eb51002d0ee99414e3918e06d5e9a3962d Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 27 Sep 2017 10:35:32 +0200 Subject: drm/atomic: Make atomic iterators less surprising Commit 669c9215afea ("drm/atomic: Make async plane update checks work as intended, v2.") assumed incorrectly that if only 1 plane is matched in the loop, the variables will be set to that plane. In reality we reset them to NULL every time a new plane was iterated. This behavior is surprising, so fix this by making the for loops only assign the variables on a match. When we have not added all the planes/crtc/connector to the state, and there's a few NULL ones after the last one we iterated, te assumption is broken that the pointers will hold the values from the last loop iteration, which holds true for all other for_each macros we're using. Except of course the iterator pointer itself, but that one really is entirely internal. Cc: Dmitry Osipenko Fixes: 669c9215afea ("drm/atomic: Make async plane update checks work as intended, v2.") Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/20170927083532.5756-2-maarten.lankhorst@linux.intel.com Reviewed-by: Daniel Vetter Tested-by: Dmitry Osipenko --- include/drm/drm_atomic.h | 85 ++++++++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 43 deletions(-) (limited to 'include/drm') diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 6fae95f28e10..5afd6e364fb6 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -585,12 +585,12 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); */ #define for_each_oldnew_connector_in_state(__state, connector, old_connector_state, new_connector_state, __i) \ for ((__i) = 0; \ - (__i) < (__state)->num_connector && \ - ((connector) = (__state)->connectors[__i].ptr, \ - (old_connector_state) = (__state)->connectors[__i].old_state, \ - (new_connector_state) = (__state)->connectors[__i].new_state, 1); \ - (__i)++) \ - for_each_if (connector) + (__i) < (__state)->num_connector; \ + (__i)++) \ + for_each_if ((__state)->connectors[__i].ptr && \ + ((connector) = (__state)->connectors[__i].ptr, \ + (old_connector_state) = (__state)->connectors[__i].old_state, \ + (new_connector_state) = (__state)->connectors[__i].new_state, 1)) /** * for_each_old_connector_in_state - iterate over all connectors in an atomic update @@ -606,11 +606,11 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); */ #define for_each_old_connector_in_state(__state, connector, old_connector_state, __i) \ for ((__i) = 0; \ - (__i) < (__state)->num_connector && \ - ((connector) = (__state)->connectors[__i].ptr, \ - (old_connector_state) = (__state)->connectors[__i].old_state, 1); \ - (__i)++) \ - for_each_if (connector) + (__i) < (__state)->num_connector; \ + (__i)++) \ + for_each_if ((__state)->connectors[__i].ptr && \ + ((connector) = (__state)->connectors[__i].ptr, \ + (old_connector_state) = (__state)->connectors[__i].old_state, 1)) /** * for_each_new_connector_in_state - iterate over all connectors in an atomic update @@ -626,11 +626,11 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); */ #define for_each_new_connector_in_state(__state, connector, new_connector_state, __i) \ for ((__i) = 0; \ - (__i) < (__state)->num_connector && \ - ((connector) = (__state)->connectors[__i].ptr, \ - (new_connector_state) = (__state)->connectors[__i].new_state, 1); \ - (__i)++) \ - for_each_if (connector) + (__i) < (__state)->num_connector; \ + (__i)++) \ + for_each_if ((__state)->connectors[__i].ptr && \ + ((connector) = (__state)->connectors[__i].ptr, \ + (new_connector_state) = (__state)->connectors[__i].new_state, 1)) /** * for_each_oldnew_crtc_in_state - iterate over all CRTCs in an atomic update @@ -646,12 +646,12 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); */ #define for_each_oldnew_crtc_in_state(__state, crtc, old_crtc_state, new_crtc_state, __i) \ for ((__i) = 0; \ - (__i) < (__state)->dev->mode_config.num_crtc && \ - ((crtc) = (__state)->crtcs[__i].ptr, \ - (old_crtc_state) = (__state)->crtcs[__i].old_state, \ - (new_crtc_state) = (__state)->crtcs[__i].new_state, 1); \ + (__i) < (__state)->dev->mode_config.num_crtc; \ (__i)++) \ - for_each_if (crtc) + for_each_if ((__state)->crtcs[__i].ptr && \ + ((crtc) = (__state)->crtcs[__i].ptr, \ + (old_crtc_state) = (__state)->crtcs[__i].old_state, \ + (new_crtc_state) = (__state)->crtcs[__i].new_state, 1)) /** * for_each_old_crtc_in_state - iterate over all CRTCs in an atomic update @@ -666,11 +666,11 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); */ #define for_each_old_crtc_in_state(__state, crtc, old_crtc_state, __i) \ for ((__i) = 0; \ - (__i) < (__state)->dev->mode_config.num_crtc && \ - ((crtc) = (__state)->crtcs[__i].ptr, \ - (old_crtc_state) = (__state)->crtcs[__i].old_state, 1); \ + (__i) < (__state)->dev->mode_config.num_crtc; \ (__i)++) \ - for_each_if (crtc) + for_each_if ((__state)->crtcs[__i].ptr && \ + ((crtc) = (__state)->crtcs[__i].ptr, \ + (old_crtc_state) = (__state)->crtcs[__i].old_state, 1)) /** * for_each_new_crtc_in_state - iterate over all CRTCs in an atomic update @@ -685,11 +685,11 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); */ #define for_each_new_crtc_in_state(__state, crtc, new_crtc_state, __i) \ for ((__i) = 0; \ - (__i) < (__state)->dev->mode_config.num_crtc && \ - ((crtc) = (__state)->crtcs[__i].ptr, \ - (new_crtc_state) = (__state)->crtcs[__i].new_state, 1); \ + (__i) < (__state)->dev->mode_config.num_crtc; \ (__i)++) \ - for_each_if (crtc) + for_each_if ((__state)->crtcs[__i].ptr && \ + ((crtc) = (__state)->crtcs[__i].ptr, \ + (new_crtc_state) = (__state)->crtcs[__i].new_state, 1)) /** * for_each_oldnew_plane_in_state - iterate over all planes in an atomic update @@ -705,12 +705,12 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); */ #define for_each_oldnew_plane_in_state(__state, plane, old_plane_state, new_plane_state, __i) \ for ((__i) = 0; \ - (__i) < (__state)->dev->mode_config.num_total_plane && \ - ((plane) = (__state)->planes[__i].ptr, \ - (old_plane_state) = (__state)->planes[__i].old_state, \ - (new_plane_state) = (__state)->planes[__i].new_state, 1); \ + (__i) < (__state)->dev->mode_config.num_total_plane; \ (__i)++) \ - for_each_if (plane) + for_each_if ((__state)->planes[__i].ptr && \ + ((plane) = (__state)->planes[__i].ptr, \ + (old_plane_state) = (__state)->planes[__i].old_state,\ + (new_plane_state) = (__state)->planes[__i].new_state, 1)) /** * for_each_old_plane_in_state - iterate over all planes in an atomic update @@ -725,12 +725,11 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); */ #define for_each_old_plane_in_state(__state, plane, old_plane_state, __i) \ for ((__i) = 0; \ - (__i) < (__state)->dev->mode_config.num_total_plane && \ - ((plane) = (__state)->planes[__i].ptr, \ - (old_plane_state) = (__state)->planes[__i].old_state, 1); \ + (__i) < (__state)->dev->mode_config.num_total_plane; \ (__i)++) \ - for_each_if (plane) - + for_each_if ((__state)->planes[__i].ptr && \ + ((plane) = (__state)->planes[__i].ptr, \ + (old_plane_state) = (__state)->planes[__i].old_state, 1)) /** * for_each_new_plane_in_state - iterate over all planes in an atomic update * @__state: &struct drm_atomic_state pointer @@ -744,11 +743,11 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); */ #define for_each_new_plane_in_state(__state, plane, new_plane_state, __i) \ for ((__i) = 0; \ - (__i) < (__state)->dev->mode_config.num_total_plane && \ - ((plane) = (__state)->planes[__i].ptr, \ - (new_plane_state) = (__state)->planes[__i].new_state, 1); \ + (__i) < (__state)->dev->mode_config.num_total_plane; \ (__i)++) \ - for_each_if (plane) + for_each_if ((__state)->planes[__i].ptr && \ + ((plane) = (__state)->planes[__i].ptr, \ + (new_plane_state) = (__state)->planes[__i].new_state, 1)) /** * for_each_oldnew_private_obj_in_state - iterate over all private objects in an atomic update -- cgit v1.2.3 From c70087e8f16f1dfe703d223aadd95ede1cde8e30 Mon Sep 17 00:00:00 2001 From: "benjamin.gaignard@linaro.org" Date: Mon, 2 Oct 2017 11:34:45 +0200 Subject: drm/drm_of: add drm_of_panel_bridge_remove function This function is the pendant of drm_of_find_panel_or_bridge() to remove a previously allocated panel_bridge. Given a specific port and endpoint it remove the panel bridge. Since drm_panel_bridge_remove() will check that bridge parameter is not NULL and is a real drm_panel_bridge and no a simple bridge it is safe to call it directly. Signed-off-by: Benjamin Gaignard Reviewed-by: Philippe Cornu Tested-by: Philippe Cornu Link: https://patchwork.freedesktop.org/patch/msgid/1506936888-23844-3-git-send-email-benjamin.gaignard@linaro.org --- drivers/gpu/drm/drm_of.c | 33 +++++++++++++++++++++++++++++++++ include/drm/drm_of.h | 8 ++++++++ 2 files changed, 41 insertions(+) (limited to 'include/drm') diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c index 4c191c050e7d..7a36934ea5db 100644 --- a/drivers/gpu/drm/drm_of.c +++ b/drivers/gpu/drm/drm_of.c @@ -262,3 +262,36 @@ int drm_of_find_panel_or_bridge(const struct device_node *np, return ret; } EXPORT_SYMBOL_GPL(drm_of_find_panel_or_bridge); + +#ifdef CONFIG_DRM_PANEL_BRIDGE +/* + * drm_of_panel_bridge_remove - remove panel bridge + * @np: device tree node containing panel bridge output ports + * + * Remove the panel bridge of a given DT node's port and endpoint number + * + * Returns zero if successful, or one of the standard error codes if it fails. + */ +int drm_of_panel_bridge_remove(const struct device_node *np, + int port, int endpoint) +{ + struct drm_bridge *bridge; + struct device_node *remote; + + remote = of_graph_get_remote_node(np, port, endpoint); + if (!remote) + return -ENODEV; + + bridge = of_drm_find_bridge(remote); + drm_panel_bridge_remove(bridge); + + return 0; +} +#else +int drm_of_panel_bridge_remove(const struct device_node *np, + int port, int endpoint) +{ + return -EINVAL; +} +#endif +EXPORT_SYMBOL_GPL(drm_of_panel_bridge_remove); diff --git a/include/drm/drm_of.h b/include/drm/drm_of.h index 104dd517fdbe..390966e4a308 100644 --- a/include/drm/drm_of.h +++ b/include/drm/drm_of.h @@ -29,6 +29,8 @@ int drm_of_find_panel_or_bridge(const struct device_node *np, int port, int endpoint, struct drm_panel **panel, struct drm_bridge **bridge); +int drm_of_panel_bridge_remove(const struct device_node *np, + int port, int endpoint); #else static inline uint32_t drm_of_find_possible_crtcs(struct drm_device *dev, struct device_node *port) @@ -65,6 +67,12 @@ static inline int drm_of_find_panel_or_bridge(const struct device_node *np, { return -EINVAL; } + +static inline int drm_of_panel_bridge_remove(const struct device_node *np, + int port, int endpoint) +{ + return -EINVAL; +} #endif static inline int drm_of_encoder_active_endpoint_id(struct device_node *node, -- cgit v1.2.3 From e25f1f7c94e16d4493398300efa03e5b6c77fcbf Mon Sep 17 00:00:00 2001 From: Maciej Purski Date: Thu, 24 Aug 2017 10:58:07 +0200 Subject: drm/bridge/sii8620: add remote control support MHL specification defines Remote Control Protocol(RCP) to send input events between MHL devices. The driver now recognizes RCP messages and reacts to them by reporting key events to input subsystem, allowing a user to control a device using TV remote control. Signed-off-by: Maciej Purski Acked-by: Sean Young Acked-by: Mauro Carvalho Chehab Signed-off-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/1503565087-19730-1-git-send-email-m.purski@samsung.com --- drivers/gpu/drm/bridge/Kconfig | 2 +- drivers/gpu/drm/bridge/sil-sii8620.c | 96 ++++++++++++++++++++++++++++++++++-- include/drm/bridge/mhl.h | 4 ++ 3 files changed, 96 insertions(+), 6 deletions(-) (limited to 'include/drm') diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 9dba16fd56c3..3b99d5a06c16 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -71,7 +71,7 @@ config DRM_PARADE_PS8622 config DRM_SIL_SII8620 tristate "Silicon Image SII8620 HDMI/MHL bridge" - depends on OF + depends on OF && RC_CORE select DRM_KMS_HELPER help Silicon Image SII8620 HDMI/MHL bridge chip driver. diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c index 5131bfb94f06..b7eb704d0a8a 100644 --- a/drivers/gpu/drm/bridge/sil-sii8620.c +++ b/drivers/gpu/drm/bridge/sil-sii8620.c @@ -28,6 +28,8 @@ #include #include +#include + #include "sil-sii8620.h" #define SII8620_BURST_BUF_LEN 288 @@ -58,6 +60,7 @@ enum sii8620_mt_state { struct sii8620 { struct drm_bridge bridge; struct device *dev; + struct rc_dev *rc_dev; struct clk *clk_xtal; struct gpio_desc *gpio_reset; struct gpio_desc *gpio_int; @@ -431,6 +434,16 @@ static void sii8620_mt_rap(struct sii8620 *ctx, u8 code) sii8620_mt_msc_msg(ctx, MHL_MSC_MSG_RAP, code); } +static void sii8620_mt_rcpk(struct sii8620 *ctx, u8 code) +{ + sii8620_mt_msc_msg(ctx, MHL_MSC_MSG_RCPK, code); +} + +static void sii8620_mt_rcpe(struct sii8620 *ctx, u8 code) +{ + sii8620_mt_msc_msg(ctx, MHL_MSC_MSG_RCPE, code); +} + static void sii8620_mt_read_devcap_send(struct sii8620 *ctx, struct sii8620_mt_msg *msg) { @@ -1753,6 +1766,25 @@ static void sii8620_send_features(struct sii8620 *ctx) sii8620_write_buf(ctx, REG_MDT_XMIT_WRITE_PORT, buf, ARRAY_SIZE(buf)); } +static bool sii8620_rcp_consume(struct sii8620 *ctx, u8 scancode) +{ + bool pressed = !(scancode & MHL_RCP_KEY_RELEASED_MASK); + + scancode &= MHL_RCP_KEY_ID_MASK; + + if (!ctx->rc_dev) { + dev_dbg(ctx->dev, "RCP input device not initialized\n"); + return false; + } + + if (pressed) + rc_keydown(ctx->rc_dev, RC_PROTO_CEC, scancode, 0); + else + rc_keyup(ctx->rc_dev); + + return true; +} + static void sii8620_msc_mr_set_int(struct sii8620 *ctx) { u8 ints[MHL_INT_SIZE]; @@ -1804,19 +1836,25 @@ static void sii8620_msc_mt_done(struct sii8620 *ctx) static void sii8620_msc_mr_msc_msg(struct sii8620 *ctx) { - struct sii8620_mt_msg *msg = sii8620_msc_msg_first(ctx); + struct sii8620_mt_msg *msg; u8 buf[2]; - if (!msg) - return; - sii8620_read_buf(ctx, REG_MSC_MR_MSC_MSG_RCVD_1ST_DATA, buf, 2); switch (buf[0]) { case MHL_MSC_MSG_RAPK: + msg = sii8620_msc_msg_first(ctx); + if (!msg) + return; msg->ret = buf[1]; ctx->mt_state = MT_STATE_DONE; break; + case MHL_MSC_MSG_RCP: + if (!sii8620_rcp_consume(ctx, buf[1])) + sii8620_mt_rcpe(ctx, + MHL_RCPE_STATUS_INEFFECTIVE_KEY_CODE); + sii8620_mt_rcpk(ctx, buf[1]); + break; default: dev_err(ctx->dev, "%s message type %d,%d not supported", __func__, buf[0], buf[1]); @@ -2102,11 +2140,57 @@ static void sii8620_cable_in(struct sii8620 *ctx) enable_irq(to_i2c_client(ctx->dev)->irq); } +static void sii8620_init_rcp_input_dev(struct sii8620 *ctx) +{ + struct rc_dev *rc_dev; + int ret; + + rc_dev = rc_allocate_device(RC_DRIVER_SCANCODE); + if (!rc_dev) { + dev_err(ctx->dev, "Failed to allocate RC device\n"); + ctx->error = -ENOMEM; + return; + } + + rc_dev->input_phys = "sii8620/input0"; + rc_dev->input_id.bustype = BUS_VIRTUAL; + rc_dev->map_name = RC_MAP_CEC; + rc_dev->allowed_protocols = RC_PROTO_BIT_CEC; + rc_dev->driver_name = "sii8620"; + rc_dev->device_name = "sii8620"; + + ret = rc_register_device(rc_dev); + + if (ret) { + dev_err(ctx->dev, "Failed to register RC device\n"); + ctx->error = ret; + rc_free_device(ctx->rc_dev); + return; + } + ctx->rc_dev = rc_dev; +} + static inline struct sii8620 *bridge_to_sii8620(struct drm_bridge *bridge) { return container_of(bridge, struct sii8620, bridge); } +static int sii8620_attach(struct drm_bridge *bridge) +{ + struct sii8620 *ctx = bridge_to_sii8620(bridge); + + sii8620_init_rcp_input_dev(ctx); + + return sii8620_clear_error(ctx); +} + +static void sii8620_detach(struct drm_bridge *bridge) +{ + struct sii8620 *ctx = bridge_to_sii8620(bridge); + + rc_unregister_device(ctx->rc_dev); +} + static bool sii8620_mode_fixup(struct drm_bridge *bridge, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -2151,6 +2235,8 @@ end: } static const struct drm_bridge_funcs sii8620_bridge_funcs = { + .attach = sii8620_attach, + .detach = sii8620_detach, .mode_fixup = sii8620_mode_fixup, }; @@ -2217,8 +2303,8 @@ static int sii8620_remove(struct i2c_client *client) struct sii8620 *ctx = i2c_get_clientdata(client); disable_irq(to_i2c_client(ctx->dev)->irq); - drm_bridge_remove(&ctx->bridge); sii8620_hw_off(ctx); + drm_bridge_remove(&ctx->bridge); return 0; } diff --git a/include/drm/bridge/mhl.h b/include/drm/bridge/mhl.h index fbdfc8d7f3c7..96a5e0f6ff12 100644 --- a/include/drm/bridge/mhl.h +++ b/include/drm/bridge/mhl.h @@ -262,6 +262,10 @@ enum { #define MHL_RAPK_UNSUPPORTED 0x02 /* Rcvd RAP action code not supported */ #define MHL_RAPK_BUSY 0x03 /* Responder too busy to respond */ +/* Bit masks for RCP messages */ +#define MHL_RCP_KEY_RELEASED_MASK 0x80 +#define MHL_RCP_KEY_ID_MASK 0x7F + /* * Error status codes for RCPE messages */ -- cgit v1.2.3