Commit 26c8404e authored by Radhey Shyam Pandey's avatar Radhey Shyam Pandey Committed by Niklas Cassel
Browse files

ata: ahci_ceva: fix error handling for Xilinx GT PHY support



Platform clock and phy error resources are not cleaned up in Xilinx GT PHY
error path.

To fix introduce the function ceva_ahci_platform_enable_resources() which
is a customized version of ahci_platform_enable_resources() and inline with
SATA IP programming sequence it does:

- Assert SATA reset
- Program PS GTR phy
- Bring SATA by de-asserting the reset
- Wait for GT lane PLL to be locked

ceva_ahci_platform_enable_resources() is also used in the resume path
as the same SATA programming sequence (as in probe) should be followed.
Also cleanup the mixed usage of ahci_platform_enable_resources() and custom
implementation in the probe function as both are not required.

Fixes: 9a9d3abe ("ata: ahci: ceva: Update the driver to support xilinx GT phy")
Signed-off-by: default avatarRadhey Shyam Pandey <radhey.shyam.pandey@amd.com>
Reviewed-by: default avatarDamien Le Moal <dlemoal@kernel.org>
Signed-off-by: default avatarNiklas Cassel <cassel@kernel.org>
parent 9815e396
Loading
Loading
Loading
Loading
+79 −46
Original line number Diff line number Diff line
@@ -88,7 +88,6 @@ struct ceva_ahci_priv {
	u32 axicc;
	bool is_cci_enabled;
	int flags;
	struct reset_control *rst;
};

