diff options
| -rw-r--r-- | drivers/ata/ahci.h | 2 | ||||
| -rw-r--r-- | drivers/ata/ahci_imx.c | 101 | ||||
| -rw-r--r-- | drivers/ata/ahci_platform.c | 3 | ||||
| -rw-r--r-- | drivers/ata/libahci.c | 4 |
4 files changed, 105 insertions, 5 deletions
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 11456371f29b..2289efdf8203 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h | |||
| @@ -339,6 +339,7 @@ extern struct device_attribute *ahci_sdev_attrs[]; | |||
| 339 | .sdev_attrs = ahci_sdev_attrs | 339 | .sdev_attrs = ahci_sdev_attrs |
| 340 | 340 | ||
| 341 | extern struct ata_port_operations ahci_ops; | 341 | extern struct ata_port_operations ahci_ops; |
| 342 | extern struct ata_port_operations ahci_platform_ops; | ||
| 342 | extern struct ata_port_operations ahci_pmp_retry_srst_ops; | 343 | extern struct ata_port_operations ahci_pmp_retry_srst_ops; |
| 343 | 344 | ||
| 344 | unsigned int ahci_dev_classify(struct ata_port *ap); | 345 | unsigned int ahci_dev_classify(struct ata_port *ap); |
| @@ -368,6 +369,7 @@ irqreturn_t ahci_hw_interrupt(int irq, void *dev_instance); | |||
| 368 | irqreturn_t ahci_thread_fn(int irq, void *dev_instance); | 369 | irqreturn_t ahci_thread_fn(int irq, void *dev_instance); |
| 369 | void ahci_print_info(struct ata_host *host, const char *scc_s); | 370 | void ahci_print_info(struct ata_host *host, const char *scc_s); |
| 370 | int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis); | 371 | int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis); |
| 372 | void ahci_error_handler(struct ata_port *ap); | ||
| 371 | 373 | ||
| 372 | static inline void __iomem *__ahci_port_base(struct ata_host *host, | 374 | static inline void __iomem *__ahci_port_base(struct ata_host *host, |
| 373 | unsigned int port_no) | 375 | unsigned int port_no) |
diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c index 58debb0acc3a..ae2d73fe321e 100644 --- a/drivers/ata/ahci_imx.c +++ b/drivers/ata/ahci_imx.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * copyright (c) 2013 Freescale Semiconductor, Inc. | ||
| 2 | * Freescale IMX AHCI SATA platform driver | 3 | * Freescale IMX AHCI SATA platform driver |
| 3 | * Copyright 2013 Freescale Semiconductor, Inc. | ||
| 4 | * | 4 | * |
| 5 | * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov | 5 | * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov |
| 6 | * | 6 | * |
| @@ -25,10 +25,13 @@ | |||
| 25 | #include <linux/of_device.h> | 25 | #include <linux/of_device.h> |
| 26 | #include <linux/mfd/syscon.h> | 26 | #include <linux/mfd/syscon.h> |
| 27 | #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> | 27 | #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> |
| 28 | #include <linux/libata.h> | ||
| 28 | #include "ahci.h" | 29 | #include "ahci.h" |
| 29 | 30 | ||
| 30 | enum { | 31 | enum { |
| 31 | HOST_TIMER1MS = 0xe0, /* Timer 1-ms */ | 32 | PORT_PHY_CTL = 0x178, /* Port0 PHY Control */ |
| 33 | PORT_PHY_CTL_PDDQ_LOC = 0x100000, /* PORT_PHY_CTL bits */ | ||
| 34 | HOST_TIMER1MS = 0xe0, /* Timer 1-ms */ | ||
| 32 | }; | 35 | }; |
| 33 | 36 | ||
| 34 | struct imx_ahci_priv { | 37 | struct imx_ahci_priv { |
| @@ -36,6 +39,56 @@ struct imx_ahci_priv { | |||
| 36 | struct clk *sata_ref_clk; | 39 | struct clk *sata_ref_clk; |
| 37 | struct clk *ahb_clk; | 40 | struct clk *ahb_clk; |
| 38 | struct regmap *gpr; | 41 | struct regmap *gpr; |
| 42 | bool no_device; | ||
| 43 | bool first_time; | ||
| 44 | }; | ||
| 45 | |||
| 46 | static int ahci_imx_hotplug; | ||
| 47 | module_param_named(hotplug, ahci_imx_hotplug, int, 0644); | ||
| 48 | MODULE_PARM_DESC(hotplug, "AHCI IMX hot-plug support (0=Don't support, 1=support)"); | ||
| 49 | |||
| 50 | static void ahci_imx_error_handler(struct ata_port *ap) | ||
| 51 | { | ||
| 52 | u32 reg_val; | ||
| 53 | struct ata_device *dev; | ||
| 54 | struct ata_host *host = dev_get_drvdata(ap->dev); | ||
| 55 | struct ahci_host_priv *hpriv = host->private_data; | ||
| 56 | void __iomem *mmio = hpriv->mmio; | ||
| 57 | struct imx_ahci_priv *imxpriv = dev_get_drvdata(ap->dev->parent); | ||
| 58 | |||
| 59 | ahci_error_handler(ap); | ||
| 60 | |||
| 61 | if (!(imxpriv->first_time) || ahci_imx_hotplug) | ||
| 62 | return; | ||
| 63 | |||
| 64 | imxpriv->first_time = false; | ||
| 65 | |||
| 66 | ata_for_each_dev(dev, &ap->link, ENABLED) | ||
| 67 | return; | ||
| 68 | /* | ||
| 69 | * Disable link to save power. An imx ahci port can't be recovered | ||
| 70 | * without full reset once the pddq mode is enabled making it | ||
| 71 | * impossible to use as part of libata LPM. | ||
| 72 | */ | ||
| 73 | reg_val = readl(mmio + PORT_PHY_CTL); | ||
| 74 | writel(reg_val | PORT_PHY_CTL_PDDQ_LOC, mmio + PORT_PHY_CTL); | ||
| 75 | regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, | ||
| 76 | IMX6Q_GPR13_SATA_MPLL_CLK_EN, | ||
| 77 | !IMX6Q_GPR13_SATA_MPLL_CLK_EN); | ||
| 78 | clk_disable_unprepare(imxpriv->sata_ref_clk); | ||
| 79 | imxpriv->no_device = true; | ||
| 80 | } | ||
| 81 | |||
| 82 | static struct ata_port_operations ahci_imx_ops = { | ||
| 83 | .inherits = &ahci_platform_ops, | ||
| 84 | .error_handler = ahci_imx_error_handler, | ||
| 85 | }; | ||
| 86 | |||
| 87 | static const struct ata_port_info ahci_imx_port_info = { | ||
| 88 | .flags = AHCI_FLAG_COMMON, | ||
| 89 | .pio_mask = ATA_PIO4, | ||
| 90 | .udma_mask = ATA_UDMA6, | ||
| 91 | .port_ops = &ahci_imx_ops, | ||
| 39 | }; | 92 | }; |
| 40 | 93 | ||
| 41 | static int imx6q_sata_init(struct device *dev, void __iomem *mmio) | 94 | static int imx6q_sata_init(struct device *dev, void __iomem *mmio) |
| @@ -117,9 +170,51 @@ static void imx6q_sata_exit(struct device *dev) | |||
| 117 | clk_disable_unprepare(imxpriv->sata_ref_clk); | 170 | clk_disable_unprepare(imxpriv->sata_ref_clk); |
| 118 | } | 171 | } |
| 119 | 172 | ||
| 173 | static int imx_ahci_suspend(struct device *dev) | ||
| 174 | { | ||
| 175 | struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent); | ||
| 176 | |||
| 177 | /* | ||
| 178 | * If no_device is set, The CLKs had been gated off in the | ||
| 179 | * initialization so don't do it again here. | ||
| 180 | */ | ||
| 181 | if (!imxpriv->no_device) { | ||
| 182 | regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, | ||
| 183 | IMX6Q_GPR13_SATA_MPLL_CLK_EN, | ||
| 184 | !IMX6Q_GPR13_SATA_MPLL_CLK_EN); | ||
| 185 | clk_disable_unprepare(imxpriv->sata_ref_clk); | ||
| 186 | } | ||
| 187 | |||
| 188 | return 0; | ||
| 189 | } | ||
| 190 | |||
| 191 | static int imx_ahci_resume(struct device *dev) | ||
| 192 | { | ||
| 193 | struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent); | ||
| 194 | int ret; | ||
| 195 | |||
| 196 | if (!imxpriv->no_device) { | ||
| 197 | ret = clk_prepare_enable(imxpriv->sata_ref_clk); | ||
| 198 | if (ret < 0) { | ||
| 199 | dev_err(dev, "pre-enable sata_ref clock err:%d\n", ret); | ||
| 200 | return ret; | ||
| 201 | } | ||
| 202 | |||
| 203 | regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, | ||
| 204 | IMX6Q_GPR13_SATA_MPLL_CLK_EN, | ||
| 205 | IMX6Q_GPR13_SATA_MPLL_CLK_EN); | ||
| 206 | usleep_range(1000, 2000); | ||
| 207 | } | ||
| 208 | |||
| 209 | return 0; | ||
| 210 | } | ||
| 211 | |||
| 120 | static struct ahci_platform_data imx6q_sata_pdata = { | 212 | static struct ahci_platform_data imx6q_sata_pdata = { |
| 121 | .init = imx6q_sata_init, | 213 | .init = imx6q_sata_init, |
| 122 | .exit = imx6q_sata_exit, | 214 | .exit = imx6q_sata_exit, |
| 215 | .ata_port_info = &ahci_imx_port_info, | ||
| 216 | .suspend = imx_ahci_suspend, | ||
| 217 | .resume = imx_ahci_resume, | ||
| 123 | }; | 218 | }; |
| 124 | 219 | ||
| 125 | static const struct of_device_id imx_ahci_of_match[] = { | 220 | static const struct of_device_id imx_ahci_of_match[] = { |
| @@ -152,6 +247,8 @@ static int imx_ahci_probe(struct platform_device *pdev) | |||
| 152 | ahci_dev = &ahci_pdev->dev; | 247 | ahci_dev = &ahci_pdev->dev; |
| 153 | ahci_dev->parent = dev; | 248 | ahci_dev->parent = dev; |
| 154 | 249 | ||
| 250 | imxpriv->no_device = false; | ||
| 251 | imxpriv->first_time = true; | ||
| 155 | imxpriv->ahb_clk = devm_clk_get(dev, "ahb"); | 252 | imxpriv->ahb_clk = devm_clk_get(dev, "ahb"); |
| 156 | if (IS_ERR(imxpriv->ahb_clk)) { | 253 | if (IS_ERR(imxpriv->ahb_clk)) { |
| 157 | dev_err(dev, "can't get ahb clock.\n"); | 254 | dev_err(dev, "can't get ahb clock.\n"); |
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index 2daaee05cab1..7708ca71f14e 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c | |||
| @@ -49,10 +49,11 @@ static struct platform_device_id ahci_devtype[] = { | |||
| 49 | }; | 49 | }; |
| 50 | MODULE_DEVICE_TABLE(platform, ahci_devtype); | 50 | MODULE_DEVICE_TABLE(platform, ahci_devtype); |
| 51 | 51 | ||
| 52 | static struct ata_port_operations ahci_platform_ops = { | 52 | struct ata_port_operations ahci_platform_ops = { |
| 53 | .inherits = &ahci_ops, | 53 | .inherits = &ahci_ops, |
| 54 | .host_stop = ahci_host_stop, | 54 | .host_stop = ahci_host_stop, |
| 55 | }; | 55 | }; |
| 56 | EXPORT_SYMBOL_GPL(ahci_platform_ops); | ||
| 56 | 57 | ||
| 57 | static struct ata_port_operations ahci_platform_retry_srst_ops = { | 58 | static struct ata_port_operations ahci_platform_retry_srst_ops = { |
| 58 | .inherits = &ahci_pmp_retry_srst_ops, | 59 | .inherits = &ahci_pmp_retry_srst_ops, |
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index b67086fde1f1..7e2a1b38093e 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c | |||
| @@ -89,7 +89,6 @@ static int ahci_pmp_retry_softreset(struct ata_link *link, unsigned int *class, | |||
| 89 | static int ahci_hardreset(struct ata_link *link, unsigned int *class, | 89 | static int ahci_hardreset(struct ata_link *link, unsigned int *class, |
| 90 | unsigned long deadline); | 90 | unsigned long deadline); |
| 91 | static void ahci_postreset(struct ata_link *link, unsigned int *class); | 91 | static void ahci_postreset(struct ata_link *link, unsigned int *class); |
| 92 | static void ahci_error_handler(struct ata_port *ap); | ||
| 93 | static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); | 92 | static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); |
| 94 | static void ahci_dev_config(struct ata_device *dev); | 93 | static void ahci_dev_config(struct ata_device *dev); |
| 95 | #ifdef CONFIG_PM | 94 | #ifdef CONFIG_PM |
| @@ -1982,7 +1981,7 @@ static void ahci_thaw(struct ata_port *ap) | |||
| 1982 | writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); | 1981 | writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); |
| 1983 | } | 1982 | } |
| 1984 | 1983 | ||
| 1985 | static void ahci_error_handler(struct ata_port *ap) | 1984 | void ahci_error_handler(struct ata_port *ap) |
| 1986 | { | 1985 | { |
| 1987 | if (!(ap->pflags & ATA_PFLAG_FROZEN)) { | 1986 | if (!(ap->pflags & ATA_PFLAG_FROZEN)) { |
| 1988 | /* restart engine */ | 1987 | /* restart engine */ |
| @@ -1995,6 +1994,7 @@ static void ahci_error_handler(struct ata_port *ap) | |||
| 1995 | if (!ata_dev_enabled(ap->link.device)) | 1994 | if (!ata_dev_enabled(ap->link.device)) |
| 1996 | ahci_stop_engine(ap); | 1995 | ahci_stop_engine(ap); |
| 1997 | } | 1996 | } |
| 1997 | EXPORT_SYMBOL_GPL(ahci_error_handler); | ||
| 1998 | 1998 | ||
| 1999 | static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) | 1999 | static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) |
| 2000 | { | 2000 | { |
