Merge branch 'for-3.15' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 31 Mar 2014 22:27:37 +0000 (15:27 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 31 Mar 2014 22:27:37 +0000 (15:27 -0700)
Pull libata updates from Tejun Heo:
 "A lot of activities on libata side this time.

   - A lot of changes around ahci.  Various embedded platforms are
     implementing ahci controllers.  Some were built atop ahci_platform,
     others were doing their own things.  Hans made some structural
     changes to libahci and librarized ahci_platform so that ahci
     platform drivers can share more common code.  A couple platform
     drivers are added on top of that and several are added to replace
     older drivers which were doing their own things (older ones are
     scheduled to be removed).

   - Dan finishes the patchset to make libata PM operations
     asynchronous.  Combined with one patch being routed through scsi,
     this should speed resume measurably.

   - Various fixes and cleanups from Bartlomiej and others"

* 'for-3.15' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata: (61 commits)
  ata: fix Marvell SATA driver dependencies
  ata: fix ARASAN CompactFlash PATA driver dependencies
  ata: remove superfluous casts
  ata: sata_highbank: remove superfluous cast
  ata: fix Calxeda Highbank SATA driver dependencies
  ata: fix R-Car SATA driver dependencies
  ARM: davinci: da850: update SATA AHCI support
  ata: add new-style AHCI platform driver for DaVinci DA850 AHCI controller
  ata: move library code from ahci_platform.c to libahci_platform.c
  ata: ahci_platform: fix ahci_platform_data->suspend method handling
  libata: remove unused ata_sas_port_async_resume() stub
  libata.h: add stub for ata_sas_port_resume
  libata: async resume
  libata, libsas: kill pm_result and related cleanup
  ata: Fix compiler warning with APM X-Gene host controller driver
  arm64: Add APM X-Gene SoC AHCI SATA host controller DTS entries
  ata: Add APM X-Gene SoC AHCI SATA host controller driver
  Documentation: Add documentation for the APM X-Gene SoC SATA host controller DTS binding
  arm64: Add APM X-Gene SoC 15Gbps Multi-purpose PHY DTS entries
  ata: ahci_sunxi: fix code formatting
  ...

92 files changed:
Documentation/devicetree/bindings/ata/ahci-platform.txt
Documentation/devicetree/bindings/ata/apm-xgene.txt [new file with mode: 0644]
arch/arm/mach-davinci/da850.c
arch/arm/mach-davinci/devices-da8xx.c
arch/arm64/boot/dts/apm-storm.dtsi
drivers/ata/Kconfig
drivers/ata/Makefile
drivers/ata/acard-ahci.c
drivers/ata/ahci.c
drivers/ata/ahci.h
drivers/ata/ahci_da850.c [new file with mode: 0644]
drivers/ata/ahci_imx.c
drivers/ata/ahci_platform.c
drivers/ata/ahci_st.c [new file with mode: 0644]
drivers/ata/ahci_sunxi.c [new file with mode: 0644]
drivers/ata/ahci_xgene.c [new file with mode: 0644]
drivers/ata/ata_generic.c
drivers/ata/libahci.c
drivers/ata/libahci_platform.c [new file with mode: 0644]
drivers/ata/libata-acpi.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata-zpodd.c
drivers/ata/pata_acpi.c
drivers/ata/pata_amd.c
drivers/ata/pata_arasan_cf.c
drivers/ata/pata_artop.c
drivers/ata/pata_at91.c
drivers/ata/pata_atiixp.c
drivers/ata/pata_atp867x.c
drivers/ata/pata_cmd640.c
drivers/ata/pata_cmd64x.c
drivers/ata/pata_cs5520.c
drivers/ata/pata_cs5530.c
drivers/ata/pata_cs5535.c
drivers/ata/pata_cs5536.c
drivers/ata/pata_cypress.c
drivers/ata/pata_efar.c
drivers/ata/pata_ep93xx.c
drivers/ata/pata_hpt366.c
drivers/ata/pata_hpt37x.c
drivers/ata/pata_hpt3x2n.c
drivers/ata/pata_hpt3x3.c
drivers/ata/pata_imx.c
drivers/ata/pata_it8213.c
drivers/ata/pata_it821x.c
drivers/ata/pata_jmicron.c
drivers/ata/pata_legacy.c
drivers/ata/pata_marvell.c
drivers/ata/pata_mpiix.c
drivers/ata/pata_netcell.c
drivers/ata/pata_ninja32.c
drivers/ata/pata_ns87410.c
drivers/ata/pata_ns87415.c
drivers/ata/pata_oldpiix.c
drivers/ata/pata_opti.c
drivers/ata/pata_optidma.c
drivers/ata/pata_pcmcia.c
drivers/ata/pata_pdc2027x.c
drivers/ata/pata_pdc202xx_old.c
drivers/ata/pata_piccolo.c
drivers/ata/pata_platform.c
drivers/ata/pata_pxa.c
drivers/ata/pata_radisys.c
drivers/ata/pata_rdc.c
drivers/ata/pata_rz1000.c
drivers/ata/pata_sc1200.c
drivers/ata/pata_scc.c
drivers/ata/pata_sch.c
drivers/ata/pata_serverworks.c
drivers/ata/pata_sil680.c
drivers/ata/pata_sis.c
drivers/ata/pata_sl82c105.c
drivers/ata/pata_triflex.c
drivers/ata/pata_via.c
drivers/ata/pdc_adma.c
drivers/ata/sata_dwc_460ex.c
drivers/ata/sata_highbank.c
drivers/ata/sata_nv.c
drivers/ata/sata_promise.c
drivers/ata/sata_qstor.c
drivers/ata/sata_sil.c
drivers/ata/sata_sis.c
drivers/ata/sata_svw.c
drivers/ata/sata_sx4.c
drivers/ata/sata_uli.c
drivers/ata/sata_via.c
drivers/ata/sata_vsc.c
drivers/scsi/libsas/sas_ata.c
include/linux/ahci_platform.h
include/linux/libata.h
include/scsi/libsas.h

index 89de1564950ce64cf2bdb1e087da04e2043a0db6..48b285ffa3a650e7d0adb028e7f577617b2dff9c 100644 (file)
@@ -4,17 +4,33 @@ SATA nodes are defined to describe on-chip Serial ATA controllers.
 Each SATA controller should have its own node.
 
 Required properties:
-- compatible        : compatible list, contains "snps,spear-ahci"
+- compatible        : compatible list, one of "snps,spear-ahci",
+                      "snps,exynos5440-ahci", "ibm,476gtr-ahci",
+                      "allwinner,sun4i-a10-ahci", "fsl,imx53-ahci"
+                      "fsl,imx6q-ahci" or "snps,dwc-ahci"
 - interrupts        : <interrupt mapping for SATA IRQ>
 - reg               : <registers mapping>
 
 Optional properties:
 - dma-coherent      : Present if dma operations are coherent
+- clocks            : a list of phandle + clock specifier pairs
+- target-supply     : regulator for SATA target power
 
-Example:
+"fsl,imx53-ahci", "fsl,imx6q-ahci" required properties:
+- clocks            : must contain the sata, sata_ref and ahb clocks
+- clock-names       : must contain "ahb" for the ahb clock
+
+Examples:
         sata@ffe08000 {
                compatible = "snps,spear-ahci";
                reg = <0xffe08000 0x1000>;
                interrupts = <115>;
-
         };
+
+       ahci: sata@01c18000 {
+               compatible = "allwinner,sun4i-a10-ahci";
+               reg = <0x01c18000 0x1000>;
+               interrupts = <56>;
+               clocks = <&pll6 0>, <&ahb_gates 25>;
+               target-supply = <&reg_ahci_5v>;
+       };
diff --git a/Documentation/devicetree/bindings/ata/apm-xgene.txt b/Documentation/devicetree/bindings/ata/apm-xgene.txt
new file mode 100644 (file)
index 0000000..7bcfbf5
--- /dev/null
@@ -0,0 +1,76 @@
+* APM X-Gene 6.0 Gb/s SATA host controller nodes
+
+SATA host controller nodes are defined to describe on-chip Serial ATA
+controllers. Each SATA controller (pair of ports) have its own node.
+
+Required properties:
+- compatible           : Shall contain:
+  * "apm,xgene-ahci"
+- reg                  : First memory resource shall be the AHCI memory
+                         resource.
+                         Second memory resource shall be the host controller
+                         core memory resource.
+                         Third memory resource shall be the host controller
+                         diagnostic memory resource.
+                         4th memory resource shall be the host controller
+                         AXI memory resource.
+                         5th optional memory resource shall be the host
+                         controller MUX memory resource if required.
+- interrupts           : Interrupt-specifier for SATA host controller IRQ.
+- clocks               : Reference to the clock entry.
+- phys                 : A list of phandles + phy-specifiers, one for each
+                         entry in phy-names.
+- phy-names            : Should contain:
+  * "sata-phy" for the SATA 6.0Gbps PHY
+
+Optional properties:
+- status               : Shall be "ok" if enabled or "disabled" if disabled.
+                         Default is "ok".
+
+Example:
+               sataclk: sataclk {
+                       compatible = "fixed-clock";
+                       #clock-cells = <1>;
+                       clock-frequency = <100000000>;
+                       clock-output-names = "sataclk";
+               };
+
+               phy2: phy@1f22a000 {
+                       compatible = "apm,xgene-phy";
+                       reg = <0x0 0x1f22a000 0x0 0x100>;
+                       #phy-cells = <1>;
+               };
+
+               phy3: phy@1f23a000 {
+                       compatible = "apm,xgene-phy";
+                       reg = <0x0 0x1f23a000 0x0 0x100>;
+                       #phy-cells = <1>;
+               };
+
+               sata2: sata@1a400000 {
+                       compatible = "apm,xgene-ahci";
+                       reg = <0x0 0x1a400000 0x0 0x1000>,
+                             <0x0 0x1f220000 0x0 0x1000>,
+                             <0x0 0x1f22d000 0x0 0x1000>,
+                             <0x0 0x1f22e000 0x0 0x1000>,
+                             <0x0 0x1f227000 0x0 0x1000>;
+                       interrupts = <0x0 0x87 0x4>;
+                       status = "ok";
+                       clocks = <&sataclk 0>;
+                       phys = <&phy2 0>;
+                       phy-names = "sata-phy";
+               };
+
+               sata3: sata@1a800000 {
+                       compatible = "apm,xgene-ahci-pcie";
+                       reg = <0x0 0x1a800000 0x0 0x1000>,
+                             <0x0 0x1f230000 0x0 0x1000>,
+                             <0x0 0x1f23d000 0x0 0x1000>,
+                             <0x0 0x1f23e000 0x0 0x1000>,
+                             <0x0 0x1f237000 0x0 0x1000>;
+                       interrupts = <0x0 0x88 0x4>;
+                       status = "ok";
+                       clocks = <&sataclk 0>;
+                       phys = <&phy3 0>;
+                       phy-names = "sata-phy";
+               };
index 2ab00434b2eb64405a2c4b75f315950cbe9663c0..85399c98f84a7f30657ecc57beb267d404593560 100644 (file)
@@ -472,7 +472,7 @@ static struct clk_lookup da850_clks[] = {
        CLK("spi_davinci.0",    NULL,           &spi0_clk),
        CLK("spi_davinci.1",    NULL,           &spi1_clk),
        CLK("vpif",             NULL,           &vpif_clk),
-       CLK("ahci",             NULL,           &sata_clk),
+       CLK("ahci_da850",               NULL,           &sata_clk),
        CLK("davinci-rproc.0",  NULL,           &dsp_clk),
        CLK("ehrpwm",           "fck",          &ehrpwm_clk),
        CLK("ehrpwm",           "tbclk",        &ehrpwm_tbclk),
index 0486cdf28c8d552205ff4285fe7d7476721cc2a6..56ea41d5f8491307ab89b3178365071cec34ee3d 100644 (file)
@@ -1020,111 +1020,29 @@ int __init da8xx_register_spi_bus(int instance, unsigned num_chipselect)
 }
 
 #ifdef CONFIG_ARCH_DAVINCI_DA850
-
 static struct resource da850_sata_resources[] = {
        {
                .start  = DA850_SATA_BASE,
                .end    = DA850_SATA_BASE + 0x1fff,
                .flags  = IORESOURCE_MEM,
        },
+       {
+               .start  = DA8XX_SYSCFG1_BASE + DA8XX_PWRDN_REG,
+               .end    = DA8XX_SYSCFG1_BASE + DA8XX_PWRDN_REG + 0x3,
+               .flags  = IORESOURCE_MEM,
+       },
        {
                .start  = IRQ_DA850_SATAINT,
                .flags  = IORESOURCE_IRQ,
        },
 };
 
-/* SATA PHY Control Register offset from AHCI base */
-#define SATA_P0PHYCR_REG       0x178
-
-#define SATA_PHY_MPY(x)                ((x) << 0)
-#define SATA_PHY_LOS(x)                ((x) << 6)
-#define SATA_PHY_RXCDR(x)      ((x) << 10)
-#define SATA_PHY_RXEQ(x)       ((x) << 13)
-#define SATA_PHY_TXSWING(x)    ((x) << 19)
-#define SATA_PHY_ENPLL(x)      ((x) << 31)
-
-static struct clk *da850_sata_clk;
-static unsigned long da850_sata_refclkpn;
-
-/* Supported DA850 SATA crystal frequencies */
-#define KHZ_TO_HZ(freq) ((freq) * 1000)
-static unsigned long da850_sata_xtal[] = {
-       KHZ_TO_HZ(300000),
-       KHZ_TO_HZ(250000),
-       0,                      /* Reserved */
-       KHZ_TO_HZ(187500),
-       KHZ_TO_HZ(150000),
-       KHZ_TO_HZ(125000),
-       KHZ_TO_HZ(120000),
-       KHZ_TO_HZ(100000),
-       KHZ_TO_HZ(75000),
-       KHZ_TO_HZ(60000),
-};
-
-static int da850_sata_init(struct device *dev, void __iomem *addr)
-{
-       int i, ret;
-       unsigned int val;
-
-       da850_sata_clk = clk_get(dev, NULL);
-       if (IS_ERR(da850_sata_clk))
-               return PTR_ERR(da850_sata_clk);
-
-       ret = clk_prepare_enable(da850_sata_clk);
-       if (ret)
-               goto err0;
-
-       /* Enable SATA clock receiver */
-       val = __raw_readl(DA8XX_SYSCFG1_VIRT(DA8XX_PWRDN_REG));
-       val &= ~BIT(0);
-       __raw_writel(val, DA8XX_SYSCFG1_VIRT(DA8XX_PWRDN_REG));
-
-       /* Get the multiplier needed for 1.5GHz PLL output */
-       for (i = 0; i < ARRAY_SIZE(da850_sata_xtal); i++)
-               if (da850_sata_xtal[i] == da850_sata_refclkpn)
-                       break;
-
-       if (i == ARRAY_SIZE(da850_sata_xtal)) {
-               ret = -EINVAL;
-               goto err1;
-       }
-
-       val = SATA_PHY_MPY(i + 1) |
-               SATA_PHY_LOS(1) |
-               SATA_PHY_RXCDR(4) |
-               SATA_PHY_RXEQ(1) |
-               SATA_PHY_TXSWING(3) |
-               SATA_PHY_ENPLL(1);
-
-       __raw_writel(val, addr + SATA_P0PHYCR_REG);
-
-       return 0;
-
-err1:
-       clk_disable_unprepare(da850_sata_clk);
-err0:
-       clk_put(da850_sata_clk);
-       return ret;
-}
-
-static void da850_sata_exit(struct device *dev)
-{
-       clk_disable_unprepare(da850_sata_clk);
-       clk_put(da850_sata_clk);
-}
-
-static struct ahci_platform_data da850_sata_pdata = {
-       .init   = da850_sata_init,
-       .exit   = da850_sata_exit,
-};
-
 static u64 da850_sata_dmamask = DMA_BIT_MASK(32);
 
 static struct platform_device da850_sata_device = {
-       .name   = "ahci",
+       .name   = "ahci_da850",
        .id     = -1,
        .dev    = {
-               .platform_data          = &da850_sata_pdata,
                .dma_mask               = &da850_sata_dmamask,
                .coherent_dma_mask      = DMA_BIT_MASK(32),
        },
@@ -1134,9 +1052,8 @@ static struct platform_device da850_sata_device = {
 
 int __init da850_register_sata(unsigned long refclkpn)
 {
-       da850_sata_refclkpn = refclkpn;
-       if (!da850_sata_refclkpn)
-               return -EINVAL;
+       /* please see comment in drivers/ata/ahci_da850.c */
+       BUG_ON(refclkpn != 100 * 1000 * 1000);
 
        return platform_device_register(&da850_sata_device);
 }
index d37d7369e260f3f7d2564711217f6d6ac19a859a..93f4b2dd92484863e8015da4a622a0c17745de5a 100644 (file)
                                reg-names = "csr-reg";
                                clock-output-names = "eth8clk";
                        };
+
+                       sataphy1clk: sataphy1clk@1f21c000 {
+                               compatible = "apm,xgene-device-clock";
+                               #clock-cells = <1>;
+                               clocks = <&socplldiv2 0>;
+                               reg = <0x0 0x1f21c000 0x0 0x1000>;
+                               reg-names = "csr-reg";
+                               clock-output-names = "sataphy1clk";
+                               status = "disabled";
+                               csr-offset = <0x4>;
+                               csr-mask = <0x00>;
+                               enable-offset = <0x0>;
+                               enable-mask = <0x06>;
+                       };
+
+                       sataphy2clk: sataphy1clk@1f22c000 {
+                               compatible = "apm,xgene-device-clock";
+                               #clock-cells = <1>;
+                               clocks = <&socplldiv2 0>;
+                               reg = <0x0 0x1f22c000 0x0 0x1000>;
+                               reg-names = "csr-reg";
+                               clock-output-names = "sataphy2clk";
+                               status = "ok";
+                               csr-offset = <0x4>;
+                               csr-mask = <0x3a>;
+                               enable-offset = <0x0>;
+                               enable-mask = <0x06>;
+                       };
+
+                       sataphy3clk: sataphy1clk@1f23c000 {
+                               compatible = "apm,xgene-device-clock";
+                               #clock-cells = <1>;
+                               clocks = <&socplldiv2 0>;
+                               reg = <0x0 0x1f23c000 0x0 0x1000>;
+                               reg-names = "csr-reg";
+                               clock-output-names = "sataphy3clk";
+                               status = "ok";
+                               csr-offset = <0x4>;
+                               csr-mask = <0x3a>;
+                               enable-offset = <0x0>;
+                               enable-mask = <0x06>;
+                       };
+
+                       sata01clk: sata01clk@1f21c000 {
+                               compatible = "apm,xgene-device-clock";
+                               #clock-cells = <1>;
+                               clocks = <&socplldiv2 0>;
+                               reg = <0x0 0x1f21c000 0x0 0x1000>;
+                               reg-names = "csr-reg";
+                               clock-output-names = "sata01clk";
+                               csr-offset = <0x4>;
+                               csr-mask = <0x05>;
+                               enable-offset = <0x0>;
+                               enable-mask = <0x39>;
+                       };
+
+                       sata23clk: sata23clk@1f22c000 {
+                               compatible = "apm,xgene-device-clock";
+                               #clock-cells = <1>;
+                               clocks = <&socplldiv2 0>;
+                               reg = <0x0 0x1f22c000 0x0 0x1000>;
+                               reg-names = "csr-reg";
+                               clock-output-names = "sata23clk";
+                               csr-offset = <0x4>;
+                               csr-mask = <0x05>;
+                               enable-offset = <0x0>;
+                               enable-mask = <0x39>;
+                       };
+
+                       sata45clk: sata45clk@1f23c000 {
+                               compatible = "apm,xgene-device-clock";
+                               #clock-cells = <1>;
+                               clocks = <&socplldiv2 0>;
+                               reg = <0x0 0x1f23c000 0x0 0x1000>;
+                               reg-names = "csr-reg";
+                               clock-output-names = "sata45clk";
+                               csr-offset = <0x4>;
+                               csr-mask = <0x05>;
+                               enable-offset = <0x0>;
+                               enable-mask = <0x39>;
+                       };
                };
 
                serial0: serial@1c020000 {
                        interrupt-parent = <&gic>;
                        interrupts = <0x0 0x4c 0x4>;
                };
+
+               phy1: phy@1f21a000 {
+                       compatible = "apm,xgene-phy";
+                       reg = <0x0 0x1f21a000 0x0 0x100>;
+                       #phy-cells = <1>;
+                       clocks = <&sataphy1clk 0>;
+                       status = "disabled";
+                       apm,tx-boost-gain = <30 30 30 30 30 30>;
+                       apm,tx-eye-tuning = <2 10 10 2 10 10>;
+               };
+
+               phy2: phy@1f22a000 {
+                       compatible = "apm,xgene-phy";
+                       reg = <0x0 0x1f22a000 0x0 0x100>;
+                       #phy-cells = <1>;
+                       clocks = <&sataphy2clk 0>;
+                       status = "ok";
+                       apm,tx-boost-gain = <30 30 30 30 30 30>;
+                       apm,tx-eye-tuning = <1 10 10 2 10 10>;
+               };
+
+               phy3: phy@1f23a000 {
+                       compatible = "apm,xgene-phy";
+                       reg = <0x0 0x1f23a000 0x0 0x100>;
+                       #phy-cells = <1>;
+                       clocks = <&sataphy3clk 0>;
+                       status = "ok";
+                       apm,tx-boost-gain = <31 31 31 31 31 31>;
+                       apm,tx-eye-tuning = <2 10 10 2 10 10>;
+               };
+
+               sata1: sata@1a000000 {
+                       compatible = "apm,xgene-ahci";
+                       reg = <0x0 0x1a000000 0x0 0x1000>,
+                             <0x0 0x1f210000 0x0 0x1000>,
+                             <0x0 0x1f21d000 0x0 0x1000>,
+                             <0x0 0x1f21e000 0x0 0x1000>,
+                             <0x0 0x1f217000 0x0 0x1000>;
+                       interrupts = <0x0 0x86 0x4>;
+                       status = "disabled";
+                       clocks = <&sata01clk 0>;
+                       phys = <&phy1 0>;
+                       phy-names = "sata-phy";
+               };
+
+               sata2: sata@1a400000 {
+                       compatible = "apm,xgene-ahci";
+                       reg = <0x0 0x1a400000 0x0 0x1000>,
+                             <0x0 0x1f220000 0x0 0x1000>,
+                             <0x0 0x1f22d000 0x0 0x1000>,
+                             <0x0 0x1f22e000 0x0 0x1000>,
+                             <0x0 0x1f227000 0x0 0x1000>;
+                       interrupts = <0x0 0x87 0x4>;
+                       status = "ok";
+                       clocks = <&sata23clk 0>;
+                       phys = <&phy2 0>;
+                       phy-names = "sata-phy";
+               };
+
+               sata3: sata@1a800000 {
+                       compatible = "apm,xgene-ahci";
+                       reg = <0x0 0x1a800000 0x0 0x1000>,
+                             <0x0 0x1f230000 0x0 0x1000>,
+                             <0x0 0x1f23d000 0x0 0x1000>,
+                             <0x0 0x1f23e000 0x0 0x1000>;
+                       interrupts = <0x0 0x88 0x4>;
+                       status = "ok";
+                       clocks = <&sata45clk 0>;
+                       phys = <&phy3 0>;
+                       phy-names = "sata-phy";
+               };
        };
 };
