|
@@ -59,6 +59,7 @@
|
|
|
#include <linux/dmapool.h>
|
|
|
#include <linux/dma-mapping.h>
|
|
|
#include <linux/device.h>
|
|
|
+#include <linux/clk.h>
|
|
|
#include <linux/platform_device.h>
|
|
|
#include <linux/ata_platform.h>
|
|
|
#include <linux/mbus.h>
|
|
@@ -538,6 +539,7 @@ struct mv_port_signal {
|
|
|
|
|
|
struct mv_host_priv {
|
|
|
u32 hp_flags;
|
|
|
+ unsigned int board_idx;
|
|
|
u32 main_irq_mask;
|
|
|
struct mv_port_signal signal[8];
|
|
|
const struct mv_hw_ops *ops;
|
|
@@ -548,6 +550,10 @@ struct mv_host_priv {
|
|
|
u32 irq_cause_offset;
|
|
|
u32 irq_mask_offset;
|
|
|
u32 unmask_all_irqs;
|
|
|
+
|
|
|
+#if defined(CONFIG_HAVE_CLK)
|
|
|
+ struct clk *clk;
|
|
|
+#endif
|
|
|
/*
|
|
|
* These consistent DMA memory pools give us guaranteed
|
|
|
* alignment for hardware-accessed data structures,
|
|
@@ -2775,7 +2781,7 @@ static void mv_port_intr(struct ata_port *ap, u32 port_cause)
|
|
|
struct mv_port_priv *pp;
|
|
|
int edma_was_enabled;
|
|
|
|
|
|
- if (!ap || (ap->flags & ATA_FLAG_DISABLED)) {
|
|
|
+ if (ap->flags & ATA_FLAG_DISABLED) {
|
|
|
mv_unexpected_intr(ap, 0);
|
|
|
return;
|
|
|
}
|
|
@@ -3393,7 +3399,7 @@ static void mv_soc_reset_hc_port(struct mv_host_priv *hpriv,
|
|
|
ZERO(0x024); /* respq outp */
|
|
|
ZERO(0x020); /* respq inp */
|
|
|
ZERO(0x02c); /* test control */
|
|
|
- writel(0xbc, port_mmio + EDMA_IORDY_TMOUT);
|
|
|
+ writel(0x800, port_mmio + EDMA_IORDY_TMOUT);
|
|
|
}
|
|
|
|
|
|
#undef ZERO
|
|
@@ -3854,7 +3860,6 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
|
|
|
/**
|
|
|
* mv_init_host - Perform some early initialization of the host.
|
|
|
* @host: ATA host to initialize
|
|
|
- * @board_idx: controller index
|
|
|
*
|
|
|
* If possible, do an early global reset of the host. Then do
|
|
|
* our port init and clear/unmask all/relevant host interrupts.
|
|
@@ -3862,13 +3867,13 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
|
|
|
* LOCKING:
|
|
|
* Inherited from caller.
|
|
|
*/
|
|
|
-static int mv_init_host(struct ata_host *host, unsigned int board_idx)
|
|
|
+static int mv_init_host(struct ata_host *host)
|
|
|
{
|
|
|
int rc = 0, n_hc, port, hc;
|
|
|
struct mv_host_priv *hpriv = host->private_data;
|
|
|
void __iomem *mmio = hpriv->base;
|
|
|
|
|
|
- rc = mv_chip_id(host, board_idx);
|
|
|
+ rc = mv_chip_id(host, hpriv->board_idx);
|
|
|
if (rc)
|
|
|
goto done;
|
|
|
|
|
@@ -3905,14 +3910,6 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
|
|
|
void __iomem *port_mmio = mv_port_base(mmio, port);
|
|
|
|
|
|
mv_port_init(&ap->ioaddr, port_mmio);
|
|
|
-
|
|
|
-#ifdef CONFIG_PCI
|
|
|
- if (!IS_SOC(hpriv)) {
|
|
|
- unsigned int offset = port_mmio - mmio;
|
|
|
- ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio");
|
|
|
- ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port");
|
|
|
- }
|
|
|
-#endif
|
|
|
}
|
|
|
|
|
|
for (hc = 0; hc < n_hc; hc++) {
|
|
@@ -4035,12 +4032,21 @@ static int mv_platform_probe(struct platform_device *pdev)
|
|
|
return -ENOMEM;
|
|
|
host->private_data = hpriv;
|
|
|
hpriv->n_ports = n_ports;
|
|
|
+ hpriv->board_idx = chip_soc;
|
|
|
|
|
|
host->iomap = NULL;
|
|
|
hpriv->base = devm_ioremap(&pdev->dev, res->start,
|
|
|
resource_size(res));
|
|
|
hpriv->base -= SATAHC0_REG_BASE;
|
|
|
|
|
|
+#if defined(CONFIG_HAVE_CLK)
|
|
|
+ hpriv->clk = clk_get(&pdev->dev, NULL);
|
|
|
+ if (IS_ERR(hpriv->clk))
|
|
|
+ dev_notice(&pdev->dev, "cannot get clkdev\n");
|
|
|
+ else
|
|
|
+ clk_enable(hpriv->clk);
|
|
|
+#endif
|
|
|
+
|
|
|
/*
|
|
|
* (Re-)program MBUS remapping windows if we are asked to.
|
|
|
*/
|
|
@@ -4049,12 +4055,12 @@ static int mv_platform_probe(struct platform_device *pdev)
|
|
|
|
|
|
rc = mv_create_dma_pools(hpriv, &pdev->dev);
|
|
|
if (rc)
|
|
|
- return rc;
|
|
|
+ goto err;
|
|
|
|
|
|
/* initialize adapter */
|
|
|
- rc = mv_init_host(host, chip_soc);
|
|
|
+ rc = mv_init_host(host);
|
|
|
if (rc)
|
|
|
- return rc;
|
|
|
+ goto err;
|
|
|
|
|
|
dev_printk(KERN_INFO, &pdev->dev,
|
|
|
"slots %u ports %d\n", (unsigned)MV_MAX_Q_DEPTH,
|
|
@@ -4062,6 +4068,15 @@ static int mv_platform_probe(struct platform_device *pdev)
|
|
|
|
|
|
return ata_host_activate(host, platform_get_irq(pdev, 0), mv_interrupt,
|
|
|
IRQF_SHARED, &mv6_sht);
|
|
|
+err:
|
|
|
+#if defined(CONFIG_HAVE_CLK)
|
|
|
+ if (!IS_ERR(hpriv->clk)) {
|
|
|
+ clk_disable(hpriv->clk);
|
|
|
+ clk_put(hpriv->clk);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+ return rc;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -4076,14 +4091,66 @@ static int __devexit mv_platform_remove(struct platform_device *pdev)
|
|
|
{
|
|
|
struct device *dev = &pdev->dev;
|
|
|
struct ata_host *host = dev_get_drvdata(dev);
|
|
|
-
|
|
|
+#if defined(CONFIG_HAVE_CLK)
|
|
|
+ struct mv_host_priv *hpriv = host->private_data;
|
|
|
+#endif
|
|
|
ata_host_detach(host);
|
|
|
+
|
|
|
+#if defined(CONFIG_HAVE_CLK)
|
|
|
+ if (!IS_ERR(hpriv->clk)) {
|
|
|
+ clk_disable(hpriv->clk);
|
|
|
+ clk_put(hpriv->clk);
|
|
|
+ }
|
|
|
+#endif
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_PM
|
|
|
+static int mv_platform_suspend(struct platform_device *pdev, pm_message_t state)
|
|
|
+{
|
|
|
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
|
|
|
+ if (host)
|
|
|
+ return ata_host_suspend(host, state);
|
|
|
+ else
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int mv_platform_resume(struct platform_device *pdev)
|
|
|
+{
|
|
|
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (host) {
|
|
|
+ struct mv_host_priv *hpriv = host->private_data;
|
|
|
+ const struct mv_sata_platform_data *mv_platform_data = \
|
|
|
+ pdev->dev.platform_data;
|
|
|
+ /*
|
|
|
+ * (Re-)program MBUS remapping windows if we are asked to.
|
|
|
+ */
|
|
|
+ if (mv_platform_data->dram != NULL)
|
|
|
+ mv_conf_mbus_windows(hpriv, mv_platform_data->dram);
|
|
|
+
|
|
|
+ /* initialize adapter */
|
|
|
+ ret = mv_init_host(host);
|
|
|
+ if (ret) {
|
|
|
+ printk(KERN_ERR DRV_NAME ": Error during HW init\n");
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ ata_host_resume(host);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+#else
|
|
|
+#define mv_platform_suspend NULL
|
|
|
+#define mv_platform_resume NULL
|
|
|
+#endif
|
|
|
+
|
|
|
static struct platform_driver mv_platform_driver = {
|
|
|
.probe = mv_platform_probe,
|
|
|
.remove = __devexit_p(mv_platform_remove),
|
|
|
+ .suspend = mv_platform_suspend,
|
|
|
+ .resume = mv_platform_resume,
|
|
|
.driver = {
|
|
|
.name = DRV_NAME,
|
|
|
.owner = THIS_MODULE,
|
|
@@ -4094,6 +4161,9 @@ static struct platform_driver mv_platform_driver = {
|
|
|
#ifdef CONFIG_PCI
|
|
|
static int mv_pci_init_one(struct pci_dev *pdev,
|
|
|
const struct pci_device_id *ent);
|
|
|
+#ifdef CONFIG_PM
|
|
|
+static int mv_pci_device_resume(struct pci_dev *pdev);
|
|
|
+#endif
|
|
|
|
|
|
|
|
|
static struct pci_driver mv_pci_driver = {
|
|
@@ -4101,6 +4171,11 @@ static struct pci_driver mv_pci_driver = {
|
|
|
.id_table = mv_pci_tbl,
|
|
|
.probe = mv_pci_init_one,
|
|
|
.remove = ata_pci_remove_one,
|
|
|
+#ifdef CONFIG_PM
|
|
|
+ .suspend = ata_pci_device_suspend,
|
|
|
+ .resume = mv_pci_device_resume,
|
|
|
+#endif
|
|
|
+
|
|
|
};
|
|
|
|
|
|
/* move to PCI layer or libata core? */
|
|
@@ -4194,7 +4269,7 @@ static int mv_pci_init_one(struct pci_dev *pdev,
|
|
|
const struct ata_port_info *ppi[] = { &mv_port_info[board_idx], NULL };
|
|
|
struct ata_host *host;
|
|
|
struct mv_host_priv *hpriv;
|
|
|
- int n_ports, rc;
|
|
|
+ int n_ports, port, rc;
|
|
|
|
|
|
if (!printed_version++)
|
|
|
dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
|
|
@@ -4208,6 +4283,7 @@ static int mv_pci_init_one(struct pci_dev *pdev,
|
|
|
return -ENOMEM;
|
|
|
host->private_data = hpriv;
|
|
|
hpriv->n_ports = n_ports;
|
|
|
+ hpriv->board_idx = board_idx;
|
|
|
|
|
|
/* acquire resources */
|
|
|
rc = pcim_enable_device(pdev);
|
|
@@ -4230,8 +4306,17 @@ static int mv_pci_init_one(struct pci_dev *pdev,
|
|
|
if (rc)
|
|
|
return rc;
|
|
|
|
|
|
+ for (port = 0; port < host->n_ports; port++) {
|
|
|
+ struct ata_port *ap = host->ports[port];
|
|
|
+ void __iomem *port_mmio = mv_port_base(hpriv->base, port);
|
|
|
+ unsigned int offset = port_mmio - hpriv->base;
|
|
|
+
|
|
|
+ ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio");
|
|
|
+ ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port");
|
|
|
+ }
|
|
|
+
|
|
|
/* initialize adapter */
|
|
|
- rc = mv_init_host(host, board_idx);
|
|
|
+ rc = mv_init_host(host);
|
|
|
if (rc)
|
|
|
return rc;
|
|
|
|
|
@@ -4247,6 +4332,27 @@ static int mv_pci_init_one(struct pci_dev *pdev,
|
|
|
return ata_host_activate(host, pdev->irq, mv_interrupt, IRQF_SHARED,
|
|
|
IS_GEN_I(hpriv) ? &mv5_sht : &mv6_sht);
|
|
|
}
|
|
|
+
|
|
|
+#ifdef CONFIG_PM
|
|
|
+static int mv_pci_device_resume(struct pci_dev *pdev)
|
|
|
+{
|
|
|
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
|
|
|
+ int rc;
|
|
|
+
|
|
|
+ rc = ata_pci_device_do_resume(pdev);
|
|
|
+ if (rc)
|
|
|
+ return rc;
|
|
|
+
|
|
|
+ /* initialize adapter */
|
|
|
+ rc = mv_init_host(host);
|
|
|
+ if (rc)
|
|
|
+ return rc;
|
|
|
+
|
|
|
+ ata_host_resume(host);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+#endif
|
|
|
#endif
|
|
|
|
|
|
static int mv_platform_probe(struct platform_device *pdev);
|