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: 9a9d3abe24
("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>
This commit is contained in:
parent
9815e39617
commit
26c8404e16
@ -88,7 +88,6 @@ struct ceva_ahci_priv {
|
|||||||
u32 axicc;
|
u32 axicc;
|
||||||
bool is_cci_enabled;
|
bool is_cci_enabled;
|
||||||
int flags;
|
int flags;
|
||||||
struct reset_control *rst;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static unsigned int ceva_ahci_read_id(struct ata_device *dev,
|
static unsigned int ceva_ahci_read_id(struct ata_device *dev,
|
||||||
@ -189,6 +188,60 @@ static const struct scsi_host_template ahci_platform_sht = {
|
|||||||
AHCI_SHT(DRV_NAME),
|
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)
|
static int ceva_ahci_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device_node *np = pdev->dev.of_node;
|
struct device_node *np = pdev->dev.of_node;
|
||||||
@ -203,47 +256,19 @@ static int ceva_ahci_probe(struct platform_device *pdev)
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
cevapriv->ahci_pdev = pdev;
|
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);
|
hpriv = ahci_platform_get_resources(pdev, 0);
|
||||||
if (IS_ERR(hpriv))
|
if (IS_ERR(hpriv))
|
||||||
return PTR_ERR(hpriv);
|
return PTR_ERR(hpriv);
|
||||||
|
|
||||||
if (!cevapriv->rst) {
|
hpriv->rsts = devm_reset_control_get_optional_exclusive(&pdev->dev,
|
||||||
rc = ahci_platform_enable_resources(hpriv);
|
NULL);
|
||||||
if (rc)
|
if (IS_ERR(hpriv->rsts))
|
||||||
return rc;
|
return dev_err_probe(&pdev->dev, PTR_ERR(hpriv->rsts),
|
||||||
} else {
|
"failed to get reset\n");
|
||||||
int i;
|
|
||||||
|
|
||||||
rc = ahci_platform_enable_clks(hpriv);
|
rc = ceva_ahci_platform_enable_resources(hpriv);
|
||||||
if (rc)
|
if (rc)
|
||||||
return 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (of_property_read_bool(np, "ceva,broken-gen2"))
|
if (of_property_read_bool(np, "ceva,broken-gen2"))
|
||||||
cevapriv->flags = CEVA_FLAG_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",
|
if (of_property_read_u8_array(np, "ceva,p0-cominit-params",
|
||||||
(u8 *)&cevapriv->pp2c[0], 4) < 0) {
|
(u8 *)&cevapriv->pp2c[0], 4) < 0) {
|
||||||
dev_warn(dev, "ceva,p0-cominit-params property not defined\n");
|
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",
|
if (of_property_read_u8_array(np, "ceva,p1-cominit-params",
|
||||||
(u8 *)&cevapriv->pp2c[1], 4) < 0) {
|
(u8 *)&cevapriv->pp2c[1], 4) < 0) {
|
||||||
dev_warn(dev, "ceva,p1-cominit-params property not defined\n");
|
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*/
|
/* Read OOB timing value for COMWAKE from device-tree*/
|
||||||
if (of_property_read_u8_array(np, "ceva,p0-comwake-params",
|
if (of_property_read_u8_array(np, "ceva,p0-comwake-params",
|
||||||
(u8 *)&cevapriv->pp3c[0], 4) < 0) {
|
(u8 *)&cevapriv->pp3c[0], 4) < 0) {
|
||||||
dev_warn(dev, "ceva,p0-comwake-params property not defined\n");
|
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",
|
if (of_property_read_u8_array(np, "ceva,p1-comwake-params",
|
||||||
(u8 *)&cevapriv->pp3c[1], 4) < 0) {
|
(u8 *)&cevapriv->pp3c[1], 4) < 0) {
|
||||||
dev_warn(dev, "ceva,p1-comwake-params property not defined\n");
|
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 */
|
/* Read phy BURST timing value from device-tree */
|
||||||
if (of_property_read_u8_array(np, "ceva,p0-burst-params",
|
if (of_property_read_u8_array(np, "ceva,p0-burst-params",
|
||||||
(u8 *)&cevapriv->pp4c[0], 4) < 0) {
|
(u8 *)&cevapriv->pp4c[0], 4) < 0) {
|
||||||
dev_warn(dev, "ceva,p0-burst-params property not defined\n");
|
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",
|
if (of_property_read_u8_array(np, "ceva,p1-burst-params",
|
||||||
(u8 *)&cevapriv->pp4c[1], 4) < 0) {
|
(u8 *)&cevapriv->pp4c[1], 4) < 0) {
|
||||||
dev_warn(dev, "ceva,p1-burst-params property not defined\n");
|
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 */
|
/* Read phy RETRY interval timing value from device-tree */
|
||||||
if (of_property_read_u16_array(np, "ceva,p0-retry-params",
|
if (of_property_read_u16_array(np, "ceva,p0-retry-params",
|
||||||
(u16 *)&cevapriv->pp5c[0], 2) < 0) {
|
(u16 *)&cevapriv->pp5c[0], 2) < 0) {
|
||||||
dev_warn(dev, "ceva,p0-retry-params property not defined\n");
|
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",
|
if (of_property_read_u16_array(np, "ceva,p1-retry-params",
|
||||||
(u16 *)&cevapriv->pp5c[1], 2) < 0) {
|
(u16 *)&cevapriv->pp5c[1], 2) < 0) {
|
||||||
dev_warn(dev, "ceva,p1-retry-params property not defined\n");
|
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;
|
struct ahci_host_priv *hpriv = host->private_data;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = ahci_platform_enable_resources(hpriv);
|
rc = ceva_ahci_platform_enable_resources(hpriv);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user