Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2e9914b0 authored by Padmanabhan Komanduru's avatar Padmanabhan Komanduru
Browse files

drm/msm/dp: retry failed AUX transactions



Retry AUX read/write transactions that have failed due to
AUX controller hardware indicating an error or due to a
software based timeout waiting for transaction completion.

Change-Id: Id9c3c7ae1ab320540545b9c178d947a3cd023079
Signed-off-by: default avatarPadmanabhan Komanduru <pkomandu@codeaurora.org>
parent 20a21dbc
Loading
Loading
Loading
Loading
+36 −5
Original line number Original line Diff line number Diff line
@@ -28,11 +28,13 @@ struct dp_aux_private {
	struct device *dev;
	struct device *dev;
	struct dp_aux dp_aux;
	struct dp_aux dp_aux;
	struct dp_catalog_aux *catalog;
	struct dp_catalog_aux *catalog;
	struct dp_aux_cfg *cfg;


	struct mutex mutex;
	struct mutex mutex;
	struct completion comp;
	struct completion comp;


	u32 aux_error_num;
	u32 aux_error_num;
	u32 retry_cnt;
	bool cmd_busy;
	bool cmd_busy;
	bool native;
	bool native;
	bool read;
	bool read;
@@ -127,7 +129,7 @@ static int dp_aux_cmd_fifo_tx(struct dp_aux_private *aux,


	timeout = wait_for_completion_timeout(&aux->comp, aux_timeout_ms);
	timeout = wait_for_completion_timeout(&aux->comp, aux_timeout_ms);
	if (!timeout) {
	if (!timeout) {
		pr_err("aux write timeout\n");
		pr_err("aux %s timeout\n", (aux->read ? "read" : "write"));
		return -ETIMEDOUT;
		return -ETIMEDOUT;
	}
	}


@@ -232,6 +234,22 @@ static void dp_aux_isr(struct dp_aux *dp_aux)
		dp_aux_i2c_handler(aux);
		dp_aux_i2c_handler(aux);
}
}


static void dp_aux_reconfig(struct dp_aux *dp_aux)
{
	struct dp_aux_private *aux;

	if (!dp_aux) {
		pr_err("invalid input\n");
		return;
	}

	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);

	aux->catalog->update_aux_cfg(aux->catalog,
			aux->cfg, PHY_AUX_CFG1);
	aux->catalog->reset(aux->catalog);
}

/*
/*
 * This function does the real job to process an AUX transaction.
 * This function does the real job to process an AUX transaction.
 * It will call aux_reset() function to reset the AUX channel,
 * It will call aux_reset() function to reset the AUX channel,
@@ -243,6 +261,7 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux,
	ssize_t ret;
	ssize_t ret;
	int const aux_cmd_native_max = 16;
	int const aux_cmd_native_max = 16;
	int const aux_cmd_i2c_max = 128;
	int const aux_cmd_i2c_max = 128;
	int const retry_count = 5;
	struct dp_aux_private *aux = container_of(drm_aux,
	struct dp_aux_private *aux = container_of(drm_aux,
		struct dp_aux_private, drm_aux);
		struct dp_aux_private, drm_aux);


@@ -270,8 +289,14 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux,
	}
	}


	ret = dp_aux_cmd_fifo_tx(aux, msg);
	ret = dp_aux_cmd_fifo_tx(aux, msg);
	if (ret < 0) {
	if ((ret < 0) && aux->native) {
		aux->catalog->reset(aux->catalog); /* reset aux */
		aux->retry_cnt++;
		if (!(aux->retry_cnt % retry_count))
			aux->catalog->update_aux_cfg(aux->catalog,
				aux->cfg, PHY_AUX_CFG1);
		aux->catalog->reset(aux->catalog);
		goto unlock_exit;
	} else if (ret < 0) {
		goto unlock_exit;
		goto unlock_exit;
	}
	}


@@ -289,6 +314,7 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux,


	/* Return requested size for success or retry */
	/* Return requested size for success or retry */
	ret = msg->size;
	ret = msg->size;
	aux->retry_cnt = 0;


unlock_exit:
unlock_exit:
	aux->cmd_busy = false;
	aux->cmd_busy = false;