index 868429a47be41a2c50ff146389df25dfcb8f5b30..20e03a7eb8b431f692e534f6a3d895a2c2cd9476 100644 (file)
@@ -11,13 +11,13 @@ config HAVE_PATA_PLATFORM
          to update the PATA_PLATFORM entry.
 
 menuconfig ATA
-       tristate "Serial ATA and Parallel ATA drivers"
+       tristate "Serial ATA and Parallel ATA drivers (libata)"
        depends on HAS_IOMEM
        depends on BLOCK
        depends on !(M32R || M68K || S390) || BROKEN
        select SCSI
        ---help---
-         If you want to use a ATA hard disk, ATA tape drive, ATA CD-ROM or
+         If you want to use an ATA hard disk, ATA tape drive, ATA CD-ROM or
          any other ATA device under Linux, say Y and make sure that you know
          the name of your ATA host adapter (the card inside your computer
          that "speaks" the ATA protocol, also called ATA controller),
@@ -60,7 +60,7 @@ config ATA_ACPI
 
 config SATA_ZPODD
        bool "SATA Zero Power Optical Disc Drive (ZPODD) support"
-       depends on ATA_ACPI
+       depends on ATA_ACPI && PM_RUNTIME
        default n
        help
          This option adds support for SATA Zero Power Optical Disc
@@ -97,15 +97,48 @@ config SATA_AHCI_PLATFORM
 
          If unsure, say N.
 
+config AHCI_DA850
+       tristate "DaVinci DA850 AHCI SATA support"
+       depends on ARCH_DAVINCI_DA850
+       help
+         This option enables support for the DaVinci DA850 SoC's
+         onboard AHCI SATA.
+
+         If unsure, say N.
+
+config AHCI_ST
+       tristate "ST AHCI SATA support"
+       depends on ARCH_STI
+       help
+         This option enables support for ST AHCI SATA controller.
+
+         If unsure, say N.
+
 config AHCI_IMX
        tristate "Freescale i.MX AHCI SATA support"
-       depends on SATA_AHCI_PLATFORM && MFD_SYSCON
+       depends on MFD_SYSCON
        help
          This option enables support for the Freescale i.MX SoC's
          onboard AHCI SATA.
 
          If unsure, say N.
 
+config AHCI_SUNXI
+       tristate "Allwinner sunxi AHCI SATA support"
+       depends on ARCH_SUNXI
+       help
+         This option enables support for the Allwinner sunxi SoC's
+         onboard AHCI SATA.
+
+         If unsure, say N.
+
+config AHCI_XGENE
+       tristate "APM X-Gene 6.0Gbps AHCI SATA host controller support"
+       depends on ARM64 || COMPILE_TEST
+       select PHY_XGENE
+       help
+        This option enables support for APM X-Gene SoC SATA host controller.
+
 config SATA_FSL
        tristate "Freescale 3.0Gbps SATA support"
        depends on FSL_SOC
@@ -239,6 +272,7 @@ config SATA_DWC_VDEBUG
 
 config SATA_HIGHBANK
        tristate "Calxeda Highbank SATA support"
+       depends on ARCH_HIGHBANK || COMPILE_TEST
        help
          This option enables support for the Calxeda Highbank SoC's
          onboard SATA.
@@ -247,6 +281,8 @@ config SATA_HIGHBANK
 
 config SATA_MV
        tristate "Marvell SATA support"
+       depends on PCI || ARCH_DOVE || ARCH_KIRKWOOD || ARCH_MV78XX0 || \
+                  ARCH_MVEBU || ARCH_ORION5X || COMPILE_TEST
        select GENERIC_PHY
        help
          This option enables support for the Marvell Serial ATA family.
@@ -273,6 +309,7 @@ config SATA_PROMISE
 
 config SATA_RCAR
        tristate "Renesas R-Car SATA support"
+       depends on ARCH_SHMOBILE || COMPILE_TEST
        help
          This option enables support for Renesas R-Car Serial ATA.
 
@@ -352,6 +389,7 @@ config PATA_AMD
 
 config PATA_ARASAN_CF
        tristate "ARASAN CompactFlash PATA Controller Support"
+       depends on ARCH_SPEAR13XX || COMPILE_TEST
        depends on DMADEVICES
        select DMA_ENGINE
        help
@@ -403,7 +441,7 @@ config PATA_CMD64X
 
 config PATA_CS5520
        tristate "CS5510/5520 PATA support"
-       depends on PCI
+       depends on PCI && (X86_32 || COMPILE_TEST)
        help
          This option enables support for the Cyrix 5510/5520
          companion chip used with the MediaGX/Geode processor family.
@@ -412,7 +450,7 @@ config PATA_CS5520
 
 config PATA_CS5530
        tristate "CS5530 PATA support"
-       depends on PCI
+       depends on PCI && (X86_32 || COMPILE_TEST)
        help
          This option enables support for the Cyrix/NatSemi/AMD CS5530
          companion chip used with the MediaGX/Geode processor family.
@@ -421,7 +459,7 @@ config PATA_CS5530
 
 config PATA_CS5535
        tristate "CS5535 PATA support (Experimental)"
-       depends on PCI && X86 && !X86_64
+       depends on PCI && X86_32
        help
          This option enables support for the NatSemi/AMD CS5535
          companion chip used with the Geode processor family.
@@ -430,7 +468,7 @@ config PATA_CS5535
 
 config PATA_CS5536
        tristate "CS5536 PATA support"
-       depends on PCI
+       depends on PCI && (X86_32 || MIPS || COMPILE_TEST)
        help
          This option enables support for the AMD CS5536
          companion chip used with the Geode LX processor family.
@@ -666,7 +704,7 @@ config PATA_RDC
 
 config PATA_SC1200
        tristate "SC1200 PATA support"
-       depends on PCI
+       depends on PCI && (X86_32 || COMPILE_TEST)
        help
          This option enables support for the NatSemi/AMD SC1200 SoC
          companion chip used with the Geode processor family.
index 46518c622460942cdf8e2971dd95f3b069961ada..44c8016e565c9b8771924fbc7f7b5a00d9c078c7 100644 (file)
@@ -4,13 +4,17 @@ obj-$(CONFIG_ATA)             += libata.o
 # non-SFF interface
 obj-$(CONFIG_SATA_AHCI)                += ahci.o libahci.o
 obj-$(CONFIG_SATA_ACARD_AHCI)  += acard-ahci.o libahci.o
-obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o
+obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o libahci_platform.o
 obj-$(CONFIG_SATA_FSL)         += sata_fsl.o
 obj-$(CONFIG_SATA_INIC162X)    += sata_inic162x.o
 obj-$(CONFIG_SATA_SIL24)       += sata_sil24.o
 obj-$(CONFIG_SATA_DWC)         += sata_dwc_460ex.o
 obj-$(CONFIG_SATA_HIGHBANK)    += sata_highbank.o libahci.o
-obj-$(CONFIG_AHCI_IMX)         += ahci_imx.o
+obj-$(CONFIG_AHCI_DA850)       += ahci_da850.o libahci.o libahci_platform.o
+obj-$(CONFIG_AHCI_IMX)         += ahci_imx.o libahci.o libahci_platform.o
+obj-$(CONFIG_AHCI_SUNXI)       += ahci_sunxi.o libahci.o libahci_platform.o
+obj-$(CONFIG_AHCI_ST)          += ahci_st.o libahci.o libahci_platform.o
+obj-$(CONFIG_AHCI_XGENE)       += ahci_xgene.o libahci.o libahci_platform.o
 
 # SFF w/ custom DMA
 obj-$(CONFIG_PDC_ADMA)         += pdc_adma.o
index fd665d919df2e59a4b44c334bd9c96d14fd946b5..b51605ac597418f7aa352789dc9aeeb1b8ca015b 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index c81d809c111b238e72f65d185add59f5bef4fade..a52a5b662f35ecceb992fd41943ef5f636834838 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -578,6 +577,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
                                 unsigned long deadline)
 {
        struct ata_port *ap = link->ap;
+       struct ahci_host_priv *hpriv = ap->host->private_data;
        bool online;
        int rc;
 
@@ -588,7 +588,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
        rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
                                 deadline, &online, NULL);
 
-       ahci_start_engine(ap);
+       hpriv->start_engine(ap);
 
        DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
 
@@ -603,6 +603,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
 {
        struct ata_port *ap = link->ap;
        struct ahci_port_priv *pp = ap->private_data;
+       struct ahci_host_priv *hpriv = ap->host->private_data;
        u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
        struct ata_taskfile tf;
        bool online;
@@ -618,7 +619,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
        rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
                                 deadline, &online, NULL);
 
-       ahci_start_engine(ap);
+       hpriv->start_engine(ap);
 
        /* The pseudo configuration device on SIMG4726 attached to
         * ASUS P5W-DH Deluxe doesn't send signature FIS after
index 2289efdf82030e388ce977957eeb5b26f26f19d2..51af275b3388541baad3f7bf021a098de9da9bf0 100644 (file)
@@ -37,6 +37,8 @@
 
 #include <linux/clk.h>
 #include <linux/libata.h>
+#include <linux/phy/phy.h>
+#include <linux/regulator/consumer.h>
 
 /* Enclosure Management Control */
 #define EM_CTRL_MSG_TYPE              0x000f0000
@@ -51,6 +53,7 @@
 
 enum {
        AHCI_MAX_PORTS          = 32,
+       AHCI_MAX_CLKS           = 3,
        AHCI_MAX_SG             = 168, /* hardware max is 64K */
        AHCI_DMA_BOUNDARY       = 0xffffffff,
        AHCI_MAX_CMDS           = 32,
@@ -321,8 +324,17 @@ struct ahci_host_priv {
        u32                     em_loc; /* enclosure management location */
        u32                     em_buf_sz;      /* EM buffer size in byte */
        u32                     em_msg_type;    /* EM message type */
-       struct clk              *clk;           /* Only for platforms supporting clk */
+       bool                    got_runtime_pm; /* Did we do pm_runtime_get? */
+       struct clk              *clks[AHCI_MAX_CLKS]; /* Optional */
+       struct regulator        *target_pwr;    /* Optional */
+       struct phy              *phy;           /* If platform uses phy */
        void                    *plat_data;     /* Other platform data */
+       /*
+        * Optional ahci_start_engine override, if not set this gets set to the
+        * default ahci_start_engine during ahci_save_initial_config, this can
+        * be overridden anytime before the host is activated.
+        */
+       void                    (*start_engine)(struct ata_port *ap);
 };
 
 extern int ahci_ignore_sss;
diff --git a/drivers/ata/ahci_da850.c b/drivers/ata/ahci_da850.c
new file mode 100644 (file)
index 0000000..2c83613
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * DaVinci DA850 AHCI SATA platform driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/libata.h>
+#include <linux/ahci_platform.h>
+#include "ahci.h"
+
+/* SATA PHY Control Register offset from AHCI base */
+#define SATA_P0PHYCR_REG       0x178
+
+#define SATA_PHY_MPY(x)                ((x) << 0)
+#define SATA_PHY_LOS(x)                ((x) << 6)
+#define SATA_PHY_RXCDR(x)      ((x) << 10)
+#define SATA_PHY_RXEQ(x)       ((x) << 13)
+#define SATA_PHY_TXSWING(x)    ((x) << 19)
+#define SATA_PHY_ENPLL(x)      ((x) << 31)
+
+/*
+ * The multiplier needed for 1.5GHz PLL output.
+ *
+ * NOTE: This is currently hardcoded to be suitable for 100MHz crystal
+ * frequency (which is used by DA850 EVM board) and may need to be changed
+ * if you would like to use this driver on some other board.
+ */
+#define DA850_SATA_CLK_MULTIPLIER      7
+
+static void da850_sata_init(struct device *dev, void __iomem *pwrdn_reg,
+                           void __iomem *ahci_base)
+{
+       unsigned int val;
+
+       /* Enable SATA clock receiver */
+       val = readl(pwrdn_reg);
+       val &= ~BIT(0);
+       writel(val, pwrdn_reg);
+
+       val = SATA_PHY_MPY(DA850_SATA_CLK_MULTIPLIER + 1) | SATA_PHY_LOS(1) |
+             SATA_PHY_RXCDR(4) | SATA_PHY_RXEQ(1) | SATA_PHY_TXSWING(3) |
+             SATA_PHY_ENPLL(1);
+
+       writel(val, ahci_base + SATA_P0PHYCR_REG);
+}
+
+static const struct ata_port_info ahci_da850_port_info = {
+       .flags          = AHCI_FLAG_COMMON,
+       .pio_mask       = ATA_PIO4,
+       .udma_mask      = ATA_UDMA6,
+       .port_ops       = &ahci_platform_ops,
+};
+
+static int ahci_da850_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct ahci_host_priv *hpriv;
+       struct resource *res;
+       void __iomem *pwrdn_reg;
+       int rc;
+
+       hpriv = ahci_platform_get_resources(pdev);
+       if (IS_ERR(hpriv))
+               return PTR_ERR(hpriv);
+
+       rc = ahci_platform_enable_resources(hpriv);
+       if (rc)
+               return rc;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!res)
+               goto disable_resources;
+
+       pwrdn_reg = devm_ioremap(dev, res->start, resource_size(res));
+       if (!pwrdn_reg)
+               goto disable_resources;
+
+       da850_sata_init(dev, pwrdn_reg, hpriv->mmio);
+
+       rc = ahci_platform_init_host(pdev, hpriv, &ahci_da850_port_info, 0, 0);
+       if (rc)
+               goto disable_resources;
+
+       return 0;
+disable_resources:
+       ahci_platform_disable_resources(hpriv);
+       return rc;
+}
+
+static SIMPLE_DEV_PM_OPS(ahci_da850_pm_ops, ahci_platform_suspend,
+                        ahci_platform_resume);
+
+static struct platform_driver ahci_da850_driver = {
+       .probe = ahci_da850_probe,
+       .remove = ata_platform_remove_one,
+       .driver = {
+               .name = "ahci_da850",
+               .owner = THIS_MODULE,
+               .pm = &ahci_da850_pm_ops,
+       },
+};
+module_platform_driver(ahci_da850_driver);
+
+MODULE_DESCRIPTION("DaVinci DA850 AHCI SATA platform driver");
+MODULE_AUTHOR("Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>");
+MODULE_LICENSE("GPL");
index dd4d6f74d7bd5067a62840019a53c016b74efd6e..497c7abe1c7df5ef79ccd246828b68a1251c5201 100644 (file)
@@ -42,13 +42,7 @@ enum ahci_imx_type {
 struct imx_ahci_priv {
        struct platform_device *ahci_pdev;
        enum ahci_imx_type type;
-
-       /* i.MX53 clock */
-       struct clk *sata_gate_clk;
-       /* Common clock */
-       struct clk *sata_ref_clk;
        struct clk *ahb_clk;
-
        struct regmap *gpr;
        bool no_device;
        bool first_time;
@@ -58,28 +52,52 @@ static int ahci_imx_hotplug;
 module_param_named(hotplug, ahci_imx_hotplug, int, 0644);
 MODULE_PARM_DESC(hotplug, "AHCI IMX hot-plug support (0=Don't support, 1=support)");
 
-static int imx_sata_clock_enable(struct device *dev)
+static void ahci_imx_host_stop(struct ata_host *host);
+
+static int imx_sata_enable(struct ahci_host_priv *hpriv)
 {
-       struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
+       struct imx_ahci_priv *imxpriv = hpriv->plat_data;
        int ret;
 
-       if (imxpriv->type == AHCI_IMX53) {
-               ret = clk_prepare_enable(imxpriv->sata_gate_clk);
-               if (ret < 0) {
-                       dev_err(dev, "prepare-enable sata_gate clock err:%d\n",
-                               ret);
+       if (imxpriv->no_device)
+               return 0;
+
+       if (hpriv->target_pwr) {
+               ret = regulator_enable(hpriv->target_pwr);
+               if (ret)
                        return ret;
-               }
        }
 
-       ret = clk_prepare_enable(imxpriv->sata_ref_clk);
-       if (ret < 0) {
-               dev_err(dev, "prepare-enable sata_ref clock err:%d\n",
-                       ret);
-               goto clk_err;
-       }
+       ret = ahci_platform_enable_clks(hpriv);
+       if (ret < 0)
+               goto disable_regulator;
 
        if (imxpriv->type == AHCI_IMX6Q) {
+               /*
+                * set PHY Paremeters, two steps to configure the GPR13,
+                * one write for rest of parameters, mask of first write
+                * is 0x07ffffff, and the other one write for setting
+                * the mpll_clk_en.
+                */
+               regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
+                                  IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK |
+                                  IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK |
+                                  IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK |
+                                  IMX6Q_GPR13_SATA_SPD_MODE_MASK |
+                                  IMX6Q_GPR13_SATA_MPLL_SS_EN |
+                                  IMX6Q_GPR13_SATA_TX_ATTEN_MASK |
+                                  IMX6Q_GPR13_SATA_TX_BOOST_MASK |
+                                  IMX6Q_GPR13_SATA_TX_LVL_MASK |
+                                  IMX6Q_GPR13_SATA_MPLL_CLK_EN |
+                                  IMX6Q_GPR13_SATA_TX_EDGE_RATE,
+                                  IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB |
+                                  IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M |
+                                  IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F |
+                                  IMX6Q_GPR13_SATA_SPD_MODE_3P0G |
+                                  IMX6Q_GPR13_SATA_MPLL_SS_EN |
+                                  IMX6Q_GPR13_SATA_TX_ATTEN_9_16 |
+                                  IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB |
+                                  IMX6Q_GPR13_SATA_TX_LVL_1_025_V);
                regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
                                   IMX6Q_GPR13_SATA_MPLL_CLK_EN,
                                   IMX6Q_GPR13_SATA_MPLL_CLK_EN);
@@ -89,15 +107,19 @@ static int imx_sata_clock_enable(struct device *dev)
 
        return 0;
 
-clk_err:
-       if (imxpriv->type == AHCI_IMX53)
-               clk_disable_unprepare(imxpriv->sata_gate_clk);
+disable_regulator:
+       if (hpriv->target_pwr)
+               regulator_disable(hpriv->target_pwr);
+
        return ret;
 }
 
-static void imx_sata_clock_disable(struct device *dev)
+static void imx_sata_disable(struct ahci_host_priv *hpriv)
 {
-       struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
+       struct imx_ahci_priv *imxpriv = hpriv->plat_data;
+
+       if (imxpriv->no_device)
+               return;
 
        if (imxpriv->type == AHCI_IMX6Q) {
                regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
@@ -105,10 +127,10 @@ static void imx_sata_clock_disable(struct device *dev)
                                   !IMX6Q_GPR13_SATA_MPLL_CLK_EN);
        }
 
-       clk_disable_unprepare(imxpriv->sata_ref_clk);
+       ahci_platform_disable_clks(hpriv);
 
-       if (imxpriv->type == AHCI_IMX53)
-               clk_disable_unprepare(imxpriv->sata_gate_clk);
+       if (hpriv->target_pwr)
+               regulator_disable(hpriv->target_pwr);
 }
 
 static void ahci_imx_error_handler(struct ata_port *ap)
@@ -118,7 +140,7 @@ static void ahci_imx_error_handler(struct ata_port *ap)
        struct ata_host *host = dev_get_drvdata(ap->dev);
        struct ahci_host_priv *hpriv = host->private_data;
        void __iomem *mmio = hpriv->mmio;
-       struct imx_ahci_priv *imxpriv = dev_get_drvdata(ap->dev->parent);
+       struct imx_ahci_priv *imxpriv = hpriv->plat_data;
 
        ahci_error_handler(ap);
 
@@ -136,7 +158,7 @@ static void ahci_imx_error_handler(struct ata_port *ap)
         */
        reg_val = readl(mmio + PORT_PHY_CTL);
        writel(reg_val | PORT_PHY_CTL_PDDQ_LOC, mmio + PORT_PHY_CTL);
-       imx_sata_clock_disable(ap->dev);
+       imx_sata_disable(hpriv);
        imxpriv->no_device = true;
 }
 
