[PATCH] drm: adv7511: Refactor power management
Chris Kohn
christian.kohn at xilinx.com
Mon Mar 2 17:45:46 PST 2015
Hi Laurent,
> -----Original Message-----
> From: Laurent Pinchart [mailto:laurent.pinchart+renesas at ideasonboard.com]
> Sent: Monday, March 02, 2015 5:20 AM
> To: dri-devel at lists.freedesktop.org
> Cc: Lars-Peter Clausen; Chris Kohn; Hyun Kwon
> Subject: [PATCH] drm: adv7511: Refactor power management
>
> From: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
>
> Remove the internal dependency on DPMS mode for power management by
> using a by a powered state boolean instead, and use the new power off handler
> at probe time. This ensure that the regmap cache is properly marked as dirty
> when the device is probed, and the registers properly synced during the first
> power up.
>
> As a side effect this removes the initialization of current_edid_segment at probe
> time, as the field will be initialized when the device is powered on, at the latest
> right before reading EDID data.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
Works fine on my platform.
Tested-by: Christian Kohn <christian.kohn at xilinx.com>
Cheers,
Chris
> ---
> drivers/gpu/drm/i2c/adv7511.c | 97 +++++++++++++++++++++++------------------
> --
> 1 file changed, 51 insertions(+), 46 deletions(-)
>
> diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
> index fa140e04d5fa..7fb7e22f4ad1 100644
> --- a/drivers/gpu/drm/i2c/adv7511.c
> +++ b/drivers/gpu/drm/i2c/adv7511.c
> @@ -27,7 +27,7 @@ struct adv7511 {
> struct regmap *regmap;
> struct regmap *packet_memory_regmap;
> enum drm_connector_status status;
> - int dpms_mode;
> + bool powered;
>
> unsigned int f_tmds;
>
> @@ -357,6 +357,46 @@ static void adv7511_set_link_config(struct adv7511
> *adv7511,
> adv7511->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB;
> }
>
> +static void adv7511_power_on(struct adv7511 *adv7511) {
> + adv7511->current_edid_segment = -1;
> +
> + regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
> + ADV7511_INT0_EDID_READY |
> ADV7511_INT1_DDC_ERROR);
> + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
> + ADV7511_POWER_POWER_DOWN, 0);
> +
> + /*
> + * Per spec it is allowed to pulse the HDP signal to indicate that the
> + * EDID information has changed. Some monitors do this when they
> wakeup
> + * from standby or are enabled. When the HDP goes low the adv7511 is
> + * reset and the outputs are disabled which might cause the monitor to
> + * go to standby again. To avoid this we ignore the HDP pin for the
> + * first few seconds after enabling the output.
> + */
> + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
> + ADV7511_REG_POWER2_HDP_SRC_MASK,
> + ADV7511_REG_POWER2_HDP_SRC_NONE);
> +
> + /*
> + * Most of the registers are reset during power down or when HPD is
> low.
> + */
> + regcache_sync(adv7511->regmap);
> +
> + adv7511->powered = true;
> +}
> +
> +static void adv7511_power_off(struct adv7511 *adv7511) {
> + /* TODO: setup additional power down modes */
> + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
> + ADV7511_POWER_POWER_DOWN,
> + ADV7511_POWER_POWER_DOWN);
> + regcache_mark_dirty(adv7511->regmap);
> +
> + adv7511->powered = false;
> +}
> +
> /* -----------------------------------------------------------------------------
> * Interrupt and hotplug detection
> */
> @@ -526,7 +566,7 @@ static int adv7511_get_modes(struct drm_encoder
> *encoder,
> unsigned int count;
>
> /* Reading the EDID only works if the device is powered */
> - if (adv7511->dpms_mode != DRM_MODE_DPMS_ON) {
> + if (!adv7511->powered) {
> regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
> ADV7511_INT0_EDID_READY |
> ADV7511_INT1_DDC_ERROR);
> regmap_update_bits(adv7511->regmap,
> ADV7511_REG_POWER, @@ -536,7 +576,7 @@ static int
> adv7511_get_modes(struct drm_encoder *encoder,
>
> edid = drm_do_get_edid(connector, adv7511_get_edid_block,
> adv7511);
>
> - if (adv7511->dpms_mode != DRM_MODE_DPMS_ON)
> + if (!adv7511->powered)
> regmap_update_bits(adv7511->regmap,
> ADV7511_REG_POWER,
> ADV7511_POWER_POWER_DOWN,
> ADV7511_POWER_POWER_DOWN);
> @@ -558,41 +598,10 @@ static void adv7511_encoder_dpms(struct
> drm_encoder *encoder, int mode) {
> struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
>
> - switch (mode) {
> - case DRM_MODE_DPMS_ON:
> - adv7511->current_edid_segment = -1;
> -
> - regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
> - ADV7511_INT0_EDID_READY |
> ADV7511_INT1_DDC_ERROR);
> - regmap_update_bits(adv7511->regmap,
> ADV7511_REG_POWER,
> - ADV7511_POWER_POWER_DOWN, 0);
> - /*
> - * Per spec it is allowed to pulse the HDP signal to indicate
> - * that the EDID information has changed. Some monitors do
> this
> - * when they wakeup from standby or are enabled. When the
> HDP
> - * goes low the adv7511 is reset and the outputs are disabled
> - * which might cause the monitor to go to standby again. To
> - * avoid this we ignore the HDP pin for the first few seconds
> - * after enabeling the output.
> - */
> - regmap_update_bits(adv7511->regmap,
> ADV7511_REG_POWER2,
> - ADV7511_REG_POWER2_HDP_SRC_MASK,
> - ADV7511_REG_POWER2_HDP_SRC_NONE);
> - /* Most of the registers are reset during power down or
> - * when HPD is low
> - */
> - regcache_sync(adv7511->regmap);
> - break;
> - default:
> - /* TODO: setup additional power down modes */
> - regmap_update_bits(adv7511->regmap,
> ADV7511_REG_POWER,
> - ADV7511_POWER_POWER_DOWN,
> - ADV7511_POWER_POWER_DOWN);
> - regcache_mark_dirty(adv7511->regmap);
> - break;
> - }
> -
> - adv7511->dpms_mode = mode;
> + if (mode == DRM_MODE_DPMS_ON)
> + adv7511_power_on(adv7511);
> + else
> + adv7511_power_off(adv7511);
> }
>
> static enum drm_connector_status
> @@ -620,10 +629,9 @@ adv7511_encoder_detect(struct drm_encoder
> *encoder,
> * there is a pending HPD interrupt and the cable is connected there was
> * at least one transition from disconnected to connected and the chip
> * has to be reinitialized. */
> - if (status == connector_status_connected && hpd &&
> - adv7511->dpms_mode == DRM_MODE_DPMS_ON) {
> + if (status == connector_status_connected && hpd && adv7511-
> >powered) {
> regcache_mark_dirty(adv7511->regmap);
> - adv7511_encoder_dpms(encoder, adv7511->dpms_mode);
> + adv7511_power_on(adv7511);
> adv7511_get_modes(encoder, connector);
> if (adv7511->status == connector_status_connected)
> status = connector_status_disconnected; @@ -858,7
> +866,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct
> i2c_device_id *id)
> if (!adv7511)
> return -ENOMEM;
>
> - adv7511->dpms_mode = DRM_MODE_DPMS_OFF;
> + adv7511->powered = false;
> adv7511->status = connector_status_disconnected;
>
> ret = adv7511_parse_dt(dev->of_node, &link_config); @@ -918,10
> +926,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct
> i2c_device_id *id)
> regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL,
> ADV7511_CEC_CTRL_POWER_DOWN);
>
> - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
> - ADV7511_POWER_POWER_DOWN,
> ADV7511_POWER_POWER_DOWN);
> -
> - adv7511->current_edid_segment = -1;
> + adv7511_power_off(adv7511);
>
> i2c_set_clientdata(i2c, adv7511);
>
> --
> Regards,
>
> Laurent Pinchart
More information about the dri-devel
mailing list