@@ -317,6 +343,7 @@ static void dp_aux_init(struct dp_aux *dp_aux, struct dp_aux_cfg *aux_cfg)


	aux->catalog->reset(aux->catalog);
	aux->catalog->reset(aux->catalog);
	aux->catalog->enable(aux->catalog, true);
	aux->catalog->enable(aux->catalog, true);
	aux->retry_cnt = 0;
	dp_aux_reset_phy_config_indices(aux_cfg);
	dp_aux_reset_phy_config_indices(aux_cfg);
	aux->catalog->setup(aux->catalog, aux_cfg);
	aux->catalog->setup(aux->catalog, aux_cfg);
}
}
@@ -374,13 +401,14 @@ static void dp_aux_deregister(struct dp_aux *dp_aux)
	drm_dp_aux_unregister(&aux->drm_aux);
	drm_dp_aux_unregister(&aux->drm_aux);
}
}


struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog)
struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
		struct dp_aux_cfg *aux_cfg)
{
{
	int rc = 0;
	int rc = 0;
	struct dp_aux_private *aux;
	struct dp_aux_private *aux;
	struct dp_aux *dp_aux;
	struct dp_aux *dp_aux;


	if (!catalog) {
	if (!catalog || !aux_cfg) {
		pr_err("invalid input\n");
		pr_err("invalid input\n");
		rc = -ENODEV;
		rc = -ENODEV;
		goto error;
		goto error;
@@ -398,13 +426,16 @@ struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog)


	aux->dev = dev;
	aux->dev = dev;
	aux->catalog = catalog;
	aux->catalog = catalog;
	aux->cfg = aux_cfg;
	dp_aux = &aux->dp_aux;
	dp_aux = &aux->dp_aux;
	aux->retry_cnt = 0;


	dp_aux->isr     = dp_aux_isr;
	dp_aux->isr     = dp_aux_isr;
	dp_aux->init    = dp_aux_init;
	dp_aux->init    = dp_aux_init;
	dp_aux->deinit  = dp_aux_deinit;
	dp_aux->deinit  = dp_aux_deinit;
	dp_aux->drm_aux_register = dp_aux_register;
	dp_aux->drm_aux_register = dp_aux_register;
	dp_aux->drm_aux_deregister = dp_aux_deregister;
	dp_aux->drm_aux_deregister = dp_aux_deregister;
	dp_aux->reconfig = dp_aux_reconfig;


	return dp_aux;
	return dp_aux;
error:
error:
+3 −1
Original line number Original line Diff line number Diff line
@@ -34,9 +34,11 @@ struct dp_aux {
	void (*isr)(struct dp_aux *aux);
	void (*isr)(struct dp_aux *aux);
	void (*init)(struct dp_aux *aux, struct dp_aux_cfg *aux_cfg);
	void (*init)(struct dp_aux *aux, struct dp_aux_cfg *aux_cfg);
	void (*deinit)(struct dp_aux *aux);
	void (*deinit)(struct dp_aux *aux);
	void (*reconfig)(struct dp_aux *aux);
};
};


struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog);
struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
		struct dp_aux_cfg *aux_cfg);
void dp_aux_put(struct dp_aux *aux);
void dp_aux_put(struct dp_aux *aux);


#endif /*__DP_AUX_H_*/
#endif /*__DP_AUX_H_*/
+25 −0
Original line number Original line Diff line number Diff line
@@ -364,6 +364,30 @@ static void dp_catalog_aux_enable(struct dp_catalog_aux *aux, bool enable)
	dp_write(base + DP_AUX_CTRL, aux_ctrl);
	dp_write(base + DP_AUX_CTRL, aux_ctrl);
}
}


static void dp_catalog_aux_update_cfg(struct dp_catalog_aux *aux,
		struct dp_aux_cfg *cfg, enum dp_phy_aux_config_type type)
{
	struct dp_catalog_private *catalog;
	u32 new_index = 0, current_index = 0;

	if (!aux || !cfg || (type >= PHY_AUX_CFG_MAX)) {
		pr_err("invalid input\n");
		return;
	}

	dp_catalog_get_priv(aux);

