Commit ab28896f authored by Pin-yen Lin's avatar Pin-yen Lin Committed by Robert Foss

drm/bridge: it6505: Improve synchronization between extcon subsystem

Originally, the it6505 relies on a short sleep in the IRQ handler and a
long sleep to make sure it6505->lane_swap and it6505->lane_count is
configured in it6505_extcon_work and it6505_detect, respectively.

Use completion and additional DPCD read to remove the unnecessary waits,
and use a different lock for it6505_extcon_work and the threaded IRQ
handler because they no longer need to run exclusively.

The wait time of the completion is usually less than 10ms in local
experiments, but leave it larger here just in case.
Signed-off-by: default avatarPin-yen Lin <treapking@chromium.org>
Reviewed-by: default avatarRobert Foss <robert.foss@linaro.org>
Signed-off-by: default avatarRobert Foss <robert.foss@linaro.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20221013110411.1674359-4-treapking@chromium.org
parent 5827b1e1
...@@ -412,6 +412,7 @@ struct it6505 { ...@@ -412,6 +412,7 @@ struct it6505 {
* Mutex protects extcon and interrupt functions from interfering * Mutex protects extcon and interrupt functions from interfering
* each other. * each other.
*/ */
struct mutex irq_lock;
struct mutex extcon_lock; struct mutex extcon_lock;
struct mutex mode_lock; /* used to bridge_detect */ struct mutex mode_lock; /* used to bridge_detect */
struct mutex aux_lock; /* used to aux data transfers */ struct mutex aux_lock; /* used to aux data transfers */
...@@ -440,7 +441,7 @@ struct it6505 { ...@@ -440,7 +441,7 @@ struct it6505 {
enum hdcp_state hdcp_status; enum hdcp_state hdcp_status;
struct delayed_work hdcp_work; struct delayed_work hdcp_work;
struct work_struct hdcp_wait_ksv_list; struct work_struct hdcp_wait_ksv_list;
struct completion wait_edid_complete; struct completion extcon_completion;
u8 auto_train_retry; u8 auto_train_retry;
bool hdcp_desired; bool hdcp_desired;
bool is_repeater; bool is_repeater;
...@@ -2316,8 +2317,8 @@ static void it6505_irq_hpd(struct it6505 *it6505) ...@@ -2316,8 +2317,8 @@ static void it6505_irq_hpd(struct it6505 *it6505)
it6505->hpd_state ? "high" : "low"); it6505->hpd_state ? "high" : "low");
if (it6505->hpd_state) { if (it6505->hpd_state) {
wait_for_completion_timeout(&it6505->wait_edid_complete, wait_for_completion_timeout(&it6505->extcon_completion,
msecs_to_jiffies(6000)); msecs_to_jiffies(1000));
it6505_aux_on(it6505); it6505_aux_on(it6505);
if (it6505->dpcd[0] == 0) { if (it6505->dpcd[0] == 0) {
it6505_get_dpcd(it6505, DP_DPCD_REV, it6505->dpcd, it6505_get_dpcd(it6505, DP_DPCD_REV, it6505->dpcd,
...@@ -2493,8 +2494,7 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data) ...@@ -2493,8 +2494,7 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data)
}; };
int int_status[3], i; int int_status[3], i;
msleep(100); mutex_lock(&it6505->irq_lock);
mutex_lock(&it6505->extcon_lock);
if (it6505->enable_drv_hold || !it6505->powered) if (it6505->enable_drv_hold || !it6505->powered)
goto unlock; goto unlock;
...@@ -2524,7 +2524,7 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data) ...@@ -2524,7 +2524,7 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data)
} }
unlock: unlock:
mutex_unlock(&it6505->extcon_lock); mutex_unlock(&it6505->irq_lock);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -2701,9 +2701,12 @@ static void it6505_extcon_work(struct work_struct *work) ...@@ -2701,9 +2701,12 @@ static void it6505_extcon_work(struct work_struct *work)
*/ */
if (ret) if (ret)
it6505_poweron(it6505); it6505_poweron(it6505);
complete_all(&it6505->extcon_completion);
} else { } else {
DRM_DEV_DEBUG_DRIVER(dev, "start to power off"); DRM_DEV_DEBUG_DRIVER(dev, "start to power off");
pm_runtime_put_sync(dev); pm_runtime_put_sync(dev);
reinit_completion(&it6505->extcon_completion);
drm_helper_hpd_irq_event(it6505->bridge.dev); drm_helper_hpd_irq_event(it6505->bridge.dev);
memset(it6505->dpcd, 0, sizeof(it6505->dpcd)); memset(it6505->dpcd, 0, sizeof(it6505->dpcd));
...@@ -3274,6 +3277,7 @@ static int it6505_i2c_probe(struct i2c_client *client, ...@@ -3274,6 +3277,7 @@ static int it6505_i2c_probe(struct i2c_client *client,
if (!it6505) if (!it6505)
return -ENOMEM; return -ENOMEM;
mutex_init(&it6505->irq_lock);
mutex_init(&it6505->extcon_lock); mutex_init(&it6505->extcon_lock);
mutex_init(&it6505->mode_lock); mutex_init(&it6505->mode_lock);
mutex_init(&it6505->aux_lock); mutex_init(&it6505->aux_lock);
...@@ -3329,7 +3333,7 @@ static int it6505_i2c_probe(struct i2c_client *client, ...@@ -3329,7 +3333,7 @@ static int it6505_i2c_probe(struct i2c_client *client,
INIT_WORK(&it6505->link_works, it6505_link_training_work); INIT_WORK(&it6505->link_works, it6505_link_training_work);
INIT_WORK(&it6505->hdcp_wait_ksv_list, it6505_hdcp_wait_ksv_list); INIT_WORK(&it6505->hdcp_wait_ksv_list, it6505_hdcp_wait_ksv_list);
INIT_DELAYED_WORK(&it6505->hdcp_work, it6505_hdcp_work); INIT_DELAYED_WORK(&it6505->hdcp_work, it6505_hdcp_work);
init_completion(&it6505->wait_edid_complete); init_completion(&it6505->extcon_completion);
memset(it6505->dpcd, 0, sizeof(it6505->dpcd)); memset(it6505->dpcd, 0, sizeof(it6505->dpcd));
it6505->powered = false; it6505->powered = false;
it6505->enable_drv_hold = DEFAULT_DRV_HOLD; it6505->enable_drv_hold = DEFAULT_DRV_HOLD;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment