| @@ -76,8 +76,7 @@ enum brcm_ahci_version { · 75 unmodified lines |
| 76 | }; | 76 | }; |
| 77 | | 77 | |
| 78 | enum brcm_ahci_quirks { | 78 | enum brcm_ahci_quirks { |
| 79 | BRCM_AHCI_QUIRK_NO_NCQ = BIT(0), | 79 | BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE = BIT(0), |
| 80 | BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE = BIT(1), | | |
| 81 | }; | 80 | }; |
| 82 | | 81 | |
| 83 | struct brcm_ahci_priv { | 82 | struct brcm_ahci_priv { |
| @@ -213,19 +212,12 @@ static void brcm_sata_phys_disable(struct brcm_ahci_priv *priv) · 129 unmodified lines |
| 213 | brcm_sata_phy_disable(priv, i); | 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 | struct brcm_ahci_priv *priv) | 216 | struct brcm_ahci_priv *priv) |
| 218 | { | 217 | { |
| 219 | void __iomem *ahci; | | |
| 220 | struct resource *res; | | |
| 221 | u32 impl; | 218 | u32 impl; |
| 222 | | 219 | |
| 223 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ahci"); | 220 | impl = readl(hpriv->mmio + HOST_PORTS_IMPL); |
| 224 | ahci = devm_ioremap_resource(&pdev->dev, res); | | |
| 225 | if (IS_ERR(ahci)) | | |
| 226 | return 0; | | |
| 227 | | | |
| 228 | impl = readl(ahci + HOST_PORTS_IMPL); | | |
| 229 | | 221 | |
| 230 | if (fls(impl) > SATA_TOP_MAX_PHYS) | 222 | if (fls(impl) > SATA_TOP_MAX_PHYS) |
| 231 | dev_warn(priv->dev, "warning: more ports than PHYs (%#x)\n", | 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 | else if (!impl) | 225 | else if (!impl) |
| 234 | dev_info(priv->dev, "no ports found\n"); | 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 | return impl; | 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 | /* Perform the SATA PHY reset sequence */ | 274 | /* Perform the SATA PHY reset sequence */ |
| 286 | brcm_sata_phy_disable(priv, ap->port_no); | 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 | /* Bring the PHY back on */ | 284 | /* Bring the PHY back on */ |
| 289 | brcm_sata_phy_enable(priv, ap->port_no); | 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 | struct ata_host *host = dev_get_drvdata(dev); | 343 | struct ata_host *host = dev_get_drvdata(dev); |
| 348 | struct ahci_host_priv *hpriv = host->private_data; | 344 | struct ahci_host_priv *hpriv = host->private_data; |
| 349 | struct brcm_ahci_priv *priv = hpriv->plat_data; | 345 | struct brcm_ahci_priv *priv = hpriv->plat_data; |
| 350 | int ret; | | |
| 351 | | 346 | |
| 352 | ret = ahci_platform_suspend(dev); | | |
| 353 | brcm_sata_phys_disable(priv); | 347 | brcm_sata_phys_disable(priv); |
| 354 | return ret; | 348 | |
| | 349 | return ahci_platform_suspend(dev); |
| 355 | } | 350 | } |
| 356 | | 351 | |
| 357 | static int brcm_ahci_resume(struct device *dev) | 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 | struct ata_host *host = dev_get_drvdata(dev); | 354 | struct ata_host *host = dev_get_drvdata(dev); |
| 360 | struct ahci_host_priv *hpriv = host->private_data; | 355 | struct ahci_host_priv *hpriv = host->private_data; |
| 361 | struct brcm_ahci_priv *priv = hpriv->plat_data; | 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 | brcm_sata_init(priv); | 364 | brcm_sata_init(priv); |
| 364 | brcm_sata_phys_enable(priv); | 365 | brcm_sata_phys_enable(priv); |
| 365 | brcm_sata_alpm_init(hpriv); | 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 | #endif | 396 | #endif |
| 369 | | 397 | |
| @@ -410,44 +438,71 @@ static int brcm_ahci_probe(struct platform_device *pdev) · 40 unmodified lines |
| 410 | if (!IS_ERR_OR_NULL(priv->rcdev)) | 438 | if (!IS_ERR_OR_NULL(priv->rcdev)) |
| 411 | reset_control_deassert(priv->rcdev); | 439 | reset_control_deassert(priv->rcdev); |
| 412 | | 440 | |
| 413 | if ((priv->version == BRCM_SATA_BCM7425) || | 441 | hpriv = ahci_platform_get_resources(pdev, 0); |
| 414 | (priv->version == BRCM_SATA_NSP)) { | 442 | if (IS_ERR(hpriv)) { |
| 415 | priv->quirks |= BRCM_AHCI_QUIRK_NO_NCQ; | 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 | priv->quirks |= BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE; | 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 | brcm_sata_init(priv); | 469 | brcm_sata_init(priv); |
| 420 | | 470 | |
| 421 | priv->port_mask = brcm_ahci_get_portmask(pdev, priv); | 471 | /* Initializes priv->port_mask which is used below */ |
| 422 | if (!priv->port_mask) | 472 | priv->port_mask = brcm_ahci_get_portmask(hpriv, priv); |
| 423 | return -ENODEV; | 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 | brcm_sata_phys_enable(priv); | 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 | brcm_sata_alpm_init(hpriv); | 481 | brcm_sata_alpm_init(hpriv); |
| 434 | | 482 | |
| 435 | ret = ahci_platform_enable_resources(hpriv); | 483 | ret = ahci_platform_enable_phys(hpriv); |
| 436 | if (ret) | 484 | if (ret) |
| 437 | return ret; | 485 | goto out_disable_phys; |
| 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; | | |
| 442 | | 486 | |
| 443 | ret = ahci_platform_init_host(pdev, hpriv, &ahci_brcm_port_info, | 487 | ret = ahci_platform_init_host(pdev, hpriv, &ahci_brcm_port_info, |
| 444 | &ahci_platform_sht); | 488 | &ahci_platform_sht); |
| 445 | if (ret) | 489 | if (ret) |
| 446 | return ret; | 490 | goto out_disable_platform_phys; |
| 447 | | 491 | |
| 448 | dev_info(dev, "Broadcom AHCI SATA3 registered\n"); | 492 | dev_info(dev, "Broadcom AHCI SATA3 registered\n"); |
| 449 | | 493 | |
| 450 | return 0; | 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 | static int brcm_ahci_remove(struct platform_device *pdev) | 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 | struct brcm_ahci_priv *priv = hpriv->plat_data; | 512 | struct brcm_ahci_priv *priv = hpriv->plat_data; |
| 458 | int ret; | 513 | int ret; |
| 459 | | 514 | |
| | 515 | brcm_sata_phys_disable(priv); |
| | 516 | |
| 460 | ret = ata_platform_remove_one(pdev); | 517 | ret = ata_platform_remove_one(pdev); |
| 461 | if (ret) | 518 | if (ret) |
| 462 | return ret; | 519 | return ret; |
| 463 | | 520 | |
| 464 | brcm_sata_phys_disable(priv); | | |
| 465 | | | |
| 466 | return 0; | 521 | return 0; |
| 467 | } | 522 | } |
| 468 | | 523 | |