summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-04-03 17:42:25 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2018-04-03 17:42:25 -0700
commita23867f1d2de572f84b459651dfe99fa9e79fadf (patch)
treeae3cecc903408653646986aa03b5361ef5ae1204 /drivers
parentef1c4a6fa91bbbe9b09f770d28eba31a9edf770c (diff)
parent027fa4dee935d25cef5994af1b8864eb00dcffac (diff)
Merge branch 'for-4.17' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata
Pull libata updates from Tejun Heo: "Nothing too interesting. The biggest change is refcnting fix for ata_host - the bug is recent and can only be triggered on controller hotplug, so very few are hitting it. There also are a number of trivial license / error message changes and some hardware specific changes" * 'for-4.17' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata: (23 commits) ahci: imx: add the imx8qm ahci sata support libata: ensure host is free'd on error exit paths ata: ahci-platform: add reset control support ahci: imx: fix the build warning ata: add Amiga Gayle PATA controller driver ahci: imx: add the imx6qp ahci sata support ata: change Tegra124 to Tegra ata: ahci_tegra: Add AHCI support for Tegra210 ata: ahci_tegra: disable DIPM ata: ahci_tegra: disable devslp for Tegra124 ata: ahci_tegra: initialize regulators from soc struct ata: ahci_tegra: Update initialization sequence dt-bindings: Tegra210: add binding documentation libata: add refcounting to ata_host pata_bk3710: clarify license version and use SPDX header pata_falcon: clarify license version and use SPDX header pata_it821x: Delete an error message for a failed memory allocation in it821x_firmware_command() pata_macio: Delete an error message for a failed memory allocation in two functions pata_mpc52xx: Delete an error message for a failed memory allocation in mpc52xx_ata_probe() sata_dwc_460ex: Delete an error message for a failed memory allocation in sata_dwc_port_start() ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ata/Kconfig16
-rw-r--r--drivers/ata/Makefile1
-rw-r--r--drivers/ata/ahci.h1
-rw-r--r--drivers/ata/ahci_imx.c371
-rw-r--r--drivers/ata/ahci_tegra.c359
-rw-r--r--drivers/ata/libahci_platform.c24
-rw-r--r--drivers/ata/libata-core.c46
-rw-r--r--drivers/ata/libata-transport.c4
-rw-r--r--drivers/ata/libata.h2
-rw-r--r--drivers/ata/pata_arasan_cf.c6
-rw-r--r--drivers/ata/pata_bk3710.c8
-rw-r--r--drivers/ata/pata_falcon.c8
-rw-r--r--drivers/ata/pata_gayle.c219
-rw-r--r--drivers/ata/pata_it821x.c6
-rw-r--r--drivers/ata/pata_macio.c12
-rw-r--r--drivers/ata/pata_mpc52xx.c1
-rw-r--r--drivers/ata/pata_samsung_cf.c4
-rw-r--r--drivers/ata/sata_dwc_460ex.c1
18 files changed, 966 insertions, 123 deletions
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 4582fa27cf37..2b16e7c8fff3 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -211,10 +211,10 @@ config AHCI_SUNXI
If unsure, say N.
config AHCI_TEGRA
- tristate "NVIDIA Tegra124 AHCI SATA support"
+ tristate "NVIDIA Tegra AHCI SATA support"
depends on ARCH_TEGRA
help
- This option enables support for the NVIDIA Tegra124 SoC's
+ This option enables support for the NVIDIA Tegra SoC's
onboard AHCI SATA.
If unsure, say N.
@@ -954,6 +954,18 @@ config PATA_FALCON
If unsure, say N.
+config PATA_GAYLE
+ tristate "Amiga Gayle PATA support"
+ depends on M68K && AMIGA
+ help
+ This option enables support for the on-board IDE
+ interfaces on some Amiga models (A600, A1200,
+ A4000 and A4000T) and also for IDE interfaces on
+ the Zorro expansion bus (M-Tech E-Matrix 530
+ expansion card).
+
+ If unsure, say N.
+
config PATA_ISAPNP
tristate "ISA Plug and Play PATA support"
depends on ISAPNP
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 6dae8c985e8e..d21cdd83f7ab 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -97,6 +97,7 @@ obj-$(CONFIG_PATA_WINBOND) += pata_sl82c105.o
# SFF PIO only
obj-$(CONFIG_PATA_CMD640_PCI) += pata_cmd640.o
obj-$(CONFIG_PATA_FALCON) += pata_falcon.o
+obj-$(CONFIG_PATA_GAYLE) += pata_gayle.o
obj-$(CONFIG_PATA_ISAPNP) += pata_isapnp.o
obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o
obj-$(CONFIG_PATA_MPIIX) += pata_mpiix.o
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index a9d996e17d75..4356ef1d28a8 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -350,6 +350,7 @@ struct ahci_host_priv {
u32 em_msg_type; /* EM message type */
bool got_runtime_pm; /* Did we do pm_runtime_get? */
struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
+ struct reset_control *rsts; /* Optional */
struct regulator **target_pwrs; /* Optional */
/*
* If platform uses PHYs. There is a 1:1 relation between the port number and
diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c
index a58bcc069c54..6822e2f33f7e 100644
--- a/drivers/ata/ahci_imx.c
+++ b/drivers/ata/ahci_imx.c
@@ -23,6 +23,7 @@
#include <linux/regmap.h>
#include <linux/ahci_platform.h>
#include <linux/of_device.h>
+#include <linux/of_gpio.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include <linux/libata.h>
@@ -53,11 +54,49 @@ enum {
/* Clock Reset Register */
IMX_CLOCK_RESET = 0x7f3f,
IMX_CLOCK_RESET_RESET = 1 << 0,
+ /* IMX8QM HSIO AHCI definitions */
+ IMX8QM_SATA_PHY_RX_IMPED_RATIO_OFFSET = 0x03,
+ IMX8QM_SATA_PHY_TX_IMPED_RATIO_OFFSET = 0x09,
+ IMX8QM_SATA_PHY_IMPED_RATIO_85OHM = 0x6c,
+ IMX8QM_LPCG_PHYX2_OFFSET = 0x00000,
+ IMX8QM_CSR_PHYX2_OFFSET = 0x90000,
+ IMX8QM_CSR_PHYX1_OFFSET = 0xa0000,
+ IMX8QM_CSR_PHYX_STTS0_OFFSET = 0x4,
+ IMX8QM_CSR_PCIEA_OFFSET = 0xb0000,
+ IMX8QM_CSR_PCIEB_OFFSET = 0xc0000,
+ IMX8QM_CSR_SATA_OFFSET = 0xd0000,
+ IMX8QM_CSR_PCIE_CTRL2_OFFSET = 0x8,
+ IMX8QM_CSR_MISC_OFFSET = 0xe0000,
+
+ IMX8QM_LPCG_PHYX2_PCLK0_MASK = (0x3 << 16),
+ IMX8QM_LPCG_PHYX2_PCLK1_MASK = (0x3 << 20),
+ IMX8QM_PHY_APB_RSTN_0 = BIT(0),
+ IMX8QM_PHY_MODE_SATA = BIT(19),
+ IMX8QM_PHY_MODE_MASK = (0xf << 17),
+ IMX8QM_PHY_PIPE_RSTN_0 = BIT(24),
+ IMX8QM_PHY_PIPE_RSTN_OVERRIDE_0 = BIT(25),
+ IMX8QM_PHY_PIPE_RSTN_1 = BIT(26),
+ IMX8QM_PHY_PIPE_RSTN_OVERRIDE_1 = BIT(27),
+ IMX8QM_STTS0_LANE0_TX_PLL_LOCK = BIT(4),
+ IMX8QM_MISC_IOB_RXENA = BIT(0),
+ IMX8QM_MISC_IOB_TXENA = BIT(1),
+ IMX8QM_MISC_PHYX1_EPCS_SEL = BIT(12),
+ IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_1 = BIT(24),
+ IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_0 = BIT(25),
+ IMX8QM_MISC_CLKREQN_IN_OVERRIDE_1 = BIT(28),
+ IMX8QM_MISC_CLKREQN_IN_OVERRIDE_0 = BIT(29),
+ IMX8QM_SATA_CTRL_RESET_N = BIT(12),
+ IMX8QM_SATA_CTRL_EPCS_PHYRESET_N = BIT(7),
+ IMX8QM_CTRL_BUTTON_RST_N = BIT(21),
+ IMX8QM_CTRL_POWER_UP_RST_N = BIT(23),
+ IMX8QM_CTRL_LTSSM_ENABLE = BIT(4),
};
enum ahci_imx_type {
AHCI_IMX53,
AHCI_IMX6Q,
+ AHCI_IMX6QP,
+ AHCI_IMX8QM,
};
struct imx_ahci_priv {
@@ -66,10 +105,18 @@ struct imx_ahci_priv {
struct clk *sata_clk;
struct clk *sata_ref_clk;
struct clk *ahb_clk;
+ struct clk *epcs_tx_clk;
+ struct clk *epcs_rx_clk;
+ struct clk *phy_apbclk;
+ struct clk *phy_pclk0;
+ struct clk *phy_pclk1;
+ void __iomem *phy_base;
+ int clkreq_gpio;
struct regmap *gpr;
bool no_device;
bool first_time;
u32 phy_params;
+ u32 imped_ratio;
};
static int ahci_imx_hotplug;
@@ -188,11 +235,26 @@ static int imx_phy_reg_read(u16 *val, void __iomem *mmio)
static int imx_sata_phy_reset(struct ahci_host_priv *hpriv)
{
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
void __iomem *mmio = hpriv->mmio;
int timeout = 10;
u16 val;
int ret;
+ if (imxpriv->type == AHCI_IMX6QP) {
+ /* 6qp adds the sata reset mechanism, use it for 6qp sata */
+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR5,
+ IMX6Q_GPR5_SATA_SW_PD, 0);
+
+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR5,
+ IMX6Q_GPR5_SATA_SW_RST, 0);
+ udelay(50);
+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR5,
+ IMX6Q_GPR5_SATA_SW_RST,
+ IMX6Q_GPR5_SATA_SW_RST);
+ return 0;
+ }
+
/* Reset SATA PHY by setting RESET bit of PHY register CLOCK_RESET */
ret = imx_phy_reg_addressing(IMX_CLOCK_RESET, mmio);
if (ret)
@@ -391,6 +453,207 @@ static struct attribute *fsl_sata_ahci_attrs[] = {
};
ATTRIBUTE_GROUPS(fsl_sata_ahci);
+static int imx8_sata_enable(struct ahci_host_priv *hpriv)
+{
+ u32 val, reg;
+ int i, ret;
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
+ struct device *dev = &imxpriv->ahci_pdev->dev;
+
+ /* configure the hsio for sata */
+ ret = clk_prepare_enable(imxpriv->phy_pclk0);
+ if (ret < 0) {
+ dev_err(dev, "can't enable phy_pclk0.\n");
+ return ret;
+ }
+ ret = clk_prepare_enable(imxpriv->phy_pclk1);
+ if (ret < 0) {
+ dev_err(dev, "can't enable phy_pclk1.\n");
+ goto disable_phy_pclk0;
+ }
+ ret = clk_prepare_enable(imxpriv->epcs_tx_clk);
+ if (ret < 0) {
+ dev_err(dev, "can't enable epcs_tx_clk.\n");
+ goto disable_phy_pclk1;
+ }
+ ret = clk_prepare_enable(imxpriv->epcs_rx_clk);
+ if (ret < 0) {
+ dev_err(dev, "can't enable epcs_rx_clk.\n");
+ goto disable_epcs_tx_clk;
+ }
+ ret = clk_prepare_enable(imxpriv->phy_apbclk);
+ if (ret < 0) {
+ dev_err(dev, "can't enable phy_apbclk.\n");
+ goto disable_epcs_rx_clk;
+ }
+ /* Configure PHYx2 PIPE_RSTN */
+ regmap_read(imxpriv->gpr, IMX8QM_CSR_PCIEA_OFFSET +
+ IMX8QM_CSR_PCIE_CTRL2_OFFSET, &val);
+ if ((val & IMX8QM_CTRL_LTSSM_ENABLE) == 0) {
+ /* The link of the PCIEA of HSIO is down */
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_PHYX2_OFFSET,
+ IMX8QM_PHY_PIPE_RSTN_0 |
+ IMX8QM_PHY_PIPE_RSTN_OVERRIDE_0,
+ IMX8QM_PHY_PIPE_RSTN_0 |
+ IMX8QM_PHY_PIPE_RSTN_OVERRIDE_0);
+ }
+ regmap_read(imxpriv->gpr, IMX8QM_CSR_PCIEB_OFFSET +
+ IMX8QM_CSR_PCIE_CTRL2_OFFSET, &reg);
+ if ((reg & IMX8QM_CTRL_LTSSM_ENABLE) == 0) {
+ /* The link of the PCIEB of HSIO is down */
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_PHYX2_OFFSET,
+ IMX8QM_PHY_PIPE_RSTN_1 |
+ IMX8QM_PHY_PIPE_RSTN_OVERRIDE_1,
+ IMX8QM_PHY_PIPE_RSTN_1 |
+ IMX8QM_PHY_PIPE_RSTN_OVERRIDE_1);
+ }
+ if (((reg | val) & IMX8QM_CTRL_LTSSM_ENABLE) == 0) {
+ /* The links of both PCIA and PCIEB of HSIO are down */
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_LPCG_PHYX2_OFFSET,
+ IMX8QM_LPCG_PHYX2_PCLK0_MASK |
+ IMX8QM_LPCG_PHYX2_PCLK1_MASK,
+ 0);
+ }
+
+ /* set PWR_RST and BT_RST of csr_pciea */
+ val = IMX8QM_CSR_PCIEA_OFFSET + IMX8QM_CSR_PCIE_CTRL2_OFFSET;
+ regmap_update_bits(imxpriv->gpr,
+ val,
+ IMX8QM_CTRL_BUTTON_RST_N,
+ IMX8QM_CTRL_BUTTON_RST_N);
+ regmap_update_bits(imxpriv->gpr,
+ val,
+ IMX8QM_CTRL_POWER_UP_RST_N,
+ IMX8QM_CTRL_POWER_UP_RST_N);
+
+ /* PHYX1_MODE to SATA */
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_PHYX1_OFFSET,
+ IMX8QM_PHY_MODE_MASK,
+ IMX8QM_PHY_MODE_SATA);
+
+ /*
+ * BIT0 RXENA 1, BIT1 TXENA 0
+ * BIT12 PHY_X1_EPCS_SEL 1.
+ */
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_MISC_OFFSET,
+ IMX8QM_MISC_IOB_RXENA,
+ IMX8QM_MISC_IOB_RXENA);
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_MISC_OFFSET,
+ IMX8QM_MISC_IOB_TXENA,
+ 0);
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_MISC_OFFSET,
+ IMX8QM_MISC_PHYX1_EPCS_SEL,
+ IMX8QM_MISC_PHYX1_EPCS_SEL);
+ /*
+ * It is possible, for PCIe and SATA are sharing
+ * the same clock source, HPLL or external oscillator.
+ * When PCIe is in low power modes (L1.X or L2 etc),
+ * the clock source can be turned off. In this case,
+ * if this clock source is required to be toggling by
+ * SATA, then SATA functions will be abnormal.
+ * Set the override here to avoid it.
+ */
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_MISC_OFFSET,
+ IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_1 |
+ IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_0 |
+ IMX8QM_MISC_CLKREQN_IN_OVERRIDE_1 |
+ IMX8QM_MISC_CLKREQN_IN_OVERRIDE_0,
+ IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_1 |
+ IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_0 |
+ IMX8QM_MISC_CLKREQN_IN_OVERRIDE_1 |
+ IMX8QM_MISC_CLKREQN_IN_OVERRIDE_0);
+
+ /* clear PHY RST, then set it */
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_SATA_OFFSET,
+ IMX8QM_SATA_CTRL_EPCS_PHYRESET_N,
+ 0);
+
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_SATA_OFFSET,
+ IMX8QM_SATA_CTRL_EPCS_PHYRESET_N,
+ IMX8QM_SATA_CTRL_EPCS_PHYRESET_N);
+
+ /* CTRL RST: SET -> delay 1 us -> CLEAR -> SET */
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_SATA_OFFSET,
+ IMX8QM_SATA_CTRL_RESET_N,
+ IMX8QM_SATA_CTRL_RESET_N);
+ udelay(1);
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_SATA_OFFSET,
+ IMX8QM_SATA_CTRL_RESET_N,
+ 0);
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_SATA_OFFSET,
+ IMX8QM_SATA_CTRL_RESET_N,
+ IMX8QM_SATA_CTRL_RESET_N);
+
+ /* APB reset */
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_PHYX1_OFFSET,
+ IMX8QM_PHY_APB_RSTN_0,
+ IMX8QM_PHY_APB_RSTN_0);
+
+ for (i = 0; i < 100; i++) {
+ reg = IMX8QM_CSR_PHYX1_OFFSET +
+ IMX8QM_CSR_PHYX_STTS0_OFFSET;
+ regmap_read(imxpriv->gpr, reg, &val);
+ val &= IMX8QM_STTS0_LANE0_TX_PLL_LOCK;
+ if (val == IMX8QM_STTS0_LANE0_TX_PLL_LOCK)
+ break;
+ udelay(1);
+ }
+
+ if (val != IMX8QM_STTS0_LANE0_TX_PLL_LOCK) {
+ dev_err(dev, "TX PLL of the PHY is not locked\n");
+ ret = -ENODEV;
+ } else {
+ writeb(imxpriv->imped_ratio, imxpriv->phy_base +
+ IMX8QM_SATA_PHY_RX_IMPED_RATIO_OFFSET);
+ writeb(imxpriv->imped_ratio, imxpriv->phy_base +
+ IMX8QM_SATA_PHY_TX_IMPED_RATIO_OFFSET);
+ reg = readb(imxpriv->phy_base +
+ IMX8QM_SATA_PHY_RX_IMPED_RATIO_OFFSET);
+ if (unlikely(reg != imxpriv->imped_ratio))
+ dev_info(dev, "Can't set PHY RX impedance ratio.\n");
+ reg = readb(imxpriv->phy_base +
+ IMX8QM_SATA_PHY_TX_IMPED_RATIO_OFFSET);
+ if (unlikely(reg != imxpriv->imped_ratio))
+ dev_info(dev, "Can't set PHY TX impedance ratio.\n");
+ usleep_range(50, 100);
+
+ /*
+ * To reduce the power consumption, gate off
+ * the PHY clks
+ */
+ clk_disable_unprepare(imxpriv->phy_apbclk);
+ clk_disable_unprepare(imxpriv->phy_pclk1);
+ clk_disable_unprepare(imxpriv->phy_pclk0);
+ return ret;
+ }
+
+ clk_disable_unprepare(imxpriv->phy_apbclk);
+disable_epcs_rx_clk:
+ clk_disable_unprepare(imxpriv->epcs_rx_clk);
+disable_epcs_tx_clk:
+ clk_disable_unprepare(imxpriv->epcs_tx_clk);
+disable_phy_pclk1:
+ clk_disable_unprepare(imxpriv->phy_pclk1);
+disable_phy_pclk0:
+ clk_disable_unprepare(imxpriv->phy_pclk0);
+
+ return ret;
+}
+
static int imx_sata_enable(struct ahci_host_priv *hpriv)
{
struct imx_ahci_priv *imxpriv = hpriv->plat_data;
@@ -408,7 +671,7 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv)
if (ret < 0)
goto disable_regulator;
- if (imxpriv->type == AHCI_IMX6Q) {
+ if (imxpriv->type == AHCI_IMX6Q || imxpriv->type == AHCI_IMX6QP) {
/*
* set PHY Paremeters, two steps to configure the GPR13,
* one write for rest of parameters, mask of first write
@@ -438,6 +701,8 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv)
dev_err(dev, "failed to reset phy: %d\n", ret);
goto disable_clk;
}
+ } else if (imxpriv->type == AHCI_IMX8QM) {
+ ret = imx8_sata_enable(hpriv);
}
usleep_range(1000, 2000);
@@ -459,10 +724,29 @@ static void imx_sata_disable(struct ahci_host_priv *hpriv)
if (imxpriv->no_device)
return;
- if (imxpriv->type == AHCI_IMX6Q) {
+ switch (imxpriv->type) {
+ case AHCI_IMX6QP:
+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR5,
+ IMX6Q_GPR5_SATA_SW_PD,
+ IMX6Q_GPR5_SATA_SW_PD);
regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
IMX6Q_GPR13_SATA_MPLL_CLK_EN,
!IMX6Q_GPR13_SATA_MPLL_CLK_EN);
+ break;
+
+ case AHCI_IMX6Q:
+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
+ IMX6Q_GPR13_SATA_MPLL_CLK_EN,
+ !IMX6Q_GPR13_SATA_MPLL_CLK_EN);
+ break;
+
+ case AHCI_IMX8QM:
+ clk_disable_unprepare(imxpriv->epcs_rx_clk);
+ clk_disable_unprepare(imxpriv->epcs_tx_clk);
+ break;
+
+ default:
+ break;
}
clk_disable_unprepare(imxpriv->sata_ref_clk);
@@ -513,7 +797,7 @@ static int ahci_imx_softreset(struct ata_link *link, unsigned int *class,
if (imxpriv->type == AHCI_IMX53)
ret = ahci_pmp_retry_srst_ops.softreset(link, class, deadline);
- else if (imxpriv->type == AHCI_IMX6Q)
+ else
ret = ahci_ops.softreset(link, class, deadline);
return ret;
@@ -536,6 +820,8 @@ static const struct ata_port_info ahci_imx_port_info = {
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 },
+ { .compatible = "fsl,imx6qp-ahci", .data = (void *)AHCI_IMX6QP },
+ { .compatible = "fsl,imx8qm-ahci", .data = (void *)AHCI_IMX8QM },
{},
};
MODULE_DEVICE_TABLE(of, imx_ahci_of_match);
@@ -703,6 +989,79 @@ static struct scsi_host_template ahci_platform_sht = {
AHCI_SHT(DRV_NAME),
};
+static int imx8_sata_probe(struct device *dev, struct imx_ahci_priv *imxpriv)
+{
+ int ret;
+ struct resource *phy_res;
+ struct platform_device *pdev = imxpriv->ahci_pdev;
+ struct device_node *np = dev->of_node;
+
+ if (of_property_read_u32(np, "fsl,phy-imp", &imxpriv->imped_ratio))
+ imxpriv->imped_ratio = IMX8QM_SATA_PHY_IMPED_RATIO_85OHM;
+ phy_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy");
+ if (phy_res) {
+ imxpriv->phy_base = devm_ioremap(dev, phy_res->start,
+ resource_size(phy_res));
+ if (!imxpriv->phy_base) {
+ dev_err(dev, "error with ioremap\n");
+ return -ENOMEM;
+ }
+ } else {
+ dev_err(dev, "missing *phy* reg region.\n");
+ return -ENOMEM;
+ }
+ imxpriv->gpr =
+ syscon_regmap_lookup_by_phandle(np, "hsio");
+ if (IS_ERR(imxpriv->gpr)) {
+ dev_err(dev, "unable to find gpr registers\n");
+ return PTR_ERR(imxpriv->gpr);
+ }
+
+ imxpriv->epcs_tx_clk = devm_clk_get(dev, "epcs_tx");
+ if (IS_ERR(imxpriv->epcs_tx_clk)) {
+ dev_err(dev, "can't get epcs_tx_clk clock.\n");
+ return PTR_ERR(imxpriv->epcs_tx_clk);
+ }
+ imxpriv->epcs_rx_clk = devm_clk_get(dev, "epcs_rx");
+ if (IS_ERR(imxpriv->epcs_rx_clk)) {
+ dev_err(dev, "can't get epcs_rx_clk clock.\n");
+ return PTR_ERR(imxpriv->epcs_rx_clk);
+ }
+ imxpriv->phy_pclk0 = devm_clk_get(dev, "phy_pclk0");
+ if (IS_ERR(imxpriv->phy_pclk0)) {
+ dev_err(dev, "can't get phy_pclk0 clock.\n");
+ return PTR_ERR(imxpriv->phy_pclk0);
+ }
+ imxpriv->phy_pclk1 = devm_clk_get(dev, "phy_pclk1");
+ if (IS_ERR(imxpriv->phy_pclk1)) {
+ dev_err(dev, "can't get phy_pclk1 clock.\n");
+ return PTR_ERR(imxpriv->phy_pclk1);
+ }
+ imxpriv->phy_apbclk = devm_clk_get(dev, "phy_apbclk");
+ if (IS_ERR(imxpriv->phy_apbclk)) {
+ dev_err(dev, "can't get phy_apbclk clock.\n");
+ return PTR_ERR(imxpriv->phy_apbclk);
+ }
+
+ /* Fetch GPIO, then enable the external OSC */
+ imxpriv->clkreq_gpio = of_get_named_gpio(np, "clkreq-gpio", 0);
+ if (gpio_is_valid(imxpriv->clkreq_gpio)) {
+ ret = devm_gpio_request_one(dev, imxpriv->clkreq_gpio,
+ GPIOF_OUT_INIT_LOW,
+ "SATA CLKREQ");
+ if (ret == -EBUSY) {
+ dev_info(dev, "clkreq had been initialized.\n");
+ } else if (ret) {
+ dev_err(dev, "%d unable to get clkreq.\n", ret);
+ return ret;
+ }
+ } else if (imxpriv->clkreq_gpio == -EPROBE_DEFER) {
+ return imxpriv->clkreq_gpio;
+ }
+
+ return 0;
+}
+
static int imx_ahci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -743,7 +1102,7 @@ static int imx_ahci_probe(struct platform_device *pdev)
return PTR_ERR(imxpriv->ahb_clk);
}
- if (imxpriv->type == AHCI_IMX6Q) {
+ if (imxpriv->type == AHCI_IMX6Q || imxpriv->type == AHCI_IMX6QP) {
u32 reg_value;
imxpriv->gpr = syscon_regmap_lookup_by_compatible(
@@ -762,6 +1121,10 @@ static int imx_ahci_probe(struct platform_device *pdev)
IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F |
IMX6Q_GPR13_SATA_SPD_MODE_3P0G |
reg_value;
+ } else if (imxpriv->type == AHCI_IMX8QM) {
+ ret = imx8_sata_probe(dev, imxpriv);
+ if (ret)
+ return ret;
}
hpriv = ahci_platform_get_resources(pdev);
diff --git a/drivers/ata/ahci_tegra.c b/drivers/ata/ahci_tegra.c
index 3a62eb246d80..64d848409fe2 100644
--- a/drivers/ata/ahci_tegra.c
+++ b/drivers/ata/ahci_tegra.c
@@ -34,7 +34,8 @@
#define DRV_NAME "tegra-ahci"
#define SATA_CONFIGURATION_0 0x180
-#define SATA_CONFIGURATION_EN_FPCI BIT(0)
+#define SATA_CONFIGURATION_0_EN_FPCI BIT(0)
+#define SATA_CONFIGURATION_0_CLK_OVERRIDE BIT(31)
#define SCFG_OFFSET 0x1000
@@ -45,17 +46,55 @@
#define T_SATA0_CFG_1_SERR BIT(8)
#define T_SATA0_CFG_9 0x24
-#define T_SATA0_CFG_9_BASE_ADDRESS_SHIFT 13
+#define T_SATA0_CFG_9_BASE_ADDRESS 0x40020000
#define SATA_FPCI_BAR5 0x94
-#define SATA_FPCI_BAR5_START_SHIFT 4
+#define SATA_FPCI_BAR5_START_MASK (0xfffffff << 4)
+#define SATA_FPCI_BAR5_START (0x0040020 << 4)
+#define SATA_FPCI_BAR5_ACCESS_TYPE (0x1)
#define SATA_INTR_MASK 0x188
#define SATA_INTR_MASK_IP_INT_MASK BIT(16)
+#define T_SATA0_CFG_35 0x94
+#define T_SATA0_CFG_35_IDP_INDEX_MASK (0x7ff << 2)
+#define T_SATA0_CFG_35_IDP_INDEX (0x2a << 2)
+
+#define T_SATA0_AHCI_IDP1 0x98
+#define T_SATA0_AHCI_IDP1_DATA (0x400040)
+
+#define T_SATA0_CFG_PHY_1 0x12c
+#define T_SATA0_CFG_PHY_1_PADS_IDDQ_EN BIT(23)
+#define T_SATA0_CFG_PHY_1_PAD_PLL_IDDQ_EN BIT(22)
+
+#define T_SATA0_NVOOB 0x114
+#define T_SATA0_NVOOB_COMMA_CNT_MASK (0xff << 16)
+#define T_SATA0_NVOOB_COMMA_CNT (0x07 << 16)
+#define T_SATA0_NVOOB_SQUELCH_FILTER_MODE_MASK (0x3 << 24)
+#define T_SATA0_NVOOB_SQUELCH_FILTER_MODE (0x1 << 24)
+#define T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH_MASK (0x3 << 26)
+#define T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH (0x3 << 26)
+
+#define T_SATA_CFG_PHY_0 0x120
+#define T_SATA_CFG_PHY_0_USE_7BIT_ALIGN_DET_FOR_SPD BIT(11)
+#define T_SATA_CFG_PHY_0_MASK_SQUELCH BIT(24)
+
+#define T_SATA0_CFG2NVOOB_2 0x134
+#define T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW_MASK (0x1ff << 18)
+#define T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW (0xc << 18)
+
#define T_SATA0_AHCI_HBA_CAP_BKDR 0x300
+#define T_SATA0_AHCI_HBA_CAP_BKDR_PARTIAL_ST_CAP BIT(13)
+#define T_SATA0_AHCI_HBA_CAP_BKDR_SLUMBER_ST_CAP BIT(14)
+#define T_SATA0_AHCI_HBA_CAP_BKDR_SALP BIT(26)
+#define T_SATA0_AHCI_HBA_CAP_BKDR_SUPP_PM BIT(17)
+#define T_SATA0_AHCI_HBA_CAP_BKDR_SNCQ BIT(30)
#define T_SATA0_BKDOOR_CC 0x4a4
+#define T_SATA0_BKDOOR_CC_CLASS_CODE_MASK (0xffff << 16)
+#define T_SATA0_BKDOOR_CC_CLASS_CODE (0x0106 << 16)
+#define T_SATA0_BKDOOR_CC_PROG_IF_MASK (0xff << 8)
+#define T_SATA0_BKDOOR_CC_PROG_IF (0x01 << 8)
#define T_SATA0_CFG_SATA 0x54c
#define T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN BIT(12)
@@ -82,6 +121,27 @@
#define T_SATA0_CHX_PHY_CTRL11 0x6d0
#define T_SATA0_CHX_PHY_CTRL11_GEN2_RX_EQ (0x2800 << 16)
+#define T_SATA0_CHX_PHY_CTRL17_0 0x6e8
+#define T_SATA0_CHX_PHY_CTRL17_0_RX_EQ_CTRL_L_GEN1 0x55010000
+#define T_SATA0_CHX_PHY_CTRL18_0 0x6ec
+#define T_SATA0_CHX_PHY_CTRL18_0_RX_EQ_CTRL_L_GEN2 0x55010000
+#define T_SATA0_CHX_PHY_CTRL20_0 0x6f4
+#define T_SATA0_CHX_PHY_CTRL20_0_RX_EQ_CTRL_H_GEN1 0x1
+#define T_SATA0_CHX_PHY_CTRL21_0 0x6f8
+#define T_SATA0_CHX_PHY_CTRL21_0_RX_EQ_CTRL_H_GEN2 0x1
+
+/* AUX Registers */
+#define SATA_AUX_MISC_CNTL_1_0 0x8
+#define SATA_AUX_MISC_CNTL_1_0_DEVSLP_OVERRIDE BIT(17)
+#define SATA_AUX_MISC_CNTL_1_0_SDS_SUPPORT BIT(13)
+#define SATA_AUX_MISC_CNTL_1_0_DESO_SUPPORT BIT(15)
+
+#define SATA_AUX_RX_STAT_INT_0 0xc
+#define SATA_AUX_RX_STAT_INT_0_SATA_DEVSLP BIT(7)
+
+#define SATA_AUX_SPARE_CFG0_0 0x18
+#define SATA_AUX_SPARE_CFG0_0_MDAT_TIMER_AFTER_PG_VALID BIT(14)
+
#define FUSE_SATA_CALIB 0x124
#define FUSE_SATA_CALIB_MASK 0x3
@@ -99,23 +159,92 @@ static const struct sata_pad_calibration tegra124_pad_calibration[] = {
{0x14, 0x0e, 0x1a, 0x0e},
};
+struct tegra_ahci_ops {
+ int (*init)(struct ahci_host_priv *hpriv);
+};
+
+struct tegra_ahci_soc {
+ const char *const *supply_names;
+ u32 num_supplies;
+ bool supports_devslp;
+ const struct tegra_ahci_ops *ops;
+};
+
struct tegra_ahci_priv {
struct platform_device *pdev;
void __iomem *sata_regs;
+ void __iomem *sata_aux_regs;
struct reset_control *sata_rst;
struct reset_control *sata_oob_rst;
struct reset_control *sata_cold_rst;
/* Needs special handling, cannot use ahci_platform */
struct clk *sata_clk;
- struct regulator_bulk_data supplies[5];
+ struct regulator_bulk_data *supplies;
+ const struct tegra_ahci_soc *soc;
};
+static void tegra_ahci_handle_quirks(struct ahci_host_priv *hpriv)
+{
+ struct tegra_ahci_priv *tegra = hpriv->plat_data;
+ u32 val;
+
+ if (tegra->sata_aux_regs && !tegra->soc->supports_devslp) {
+ val = readl(tegra->sata_aux_regs + SATA_AUX_MISC_CNTL_1_0);
+ val &= ~SATA_AUX_MISC_CNTL_1_0_SDS_SUPPORT;
+ writel(val, tegra->sata_aux_regs + SATA_AUX_MISC_CNTL_1_0);
+ }
+}
+
+static int tegra124_ahci_init(struct ahci_host_priv *hpriv)
+{
+ struct tegra_ahci_priv *tegra = hpriv->plat_data;
+ struct sata_pad_calibration calib;
+ int ret;
+ u32 val;
+
+ /* Pad calibration */
+ ret = tegra_fuse_readl(FUSE_SATA_CALIB, &val);
+ if (ret)
+ return ret;
+
+ calib = tegra124_pad_calibration[val & FUSE_SATA_CALIB_MASK];
+
+ writel(BIT(0), tegra->sata_regs + SCFG_OFFSET + T_SATA0_INDEX);
+
+ val = readl(tegra->sata_regs +
+ SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN1);
+ val &= ~T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_MASK;
+ val &= ~T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_MASK;
+ val |= calib.gen1_tx_amp << T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT;
+ val |= calib.gen1_tx_peak << T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT;
+ writel(val, tegra->sata_regs + SCFG_OFFSET +
+ T_SATA0_CHX_PHY_CTRL1_GEN1);
+
+ val = readl(tegra->sata_regs +
+ SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN2);
+ val &= ~T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_MASK;
+ val &= ~T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_MASK;
+ val |= calib.gen2_tx_amp << T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT;
+ val |= calib.gen2_tx_peak << T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT;
+ writel(val, tegra->sata_regs + SCFG_OFFSET +
+ T_SATA0_CHX_PHY_CTRL1_GEN2);
+
+ writel(T_SATA0_CHX_PHY_CTRL11_GEN2_RX_EQ,
+ tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL11);
+ writel(T_SATA0_CHX_PHY_CTRL2_CDR_CNTL_GEN1,
+ tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL2);
+
+ writel(0, tegra->sata_regs + SCFG_OFFSET + T_SATA0_INDEX);
+
+ return 0;
+}
+
static int tegra_ahci_power_on(struct ahci_host_priv *hpriv)
{
struct tegra_ahci_priv *tegra = hpriv->plat_data;
int ret;
- ret = regulator_bulk_enable(ARRAY_SIZE(tegra->supplies),
+ ret = regulator_bulk_enable(tegra->soc->num_supplies,
tegra->supplies);
if (ret)
return ret;
@@ -144,7 +273,7 @@ disable_power:
tegra_powergate_power_off(TEGRA_POWERGATE_SATA);
disable_regulators:
- regulator_bulk_disable(ARRAY_SIZE(tegra->supplies), tegra->supplies);
+ regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies);
return ret;
}
@@ -162,15 +291,14 @@ static void tegra_ahci_power_off(struct ahci_host_priv *hpriv)
clk_disable_unprepare(tegra->sata_clk);
tegra_powergate_power_off(TEGRA_POWERGATE_SATA);
- regulator_bulk_disable(ARRAY_SIZE(tegra->supplies), tegra->supplies);
+ regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies);
}
static int tegra_ahci_controller_init(struct ahci_host_priv *hpriv)
{
struct tegra_ahci_priv *tegra = hpriv->plat_data;
int ret;
- unsigned int val;
- struct sata_pad_calibration calib;
+ u32 val;
ret = tegra_ahci_power_on(hpriv);
if (ret) {
@@ -179,78 +307,115 @@ static int tegra_ahci_controller_init(struct ahci_host_priv *hpriv)
return ret;
}
+ /*
+ * Program the following SATA IPFS registers to allow SW accesses to
+ * SATA's MMIO register range.
+ */
+ val = readl(tegra->sata_regs + SATA_FPCI_BAR5);
+ val &= ~(SATA_FPCI_BAR5_START_MASK | SATA_FPCI_BAR5_ACCESS_TYPE);
+ val |= SATA_FPCI_BAR5_START | SATA_FPCI_BAR5_ACCESS_TYPE;
+ writel(val, tegra->sata_regs + SATA_FPCI_BAR5);
+
+ /* Program the following SATA IPFS register to enable the SATA */
val = readl(tegra->sata_regs + SATA_CONFIGURATION_0);
- val |= SATA_CONFIGURATION_EN_FPCI;
+ val |= SATA_CONFIGURATION_0_EN_FPCI;
writel(val, tegra->sata_regs + SATA_CONFIGURATION_0);
- /* Pad calibration */
-
- ret = tegra_fuse_readl(FUSE_SATA_CALIB, &val);
- if (ret) {
- dev_err(&tegra->pdev->dev,
- "failed to read calibration fuse: %d\n", ret);
- return ret;
- }
-
- calib = tegra124_pad_calibration[val & FUSE_SATA_CALIB_MASK];
-
- writel(BIT(0), tegra->sata_regs + SCFG_OFFSET + T_SATA0_INDEX);
-
- val = readl(tegra->sata_regs +
- SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN1);
- val &= ~T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_MASK;
- val &= ~T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_MASK;
- val |= calib.gen1_tx_amp <<
- T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT;
- val |= calib.gen1_tx_peak <<
- T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT;
- writel(val, tegra->sata_regs + SCFG_OFFSET +
- T_SATA0_CHX_PHY_CTRL1_GEN1);
-
- val = readl(tegra->sata_regs +
- SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN2);
- val &= ~T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_MASK;
- val &= ~T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_MASK;
- val |= calib.gen2_tx_amp <<
- T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT;
- val |= calib.gen2_tx_peak <<
- T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT;
- writel(val, tegra->sata_regs + SCFG_OFFSET +
- T_SATA0_CHX_PHY_CTRL1_GEN2);
-
- writel(T_SATA0_CHX_PHY_CTRL11_GEN2_RX_EQ,
- tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL11);
- writel(T_SATA0_CHX_PHY_CTRL2_CDR_CNTL_GEN1,
- tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL2);
-
- writel(0, tegra->sata_regs + SCFG_OFFSET + T_SATA0_INDEX);
-
- /* Program controller device ID */
+ /* Electrical settings for better link stability */
+ val = T_SATA0_CHX_PHY_CTRL17_0_RX_EQ_CTRL_L_GEN1;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL17_0);
+ val = T_SATA0_CHX_PHY_CTRL18_0_RX_EQ_CTRL_L_GEN2;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL18_0);
+ val = T_SATA0_CHX_PHY_CTRL20_0_RX_EQ_CTRL_H_GEN1;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL20_0);
+ val = T_SATA0_CHX_PHY_CTRL21_0_RX_EQ_CTRL_H_GEN2;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL21_0);
+
+ /* For SQUELCH Filter & Gen3 drive getting detected as Gen1 drive */
+
+ val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA_CFG_PHY_0);
+ val |= T_SATA_CFG_PHY_0_MASK_SQUELCH;
+ val &= ~T_SATA_CFG_PHY_0_USE_7BIT_ALIGN_DET_FOR_SPD;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA_CFG_PHY_0);
+
+ val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_NVOOB);
+ val &= ~(T_SATA0_NVOOB_COMMA_CNT_MASK |
+ T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH_MASK |
+ T_SATA0_NVOOB_SQUELCH_FILTER_MODE_MASK);
+ val |= (T_SATA0_NVOOB_COMMA_CNT |
+ T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH |
+ T_SATA0_NVOOB_SQUELCH_FILTER_MODE);
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_NVOOB);
+
+ /*
+ * Change CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW from 83.3 ns to 58.8ns
+ */
+ val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG2NVOOB_2);
+ val &= ~T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW_MASK;
+ val |= T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG2NVOOB_2);
+
+ if (tegra->soc->ops && tegra->soc->ops->init)
+ tegra->soc->ops->init(hpriv);
+
+ /*
+ * Program the following SATA configuration registers to
+ * initialize SATA
+ */
+ val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_1);
+ val |= (T_SATA0_CFG_1_IO_SPACE | T_SATA0_CFG_1_MEMORY_SPACE |
+ T_SATA0_CFG_1_BUS_MASTER | T_SATA0_CFG_1_SERR);
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_1);
+ val = T_SATA0_CFG_9_BASE_ADDRESS;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_9);
+ /* Program Class Code and Programming interface for SATA */
val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA);
val |= T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN;
writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA);
- writel(0x01060100, tegra->sata_regs + SCFG_OFFSET + T_SATA0_BKDOOR_CC);
+ val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_BKDOOR_CC);
+ val &=
+ ~(T_SATA0_BKDOOR_CC_CLASS_CODE_MASK |
+ T_SATA0_BKDOOR_CC_PROG_IF_MASK);
+ val |= T_SATA0_BKDOOR_CC_CLASS_CODE | T_SATA0_BKDOOR_CC_PROG_IF;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_BKDOOR_CC);
val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA);
val &= ~T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN;
writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA);
- /* Enable IO & memory access, bus master mode */
-
- val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_1);
- val |= T_SATA0_CFG_1_IO_SPACE | T_SATA0_CFG_1_MEMORY_SPACE |
- T_SATA0_CFG_1_BUS_MASTER | T_SATA0_CFG_1_SERR;
- writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_1);
-
- /* Program SATA MMIO */
-
- writel(0x10000 << SATA_FPCI_BAR5_START_SHIFT,
- tegra->sata_regs + SATA_FPCI_BAR5);
+ /* Enabling LPM capabilities through Backdoor Programming */
+ val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_AHCI_HBA_CAP_BKDR);
+ val |= (T_SATA0_AHCI_HBA_CAP_BKDR_PARTIAL_ST_CAP |
+ T_SATA0_AHCI_HBA_CAP_BKDR_SLUMBER_ST_CAP |
+ T_SATA0_AHCI_HBA_CAP_BKDR_SALP |
+ T_SATA0_AHCI_HBA_CAP_BKDR_SUPP_PM);
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_AHCI_HBA_CAP_BKDR);
+
+ /* SATA Second Level Clock Gating configuration
+ * Enabling Gating of Tx/Rx clocks and driving Pad IDDQ and Lane
+ * IDDQ Signals
+ */
+ val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_35);
+ val &= ~T_SATA0_CFG_35_IDP_INDEX_MASK;
+ val |= T_SATA0_CFG_35_IDP_INDEX;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_35);
+
+ val = T_SATA0_AHCI_IDP1_DATA;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_AHCI_IDP1);
+
+ val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_PHY_1);
+ val |= (T_SATA0_CFG_PHY_1_PADS_IDDQ_EN |
+ T_SATA0_CFG_PHY_1_PAD_PLL_IDDQ_EN);
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_PHY_1);
+
+ /* Enabling IPFS Clock Gating */
+ val = readl(tegra->sata_regs + SATA_CONFIGURATION_0);
+ val &= ~SATA_CONFIGURATION_0_CLK_OVERRIDE;
+ writel(val, tegra->sata_regs + SATA_CONFIGURATION_0);
- writel(0x08000 << T_SATA0_CFG_9_BASE_ADDRESS_SHIFT,
- tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_9);
+ tegra_ahci_handle_quirks(hpriv);
/* Unmask SATA interrupts */
@@ -279,14 +444,40 @@ static struct ata_port_operations ahci_tegra_port_ops = {
};
static const struct ata_port_info ahci_tegra_port_info = {
- .flags = AHCI_FLAG_COMMON,
+ .flags = AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM,
.pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_tegra_port_ops,
};
+static const char *const tegra124_supply_names[] = {
+ "avdd", "hvdd", "vddio", "target-5v", "target-12v"
+};
+
+static const struct tegra_ahci_ops tegra124_ahci_ops = {
+ .init = tegra124_ahci_init,
+};
+
+static const struct tegra_ahci_soc tegra124_ahci_soc = {
+ .supply_names = tegra124_supply_names,
+ .num_supplies = ARRAY_SIZE(tegra124_supply_names),
+ .supports_devslp = false,
+ .ops = &tegra124_ahci_ops,
+};
+
+static const struct tegra_ahci_soc tegra210_ahci_soc = {
+ .supports_devslp = false,
+};
+
static const struct of_device_id tegra_ahci_of_match[] = {
- { .compatible = "nvidia,tegra124-ahci" },
+ {
+ .compatible = "nvidia,tegra124-ahci",
+ .data = &tegra124_ahci_soc
+ },
+ {
+ .compatible = "nvidia,tegra210-ahci",
+ .data = &tegra210_ahci_soc
+ },
{}
};
MODULE_DEVICE_TABLE(of, tegra_ahci_of_match);
@@ -301,6 +492,7 @@ static int tegra_ahci_probe(struct platform_device *pdev)
struct tegra_ahci_priv *tegra;
struct resource *res;
int ret;
+ unsigned int i;
hpriv = ahci_platform_get_resources(pdev);
if (IS_ERR(hpriv))
@@ -313,12 +505,23 @@ static int tegra_ahci_probe(struct platform_device *pdev)
hpriv->plat_data = tegra;
tegra->pdev = pdev;
+ tegra->soc = of_device_get_match_data(&pdev->dev);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
tegra->sata_regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(tegra->sata_regs))
return PTR_ERR(tegra->sata_regs);
+ /*
+ * AUX registers is optional.
+ */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ if (res) {
+ tegra->sata_aux_regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(tegra->sata_aux_regs))
+ return PTR_ERR(tegra->sata_aux_regs);
+ }
+
tegra->sata_rst = devm_reset_control_get(&pdev->dev, "sata");
if (IS_ERR(tegra->sata_rst)) {
dev_err(&pdev->dev, "Failed to get sata reset\n");
@@ -343,13 +546,17 @@ static int tegra_ahci_probe(struct platform_device *pdev)
return PTR_ERR(tegra->sata_clk);
}
- tegra->supplies[0].supply = "avdd";
- tegra->supplies[1].supply = "hvdd";
- tegra->supplies[2].supply = "vddio";
- tegra->supplies[3].supply = "target-5v";
- tegra->supplies[4].supply = "target-12v";
+ tegra->supplies = devm_kcalloc(&pdev->dev,
+ tegra->soc->num_supplies,
+ sizeof(*tegra->supplies), GFP_KERNEL);
+ if (!tegra->supplies)
+ return -ENOMEM;
+
+ for (i = 0; i < tegra->soc->num_supplies; i++)
+ tegra->supplies[i].supply = tegra->soc->supply_names[i];
- ret = devm_regulator_bulk_get(&pdev->dev, ARRAY_SIZE(tegra->supplies),
+ ret = devm_regulator_bulk_get(&pdev->dev,
+ tegra->soc->num_supplies,
tegra->supplies);
if (ret) {
dev_err(&pdev->dev, "Failed to get regulators\n");
@@ -385,5 +592,5 @@ static struct platform_driver tegra_ahci_driver = {
module_platform_driver(tegra_ahci_driver);
MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>");
-MODULE_DESCRIPTION("Tegra124 AHCI SATA driver");
+MODULE_DESCRIPTION("Tegra AHCI SATA driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
index 30cc8f1a31e1..46a762442dc5 100644
--- a/drivers/ata/libahci_platform.c
+++ b/drivers/ata/libahci_platform.c
@@ -25,6 +25,7 @@
#include <linux/phy/phy.h>
#include <linux/pm_runtime.h>
#include <linux/of_platform.h>
+#include <linux/reset.h>
#include "ahci.h"
static void ahci_host_stop(struct ata_host *host);
@@ -195,7 +196,8 @@ EXPORT_SYMBOL_GPL(ahci_platform_disable_regulators);
* following order:
* 1) Regulator
* 2) Clocks (through ahci_platform_enable_clks)
- * 3) Phys
+ * 3) Resets
+ * 4) Phys
*
* If resource enabling fails at any point the previous enabled resources
* are disabled in reverse order.
@@ -215,12 +217,19 @@ int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
if (rc)
goto disable_regulator;
- rc = ahci_platform_enable_phys(hpriv);
+ rc = reset_control_deassert(hpriv->rsts);
if (rc)
goto disable_clks;
+ rc = ahci_platform_enable_phys(hpriv);
+ if (rc)
+ goto disable_resets;
+
return 0;
+disable_resets:
+ reset_control_assert(hpriv->rsts);
+
disable_clks:
ahci_platform_disable_clks(hpriv);
@@ -239,12 +248,15 @@ EXPORT_SYMBOL_GPL(ahci_platform_enable_resources);
* following order:
* 1) Phys
* 2) Clocks (through ahci_platform_disable_clks)
- * 3) Regulator
+ * 3) Resets
+ * 4) Regulator
*/
void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
{
ahci_platform_disable_phys(hpriv);
+ reset_control_assert(hpriv->rsts);
+
ahci_platform_disable_clks(hpriv);
ahci_platform_disable_regulators(hpriv);
@@ -393,6 +405,12 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev)
hpriv->clks[i] = clk;
}
+ hpriv->rsts = devm_reset_control_array_get_optional_shared(dev);
+ if (IS_ERR(hpriv->rsts)) {
+ rc = PTR_ERR(hpriv->rsts);
+ goto err_out;
+ }
+
hpriv->nports = child_nodes = of_get_child_count(dev->of_node);
/*
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 728ed4764678..8bc71ca61e7f 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -6026,7 +6026,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
return ap;
}
-static void ata_host_release(struct device *gendev, void *res)
+static void ata_devres_release(struct device *gendev, void *res)
{
struct ata_host *host = dev_get_drvdata(gendev);
int i;
@@ -6040,13 +6040,36 @@ static void ata_host_release(struct device *gendev, void *res)
if (ap->scsi_host)
scsi_host_put(ap->scsi_host);
+ }
+
+ dev_set_drvdata(gendev, NULL);
+ ata_host_put(host);
+}
+
+static void ata_host_release(struct kref *kref)
+{
+ struct ata_host *host = container_of(kref, struct ata_host, kref);
+ int i;
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
kfree(ap->pmp_link);
kfree(ap->slave_link);
kfree(ap);
host->ports[i] = NULL;
}
+ kfree(host);
+}
- dev_set_drvdata(gendev, NULL);
+void ata_host_get(struct ata_host *host)
+{
+ kref_get(&host->kref);
+}
+
+void ata_host_put(struct ata_host *host)
+{
+ kref_put(&host->kref, ata_host_release);
}
/**
@@ -6074,26 +6097,31 @@ struct ata_host *ata_host_alloc(struct device *dev, int max_ports)
struct ata_host *host;
size_t sz;
int i;
+ void *dr;
DPRINTK("ENTER\n");
- if (!devres_open_group(dev, NULL, GFP_KERNEL))
- return NULL;
-
/* alloc a container for our list of ATA ports (buses) */
sz = sizeof(struct ata_host) + (max_ports + 1) * sizeof(void *);
- /* alloc a container for our list of ATA ports (buses) */
- host = devres_alloc(ata_host_release, sz, GFP_KERNEL);
+ host = kzalloc(sz, GFP_KERNEL);
if (!host)
+ return NULL;
+
+ if (!devres_open_group(dev, NULL, GFP_KERNEL))
+ goto err_free;
+
+ dr = devres_alloc(ata_devres_release, 0, GFP_KERNEL);
+ if (!dr)
goto err_out;
- devres_add(dev, host);
+ devres_add(dev, dr);
dev_set_drvdata(dev, host);
spin_lock_init(&host->lock);
mutex_init(&host->eh_mutex);
host->dev = dev;
host->n_ports = max_ports;
+ kref_init(&host->kref);
/* allocate ports bound to this host */
for (i = 0; i < max_ports; i++) {
@@ -6112,6 +6140,8 @@ struct ata_host *ata_host_alloc(struct device *dev, int max_ports)
err_out:
devres_release_group(dev, NULL);
+ err_free:
+ kfree(host);
return NULL;
}
diff --git a/drivers/ata/libata-transport.c b/drivers/ata/libata-transport.c
index 19e6e539a061..a0b0b4d986f2 100644
--- a/drivers/ata/libata-transport.c
+++ b/drivers/ata/libata-transport.c
@@ -224,6 +224,8 @@ static DECLARE_TRANSPORT_CLASS(ata_port_class,
static void ata_tport_release(struct device *dev)
{
+ struct ata_port *ap = tdev_to_port(dev);
+ ata_host_put(ap->host);
}
/**
@@ -284,6 +286,7 @@ int ata_tport_add(struct device *parent,
dev->type = &ata_port_type;
dev->parent = parent;
+ ata_host_get(ap->host);
dev->release = ata_tport_release;
dev_set_name(dev, "ata%d", ap->print_id);
transport_setup_device(dev);
@@ -314,6 +317,7 @@ int ata_tport_add(struct device *parent,
tport_err:
transport_destroy_device(dev);
put_device(dev);
+ ata_host_put(ap->host);
return error;
}
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index f953cb4bb1ba..9e21c49cf6be 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -100,6 +100,8 @@ extern int ata_port_probe(struct ata_port *ap);
extern void __ata_port_probe(struct ata_port *ap);
extern unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
u8 page, void *buf, unsigned int sectors);
+extern void ata_host_get(struct ata_host *host);
+extern void ata_host_put(struct ata_host *host);
#define to_ata_port(d) container_of(d, struct ata_port, tdev)
diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c
index b4d54771c9fe..ebecab8c3f36 100644
--- a/drivers/ata/pata_arasan_cf.c
+++ b/drivers/ata/pata_arasan_cf.c
@@ -796,7 +796,7 @@ static int arasan_cf_probe(struct platform_device *pdev)
struct resource *res;
u32 quirk;
irq_handler_t irq_handler = NULL;
- int ret = 0;
+ int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
@@ -809,10 +809,8 @@ static int arasan_cf_probe(struct platform_device *pdev)
}
acdev = devm_kzalloc(&pdev->dev, sizeof(*acdev), GFP_KERNEL);
- if (!acdev) {
- dev_warn(&pdev->dev, "kzalloc fail\n");
+ if (!acdev)
return -ENOMEM;
- }
if (pdata)
quirk = pdata->quirk;
diff --git a/drivers/ata/pata_bk3710.c b/drivers/ata/pata_bk3710.c
index 6c3bd5fae3e4..fad95cfecced 100644
--- a/drivers/ata/pata_bk3710.c
+++ b/drivers/ata/pata_bk3710.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0
+
/*
* Palmchip BK3710 PATA controller driver
*
@@ -8,10 +10,6 @@
*
* Copyright (C) 2006 Texas Instruments.
* Copyright (C) 2007 MontaVista Software, Inc., <source@mvista.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
*/
#include <linux/ata.h>
@@ -379,4 +377,4 @@ static int __init pata_bk3710_init(void)
}
module_init(pata_bk3710_init);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/ata/pata_falcon.c b/drivers/ata/pata_falcon.c
index 5b0c57d1c59f..41e0d6a6cd05 100644
--- a/drivers/ata/pata_falcon.c
+++ b/drivers/ata/pata_falcon.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0
+
/*
* Atari Falcon PATA controller driver
*
@@ -7,10 +9,6 @@
* Based on falconide.c:
*
* Created 12 Jul 1997 by Geert Uytterhoeven
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
*/
#include <linux/kernel.h>
@@ -180,5 +178,5 @@ module_init(pata_falcon_init_one);
MODULE_AUTHOR("Bartlomiej Zolnierkiewicz");
MODULE_DESCRIPTION("low-level driver for Atari Falcon PATA");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/pata_gayle.c b/drivers/ata/pata_gayle.c
new file mode 100644
index 000000000000..65bc9f3042ce
--- /dev/null
+++ b/drivers/ata/pata_gayle.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Amiga Gayle PATA controller driver
+ *
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Based on gayle.c:
+ *
+ * Created 12 Jul 1997 by Geert Uytterhoeven
+ */
+
+#include <linux/ata.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/libata.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/zorro.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <asm/amigayle.h>
+#include <asm/ide.h>
+#include <asm/setup.h>
+
+#define DRV_NAME "pata_gayle"
+#define DRV_VERSION "0.1.0"
+
+#define GAYLE_CONTROL 0x101a
+
+static struct scsi_host_template pata_gayle_sht = {
+ ATA_PIO_SHT(DRV_NAME),
+};
+
+/* FIXME: is this needed? */
+static unsigned int pata_gayle_data_xfer(struct ata_queued_cmd *qc,
+ unsigned char *buf,
+ unsigned int buflen, int rw)
+{
+ struct ata_device *dev = qc->dev;
+ struct ata_port *ap = dev->link->ap;
+ void __iomem *data_addr = ap->ioaddr.data_addr;
+ unsigned int words = buflen >> 1;
+
+ /* Transfer multiple of 2 bytes */
+ if (rw == READ)
+ raw_insw((u16 *)data_addr, (u16 *)buf, words);
+ else
+ raw_outsw((u16 *)data_addr, (u16 *)buf, words);
+
+ /* Transfer trailing byte, if any. */
+ if (unlikely(buflen & 0x01)) {
+ unsigned char pad[2] = { };
+
+ /* Point buf to the tail of buffer */
+ buf += buflen - 1;
+
+ if (rw == READ) {
+ raw_insw((u16 *)data_addr, (u16 *)pad, 1);
+ *buf = pad[0];
+ } else {
+ pad[0] = *buf;
+ raw_outsw((u16 *)data_addr, (u16 *)pad, 1);
+ }
+ words++;
+ }
+
+ return words << 1;
+}
+
+/*
+ * Provide our own set_mode() as we don't want to change anything that has
+ * already been configured..
+ */
+static int pata_gayle_set_mode(struct ata_link *link,
+ struct ata_device **unused)
+{
+ struct ata_device *dev;
+
+ ata_for_each_dev(dev, link, ENABLED) {
+ /* We don't really care */
+ dev->pio_mode = dev->xfer_mode = XFER_PIO_0;
+ dev->xfer_shift = ATA_SHIFT_PIO;
+ dev->flags |= ATA_DFLAG_PIO;
+ ata_dev_info(dev, "configured for PIO\n");
+ }
+ return 0;
+}
+
+static bool pata_gayle_irq_check(struct ata_port *ap)
+{
+ u8 ch;
+
+ ch = z_readb((unsigned long)ap->private_data);
+
+ return !!(ch & GAYLE_IRQ_IDE);
+}
+
+static void pata_gayle_irq_clear(struct ata_port *ap)
+{
+ (void)z_readb((unsigned long)ap->ioaddr.status_addr);
+ z_writeb(0x7c, (unsigned long)ap->private_data);
+}
+
+static struct ata_port_operations pata_gayle_a1200_ops = {
+ .inherits = &ata_sff_port_ops,
+ .sff_data_xfer = pata_gayle_data_xfer,
+ .sff_irq_check = pata_gayle_irq_check,
+ .sff_irq_clear = pata_gayle_irq_clear,
+ .cable_detect = ata_cable_unknown,
+ .set_mode = pata_gayle_set_mode,
+};
+
+static struct ata_port_operations pata_gayle_a4000_ops = {
+ .inherits = &ata_sff_port_ops,
+ .sff_data_xfer = pata_gayle_data_xfer,
+ .cable_detect = ata_cable_unknown,
+ .set_mode = pata_gayle_set_mode,
+};
+
+static int __init pata_gayle_init_one(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct gayle_ide_platform_data *pdata;
+ struct ata_host *host;
+ struct ata_port *ap;
+ void __iomem *base;
+ int ret;
+
+ pdata = dev_get_platdata(&pdev->dev);
+
+ dev_info(&pdev->dev, "Amiga Gayle IDE controller (A%u style)\n",
+ pdata->explicit_ack ? 1200 : 4000);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ if (!devm_request_mem_region(&pdev->dev, res->start,
+ resource_size(res), DRV_NAME)) {
+ pr_err(DRV_NAME ": resources busy\n");
+ return -EBUSY;
+ }
+
+ /* allocate host */
+ host = ata_host_alloc(&pdev->dev, 1);
+ if (!host)
+ return -ENOMEM;
+
+ ap = host->ports[0];
+
+ if (pdata->explicit_ack)
+ ap->ops = &pata_gayle_a1200_ops;
+ else
+ ap->ops = &pata_gayle_a4000_ops;
+
+ ap->pio_mask = ATA_PIO4;
+ ap->flags |= ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_IORDY;
+
+ base = ZTWO_VADDR(pdata->base);
+ ap->ioaddr.data_addr = base;
+ ap->ioaddr.error_addr = base + 2 + 1 * 4;
+ ap->ioaddr.feature_addr = base + 2 + 1 * 4;
+ ap->ioaddr.nsect_addr = base + 2 + 2 * 4;
+ ap->ioaddr.lbal_addr = base + 2 + 3 * 4;
+ ap->ioaddr.lbam_addr = base + 2 + 4 * 4;
+ ap->ioaddr.lbah_addr = base + 2 + 5 * 4;
+ ap->ioaddr.device_addr = base + 2 + 6 * 4;
+ ap->ioaddr.status_addr = base + 2 + 7 * 4;
+ ap->ioaddr.command_addr = base + 2 + 7 * 4;
+
+ ap->ioaddr.altstatus_addr = base + GAYLE_CONTROL;
+ ap->ioaddr.ctl_addr = base + GAYLE_CONTROL;
+
+ ap->private_data = (void *)ZTWO_VADDR(pdata->irqport);
+
+ ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", pdata->base,
+ pdata->base + GAYLE_CONTROL);
+
+ ret = ata_host_activate(host, IRQ_AMIGA_PORTS, ata_sff_interrupt,
+ IRQF_SHARED, &pata_gayle_sht);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, host);
+
+ return 0;
+}
+
+static int __exit pata_gayle_remove_one(struct platform_device *pdev)
+{
+ struct ata_host *host = platform_get_drvdata(pdev);
+
+ ata_host_detach(host);
+
+ return 0;
+}
+
+static struct platform_driver pata_gayle_driver = {
+ .remove = __exit_p(pata_gayle_remove_one),
+ .driver = {
+ .name = "amiga-gayle-ide",
+ },
+};
+
+module_platform_driver_probe(pata_gayle_driver, pata_gayle_init_one);
+
+MODULE_AUTHOR("Bartlomiej Zolnierkiewicz");
+MODULE_DESCRIPTION("low-level driver for Amiga Gayle PATA");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:amiga-gayle-ide");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
index 8468b300193b..9bac79edbc2c 100644
--- a/drivers/ata/pata_it821x.c
+++ b/drivers/ata/pata_it821x.c
@@ -658,10 +658,10 @@ static u8 *it821x_firmware_command(struct ata_port *ap, u8 cmd, int len)
u8 status;
int n = 0;
u16 *buf = kmalloc(len, GFP_KERNEL);
- if (buf == NULL) {
- printk(KERN_ERR "it821x_firmware_command: Out of memory\n");
+
+ if (!buf)
return NULL;
- }
+
/* This isn't quite a normal ATA command as we are talking to the
firmware not the drives */
ap->ctl |= ATA_NIEN;
diff --git a/drivers/ata/pata_macio.c b/drivers/ata/pata_macio.c
index 0adcb40d2794..9588e685d994 100644
--- a/drivers/ata/pata_macio.c
+++ b/drivers/ata/pata_macio.c
@@ -1131,11 +1131,9 @@ static int pata_macio_attach(struct macio_dev *mdev,
/* Allocate and init private data structure */
priv = devm_kzalloc(&mdev->ofdev.dev,
sizeof(struct pata_macio_priv), GFP_KERNEL);
- if (priv == NULL) {
- dev_err(&mdev->ofdev.dev,
- "Failed to allocate private memory\n");
+ if (!priv)
return -ENOMEM;
- }
+
priv->node = of_node_get(mdev->ofdev.dev.of_node);
priv->mdev = mdev;
priv->dev = &mdev->ofdev.dev;
@@ -1277,11 +1275,9 @@ static int pata_macio_pci_attach(struct pci_dev *pdev,
/* Allocate and init private data structure */
priv = devm_kzalloc(&pdev->dev,
sizeof(struct pata_macio_priv), GFP_KERNEL);
- if (priv == NULL) {
- dev_err(&pdev->dev,
- "Failed to allocate private memory\n");
+ if (!priv)
return -ENOMEM;
- }
+
priv->node = of_node_get(np);
priv->pdev = pdev;
priv->dev = &pdev->dev;
diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
index 9730125530f6..f1d352d5f128 100644
--- a/drivers/ata/pata_mpc52xx.c
+++ b/drivers/ata/pata_mpc52xx.c
@@ -738,7 +738,6 @@ static int mpc52xx_ata_probe(struct platform_device *op)
/* Prepare our private structure */
priv = devm_kzalloc(&op->dev, sizeof(*priv), GFP_ATOMIC);
if (!priv) {
- dev_err(&op->dev, "error allocating private structure\n");
rv = -ENOMEM;
goto err1;
}
diff --git a/drivers/ata/pata_samsung_cf.c b/drivers/ata/pata_samsung_cf.c
index 50801c40b029..bb96dc35950d 100644
--- a/drivers/ata/pata_samsung_cf.c
+++ b/drivers/ata/pata_samsung_cf.c
@@ -505,10 +505,8 @@ static int __init pata_s3c_probe(struct platform_device *pdev)
cpu_type = platform_get_device_id(pdev)->driver_data;
info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
- if (!info) {
- dev_err(dev, "failed to allocate memory for device data\n");
+ if (!info)
return -ENOMEM;
- }
info->irq = platform_get_irq(pdev, 0);
diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c
index 6af4ec3c88c3..ce3d6674ef80 100644
--- a/drivers/ata/sata_dwc_460ex.c
+++ b/drivers/ata/sata_dwc_460ex.c
@@ -901,7 +901,6 @@ static int sata_dwc_port_start(struct ata_port *ap)
/* Allocate Port Struct */
hsdevp = kzalloc(sizeof(*hsdevp), GFP_KERNEL);
if (!hsdevp) {
- dev_err(ap->dev, "%s: kmalloc failed for hsdevp\n", __func__);
err = -ENOMEM;
goto CLEANUP;
}