1
0
Fork 0

Merge branch 'for-3.15' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata

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
  ...
hifive-unleashed-5.1
Linus Torvalds 2014-03-31 15:27:37 -07:00
commit 01d5f3b598
92 changed files with 2351 additions and 938 deletions

View 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>;
};

View File

@ -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";
};

View 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),

View 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);
}

View File

@ -176,6 +176,87 @@
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 {
@ -187,5 +268,76 @@
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";
};
};
};

View 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.

View 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

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

View 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

View 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;

View File

@ -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");

View 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,288 +52,32 @@ 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;
}
if (imxpriv->type == AHCI_IMX6Q) {
regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
IMX6Q_GPR13_SATA_MPLL_CLK_EN,
IMX6Q_GPR13_SATA_MPLL_CLK_EN);
}
usleep_range(1000, 2000);
return 0;
clk_err:
if (imxpriv->type == AHCI_IMX53)
clk_disable_unprepare(imxpriv->sata_gate_clk);
return ret;
}
static void imx_sata_clock_disable(struct device *dev)
{
struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
if (imxpriv->type == AHCI_IMX6Q) {
regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
IMX6Q_GPR13_SATA_MPLL_CLK_EN,
!IMX6Q_GPR13_SATA_MPLL_CLK_EN);
}
clk_disable_unprepare(imxpriv->sata_ref_clk);
if (imxpriv->type == AHCI_IMX53)
clk_disable_unprepare(imxpriv->sata_gate_clk);
}
static void ahci_imx_error_handler(struct ata_port *ap)
{
u32 reg_val;
struct ata_device *dev;
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);
ahci_error_handler(ap);
if (!(imxpriv->first_time) || ahci_imx_hotplug)
return;
imxpriv->first_time = false;
ata_for_each_dev(dev, &ap->link, ENABLED)
return;
/*
* Disable link to save power. An imx ahci port can't be recovered
* without full reset once the pddq mode is enabled making it
* impossible to use as part of libata LPM.
*/
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);
imxpriv->no_device = true;
}
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);
int ret = -EIO;
if (imxpriv->type == AHCI_IMX53)
ret = ahci_pmp_retry_srst_ops.softreset(link, class, deadline);
else if (imxpriv->type == AHCI_IMX6Q)
ret = ahci_ops.softreset(link, class, deadline);
return ret;
}
static struct ata_port_operations ahci_imx_ops = {
.inherits = &ahci_platform_ops,
.error_handler = ahci_imx_error_handler,
.softreset = ahci_imx_softreset,
};
static const struct ata_port_info ahci_imx_port_info = {
.flags = AHCI_FLAG_COMMON,
.pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.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);
ret = ahci_platform_enable_clks(hpriv);
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 },
{},
};
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 imx_ahci_priv *imxpriv;
struct device *ahci_dev;
struct platform_device *ahci_pdev;
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");
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->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;
}
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;
}
}
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;
}
imxpriv->ahci_pdev = ahci_pdev;
platform_set_drvdata(pdev, imxpriv);
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;
}
res[0] = *mem;
res[1] = *irq;
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;
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;
}
goto disable_regulator;
if (imxpriv->type == AHCI_IMX6Q) {
/*
* Set PHY Paremeters, two steps to configure the GPR13,
* 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().
* 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 |
@ -360,42 +98,229 @@ static int imx_ahci_probe(struct platform_device *pdev)
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);
}
ret = platform_device_add_resources(ahci_pdev, res, 2);
if (ret)
goto err_out;
ret = platform_device_add_data(ahci_pdev, pdata, sizeof(*pdata));
if (ret)
goto err_out;
ret = platform_device_add(ahci_pdev);
if (ret) {
err_out:
platform_device_put(ahci_pdev);
return ret;
}
usleep_range(1000, 2000);
return 0;
disable_regulator:
if (hpriv->target_pwr)
regulator_disable(hpriv->target_pwr);
return ret;
}
static int imx_ahci_remove(struct platform_device *pdev)
static void imx_sata_disable(struct ahci_host_priv *hpriv)
{
struct imx_ahci_priv *imxpriv = platform_get_drvdata(pdev);
struct platform_device *ahci_pdev = imxpriv->ahci_pdev;
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,
IMX6Q_GPR13_SATA_MPLL_CLK_EN,
!IMX6Q_GPR13_SATA_MPLL_CLK_EN);
}
ahci_platform_disable_clks(hpriv);
if (hpriv->target_pwr)
regulator_disable(hpriv->target_pwr);
}
static void ahci_imx_error_handler(struct ata_port *ap)
{
u32 reg_val;
struct ata_device *dev;
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 = hpriv->plat_data;
ahci_error_handler(ap);
if (!(imxpriv->first_time) || ahci_imx_hotplug)
return;
imxpriv->first_time = false;
ata_for_each_dev(dev, &ap->link, ENABLED)
return;
/*
* Disable link to save power. An imx ahci port can't be recovered
* without full reset once the pddq mode is enabled making it
* impossible to use as part of libata LPM.
*/
reg_val = readl(mmio + PORT_PHY_CTL);
writel(reg_val | PORT_PHY_CTL_PDDQ_LOC, mmio + PORT_PHY_CTL);
imx_sata_disable(hpriv);
imxpriv->no_device = true;
}
static int ahci_imx_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
struct ata_port *ap = link->ap;
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)
ret = ahci_pmp_retry_srst_ops.softreset(link, class, deadline);
else if (imxpriv->type == AHCI_IMX6Q)
ret = ahci_ops.softreset(link, class, deadline);
return ret;
}
static struct ata_port_operations ahci_imx_ops = {
.inherits = &ahci_ops,
.host_stop = ahci_imx_host_stop,
.error_handler = ahci_imx_error_handler,
.softreset = ahci_imx_softreset,
};
static const struct ata_port_info ahci_imx_port_info = {
.flags = AHCI_FLAG_COMMON,
.pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_imx_ops,
};
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 },
{},
};
MODULE_DEVICE_TABLE(of, imx_ahci_of_match);
static int imx_ahci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct of_device_id *of_id;
struct ahci_host_priv *hpriv;
struct imx_ahci_priv *imxpriv;
unsigned int reg_val;
int ret;
of_id = of_match_device(imx_ahci_of_match, dev);
if (!of_id)
return -EINVAL;
imxpriv = devm_kzalloc(dev, sizeof(*imxpriv), GFP_KERNEL);
if (!imxpriv)
return -ENOMEM;
imxpriv->no_device = false;
imxpriv->first_time = true;
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");
return PTR_ERR(imxpriv->ahb_clk);
}
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);
}
}
hpriv = ahci_platform_get_resources(pdev);
if (IS_ERR(hpriv))
return PTR_ERR(hpriv);
hpriv->plat_data = imxpriv;
ret = imx_sata_enable(hpriv);
if (ret)
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(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);
}
reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
writel(reg_val, hpriv->mmio + HOST_TIMER1MS);
ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info, 0, 0);
if (ret)
imx_sata_disable(hpriv);
return ret;
}
static void ahci_imx_host_stop(struct ata_host *host)
{
struct ahci_host_priv *hpriv = host->private_data;
imx_sata_disable(hpriv);
}
#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 = ahci_platform_suspend_host(dev);
if (ret)
return ret;
imx_sata_disable(hpriv);
platform_device_unregister(ahci_pdev);
return 0;
}
static int imx_ahci_resume(struct device *dev)
{
struct ata_host *host = dev_get_drvdata(dev);
struct ahci_host_priv *hpriv = host->private_data;
int ret;
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);

