Skip to content

Commit

Permalink
ata: ahci_ceva: fix error handling for Xilinx GT PHY support
Browse files Browse the repository at this point in the history
[ Upstream commit 26c8404 ]

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: 9a9d3ab ("ata: ahci: ceva: Update the driver to support xilinx GT phy")
Signed-off-by: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Signed-off-by: Niklas Cassel <cassel@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
Radhey Shyam Pandey authored and gregkh committed Mar 1, 2024
1 parent 3e83197 commit d4c5876
Showing 1 changed file with 79 additions and 46 deletions.
125 changes: 79 additions & 46 deletions drivers/ata/ahci_ceva.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -189,6 +188,60 @@ static const struct scsi_host_template ahci_platform_sht = {
AHCI_SHT(DRV_NAME),
};

static int ceva_ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
{
int rc, i;

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

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

/* Assert the controller reset */
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)
goto disable_rsts;
}

/* De-assert the controller reset */
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]);
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;
Expand All @@ -203,47 +256,19 @@ static int ceva_ahci_probe(struct platform_device *pdev)
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);

if (!cevapriv->rst) {
rc = ahci_platform_enable_resources(hpriv);
if (rc)
return rc;
} else {
int i;
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 = ahci_platform_enable_clks(hpriv);
if (rc)
return rc;
/* Assert the controller reset */
reset_control_assert(cevapriv->rst);

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

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

for (i = 0; i < hpriv->nports; i++) {
rc = phy_power_on(hpriv->phys[i]);
if (rc) {
phy_exit(hpriv->phys[i]);
return rc;
}
}
}
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;
Expand All @@ -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;
}

/*
Expand Down Expand Up @@ -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;

Expand Down

0 comments on commit d4c5876

Please sign in to comment.