diff options
Diffstat (limited to 'drivers/ata/sata_mv.c')
-rw-r--r-- | drivers/ata/sata_mv.c | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 47184567248d..8a751054c8a1 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c | |||
@@ -251,6 +251,11 @@ enum { | |||
251 | HC_IRQ_COAL_IO_THRESHOLD_OFS = 0x000c, | 251 | HC_IRQ_COAL_IO_THRESHOLD_OFS = 0x000c, |
252 | HC_IRQ_COAL_TIME_THRESHOLD_OFS = 0x0010, | 252 | HC_IRQ_COAL_TIME_THRESHOLD_OFS = 0x0010, |
253 | 253 | ||
254 | SOC_LED_CTRL_OFS = 0x2c, | ||
255 | SOC_LED_CTRL_BLINK = (1 << 0), /* Active LED blink */ | ||
256 | SOC_LED_CTRL_ACT_PRESENCE = (1 << 2), /* Multiplex dev presence */ | ||
257 | /* with dev activity LED */ | ||
258 | |||
254 | /* Shadow block registers */ | 259 | /* Shadow block registers */ |
255 | SHD_BLK_OFS = 0x100, | 260 | SHD_BLK_OFS = 0x100, |
256 | SHD_CTL_AST_OFS = 0x20, /* ofs from SHD_BLK_OFS */ | 261 | SHD_CTL_AST_OFS = 0x20, /* ofs from SHD_BLK_OFS */ |
@@ -411,6 +416,7 @@ enum { | |||
411 | MV_HP_PCIE = (1 << 9), /* PCIe bus/regs: 7042 */ | 416 | MV_HP_PCIE = (1 << 9), /* PCIe bus/regs: 7042 */ |
412 | MV_HP_CUT_THROUGH = (1 << 10), /* can use EDMA cut-through */ | 417 | MV_HP_CUT_THROUGH = (1 << 10), /* can use EDMA cut-through */ |
413 | MV_HP_FLAG_SOC = (1 << 11), /* SystemOnChip, no PCI */ | 418 | MV_HP_FLAG_SOC = (1 << 11), /* SystemOnChip, no PCI */ |
419 | MV_HP_QUIRK_LED_BLINK_EN = (1 << 12), /* is led blinking enabled? */ | ||
414 | 420 | ||
415 | /* Port private flags (pp_flags) */ | 421 | /* Port private flags (pp_flags) */ |
416 | MV_PP_FLAG_EDMA_EN = (1 << 0), /* is EDMA engine enabled? */ | 422 | MV_PP_FLAG_EDMA_EN = (1 << 0), /* is EDMA engine enabled? */ |
@@ -1404,6 +1410,61 @@ static void mv_bmdma_enable_iie(struct ata_port *ap, int enable_bmdma) | |||
1404 | mv_write_cached_reg(mv_ap_base(ap) + EDMA_UNKNOWN_RSVD_OFS, old, new); | 1410 | mv_write_cached_reg(mv_ap_base(ap) + EDMA_UNKNOWN_RSVD_OFS, old, new); |
1405 | } | 1411 | } |
1406 | 1412 | ||
1413 | /* | ||
1414 | * SOC chips have an issue whereby the HDD LEDs don't always blink | ||
1415 | * during I/O when NCQ is enabled. Enabling a special "LED blink" mode | ||
1416 | * of the SOC takes care of it, generating a steady blink rate when | ||
1417 | * any drive on the chip is active. | ||
1418 | * | ||
1419 | * Unfortunately, the blink mode is a global hardware setting for the SOC, | ||
1420 | * so we must use it whenever at least one port on the SOC has NCQ enabled. | ||
1421 | * | ||
1422 | * We turn "LED blink" off when NCQ is not in use anywhere, because the normal | ||
1423 | * LED operation works then, and provides better (more accurate) feedback. | ||
1424 | * | ||
1425 | * Note that this code assumes that an SOC never has more than one HC onboard. | ||
1426 | */ | ||
1427 | static void mv_soc_led_blink_enable(struct ata_port *ap) | ||
1428 | { | ||
1429 | struct ata_host *host = ap->host; | ||
1430 | struct mv_host_priv *hpriv = host->private_data; | ||
1431 | void __iomem *hc_mmio; | ||
1432 | u32 led_ctrl; | ||
1433 | |||
1434 | if (hpriv->hp_flags & MV_HP_QUIRK_LED_BLINK_EN) | ||
1435 | return; | ||
1436 | hpriv->hp_flags |= MV_HP_QUIRK_LED_BLINK_EN; | ||
1437 | hc_mmio = mv_hc_base_from_port(mv_host_base(host), ap->port_no); | ||
1438 | led_ctrl = readl(hc_mmio + SOC_LED_CTRL_OFS); | ||
1439 | writel(led_ctrl | SOC_LED_CTRL_BLINK, hc_mmio + SOC_LED_CTRL_OFS); | ||
1440 | } | ||
1441 | |||
1442 | static void mv_soc_led_blink_disable(struct ata_port *ap) | ||
1443 | { | ||
1444 | struct ata_host *host = ap->host; | ||
1445 | struct mv_host_priv *hpriv = host->private_data; | ||
1446 | void __iomem *hc_mmio; | ||
1447 | u32 led_ctrl; | ||
1448 | unsigned int port; | ||
1449 | |||
1450 | if (!(hpriv->hp_flags & MV_HP_QUIRK_LED_BLINK_EN)) | ||
1451 | return; | ||
1452 | |||
1453 | /* disable led-blink only if no ports are using NCQ */ | ||
1454 | for (port = 0; port < hpriv->n_ports; port++) { | ||
1455 | struct ata_port *this_ap = host->ports[port]; | ||
1456 | struct mv_port_priv *pp = this_ap->private_data; | ||
1457 | |||
1458 | if (pp->pp_flags & MV_PP_FLAG_NCQ_EN) | ||
1459 | return; | ||
1460 | } | ||
1461 | |||
1462 | hpriv->hp_flags &= ~MV_HP_QUIRK_LED_BLINK_EN; | ||
1463 | hc_mmio = mv_hc_base_from_port(mv_host_base(host), ap->port_no); | ||
1464 | led_ctrl = readl(hc_mmio + SOC_LED_CTRL_OFS); | ||
1465 | writel(led_ctrl & ~SOC_LED_CTRL_BLINK, hc_mmio + SOC_LED_CTRL_OFS); | ||
1466 | } | ||
1467 | |||
1407 | static void mv_edma_cfg(struct ata_port *ap, int want_ncq, int want_edma) | 1468 | static void mv_edma_cfg(struct ata_port *ap, int want_ncq, int want_edma) |
1408 | { | 1469 | { |
1409 | u32 cfg; | 1470 | u32 cfg; |
@@ -1451,6 +1512,13 @@ static void mv_edma_cfg(struct ata_port *ap, int want_ncq, int want_edma) | |||
1451 | if (hpriv->hp_flags & MV_HP_CUT_THROUGH) | 1512 | if (hpriv->hp_flags & MV_HP_CUT_THROUGH) |
1452 | cfg |= (1 << 17); /* enab cut-thru (dis stor&forwrd) */ | 1513 | cfg |= (1 << 17); /* enab cut-thru (dis stor&forwrd) */ |
1453 | mv_bmdma_enable_iie(ap, !want_edma); | 1514 | mv_bmdma_enable_iie(ap, !want_edma); |
1515 | |||
1516 | if (IS_SOC(hpriv)) { | ||
1517 | if (want_ncq) | ||
1518 | mv_soc_led_blink_enable(ap); | ||
1519 | else | ||
1520 | mv_soc_led_blink_disable(ap); | ||
1521 | } | ||
1454 | } | 1522 | } |
1455 | 1523 | ||
1456 | if (want_ncq) { | 1524 | if (want_ncq) { |