From 3611136b7f3f7997bbde87e50d29ef455fcc302a Mon Sep 17 00:00:00 2001 From: Guochun Huang Date: Tue, 19 Jul 2022 10:40:15 +0800 Subject: [PATCH] drm/bridge: maxim-max96755f: Add lock irq handler Signed-off-by: Guochun Huang Change-Id: Ieebaeadf9b051963dcba4a589a983e6188ef285d --- drivers/gpu/drm/bridge/maxim-max96755f.c | 89 ++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/bridge/maxim-max96755f.c b/drivers/gpu/drm/bridge/maxim-max96755f.c index c1b8fb81df67..8fb5fb2ddd95 100644 --- a/drivers/gpu/drm/bridge/maxim-max96755f.c +++ b/drivers/gpu/drm/bridge/maxim-max96755f.c @@ -13,6 +13,8 @@ #include #include +#include +#include #include #include #include @@ -37,6 +39,11 @@ struct max96755f_bridge { bool dv_swp_ab; bool dpi_deskew_en; bool split_mode; + struct { + struct gpio_desc *gpio; + int irq; + atomic_t triggered; + } lock; }; #define to_max96755f_bridge(x) container_of(x, struct max96755f_bridge, x) @@ -61,6 +68,9 @@ max96755f_bridge_connector_detect(struct drm_connector *connector, bool force) { struct max96755f_bridge *ser = to_max96755f_bridge(connector); + if (!drm_kms_helper_is_poll_worker()) + return connector->status; + return drm_bridge_detect(&ser->bridge); } @@ -107,6 +117,19 @@ static struct mipi_dsi_device *max96755f_attach_dsi(struct max96755f_bridge *max return dsi; } +static bool max96755f_bridge_link_locked(struct max96755f_bridge *ser) +{ + u32 val; + + if (regmap_read(ser->regmap, 0x0013, &val)) + return false; + + if (!FIELD_GET(LOCKED, val)) + return false; + + return true; +} + static int max96755f_bridge_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) { @@ -140,6 +163,13 @@ static int max96755f_bridge_attach(struct drm_bridge *bridge, return ret; } + if (max96755f_bridge_link_locked(ser)) { + connector->status = connector_status_connected; + enable_irq(ser->lock.irq); + } else { + connector->status = connector_status_disconnected; + } + drm_connector_attach_encoder(connector, bridge->encoder); ser->dsi = max96755f_attach_dsi(ser, ser->dsi_node); @@ -238,6 +268,16 @@ static void max96755f_bridge_pre_enable(struct drm_bridge *bridge) drm_panel_prepare(ser->panel); } +static void max96755f_bridge_reset_oneshot(struct max96755f_bridge *ser) +{ + regmap_update_bits(ser->regmap, 0x10, RESET_ONESHOT, + FIELD_PREP(RESET_ONESHOT, 1)); + + mdelay(100); + /* One-Shot Link Reset will trigger lock interrupt */ + atomic_set(&ser->lock.triggered, 0); +} + static void max96755f_bridge_enable(struct drm_bridge *bridge) { struct max96755f_bridge *ser = to_max96755f_bridge(bridge); @@ -272,18 +312,20 @@ static void max96755f_bridge_enable(struct drm_bridge *bridge) FIELD_PREP(VID_TX_EN_X, 1)); } - regmap_update_bits(ser->regmap, 0x10, RESET_ONESHOT, - FIELD_PREP(RESET_ONESHOT, 1)); - mdelay(100); + max96755f_bridge_reset_oneshot(ser); if (ser->panel) drm_panel_enable(ser->panel); + + enable_irq(ser->lock.irq); } static void max96755f_bridge_disable(struct drm_bridge *bridge) { struct max96755f_bridge *ser = to_max96755f_bridge(bridge); + disable_irq(ser->lock.irq); + if (ser->panel) drm_panel_disable(ser->panel); @@ -310,13 +352,20 @@ static enum drm_connector_status max96755f_bridge_detect(struct drm_bridge *bridge) { struct max96755f_bridge *ser = to_max96755f_bridge(bridge); - u32 val; + struct drm_connector *connector = &ser->connector; - if (regmap_read(ser->regmap, 0x0013, &val)) + if (!max96755f_bridge_link_locked(ser)) return connector_status_disconnected; - if (!FIELD_GET(LOCKED, val)) - return connector_status_disconnected; + if (connector->status == connector_status_connected) { + if (atomic_cmpxchg(&ser->lock.triggered, 1, 0)) + return connector_status_disconnected; + } else { + atomic_set(&ser->lock.triggered, 0); + } + + if (ser->next_bridge && (ser->next_bridge->ops & DRM_BRIDGE_OP_DETECT)) + return drm_bridge_detect(ser->next_bridge); return connector_status_connected; } @@ -379,6 +428,15 @@ static int max96755f_link_parse(struct max96755f_bridge *ser) return ret; } +static irqreturn_t max96755f_bridge_lock_irq_handler(int irq, void *arg) +{ + struct max96755f_bridge *ser = arg; + + atomic_set(&ser->lock.triggered, 1); + + return IRQ_HANDLED; +} + static int max96755f_bridge_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -406,6 +464,23 @@ static int max96755f_bridge_probe(struct platform_device *pdev) if (ret) dev_err_probe(dev, ret, "failed to parse link\n"); + ser->lock.gpio = devm_gpiod_get(dev, "lock", GPIOD_IN); + if (IS_ERR(ser->lock.gpio)) + return dev_err_probe(dev, PTR_ERR(ser->lock.gpio), + "failed to get lock GPIO\n"); + + ser->lock.irq = gpiod_to_irq(ser->lock.gpio); + if (ser->lock.irq < 0) + return ser->lock.irq; + + irq_set_status_flags(ser->lock.irq, IRQ_NOAUTOEN); + ret = devm_request_threaded_irq(dev, ser->lock.irq, NULL, + max96755f_bridge_lock_irq_handler, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + dev_name(dev), ser); + if (ret) + return dev_err_probe(dev, ret, "failed to request lock IRQ\n"); + ser->bridge.funcs = &max96755f_bridge_funcs; ser->bridge.of_node = dev->of_node; ser->bridge.ops = DRM_BRIDGE_OP_DETECT;