View File

@ -12,135 +12,36 @@
* 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;
}
hpriv = ahci_platform_get_resources(pdev);
if (IS_ERR(hpriv))
return PTR_ERR(hpriv);
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->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;
goto disable_resources;
}
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;
}
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);
disable_resources:
ahci_platform_disable_resources(hpriv);
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);
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);

View File

@ -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");

View File

@ -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");

View File

@ -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");

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

View 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)

View File

@ -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");

View 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;
}

View 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)
{
ata_port_request_pm(ap, mesg, 0, ata_port_suspend_ehi, true);
}
static int ata_port_pm_suspend(struct device *dev)
{
struct ata_port *ap = to_ata_port(dev);
return __ata_port_suspend_common(ap, mesg, NULL);
}
static int ata_port_suspend(struct device *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)
{
if (pm_runtime_suspended(dev))
return 0;
return ata_port_suspend_common(dev, PMSG_FREEZE);
}
static int ata_port_poweroff(struct device *dev)
{
return ata_port_suspend_common(dev, PMSG_HIBERNATE);
}
static int __ata_port_resume_common(struct ata_port *ap, pm_message_t mesg,
int *async)
{
int rc;
rc = ata_port_request_pm(ap, mesg, ATA_EH_RESET,
ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, async);
return rc;
}
static int ata_port_resume_common(struct device *dev, pm_message_t mesg)
static int ata_port_pm_freeze(struct device *dev)
{
struct ata_port *ap = to_ata_port(dev);
return __ata_port_resume_common(ap, mesg, NULL);
if (pm_runtime_suspended(dev))
return 0;
ata_port_suspend(ap, PMSG_FREEZE);
return 0;
}
static int ata_port_resume(struct device *dev)
static int ata_port_pm_poweroff(struct device *dev)
{
int rc;
ata_port_suspend(to_ata_port(dev), PMSG_HIBERNATE);
return 0;
}
rc = ata_port_resume_common(dev, PMSG_RESUME);
if (!rc) {
pm_runtime_disable(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
}
static const unsigned int ata_port_resume_ehi = ATA_EHI_NO_AUTOPSY
| ATA_EHI_QUIET;
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 void ata_port_resume_async(struct ata_port *ap, pm_message_t mesg)
{
ata_port_request_pm(ap, mesg, ATA_EH_RESET, ata_port_resume_ehi, true);
}
static int ata_port_pm_resume(struct device *dev)
{
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

View 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 */

View 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);

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

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

View 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);
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

View 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;
}

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

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

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

View 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)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

View 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;

View 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);

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

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

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

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

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

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

View 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

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

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

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

View 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__);
}
/**

View File

@ -19,15 +19,37 @@
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 */

View 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);

View 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;