@@ -144,7 +166,9 @@ static int ahci_imx_softreset(struct ata_link *link, unsigned int *class,
                       unsigned long deadline)
 {
        struct ata_port *ap = link->ap;
-       struct imx_ahci_priv *imxpriv = dev_get_drvdata(ap->dev->parent);
+       struct ata_host *host = dev_get_drvdata(ap->dev);
+       struct ahci_host_priv *hpriv = host->private_data;
+       struct imx_ahci_priv *imxpriv = hpriv->plat_data;
        int ret = -EIO;
 
        if (imxpriv->type == AHCI_IMX53)
@@ -156,7 +180,8 @@ static int ahci_imx_softreset(struct ata_link *link, unsigned int *class,
 }
 
 static struct ata_port_operations ahci_imx_ops = {
-       .inherits       = &ahci_platform_ops,
+       .inherits       = &ahci_ops,
+       .host_stop      = ahci_imx_host_stop,
        .error_handler  = ahci_imx_error_handler,
        .softreset      = ahci_imx_softreset,
 };
@@ -168,79 +193,6 @@ static const struct ata_port_info ahci_imx_port_info = {
        .port_ops       = &ahci_imx_ops,
 };
 
-static int imx_sata_init(struct device *dev, void __iomem *mmio)
-{
-       int ret = 0;
-       unsigned int reg_val;
-       struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
-
-       ret = imx_sata_clock_enable(dev);
-       if (ret < 0)
-               return ret;
-
-       /*
-        * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL,
-        * and IP vendor specific register HOST_TIMER1MS.
-        * Configure CAP_SSS (support stagered spin up).
-        * Implement the port0.
-        * Get the ahb clock rate, and configure the TIMER1MS register.
-        */
-       reg_val = readl(mmio + HOST_CAP);
-       if (!(reg_val & HOST_CAP_SSS)) {
-               reg_val |= HOST_CAP_SSS;
-               writel(reg_val, mmio + HOST_CAP);
-       }
-       reg_val = readl(mmio + HOST_PORTS_IMPL);
-       if (!(reg_val & 0x1)) {
-               reg_val |= 0x1;
-               writel(reg_val, mmio + HOST_PORTS_IMPL);
-       }
-
-       reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
-       writel(reg_val, mmio + HOST_TIMER1MS);
-
-       return 0;
-}
-
-static void imx_sata_exit(struct device *dev)
-{
-       imx_sata_clock_disable(dev);
-}
-
-static int imx_ahci_suspend(struct device *dev)
-{
-       struct imx_ahci_priv *imxpriv =  dev_get_drvdata(dev->parent);
-
-       /*
-        * If no_device is set, The CLKs had been gated off in the
-        * initialization so don't do it again here.
-        */
-       if (!imxpriv->no_device)
-               imx_sata_clock_disable(dev);
-
-       return 0;
-}
-
-static int imx_ahci_resume(struct device *dev)
-{
-       struct imx_ahci_priv *imxpriv =  dev_get_drvdata(dev->parent);
-       int ret = 0;
-
-       if (!imxpriv->no_device)
-               ret = imx_sata_clock_enable(dev);
-
-       return ret;
-}
-
-static struct ahci_platform_data imx_sata_pdata = {
-       .init           = imx_sata_init,
-       .exit           = imx_sata_exit,
-       .ata_port_info  = &ahci_imx_port_info,
-       .suspend        = imx_ahci_suspend,
-       .resume         = imx_ahci_resume,
-
-};
-
 static const struct of_device_id imx_ahci_of_match[] = {
        { .compatible = "fsl,imx53-ahci", .data = (void *)AHCI_IMX53 },
        { .compatible = "fsl,imx6q-ahci", .data = (void *)AHCI_IMX6Q },
@@ -251,151 +203,124 @@ MODULE_DEVICE_TABLE(of, imx_ahci_of_match);
 static int imx_ahci_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct resource *mem, *irq, res[2];
        const struct of_device_id *of_id;
-       enum ahci_imx_type type;
-       const struct ahci_platform_data *pdata = NULL;
+       struct ahci_host_priv *hpriv;
        struct imx_ahci_priv *imxpriv;
-       struct device *ahci_dev;
-       struct platform_device *ahci_pdev;
+       unsigned int reg_val;
        int ret;
 
        of_id = of_match_device(imx_ahci_of_match, dev);
        if (!of_id)
                return -EINVAL;
 
-       type = (enum ahci_imx_type)of_id->data;
-       pdata = &imx_sata_pdata;
-
        imxpriv = devm_kzalloc(dev, sizeof(*imxpriv), GFP_KERNEL);
-       if (!imxpriv) {
-               dev_err(dev, "can't alloc ahci_host_priv\n");
+       if (!imxpriv)
                return -ENOMEM;
-       }
-
-       ahci_pdev = platform_device_alloc("ahci", -1);
-       if (!ahci_pdev)
-               return -ENODEV;
-
-       ahci_dev = &ahci_pdev->dev;
-       ahci_dev->parent = dev;
 
        imxpriv->no_device = false;
        imxpriv->first_time = true;
-       imxpriv->type = type;
-
+       imxpriv->type = (enum ahci_imx_type)of_id->data;
        imxpriv->ahb_clk = devm_clk_get(dev, "ahb");
        if (IS_ERR(imxpriv->ahb_clk)) {
                dev_err(dev, "can't get ahb clock.\n");
-               ret = PTR_ERR(imxpriv->ahb_clk);
-               goto err_out;
+               return PTR_ERR(imxpriv->ahb_clk);
        }
 
-       if (type == AHCI_IMX53) {
-               imxpriv->sata_gate_clk = devm_clk_get(dev, "sata_gate");
-               if (IS_ERR(imxpriv->sata_gate_clk)) {
-                       dev_err(dev, "can't get sata_gate clock.\n");
-                       ret = PTR_ERR(imxpriv->sata_gate_clk);
-                       goto err_out;
+       if (imxpriv->type == AHCI_IMX6Q) {
+               imxpriv->gpr = syscon_regmap_lookup_by_compatible(
+                                                       "fsl,imx6q-iomuxc-gpr");
+               if (IS_ERR(imxpriv->gpr)) {
+                       dev_err(dev,
+                               "failed to find fsl,imx6q-iomux-gpr regmap\n");
+                       return PTR_ERR(imxpriv->gpr);
                }
        }
 
-       imxpriv->sata_ref_clk = devm_clk_get(dev, "sata_ref");
-       if (IS_ERR(imxpriv->sata_ref_clk)) {
-               dev_err(dev, "can't get sata_ref clock.\n");
-               ret = PTR_ERR(imxpriv->sata_ref_clk);
-               goto err_out;
-       }
+       hpriv = ahci_platform_get_resources(pdev);
+       if (IS_ERR(hpriv))
+               return PTR_ERR(hpriv);
+
+       hpriv->plat_data = imxpriv;
 
-       imxpriv->ahci_pdev = ahci_pdev;
-       platform_set_drvdata(pdev, imxpriv);
+       ret = imx_sata_enable(hpriv);
+       if (ret)
+               return ret;
 
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!mem || !irq) {
-               dev_err(dev, "no mmio/irq resource\n");
-               ret = -ENOMEM;
-               goto err_out;
+       /*
+        * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL,
+        * and IP vendor specific register HOST_TIMER1MS.
+        * Configure CAP_SSS (support stagered spin up).
+        * Implement the port0.
+        * Get the ahb clock rate, and configure the TIMER1MS register.
+        */
+       reg_val = readl(hpriv->mmio + HOST_CAP);
+       if (!(reg_val & HOST_CAP_SSS)) {
+               reg_val |= HOST_CAP_SSS;
+               writel(reg_val, hpriv->mmio + HOST_CAP);
+       }
+       reg_val = readl(hpriv->mmio + HOST_PORTS_IMPL);
+       if (!(reg_val & 0x1)) {
+               reg_val |= 0x1;
+               writel(reg_val, hpriv->mmio + HOST_PORTS_IMPL);
        }
 
-       res[0] = *mem;
-       res[1] = *irq;
+       reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
+       writel(reg_val, hpriv->mmio + HOST_TIMER1MS);
 
-       ahci_dev->coherent_dma_mask = DMA_BIT_MASK(32);
-       ahci_dev->dma_mask = &ahci_dev->coherent_dma_mask;
-       ahci_dev->of_node = dev->of_node;
+       ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info, 0, 0);
+       if (ret)
+               imx_sata_disable(hpriv);
 
-       if (type == AHCI_IMX6Q) {
-               imxpriv->gpr = syscon_regmap_lookup_by_compatible(
-                                                       "fsl,imx6q-iomuxc-gpr");
-               if (IS_ERR(imxpriv->gpr)) {
-                       dev_err(dev,
-                               "failed to find fsl,imx6q-iomux-gpr regmap\n");
-                       ret = PTR_ERR(imxpriv->gpr);
-                       goto err_out;
-               }
+       return ret;
+}
 
-               /*
-                * Set PHY Paremeters, two steps to configure the GPR13,
-                * one write for rest of parameters, mask of first write
-                * is 0x07fffffe, and the other one write for setting
-                * the mpll_clk_en happens in imx_sata_clock_enable().
-                */
-               regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
-                                  IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK |
-                                  IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK |
-                                  IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK |
-                                  IMX6Q_GPR13_SATA_SPD_MODE_MASK |
-                                  IMX6Q_GPR13_SATA_MPLL_SS_EN |
-                                  IMX6Q_GPR13_SATA_TX_ATTEN_MASK |
-                                  IMX6Q_GPR13_SATA_TX_BOOST_MASK |
-                                  IMX6Q_GPR13_SATA_TX_LVL_MASK |
-                                  IMX6Q_GPR13_SATA_MPLL_CLK_EN |
-                                  IMX6Q_GPR13_SATA_TX_EDGE_RATE,
-                                  IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB |
-                                  IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M |
-                                  IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F |
-                                  IMX6Q_GPR13_SATA_SPD_MODE_3P0G |
-                                  IMX6Q_GPR13_SATA_MPLL_SS_EN |
-                                  IMX6Q_GPR13_SATA_TX_ATTEN_9_16 |
-                                  IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB |
-                                  IMX6Q_GPR13_SATA_TX_LVL_1_025_V);
-       }
+static void ahci_imx_host_stop(struct ata_host *host)
+{
+       struct ahci_host_priv *hpriv = host->private_data;
 
-       ret = platform_device_add_resources(ahci_pdev, res, 2);
-       if (ret)
-               goto err_out;
+       imx_sata_disable(hpriv);
+}
 
-       ret = platform_device_add_data(ahci_pdev, pdata, sizeof(*pdata));
-       if (ret)
-               goto err_out;
+#ifdef CONFIG_PM_SLEEP
+static int imx_ahci_suspend(struct device *dev)
+{
+       struct ata_host *host = dev_get_drvdata(dev);
+       struct ahci_host_priv *hpriv = host->private_data;
+       int ret;
 
-       ret = platform_device_add(ahci_pdev);
-       if (ret) {
-err_out:
-               platform_device_put(ahci_pdev);
+       ret = ahci_platform_suspend_host(dev);
+       if (ret)
                return ret;
-       }
+
+       imx_sata_disable(hpriv);
 
        return 0;
 }
 
-static int imx_ahci_remove(struct platform_device *pdev)
+static int imx_ahci_resume(struct device *dev)
 {
-       struct imx_ahci_priv *imxpriv = platform_get_drvdata(pdev);
-       struct platform_device *ahci_pdev = imxpriv->ahci_pdev;
+       struct ata_host *host = dev_get_drvdata(dev);
+       struct ahci_host_priv *hpriv = host->private_data;
+       int ret;
 
-       platform_device_unregister(ahci_pdev);
-       return 0;
+       ret = imx_sata_enable(hpriv);
+       if (ret)
+               return ret;
+
+       return ahci_platform_resume_host(dev);
 }
+#endif
+
+static SIMPLE_DEV_PM_OPS(ahci_imx_pm_ops, imx_ahci_suspend, imx_ahci_resume);
 
 static struct platform_driver imx_ahci_driver = {
        .probe = imx_ahci_probe,
-       .remove = imx_ahci_remove,
+       .remove = ata_platform_remove_one,
        .driver = {
                .name = "ahci-imx",
                .owner = THIS_MODULE,
                .of_match_table = imx_ahci_of_match,
+               .pm = &ahci_imx_pm_ops,
        },
 };
 module_platform_driver(imx_ahci_driver);
index 4b231baceb0995557c2cae40e501f6d3449dc365..ef67e79944f9962e3e32382dd43794404d866b01 100644 (file)
  * any later version.
  */
 
-#include <linux/clk.h>
 #include <linux/kernel.h>
-#include <linux/gfp.h>
 #include <linux/module.h>
 #include <linux/pm.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/libata.h>
 #include <linux/ahci_platform.h>
 #include "ahci.h"
 
-static void ahci_host_stop(struct ata_host *host);
-
-enum ahci_type {
-       AHCI,           /* standard platform ahci */
-       IMX53_AHCI,     /* ahci on i.mx53 */
-       STRICT_AHCI,    /* delayed DMA engine start */
-};
-
-static struct platform_device_id ahci_devtype[] = {
-       {
-               .name = "ahci",
-               .driver_data = AHCI,
-       }, {
-               .name = "imx53-ahci",
-               .driver_data = IMX53_AHCI,
-       }, {
-               .name = "strict-ahci",
-               .driver_data = STRICT_AHCI,
-       }, {
-               /* sentinel */
-       }
-};
-MODULE_DEVICE_TABLE(platform, ahci_devtype);
-
-struct ata_port_operations ahci_platform_ops = {
-       .inherits       = &ahci_ops,
-       .host_stop      = ahci_host_stop,
-};
-EXPORT_SYMBOL_GPL(ahci_platform_ops);
-
-static struct ata_port_operations ahci_platform_retry_srst_ops = {
-       .inherits       = &ahci_pmp_retry_srst_ops,
-       .host_stop      = ahci_host_stop,
-};
-
-static const struct ata_port_info ahci_port_info[] = {
-       /* by features */
-       [AHCI] = {
-               .flags          = AHCI_FLAG_COMMON,
-               .pio_mask       = ATA_PIO4,
-               .udma_mask      = ATA_UDMA6,
-               .port_ops       = &ahci_platform_ops,
-       },
-       [IMX53_AHCI] = {
-               .flags          = AHCI_FLAG_COMMON,
-               .pio_mask       = ATA_PIO4,
-               .udma_mask      = ATA_UDMA6,
-               .port_ops       = &ahci_platform_retry_srst_ops,
-       },
-       [STRICT_AHCI] = {
-               AHCI_HFLAGS     (AHCI_HFLAG_DELAY_ENGINE),
-               .flags          = AHCI_FLAG_COMMON,
-               .pio_mask       = ATA_PIO4,
-               .udma_mask      = ATA_UDMA6,
-               .port_ops       = &ahci_platform_ops,
-       },
-};
-
-static struct scsi_host_template ahci_platform_sht = {
-       AHCI_SHT("ahci_platform"),
+static const struct ata_port_info ahci_port_info = {
+       .flags          = AHCI_FLAG_COMMON,
+       .pio_mask       = ATA_PIO4,
+       .udma_mask      = ATA_UDMA6,
+       .port_ops       = &ahci_platform_ops,
 };
 
 static int ahci_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct ahci_platform_data *pdata = dev_get_platdata(dev);
-       const struct platform_device_id *id = platform_get_device_id(pdev);
-       struct ata_port_info pi = ahci_port_info[id ? id->driver_data : 0];
-       const struct ata_port_info *ppi[] = { &pi, NULL };
        struct ahci_host_priv *hpriv;
-       struct ata_host *host;
-       struct resource *mem;
-       int irq;
-       int n_ports;
-       int i;
        int rc;
 
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!mem) {
-               dev_err(dev, "no mmio space\n");
-               return -EINVAL;
-       }
-
-       irq = platform_get_irq(pdev, 0);
-       if (irq <= 0) {
-               dev_err(dev, "no irq\n");
-               return -EINVAL;
-       }
-
-       if (pdata && pdata->ata_port_info)
-               pi = *pdata->ata_port_info;
-
-       hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
-       if (!hpriv) {
-               dev_err(dev, "can't alloc ahci_host_priv\n");
-               return -ENOMEM;
-       }
-
-       hpriv->flags |= (unsigned long)pi.private_data;
-
-       hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem));
-       if (!hpriv->mmio) {
-               dev_err(dev, "can't map %pR\n", mem);
-               return -ENOMEM;
-       }
+       hpriv = ahci_platform_get_resources(pdev);
+       if (IS_ERR(hpriv))
+               return PTR_ERR(hpriv);
 
