| @@ -76,8 +76,7 @@ enum brcm_ahci_version { · 75 unmodified lines |
| 76 | 76 | }; |
| 77 | 77 | |
| 78 | 78 | enum brcm_ahci_quirks { |
| 79 | | − BRCM_AHCI_QUIRK_NO_NCQ = BIT(0), |
| 80 | | − BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE = BIT(1), |
| 79 | + BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE = BIT(0), |
| 81 | 80 | }; |
| 82 | 81 | |
| 83 | 82 | struct brcm_ahci_priv { |
| @@ -213,19 +212,12 @@ static void brcm_sata_phys_disable(struct brcm_ahci_priv *priv) · 129 unmodified lines |
| 213 | 212 | brcm_sata_phy_disable(priv, i); |
| 214 | 213 | } |
| 215 | 214 | |
| 216 | | −static u32 brcm_ahci_get_portmask(struct platform_device *pdev, |
| 215 | +static u32 brcm_ahci_get_portmask(struct ahci_host_priv *hpriv, |
| 217 | 216 | struct brcm_ahci_priv *priv) |
| 218 | 217 | { |
| 219 | | − void __iomem *ahci; |
| 220 | | − struct resource *res; |
| 221 | 218 | u32 impl; |
| 222 | 219 | |
| 223 | | − res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ahci"); |
| 224 | | − ahci = devm_ioremap_resource(&pdev->dev, res); |
| 225 | | − if (IS_ERR(ahci)) |
| 226 | | − return 0; |
| 227 | | − |
| 228 | | − impl = readl(ahci + HOST_PORTS_IMPL); |
| 220 | + impl = readl(hpriv->mmio + HOST_PORTS_IMPL); |
| 229 | 221 | |
| 230 | 222 | if (fls(impl) > SATA_TOP_MAX_PHYS) |
| 231 | 223 | dev_warn(priv->dev, "warning: more ports than PHYs (%#x)\n", |
| @@ -233,9 +225,6 @@ static u32 brcm_ahci_get_portmask(struct platform_device *pdev, · 1 unmodified line |
| 233 | 225 | else if (!impl) |
| 234 | 226 | dev_info(priv->dev, "no ports found\n"); |
| 235 | 227 | |
| 236 | | − devm_iounmap(&pdev->dev, ahci); |
| 237 | | − devm_release_mem_region(&pdev->dev, res->start, resource_size(res)); |
| 238 | | − |
| 239 | 228 | return impl; |
| 240 | 229 | } |
| 241 | 230 | |
| @@ -285,6 +274,13 @@ static unsigned int brcm_ahci_read_id(struct ata_device *dev, · 43 unmodified lines |
| 285 | 274 | /* Perform the SATA PHY reset sequence */ |
| 286 | 275 | brcm_sata_phy_disable(priv, ap->port_no); |
| 287 | 276 | |
| 277 | + /* Reset the SATA clock */ |
| 278 | + ahci_platform_disable_clks(hpriv); |
| 279 | + msleep(10); |
| 280 | + |
| 281 | + ahci_platform_enable_clks(hpriv); |
| 282 | + msleep(10); |
| 283 | + |
| 288 | 284 | /* Bring the PHY back on */ |
| 289 | 285 | brcm_sata_phy_enable(priv, ap->port_no); |
| 290 | 286 | |
| @@ -347,11 +343,10 @@ static int brcm_ahci_suspend(struct device *dev) · 56 unmodified lines |
| 347 | 343 | struct ata_host *host = dev_get_drvdata(dev); |
| 348 | 344 | struct ahci_host_priv *hpriv = host->private_data; |
| 349 | 345 | struct brcm_ahci_priv *priv = hpriv->plat_data; |
| 350 | | − int ret; |
| 351 | 346 | |
| 352 | | − ret = ahci_platform_suspend(dev); |
| 353 | 347 | brcm_sata_phys_disable(priv); |
| 354 | | − return ret; |
| 348 | + |
| 349 | + return ahci_platform_suspend(dev); |
| 355 | 350 | } |
| 356 | 351 | |
| 357 | 352 | static int brcm_ahci_resume(struct device *dev) |
| @@ -359,11 +354,44 @@ static int brcm_ahci_resume(struct device *dev) · 1 unmodified line |
| 359 | 354 | struct ata_host *host = dev_get_drvdata(dev); |
| 360 | 355 | struct ahci_host_priv *hpriv = host->private_data; |
| 361 | 356 | struct brcm_ahci_priv *priv = hpriv->plat_data; |
| 357 | + int ret; |
| 358 | + |
| 359 | + /* Make sure clocks are turned on before re-configuration */ |
| 360 | + ret = ahci_platform_enable_clks(hpriv); |
| 361 | + if (ret) |
| 362 | + return ret; |
| 362 | 363 | |
| 363 | 364 | brcm_sata_init(priv); |
| 364 | 365 | brcm_sata_phys_enable(priv); |
| 365 | 366 | brcm_sata_alpm_init(hpriv); |
| 366 | | − return ahci_platform_resume(dev); |
| 367 | + |
| 368 | + /* Since we had to enable clocks earlier on, we cannot use |
| 369 | + * ahci_platform_resume() as-is since a second call to |
| 370 | + * ahci_platform_enable_resources() would bump up the resources |
| 371 | + * (regulators, clocks, PHYs) count artificially so we copy the part |
| 372 | + * after ahci_platform_enable_resources(). |
| 373 | + */ |
| 374 | + ret = ahci_platform_enable_phys(hpriv); |
| 375 | + if (ret) |
| 376 | + goto out_disable_phys; |
| 377 | + |
| 378 | + ret = ahci_platform_resume_host(dev); |
| 379 | + if (ret) |
| 380 | + goto out_disable_platform_phys; |
| 381 | + |
| 382 | + /* We resumed so update PM runtime state */ |
| 383 | + pm_runtime_disable(dev); |
| 384 | + pm_runtime_set_active(dev); |
| 385 | + pm_runtime_enable(dev); |
| 386 | + |
| 387 | + return 0; |
| 388 | + |
| 389 | +out_disable_platform_phys: |
| 390 | + ahci_platform_disable_phys(hpriv); |
| 391 | +out_disable_phys: |
| 392 | + brcm_sata_phys_disable(priv); |
| 393 | + ahci_platform_disable_clks(hpriv); |
| 394 | + return ret; |
| 367 | 395 | } |
| 368 | 396 | #endif |
| 369 | 397 | |
| @@ -410,44 +438,71 @@ static int brcm_ahci_probe(struct platform_device *pdev) · 40 unmodified lines |
| 410 | 438 | if (!IS_ERR_OR_NULL(priv->rcdev)) |
| 411 | 439 | reset_control_deassert(priv->rcdev); |
| 412 | 440 | |
| 413 | | − if ((priv->version == BRCM_SATA_BCM7425) || |
| 414 | | − (priv->version == BRCM_SATA_NSP)) { |
| 415 | | − priv->quirks |= BRCM_AHCI_QUIRK_NO_NCQ; |
| 441 | + hpriv = ahci_platform_get_resources(pdev, 0); |
| 442 | + if (IS_ERR(hpriv)) { |
| 443 | + ret = PTR_ERR(hpriv); |
| 444 | + goto out_reset; |
| 445 | + } |
| 446 | + |
| 447 | + hpriv->plat_data = priv; |
| 448 | + hpriv->flags = AHCI_HFLAG_WAKE_BEFORE_STOP | AHCI_HFLAG_NO_WRITE_TO_RO; |
| 449 | + |
| 450 | + switch (priv->version) { |
| 451 | + case BRCM_SATA_BCM7425: |
| 452 | + hpriv->flags |= AHCI_HFLAG_DELAY_ENGINE; |
| 453 | + /* fall through */ |
| 454 | + case BRCM_SATA_NSP: |
| 455 | + hpriv->flags |= AHCI_HFLAG_NO_NCQ; |
| 416 | 456 | priv->quirks |= BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE; |
| 457 | + break; |
| 458 | + default: |
| 459 | + break; |
| 417 | 460 | } |
| 418 | 461 | |
| 462 | + ret = ahci_platform_enable_clks(hpriv); |
| 463 | + if (ret) |
| 464 | + goto out_reset; |
| 465 | + |
| 466 | + /* Must be first so as to configure endianness including that |
| 467 | + * of the standard AHCI register space. |
| 468 | + */ |
| 419 | 469 | brcm_sata_init(priv); |
| 420 | 470 | |
| 421 | | − priv->port_mask = brcm_ahci_get_portmask(pdev, priv); |
| 422 | | − if (!priv->port_mask) |
| 423 | | − return -ENODEV; |
| 471 | + /* Initializes priv->port_mask which is used below */ |
| 472 | + priv->port_mask = brcm_ahci_get_portmask(hpriv, priv); |
| 473 | + if (!priv->port_mask) { |
| 474 | + ret = -ENODEV; |
| 475 | + goto out_disable_clks; |
| 476 | + } |
| 424 | 477 | |
| 478 | + /* Must be done before ahci_platform_enable_phys() */ |
| 425 | 479 | brcm_sata_phys_enable(priv); |
| 426 | 480 | |
| 427 | | − hpriv = ahci_platform_get_resources(pdev, 0); |
| 428 | | − if (IS_ERR(hpriv)) |
| 429 | | − return PTR_ERR(hpriv); |
| 430 | | − hpriv->plat_data = priv; |
| 431 | | − hpriv->flags = AHCI_HFLAG_WAKE_BEFORE_STOP; |
| 432 | | − |
| 433 | 481 | brcm_sata_alpm_init(hpriv); |
| 434 | 482 | |
| 435 | | − ret = ahci_platform_enable_resources(hpriv); |
| 483 | + ret = ahci_platform_enable_phys(hpriv); |
| 436 | 484 | if (ret) |
| 437 | | − return ret; |
| 438 | | − |
| 439 | | − if (priv->quirks & BRCM_AHCI_QUIRK_NO_NCQ) |
| 440 | | − hpriv->flags |= AHCI_HFLAG_NO_NCQ; |
| 441 | | − hpriv->flags |= AHCI_HFLAG_NO_WRITE_TO_RO; |
| 485 | + goto out_disable_phys; |
| 442 | 486 | |
| 443 | 487 | ret = ahci_platform_init_host(pdev, hpriv, &ahci_brcm_port_info, |
| 444 | 488 | &ahci_platform_sht); |
| 445 | 489 | if (ret) |
| 446 | | − return ret; |
| 490 | + goto out_disable_platform_phys; |
| 447 | 491 | |
| 448 | 492 | dev_info(dev, "Broadcom AHCI SATA3 registered\n"); |
| 449 | 493 | |
| 450 | 494 | return 0; |
| 495 | + |
| 496 | +out_disable_platform_phys: |
| 497 | + ahci_platform_disable_phys(hpriv); |
| 498 | +out_disable_phys: |
| 499 | + brcm_sata_phys_disable(priv); |
| 500 | +out_disable_clks: |
| 501 | + ahci_platform_disable_clks(hpriv); |
| 502 | +out_reset: |
| 503 | + if (!IS_ERR_OR_NULL(priv->rcdev)) |
| 504 | + reset_control_assert(priv->rcdev); |
| 505 | + return ret; |
| 451 | 506 | } |
| 452 | 507 | |
| 453 | 508 | static int brcm_ahci_remove(struct platform_device *pdev) |
| @@ -457,12 +512,12 @@ static int brcm_ahci_remove(struct platform_device *pdev) · 3 unmodified lines |
| 457 | 512 | struct brcm_ahci_priv *priv = hpriv->plat_data; |
| 458 | 513 | int ret; |
| 459 | 514 | |
| 515 | + brcm_sata_phys_disable(priv); |
| 516 | + |
| 460 | 517 | ret = ata_platform_remove_one(pdev); |
| 461 | 518 | if (ret) |
| 462 | 519 | return ret; |
| 463 | 520 | |
| 464 | | − brcm_sata_phys_disable(priv); |
| 465 | | − |
| 466 | 521 | return 0; |
| 467 | 522 | } |
| 468 | 523 | |