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 | { |