-       hpriv->clk = clk_get(dev, NULL);
-       if (IS_ERR(hpriv->clk)) {
-               dev_err(dev, "can't get clock\n");
-       } else {
-               rc = clk_prepare_enable(hpriv->clk);
-               if (rc) {
-                       dev_err(dev, "clock prepare enable failed");
-                       goto free_clk;
-               }
-       }
+       rc = ahci_platform_enable_resources(hpriv);
+       if (rc)
+               return rc;
 
        /*
         * Some platforms might need to prepare for mmio region access,
@@ -151,69 +52,10 @@ static int ahci_probe(struct platform_device *pdev)
        if (pdata && pdata->init) {
                rc = pdata->init(dev, hpriv->mmio);
                if (rc)
-                       goto disable_unprepare_clk;
-       }
-
-       ahci_save_initial_config(dev, hpriv,
-               pdata ? pdata->force_port_map : 0,
-               pdata ? pdata->mask_port_map  : 0);
-
-       /* prepare host */
-       if (hpriv->cap & HOST_CAP_NCQ)
-               pi.flags |= ATA_FLAG_NCQ;
-
-       if (hpriv->cap & HOST_CAP_PMP)
-               pi.flags |= ATA_FLAG_PMP;
-
-       ahci_set_em_messages(hpriv, &pi);
-
-       /* CAP.NP sometimes indicate the index of the last enabled
-        * port, at other times, that of the last possible port, so
-        * determining the maximum port number requires looking at
-        * both CAP.NP and port_map.
-        */
-       n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
-
-       host = ata_host_alloc_pinfo(dev, ppi, n_ports);
-       if (!host) {
-               rc = -ENOMEM;
-               goto pdata_exit;
-       }
-
-       host->private_data = hpriv;
-
-       if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
-               host->flags |= ATA_HOST_PARALLEL_SCAN;
-       else
-               dev_info(dev, "SSS flag set, parallel bus scan disabled\n");
-
-       if (pi.flags & ATA_FLAG_EM)
-               ahci_reset_em(host);
-
-       for (i = 0; i < host->n_ports; i++) {
-               struct ata_port *ap = host->ports[i];
-
-               ata_port_desc(ap, "mmio %pR", mem);
-               ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
-
-               /* set enclosure management message type */
-               if (ap->flags & ATA_FLAG_EM)
-                       ap->em_message_type = hpriv->em_msg_type;
-
-               /* disabled/not-implemented port */
-               if (!(hpriv->port_map & (1 << i)))
-                       ap->ops = &ata_dummy_port_ops;
+                       goto disable_resources;
        }
 
-       rc = ahci_reset_controller(host);
-       if (rc)
-               goto pdata_exit;
-
-       ahci_init_controller(host);
-       ahci_print_info(host, "platform");
-
-       rc = ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED,
-                              &ahci_platform_sht);
+       rc = ahci_platform_init_host(pdev, hpriv, &ahci_port_info, 0, 0);
        if (rc)
                goto pdata_exit;
 
@@ -221,115 +63,19 @@ static int ahci_probe(struct platform_device *pdev)
 pdata_exit:
        if (pdata && pdata->exit)
                pdata->exit(dev);
-disable_unprepare_clk:
-       if (!IS_ERR(hpriv->clk))
-               clk_disable_unprepare(hpriv->clk);
-free_clk:
-       if (!IS_ERR(hpriv->clk))
-               clk_put(hpriv->clk);
-       return rc;
-}
-
-static void ahci_host_stop(struct ata_host *host)
-{
-       struct device *dev = host->dev;
-       struct ahci_platform_data *pdata = dev_get_platdata(dev);
-       struct ahci_host_priv *hpriv = host->private_data;
-
-       if (pdata && pdata->exit)
-               pdata->exit(dev);
-
-       if (!IS_ERR(hpriv->clk)) {
-               clk_disable_unprepare(hpriv->clk);
-               clk_put(hpriv->clk);
-       }
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int ahci_suspend(struct device *dev)
-{
-       struct ahci_platform_data *pdata = dev_get_platdata(dev);
-       struct ata_host *host = dev_get_drvdata(dev);
-       struct ahci_host_priv *hpriv = host->private_data;
-       void __iomem *mmio = hpriv->mmio;
-       u32 ctl;
-       int rc;
-
-       if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
-               dev_err(dev, "firmware update required for suspend/resume\n");
-               return -EIO;
-       }
-
-       /*
-        * AHCI spec rev1.1 section 8.3.3:
-        * Software must disable interrupts prior to requesting a
-        * transition of the HBA to D3 state.
-        */
-       ctl = readl(mmio + HOST_CTL);
-       ctl &= ~HOST_IRQ_EN;
-       writel(ctl, mmio + HOST_CTL);
-       readl(mmio + HOST_CTL); /* flush */
-
-       rc = ata_host_suspend(host, PMSG_SUSPEND);
-       if (rc)
-               return rc;
-
-       if (pdata && pdata->suspend)
-               return pdata->suspend(dev);
-
-       if (!IS_ERR(hpriv->clk))
-               clk_disable_unprepare(hpriv->clk);
-
-       return 0;
-}
-
-static int ahci_resume(struct device *dev)
-{
-       struct ahci_platform_data *pdata = dev_get_platdata(dev);
-       struct ata_host *host = dev_get_drvdata(dev);
-       struct ahci_host_priv *hpriv = host->private_data;
-       int rc;
-
-       if (!IS_ERR(hpriv->clk)) {
-               rc = clk_prepare_enable(hpriv->clk);
-               if (rc) {
-                       dev_err(dev, "clock prepare enable failed");
-                       return rc;
-               }
-       }
-
-       if (pdata && pdata->resume) {
-               rc = pdata->resume(dev);
-               if (rc)
-                       goto disable_unprepare_clk;
-       }
-
-       if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
-               rc = ahci_reset_controller(host);
-               if (rc)
-                       goto disable_unprepare_clk;
-
-               ahci_init_controller(host);
-       }
-
-       ata_host_resume(host);
-
-       return 0;
-
-disable_unprepare_clk:
-       if (!IS_ERR(hpriv->clk))
-               clk_disable_unprepare(hpriv->clk);
-
+disable_resources:
+       ahci_platform_disable_resources(hpriv);
        return rc;
 }
-#endif
 
-static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_suspend, ahci_resume);
+static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend,
+                        ahci_platform_resume);
 
 static const struct of_device_id ahci_of_match[] = {
        { .compatible = "snps,spear-ahci", },
        { .compatible = "snps,exynos5440-ahci", },
        { .compatible = "ibm,476gtr-ahci", },
+       { .compatible = "snps,dwc-ahci", },
        {},
 };
 MODULE_DEVICE_TABLE(of, ahci_of_match);
@@ -343,7 +89,6 @@ static struct platform_driver ahci_driver = {
                .of_match_table = ahci_of_match,
                .pm = &ahci_pm_ops,
        },
-       .id_table       = ahci_devtype,
 };
 module_platform_driver(ahci_driver);
 
