When there are multiple EDID reads, the bridge will be repeatedly enabled and disabled. Add a cache for EDID to speed this up. Signed-off-by: Pin-yen Lin <treapking@xxxxxxxxxxxx> Reviewed-by: Robert Foss <rfoss@xxxxxxxxxx> Reviewed-by: Douglas Anderson <dianders@xxxxxxxxxxxx> --- Changes in v2: - Remove the NULL assignment in ps8640_remove drivers/gpu/drm/bridge/parade-ps8640.c | 60 +++++++++++++++----------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c index 08de501c436e..cddbfe91f75e 100644 --- a/drivers/gpu/drm/bridge/parade-ps8640.c +++ b/drivers/gpu/drm/bridge/parade-ps8640.c @@ -105,6 +105,7 @@ struct ps8640 { struct gpio_desc *gpio_reset; struct gpio_desc *gpio_powerdown; struct device_link *link; + struct edid *edid; bool pre_enabled; bool need_post_hpd_delay; }; @@ -543,34 +544,37 @@ static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge, { struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); bool poweroff = !ps_bridge->pre_enabled; - struct edid *edid; - /* - * When we end calling get_edid() triggered by an ioctl, i.e - * - * drm_mode_getconnector (ioctl) - * -> drm_helper_probe_single_connector_modes - * -> drm_bridge_connector_get_modes - * -> ps8640_bridge_get_edid - * - * We need to make sure that what we need is enabled before reading - * EDID, for this chip, we need to do a full poweron, otherwise it will - * fail. - */ - if (poweroff) - drm_atomic_bridge_chain_pre_enable(bridge, connector->state->state); + if (!ps_bridge->edid) { + /* + * When we end calling get_edid() triggered by an ioctl, i.e + * + * drm_mode_getconnector (ioctl) + * -> drm_helper_probe_single_connector_modes + * -> drm_bridge_connector_get_modes + * -> ps8640_bridge_get_edid + * + * We need to make sure that what we need is enabled before + * reading EDID, for this chip, we need to do a full poweron, + * otherwise it will fail. + */ + if (poweroff) + drm_atomic_bridge_chain_pre_enable(bridge, + connector->state->state); - edid = drm_get_edid(connector, - ps_bridge->page[PAGE0_DP_CNTL]->adapter); + ps_bridge->edid = drm_get_edid(connector, + ps_bridge->page[PAGE0_DP_CNTL]->adapter); - /* - * If we call the get_edid() function without having enabled the chip - * before, return the chip to its original power state. - */ - if (poweroff) - drm_atomic_bridge_chain_post_disable(bridge, connector->state->state); + /* + * If we call the get_edid() function without having enabled the + * chip before, return the chip to its original power state. + */ + if (poweroff) + drm_atomic_bridge_chain_post_disable(bridge, + connector->state->state); + } - return edid; + return drm_edid_duplicate(ps_bridge->edid); } static void ps8640_runtime_disable(void *data) @@ -767,6 +771,13 @@ static int ps8640_probe(struct i2c_client *client) return ret; } +static void ps8640_remove(struct i2c_client *client) +{ + struct ps8640 *ps_bridge = i2c_get_clientdata(client); + + kfree(ps_bridge->edid); +} + static const struct of_device_id ps8640_match[] = { { .compatible = "parade,ps8640" }, { } @@ -775,6 +786,7 @@ MODULE_DEVICE_TABLE(of, ps8640_match); static struct i2c_driver ps8640_driver = { .probe_new = ps8640_probe, + .remove = ps8640_remove, .driver = { .name = "ps8640", .of_match_table = ps8640_match, -- 2.40.0.rc1.284.g88254d51c5-goog