From a5a84fe29fa01c0f59fee5ef69c2b9418771952e Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Thu, 7 Mar 2024 11:56:25 -0500 Subject: [PATCH] Fixes for 6.7 Signed-off-by: Sasha Levin --- ...dma-correct-max_segment_size-setting.patch | 66 +++++ ...ma-utilize-common-dt-binding-header-.patch | 69 +++++ ...bridge-add-transparent-bridge-helper.patch | 233 ++++++++++++++++ ...pd-separate-allocation-and-registrat.patch | 175 ++++++++++++ ...idge-implement-generic-dp-hpd-bridge.patch | 262 ++++++++++++++++++ ...fsl-edma-add-fsl-edma.h-to-prevent-h.patch | 57 ++++ queue-6.7/series | 8 + ...c-glink-switch-to-drm_aux_hpd_bridge.patch | 111 ++++++++ ...ink_altmode-fix-drm-bridge-use-after.patch | 123 ++++++++ 9 files changed, 1104 insertions(+) create mode 100644 queue-6.7/dmaengine-fsl-edma-correct-max_segment_size-setting.patch create mode 100644 queue-6.7/dmaengine-fsl-edma-utilize-common-dt-binding-header-.patch create mode 100644 queue-6.7/drm-bridge-add-transparent-bridge-helper.patch create mode 100644 queue-6.7/drm-bridge-aux-hpd-separate-allocation-and-registrat.patch create mode 100644 queue-6.7/drm-bridge-implement-generic-dp-hpd-bridge.patch create mode 100644 queue-6.7/dt-bindings-dma-fsl-edma-add-fsl-edma.h-to-prevent-h.patch create mode 100644 queue-6.7/series create mode 100644 queue-6.7/soc-qcom-pmic-glink-switch-to-drm_aux_hpd_bridge.patch create mode 100644 queue-6.7/soc-qcom-pmic_glink_altmode-fix-drm-bridge-use-after.patch diff --git a/queue-6.7/dmaengine-fsl-edma-correct-max_segment_size-setting.patch b/queue-6.7/dmaengine-fsl-edma-correct-max_segment_size-setting.patch new file mode 100644 index 00000000000..bd4aa8cdbbc --- /dev/null +++ b/queue-6.7/dmaengine-fsl-edma-correct-max_segment_size-setting.patch @@ -0,0 +1,66 @@ +From 6460f2928f75e0db6289f78ff562d4b566193b7b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Feb 2024 14:47:32 -0500 +Subject: dmaengine: fsl-edma: correct max_segment_size setting + +From: Frank Li + +[ Upstream commit a79f949a5ce1d45329d63742c2a995f2b47f9852 ] + +Correcting the previous setting of 0x3fff to the actual value of 0x7fff. + +Introduced new macro 'EDMA_TCD_ITER_MASK' for improved code clarity and +utilization of FIELD_GET to obtain the accurate maximum value. + +Cc: stable@vger.kernel.org +Fixes: e06748539432 ("dmaengine: fsl-edma: support edma memcpy") +Signed-off-by: Frank Li +Link: https://lore.kernel.org/r/20240207194733.2112870-1-Frank.Li@nxp.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/fsl-edma-common.h | 5 +++-- + drivers/dma/fsl-edma-main.c | 4 +++- + 2 files changed, 6 insertions(+), 3 deletions(-) + +diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h +index bb5221158a770..f5e216b157c75 100644 +--- a/drivers/dma/fsl-edma-common.h ++++ b/drivers/dma/fsl-edma-common.h +@@ -30,8 +30,9 @@ + #define EDMA_TCD_ATTR_SSIZE(x) (((x) & GENMASK(2, 0)) << 8) + #define EDMA_TCD_ATTR_SMOD(x) (((x) & GENMASK(4, 0)) << 11) + +-#define EDMA_TCD_CITER_CITER(x) ((x) & GENMASK(14, 0)) +-#define EDMA_TCD_BITER_BITER(x) ((x) & GENMASK(14, 0)) ++#define EDMA_TCD_ITER_MASK GENMASK(14, 0) ++#define EDMA_TCD_CITER_CITER(x) ((x) & EDMA_TCD_ITER_MASK) ++#define EDMA_TCD_BITER_BITER(x) ((x) & EDMA_TCD_ITER_MASK) + + #define EDMA_TCD_CSR_START BIT(0) + #define EDMA_TCD_CSR_INT_MAJOR BIT(1) +diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c +index 45cc419b1b4ac..d36e28b9c767a 100644 +--- a/drivers/dma/fsl-edma-main.c ++++ b/drivers/dma/fsl-edma-main.c +@@ -10,6 +10,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -582,7 +583,8 @@ static int fsl_edma_probe(struct platform_device *pdev) + DMAENGINE_ALIGN_32_BYTES; + + /* Per worst case 'nbytes = 1' take CITER as the max_seg_size */ +- dma_set_max_seg_size(fsl_edma->dma_dev.dev, 0x3fff); ++ dma_set_max_seg_size(fsl_edma->dma_dev.dev, ++ FIELD_GET(EDMA_TCD_ITER_MASK, EDMA_TCD_ITER_MASK)); + + fsl_edma->dma_dev.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT; + +-- +2.43.0 + diff --git a/queue-6.7/dmaengine-fsl-edma-utilize-common-dt-binding-header-.patch b/queue-6.7/dmaengine-fsl-edma-utilize-common-dt-binding-header-.patch new file mode 100644 index 00000000000..97a0495f862 --- /dev/null +++ b/queue-6.7/dmaengine-fsl-edma-utilize-common-dt-binding-header-.patch @@ -0,0 +1,69 @@ +From ec7dd0a2ede3646cd4ef01d0026d36bd8f7bfb53 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Nov 2023 10:48:23 -0500 +Subject: dmaengine: fsl-edma: utilize common dt-binding header file + +From: Frank Li + +[ Upstream commit d0e217b72f9f5c5ef35e3423d393ea8093ce98ec ] + +Refactor the code to use the common dt-binding header file, fsl-edma.h. +Renaming ARGS* to FSL_EDMA*, ensuring no functional changes. + +Signed-off-by: Frank Li +Link: https://lore.kernel.org/r/20231114154824.3617255-4-Frank.Li@nxp.com +Signed-off-by: Vinod Koul +Stable-dep-of: a79f949a5ce1 ("dmaengine: fsl-edma: correct max_segment_size setting") +Signed-off-by: Sasha Levin +--- + drivers/dma/fsl-edma-main.c | 17 ++++++----------- + 1 file changed, 6 insertions(+), 11 deletions(-) + +diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c +index 75cae7ccae270..45cc419b1b4ac 100644 +--- a/drivers/dma/fsl-edma-main.c ++++ b/drivers/dma/fsl-edma-main.c +@@ -9,6 +9,7 @@ + * Vybrid and Layerscape SoCs. + */ + ++#include + #include + #include + #include +@@ -21,12 +22,6 @@ + + #include "fsl-edma-common.h" + +-#define ARGS_RX BIT(0) +-#define ARGS_REMOTE BIT(1) +-#define ARGS_MULTI_FIFO BIT(2) +-#define ARGS_EVEN_CH BIT(3) +-#define ARGS_ODD_CH BIT(4) +- + static void fsl_edma_synchronize(struct dma_chan *chan) + { + struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); +@@ -155,14 +150,14 @@ static struct dma_chan *fsl_edma3_xlate(struct of_phandle_args *dma_spec, + i = fsl_chan - fsl_edma->chans; + + fsl_chan->priority = dma_spec->args[1]; +- fsl_chan->is_rxchan = dma_spec->args[2] & ARGS_RX; +- fsl_chan->is_remote = dma_spec->args[2] & ARGS_REMOTE; +- fsl_chan->is_multi_fifo = dma_spec->args[2] & ARGS_MULTI_FIFO; ++ fsl_chan->is_rxchan = dma_spec->args[2] & FSL_EDMA_RX; ++ fsl_chan->is_remote = dma_spec->args[2] & FSL_EDMA_REMOTE; ++ fsl_chan->is_multi_fifo = dma_spec->args[2] & FSL_EDMA_MULTI_FIFO; + +- if ((dma_spec->args[2] & ARGS_EVEN_CH) && (i & 0x1)) ++ if ((dma_spec->args[2] & FSL_EDMA_EVEN_CH) && (i & 0x1)) + continue; + +- if ((dma_spec->args[2] & ARGS_ODD_CH) && !(i & 0x1)) ++ if ((dma_spec->args[2] & FSL_EDMA_ODD_CH) && !(i & 0x1)) + continue; + + if (!b_chmux && i == dma_spec->args[0]) { +-- +2.43.0 + diff --git a/queue-6.7/drm-bridge-add-transparent-bridge-helper.patch b/queue-6.7/drm-bridge-add-transparent-bridge-helper.patch new file mode 100644 index 00000000000..3932022cae4 --- /dev/null +++ b/queue-6.7/drm-bridge-add-transparent-bridge-helper.patch @@ -0,0 +1,233 @@ +From 17e9df4c7836d0de0a085dca309eba6b7a2c2747 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 3 Dec 2023 14:43:28 +0300 +Subject: drm/bridge: add transparent bridge helper + +From: Dmitry Baryshkov + +[ Upstream commit 2a04739139b2b2761571e18937e2400e71eff664 ] + +Define a helper for creating simple transparent bridges which serve the +only purpose of linking devices into the bridge chain up to the last +bridge representing the connector. This is especially useful for +DP/USB-C bridge chains, which can span across several devices, but do +not require any additional functionality from the intermediate bridges. + +Reviewed-by: Neil Armstrong +Signed-off-by: Dmitry Baryshkov +Link: https://patchwork.freedesktop.org/patch/msgid/20231203114333.1305826-2-dmitry.baryshkov@linaro.org +Stable-dep-of: b979f2d50a09 ("soc: qcom: pmic_glink_altmode: fix drm bridge use-after-free") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/bridge/Kconfig | 9 ++ + drivers/gpu/drm/bridge/Makefile | 1 + + drivers/gpu/drm/bridge/aux-bridge.c | 140 ++++++++++++++++++++++++++++ + include/drm/bridge/aux-bridge.h | 19 ++++ + 4 files changed, 169 insertions(+) + create mode 100644 drivers/gpu/drm/bridge/aux-bridge.c + create mode 100644 include/drm/bridge/aux-bridge.h + +diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig +index 3e6a4e2044c0e..a22645efe93a0 100644 +--- a/drivers/gpu/drm/bridge/Kconfig ++++ b/drivers/gpu/drm/bridge/Kconfig +@@ -12,6 +12,15 @@ config DRM_PANEL_BRIDGE + help + DRM bridge wrapper of DRM panels + ++config DRM_AUX_BRIDGE ++ tristate ++ depends on DRM_BRIDGE && OF ++ select AUXILIARY_BUS ++ select DRM_PANEL_BRIDGE ++ help ++ Simple transparent bridge that is used by several non-DRM drivers to ++ build bridges chain. ++ + menu "Display Interface Bridges" + depends on DRM && DRM_BRIDGE + +diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile +index 2b892b7ed59e8..918e3bfff079c 100644 +--- a/drivers/gpu/drm/bridge/Makefile ++++ b/drivers/gpu/drm/bridge/Makefile +@@ -1,4 +1,5 @@ + # SPDX-License-Identifier: GPL-2.0 ++obj-$(CONFIG_DRM_AUX_BRIDGE) += aux-bridge.o + obj-$(CONFIG_DRM_CHIPONE_ICN6211) += chipone-icn6211.o + obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o + obj-$(CONFIG_DRM_CROS_EC_ANX7688) += cros-ec-anx7688.o +diff --git a/drivers/gpu/drm/bridge/aux-bridge.c b/drivers/gpu/drm/bridge/aux-bridge.c +new file mode 100644 +index 0000000000000..49d7c2ab1ecc3 +--- /dev/null ++++ b/drivers/gpu/drm/bridge/aux-bridge.c +@@ -0,0 +1,140 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2023 Linaro Ltd. ++ * ++ * Author: Dmitry Baryshkov ++ */ ++#include ++#include ++ ++#include ++#include ++ ++static DEFINE_IDA(drm_aux_bridge_ida); ++ ++static void drm_aux_bridge_release(struct device *dev) ++{ ++ struct auxiliary_device *adev = to_auxiliary_dev(dev); ++ ++ ida_free(&drm_aux_bridge_ida, adev->id); ++ ++ kfree(adev); ++} ++ ++static void drm_aux_bridge_unregister_adev(void *_adev) ++{ ++ struct auxiliary_device *adev = _adev; ++ ++ auxiliary_device_delete(adev); ++ auxiliary_device_uninit(adev); ++} ++ ++/** ++ * drm_aux_bridge_register - Create a simple bridge device to link the chain ++ * @parent: device instance providing this bridge ++ * ++ * Creates a simple DRM bridge that doesn't implement any drm_bridge ++ * operations. Such bridges merely fill a place in the bridge chain linking ++ * surrounding DRM bridges. ++ * ++ * Return: zero on success, negative error code on failure ++ */ ++int drm_aux_bridge_register(struct device *parent) ++{ ++ struct auxiliary_device *adev; ++ int ret; ++ ++ adev = kzalloc(sizeof(*adev), GFP_KERNEL); ++ if (!adev) ++ return -ENOMEM; ++ ++ ret = ida_alloc(&drm_aux_bridge_ida, GFP_KERNEL); ++ if (ret < 0) { ++ kfree(adev); ++ return ret; ++ } ++ ++ adev->id = ret; ++ adev->name = "aux_bridge"; ++ adev->dev.parent = parent; ++ adev->dev.of_node = parent->of_node; ++ adev->dev.release = drm_aux_bridge_release; ++ ++ ret = auxiliary_device_init(adev); ++ if (ret) { ++ ida_free(&drm_aux_bridge_ida, adev->id); ++ kfree(adev); ++ return ret; ++ } ++ ++ ret = auxiliary_device_add(adev); ++ if (ret) { ++ auxiliary_device_uninit(adev); ++ return ret; ++ } ++ ++ return devm_add_action_or_reset(parent, drm_aux_bridge_unregister_adev, adev); ++} ++EXPORT_SYMBOL_GPL(drm_aux_bridge_register); ++ ++struct drm_aux_bridge_data { ++ struct drm_bridge bridge; ++ struct drm_bridge *next_bridge; ++ struct device *dev; ++}; ++ ++static int drm_aux_bridge_attach(struct drm_bridge *bridge, ++ enum drm_bridge_attach_flags flags) ++{ ++ struct drm_aux_bridge_data *data; ++ ++ if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) ++ return -EINVAL; ++ ++ data = container_of(bridge, struct drm_aux_bridge_data, bridge); ++ ++ return drm_bridge_attach(bridge->encoder, data->next_bridge, bridge, ++ DRM_BRIDGE_ATTACH_NO_CONNECTOR); ++} ++ ++static const struct drm_bridge_funcs drm_aux_bridge_funcs = { ++ .attach = drm_aux_bridge_attach, ++}; ++ ++static int drm_aux_bridge_probe(struct auxiliary_device *auxdev, ++ const struct auxiliary_device_id *id) ++{ ++ struct drm_aux_bridge_data *data; ++ ++ data = devm_kzalloc(&auxdev->dev, sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ data->dev = &auxdev->dev; ++ data->next_bridge = devm_drm_of_get_bridge(&auxdev->dev, auxdev->dev.of_node, 0, 0); ++ if (IS_ERR(data->next_bridge)) ++ return dev_err_probe(&auxdev->dev, PTR_ERR(data->next_bridge), ++ "failed to acquire drm_bridge\n"); ++ ++ data->bridge.funcs = &drm_aux_bridge_funcs; ++ data->bridge.of_node = data->dev->of_node; ++ ++ return devm_drm_bridge_add(data->dev, &data->bridge); ++} ++ ++static const struct auxiliary_device_id drm_aux_bridge_table[] = { ++ { .name = KBUILD_MODNAME ".aux_bridge" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(auxiliary, drm_aux_bridge_table); ++ ++static struct auxiliary_driver drm_aux_bridge_drv = { ++ .name = "aux_bridge", ++ .id_table = drm_aux_bridge_table, ++ .probe = drm_aux_bridge_probe, ++}; ++module_auxiliary_driver(drm_aux_bridge_drv); ++ ++MODULE_AUTHOR("Dmitry Baryshkov "); ++MODULE_DESCRIPTION("DRM transparent bridge"); ++MODULE_LICENSE("GPL"); +diff --git a/include/drm/bridge/aux-bridge.h b/include/drm/bridge/aux-bridge.h +new file mode 100644 +index 0000000000000..b3a9cc9c862fd +--- /dev/null ++++ b/include/drm/bridge/aux-bridge.h +@@ -0,0 +1,19 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright (C) 2023 Linaro Ltd. ++ * ++ * Author: Dmitry Baryshkov ++ */ ++#ifndef DRM_AUX_BRIDGE_H ++#define DRM_AUX_BRIDGE_H ++ ++#if IS_ENABLED(CONFIG_DRM_AUX_BRIDGE) ++int drm_aux_bridge_register(struct device *parent); ++#else ++static inline int drm_aux_bridge_register(struct device *parent) ++{ ++ return 0; ++} ++#endif ++ ++#endif +-- +2.43.0 + diff --git a/queue-6.7/drm-bridge-aux-hpd-separate-allocation-and-registrat.patch b/queue-6.7/drm-bridge-aux-hpd-separate-allocation-and-registrat.patch new file mode 100644 index 00000000000..df23d7dd028 --- /dev/null +++ b/queue-6.7/drm-bridge-aux-hpd-separate-allocation-and-registrat.patch @@ -0,0 +1,175 @@ +From 357c636cf7159761a5bf455bd7e68e1c884eaa60 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 17 Feb 2024 16:02:24 +0100 +Subject: drm/bridge: aux-hpd: separate allocation and registration + +From: Johan Hovold + +[ Upstream commit e5ca263508f7e9d2cf711edf3258d11ca087885c ] + +Combining allocation and registration is an anti-pattern that should be +avoided. Add two new functions for allocating and registering an dp-hpd +bridge with a proper 'devm' prefix so that it is clear that these are +device managed interfaces. + + devm_drm_dp_hpd_bridge_alloc() + devm_drm_dp_hpd_bridge_add() + +The new interface will be used to fix a use-after-free bug in the +Qualcomm PMIC GLINK driver and may prevent similar issues from being +introduced elsewhere. + +The existing drm_dp_hpd_bridge_register() is reimplemented using the +above and left in place for now. + +Signed-off-by: Johan Hovold +Reviewed-by: Bjorn Andersson +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Dmitry Baryshkov +Link: https://patchwork.freedesktop.org/patch/msgid/20240217150228.5788-3-johan+linaro@kernel.org +Stable-dep-of: b979f2d50a09 ("soc: qcom: pmic_glink_altmode: fix drm bridge use-after-free") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/bridge/aux-hpd-bridge.c | 67 +++++++++++++++++++------ + include/drm/bridge/aux-bridge.h | 15 ++++++ + 2 files changed, 67 insertions(+), 15 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/aux-hpd-bridge.c b/drivers/gpu/drm/bridge/aux-hpd-bridge.c +index 5d2ab3a715f9c..44bb771211b82 100644 +--- a/drivers/gpu/drm/bridge/aux-hpd-bridge.c ++++ b/drivers/gpu/drm/bridge/aux-hpd-bridge.c +@@ -29,16 +29,13 @@ static void drm_aux_hpd_bridge_release(struct device *dev) + kfree(adev); + } + +-static void drm_aux_hpd_bridge_unregister_adev(void *_adev) ++static void drm_aux_hpd_bridge_free_adev(void *_adev) + { +- struct auxiliary_device *adev = _adev; +- +- auxiliary_device_delete(adev); +- auxiliary_device_uninit(adev); ++ auxiliary_device_uninit(_adev); + } + + /** +- * drm_dp_hpd_bridge_register - Create a simple HPD DisplayPort bridge ++ * devm_drm_dp_hpd_bridge_alloc - allocate a HPD DisplayPort bridge + * @parent: device instance providing this bridge + * @np: device node pointer corresponding to this bridge instance + * +@@ -46,11 +43,9 @@ static void drm_aux_hpd_bridge_unregister_adev(void *_adev) + * DRM_MODE_CONNECTOR_DisplayPort, which terminates the bridge chain and is + * able to send the HPD events. + * +- * Return: device instance that will handle created bridge or an error code +- * encoded into the pointer. ++ * Return: bridge auxiliary device pointer or an error pointer + */ +-struct device *drm_dp_hpd_bridge_register(struct device *parent, +- struct device_node *np) ++struct auxiliary_device *devm_drm_dp_hpd_bridge_alloc(struct device *parent, struct device_node *np) + { + struct auxiliary_device *adev; + int ret; +@@ -79,13 +74,55 @@ struct device *drm_dp_hpd_bridge_register(struct device *parent, + return ERR_PTR(ret); + } + +- ret = auxiliary_device_add(adev); +- if (ret) { +- auxiliary_device_uninit(adev); ++ ret = devm_add_action_or_reset(parent, drm_aux_hpd_bridge_free_adev, adev); ++ if (ret) + return ERR_PTR(ret); +- } + +- ret = devm_add_action_or_reset(parent, drm_aux_hpd_bridge_unregister_adev, adev); ++ return adev; ++} ++EXPORT_SYMBOL_GPL(devm_drm_dp_hpd_bridge_alloc); ++ ++static void drm_aux_hpd_bridge_del_adev(void *_adev) ++{ ++ auxiliary_device_delete(_adev); ++} ++ ++/** ++ * devm_drm_dp_hpd_bridge_add - register a HDP DisplayPort bridge ++ * @dev: struct device to tie registration lifetime to ++ * @adev: bridge auxiliary device to be registered ++ * ++ * Returns: zero on success or a negative errno ++ */ ++int devm_drm_dp_hpd_bridge_add(struct device *dev, struct auxiliary_device *adev) ++{ ++ int ret; ++ ++ ret = auxiliary_device_add(adev); ++ if (ret) ++ return ret; ++ ++ return devm_add_action_or_reset(dev, drm_aux_hpd_bridge_del_adev, adev); ++} ++EXPORT_SYMBOL_GPL(devm_drm_dp_hpd_bridge_add); ++ ++/** ++ * drm_dp_hpd_bridge_register - allocate and register a HDP DisplayPort bridge ++ * @parent: device instance providing this bridge ++ * @np: device node pointer corresponding to this bridge instance ++ * ++ * Return: device instance that will handle created bridge or an error pointer ++ */ ++struct device *drm_dp_hpd_bridge_register(struct device *parent, struct device_node *np) ++{ ++ struct auxiliary_device *adev; ++ int ret; ++ ++ adev = devm_drm_dp_hpd_bridge_alloc(parent, np); ++ if (IS_ERR(adev)) ++ return ERR_CAST(adev); ++ ++ ret = devm_drm_dp_hpd_bridge_add(parent, adev); + if (ret) + return ERR_PTR(ret); + +diff --git a/include/drm/bridge/aux-bridge.h b/include/drm/bridge/aux-bridge.h +index 66249ff0858e7..874f177381e34 100644 +--- a/include/drm/bridge/aux-bridge.h ++++ b/include/drm/bridge/aux-bridge.h +@@ -9,6 +9,8 @@ + + #include + ++struct auxiliary_device; ++ + #if IS_ENABLED(CONFIG_DRM_AUX_BRIDGE) + int drm_aux_bridge_register(struct device *parent); + #else +@@ -19,10 +21,23 @@ static inline int drm_aux_bridge_register(struct device *parent) + #endif + + #if IS_ENABLED(CONFIG_DRM_AUX_HPD_BRIDGE) ++struct auxiliary_device *devm_drm_dp_hpd_bridge_alloc(struct device *parent, struct device_node *np); ++int devm_drm_dp_hpd_bridge_add(struct device *dev, struct auxiliary_device *adev); + struct device *drm_dp_hpd_bridge_register(struct device *parent, + struct device_node *np); + void drm_aux_hpd_bridge_notify(struct device *dev, enum drm_connector_status status); + #else ++static inline struct auxiliary_device *devm_drm_dp_hpd_bridge_alloc(struct device *parent, ++ struct device_node *np) ++{ ++ return NULL; ++} ++ ++static inline int devm_drm_dp_hpd_bridge_add(struct auxiliary_device *adev) ++{ ++ return 0; ++} ++ + static inline struct device *drm_dp_hpd_bridge_register(struct device *parent, + struct device_node *np) + { +-- +2.43.0 + diff --git a/queue-6.7/drm-bridge-implement-generic-dp-hpd-bridge.patch b/queue-6.7/drm-bridge-implement-generic-dp-hpd-bridge.patch new file mode 100644 index 00000000000..a50a252d4c9 --- /dev/null +++ b/queue-6.7/drm-bridge-implement-generic-dp-hpd-bridge.patch @@ -0,0 +1,262 @@ +From 4230cbaf334c8b0e1edc5130623d2cd45ec4345d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 3 Dec 2023 14:43:31 +0300 +Subject: drm/bridge: implement generic DP HPD bridge + +From: Dmitry Baryshkov + +[ Upstream commit e560518a6c2e60f1566473c146fddcff3281f617 ] + +Several USB-C controllers implement a pretty simple DRM bridge which +implements just the HPD notification operations. Add special helper +for creating such simple bridges. + +Acked-by: Neil Armstrong +Signed-off-by: Dmitry Baryshkov +Link: https://patchwork.freedesktop.org/patch/msgid/20231203114333.1305826-5-dmitry.baryshkov@linaro.org +Stable-dep-of: b979f2d50a09 ("soc: qcom: pmic_glink_altmode: fix drm bridge use-after-free") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/bridge/Kconfig | 8 ++ + drivers/gpu/drm/bridge/Makefile | 1 + + drivers/gpu/drm/bridge/aux-hpd-bridge.c | 163 ++++++++++++++++++++++++ + include/drm/bridge/aux-bridge.h | 18 +++ + 4 files changed, 190 insertions(+) + create mode 100644 drivers/gpu/drm/bridge/aux-hpd-bridge.c + +diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig +index a22645efe93a0..efd996f6c1384 100644 +--- a/drivers/gpu/drm/bridge/Kconfig ++++ b/drivers/gpu/drm/bridge/Kconfig +@@ -21,6 +21,14 @@ config DRM_AUX_BRIDGE + Simple transparent bridge that is used by several non-DRM drivers to + build bridges chain. + ++config DRM_AUX_HPD_BRIDGE ++ tristate ++ depends on DRM_BRIDGE && OF ++ select AUXILIARY_BUS ++ help ++ Simple bridge that terminates the bridge chain and provides HPD ++ support. ++ + menu "Display Interface Bridges" + depends on DRM && DRM_BRIDGE + +diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile +index 918e3bfff079c..017b5832733b2 100644 +--- a/drivers/gpu/drm/bridge/Makefile ++++ b/drivers/gpu/drm/bridge/Makefile +@@ -1,5 +1,6 @@ + # SPDX-License-Identifier: GPL-2.0 + obj-$(CONFIG_DRM_AUX_BRIDGE) += aux-bridge.o ++obj-$(CONFIG_DRM_AUX_HPD_BRIDGE) += aux-hpd-bridge.o + obj-$(CONFIG_DRM_CHIPONE_ICN6211) += chipone-icn6211.o + obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o + obj-$(CONFIG_DRM_CROS_EC_ANX7688) += cros-ec-anx7688.o +diff --git a/drivers/gpu/drm/bridge/aux-hpd-bridge.c b/drivers/gpu/drm/bridge/aux-hpd-bridge.c +new file mode 100644 +index 0000000000000..5d2ab3a715f9c +--- /dev/null ++++ b/drivers/gpu/drm/bridge/aux-hpd-bridge.c +@@ -0,0 +1,163 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2023 Linaro Ltd. ++ * ++ * Author: Dmitry Baryshkov ++ */ ++#include ++#include ++#include ++ ++#include ++#include ++ ++static DEFINE_IDA(drm_aux_hpd_bridge_ida); ++ ++struct drm_aux_hpd_bridge_data { ++ struct drm_bridge bridge; ++ struct device *dev; ++}; ++ ++static void drm_aux_hpd_bridge_release(struct device *dev) ++{ ++ struct auxiliary_device *adev = to_auxiliary_dev(dev); ++ ++ ida_free(&drm_aux_hpd_bridge_ida, adev->id); ++ ++ of_node_put(adev->dev.platform_data); ++ ++ kfree(adev); ++} ++ ++static void drm_aux_hpd_bridge_unregister_adev(void *_adev) ++{ ++ struct auxiliary_device *adev = _adev; ++ ++ auxiliary_device_delete(adev); ++ auxiliary_device_uninit(adev); ++} ++ ++/** ++ * drm_dp_hpd_bridge_register - Create a simple HPD DisplayPort bridge ++ * @parent: device instance providing this bridge ++ * @np: device node pointer corresponding to this bridge instance ++ * ++ * Creates a simple DRM bridge with the type set to ++ * DRM_MODE_CONNECTOR_DisplayPort, which terminates the bridge chain and is ++ * able to send the HPD events. ++ * ++ * Return: device instance that will handle created bridge or an error code ++ * encoded into the pointer. ++ */ ++struct device *drm_dp_hpd_bridge_register(struct device *parent, ++ struct device_node *np) ++{ ++ struct auxiliary_device *adev; ++ int ret; ++ ++ adev = kzalloc(sizeof(*adev), GFP_KERNEL); ++ if (!adev) ++ return ERR_PTR(-ENOMEM); ++ ++ ret = ida_alloc(&drm_aux_hpd_bridge_ida, GFP_KERNEL); ++ if (ret < 0) { ++ kfree(adev); ++ return ERR_PTR(ret); ++ } ++ ++ adev->id = ret; ++ adev->name = "dp_hpd_bridge"; ++ adev->dev.parent = parent; ++ adev->dev.of_node = parent->of_node; ++ adev->dev.release = drm_aux_hpd_bridge_release; ++ adev->dev.platform_data = np; ++ ++ ret = auxiliary_device_init(adev); ++ if (ret) { ++ ida_free(&drm_aux_hpd_bridge_ida, adev->id); ++ kfree(adev); ++ return ERR_PTR(ret); ++ } ++ ++ ret = auxiliary_device_add(adev); ++ if (ret) { ++ auxiliary_device_uninit(adev); ++ return ERR_PTR(ret); ++ } ++ ++ ret = devm_add_action_or_reset(parent, drm_aux_hpd_bridge_unregister_adev, adev); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ return &adev->dev; ++} ++EXPORT_SYMBOL_GPL(drm_dp_hpd_bridge_register); ++ ++/** ++ * drm_aux_hpd_bridge_notify - notify hot plug detection events ++ * @dev: device created for the HPD bridge ++ * @status: output connection status ++ * ++ * A wrapper around drm_bridge_hpd_notify() that is used to report hot plug ++ * detection events for bridges created via drm_dp_hpd_bridge_register(). ++ * ++ * This function shall be called in a context that can sleep. ++ */ ++void drm_aux_hpd_bridge_notify(struct device *dev, enum drm_connector_status status) ++{ ++ struct auxiliary_device *adev = to_auxiliary_dev(dev); ++ struct drm_aux_hpd_bridge_data *data = auxiliary_get_drvdata(adev); ++ ++ if (!data) ++ return; ++ ++ drm_bridge_hpd_notify(&data->bridge, status); ++} ++EXPORT_SYMBOL_GPL(drm_aux_hpd_bridge_notify); ++ ++static int drm_aux_hpd_bridge_attach(struct drm_bridge *bridge, ++ enum drm_bridge_attach_flags flags) ++{ ++ return flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR ? 0 : -EINVAL; ++} ++ ++static const struct drm_bridge_funcs drm_aux_hpd_bridge_funcs = { ++ .attach = drm_aux_hpd_bridge_attach, ++}; ++ ++static int drm_aux_hpd_bridge_probe(struct auxiliary_device *auxdev, ++ const struct auxiliary_device_id *id) ++{ ++ struct drm_aux_hpd_bridge_data *data; ++ ++ data = devm_kzalloc(&auxdev->dev, sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ data->dev = &auxdev->dev; ++ data->bridge.funcs = &drm_aux_hpd_bridge_funcs; ++ data->bridge.of_node = dev_get_platdata(data->dev); ++ data->bridge.ops = DRM_BRIDGE_OP_HPD; ++ data->bridge.type = id->driver_data; ++ ++ auxiliary_set_drvdata(auxdev, data); ++ ++ return devm_drm_bridge_add(data->dev, &data->bridge); ++} ++ ++static const struct auxiliary_device_id drm_aux_hpd_bridge_table[] = { ++ { .name = KBUILD_MODNAME ".dp_hpd_bridge", .driver_data = DRM_MODE_CONNECTOR_DisplayPort, }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(auxiliary, drm_aux_hpd_bridge_table); ++ ++static struct auxiliary_driver drm_aux_hpd_bridge_drv = { ++ .name = "aux_hpd_bridge", ++ .id_table = drm_aux_hpd_bridge_table, ++ .probe = drm_aux_hpd_bridge_probe, ++}; ++module_auxiliary_driver(drm_aux_hpd_bridge_drv); ++ ++MODULE_AUTHOR("Dmitry Baryshkov "); ++MODULE_DESCRIPTION("DRM HPD bridge"); ++MODULE_LICENSE("GPL"); +diff --git a/include/drm/bridge/aux-bridge.h b/include/drm/bridge/aux-bridge.h +index b3a9cc9c862fd..66249ff0858e7 100644 +--- a/include/drm/bridge/aux-bridge.h ++++ b/include/drm/bridge/aux-bridge.h +@@ -7,6 +7,8 @@ + #ifndef DRM_AUX_BRIDGE_H + #define DRM_AUX_BRIDGE_H + ++#include ++ + #if IS_ENABLED(CONFIG_DRM_AUX_BRIDGE) + int drm_aux_bridge_register(struct device *parent); + #else +@@ -16,4 +18,20 @@ static inline int drm_aux_bridge_register(struct device *parent) + } + #endif + ++#if IS_ENABLED(CONFIG_DRM_AUX_HPD_BRIDGE) ++struct device *drm_dp_hpd_bridge_register(struct device *parent, ++ struct device_node *np); ++void drm_aux_hpd_bridge_notify(struct device *dev, enum drm_connector_status status); ++#else ++static inline struct device *drm_dp_hpd_bridge_register(struct device *parent, ++ struct device_node *np) ++{ ++ return 0; ++} ++ ++static inline void drm_aux_hpd_bridge_notify(struct device *dev, enum drm_connector_status status) ++{ ++} ++#endif ++ + #endif +-- +2.43.0 + diff --git a/queue-6.7/dt-bindings-dma-fsl-edma-add-fsl-edma.h-to-prevent-h.patch b/queue-6.7/dt-bindings-dma-fsl-edma-add-fsl-edma.h-to-prevent-h.patch new file mode 100644 index 00000000000..e3dd808ada7 --- /dev/null +++ b/queue-6.7/dt-bindings-dma-fsl-edma-add-fsl-edma.h-to-prevent-h.patch @@ -0,0 +1,57 @@ +From 82feb6d3481ed699bc0a8b95fb9846a5d5dd2bd0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Nov 2023 10:48:22 -0500 +Subject: dt-bindings: dma: fsl-edma: Add fsl-edma.h to prevent hardcoding in + dts + +From: Frank Li + +[ Upstream commit 1e9b05258271b76ccc04a4b535009d2cb596506a ] + +Introduce a common dt-bindings header file, fsl-edma.h, shared between +the driver and dts files. This addition aims to eliminate hardcoded values +in dts files, promoting maintainability and consistency. + +DTS header file not support BIT() macro yet. Directly use 2^n number. + +Signed-off-by: Frank Li +Reviewed-by: Rob Herring +Link: https://lore.kernel.org/r/20231114154824.3617255-3-Frank.Li@nxp.com +Signed-off-by: Vinod Koul +Stable-dep-of: a79f949a5ce1 ("dmaengine: fsl-edma: correct max_segment_size setting") +Signed-off-by: Sasha Levin +--- + include/dt-bindings/dma/fsl-edma.h | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + create mode 100644 include/dt-bindings/dma/fsl-edma.h + +diff --git a/include/dt-bindings/dma/fsl-edma.h b/include/dt-bindings/dma/fsl-edma.h +new file mode 100644 +index 0000000000000..fd11478cfe9cc +--- /dev/null ++++ b/include/dt-bindings/dma/fsl-edma.h +@@ -0,0 +1,21 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++#ifndef _FSL_EDMA_DT_BINDING_H_ ++#define _FSL_EDMA_DT_BINDING_H_ ++ ++/* Receive Channel */ ++#define FSL_EDMA_RX 0x1 ++ ++/* iMX8 audio remote DMA */ ++#define FSL_EDMA_REMOTE 0x2 ++ ++/* FIFO is continue memory region */ ++#define FSL_EDMA_MULTI_FIFO 0x4 ++ ++/* Channel need stick to even channel */ ++#define FSL_EDMA_EVEN_CH 0x8 ++ ++/* Channel need stick to odd channel */ ++#define FSL_EDMA_ODD_CH 0x10 ++ ++#endif +-- +2.43.0 + diff --git a/queue-6.7/series b/queue-6.7/series new file mode 100644 index 00000000000..6b07d27fa29 --- /dev/null +++ b/queue-6.7/series @@ -0,0 +1,8 @@ +drm-bridge-add-transparent-bridge-helper.patch +drm-bridge-implement-generic-dp-hpd-bridge.patch +soc-qcom-pmic-glink-switch-to-drm_aux_hpd_bridge.patch +drm-bridge-aux-hpd-separate-allocation-and-registrat.patch +soc-qcom-pmic_glink_altmode-fix-drm-bridge-use-after.patch +dt-bindings-dma-fsl-edma-add-fsl-edma.h-to-prevent-h.patch +dmaengine-fsl-edma-utilize-common-dt-binding-header-.patch +dmaengine-fsl-edma-correct-max_segment_size-setting.patch diff --git a/queue-6.7/soc-qcom-pmic-glink-switch-to-drm_aux_hpd_bridge.patch b/queue-6.7/soc-qcom-pmic-glink-switch-to-drm_aux_hpd_bridge.patch new file mode 100644 index 00000000000..bba56aac59d --- /dev/null +++ b/queue-6.7/soc-qcom-pmic-glink-switch-to-drm_aux_hpd_bridge.patch @@ -0,0 +1,111 @@ +From c2f051c3e81e9216cc2ca7096b1dfd0093ae89a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 3 Dec 2023 14:43:32 +0300 +Subject: soc: qcom: pmic-glink: switch to DRM_AUX_HPD_BRIDGE + +From: Dmitry Baryshkov + +[ Upstream commit 2bcca96abfbf89d26fc10fc92e40532bb2ae8891 ] + +Use the freshly defined DRM_AUX_HPD_BRIDGE instead of open-coding the +same functionality for the DRM bridge chain termination. + +Reviewed-by: Bjorn Andersson +Acked-by: Bjorn Andersson +Signed-off-by: Dmitry Baryshkov +Link: https://patchwork.freedesktop.org/patch/msgid/20231203114333.1305826-6-dmitry.baryshkov@linaro.org +Stable-dep-of: b979f2d50a09 ("soc: qcom: pmic_glink_altmode: fix drm bridge use-after-free") +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/Kconfig | 1 + + drivers/soc/qcom/pmic_glink_altmode.c | 33 ++++++++------------------- + 2 files changed, 10 insertions(+), 24 deletions(-) + +diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig +index b3634e10f6f5e..c954001ae79ec 100644 +--- a/drivers/soc/qcom/Kconfig ++++ b/drivers/soc/qcom/Kconfig +@@ -86,6 +86,7 @@ config QCOM_PMIC_GLINK + depends on OF + select AUXILIARY_BUS + select QCOM_PDR_HELPERS ++ select DRM_AUX_HPD_BRIDGE + help + The Qualcomm PMIC GLINK driver provides access, over GLINK, to the + USB and battery firmware running on one of the coprocessors in +diff --git a/drivers/soc/qcom/pmic_glink_altmode.c b/drivers/soc/qcom/pmic_glink_altmode.c +index 7ee52cf2570fa..1539ccb7a346d 100644 +--- a/drivers/soc/qcom/pmic_glink_altmode.c ++++ b/drivers/soc/qcom/pmic_glink_altmode.c +@@ -11,7 +11,7 @@ + #include + #include + #include +-#include ++#include + + #include + #include +@@ -76,7 +76,7 @@ struct pmic_glink_altmode_port { + + struct work_struct work; + +- struct drm_bridge bridge; ++ struct device *bridge; + + enum typec_orientation orientation; + u16 svid; +@@ -230,10 +230,10 @@ static void pmic_glink_altmode_worker(struct work_struct *work) + else + pmic_glink_altmode_enable_usb(altmode, alt_port); + +- if (alt_port->hpd_state) +- drm_bridge_hpd_notify(&alt_port->bridge, connector_status_connected); +- else +- drm_bridge_hpd_notify(&alt_port->bridge, connector_status_disconnected); ++ drm_aux_hpd_bridge_notify(alt_port->bridge, ++ alt_port->hpd_state ? ++ connector_status_connected : ++ connector_status_disconnected); + + pmic_glink_altmode_request(altmode, ALTMODE_PAN_ACK, alt_port->index); + }; +@@ -365,16 +365,6 @@ static void pmic_glink_altmode_callback(const void *data, size_t len, void *priv + } + } + +-static int pmic_glink_altmode_attach(struct drm_bridge *bridge, +- enum drm_bridge_attach_flags flags) +-{ +- return flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR ? 0 : -EINVAL; +-} +- +-static const struct drm_bridge_funcs pmic_glink_altmode_bridge_funcs = { +- .attach = pmic_glink_altmode_attach, +-}; +- + static void pmic_glink_altmode_put_retimer(void *data) + { + typec_retimer_put(data); +@@ -464,15 +454,10 @@ static int pmic_glink_altmode_probe(struct auxiliary_device *adev, + alt_port->index = port; + INIT_WORK(&alt_port->work, pmic_glink_altmode_worker); + +- alt_port->bridge.funcs = &pmic_glink_altmode_bridge_funcs; +- alt_port->bridge.of_node = to_of_node(fwnode); +- alt_port->bridge.ops = DRM_BRIDGE_OP_HPD; +- alt_port->bridge.type = DRM_MODE_CONNECTOR_DisplayPort; +- +- ret = devm_drm_bridge_add(dev, &alt_port->bridge); +- if (ret) { ++ alt_port->bridge = drm_dp_hpd_bridge_register(dev, to_of_node(fwnode)); ++ if (IS_ERR(alt_port->bridge)) { + fwnode_handle_put(fwnode); +- return ret; ++ return PTR_ERR(alt_port->bridge); + } + + alt_port->dp_alt.svid = USB_TYPEC_DP_SID; +-- +2.43.0 + diff --git a/queue-6.7/soc-qcom-pmic_glink_altmode-fix-drm-bridge-use-after.patch b/queue-6.7/soc-qcom-pmic_glink_altmode-fix-drm-bridge-use-after.patch new file mode 100644 index 00000000000..bbb518d6869 --- /dev/null +++ b/queue-6.7/soc-qcom-pmic_glink_altmode-fix-drm-bridge-use-after.patch @@ -0,0 +1,123 @@ +From 34ffd4992df436d6a57996dbb04e9105b44c6a9f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 17 Feb 2024 16:02:25 +0100 +Subject: soc: qcom: pmic_glink_altmode: fix drm bridge use-after-free + +From: Johan Hovold + +[ Upstream commit b979f2d50a099f3402418d7ff5f26c3952fb08bb ] + +A recent DRM series purporting to simplify support for "transparent +bridges" and handling of probe deferrals ironically exposed a +use-after-free issue on pmic_glink_altmode probe deferral. + +This has manifested itself as the display subsystem occasionally failing +to initialise and NULL-pointer dereferences during boot of machines like +the Lenovo ThinkPad X13s. + +Specifically, the dp-hpd bridge is currently registered before all +resources have been acquired which means that it can also be +deregistered on probe deferrals. + +In the meantime there is a race window where the new aux bridge driver +(or PHY driver previously) may have looked up the dp-hpd bridge and +stored a (non-reference-counted) pointer to the bridge which is about to +be deallocated. + +When the display controller is later initialised, this triggers a +use-after-free when attaching the bridges: + + dp -> aux -> dp-hpd (freed) + +which may, for example, result in the freed bridge failing to attach: + + [drm:drm_bridge_attach [drm]] *ERROR* failed to attach bridge /soc@0/phy@88eb000 to encoder TMDS-31: -16 + +or a NULL-pointer dereference: + + Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000 + ... + Call trace: + drm_bridge_attach+0x70/0x1a8 [drm] + drm_aux_bridge_attach+0x24/0x38 [aux_bridge] + drm_bridge_attach+0x80/0x1a8 [drm] + dp_bridge_init+0xa8/0x15c [msm] + msm_dp_modeset_init+0x28/0xc4 [msm] + +The DRM bridge implementation is clearly fragile and implicitly built on +the assumption that bridges may never go away. In this case, the fix is +to move the bridge registration in the pmic_glink_altmode driver to +after all resources have been looked up. + +Incidentally, with the new dp-hpd bridge implementation, which registers +child devices, this is also a requirement due to a long-standing issue +in driver core that can otherwise lead to a probe deferral loop (see +commit fbc35b45f9f6 ("Add documentation on meaning of -EPROBE_DEFER")). + +[DB: slightly fixed commit message by adding the word 'commit'] +Fixes: 080b4e24852b ("soc: qcom: pmic_glink: Introduce altmode support") +Fixes: 2bcca96abfbf ("soc: qcom: pmic-glink: switch to DRM_AUX_HPD_BRIDGE") +Cc: # 6.3 +Cc: Bjorn Andersson +Cc: Dmitry Baryshkov +Signed-off-by: Johan Hovold +Reviewed-by: Bjorn Andersson +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Dmitry Baryshkov +Link: https://patchwork.freedesktop.org/patch/msgid/20240217150228.5788-4-johan+linaro@kernel.org +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/pmic_glink_altmode.c | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +diff --git a/drivers/soc/qcom/pmic_glink_altmode.c b/drivers/soc/qcom/pmic_glink_altmode.c +index 1539ccb7a346d..e1d32e1b79902 100644 +--- a/drivers/soc/qcom/pmic_glink_altmode.c ++++ b/drivers/soc/qcom/pmic_glink_altmode.c +@@ -76,7 +76,7 @@ struct pmic_glink_altmode_port { + + struct work_struct work; + +- struct device *bridge; ++ struct auxiliary_device *bridge; + + enum typec_orientation orientation; + u16 svid; +@@ -230,7 +230,7 @@ static void pmic_glink_altmode_worker(struct work_struct *work) + else + pmic_glink_altmode_enable_usb(altmode, alt_port); + +- drm_aux_hpd_bridge_notify(alt_port->bridge, ++ drm_aux_hpd_bridge_notify(&alt_port->bridge->dev, + alt_port->hpd_state ? + connector_status_connected : + connector_status_disconnected); +@@ -454,7 +454,7 @@ static int pmic_glink_altmode_probe(struct auxiliary_device *adev, + alt_port->index = port; + INIT_WORK(&alt_port->work, pmic_glink_altmode_worker); + +- alt_port->bridge = drm_dp_hpd_bridge_register(dev, to_of_node(fwnode)); ++ alt_port->bridge = devm_drm_dp_hpd_bridge_alloc(dev, to_of_node(fwnode)); + if (IS_ERR(alt_port->bridge)) { + fwnode_handle_put(fwnode); + return PTR_ERR(alt_port->bridge); +@@ -510,6 +510,16 @@ static int pmic_glink_altmode_probe(struct auxiliary_device *adev, + } + } + ++ for (port = 0; port < ARRAY_SIZE(altmode->ports); port++) { ++ alt_port = &altmode->ports[port]; ++ if (!alt_port->bridge) ++ continue; ++ ++ ret = devm_drm_dp_hpd_bridge_add(dev, alt_port->bridge); ++ if (ret) ++ return ret; ++ } ++ + altmode->client = devm_pmic_glink_register_client(dev, + altmode->owner_id, + pmic_glink_altmode_callback, +-- +2.43.0 + -- 2.47.3