diff --git a/drivers/ata/ahci_st.c b/drivers/ata/ahci_st.c
new file mode 100644 (file)
index 0000000..6332222
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2012 STMicroelectronics Limited
+ *
+ * Authors: Francesco Virlinzi <francesco.virlinzi@st.com>
+ *         Alexandre Torgue <alexandre.torgue@st.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/ahci_platform.h>
+#include <linux/libata.h>
+#include <linux/reset.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+
+#include "ahci.h"
+
+#define ST_AHCI_OOBR                   0xbc
+#define ST_AHCI_OOBR_WE                        BIT(31)
+#define ST_AHCI_OOBR_CWMIN_SHIFT       24
+#define ST_AHCI_OOBR_CWMAX_SHIFT       16
+#define ST_AHCI_OOBR_CIMIN_SHIFT       8
+#define ST_AHCI_OOBR_CIMAX_SHIFT       0
+
+struct st_ahci_drv_data {
+       struct platform_device *ahci;
+       struct reset_control *pwr;
+       struct reset_control *sw_rst;
+       struct reset_control *pwr_rst;
+       struct ahci_host_priv *hpriv;
+};
+
+static void st_ahci_configure_oob(void __iomem *mmio)
+{
+       unsigned long old_val, new_val;
+
+       new_val = (0x02 << ST_AHCI_OOBR_CWMIN_SHIFT) |
+                 (0x04 << ST_AHCI_OOBR_CWMAX_SHIFT) |
+                 (0x08 << ST_AHCI_OOBR_CIMIN_SHIFT) |
+                 (0x0C << ST_AHCI_OOBR_CIMAX_SHIFT);
+
+       old_val = readl(mmio + ST_AHCI_OOBR);
+       writel(old_val | ST_AHCI_OOBR_WE, mmio + ST_AHCI_OOBR);
+       writel(new_val | ST_AHCI_OOBR_WE, mmio + ST_AHCI_OOBR);
+       writel(new_val, mmio + ST_AHCI_OOBR);
+}
+
+static int st_ahci_deassert_resets(struct device *dev)
+{
+       struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
+       int err;
+
+       if (drv_data->pwr) {
+               err = reset_control_deassert(drv_data->pwr);
+               if (err) {
+                       dev_err(dev, "unable to bring out of pwrdwn\n");
+                       return err;
+               }
+       }
+
+       st_ahci_configure_oob(drv_data->hpriv->mmio);
+
+       if (drv_data->sw_rst) {
+               err = reset_control_deassert(drv_data->sw_rst);
+               if (err) {
+                       dev_err(dev, "unable to bring out of sw-rst\n");
+                       return err;
+               }
+       }
+
+       if (drv_data->pwr_rst) {
+               err = reset_control_deassert(drv_data->pwr_rst);
+               if (err) {
+                       dev_err(dev, "unable to bring out of pwr-rst\n");
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+static void st_ahci_host_stop(struct ata_host *host)
+{
+       struct ahci_host_priv *hpriv = host->private_data;
+       struct device *dev = host->dev;
+       struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
+       int err;
+
+       if (drv_data->pwr) {
+               err = reset_control_assert(drv_data->pwr);
+               if (err)
+                       dev_err(dev, "unable to pwrdwn\n");
+       }
+
+       ahci_platform_disable_resources(hpriv);
+}
+
+static int st_ahci_probe_resets(struct platform_device *pdev)
+{
+       struct st_ahci_drv_data *drv_data = platform_get_drvdata(pdev);
+
+       drv_data->pwr = devm_reset_control_get(&pdev->dev, "pwr-dwn");
+       if (IS_ERR(drv_data->pwr)) {
+               dev_info(&pdev->dev, "power reset control not defined\n");
+               drv_data->pwr = NULL;
+       }
+
+       drv_data->sw_rst = devm_reset_control_get(&pdev->dev, "sw-rst");
+       if (IS_ERR(drv_data->sw_rst)) {
+               dev_info(&pdev->dev, "soft reset control not defined\n");
+               drv_data->sw_rst = NULL;
+       }
+
+       drv_data->pwr_rst = devm_reset_control_get(&pdev->dev, "pwr-rst");
+       if (IS_ERR(drv_data->pwr_rst)) {
+               dev_dbg(&pdev->dev, "power soft reset control not defined\n");
+               drv_data->pwr_rst = NULL;
+       }
+
+       return st_ahci_deassert_resets(&pdev->dev);
+}
+
+static struct ata_port_operations st_ahci_port_ops = {
+       .inherits       = &ahci_platform_ops,
+       .host_stop      = st_ahci_host_stop,
+};
+
+static const struct ata_port_info st_ahci_port_info = {
+       .flags          = AHCI_FLAG_COMMON,
+       .pio_mask       = ATA_PIO4,
+       .udma_mask      = ATA_UDMA6,
+       .port_ops       = &st_ahci_port_ops,
+};
+
+static int st_ahci_probe(struct platform_device *pdev)
+{
+       struct st_ahci_drv_data *drv_data;
+       struct ahci_host_priv *hpriv;
+       int err;
+
+       drv_data = devm_kzalloc(&pdev->dev, sizeof(*drv_data), GFP_KERNEL);
+       if (!drv_data)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, drv_data);
+
+       hpriv = ahci_platform_get_resources(pdev);
+       if (IS_ERR(hpriv))
+               return PTR_ERR(hpriv);
+
+       drv_data->hpriv = hpriv;
+
+       err = st_ahci_probe_resets(pdev);
+       if (err)
+               return err;
+
+       err = ahci_platform_enable_resources(hpriv);
+       if (err)
+               return err;
+
+       err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info, 0, 0);
+       if (err) {
+               ahci_platform_disable_resources(hpriv);
+               return err;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int st_ahci_suspend(struct device *dev)
+{
+       struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
+       struct ahci_host_priv *hpriv = drv_data->hpriv;
+       int err;
+
+       err = ahci_platform_suspend_host(dev);
+       if (err)
+               return err;
+
+       if (drv_data->pwr) {
+               err = reset_control_assert(drv_data->pwr);
+               if (err) {
+                       dev_err(dev, "unable to pwrdwn");
+                       return err;
+               }
+       }
+
+       ahci_platform_disable_resources(hpriv);
+
+       return 0;
+}
+
+static int st_ahci_resume(struct device *dev)
+{
+       struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
+       struct ahci_host_priv *hpriv = drv_data->hpriv;
+       int err;
+
+       err = ahci_platform_enable_resources(hpriv);
+       if (err)
+               return err;
+
+       err = st_ahci_deassert_resets(dev);
+       if (err) {
+               ahci_platform_disable_resources(hpriv);
+               return err;
+       }
+
+       return ahci_platform_resume_host(dev);
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(st_ahci_pm_ops, st_ahci_suspend, st_ahci_resume);
+
+static struct of_device_id st_ahci_match[] = {
+       { .compatible = "st,ahci", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, st_ahci_match);
+
+static struct platform_driver st_ahci_driver = {
+       .driver = {
+               .name = "st_ahci",
+               .owner = THIS_MODULE,
+               .pm = &st_ahci_pm_ops,
+               .of_match_table = of_match_ptr(st_ahci_match),
+       },
+       .probe = st_ahci_probe,
+       .remove = ata_platform_remove_one,
+};
+module_platform_driver(st_ahci_driver);
+
+MODULE_AUTHOR("Alexandre Torgue <alexandre.torgue@st.com>");
+MODULE_AUTHOR("Francesco Virlinzi <francesco.virlinzi@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics SATA AHCI Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c
new file mode 100644 (file)
index 0000000..42d3f64
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * Allwinner sunxi AHCI SATA platform driver
+ * Copyright 2013 Olliver Schinagl <oliver@schinagl.nl>
+ * Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ *
+ * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov
+ * Based on code from Allwinner Technology Co., Ltd. <www.allwinnertech.com>,
+ * Daniel Wang <danielwang@allwinnertech.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/ahci_platform.h>
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include "ahci.h"
+
+#define AHCI_BISTAFR   0x00a0
+#define AHCI_BISTCR    0x00a4
+#define AHCI_BISTFCTR  0x00a8
+#define AHCI_BISTSR    0x00ac
+#define AHCI_BISTDECR  0x00b0
+#define AHCI_DIAGNR0   0x00b4
+#define AHCI_DIAGNR1   0x00b8
+#define AHCI_OOBR      0x00bc
+#define AHCI_PHYCS0R   0x00c0
+#define AHCI_PHYCS1R   0x00c4
+#define AHCI_PHYCS2R   0x00c8
+#define AHCI_TIMER1MS  0x00e0
+#define AHCI_GPARAM1R  0x00e8
+#define AHCI_GPARAM2R  0x00ec
+#define AHCI_PPARAMR   0x00f0
+#define AHCI_TESTR     0x00f4
+#define AHCI_VERSIONR  0x00f8
+#define AHCI_IDR       0x00fc
+#define AHCI_RWCR      0x00fc
+#define AHCI_P0DMACR   0x0170
+#define AHCI_P0PHYCR   0x0178
+#define AHCI_P0PHYSR   0x017c
+
+static void sunxi_clrbits(void __iomem *reg, u32 clr_val)
+{
+       u32 reg_val;
+
+       reg_val = readl(reg);
+       reg_val &= ~(clr_val);
+       writel(reg_val, reg);
+}
+
+static void sunxi_setbits(void __iomem *reg, u32 set_val)
+{
+       u32 reg_val;
+
+       reg_val = readl(reg);
+       reg_val |= set_val;
+       writel(reg_val, reg);
+}
+
+static void sunxi_clrsetbits(void __iomem *reg, u32 clr_val, u32 set_val)
+{
+       u32 reg_val;
+
+       reg_val = readl(reg);
+       reg_val &= ~(clr_val);
+       reg_val |= set_val;
+       writel(reg_val, reg);
+}
+
+static u32 sunxi_getbits(void __iomem *reg, u8 mask, u8 shift)
+{
+       return (readl(reg) >> shift) & mask;
+}
+
+static int ahci_sunxi_phy_init(struct device *dev, void __iomem *reg_base)
+{
+       u32 reg_val;
+       int timeout;
+
+       /* This magic is from the original code */
+       writel(0, reg_base + AHCI_RWCR);
+       msleep(5);
+
+       sunxi_setbits(reg_base + AHCI_PHYCS1R, BIT(19));
+       sunxi_clrsetbits(reg_base + AHCI_PHYCS0R,
+                        (0x7 << 24),
+                        (0x5 << 24) | BIT(23) | BIT(18));
+       sunxi_clrsetbits(reg_base + AHCI_PHYCS1R,
+                        (0x3 << 16) | (0x1f << 8) | (0x3 << 6),
+                        (0x2 << 16) | (0x6 << 8) | (0x2 << 6));
+       sunxi_setbits(reg_base + AHCI_PHYCS1R, BIT(28) | BIT(15));
+       sunxi_clrbits(reg_base + AHCI_PHYCS1R, BIT(19));
+       sunxi_clrsetbits(reg_base + AHCI_PHYCS0R,
+                        (0x7 << 20), (0x3 << 20));
+       sunxi_clrsetbits(reg_base + AHCI_PHYCS2R,
+                        (0x1f << 5), (0x19 << 5));
+       msleep(5);
+
+       sunxi_setbits(reg_base + AHCI_PHYCS0R, (0x1 << 19));
+
+       timeout = 250; /* Power up takes aprox 50 us */
+       do {
+               reg_val = sunxi_getbits(reg_base + AHCI_PHYCS0R, 0x7, 28);
+               if (reg_val == 0x02)
+                       break;
+
+               if (--timeout == 0) {
+                       dev_err(dev, "PHY power up failed.\n");
+                       return -EIO;
+               }
+               udelay(1);
+       } while (1);
+
+       sunxi_setbits(reg_base + AHCI_PHYCS2R, (0x1 << 24));
+
+       timeout = 100; /* Calibration takes aprox 10 us */
+       do {
+               reg_val = sunxi_getbits(reg_base + AHCI_PHYCS2R, 0x1, 24);
+               if (reg_val == 0x00)
+                       break;
+
+               if (--timeout == 0) {
+                       dev_err(dev, "PHY calibration failed.\n");
+                       return -EIO;
+               }
+               udelay(1);
+       } while (1);
+
+       msleep(15);
+
+       writel(0x7, reg_base + AHCI_RWCR);
+
+       return 0;
+}
+
+static void ahci_sunxi_start_engine(struct ata_port *ap)
+{
+       void __iomem *port_mmio = ahci_port_base(ap);
+       struct ahci_host_priv *hpriv = ap->host->private_data;
+
+       /* Setup DMA before DMA start */
+       sunxi_clrsetbits(hpriv->mmio + AHCI_P0DMACR, 0x0000ff00, 0x00004400);
+
+       /* Start DMA */
+       sunxi_setbits(port_mmio + PORT_CMD, PORT_CMD_START);
+}
+
+static const struct ata_port_info ahci_sunxi_port_info = {
+       AHCI_HFLAGS(AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI |
+                         AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ),
+       .flags          = AHCI_FLAG_COMMON | ATA_FLAG_NCQ,
+       .pio_mask       = ATA_PIO4,
+       .udma_mask      = ATA_UDMA6,
+       .port_ops       = &ahci_platform_ops,
+};
+
+static int ahci_sunxi_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct ahci_host_priv *hpriv;
+       int rc;
+
+       hpriv = ahci_platform_get_resources(pdev);
+       if (IS_ERR(hpriv))
+               return PTR_ERR(hpriv);
+
+       hpriv->start_engine = ahci_sunxi_start_engine;
+
+       rc = ahci_platform_enable_resources(hpriv);
+       if (rc)
+               return rc;
+
+       rc = ahci_sunxi_phy_init(dev, hpriv->mmio);
+       if (rc)
+               goto disable_resources;
+
+       rc = ahci_platform_init_host(pdev, hpriv, &ahci_sunxi_port_info, 0, 0);
+       if (rc)
+               goto disable_resources;
+
+       return 0;
+
+disable_resources:
+       ahci_platform_disable_resources(hpriv);
+       return rc;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int ahci_sunxi_resume(struct device *dev)
+{
+       struct ata_host *host = dev_get_drvdata(dev);
+       struct ahci_host_priv *hpriv = host->private_data;
+       int rc;
+
+       rc = ahci_platform_enable_resources(hpriv);
+       if (rc)
+               return rc;
+
+       rc = ahci_sunxi_phy_init(dev, hpriv->mmio);
+       if (rc)
+               goto disable_resources;
+
+       rc = ahci_platform_resume_host(dev);
+       if (rc)
+               goto disable_resources;
+
+       return 0;
+
+disable_resources:
+       ahci_platform_disable_resources(hpriv);
+       return rc;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(ahci_sunxi_pm_ops, ahci_platform_suspend,
+                        ahci_sunxi_resume);
+
+static const struct of_device_id ahci_sunxi_of_match[] = {
+       { .compatible = "allwinner,sun4i-a10-ahci", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, ahci_sunxi_of_match);
+
+static struct platform_driver ahci_sunxi_driver = {
+       .probe = ahci_sunxi_probe,
+       .remove = ata_platform_remove_one,
+       .driver = {
+               .name = "ahci-sunxi",
+               .owner = THIS_MODULE,
+               .of_match_table = ahci_sunxi_of_match,
+               .pm = &ahci_sunxi_pm_ops,
+       },
+};
+module_platform_driver(ahci_sunxi_driver);
+
+MODULE_DESCRIPTION("Allwinner sunxi AHCI SATA driver");
+MODULE_AUTHOR("Olliver Schinagl <oliver@schinagl.nl>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c
new file mode 100644 (file)
index 0000000..77c89bf
--- /dev/null
@@ -0,0 +1,486 @@
+/*
+ * AppliedMicro X-Gene SoC SATA Host Controller Driver
+ *
+ * Copyright (c) 2014, Applied Micro Circuits Corporation
+ * Author: Loc Ho <lho@apm.com>
+ *         Tuan Phan <tphan@apm.com>
+ *         Suman Tripathi <stripathi@apm.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * NOTE: PM support is not currently available.
+ *
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/ahci_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/phy/phy.h>
+#include "ahci.h"
+
+/* Max # of disk per a controller */
+#define MAX_AHCI_CHN_PERCTR            2
+
+/* MUX CSR */
+#define SATA_ENET_CONFIG_REG           0x00000000
+#define  CFG_SATA_ENET_SELECT_MASK     0x00000001
+
+/* SATA core host controller CSR */
+#define SLVRDERRATTRIBUTES             0x00000000
+#define SLVWRERRATTRIBUTES             0x00000004
+#define MSTRDERRATTRIBUTES             0x00000008
+#define MSTWRERRATTRIBUTES             0x0000000c
+#define BUSCTLREG                      0x00000014
+#define IOFMSTRWAUX                    0x00000018
+#define INTSTATUSMASK                  0x0000002c
+#define ERRINTSTATUS                   0x00000030
+#define ERRINTSTATUSMASK               0x00000034
+
+/* SATA host AHCI CSR */
+#define PORTCFG                                0x000000a4
+#define  PORTADDR_SET(dst, src) \
+               (((dst) & ~0x0000003f) | (((u32)(src)) & 0x0000003f))
+#define PORTPHY1CFG            0x000000a8
+#define PORTPHY1CFG_FRCPHYRDY_SET(dst, src) \
+               (((dst) & ~0x00100000) | (((u32)(src) << 0x14) & 0x00100000))
+#define PORTPHY2CFG                    0x000000ac
+#define PORTPHY3CFG                    0x000000b0
+#define PORTPHY4CFG                    0x000000b4
+#define PORTPHY5CFG                    0x000000b8
+#define SCTL0                          0x0000012C
+#define PORTPHY5CFG_RTCHG_SET(dst, src) \
+               (((dst) & ~0xfff00000) | (((u32)(src) << 0x14) & 0xfff00000))
+#define PORTAXICFG_EN_CONTEXT_SET(dst, src) \
+               (((dst) & ~0x01000000) | (((u32)(src) << 0x18) & 0x01000000))
+#define PORTAXICFG                     0x000000bc
+#define PORTAXICFG_OUTTRANS_SET(dst, src) \
+               (((dst) & ~0x00f00000) | (((u32)(src) << 0x14) & 0x00f00000))
+
+/* SATA host controller AXI CSR */
+#define INT_SLV_TMOMASK                        0x00000010
+
+/* SATA diagnostic CSR */
+#define CFG_MEM_RAM_SHUTDOWN           0x00000070
+#define BLOCK_MEM_RDY                  0x00000074
+
+struct xgene_ahci_context {
+       struct ahci_host_priv *hpriv;
+       struct device *dev;
+       void __iomem *csr_core;         /* Core CSR address of IP */
+       void __iomem *csr_diag;         /* Diag CSR address of IP */
+       void __iomem *csr_axi;          /* AXI CSR address of IP */
+       void __iomem *csr_mux;          /* MUX CSR address of IP */
+};
+
+static int xgene_ahci_init_memram(struct xgene_ahci_context *ctx)
+{
+       dev_dbg(ctx->dev, "Release memory from shutdown\n");
+       writel(0x0, ctx->csr_diag + CFG_MEM_RAM_SHUTDOWN);
+       readl(ctx->csr_diag + CFG_MEM_RAM_SHUTDOWN); /* Force a barrier */
+       msleep(1);      /* reset may take up to 1ms */
+       if (readl(ctx->csr_diag + BLOCK_MEM_RDY) != 0xFFFFFFFF) {
+               dev_err(ctx->dev, "failed to release memory from shutdown\n");
+               return -ENODEV;
+       }
+       return 0;
+}
+
+/**
+ * xgene_ahci_read_id - Read ID data from the specified device
+ * @dev: device
+ * @tf: proposed taskfile
+ * @id: data buffer
+ *
+ * This custom read ID function is required due to the fact that the HW
+ * does not support DEVSLP and the controller state machine may get stuck
+ * after processing the ID query command.
+ */
+static unsigned int xgene_ahci_read_id(struct ata_device *dev,
+                                      struct ata_taskfile *tf, u16 *id)
+{
+       u32 err_mask;
+       void __iomem *port_mmio = ahci_port_base(dev->link->ap);
+
+       err_mask = ata_do_dev_read_id(dev, tf, id);
+       if (err_mask)
+               return err_mask;
+
+       /*
+        * Mask reserved area. Word78 spec of Link Power Management
+        * bit15-8: reserved
+        * bit7: NCQ autosence
+        * bit6: Software settings preservation supported
+        * bit5: reserved
+        * bit4: In-order sata delivery supported
+        * bit3: DIPM requests supported
+        * bit2: DMA Setup FIS Auto-Activate optimization supported
+        * bit1: DMA Setup FIX non-Zero buffer offsets supported
+        * bit0: Reserved
+        *
+        * Clear reserved bit 8 (DEVSLP bit) as we don't support DEVSLP
+        */
+       id[ATA_ID_FEATURE_SUPP] &= ~(1 << 8);
+
+       /*
+        * Due to HW errata, restart the port if no other command active.
+        * Otherwise the controller may get stuck.
+        */
+       if (!readl(port_mmio + PORT_CMD_ISSUE)) {
+               writel(PORT_CMD_FIS_RX, port_mmio + PORT_CMD);
+               readl(port_mmio + PORT_CMD);    /* Force a barrier */
+               writel(PORT_CMD_FIS_RX | PORT_CMD_START, port_mmio + PORT_CMD);
+               readl(port_mmio + PORT_CMD);    /* Force a barrier */
+       }
+       return 0;
+}
+
+static void xgene_ahci_set_phy_cfg(struct xgene_ahci_context *ctx, int channel)
+{
+       void __iomem *mmio = ctx->hpriv->mmio;
+       u32 val;
+
+       dev_dbg(ctx->dev, "port configure mmio 0x%p channel %d\n",
+               mmio, channel);
+       val = readl(mmio + PORTCFG);
+       val = PORTADDR_SET(val, channel == 0 ? 2 : 3);
+       writel(val, mmio + PORTCFG);
+       readl(mmio + PORTCFG);  /* Force a barrier */
+       /* Disable fix rate */
+       writel(0x0001fffe, mmio + PORTPHY1CFG);
+       readl(mmio + PORTPHY1CFG); /* Force a barrier */
+       writel(0x5018461c, mmio + PORTPHY2CFG);
+       readl(mmio + PORTPHY2CFG); /* Force a barrier */
+       writel(0x1c081907, mmio + PORTPHY3CFG);
+       readl(mmio + PORTPHY3CFG); /* Force a barrier */
+       writel(0x1c080815, mmio + PORTPHY4CFG);
+       readl(mmio + PORTPHY4CFG); /* Force a barrier */
+       /* Set window negotiation */
+       val = readl(mmio + PORTPHY5CFG);
+       val = PORTPHY5CFG_RTCHG_SET(val, 0x300);
+       writel(val, mmio + PORTPHY5CFG);
+       readl(mmio + PORTPHY5CFG); /* Force a barrier */
+       val = readl(mmio + PORTAXICFG);
+       val = PORTAXICFG_EN_CONTEXT_SET(val, 0x1); /* Enable context mgmt */
+       val = PORTAXICFG_OUTTRANS_SET(val, 0xe); /* Set outstanding */
+       writel(val, mmio + PORTAXICFG);
+       readl(mmio + PORTAXICFG); /* Force a barrier */
+}
+
+/**
+ * xgene_ahci_do_hardreset - Issue the actual COMRESET
+ * @link: link to reset
+ * @deadline: deadline jiffies for the operation
+ * @online: Return value to indicate if device online
+ *
+ * Due to the limitation of the hardware PHY, a difference set of setting is
+ * required for each supported disk speed - Gen3 (6.0Gbps), Gen2 (3.0Gbps),
+ * and Gen1 (1.5Gbps). Otherwise during long IO stress test, the PHY will
+ * report disparity error and etc. In addition, during COMRESET, there can
+ * be error reported in the register PORT_SCR_ERR. For SERR_DISPARITY and
+ * SERR_10B_8B_ERR, the PHY receiver line must be reseted. The following
+ * algorithm is followed to proper configure the hardware PHY during COMRESET:
+ *
+ * Alg Part 1:
+ * 1. Start the PHY at Gen3 speed (default setting)
+ * 2. Issue the COMRESET
+ * 3. If no link, go to Alg Part 3
+ * 4. If link up, determine if the negotiated speed matches the PHY
+ *    configured speed
+ * 5. If they matched, go to Alg Part 2
+ * 6. If they do not matched and first time, configure the PHY for the linked
+ *    up disk speed and repeat step 2
+ * 7. Go to Alg Part 2
+ *
+ * Alg Part 2:
+ * 1. On link up, if there are any SERR_DISPARITY and SERR_10B_8B_ERR error
+ *    reported in the register PORT_SCR_ERR, then reset the PHY receiver line
+ * 2. Go to Alg Part 3
+ *
+ * Alg Part 3:
+ * 1. Clear any pending from register PORT_SCR_ERR.
+ *
+ * NOTE: For the initial version, we will NOT support Gen1/Gen2. In addition
+ *       and until the underlying PHY supports an method to reset the receiver
+ *       line, on detection of SERR_DISPARITY or SERR_10B_8B_ERR errors,
+ *       an warning message will be printed.
+ */
+static int xgene_ahci_do_hardreset(struct ata_link *link,
+                                  unsigned long deadline, bool *online)
+{
+       const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
+       struct ata_port *ap = link->ap;
+       struct ahci_host_priv *hpriv = ap->host->private_data;
+       struct xgene_ahci_context *ctx = hpriv->plat_data;
+       struct ahci_port_priv *pp = ap->private_data;
+       u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+       void __iomem *port_mmio = ahci_port_base(ap);
+       struct ata_taskfile tf;
+       int rc;
+       u32 val;
+
+       /* clear D2H reception area to properly wait for D2H FIS */
+       ata_tf_init(link->device, &tf);
+       tf.command = ATA_BUSY;
+       ata_tf_to_fis(&tf, 0, 0, d2h_fis);
+       rc = sata_link_hardreset(link, timing, deadline, online,
+                                ahci_check_ready);
+
+       val = readl(port_mmio + PORT_SCR_ERR);
+       if (val & (SERR_DISPARITY | SERR_10B_8B_ERR))
+               dev_warn(ctx->dev, "link has error\n");
+
+       /* clear all errors if any pending */
+       val = readl(port_mmio + PORT_SCR_ERR);
+       writel(val, port_mmio + PORT_SCR_ERR);
+
+       return rc;
+}
+
+static int xgene_ahci_hardreset(struct ata_link *link, unsigned int *class,
+                               unsigned long deadline)
+{
+       struct ata_port *ap = link->ap;
+        struct ahci_host_priv *hpriv = ap->host->private_data;
+       void __iomem *port_mmio = ahci_port_base(ap);
+       bool online;
+       int rc;
+       u32 portcmd_saved;
+       u32 portclb_saved;
+       u32 portclbhi_saved;
+       u32 portrxfis_saved;
+       u32 portrxfishi_saved;
+
+       /* As hardreset resets these CSR, save it to restore later */
+       portcmd_saved = readl(port_mmio + PORT_CMD);
+       portclb_saved = readl(port_mmio + PORT_LST_ADDR);
+       portclbhi_saved = readl(port_mmio + PORT_LST_ADDR_HI);
+       portrxfis_saved = readl(port_mmio + PORT_FIS_ADDR);
+       portrxfishi_saved = readl(port_mmio + PORT_FIS_ADDR_HI);
+
+       ahci_stop_engine(ap);
+
+       rc = xgene_ahci_do_hardreset(link, deadline, &online);
+
+       /* As controller hardreset clears them, restore them */
+       writel(portcmd_saved, port_mmio + PORT_CMD);
+       writel(portclb_saved, port_mmio + PORT_LST_ADDR);
+       writel(portclbhi_saved, port_mmio + PORT_LST_ADDR_HI);
+       writel(portrxfis_saved, port_mmio + PORT_FIS_ADDR);
+       writel(portrxfishi_saved, port_mmio + PORT_FIS_ADDR_HI);
+
+       hpriv->start_engine(ap);
+
+       if (online)
+               *class = ahci_dev_classify(ap);
+
+       return rc;
+}
+
+static void xgene_ahci_host_stop(struct ata_host *host)
+{
+       struct ahci_host_priv *hpriv = host->private_data;
+
+       ahci_platform_disable_resources(hpriv);
+}
+
+static struct ata_port_operations xgene_ahci_ops = {
+       .inherits = &ahci_ops,
+       .host_stop = xgene_ahci_host_stop,
+       .hardreset = xgene_ahci_hardreset,
+       .read_id = xgene_ahci_read_id,
+};
+
+static const struct ata_port_info xgene_ahci_port_info = {
+       AHCI_HFLAGS(AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ),
+       .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ,
+       .pio_mask = ATA_PIO4,
+       .udma_mask = ATA_UDMA6,
+       .port_ops = &xgene_ahci_ops,
+};
+
+static int xgene_ahci_hw_init(struct ahci_host_priv *hpriv)
+{
+       struct xgene_ahci_context *ctx = hpriv->plat_data;
+       int i;
+       int rc;
+       u32 val;
+
+       /* Remove IP RAM out of shutdown */
+       rc = xgene_ahci_init_memram(ctx);
+       if (rc)
+               return rc;
+
+       for (i = 0; i < MAX_AHCI_CHN_PERCTR; i++)
+               xgene_ahci_set_phy_cfg(ctx, i);
+
+       /* AXI disable Mask */
+       writel(0xffffffff, hpriv->mmio + HOST_IRQ_STAT);
+       readl(hpriv->mmio + HOST_IRQ_STAT); /* Force a barrier */
+       writel(0, ctx->csr_core + INTSTATUSMASK);
+       val = readl(ctx->csr_core + INTSTATUSMASK); /* Force a barrier */
+       dev_dbg(ctx->dev, "top level interrupt mask 0x%X value 0x%08X\n",
+               INTSTATUSMASK, val);
+
+       writel(0x0, ctx->csr_core + ERRINTSTATUSMASK);
+       readl(ctx->csr_core + ERRINTSTATUSMASK); /* Force a barrier */
+       writel(0x0, ctx->csr_axi + INT_SLV_TMOMASK);
+       readl(ctx->csr_axi + INT_SLV_TMOMASK);
+
+       /* Enable AXI Interrupt */
+       writel(0xffffffff, ctx->csr_core + SLVRDERRATTRIBUTES);
+       writel(0xffffffff, ctx->csr_core + SLVWRERRATTRIBUTES);
+       writel(0xffffffff, ctx->csr_core + MSTRDERRATTRIBUTES);
+       writel(0xffffffff, ctx->csr_core + MSTWRERRATTRIBUTES);
+
+       /* Enable coherency */
+       val = readl(ctx->csr_core + BUSCTLREG);
+       val &= ~0x00000002;     /* Enable write coherency */
+       val &= ~0x00000001;     /* Enable read coherency */
+       writel(val, ctx->csr_core + BUSCTLREG);
+
+       val = readl(ctx->csr_core + IOFMSTRWAUX);
+       val |= (1 << 3);        /* Enable read coherency */
+       val |= (1 << 9);        /* Enable write coherency */
+       writel(val, ctx->csr_core + IOFMSTRWAUX);
+       val = readl(ctx->csr_core + IOFMSTRWAUX);
+       dev_dbg(ctx->dev, "coherency 0x%X value 0x%08X\n",
+               IOFMSTRWAUX, val);
+
+       return rc;
+}
+
+static int xgene_ahci_mux_select(struct xgene_ahci_context *ctx)
+{
+       u32 val;
+
+       /* Check for optional MUX resource */
+       if (IS_ERR(ctx->csr_mux))
+               return 0;
+
+       val = readl(ctx->csr_mux + SATA_ENET_CONFIG_REG);
+       val &= ~CFG_SATA_ENET_SELECT_MASK;
+       writel(val, ctx->csr_mux + SATA_ENET_CONFIG_REG);
+       val = readl(ctx->csr_mux + SATA_ENET_CONFIG_REG);
+       return val & CFG_SATA_ENET_SELECT_MASK ? -1 : 0;
+}
+
+static int xgene_ahci_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct ahci_host_priv *hpriv;
+       struct xgene_ahci_context *ctx;
+       struct resource *res;
+       int rc;
+
+       hpriv = ahci_platform_get_resources(pdev);
+       if (IS_ERR(hpriv))
+               return PTR_ERR(hpriv);
+
+       ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       hpriv->plat_data = ctx;
+       ctx->hpriv = hpriv;
+       ctx->dev = dev;
+
+       /* Retrieve the IP core resource */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       ctx->csr_core = devm_ioremap_resource(dev, res);
+       if (IS_ERR(ctx->csr_core))
+               return PTR_ERR(ctx->csr_core);
+
+       /* Retrieve the IP diagnostic resource */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+       ctx->csr_diag = devm_ioremap_resource(dev, res);
+       if (IS_ERR(ctx->csr_diag))
+               return PTR_ERR(ctx->csr_diag);
+
+       /* Retrieve the IP AXI resource */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+       ctx->csr_axi = devm_ioremap_resource(dev, res);
+       if (IS_ERR(ctx->csr_axi))
+               return PTR_ERR(ctx->csr_axi);
+
+       /* Retrieve the optional IP mux resource */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
+       ctx->csr_mux = devm_ioremap_resource(dev, res);
+
+       dev_dbg(dev, "VAddr 0x%p Mmio VAddr 0x%p\n", ctx->csr_core,
+               hpriv->mmio);
+
+       /* Select ATA */
+       if ((rc = xgene_ahci_mux_select(ctx))) {
+               dev_err(dev, "SATA mux selection failed error %d\n", rc);
+               return -ENODEV;
+       }
+
+       /* Due to errata, HW requires full toggle transition */
+       rc = ahci_platform_enable_clks(hpriv);
+       if (rc)
+               goto disable_resources;
+       ahci_platform_disable_clks(hpriv);
+
+       rc = ahci_platform_enable_resources(hpriv);
+       if (rc)
+               goto disable_resources;
+
+       /* Configure the host controller */
+       xgene_ahci_hw_init(hpriv);
+
+       /*
+        * Setup DMA mask. This is preliminary until the DMA range is sorted
+        * out.
+        */
+       rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
+       if (rc) {
+               dev_err(dev, "Unable to set dma mask\n");
+               goto disable_resources;
+       }
+
+       rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info, 0, 0);
+       if (rc)
+               goto disable_resources;
+
+       dev_dbg(dev, "X-Gene SATA host controller initialized\n");
+       return 0;
+
+disable_resources:
+       ahci_platform_disable_resources(hpriv);
+       return rc;
+}
+
+static const struct of_device_id xgene_ahci_of_match[] = {
+       {.compatible = "apm,xgene-ahci"},
+       {},
+};
+MODULE_DEVICE_TABLE(of, xgene_ahci_of_match);
+
+static struct platform_driver xgene_ahci_driver = {
+       .probe = xgene_ahci_probe,
+       .remove = ata_platform_remove_one,
+       .driver = {
+               .name = "xgene-ahci",
+               .owner = THIS_MODULE,
+               .of_match_table = xgene_ahci_of_match,
+       },
+};
+
+module_platform_driver(xgene_ahci_driver);
+
+MODULE_DESCRIPTION("APM X-Gene AHCI SATA driver");
+MODULE_AUTHOR("Loc Ho <lho@apm.com>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.4");
index 7d196656adb5581533517a6ed0ec49d8c2966b58..9498a7d3846fef6e2c88bdd8596d3f2080e0349e 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 36605abe5a6786dd8282bceb798c10663e3b16f6..6bd4f660b4e15966ca2c351b4501c0521491de32 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/kernel.h>
 #include <linux/gfp.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -394,6 +393,9 @@ static ssize_t ahci_show_em_supported(struct device *dev,
  *
  *     If inconsistent, config values are fixed up by this function.
  *
+ *     If it is not set already this function sets hpriv->start_engine to
+ *     ahci_start_engine.
+ *
  *     LOCKING:
  *     None.
  */
@@ -500,6 +502,9 @@ void ahci_save_initial_config(struct device *dev,
        hpriv->cap = cap;
        hpriv->cap2 = cap2;
        hpriv->port_map = port_map;
+
+       if (!hpriv->start_engine)
+               hpriv->start_engine = ahci_start_engine;
 }
 EXPORT_SYMBOL_GPL(ahci_save_initial_config);
 
@@ -766,7 +771,7 @@ static void ahci_start_port(struct ata_port *ap)
 
        /* enable DMA */
        if (!(hpriv->flags & AHCI_HFLAG_DELAY_ENGINE))
-               ahci_start_engine(ap);
+               hpriv->start_engine(ap);
 
        /* turn on LEDs */
        if (ap->flags & ATA_FLAG_EM) {
@@ -1032,12 +1037,13 @@ static ssize_t ahci_led_show(struct ata_port *ap, char *buf)
 static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
                                size_t size)
 {
-       int state;
+       unsigned int state;
        int pmp;
        struct ahci_port_priv *pp = ap->private_data;
        struct ahci_em_priv *emp;
 
-       state = simple_strtoul(buf, NULL, 0);
+       if (kstrtouint(buf, 0, &state) < 0)
+               return -EINVAL;
 
        /* get the slot number from the message */
        pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
@@ -1234,7 +1240,7 @@ int ahci_kick_engine(struct ata_port *ap)
 
        /* restart engine */
  out_restart:
-       ahci_start_engine(ap);
+       hpriv->start_engine(ap);
        return rc;
 }
 EXPORT_SYMBOL_GPL(ahci_kick_engine);
@@ -1387,8 +1393,8 @@ static int ahci_bad_pmp_check_ready(struct ata_link *link)
        return ata_check_ready(status);
 }
 
-int ahci_pmp_retry_softreset(struct ata_link *link, unsigned int *class,
-                               unsigned long deadline)
+static int ahci_pmp_retry_softreset(struct ata_link *link, unsigned int *class,
+                                   unsigned long deadline)
 {
        struct ata_port *ap = link->ap;
        void __iomem *port_mmio = ahci_port_base(ap);
@@ -1426,6 +1432,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
        const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
        struct ata_port *ap = link->ap;
        struct ahci_port_priv *pp = ap->private_data;
+       struct ahci_host_priv *hpriv = ap->host->private_data;
        u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
        struct ata_taskfile tf;
        bool online;
@@ -1443,7 +1450,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
        rc = sata_link_hardreset(link, timing, deadline, &online,
                                 ahci_check_ready);
 
-       ahci_start_engine(ap);
+       hpriv->start_engine(ap);
 
        if (online)
                *class = ahci_dev_classify(ap);
@@ -1629,7 +1636,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
        }
 
        if (irq_stat & PORT_IRQ_UNK_FIS) {
-               u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
+               u32 *unk = pp->rx_fis + RX_FIS_UNK;
 
                active_ehi->err_mask |= AC_ERR_HSM;
                active_ehi->action |= ATA_EH_RESET;
@@ -2007,10 +2014,12 @@ static void ahci_thaw(struct ata_port *ap)
 
 void ahci_error_handler(struct ata_port *ap)
 {
+       struct ahci_host_priv *hpriv = ap->host->private_data;
+
        if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
                /* restart engine */
                ahci_stop_engine(ap);
-               ahci_start_engine(ap);
+               hpriv->start_engine(ap);
        }
 
        sata_pmp_error_handler(ap);
@@ -2031,6 +2040,7 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
 
 static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
 {
+       struct ahci_host_priv *hpriv = ap->host->private_data;
        void __iomem *port_mmio = ahci_port_base(ap);
        struct ata_device *dev = ap->link.device;
        u32 devslp, dm, dito, mdat, deto;
@@ -2094,7 +2104,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
                   PORT_DEVSLP_ADSE);
        writel(devslp, port_mmio + PORT_DEVSLP);
 
-       ahci_start_engine(ap);
+       hpriv->start_engine(ap);
 
        /* enable device sleep feature for the drive */
        err_mask = ata_dev_set_feature(dev,
@@ -2106,6 +2116,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
 
 static void ahci_enable_fbs(struct ata_port *ap)
 {
+       struct ahci_host_priv *hpriv = ap->host->private_data;
        struct ahci_port_priv *pp = ap->private_data;
        void __iomem *port_mmio = ahci_port_base(ap);
        u32 fbs;
@@ -2134,11 +2145,12 @@ static void ahci_enable_fbs(struct ata_port *ap)
        } else
                dev_err(ap->host->dev, "Failed to enable FBS\n");
 
-       ahci_start_engine(ap);
+       hpriv->start_engine(ap);
 }
 
 static void ahci_disable_fbs(struct ata_port *ap)
 {
+       struct ahci_host_priv *hpriv = ap->host->private_data;
        struct ahci_port_priv *pp = ap->private_data;
        void __iomem *port_mmio = ahci_port_base(ap);
        u32 fbs;
@@ -2166,7 +2178,7 @@ static void ahci_disable_fbs(struct ata_port *ap)
                pp->fbs_enabled = false;
        }
 
-       ahci_start_engine(ap);
+       hpriv->start_engine(ap);
 }
 
 static void ahci_pmp_attach(struct ata_port *ap)
diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
new file mode 100644 (file)
index 0000000..7cb3a85
--- /dev/null
@@ -0,0 +1,541 @@
+/*
+ * AHCI SATA platform library
+ *
+ * Copyright 2004-2005  Red Hat, Inc.
+ *   Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2010  MontaVista Software, LLC.
+ *   Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/libata.h>
+#include <linux/ahci_platform.h>
+#include <linux/phy/phy.h>
+#include <linux/pm_runtime.h>
+#include "ahci.h"
+
+static void ahci_host_stop(struct ata_host *host);
+
+struct ata_port_operations ahci_platform_ops = {
+       .inherits       = &ahci_ops,
+       .host_stop      = ahci_host_stop,
+};
+EXPORT_SYMBOL_GPL(ahci_platform_ops);
+
+static struct scsi_host_template ahci_platform_sht = {
+       AHCI_SHT("ahci_platform"),
+};
+
+/**
+ * ahci_platform_enable_clks - Enable platform clocks
+ * @hpriv: host private area to store config values
+ *
+ * This function enables all the clks found in hpriv->clks, starting at
+ * index 0. If any clk fails to enable it disables all the clks already
+ * enabled in reverse order, and then returns an error.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_enable_clks(struct ahci_host_priv *hpriv)
+{
+       int c, rc;
+
+       for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) {
+               rc = clk_prepare_enable(hpriv->clks[c]);
+               if (rc)
+                       goto disable_unprepare_clk;
+       }
+       return 0;
+
+disable_unprepare_clk:
+       while (--c >= 0)
+               clk_disable_unprepare(hpriv->clks[c]);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
+
+/**
+ * ahci_platform_disable_clks - Disable platform clocks
+ * @hpriv: host private area to store config values
+ *
+ * This function disables all the clks found in hpriv->clks, in reverse
+ * order of ahci_platform_enable_clks (starting at the end of the array).
+ */
+void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
+{
+       int c;
+
+       for (c = AHCI_MAX_CLKS - 1; c >= 0; c--)
+               if (hpriv->clks[c])
+                       clk_disable_unprepare(hpriv->clks[c]);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
+
+/**
+ * ahci_platform_enable_resources - Enable platform resources
+ * @hpriv: host private area to store config values
+ *
+ * This function enables all ahci_platform managed resources in the
+ * following order:
+ * 1) Regulator
+ * 2) Clocks (through ahci_platform_enable_clks)
+ * 3) Phy
+ *
+ * If resource enabling fails at any point the previous enabled resources
+ * are disabled in reverse order.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
+{
+       int rc;
+
+       if (hpriv->target_pwr) {
+               rc = regulator_enable(hpriv->target_pwr);
+               if (rc)
+                       return rc;
+       }
+
+       rc = ahci_platform_enable_clks(hpriv);
+       if (rc)
+               goto disable_regulator;
+
+       if (hpriv->phy) {
+               rc = phy_init(hpriv->phy);
+               if (rc)
+                       goto disable_clks;
+
+               rc = phy_power_on(hpriv->phy);
+               if (rc) {
+                       phy_exit(hpriv->phy);
+                       goto disable_clks;
+               }
+       }
+
+       return 0;
+
+disable_clks:
+       ahci_platform_disable_clks(hpriv);
+
+disable_regulator:
+       if (hpriv->target_pwr)
+               regulator_disable(hpriv->target_pwr);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_enable_resources);
+
+/**
+ * ahci_platform_disable_resources - Disable platform resources
+ * @hpriv: host private area to store config values
+ *
+ * This function disables all ahci_platform managed resources in the
+ * following order:
+ * 1) Phy
+ * 2) Clocks (through ahci_platform_disable_clks)
+ * 3) Regulator
+ */
+void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
+{
+       if (hpriv->phy) {
+               phy_power_off(hpriv->phy);
+               phy_exit(hpriv->phy);
+       }
+
+       ahci_platform_disable_clks(hpriv);
+
+       if (hpriv->target_pwr)
+               regulator_disable(hpriv->target_pwr);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_disable_resources);
+
+static void ahci_platform_put_resources(struct device *dev, void *res)
+{
+       struct ahci_host_priv *hpriv = res;
+       int c;
+
+       if (hpriv->got_runtime_pm) {
+               pm_runtime_put_sync(dev);
+               pm_runtime_disable(dev);
+       }
+
+       for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
+               clk_put(hpriv->clks[c]);
+}
+
+/**
+ * ahci_platform_get_resources - Get platform resources
+ * @pdev: platform device to get resources for
+ *
+ * This function allocates an ahci_host_priv struct, and gets the following
+ * resources, storing a reference to them inside the returned struct:
+ *
+ * 1) mmio registers (IORESOURCE_MEM 0, mandatory)
+ * 2) regulator for controlling the targets power (optional)
+ * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node,
+ *    or for non devicetree enabled platforms a single clock
+ *     4) phy (optional)
+ *
+ * RETURNS:
+ * The allocated ahci_host_priv on success, otherwise an ERR_PTR value
+ */
+struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct ahci_host_priv *hpriv;
+       struct clk *clk;
+       int i, rc = -ENOMEM;
+
+       if (!devres_open_group(dev, NULL, GFP_KERNEL))
+               return ERR_PTR(-ENOMEM);
+
+       hpriv = devres_alloc(ahci_platform_put_resources, sizeof(*hpriv),
+                            GFP_KERNEL);
+       if (!hpriv)
+               goto err_out;
+
+       devres_add(dev, hpriv);
+
+       hpriv->mmio = devm_ioremap_resource(dev,
+                             platform_get_resource(pdev, IORESOURCE_MEM, 0));
+       if (IS_ERR(hpriv->mmio)) {
+               dev_err(dev, "no mmio space\n");
+               rc = PTR_ERR(hpriv->mmio);
+               goto err_out;
+       }
+
+       hpriv->target_pwr = devm_regulator_get_optional(dev, "target");
+       if (IS_ERR(hpriv->target_pwr)) {
+               rc = PTR_ERR(hpriv->target_pwr);
+               if (rc == -EPROBE_DEFER)
+                       goto err_out;
+               hpriv->target_pwr = NULL;
+       }
+
+       for (i = 0; i < AHCI_MAX_CLKS; i++) {
+               /*
+                * For now we must use clk_get(dev, NULL) for the first clock,
+                * because some platforms (da850, spear13xx) are not yet
+                * converted to use devicetree for clocks.  For new platforms
+                * this is equivalent to of_clk_get(dev->of_node, 0).
+                */
+               if (i == 0)
+                       clk = clk_get(dev, NULL);
+               else
+                       clk = of_clk_get(dev->of_node, i);
+
+               if (IS_ERR(clk)) {
+                       rc = PTR_ERR(clk);
+                       if (rc == -EPROBE_DEFER)
+                               goto err_out;
+                       break;
+               }
+               hpriv->clks[i] = clk;
+       }
+
+       hpriv->phy = devm_phy_get(dev, "sata-phy");
+       if (IS_ERR(hpriv->phy)) {
+               rc = PTR_ERR(hpriv->phy);
+               switch (rc) {
+               case -ENODEV:
+               case -ENOSYS:
+                       /* continue normally */
+                       hpriv->phy = NULL;
+                       break;
+
+               case -EPROBE_DEFER:
+                       goto err_out;
+
+               default:
+                       dev_err(dev, "couldn't get sata-phy\n");
+                       goto err_out;
+               }
+       }
+
+       pm_runtime_enable(dev);
+       pm_runtime_get_sync(dev);
+       hpriv->got_runtime_pm = true;
+
+       devres_remove_group(dev, NULL);
+       return hpriv;
+
+err_out:
+       devres_release_group(dev, NULL);
+       return ERR_PTR(rc);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_get_resources);
+
+/**
+ * ahci_platform_init_host - Bring up an ahci-platform host
+ * @pdev: platform device pointer for the host
+ * @hpriv: ahci-host private data for the host
+ * @pi_template: template for the ata_port_info to use
+ * @force_port_map: param passed to ahci_save_initial_config
+ * @mask_port_map: param passed to ahci_save_initial_config
+ *
+ * This function does all the usual steps needed to bring up an
+ * ahci-platform host, note any necessary resources (ie clks, phy, etc.)
+ * must be initialized / enabled before calling this.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_init_host(struct platform_device *pdev,
+                           struct ahci_host_priv *hpriv,
+                           const struct ata_port_info *pi_template,
+                           unsigned int force_port_map,
+                           unsigned int mask_port_map)
+{
+       struct device *dev = &pdev->dev;
+       struct ata_port_info pi = *pi_template;
+       const struct ata_port_info *ppi[] = { &pi, NULL };
+       struct ata_host *host;
+       int i, irq, n_ports, rc;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0) {
+               dev_err(dev, "no irq\n");
+               return -EINVAL;
+       }
+
+       /* prepare host */
+       hpriv->flags |= (unsigned long)pi.private_data;
+
+       ahci_save_initial_config(dev, hpriv, force_port_map, mask_port_map);
+
+       if (hpriv->cap & HOST_CAP_NCQ)
+               pi.flags |= ATA_FLAG_NCQ;
+
+       if (hpriv->cap & HOST_CAP_PMP)
+               pi.flags |= ATA_FLAG_PMP;
+
+       ahci_set_em_messages(hpriv, &pi);
+
+       /* CAP.NP sometimes indicate the index of the last enabled
+        * port, at other times, that of the last possible port, so
+        * determining the maximum port number requires looking at
+        * both CAP.NP and port_map.
+        */
+       n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
+
+       host = ata_host_alloc_pinfo(dev, ppi, n_ports);
+       if (!host)
+               return -ENOMEM;
+
+       host->private_data = hpriv;
+
+       if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
+               host->flags |= ATA_HOST_PARALLEL_SCAN;
+       else
+               dev_info(dev, "SSS flag set, parallel bus scan disabled\n");
+
+       if (pi.flags & ATA_FLAG_EM)
+               ahci_reset_em(host);
+
+       for (i = 0; i < host->n_ports; i++) {
+               struct ata_port *ap = host->ports[i];
+
+               ata_port_desc(ap, "mmio %pR",
+                             platform_get_resource(pdev, IORESOURCE_MEM, 0));
+               ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
+
+               /* set enclosure management message type */
+               if (ap->flags & ATA_FLAG_EM)
+                       ap->em_message_type = hpriv->em_msg_type;
+
+               /* disabled/not-implemented port */
+               if (!(hpriv->port_map & (1 << i)))
+                       ap->ops = &ata_dummy_port_ops;
+       }
+
+       rc = ahci_reset_controller(host);
+       if (rc)
+               return rc;
+
+       ahci_init_controller(host);
+       ahci_print_info(host, "platform");
+
+       return ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED,
+                                &ahci_platform_sht);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_init_host);
+
+static void ahci_host_stop(struct ata_host *host)
+{
+       struct device *dev = host->dev;
+       struct ahci_platform_data *pdata = dev_get_platdata(dev);
+       struct ahci_host_priv *hpriv = host->private_data;
+
+       if (pdata && pdata->exit)
+               pdata->exit(dev);
+
+       ahci_platform_disable_resources(hpriv);
+}
+
+#ifdef CONFIG_PM_SLEEP
+/**
+ * ahci_platform_suspend_host - Suspend an ahci-platform host
+ * @dev: device pointer for the host
+ *
+ * This function does all the usual steps needed to suspend an
+ * ahci-platform host, note any necessary resources (ie clks, phy, etc.)
+ * must be disabled after calling this.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_suspend_host(struct device *dev)
+{
+       struct ata_host *host = dev_get_drvdata(dev);
+       struct ahci_host_priv *hpriv = host->private_data;
+       void __iomem *mmio = hpriv->mmio;
+       u32 ctl;
+
+       if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
+               dev_err(dev, "firmware update required for suspend/resume\n");
+               return -EIO;
+       }
+
+       /*
+        * AHCI spec rev1.1 section 8.3.3:
+        * Software must disable interrupts prior to requesting a
+        * transition of the HBA to D3 state.
+        */
+       ctl = readl(mmio + HOST_CTL);
+       ctl &= ~HOST_IRQ_EN;
+       writel(ctl, mmio + HOST_CTL);
+       readl(mmio + HOST_CTL); /* flush */
+
+       return ata_host_suspend(host, PMSG_SUSPEND);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_suspend_host);
+
+/**
+ * ahci_platform_resume_host - Resume an ahci-platform host
+ * @dev: device pointer for the host
+ *
+ * This function does all the usual steps needed to resume an ahci-platform
+ * host, note any necessary resources (ie clks, phy, etc.)  must be
+ * initialized / enabled before calling this.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_resume_host(struct device *dev)
+{
+       struct ata_host *host = dev_get_drvdata(dev);
+       int rc;
+
+       if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
+               rc = ahci_reset_controller(host);
+               if (rc)
+                       return rc;
+
+               ahci_init_controller(host);
+       }
+
+       ata_host_resume(host);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_resume_host);
+
+/**
+ * ahci_platform_suspend - Suspend an ahci-platform device
+ * @dev: the platform device to suspend
+ *
+ * This function suspends the host associated with the device, followed by
+ * disabling all the resources of the device.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_suspend(struct device *dev)
+{
+       struct ahci_platform_data *pdata = dev_get_platdata(dev);
+       struct ata_host *host = dev_get_drvdata(dev);
+       struct ahci_host_priv *hpriv = host->private_data;
+       int rc;
+
+       rc = ahci_platform_suspend_host(dev);
+       if (rc)
+               return rc;
+
+       if (pdata && pdata->suspend) {
+               rc = pdata->suspend(dev);
+               if (rc)
+                       goto resume_host;
+       }
+
+       ahci_platform_disable_resources(hpriv);
+
+       return 0;
+
+resume_host:
+       ahci_platform_resume_host(dev);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_suspend);
+
+/**
+ * ahci_platform_resume - Resume an ahci-platform device
+ * @dev: the platform device to resume
+ *
+ * This function enables all the resources of the device followed by
+ * resuming the host associated with the device.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_resume(struct device *dev)
+{
+       struct ahci_platform_data *pdata = dev_get_platdata(dev);
+       struct ata_host *host = dev_get_drvdata(dev);
+       struct ahci_host_priv *hpriv = host->private_data;
+       int rc;
+
+       rc = ahci_platform_enable_resources(hpriv);
+       if (rc)
+               return rc;
+
+       if (pdata && pdata->resume) {
+               rc = pdata->resume(dev);
+               if (rc)
+                       goto disable_resources;
+       }
+
+       rc = ahci_platform_resume_host(dev);
+       if (rc)
+               goto disable_resources;
+
+       /* We resumed so update PM runtime state */
+       pm_runtime_disable(dev);
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+
+       return 0;
+
+disable_resources:
+       ahci_platform_disable_resources(hpriv);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_resume);
+#endif
+
+MODULE_DESCRIPTION("AHCI SATA platform library");
+MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
+MODULE_LICENSE("GPL");
index 9e69a5308693de59abd5c596244033af43f7b3a8..b4f7cc2522d91a3d843c5c65478549bd0a79c601 100644 (file)
@@ -835,6 +835,7 @@ void ata_acpi_on_resume(struct ata_port *ap)
                ata_for_each_dev(dev, &ap->link, ALL) {
                        ata_acpi_clear_gtf(dev);
                        if (ata_dev_enabled(dev) &&
+                           ata_dev_acpi_handle(dev) &&
                            ata_dev_get_GTF(dev, NULL) >= 0)
                                dev->flags |= ATA_DFLAG_ACPI_PENDING;
                }
index 8cb2522d592ac87f7b144f1f41d244cd5df777dc..34406f7fdd7a1274da79601489a30e6df774290c 100644 (file)
@@ -5352,22 +5352,17 @@ bool ata_link_offline(struct ata_link *link)
 }
 
 #ifdef CONFIG_PM
-static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
-                              unsigned int action, unsigned int ehi_flags,
-                              int *async)
+static void ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
+                               unsigned int action, unsigned int ehi_flags,
+                               bool async)
 {
        struct ata_link *link;
        unsigned long flags;
-       int rc = 0;
 
        /* Previous resume operation might still be in
         * progress.  Wait for PM_PENDING to clear.
         */
        if (ap->pflags & ATA_PFLAG_PM_PENDING) {
-               if (async) {
-                       *async = -EAGAIN;
-                       return 0;
-               }
                ata_port_wait_eh(ap);
                WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
        }
@@ -5376,11 +5371,6 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
        spin_lock_irqsave(ap->lock, flags);
 
        ap->pm_mesg = mesg;
-       if (async)
-               ap->pm_result = async;
-       else
-               ap->pm_result = &rc;
-
        ap->pflags |= ATA_PFLAG_PM_PENDING;
        ata_for_each_link(link, ap, HOST_FIRST) {
                link->eh_info.action |= action;
@@ -5391,87 +5381,81 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
 
        spin_unlock_irqrestore(ap->lock, flags);
 
-       /* wait and check result */
        if (!async) {
                ata_port_wait_eh(ap);
                WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
        }
-
-       return rc;
 }
 
-static int __ata_port_suspend_common(struct ata_port *ap, pm_message_t mesg, int *async)
+/*
+ * On some hardware, device fails to respond after spun down for suspend.  As
+ * the device won't be used before being resumed, we don't need to touch the
+ * device.  Ask EH to skip the usual stuff and proceed directly to suspend.
+ *
+ * http://thread.gmane.org/gmane.linux.ide/46764
+ */
+static const unsigned int ata_port_suspend_ehi = ATA_EHI_QUIET
+                                                | ATA_EHI_NO_AUTOPSY
+                                                | ATA_EHI_NO_RECOVERY;
+
+static void ata_port_suspend(struct ata_port *ap, pm_message_t mesg)
 {
-       /*
-        * On some hardware, device fails to respond after spun down
-        * for suspend.  As the device won't be used before being
-        * resumed, we don't need to touch the device.  Ask EH to skip
-        * the usual stuff and proceed directly to suspend.
-        *
-        * http://thread.gmane.org/gmane.linux.ide/46764
-        */
-       unsigned int ehi_flags = ATA_EHI_QUIET | ATA_EHI_NO_AUTOPSY |
-                                ATA_EHI_NO_RECOVERY;
-       return ata_port_request_pm(ap, mesg, 0, ehi_flags, async);
+       ata_port_request_pm(ap, mesg, 0, ata_port_suspend_ehi, false);
 }
 
-static int ata_port_suspend_common(struct device *dev, pm_message_t mesg)
+static void ata_port_suspend_async(struct ata_port *ap, pm_message_t mesg)
 {
-       struct ata_port *ap = to_ata_port(dev);
-
-       return __ata_port_suspend_common(ap, mesg, NULL);
+       ata_port_request_pm(ap, mesg, 0, ata_port_suspend_ehi, true);
 }
 
-static int ata_port_suspend(struct device *dev)
+static int ata_port_pm_suspend(struct device *dev)
 {
+       struct ata_port *ap = to_ata_port(dev);
+
        if (pm_runtime_suspended(dev))
                return 0;
 
-       return ata_port_suspend_common(dev, PMSG_SUSPEND);
+       ata_port_suspend(ap, PMSG_SUSPEND);
+       return 0;
 }
 
-static int ata_port_do_freeze(struct device *dev)
+static int ata_port_pm_freeze(struct device *dev)
 {
+       struct ata_port *ap = to_ata_port(dev);
+
        if (pm_runtime_suspended(dev))
                return 0;
 
-       return ata_port_suspend_common(dev, PMSG_FREEZE);
+       ata_port_suspend(ap, PMSG_FREEZE);
+       return 0;
 }
 
-static int ata_port_poweroff(struct device *dev)
+static int ata_port_pm_poweroff(struct device *dev)
 {
-       return ata_port_suspend_common(dev, PMSG_HIBERNATE);
+       ata_port_suspend(to_ata_port(dev), PMSG_HIBERNATE);
+       return 0;
 }
 
-static int __ata_port_resume_common(struct ata_port *ap, pm_message_t mesg,
-                                   int *async)
-{
-       int rc;
+static const unsigned int ata_port_resume_ehi = ATA_EHI_NO_AUTOPSY
+                                               | ATA_EHI_QUIET;
 
-       rc = ata_port_request_pm(ap, mesg, ATA_EH_RESET,
-               ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, async);
-       return rc;
+static void ata_port_resume(struct ata_port *ap, pm_message_t mesg)
+{
+       ata_port_request_pm(ap, mesg, ATA_EH_RESET, ata_port_resume_ehi, false);
 }
 
-static int ata_port_resume_common(struct device *dev, pm_message_t mesg)
+static void ata_port_resume_async(struct ata_port *ap, pm_message_t mesg)
 {
-       struct ata_port *ap = to_ata_port(dev);
-
-       return __ata_port_resume_common(ap, mesg, NULL);
+       ata_port_request_pm(ap, mesg, ATA_EH_RESET, ata_port_resume_ehi, true);
 }
 
-static int ata_port_resume(struct device *dev)
+static int ata_port_pm_resume(struct device *dev)
 {
-       int rc;
-
-       rc = ata_port_resume_common(dev, PMSG_RESUME);
-       if (!rc) {
-               pm_runtime_disable(dev);
-               pm_runtime_set_active(dev);
-               pm_runtime_enable(dev);
-       }
-
-       return rc;
+       ata_port_resume_async(to_ata_port(dev), PMSG_RESUME);
+       pm_runtime_disable(dev);
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+       return 0;
 }
 
 /*
@@ -5500,21 +5484,23 @@ static int ata_port_runtime_idle(struct device *dev)
 
 static int ata_port_runtime_suspend(struct device *dev)
 {
-       return ata_port_suspend_common(dev, PMSG_AUTO_SUSPEND);
+       ata_port_suspend(to_ata_port(dev), PMSG_AUTO_SUSPEND);
+       return 0;
 }
 
 static int ata_port_runtime_resume(struct device *dev)
 {
-       return ata_port_resume_common(dev, PMSG_AUTO_RESUME);
+       ata_port_resume(to_ata_port(dev), PMSG_AUTO_RESUME);
+       return 0;
 }
 
 static const struct dev_pm_ops ata_port_pm_ops = {
-       .suspend = ata_port_suspend,
-       .resume = ata_port_resume,
-       .freeze = ata_port_do_freeze,
-       .thaw = ata_port_resume,
-       .poweroff = ata_port_poweroff,
-       .restore = ata_port_resume,
+       .suspend = ata_port_pm_suspend,
+       .resume = ata_port_pm_resume,
+       .freeze = ata_port_pm_freeze,
+       .thaw = ata_port_pm_resume,
+       .poweroff = ata_port_pm_poweroff,
+       .restore = ata_port_pm_resume,
 
        .runtime_suspend = ata_port_runtime_suspend,
        .runtime_resume = ata_port_runtime_resume,
@@ -5526,18 +5512,17 @@ static const struct dev_pm_ops ata_port_pm_ops = {
  * level. sas suspend/resume is async to allow parallel port recovery
  * since sas has multiple ata_port instances per Scsi_Host.
  */
-int ata_sas_port_async_suspend(struct ata_port *ap, int *async)
+void ata_sas_port_suspend(struct ata_port *ap)
 {
-       return __ata_port_suspend_common(ap, PMSG_SUSPEND, async);
+       ata_port_suspend_async(ap, PMSG_SUSPEND);
 }
-EXPORT_SYMBOL_GPL(ata_sas_port_async_suspend);
+EXPORT_SYMBOL_GPL(ata_sas_port_suspend);
 
-int ata_sas_port_async_resume(struct ata_port *ap, int *async)
+void ata_sas_port_resume(struct ata_port *ap)
 {
-       return __ata_port_resume_common(ap, PMSG_RESUME, async);
+       ata_port_resume_async(ap, PMSG_RESUME);
 }
-EXPORT_SYMBOL_GPL(ata_sas_port_async_resume);
-
+EXPORT_SYMBOL_GPL(ata_sas_port_resume);
 
 /**
  *     ata_host_suspend - suspend host
index 6d87570083187bbbe749fe566195f854707a641c..6760fc4e85b8c809e39655fd92adc83871e75fce 100644 (file)
@@ -95,12 +95,13 @@ enum {
  * represents timeout for that try.  The first try can be soft or
  * hardreset.  All others are hardreset if available.  In most cases
  * the first reset w/ 10sec timeout should succeed.  Following entries
- * are mostly for error handling, hotplug and retarded devices.
+ * are mostly for error handling, hotplug and those outlier devices that
+ * take an exceptionally long time to recover from reset.
  */
 static const unsigned long ata_eh_reset_timeouts[] = {
        10000,  /* most drives spin up by 10sec */
        10000,  /* > 99% working drives spin up before 20sec */
-       35000,  /* give > 30 secs of idleness for retarded devices */
+       35000,  /* give > 30 secs of idleness for outlier devices */
         5000,  /* and sweet one last chance */
        ULONG_MAX, /* > 1 min has elapsed, give up */
 };
@@ -4069,7 +4070,7 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
 
        ata_acpi_set_state(ap, ap->pm_mesg);
  out:
-       /* report result */
+       /* update the flags */
        spin_lock_irqsave(ap->lock, flags);
 
        ap->pflags &= ~ATA_PFLAG_PM_PENDING;
@@ -4078,11 +4079,6 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
        else if (ap->pflags & ATA_PFLAG_FROZEN)
                ata_port_schedule_eh(ap);
 
-       if (ap->pm_result) {
-               *ap->pm_result = rc;
-               ap->pm_result = NULL;
-       }
-
        spin_unlock_irqrestore(ap->lock, flags);
 
        return;
@@ -4134,13 +4130,9 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
        /* tell ACPI that we're resuming */
        ata_acpi_on_resume(ap);
 
-       /* report result */
+       /* update the flags */
        spin_lock_irqsave(ap->lock, flags);
        ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED);
-       if (ap->pm_result) {
-               *ap->pm_result = rc;
-               ap->pm_result = NULL;
-       }
        spin_unlock_irqrestore(ap->lock, flags);
 }
 #endif /* CONFIG_PM */