	current_index = cfg[type].current_index;
	new_index = (current_index + 1) % cfg[type].cfg_cnt;
	pr_debug("Updating %s from 0x%08x to 0x%08x\n",
		dp_phy_aux_config_type_to_string(type),
	cfg[type].lut[current_index], cfg[type].lut[new_index]);

	dp_write(catalog->io->phy_io.base + cfg[type].offset,
			cfg[type].lut[new_index]);
	cfg[type].current_index = new_index;
}

static void dp_catalog_aux_setup(struct dp_catalog_aux *aux,
static void dp_catalog_aux_setup(struct dp_catalog_aux *aux,
		struct dp_aux_cfg *cfg)
		struct dp_aux_cfg *cfg)
{
{
@@ -895,6 +919,7 @@ struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io)
		.write_data    = dp_catalog_aux_write_data,
		.write_data    = dp_catalog_aux_write_data,
		.write_trans   = dp_catalog_aux_write_trans,
		.write_trans   = dp_catalog_aux_write_trans,
		.reset         = dp_catalog_aux_reset,
		.reset         = dp_catalog_aux_reset,
		.update_aux_cfg = dp_catalog_aux_update_cfg,
		.enable        = dp_catalog_aux_enable,
		.enable        = dp_catalog_aux_enable,
		.setup         = dp_catalog_aux_setup,
		.setup         = dp_catalog_aux_setup,
		.get_irq       = dp_catalog_aux_get_irq,
		.get_irq       = dp_catalog_aux_get_irq,
+2 −0
Original line number Original line Diff line number Diff line
@@ -43,6 +43,8 @@ struct dp_catalog_aux {
	int (*write_trans)(struct dp_catalog_aux *aux);
	int (*write_trans)(struct dp_catalog_aux *aux);
	void (*reset)(struct dp_catalog_aux *aux);
	void (*reset)(struct dp_catalog_aux *aux);
	void (*enable)(struct dp_catalog_aux *aux, bool enable);
	void (*enable)(struct dp_catalog_aux *aux, bool enable);
	void (*update_aux_cfg)(struct dp_catalog_aux *aux,
		struct dp_aux_cfg *cfg, enum dp_phy_aux_config_type type);
	void (*setup)(struct dp_catalog_aux *aux,
	void (*setup)(struct dp_catalog_aux *aux,
			struct dp_aux_cfg *aux_cfg);
			struct dp_aux_cfg *aux_cfg);
	void (*get_irq)(struct dp_catalog_aux *aux, bool cmd_busy);
	void (*get_irq)(struct dp_catalog_aux *aux, bool cmd_busy);
+2 −5
Original line number Original line Diff line number Diff line
@@ -252,13 +252,10 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp)
	int rc = 0;
	int rc = 0;
	u32 max_pclk_from_edid = 0;
	u32 max_pclk_from_edid = 0;


	rc = dp->panel->read_dpcd(dp->panel);
	rc = dp->panel->read_sink_caps(dp->panel, dp->dp_display.connector);
	if (rc)
	if (rc)
		return rc;
		return rc;


	sde_get_edid(dp->dp_display.connector, &dp->aux->drm_aux->ddc,
		(void **)&dp->panel->edid_ctrl);

	max_pclk_from_edid = dp->panel->get_max_pclk(dp->panel);
	max_pclk_from_edid = dp->panel->get_max_pclk(dp->panel);


	dp->dp_display.max_pclk_khz = min(max_pclk_from_edid,
	dp->dp_display.max_pclk_khz = min(max_pclk_from_edid,
@@ -468,7 +465,7 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
		goto err;
		goto err;
	}
	}


	dp->aux = dp_aux_get(dev, &dp->catalog->aux);
	dp->aux = dp_aux_get(dev, &dp->catalog->aux, dp->parser->aux_cfg);
	if (IS_ERR(dp->aux)) {
	if (IS_ERR(dp->aux)) {
		rc = PTR_ERR(dp->aux);
		rc = PTR_ERR(dp->aux);
		pr_err("failed to initialize aux, rc = %d\n", rc);
		pr_err("failed to initialize aux, rc = %d\n", rc);
Loading