diff options
author | Preetham Chandru R <pchandru@nvidia.com> | 2016-06-10 05:27:18 -0400 |
---|---|---|
committer | Preetham Chandru R <pchandru@nvidia.com> | 2017-08-21 05:16:34 -0400 |
commit | 4a851ae145a82d3b7a7a4e3311ca56d68f9d5bed (patch) | |
tree | fc6e0c161cc95a9cfc0b823678c4919ce37e9345 /drivers/ata | |
parent | 4ed89d15ea82e5325638c74ce95a37e2435765dc (diff) |
ata: ahci_tegra: Inetgrate with upstream RTPM
Bug 200207932
Change-Id: I68957d41f2b9fc06ae0a599b13c86a1d7b1999da
Signed-off-by: Preetham Chandru R <pchandru@nvidia.com>
Reviewed-on: http://git-master/r/1164717
(cherry picked from commit de3089dd3ead92df9cb6b879eb25f508de8ed686)
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/tegra/ahci_tegra.c | 123 | ||||
-rw-r--r-- | drivers/ata/tegra/ahci_tegra.h | 1 |
2 files changed, 6 insertions, 118 deletions
diff --git a/drivers/ata/tegra/ahci_tegra.c b/drivers/ata/tegra/ahci_tegra.c index 65bd546e3..97efb7684 100644 --- a/drivers/ata/tegra/ahci_tegra.c +++ b/drivers/ata/tegra/ahci_tegra.c | |||
@@ -80,6 +80,9 @@ static int tegra_ahci_port_suspend(struct ata_port *ap, pm_message_t mesg) | |||
80 | lpm_state = TEGRA_AHCI_PORT_RUNTIME_ACTIVE; | 80 | lpm_state = TEGRA_AHCI_PORT_RUNTIME_ACTIVE; |
81 | tegra->skip_rtpm = false; | 81 | tegra->skip_rtpm = false; |
82 | 82 | ||
83 | if (!ata_dev_enabled(ap->link.device)) | ||
84 | goto skip; | ||
85 | |||
83 | port_status = tegra_ahci_bar5_readl(hpriv, T_AHCI_PORT_PXSSTS); | 86 | port_status = tegra_ahci_bar5_readl(hpriv, T_AHCI_PORT_PXSSTS); |
84 | port_status = (port_status & T_AHCI_PORT_PXSSTS_IPM_MASK) >> | 87 | port_status = (port_status & T_AHCI_PORT_PXSSTS_IPM_MASK) >> |
85 | T_AHCI_PORT_PXSSTS_IPM_SHIFT; | 88 | T_AHCI_PORT_PXSSTS_IPM_SHIFT; |
@@ -146,13 +149,10 @@ static int tegra_ahci_port_suspend(struct ata_port *ap, pm_message_t mesg) | |||
146 | return 0; | 149 | return 0; |
147 | } | 150 | } |
148 | } | 151 | } |
152 | skip: | ||
149 | 153 | ||
150 | if (!ret && !(ap->pflags & ATA_PFLAG_SUSPENDED)) { | 154 | if (!ret && !(ap->pflags & ATA_PFLAG_SUSPENDED)) { |
151 | ret = ahci_ops.port_suspend(ap, mesg); | 155 | ret = ahci_ops.port_suspend(ap, mesg); |
152 | if (ret == 0) { | ||
153 | pm_runtime_mark_last_busy(&tegra->pdev->dev); | ||
154 | pm_runtime_put_sync_autosuspend(&tegra->pdev->dev); | ||
155 | } | ||
156 | } | 156 | } |
157 | 157 | ||
158 | return ret; | 158 | return ret; |
@@ -175,14 +175,6 @@ static int tegra_ahci_port_resume(struct ata_port *ap) | |||
175 | return 0; | 175 | return 0; |
176 | } | 176 | } |
177 | 177 | ||
178 | ret = pm_runtime_get_sync(&tegra->pdev->dev); | ||
179 | if (ret < 0) { | ||
180 | dev_err(&tegra->pdev->dev, | ||
181 | "%s(%d) Failed to resume the devcie err=%d\n", | ||
182 | __func__, __LINE__, ret); | ||
183 | return AC_ERR_SYSTEM; | ||
184 | } | ||
185 | |||
186 | if (ap->pm_mesg.event & PM_EVENT_RESUME) { | 178 | if (ap->pm_mesg.event & PM_EVENT_RESUME) { |
187 | if (ap->pm_mesg.event & PM_EVENT_AUTO) | 179 | if (ap->pm_mesg.event & PM_EVENT_AUTO) |
188 | ata_for_each_link(link, ap, HOST_FIRST) { | 180 | ata_for_each_link(link, ap, HOST_FIRST) { |
@@ -1300,89 +1292,6 @@ static void tegra_ahci_shutdown(struct platform_device *pdev) | |||
1300 | } | 1292 | } |
1301 | } | 1293 | } |
1302 | 1294 | ||
1303 | /* | ||
1304 | This function is similar to ahci_enable_ahci which is | ||
1305 | defined in libahci.c. | ||
1306 | Since tegra_ahci_enable needs to be called before a | ||
1307 | host is allocated we will not be able to call ahci_enable_ahci | ||
1308 | */ | ||
1309 | |||
1310 | static void tegra_ahci_enable(struct ahci_host_priv *hpriv) | ||
1311 | { | ||
1312 | int i; | ||
1313 | u32 tmp; | ||
1314 | u32 val; | ||
1315 | u32 mask; | ||
1316 | |||
1317 | /* turn on AHCI_EN */ | ||
1318 | tmp = tegra_ahci_bar5_readl(hpriv, T_AHCI_HBA_GHC); | ||
1319 | if (tmp & HOST_AHCI_EN) | ||
1320 | return; | ||
1321 | |||
1322 | /* Some controllers need AHCI_EN to be written multiple times. | ||
1323 | * Try a few times before giving up. | ||
1324 | */ | ||
1325 | for (i = 0; i < 5; i++) { | ||
1326 | val = mask = T_AHCI_HBA_GHC_AE; | ||
1327 | tegra_ahci_bar5_update(hpriv, val, mask, T_AHCI_HBA_GHC); | ||
1328 | tmp = tegra_ahci_bar5_readl(hpriv, T_AHCI_HBA_GHC); | ||
1329 | if (tmp & T_AHCI_HBA_GHC_AE) | ||
1330 | return; | ||
1331 | msleep(10); | ||
1332 | } | ||
1333 | |||
1334 | WARN_ON(1); | ||
1335 | } | ||
1336 | |||
1337 | /* | ||
1338 | This function is similar to ahci_reset_controller which is | ||
1339 | defined in libahci.c. | ||
1340 | Since tegra_ahci_reset_controller needs to be called before a | ||
1341 | host is allocated we will not be able to call ahci_reset_controller | ||
1342 | */ | ||
1343 | static int tegra_ahci_reset_controller(struct ahci_host_priv *hpriv) | ||
1344 | { | ||
1345 | struct tegra_ahci_priv *tegra = hpriv->plat_data; | ||
1346 | void __iomem *mmio = tegra->base_list[TEGRA_SATA_AHCI]; | ||
1347 | struct platform_device *pdev = tegra->pdev; | ||
1348 | struct device *dev = &pdev->dev; | ||
1349 | u32 tmp; | ||
1350 | u32 val; | ||
1351 | u32 mask; | ||
1352 | |||
1353 | /* we must be in AHCI mode, before using anything | ||
1354 | * AHCI-specific, such as HOST_RESET. | ||
1355 | */ | ||
1356 | tegra_ahci_enable(hpriv); | ||
1357 | |||
1358 | /* global controller reset */ | ||
1359 | tmp = tegra_ahci_bar5_readl(hpriv, T_AHCI_HBA_GHC); | ||
1360 | if ((tmp & T_AHCI_HBA_GHC_HR) == 0) { | ||
1361 | val = mask = T_AHCI_HBA_GHC_HR; | ||
1362 | tegra_ahci_bar5_update(hpriv, val, mask, T_AHCI_HBA_GHC); | ||
1363 | |||
1364 | tmp = tegra_ahci_bar5_readl(hpriv, T_AHCI_HBA_GHC); | ||
1365 | } | ||
1366 | |||
1367 | /* | ||
1368 | * to perform host reset, OS should set HOST_RESET | ||
1369 | * and poll until this bit is read to be "0". | ||
1370 | * reset must complete within 1 second, or | ||
1371 | * the hardware should be considered fried. | ||
1372 | */ | ||
1373 | tmp = ata_wait_register(NULL, mmio + HOST_CTL, HOST_RESET, | ||
1374 | HOST_RESET, 10, 1000); | ||
1375 | |||
1376 | if (tmp & T_AHCI_HBA_GHC_HR) { | ||
1377 | dev_err(dev, "controller reset failed (0x%x)\n", | ||
1378 | tmp); | ||
1379 | return -EIO; | ||
1380 | } | ||
1381 | mdelay(20); | ||
1382 | |||
1383 | return 0; | ||
1384 | } | ||
1385 | |||
1386 | static int tegra_ahci_probe(struct platform_device *pdev) | 1295 | static int tegra_ahci_probe(struct platform_device *pdev) |
1387 | { | 1296 | { |
1388 | struct ahci_host_priv *hpriv; | 1297 | struct ahci_host_priv *hpriv; |
@@ -1418,20 +1327,6 @@ static int tegra_ahci_probe(struct platform_device *pdev) | |||
1418 | if (ret) | 1327 | if (ret) |
1419 | goto poweroff_controller; | 1328 | goto poweroff_controller; |
1420 | 1329 | ||
1421 | ret = tegra_ahci_reset_controller(hpriv); | ||
1422 | if (ret) | ||
1423 | goto poweroff_controller; | ||
1424 | |||
1425 | if (!tegra_ahci_bar5_readl(hpriv, T_AHCI_PORT_PXSSTS)) { | ||
1426 | struct platform_driver *drv = | ||
1427 | to_platform_driver(pdev->dev.driver); | ||
1428 | |||
1429 | dev_info(&pdev->dev, "Drive not present\n"); | ||
1430 | drv->driver.pm = NULL; | ||
1431 | ret = -ENODEV; | ||
1432 | goto poweroff_controller; | ||
1433 | } | ||
1434 | |||
1435 | 1330 | ||
1436 | ret = ahci_platform_init_host(pdev, hpriv, &ahci_tegra_port_info, | 1331 | ret = ahci_platform_init_host(pdev, hpriv, &ahci_tegra_port_info, |
1437 | &ahci_platform_sht); | 1332 | &ahci_platform_sht); |
@@ -1446,17 +1341,11 @@ static int tegra_ahci_probe(struct platform_device *pdev) | |||
1446 | } | 1341 | } |
1447 | 1342 | ||
1448 | ret = pm_runtime_set_active(&pdev->dev); | 1343 | ret = pm_runtime_set_active(&pdev->dev); |
1449 | if (ret) { | 1344 | if (ret) |
1450 | dev_dbg(&pdev->dev, "unable to set runtime pm active err=%d\n", | 1345 | dev_dbg(&pdev->dev, "unable to set runtime pm active err=%d\n", |
1451 | ret); | 1346 | ret); |
1452 | } else { | 1347 | else |
1453 | pm_runtime_set_autosuspend_delay(&pdev->dev, | ||
1454 | TEGRA_AHCI_DEFAULT_IDLE_TIME); | ||
1455 | pm_runtime_use_autosuspend(&pdev->dev); | ||
1456 | pm_suspend_ignore_children(&pdev->dev, true); | ||
1457 | pm_runtime_get_noresume(&pdev->dev); | ||
1458 | pm_runtime_enable(&pdev->dev); | 1348 | pm_runtime_enable(&pdev->dev); |
1459 | } | ||
1460 | 1349 | ||
1461 | #ifdef CONFIG_DEBUG_FS | 1350 | #ifdef CONFIG_DEBUG_FS |
1462 | tegra_ahci_dump_debuginit(hpriv); | 1351 | tegra_ahci_dump_debuginit(hpriv); |
diff --git a/drivers/ata/tegra/ahci_tegra.h b/drivers/ata/tegra/ahci_tegra.h index ca4d4bac9..5bcb0bcf1 100644 --- a/drivers/ata/tegra/ahci_tegra.h +++ b/drivers/ata/tegra/ahci_tegra.h | |||
@@ -172,7 +172,6 @@ | |||
172 | #define PMC_IMPL_SATA_PWRGT_0_PG_INFO BIT(6) | 172 | #define PMC_IMPL_SATA_PWRGT_0_PG_INFO BIT(6) |
173 | 173 | ||
174 | #define TEGRA_AHCI_MAX_CLKS 2 | 174 | #define TEGRA_AHCI_MAX_CLKS 2 |
175 | #define TEGRA_AHCI_DEFAULT_IDLE_TIME 10000 | ||
176 | #define TEGRA_AHCI_LPM_TIMEOUT 500 | 175 | #define TEGRA_AHCI_LPM_TIMEOUT 500 |
177 | 176 | ||
178 | #define TEGRA_AHCI_READ_LOG_EXT_NOENTRY 0x80 | 177 | #define TEGRA_AHCI_READ_LOG_EXT_NOENTRY 0x80 |