static unsigned int ceva_ahci_read_id(struct ata_device *dev,
@@ -189,62 +188,88 @@ static const struct scsi_host_template ahci_platform_sht = {
	AHCI_SHT(DRV_NAME),
};

static int ceva_ahci_probe(struct platform_device *pdev)
static int ceva_ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
{
	struct device_node *np = pdev->dev.of_node;
	struct device *dev = &pdev->dev;
	struct ahci_host_priv *hpriv;
	struct ceva_ahci_priv *cevapriv;
	enum dev_dma_attr attr;
	int rc;

	cevapriv = devm_kzalloc(dev, sizeof(*cevapriv), GFP_KERNEL);
	if (!cevapriv)
		return -ENOMEM;

	cevapriv->ahci_pdev = pdev;

	cevapriv->rst = devm_reset_control_get_optional_exclusive(&pdev->dev,
								  NULL);
	if (IS_ERR(cevapriv->rst))
		dev_err_probe(&pdev->dev, PTR_ERR(cevapriv->rst),
			      "failed to get reset\n");

	hpriv = ahci_platform_get_resources(pdev, 0);
	if (IS_ERR(hpriv))
		return PTR_ERR(hpriv);
	int rc, i;

	if (!cevapriv->rst) {
		rc = ahci_platform_enable_resources(hpriv);
	rc = ahci_platform_enable_regulators(hpriv);
	if (rc)
		return rc;
	} else {
		int i;

	rc = ahci_platform_enable_clks(hpriv);
	if (rc)
			return rc;
		goto disable_regulator;

	/* Assert the controller reset */
		reset_control_assert(cevapriv->rst);
	rc = ahci_platform_assert_rsts(hpriv);
	if (rc)
		goto disable_clks;

	for (i = 0; i < hpriv->nports; i++) {
		rc = phy_init(hpriv->phys[i]);
		if (rc)
				return rc;
			goto disable_rsts;
	}

	/* De-assert the controller reset */
		reset_control_deassert(cevapriv->rst);
	ahci_platform_deassert_rsts(hpriv);

	for (i = 0; i < hpriv->nports; i++) {
		rc = phy_power_on(hpriv->phys[i]);
		if (rc) {
			phy_exit(hpriv->phys[i]);
				return rc;
			goto disable_phys;
		}
	}

	return 0;

disable_rsts:
	ahci_platform_deassert_rsts(hpriv);

disable_phys:
	while (--i >= 0) {
		phy_power_off(hpriv->phys[i]);
		phy_exit(hpriv->phys[i]);
	}

disable_clks:
	ahci_platform_disable_clks(hpriv);

disable_regulator:
	ahci_platform_disable_regulators(hpriv);

	return rc;
}

static int ceva_ahci_probe(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
	struct device *dev = &pdev->dev;
	struct ahci_host_priv *hpriv;
	struct ceva_ahci_priv *cevapriv;
	enum dev_dma_attr attr;
	int rc;

	cevapriv = devm_kzalloc(dev, sizeof(*cevapriv), GFP_KERNEL);
	if (!cevapriv)
		return -ENOMEM;

	cevapriv->ahci_pdev = pdev;
	hpriv = ahci_platform_get_resources(pdev, 0);
	if (IS_ERR(hpriv))
		return PTR_ERR(hpriv);

	hpriv->rsts = devm_reset_control_get_optional_exclusive(&pdev->dev,
								NULL);
	if (IS_ERR(hpriv->rsts))
		return dev_err_probe(&pdev->dev, PTR_ERR(hpriv->rsts),
				     "failed to get reset\n");

	rc = ceva_ahci_platform_enable_resources(hpriv);
	if (rc)
		return rc;

	if (of_property_read_bool(np, "ceva,broken-gen2"))
		cevapriv->flags = CEVA_FLAG_BROKEN_GEN2;

@@ -252,52 +277,60 @@ static int ceva_ahci_probe(struct platform_device *pdev)
	if (of_property_read_u8_array(np, "ceva,p0-cominit-params",
					(u8 *)&cevapriv->pp2c[0], 4) < 0) {
		dev_warn(dev, "ceva,p0-cominit-params property not defined\n");
		return -EINVAL;
		rc = -EINVAL;
		goto disable_resources;
	}

	if (of_property_read_u8_array(np, "ceva,p1-cominit-params",
					(u8 *)&cevapriv->pp2c[1], 4) < 0) {
		dev_warn(dev, "ceva,p1-cominit-params property not defined\n");
		return -EINVAL;
		rc = -EINVAL;
		goto disable_resources;
	}

	/* Read OOB timing value for COMWAKE from device-tree*/
	if (of_property_read_u8_array(np, "ceva,p0-comwake-params",
					(u8 *)&cevapriv->pp3c[0], 4) < 0) {
		dev_warn(dev, "ceva,p0-comwake-params property not defined\n");
		return -EINVAL;
		rc = -EINVAL;
		goto disable_resources;
	}

	if (of_property_read_u8_array(np, "ceva,p1-comwake-params",
					(u8 *)&cevapriv->pp3c[1], 4) < 0) {
		dev_warn(dev, "ceva,p1-comwake-params property not defined\n");
		return -EINVAL;
		rc = -EINVAL;
		goto disable_resources;
	}

	/* Read phy BURST timing value from device-tree */
	if (of_property_read_u8_array(np, "ceva,p0-burst-params",
					(u8 *)&cevapriv->pp4c[0], 4) < 0) {
		dev_warn(dev, "ceva,p0-burst-params property not defined\n");
		return -EINVAL;
		rc = -EINVAL;
		goto disable_resources;
	}

	if (of_property_read_u8_array(np, "ceva,p1-burst-params",
					(u8 *)&cevapriv->pp4c[1], 4) < 0) {
		dev_warn(dev, "ceva,p1-burst-params property not defined\n");
		return -EINVAL;
		rc = -EINVAL;
		goto disable_resources;
	}

	/* Read phy RETRY interval timing value from device-tree */
	if (of_property_read_u16_array(np, "ceva,p0-retry-params",
					(u16 *)&cevapriv->pp5c[0], 2) < 0) {
		dev_warn(dev, "ceva,p0-retry-params property not defined\n");
		return -EINVAL;
		rc = -EINVAL;
		goto disable_resources;
	}

	if (of_property_read_u16_array(np, "ceva,p1-retry-params",
					(u16 *)&cevapriv->pp5c[1], 2) < 0) {
		dev_warn(dev, "ceva,p1-retry-params property not defined\n");
		return -EINVAL;
		rc = -EINVAL;
		goto disable_resources;
	}

	/*
@@ -335,7 +368,7 @@ static int __maybe_unused ceva_ahci_resume(struct device *dev)
	struct ahci_host_priv *hpriv = host->private_data;
	int rc;

	rc = ahci_platform_enable_resources(hpriv);
	rc = ceva_ahci_platform_enable_resources(hpriv);
	if (rc)
		return rc;