index 88949c6d55ddd43b32b07accdb892256028d5e25..f3a65a3140d3c7e51bef6dce19f676de768abfdf 100644 (file)
@@ -85,21 +85,6 @@ static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev)
                return ODD_MECH_TYPE_UNSUPPORTED;
 }
 
-static bool odd_can_poweroff(struct ata_device *ata_dev)
-{
-       acpi_handle handle;
-       struct acpi_device *acpi_dev;
-
-       handle = ata_dev_acpi_handle(ata_dev);
-       if (!handle)
-               return false;
-
-       if (acpi_bus_get_device(handle, &acpi_dev))
-               return false;
-
-       return acpi_device_can_poweroff(acpi_dev);
-}
-
 /* Test if ODD is zero power ready by sense code */
 static bool zpready(struct ata_device *dev)
 {
@@ -267,13 +252,11 @@ static void ata_acpi_remove_pm_notifier(struct ata_device *dev)
 
 void zpodd_init(struct ata_device *dev)
 {
+       struct acpi_device *adev = ACPI_COMPANION(&dev->tdev);
        enum odd_mech_type mech_type;
        struct zpodd *zpodd;
 
-       if (dev->zpodd)
-               return;
-
-       if (!odd_can_poweroff(dev))
+       if (dev->zpodd || !adev || !acpi_device_can_poweroff(adev))
                return;
 
        mech_type = zpodd_get_mech_type(dev);
index 62c9ac80c6e96ed1f0a4421fb22b7ee3629ae2e9..5108b8744dce4c70d37d913fbf5b916984b36f6c 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index d23e2b3ca0b68a6c7109eef8e53b2e3e68048281..1206fa6b62cae199a00302729565915ed931509a 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 73492dd4a4bce8aade1f79a7dbdfd3926c7f6f6b..6fac524c2f500381ac8d76b2a94bf4d88314f1e7 100644 (file)
@@ -356,7 +356,7 @@ static void cf_exit(struct arasan_cf_dev *acdev)
 
 static void dma_callback(void *dev)
 {
-       struct arasan_cf_dev *acdev = (struct arasan_cf_dev *) dev;
+       struct arasan_cf_dev *acdev = dev;
 
        complete(&acdev->dma_completion);
 }
index 1581dee2967a80368976303fc9e7865b1e69cef2..3aa4e655e3c64cb5a81f3759f5638e2eb003c5df 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index d63ee8f41a4f29e9c0bc9209236c97ca47259ab5..e9c87274a781551d4496ac81b213855dd766ae41 100644 (file)
@@ -18,7 +18,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/gfp.h>
 #include <scsi/scsi_host.h>
index 24e51056ac26a857c1db028b9eb71450a0608d45..30fa4ca4cef65607493a1e8fd1e5fe6bf13b5bbb 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 2ca5026f2c150f9e83b37e48e8227e944a18253f..7e73a0f1e3237698b2b7afcd70207655e53dc2d3 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index 8fb69e5ca1b7f08be8ef7a635acdf8122765f577..57f1be64dbf239e8c631687ea5b5c28f1c1b5577 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/gfp.h>
index 1275a8d4dedc06940cbce5660d24136d27aea0ef..6bca3505b9e9d5431d537e2fdf2fbcae917e76c6 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index f10baabbf5db5ae2f266aed4f7559d258962f267..bcde4b786807079126aed18744edbbf972a86d3c 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index f07f2296acdcf5c986a0c33bd423736268f42c33..8afe854a5a50c24abeb2c9f96966264d09c0f8bc 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 997e16a3a63f6154373d33854fed1c1532ee657f..2c0986fa4bb2ccd8efc1d2ead606c05e6d734ae1 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 0448860a2077526cea30354fc60b6c6c3cacada9..32ddcae5a360a387b010db88cf951287ab219bd6 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/libata.h>
index 810bc9964ddec6a12a72ca50206b7b67039c1183..3435bd6a5cc918984ba7aee85cfc8e4435e7106c 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 3c12fd7acd4126c256a3c87822b744c77af4a43b..f440892225f4d220603759f196cd2b5ca155a87f 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index 980b88e109fcf5109e164d155dfca86de735c2c2..cad9d45749c419e51dbdf852fe67ee998796938b 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/err.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <scsi/scsi_host.h>
 #include <linux/ata.h>
index 35b521348d311fbb7b2921618e348661a57edfb6..8e76f79689d371bd96fbd2f276d53ab265edc026 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index a9d74eff5fc4b159367b1f8f03d7aa842e331dba..3ba843f5cdc0f91a789e536b876a0b4bb292e645 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 4be0398c153d36b448cc5f23199514a48c8cc35b..b93c0f0729e7676e9e4b78d9611d3547ed8350b9 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 85cf2861e0b7d217eaabd6ffa446a6446de84c72..255c5aaff3a81e8c3ddce32dca7ba49a6dd0cf1d 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index b0b18ec5465ffe32bae62d11f97d1b0cba8c313c..e0872db913d65d1f120a753ac2f313162add41dd 100644 (file)
@@ -15,7 +15,6 @@
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <scsi/scsi_host.h>
 #include <linux/ata.h>
@@ -100,13 +99,9 @@ static int pata_imx_probe(struct platform_device *pdev)
        struct resource *io_res;
        int ret;
 
-       io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (io_res == NULL)
-               return -EINVAL;
-
        irq = platform_get_irq(pdev, 0);
-       if (irq <= 0)
-               return -EINVAL;
+       if (irq < 0)
+               return irq;
 
        priv = devm_kzalloc(&pdev->dev,
                                sizeof(struct pata_imx_priv), GFP_KERNEL);
@@ -136,11 +131,10 @@ static int pata_imx_probe(struct platform_device *pdev)
        ap->pio_mask = ATA_PIO0;
        ap->flags |= ATA_FLAG_SLAVE_POSS;
 
-       priv->host_regs = devm_ioremap(&pdev->dev, io_res->start,
-               resource_size(io_res));
-       if (!priv->host_regs) {
-               dev_err(&pdev->dev, "failed to map IO/CTL base\n");
-               ret = -EBUSY;
+       io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       priv->host_regs = devm_ioremap_resource(&pdev->dev, io_res);
+       if (IS_ERR(priv->host_regs)) {
+               ret = PTR_ERR(priv->host_regs);
                goto err;
        }
 
index 2a8dd9527eccd4d435b65f7532091520cd5de40b..81369d187a5cb8f9e8e7d40158741533486d19a5 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index 581e04d80367a9690c22513aaba376bf7dff643f..dc3d7877f29d7898a11780595e27cabb01d53a7e 100644 (file)
@@ -72,7 +72,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
index 76e739b031b6a3a15c036b082bcb8ba8d4f1ad06..b1cfa0258fd38017337e345b5095677a50567133 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index be816428b430fbb73135ef1591bbde2219097221..bce2a8ca4678ace5375b6a0f90699481b8ff9659 100644 (file)
@@ -916,7 +916,6 @@ static __init int probe_chip_type(struct legacy_probe *probe)
                        local_irq_restore(flags);
                        return BIOS;
                }
-               local_irq_restore(flags);
        }
 
        if (ht6560a & mask)
index a4f5e781c8c237dd794588b0bc0c050216763ce0..6bad3df3a13c7741095ac7e88c80d7d7e75d98c4 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index 1f5f28bb0bb8082c5cb66dcb714af3fec6bed5e2..f39a5379e8165a0adf8e59f3fa34412822724289 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index ad1a0febd6207dc08521c245a8e650f30e149dff..e3b97093ef9a3cc60aa5a904bc39e7c31f2546b7 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index 9513e071040da8f148dc63a6b2aca8f7d7018a83..56201a69af127322e0070b3f4b18c8a0d0355cec 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 0c424dae56e7e13a686bdf062baadcbb422d8fe6..6154c3ee11a5b32d94fd065e0b5abbf8c0109c79 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 16dc3a63a23d5f763b28c92d7fcc9170d0e2320e..d44df7ccfe43930fa51354ce4dab57545bb381f9 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index d77b2e1054efc25cf8207ec6b963ce853427255f..319b64491b7b504fd1fb67350d16e8374fd6cecf 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index 4ea70cd22aee8fc70a75f9bfb5696122fee2bd32..fb042e0519d00f780d4a642e4b8a3e27bdec0d11 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 78ede3fd187559360d246cb8f52439fdbd2364ad..bb71ea214b9902ee63258acefaefc795bf18bbc8 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 40254f4df584f781100476dbd391941148042fc8..bcc4b968c0497cb74ec005c433a993054fe42273 100644 (file)
@@ -26,7 +26,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
index 9d874c85d64d7f5eb7f5d4c44fe785e8aa1c555a..1151f23177bb803df56a20fbc30be6032e382598 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index c34fc50070a6382fc48f9c428557c9f9bca5ee9b..defa050e17843d26db5ef685e8c4263fc64eb23b 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 2beb6b5045f8fd224e1f535c20254caa99aa9540..0b46be11705169b0cb8150d2a3792be72caae3c2 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 02794885de10be8329003300d19c2f8084ff9032..a5579b55e3329ee395cfbddd30eb034711e0aab1 100644 (file)
@@ -13,7 +13,6 @@
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <scsi/scsi_host.h>
 #include <linux/ata.h>
index a6f05acad61ed01d68b0ec201698a8abc406cf44..73259bfda1e364e5e99b89aec1a6ae99400f6297 100644 (file)
@@ -20,7 +20,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/ata.h>
 #include <linux/libata.h>
index f582ba180a7d6e3c799a788f86c477ed43f36660..be3f10240dca4961f80d34437acaac78298dbea1 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index 79a970f05a2e2bb54d60fcfa92211596f41791ec..521b2137ea3e39ccccb35cb78810316bebc26b72 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index 040b093617a4ada5ffa76c61c2d20615644d5b35..caedc90855b2fdb931f39018b31f3d9f7b0effff 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index ce2f828c17b30f4ff5fa831c933d3174c6136d5d..96a232fffae6089ddfa77b8981e04115700e872a 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index f35f15f4d83e30288abf6506e9802c66f969ace7..f1f5b5ae33826356230f2689996c34065afb3f7a 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index d3830c45a369cd611ba99ff78bac235c5fc4e258..5a1cde0ea3601818456b44b51c0cc059ece726e0 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index 96c6a79ef6066af0171b74864134f34a05ebb611..e27f31fe1b67b93a3c6c326be0d434a26d8d056a 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index c4b0b073ba8e8c7d13512a2c6930b987ba1a4745..73fe362d97161dffcb75a514c41b65fb9a5baf0b 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 1e8363640bf5e7bd16a065ce0222c161b745e459..78d913aa93c812f8eae1ccd572ad1c7ea1dfd22a 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index 6816911ac4229ba8e7dc46829cd2da9461015ef5..900f0e4a1faf61462b20f37b8b29176d194a17e0 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 94473da68c02d9664906f8c5c82a0f395d881d63..7bc78e264f9eda5cd4cd7eabc4a2acf6dae9bb7e 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index c3ab9a6c3965b1c8df7045da6f6a1a10f414ca9b..f6c9632bdff6a11c6fbdcc18d7ff703d1c4b20cc 100644 (file)
@@ -55,7 +55,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/gfp.h>
index 8ea6e6afd041db7736e6a69c88641253fa4b4078..f10631beffa87cd258950bb4c85778ce166205e0 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/module.h>
 #include <linux/gfp.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index 523524b68022d3710f342d96f54926014de551ae..0bb2cabd2197bba01c0b4dd175f662a353eba076 100644 (file)
@@ -29,7 +29,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/device.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
@@ -462,8 +461,7 @@ static irqreturn_t dma_dwc_interrupt(int irq, void *hsdev_instance)
        int chan;
        u32 tfr_reg, err_reg;
        unsigned long flags;
-       struct sata_dwc_device *hsdev =
-               (struct sata_dwc_device *)hsdev_instance;
+       struct sata_dwc_device *hsdev = hsdev_instance;
        struct ata_host *host = (struct ata_host *)hsdev->host;
        struct ata_port *ap;
        struct sata_dwc_device_port *hsdevp;
index 870b11eadc6d793d3abcebdcc6bb72c4cc326f45..65965cf5af06ba94c8c77ebfcf01ca584f81d0be 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/kernel.h>
 #include <linux/gfp.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/types.h>
 #include <linux/err.h>
 #include <linux/io.h>
@@ -142,7 +141,7 @@ static ssize_t ecx_transmit_led_message(struct ata_port *ap, u32 state,
                                        ssize_t size)
 {
        struct ahci_host_priv *hpriv =  ap->host->private_data;
-       struct ecx_plat_data *pdata = (struct ecx_plat_data *) hpriv->plat_data;
+       struct ecx_plat_data *pdata = hpriv->plat_data;
        struct ahci_port_priv *pp = ap->private_data;
        unsigned long flags;
        int pmp, i;
@@ -403,6 +402,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
        static const unsigned long timing[] = { 5, 100, 500};
        struct ata_port *ap = link->ap;
        struct ahci_port_priv *pp = ap->private_data;
+       struct ahci_host_priv *hpriv = ap->host->private_data;
        u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
        struct ata_taskfile tf;
        bool online;
@@ -431,7 +431,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
                        break;
        } while (!online && retry--);
 
-       ahci_start_engine(ap);
+       hpriv->start_engine(ap);
 
        if (online)
                *class = ahci_dev_classify(ap);
index d74def823d3ed865be0841d771fb7141ac1c1a07..ba5f27120332fe5b2e15d553cb7a7bc25aaa7a44 100644 (file)
@@ -40,7 +40,6 @@
 #include <linux/module.h>
 #include <linux/gfp.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index 97f4acb54ad626795972ffb8e35572101d05d08d..3638887476f610a933d57b29cae7f84c4d6f229f 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/module.h>
 #include <linux/gfp.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index 3b0dd57984e18370f5a659907c1c3326aed6fb49..9a6bd4cd29a0661cefd71f686e7c4bbc778911ed 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/module.h>
 #include <linux/gfp.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index b7695e804635b87c0d7c787be1d900facaa68963..3062f8605b2955956bff191d6034530ce7fbd636 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index 1ad2f62d34b98fd0b41be9a239827e1634327c54..b513428171b3592a4033e597ec593a7e4189ab21 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index dc4f70179e7d37470dc358b02c96b328d8bbeeae..c630fa81262439939c3ad770f3538e48c0862522 100644 (file)
@@ -39,7 +39,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index 9947010afc0f7973e2af77664f6ef39e53840358..39b5de60a1f96a93a80193b5a7ce8ec6e0ecea43 100644 (file)
@@ -82,7 +82,6 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -1021,8 +1020,7 @@ static void pdc20621_get_from_dimm(struct ata_host *host, void *psource,
        idx++;
        dist = ((long) (window_size - (offset + size))) >= 0 ? size :
                (long) (window_size - offset);
-       memcpy_fromio((char *) psource, (char *) (dimm_mmio + offset / 4),
-                     dist);
+       memcpy_fromio(psource, dimm_mmio + offset / 4, dist);
 
        psource += dist;
        size -= dist;
@@ -1031,8 +1029,7 @@ static void pdc20621_get_from_dimm(struct ata_host *host, void *psource,
                readl(mmio + PDC_GENERAL_CTLR);
                writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
                readl(mmio + PDC_DIMM_WINDOW_CTLR);
-               memcpy_fromio((char *) psource, (char *) (dimm_mmio),
-                             window_size / 4);
+               memcpy_fromio(psource, dimm_mmio, window_size / 4);
                psource += window_size;
                size -= window_size;
                idx++;
@@ -1043,8 +1040,7 @@ static void pdc20621_get_from_dimm(struct ata_host *host, void *psource,
                readl(mmio + PDC_GENERAL_CTLR);
                writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
                readl(mmio + PDC_DIMM_WINDOW_CTLR);
-               memcpy_fromio((char *) psource, (char *) (dimm_mmio),
-                             size / 4);
+               memcpy_fromio(psource, dimm_mmio, size / 4);
        }
 }
 #endif
index 6d6489118873fe50bd4f04a0cc3320e5eae5747c..08f98c3ed5c8e28f89d45ec467f3dec69f28d204 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/module.h>
 #include <linux/gfp.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index 87f056e54a9d7566504925ca812347baf6b3e62f..f72e84228c5c10e05db80755df5a64efd5606b38 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index 44f304b3de63c6ee45fa87f88793e900359ac1be..29e847aac34be5ea88871ff03c99856b20c4492e 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index d2895836f9fa4c00fec1a46d993074ecb3edeaea..766098af4eb79aebf8f080b6906db8aeade896e7 100644 (file)
@@ -700,46 +700,26 @@ void sas_probe_sata(struct asd_sas_port *port)
 
 }
 
-static bool sas_ata_flush_pm_eh(struct asd_sas_port *port, const char *func)
+static void sas_ata_flush_pm_eh(struct asd_sas_port *port, const char *func)
 {
        struct domain_device *dev, *n;
-       bool retry = false;
 
        list_for_each_entry_safe(dev, n, &port->dev_list, dev_list_node) {
-               int rc;
-
                if (!dev_is_sata(dev))
                        continue;
 
                sas_ata_wait_eh(dev);
-               rc = dev->sata_dev.pm_result;
-               if (rc == -EAGAIN)
-                       retry = true;
-               else if (rc) {
-                       /* since we don't have a
-                        * ->port_{suspend|resume} routine in our
-                        *  ata_port ops, and no entanglements with
-                        *  acpi, suspend should just be mechanical trip
-                        *  through eh, catch cases where these
-                        *  assumptions are invalidated
-                        */
-                       WARN_ONCE(1, "failed %s %s error: %d\n", func,
-                                dev_name(&dev->rphy->dev), rc);
-               }
 
                /* if libata failed to power manage the device, tear it down */
                if (ata_dev_disabled(sas_to_ata_dev(dev)))
                        sas_fail_probe(dev, func, -ENODEV);
        }
-
-       return retry;
 }
 
 void sas_suspend_sata(struct asd_sas_port *port)
 {
        struct domain_device *dev;
 
- retry:
        mutex_lock(&port->ha->disco_mutex);
        list_for_each_entry(dev, &port->dev_list, dev_list_node) {
                struct sata_device *sata;
@@ -751,20 +731,17 @@ void sas_suspend_sata(struct asd_sas_port *port)
                if (sata->ap->pm_mesg.event == PM_EVENT_SUSPEND)
                        continue;
 
-               sata->pm_result = -EIO;
-               ata_sas_port_async_suspend(sata->ap, &sata->pm_result);
+               ata_sas_port_suspend(sata->ap);
        }
        mutex_unlock(&port->ha->disco_mutex);
 
-       if (sas_ata_flush_pm_eh(port, __func__))
-               goto retry;
+       sas_ata_flush_pm_eh(port, __func__);
 }
 
 void sas_resume_sata(struct asd_sas_port *port)
 {
        struct domain_device *dev;
 
- retry:
        mutex_lock(&port->ha->disco_mutex);
        list_for_each_entry(dev, &port->dev_list, dev_list_node) {
                struct sata_device *sata;
@@ -776,13 +753,11 @@ void sas_resume_sata(struct asd_sas_port *port)
                if (sata->ap->pm_mesg.event == PM_EVENT_ON)
                        continue;
 
-               sata->pm_result = -EIO;
-               ata_sas_port_async_resume(sata->ap, &sata->pm_result);
+               ata_sas_port_resume(sata->ap);
        }
        mutex_unlock(&port->ha->disco_mutex);
 
-       if (sas_ata_flush_pm_eh(port, __func__))
-               goto retry;
+       sas_ata_flush_pm_eh(port, __func__);
 }
 
 /**
index 73a25005d88aa7cc76f7e8049b9697be18955c39..1f16d502600c5d887dbb54fea12440bd7bf9692a 100644 (file)
 
 struct device;
 struct ata_port_info;
+struct ahci_host_priv;
+struct platform_device;
 
+/*
+ * Note ahci_platform_data is deprecated, it is only kept around for use
+ * by the old da850 and spear13xx ahci code.
+ * New drivers should instead declare their own platform_driver struct, and
+ * use ahci_platform* functions in their own probe, suspend and resume methods.
+ */
 struct ahci_platform_data {
        int (*init)(struct device *dev, void __iomem *addr);
        void (*exit)(struct device *dev);
        int (*suspend)(struct device *dev);
        int (*resume)(struct device *dev);
-       const struct ata_port_info *ata_port_info;
-       unsigned int force_port_map;
-       unsigned int mask_port_map;
 };
 
+int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
+void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
+int ahci_platform_enable_resources(struct ahci_host_priv *hpriv);
+void ahci_platform_disable_resources(struct ahci_host_priv *hpriv);
+struct ahci_host_priv *ahci_platform_get_resources(
+       struct platform_device *pdev);
+int ahci_platform_init_host(struct platform_device *pdev,
+                           struct ahci_host_priv *hpriv,
+                           const struct ata_port_info *pi_template,
+                           unsigned int force_port_map,
+                           unsigned int mask_port_map);
+
+int ahci_platform_suspend_host(struct device *dev);
+int ahci_platform_resume_host(struct device *dev);
+int ahci_platform_suspend(struct device *dev);
+int ahci_platform_resume(struct device *dev);
+
 #endif /* _AHCI_PLATFORM_H */
index bec6dbe939a0267def1f73864d07c5025cb687f1..1de36be64df4d1516a2a451901733d36fd32ec4e 100644 (file)
@@ -848,7 +848,6 @@ struct ata_port {
        struct completion       park_req_pending;
 
        pm_message_t            pm_mesg;
-       int                     *pm_result;
        enum ata_lpm_policy     target_lpm_policy;
 
        struct timer_list       fastdrain_timer;
@@ -1140,16 +1139,14 @@ extern bool ata_link_offline(struct ata_link *link);
 #ifdef CONFIG_PM
 extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg);
 extern void ata_host_resume(struct ata_host *host);
-extern int ata_sas_port_async_suspend(struct ata_port *ap, int *async);
-extern int ata_sas_port_async_resume(struct ata_port *ap, int *async);
+extern void ata_sas_port_suspend(struct ata_port *ap);
+extern void ata_sas_port_resume(struct ata_port *ap);
 #else
-static inline int ata_sas_port_async_suspend(struct ata_port *ap, int *async)
+static inline void ata_sas_port_suspend(struct ata_port *ap)
 {
-       return 0;
 }
-static inline int ata_sas_port_async_resume(struct ata_port *ap, int *async)
+static inline void ata_sas_port_resume(struct ata_port *ap)
 {
-       return 0;
 }
 #endif
 extern int ata_ratelimit(void);
index f843dd8722a97eb9ca7106c6e09f8dd43a6e903c..ef7872c20da9e5f2d16c5a950b0abd0d9e9e53b2 100644 (file)
@@ -172,7 +172,6 @@ struct sata_device {
         enum   ata_command_set command_set;
         struct smp_resp        rps_resp; /* report_phy_sata_resp */
         u8     port_no;        /* port number, if this is a PM (Port) */
-       int    pm_result;
 
        struct ata_port *ap;
        struct ata_host ata_host;