Commit a23867f1 authored by Linus Torvalds's avatar Linus Torvalds

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()
  ...
parents ef1c4a6f 027fa4de
...@@ -30,6 +30,7 @@ compatible: ...@@ -30,6 +30,7 @@ compatible:
Optional properties: Optional properties:
- dma-coherent : Present if dma operations are coherent - dma-coherent : Present if dma operations are coherent
- clocks : a list of phandle + clock specifier pairs - clocks : a list of phandle + clock specifier pairs
- resets : a list of phandle + reset specifier pairs
- target-supply : regulator for SATA target power - target-supply : regulator for SATA target power
- phys : reference to the SATA PHY node - phys : reference to the SATA PHY node
- phy-names : must be "sata-phy" - phy-names : must be "sata-phy"
......
...@@ -7,6 +7,7 @@ Required properties: ...@@ -7,6 +7,7 @@ Required properties:
- compatible : should be one of the following: - compatible : should be one of the following:
- "fsl,imx53-ahci" for i.MX53 SATA controller - "fsl,imx53-ahci" for i.MX53 SATA controller
- "fsl,imx6q-ahci" for i.MX6Q SATA controller - "fsl,imx6q-ahci" for i.MX6Q SATA controller
- "fsl,imx6qp-ahci" for i.MX6QP SATA controller
- interrupts : interrupt mapping for SATA IRQ - interrupts : interrupt mapping for SATA IRQ
- reg : registers mapping - reg : registers mapping
- clocks : list of clock specifiers, must contain an entry for each - clocks : list of clock specifiers, must contain an entry for each
......
Tegra124 SoC SATA AHCI controller Tegra SoC SATA AHCI controller
Required properties : Required properties :
- compatible : For Tegra124, must contain "nvidia,tegra124-ahci". Otherwise, - compatible : Must be one of:
must contain '"nvidia,<chip>-ahci", "nvidia,tegra124-ahci"', where <chip> - Tegra124 : "nvidia,tegra124-ahci"
is tegra132. - Tegra132 : "nvidia,tegra132-ahci", "nvidia,tegra124-ahci"
- Tegra210 : "nvidia,tegra210-ahci"
- reg : Should contain 2 entries: - reg : Should contain 2 entries:
- AHCI register set (SATA BAR5) - AHCI register set (SATA BAR5)
- SATA register set - SATA register set
...@@ -13,8 +14,6 @@ Required properties : ...@@ -13,8 +14,6 @@ Required properties :
- clock-names : Must include the following entries: - clock-names : Must include the following entries:
- sata - sata
- sata-oob - sata-oob
- cml1
- pll_e
- resets : Must contain an entry for each entry in reset-names. - resets : Must contain an entry for each entry in reset-names.
See ../reset/reset.txt for details. See ../reset/reset.txt for details.
- reset-names : Must include the following entries: - reset-names : Must include the following entries:
...@@ -24,9 +23,22 @@ Required properties : ...@@ -24,9 +23,22 @@ Required properties :
- phys : Must contain an entry for each entry in phy-names. - phys : Must contain an entry for each entry in phy-names.
See ../phy/phy-bindings.txt for details. See ../phy/phy-bindings.txt for details.
- phy-names : Must include the following entries: - phy-names : Must include the following entries:
- sata-phy : XUSB PADCTL SATA PHY - For Tegra124 and Tegra132:
- hvdd-supply : Defines the SATA HVDD regulator - sata-phy : XUSB PADCTL SATA PHY
- vddio-supply : Defines the SATA VDDIO regulator - For Tegra124 and Tegra132:
- avdd-supply : Defines the SATA AVDD regulator - hvdd-supply : Defines the SATA HVDD regulator
- target-5v-supply : Defines the SATA 5V power regulator - vddio-supply : Defines the SATA VDDIO regulator
- target-12v-supply : Defines the SATA 12V power regulator - avdd-supply : Defines the SATA AVDD regulator
- target-5v-supply : Defines the SATA 5V power regulator
- target-12v-supply : Defines the SATA 12V power regulator
Optional properties:
- reg :
- AUX register set
- clock-names :
- cml1 :
cml1 clock should be defined here if the PHY driver
doesn't manage them. If it does, they should not be.
- phy-names :
- For T210:
- sata-phy
...@@ -211,10 +211,10 @@ config AHCI_SUNXI ...@@ -211,10 +211,10 @@ config AHCI_SUNXI
If unsure, say N. If unsure, say N.
config AHCI_TEGRA config AHCI_TEGRA
tristate "NVIDIA Tegra124 AHCI SATA support" tristate "NVIDIA Tegra AHCI SATA support"
depends on ARCH_TEGRA depends on ARCH_TEGRA
help help
This option enables support for the NVIDIA Tegra124 SoC's This option enables support for the NVIDIA Tegra SoC's
onboard AHCI SATA. onboard AHCI SATA.
If unsure, say N. If unsure, say N.
...@@ -954,6 +954,18 @@ config PATA_FALCON ...@@ -954,6 +954,18 @@ config PATA_FALCON
If unsure, say N. 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 config PATA_ISAPNP
tristate "ISA Plug and Play PATA support" tristate "ISA Plug and Play PATA support"
depends on ISAPNP depends on ISAPNP
......
...@@ -97,6 +97,7 @@ obj-$(CONFIG_PATA_WINBOND) += pata_sl82c105.o ...@@ -97,6 +97,7 @@ obj-$(CONFIG_PATA_WINBOND) += pata_sl82c105.o
# SFF PIO only # SFF PIO only
obj-$(CONFIG_PATA_CMD640_PCI) += pata_cmd640.o obj-$(CONFIG_PATA_CMD640_PCI) += pata_cmd640.o
obj-$(CONFIG_PATA_FALCON) += pata_falcon.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_ISAPNP) += pata_isapnp.o
obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o
obj-$(CONFIG_PATA_MPIIX) += pata_mpiix.o obj-$(CONFIG_PATA_MPIIX) += pata_mpiix.o
......
...@@ -350,6 +350,7 @@ struct ahci_host_priv { ...@@ -350,6 +350,7 @@ struct ahci_host_priv {
u32 em_msg_type; /* EM message type */ u32 em_msg_type; /* EM message type */
bool got_runtime_pm; /* Did we do pm_runtime_get? */ bool got_runtime_pm; /* Did we do pm_runtime_get? */
struct clk *clks[AHCI_MAX_CLKS]; /* Optional */ struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
struct reset_control *rsts; /* Optional */
struct regulator **target_pwrs; /* Optional */ struct regulator **target_pwrs; /* Optional */
/* /*
* If platform uses PHYs. There is a 1:1 relation between the port number and * If platform uses PHYs. There is a 1:1 relation between the port number and
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/ahci_platform.h> #include <linux/ahci_platform.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include <linux/libata.h> #include <linux/libata.h>
...@@ -53,11 +54,49 @@ enum { ...@@ -53,11 +54,49 @@ enum {
/* Clock Reset Register */ /* Clock Reset Register */
IMX_CLOCK_RESET = 0x7f3f, IMX_CLOCK_RESET = 0x7f3f,
IMX_CLOCK_RESET_RESET = 1 << 0, 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 { enum ahci_imx_type {
AHCI_IMX53, AHCI_IMX53,
AHCI_IMX6Q, AHCI_IMX6Q,
AHCI_IMX6QP,
AHCI_IMX8QM,
}; };
struct imx_ahci_priv { struct imx_ahci_priv {
...@@ -66,10 +105,18 @@ struct imx_ahci_priv { ...@@ -66,10 +105,18 @@ struct imx_ahci_priv {
struct clk *sata_clk; struct clk *sata_clk;
struct clk *sata_ref_clk; struct clk *sata_ref_clk;
struct clk *ahb_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; struct regmap *gpr;
bool no_device; bool no_device;
bool first_time; bool first_time;
u32 phy_params; u32 phy_params;
u32 imped_ratio;
}; };
static int ahci_imx_hotplug; static int ahci_imx_hotplug;
...@@ -188,11 +235,26 @@ static int imx_phy_reg_read(u16 *val, void __iomem *mmio) ...@@ -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) static int imx_sata_phy_reset(struct ahci_host_priv *hpriv)
{ {
struct imx_ahci_priv *imxpriv = hpriv->plat_data;
void __iomem *mmio = hpriv->mmio; void __iomem *mmio = hpriv->mmio;
int timeout = 10; int timeout = 10;
u16 val; u16 val;
int ret; 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 */ /* Reset SATA PHY by setting RESET bit of PHY register CLOCK_RESET */
ret = imx_phy_reg_addressing(IMX_CLOCK_RESET, mmio); ret = imx_phy_reg_addressing(IMX_CLOCK_RESET, mmio);
if (ret) if (ret)
...@@ -391,6 +453,207 @@ static struct attribute *fsl_sata_ahci_attrs[] = { ...@@ -391,6 +453,207 @@ static struct attribute *fsl_sata_ahci_attrs[] = {
}; };
ATTRIBUTE_GROUPS(fsl_sata_ahci); 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) static int imx_sata_enable(struct ahci_host_priv *hpriv)
{ {
struct imx_ahci_priv *imxpriv = hpriv->plat_data; struct imx_ahci_priv *imxpriv = hpriv->plat_data;
...@@ -408,7 +671,7 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv) ...@@ -408,7 +671,7 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv)
if (ret < 0) if (ret < 0)
goto disable_regulator; 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, * set PHY Paremeters, two steps to configure the GPR13,
* one write for rest of parameters, mask of first write * one write for rest of parameters, mask of first write
...@@ -438,6 +701,8 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv) ...@@ -438,6 +701,8 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv)
dev_err(dev, "failed to reset phy: %d\n", ret); dev_err(dev, "failed to reset phy: %d\n", ret);
goto disable_clk; goto disable_clk;
} }
} else if (imxpriv->type == AHCI_IMX8QM) {
ret = imx8_sata_enable(hpriv);
} }
usleep_range(1000, 2000); usleep_range(1000, 2000);
...@@ -459,10 +724,29 @@ static void imx_sata_disable(struct ahci_host_priv *hpriv) ...@@ -459,10 +724,29 @@ static void imx_sata_disable(struct ahci_host_priv *hpriv)
if (imxpriv->no_device) if (imxpriv->no_device)
return; 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, regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
IMX6Q_GPR13_SATA_MPLL_CLK_EN, IMX6Q_GPR13_SATA_MPLL_CLK_EN,
!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); clk_disable_unprepare(imxpriv->sata_ref_clk);
...@@ -513,7 +797,7 @@ static int ahci_imx_softreset(struct ata_link *link, unsigned int *class, ...@@ -513,7 +797,7 @@ static int ahci_imx_softreset(struct ata_link *link, unsigned int *class,
if (imxpriv->type == AHCI_IMX53) if (imxpriv->type == AHCI_IMX53)
ret = ahci_pmp_retry_srst_ops.softreset(link, class, deadline); ret = ahci_pmp_retry_srst_ops.softreset(link, class, deadline);
else if (imxpriv->type == AHCI_IMX6Q) else
ret = ahci_ops.softreset(link, class, deadline); ret = ahci_ops.softreset(link, class, deadline);
return ret; return ret;
...@@ -536,6 +820,8 @@ static const struct ata_port_info ahci_imx_port_info = { ...@@ -536,6 +820,8 @@ static const struct ata_port_info ahci_imx_port_info = {
static const struct of_device_id imx_ahci_of_match[] = { static const struct of_device_id imx_ahci_of_match[] = {
{ .compatible = "fsl,imx53-ahci", .data = (void *)AHCI_IMX53 }, { .compatible = "fsl,imx53-ahci", .data = (void *)AHCI_IMX53 },
{ .compatible = "fsl,imx6q-ahci", .data = (void *)AHCI_IMX6Q }, { .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); MODULE_DEVICE_TABLE(of, imx_ahci_of_match);
...@@ -703,6 +989,79 @@ static struct scsi_host_template ahci_platform_sht = { ...@@ -703,6 +989,79 @@ static struct scsi_host_template ahci_platform_sht = {
AHCI_SHT(DRV_NAME), 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) static int imx_ahci_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -743,7 +1102,7 @@ static int imx_ahci_probe(struct platform_device *pdev) ...@@ -743,7 +1102,7 @@ static int imx_ahci_probe(struct platform_device *pdev)
return PTR_ERR(imxpriv->ahb_clk); return PTR_ERR(imxpriv->ahb_clk);
} }
if (imxpriv->type == AHCI_IMX6Q) { if (imxpriv->type == AHCI_IMX6Q || imxpriv->type == AHCI_IMX6QP) {
u32 reg_value; u32 reg_value;
imxpriv->gpr = syscon_regmap_lookup_by_compatible( imxpriv->gpr = syscon_regmap_lookup_by_compatible(
...@@ -762,6 +1121,10 @@ static int imx_ahci_probe(struct platform_device *pdev) ...@@ -762,6 +1121,10 @@ static int imx_ahci_probe(struct platform_device *pdev)
IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F | IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F |
IMX6Q_GPR13_SATA_SPD_MODE_3P0G | IMX6Q_GPR13_SATA_SPD_MODE_3P0G |
reg_value; reg_value;
} else if (imxpriv->type == AHCI_IMX8QM) {
ret = imx8_sata_probe(dev, imxpriv);
if (ret)
return ret;
} }
hpriv = ahci_platform_get_resources(pdev); hpriv = ahci_platform_get_resources(pdev);
......
...@@ -34,7 +34,8 @@ ...@@ -34,7 +34,8 @@
#define DRV_NAME "tegra-ahci" #define DRV_NAME "tegra-ahci"
#define SATA_CONFIGURATION_0 0x180 #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 #define SCFG_OFFSET 0x1000
...@@ -45,17 +46,55 @@ ...@@ -45,17 +46,55 @@
#define T_SATA0_CFG_1_SERR BIT(8) #define T_SATA0_CFG_1_SERR BIT(8)
#define T_SATA0_CFG_9 0x24 #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 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 0x188
#define SATA_INTR_MASK_IP_INT_MASK BIT(16) #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 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 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 0x54c
#define T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN BIT(12) #define T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN BIT(12)
...@@ -82,6 +121,27 @@ ...@@ -82,6 +121,27 @@
#define T_SATA0_CHX_PHY_CTRL11 0x6d0 #define T_SATA0_CHX_PHY_CTRL11 0x6d0
#define T_SATA0_CHX_PHY_CTRL11_GEN2_RX_EQ (0x2800 << 16) #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 0x124
#define FUSE_SATA_CALIB_MASK 0x3 #define FUSE_SATA_CALIB_MASK 0x3
...@@ -99,23 +159,92 @@ static const struct sata_pad_calibration tegra124_pad_calibration[] = { ...@@ -99,23 +159,92 @@ static const struct sata_pad_calibration tegra124_pad_calibration[] = {
{0x14, 0x0e, 0x1a, 0x0e}, {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 tegra_ahci_priv {
struct platform_device *pdev; struct platform_device *pdev;
void __iomem *sata_regs; void __iomem *sata_regs;
void __iomem *sata_aux_regs;
struct reset_control *sata_rst; struct reset_control *sata_rst;
struct reset_control *sata_oob_rst; struct reset_control *sata_oob_rst;
struct reset_control *sata_cold_rst; struct reset_control *sata_cold_rst;
/* Needs special handling, cannot use ahci_platform */ /* Needs special handling, cannot use ahci_platform */
struct clk *sata_clk; 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) static int tegra_ahci_power_on(struct ahci_host_priv *hpriv)
{ {
struct tegra_ahci_priv *tegra = hpriv->plat_data; struct tegra_ahci_priv *tegra = hpriv->plat_data;
int ret; int ret;
ret = regulator_bulk_enable(ARRAY_SIZE(tegra->supplies), ret = regulator_bulk_enable(tegra->soc->num_supplies,
tegra->supplies); tegra->supplies);
if (ret) if (ret)
return ret; return ret;
...@@ -144,7 +273,7 @@ static int tegra_ahci_power_on(struct ahci_host_priv *hpriv) ...@@ -144,7 +273,7 @@ static int tegra_ahci_power_on(struct ahci_host_priv *hpriv)
tegra_powergate_power_off(TEGRA_POWERGATE_SATA); tegra_powergate_power_off(TEGRA_POWERGATE_SATA);
disable_regulators: disable_regulators:
regulator_bulk_disable(ARRAY_SIZE(tegra->supplies), tegra->supplies); regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies);
return ret; return ret;
} }
...@@ -162,15 +291,14 @@ static void tegra_ahci_power_off(struct ahci_host_priv *hpriv) ...@@ -162,15 +291,14 @@ static void tegra_ahci_power_off(struct ahci_host_priv *hpriv)
clk_disable_unprepare(tegra->sata_clk); clk_disable_unprepare(tegra->sata_clk);
tegra_powergate_power_off(TEGRA_POWERGATE_SATA); 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) static int tegra_ahci_controller_init(struct ahci_host_priv *hpriv)
{ {
struct tegra_ahci_priv *tegra = hpriv->plat_data; struct tegra_ahci_priv *tegra = hpriv->plat_data;
int ret; int ret;
unsigned int val; u32 val;
struct sata_pad_calibration calib;
ret = tegra_ahci_power_on(hpriv); ret = tegra_ahci_power_on(hpriv);
if (ret) { if (ret) {
...@@ -179,78 +307,115 @@ static int tegra_ahci_controller_init(struct ahci_host_priv *hpriv) ...@@ -179,78 +307,115 @@ static int tegra_ahci_controller_init(struct ahci_host_priv *hpriv)
return ret; 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 = 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); writel(val, tegra->sata_regs + SATA_CONFIGURATION_0);
/* Pad calibration */ /* Electrical settings for better link stability */
val = T_SATA0_CHX_PHY_CTRL17_0_RX_EQ_CTRL_L_GEN1;
ret = tegra_fuse_readl(FUSE_SATA_CALIB, &val); writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL17_0);
if (ret) { val = T_SATA0_CHX_PHY_CTRL18_0_RX_EQ_CTRL_L_GEN2;
dev_err(&tegra->pdev->dev, writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL18_0);
"failed to read calibration fuse: %d\n", ret); val = T_SATA0_CHX_PHY_CTRL20_0_RX_EQ_CTRL_H_GEN1;
return ret; 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);
calib = tegra124_pad_calibration[val & FUSE_SATA_CALIB_MASK];
/* For SQUELCH Filter & Gen3 drive getting detected as Gen1 drive */
writel(BIT(0), tegra->sata_regs + SCFG_OFFSET + T_SATA0_INDEX);
val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA_CFG_PHY_0);
val = readl(tegra->sata_regs + val |= T_SATA_CFG_PHY_0_MASK_SQUELCH;
SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN1); val &= ~T_SATA_CFG_PHY_0_USE_7BIT_ALIGN_DET_FOR_SPD;
val &= ~T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_MASK; writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA_CFG_PHY_0);
val &= ~T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_MASK;
val |= calib.gen1_tx_amp << val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_NVOOB);
T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT; val &= ~(T_SATA0_NVOOB_COMMA_CNT_MASK |
val |= calib.gen1_tx_peak << T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH_MASK |
T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT; T_SATA0_NVOOB_SQUELCH_FILTER_MODE_MASK);
writel(val, tegra->sata_regs + SCFG_OFFSET + val |= (T_SATA0_NVOOB_COMMA_CNT |
T_SATA0_CHX_PHY_CTRL1_GEN1); T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH |
T_SATA0_NVOOB_SQUELCH_FILTER_MODE);
val = readl(tegra->sata_regs + writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_NVOOB);
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; * Change CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW from 83.3 ns to 58.8ns
val |= calib.gen2_tx_amp << */
T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT; val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG2NVOOB_2);
val |= calib.gen2_tx_peak << val &= ~T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW_MASK;
T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT; val |= T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW;
writel(val, tegra->sata_regs + SCFG_OFFSET + writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG2NVOOB_2);
T_SATA0_CHX_PHY_CTRL1_GEN2);
if (tegra->soc->ops && tegra->soc->ops->init)
writel(T_SATA0_CHX_PHY_CTRL11_GEN2_RX_EQ, tegra->soc->ops->init(hpriv);
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); * Program the following SATA configuration registers to
* initialize SATA
writel(0, tegra->sata_regs + SCFG_OFFSET + T_SATA0_INDEX); */
val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_1);
/* Program controller device ID */ 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 = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA);
val |= T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN; val |= T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN;
writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA); 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 = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA);
val &= ~T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN; val &= ~T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN;
writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA); writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA);
/* Enable IO & memory access, bus master mode */ /* Enabling LPM capabilities through Backdoor Programming */
val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_AHCI_HBA_CAP_BKDR);
val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_1); val |= (T_SATA0_AHCI_HBA_CAP_BKDR_PARTIAL_ST_CAP |
val |= T_SATA0_CFG_1_IO_SPACE | T_SATA0_CFG_1_MEMORY_SPACE | T_SATA0_AHCI_HBA_CAP_BKDR_SLUMBER_ST_CAP |
T_SATA0_CFG_1_BUS_MASTER | T_SATA0_CFG_1_SERR; T_SATA0_AHCI_HBA_CAP_BKDR_SALP |
writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_1); T_SATA0_AHCI_HBA_CAP_BKDR_SUPP_PM);
writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_AHCI_HBA_CAP_BKDR);
/* Program SATA MMIO */
/* SATA Second Level Clock Gating configuration
writel(0x10000 << SATA_FPCI_BAR5_START_SHIFT, * Enabling Gating of Tx/Rx clocks and driving Pad IDDQ and Lane
tegra->sata_regs + SATA_FPCI_BAR5); * 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_ahci_handle_quirks(hpriv);
tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_9);
/* Unmask SATA interrupts */ /* Unmask SATA interrupts */
...@@ -279,14 +444,40 @@ static struct ata_port_operations ahci_tegra_port_ops = { ...@@ -279,14 +444,40 @@ static struct ata_port_operations ahci_tegra_port_ops = {
}; };
static const struct ata_port_info ahci_tegra_port_info = { 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, .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6, .udma_mask = ATA_UDMA6,
.port_ops = &ahci_tegra_port_ops, .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[] = { 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); MODULE_DEVICE_TABLE(of, tegra_ahci_of_match);
...@@ -301,6 +492,7 @@ static int tegra_ahci_probe(struct platform_device *pdev) ...@@ -301,6 +492,7 @@ static int tegra_ahci_probe(struct platform_device *pdev)
struct tegra_ahci_priv *tegra; struct tegra_ahci_priv *tegra;
struct resource *res; struct resource *res;
int ret; int ret;
unsigned int i;
hpriv = ahci_platform_get_resources(pdev); hpriv = ahci_platform_get_resources(pdev);
if (IS_ERR(hpriv)) if (IS_ERR(hpriv))
...@@ -313,12 +505,23 @@ static int tegra_ahci_probe(struct platform_device *pdev) ...@@ -313,12 +505,23 @@ static int tegra_ahci_probe(struct platform_device *pdev)
hpriv->plat_data = tegra; hpriv->plat_data = tegra;
tegra->pdev = pdev; tegra->pdev = pdev;
tegra->soc = of_device_get_match_data(&pdev->dev);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1); res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
tegra->sata_regs = devm_ioremap_resource(&pdev->dev, res); tegra->sata_regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(tegra->sata_regs)) if (IS_ERR(tegra->sata_regs))
return PTR_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"); tegra->sata_rst = devm_reset_control_get(&pdev->dev, "sata");
if (IS_ERR(tegra->sata_rst)) { if (IS_ERR(tegra->sata_rst)) {
dev_err(&pdev->dev, "Failed to get sata reset\n"); dev_err(&pdev->dev, "Failed to get sata reset\n");
...@@ -343,13 +546,17 @@ static int tegra_ahci_probe(struct platform_device *pdev) ...@@ -343,13 +546,17 @@ static int tegra_ahci_probe(struct platform_device *pdev)
return PTR_ERR(tegra->sata_clk); return PTR_ERR(tegra->sata_clk);
} }
tegra->supplies[0].supply = "avdd"; tegra->supplies = devm_kcalloc(&pdev->dev,
tegra->supplies[1].supply = "hvdd"; tegra->soc->num_supplies,
tegra->supplies[2].supply = "vddio"; sizeof(*tegra->supplies), GFP_KERNEL);
tegra->supplies[3].supply = "target-5v"; if (!tegra->supplies)
tegra->supplies[4].supply = "target-12v"; 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); tegra->supplies);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Failed to get regulators\n"); dev_err(&pdev->dev, "Failed to get regulators\n");
...@@ -385,5 +592,5 @@ static struct platform_driver tegra_ahci_driver = { ...@@ -385,5 +592,5 @@ static struct platform_driver tegra_ahci_driver = {
module_platform_driver(tegra_ahci_driver); module_platform_driver(tegra_ahci_driver);
MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>"); MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>");
MODULE_DESCRIPTION("Tegra124 AHCI SATA driver"); MODULE_DESCRIPTION("Tegra AHCI SATA driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/reset.h>
#include "ahci.h" #include "ahci.h"
static void ahci_host_stop(struct ata_host *host); static void ahci_host_stop(struct ata_host *host);
...@@ -195,7 +196,8 @@ EXPORT_SYMBOL_GPL(ahci_platform_disable_regulators); ...@@ -195,7 +196,8 @@ EXPORT_SYMBOL_GPL(ahci_platform_disable_regulators);
* following order: * following order:
* 1) Regulator * 1) Regulator
* 2) Clocks (through ahci_platform_enable_clks) * 2) Clocks (through ahci_platform_enable_clks)
* 3) Phys * 3) Resets
* 4) Phys
* *
* If resource enabling fails at any point the previous enabled resources * If resource enabling fails at any point the previous enabled resources
* are disabled in reverse order. * are disabled in reverse order.
...@@ -215,12 +217,19 @@ int ahci_platform_enable_resources(struct ahci_host_priv *hpriv) ...@@ -215,12 +217,19 @@ int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
if (rc) if (rc)
goto disable_regulator; goto disable_regulator;
rc = ahci_platform_enable_phys(hpriv); rc = reset_control_deassert(hpriv->rsts);
if (rc) if (rc)
goto disable_clks; goto disable_clks;
rc = ahci_platform_enable_phys(hpriv);
if (rc)
goto disable_resets;
return 0; return 0;
disable_resets:
reset_control_assert(hpriv->rsts);
disable_clks: disable_clks:
ahci_platform_disable_clks(hpriv); ahci_platform_disable_clks(hpriv);
...@@ -239,12 +248,15 @@ EXPORT_SYMBOL_GPL(ahci_platform_enable_resources); ...@@ -239,12 +248,15 @@ EXPORT_SYMBOL_GPL(ahci_platform_enable_resources);
* following order: * following order:
* 1) Phys * 1) Phys
* 2) Clocks (through ahci_platform_disable_clks) * 2) Clocks (through ahci_platform_disable_clks)
* 3) Regulator * 3) Resets
* 4) Regulator
*/ */
void ahci_platform_disable_resources(struct ahci_host_priv *hpriv) void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
{ {
ahci_platform_disable_phys(hpriv); ahci_platform_disable_phys(hpriv);
reset_control_assert(hpriv->rsts);
ahci_platform_disable_clks(hpriv); ahci_platform_disable_clks(hpriv);
ahci_platform_disable_regulators(hpriv); ahci_platform_disable_regulators(hpriv);
...@@ -393,6 +405,12 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev) ...@@ -393,6 +405,12 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev)
hpriv->clks[i] = clk; 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); hpriv->nports = child_nodes = of_get_child_count(dev->of_node);
/* /*
......
...@@ -6026,7 +6026,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host) ...@@ -6026,7 +6026,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
return ap; 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); struct ata_host *host = dev_get_drvdata(gendev);
int i; int i;
...@@ -6040,13 +6040,36 @@ static void ata_host_release(struct device *gendev, void *res) ...@@ -6040,13 +6040,36 @@ static void ata_host_release(struct device *gendev, void *res)
if (ap->scsi_host) if (ap->scsi_host)
scsi_host_put(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->pmp_link);
kfree(ap->slave_link); kfree(ap->slave_link);
kfree(ap); kfree(ap);
host->ports[i] = NULL; 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) ...@@ -6074,26 +6097,31 @@ struct ata_host *ata_host_alloc(struct device *dev, int max_ports)
struct ata_host *host; struct ata_host *host;
size_t sz; size_t sz;
int i; int i;
void *dr;
DPRINTK("ENTER\n"); DPRINTK("ENTER\n");
if (!devres_open_group(dev, NULL, GFP_KERNEL))
return NULL;
/* alloc a container for our list of ATA ports (buses) */ /* alloc a container for our list of ATA ports (buses) */
sz = sizeof(struct ata_host) + (max_ports + 1) * sizeof(void *); sz = sizeof(struct ata_host) + (max_ports + 1) * sizeof(void *);
/* alloc a container for our list of ATA ports (buses) */ host = kzalloc(sz, GFP_KERNEL);
host = devres_alloc(ata_host_release, sz, GFP_KERNEL);
if (!host) 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; goto err_out;
devres_add(dev, host); devres_add(dev, dr);
dev_set_drvdata(dev, host); dev_set_drvdata(dev, host);
spin_lock_init(&host->lock); spin_lock_init(&host->lock);
mutex_init(&host->eh_mutex); mutex_init(&host->eh_mutex);
host->dev = dev; host->dev = dev;
host->n_ports = max_ports; host->n_ports = max_ports;
kref_init(&host->kref);
/* allocate ports bound to this host */ /* allocate ports bound to this host */
for (i = 0; i < max_ports; i++) { for (i = 0; i < max_ports; i++) {
...@@ -6112,6 +6140,8 @@ struct ata_host *ata_host_alloc(struct device *dev, int max_ports) ...@@ -6112,6 +6140,8 @@ struct ata_host *ata_host_alloc(struct device *dev, int max_ports)
err_out: err_out:
devres_release_group(dev, NULL); devres_release_group(dev, NULL);
err_free:
kfree(host);
return NULL; return NULL;
} }
......
...@@ -224,6 +224,8 @@ static DECLARE_TRANSPORT_CLASS(ata_port_class, ...@@ -224,6 +224,8 @@ static DECLARE_TRANSPORT_CLASS(ata_port_class,
static void ata_tport_release(struct device *dev) 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, ...@@ -284,6 +286,7 @@ int ata_tport_add(struct device *parent,
dev->type = &ata_port_type; dev->type = &ata_port_type;
dev->parent = parent; dev->parent = parent;
ata_host_get(ap->host);
dev->release = ata_tport_release; dev->release = ata_tport_release;
dev_set_name(dev, "ata%d", ap->print_id); dev_set_name(dev, "ata%d", ap->print_id);
transport_setup_device(dev); transport_setup_device(dev);
...@@ -314,6 +317,7 @@ int ata_tport_add(struct device *parent, ...@@ -314,6 +317,7 @@ int ata_tport_add(struct device *parent,
tport_err: tport_err:
transport_destroy_device(dev); transport_destroy_device(dev);
put_device(dev); put_device(dev);
ata_host_put(ap->host);
return error; return error;
} }
......
...@@ -100,6 +100,8 @@ extern int ata_port_probe(struct ata_port *ap); ...@@ -100,6 +100,8 @@ extern int ata_port_probe(struct ata_port *ap);
extern void __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, extern unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
u8 page, void *buf, unsigned int sectors); 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) #define to_ata_port(d) container_of(d, struct ata_port, tdev)
......
...@@ -796,7 +796,7 @@ static int arasan_cf_probe(struct platform_device *pdev) ...@@ -796,7 +796,7 @@ static int arasan_cf_probe(struct platform_device *pdev)
struct resource *res; struct resource *res;
u32 quirk; u32 quirk;
irq_handler_t irq_handler = NULL; irq_handler_t irq_handler = NULL;
int ret = 0; int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) if (!res)
...@@ -809,10 +809,8 @@ static int arasan_cf_probe(struct platform_device *pdev) ...@@ -809,10 +809,8 @@ static int arasan_cf_probe(struct platform_device *pdev)
} }
acdev = devm_kzalloc(&pdev->dev, sizeof(*acdev), GFP_KERNEL); acdev = devm_kzalloc(&pdev->dev, sizeof(*acdev), GFP_KERNEL);
if (!acdev) { if (!acdev)
dev_warn(&pdev->dev, "kzalloc fail\n");
return -ENOMEM; return -ENOMEM;
}
if (pdata) if (pdata)
quirk = pdata->quirk; quirk = pdata->quirk;
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* Palmchip BK3710 PATA controller driver * Palmchip BK3710 PATA controller driver
* *
...@@ -8,10 +10,6 @@ ...@@ -8,10 +10,6 @@
* *
* Copyright (C) 2006 Texas Instruments. * Copyright (C) 2006 Texas Instruments.
* Copyright (C) 2007 MontaVista Software, Inc., <source@mvista.com> * 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> #include <linux/ata.h>
...@@ -379,4 +377,4 @@ static int __init pata_bk3710_init(void) ...@@ -379,4 +377,4 @@ static int __init pata_bk3710_init(void)
} }
module_init(pata_bk3710_init); module_init(pata_bk3710_init);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL v2");
// SPDX-License-Identifier: GPL-2.0
/* /*
* Atari Falcon PATA controller driver * Atari Falcon PATA controller driver
* *
...@@ -7,10 +9,6 @@ ...@@ -7,10 +9,6 @@
* Based on falconide.c: * Based on falconide.c:
* *
* Created 12 Jul 1997 by Geert Uytterhoeven * 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> #include <linux/kernel.h>
...@@ -180,5 +178,5 @@ module_init(pata_falcon_init_one); ...@@ -180,5 +178,5 @@ module_init(pata_falcon_init_one);
MODULE_AUTHOR("Bartlomiej Zolnierkiewicz"); MODULE_AUTHOR("Bartlomiej Zolnierkiewicz");
MODULE_DESCRIPTION("low-level driver for Atari Falcon PATA"); MODULE_DESCRIPTION("low-level driver for Atari Falcon PATA");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL v2");
MODULE_VERSION(DRV_VERSION); MODULE_VERSION(DRV_VERSION);
// 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);
...@@ -658,10 +658,10 @@ static u8 *it821x_firmware_command(struct ata_port *ap, u8 cmd, int len) ...@@ -658,10 +658,10 @@ static u8 *it821x_firmware_command(struct ata_port *ap, u8 cmd, int len)
u8 status; u8 status;
int n = 0; int n = 0;
u16 *buf = kmalloc(len, GFP_KERNEL); u16 *buf = kmalloc(len, GFP_KERNEL);
if (buf == NULL) {
printk(KERN_ERR "it821x_firmware_command: Out of memory\n"); if (!buf)
return NULL; return NULL;
}
/* This isn't quite a normal ATA command as we are talking to the /* This isn't quite a normal ATA command as we are talking to the
firmware not the drives */ firmware not the drives */
ap->ctl |= ATA_NIEN; ap->ctl |= ATA_NIEN;
......
...@@ -1131,11 +1131,9 @@ static int pata_macio_attach(struct macio_dev *mdev, ...@@ -1131,11 +1131,9 @@ static int pata_macio_attach(struct macio_dev *mdev,
/* Allocate and init private data structure */ /* Allocate and init private data structure */
priv = devm_kzalloc(&mdev->ofdev.dev, priv = devm_kzalloc(&mdev->ofdev.dev,
sizeof(struct pata_macio_priv), GFP_KERNEL); sizeof(struct pata_macio_priv), GFP_KERNEL);
if (priv == NULL) { if (!priv)
dev_err(&mdev->ofdev.dev,
"Failed to allocate private memory\n");
return -ENOMEM; return -ENOMEM;
}
priv->node = of_node_get(mdev->ofdev.dev.of_node); priv->node = of_node_get(mdev->ofdev.dev.of_node);
priv->mdev = mdev; priv->mdev = mdev;
priv->dev = &mdev->ofdev.dev; priv->dev = &mdev->ofdev.dev;
...@@ -1277,11 +1275,9 @@ static int pata_macio_pci_attach(struct pci_dev *pdev, ...@@ -1277,11 +1275,9 @@ static int pata_macio_pci_attach(struct pci_dev *pdev,
/* Allocate and init private data structure */ /* Allocate and init private data structure */
priv = devm_kzalloc(&pdev->dev, priv = devm_kzalloc(&pdev->dev,
sizeof(struct pata_macio_priv), GFP_KERNEL); sizeof(struct pata_macio_priv), GFP_KERNEL);
if (priv == NULL) { if (!priv)
dev_err(&pdev->dev,
"Failed to allocate private memory\n");
return -ENOMEM; return -ENOMEM;
}
priv->node = of_node_get(np); priv->node = of_node_get(np);
priv->pdev = pdev; priv->pdev = pdev;
priv->dev = &pdev->dev; priv->dev = &pdev->dev;
......
...@@ -738,7 +738,6 @@ static int mpc52xx_ata_probe(struct platform_device *op) ...@@ -738,7 +738,6 @@ static int mpc52xx_ata_probe(struct platform_device *op)
/* Prepare our private structure */ /* Prepare our private structure */
priv = devm_kzalloc(&op->dev, sizeof(*priv), GFP_ATOMIC); priv = devm_kzalloc(&op->dev, sizeof(*priv), GFP_ATOMIC);
if (!priv) { if (!priv) {
dev_err(&op->dev, "error allocating private structure\n");
rv = -ENOMEM; rv = -ENOMEM;
goto err1; goto err1;
} }
......
...@@ -505,10 +505,8 @@ static int __init pata_s3c_probe(struct platform_device *pdev) ...@@ -505,10 +505,8 @@ static int __init pata_s3c_probe(struct platform_device *pdev)
cpu_type = platform_get_device_id(pdev)->driver_data; cpu_type = platform_get_device_id(pdev)->driver_data;
info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
if (!info) { if (!info)
dev_err(dev, "failed to allocate memory for device data\n");
return -ENOMEM; return -ENOMEM;
}
info->irq = platform_get_irq(pdev, 0); info->irq = platform_get_irq(pdev, 0);
......
...@@ -901,7 +901,6 @@ static int sata_dwc_port_start(struct ata_port *ap) ...@@ -901,7 +901,6 @@ static int sata_dwc_port_start(struct ata_port *ap)
/* Allocate Port Struct */ /* Allocate Port Struct */
hsdevp = kzalloc(sizeof(*hsdevp), GFP_KERNEL); hsdevp = kzalloc(sizeof(*hsdevp), GFP_KERNEL);
if (!hsdevp) { if (!hsdevp) {
dev_err(ap->dev, "%s: kmalloc failed for hsdevp\n", __func__);
err = -ENOMEM; err = -ENOMEM;
goto CLEANUP; goto CLEANUP;
} }
......
...@@ -617,6 +617,7 @@ struct ata_host { ...@@ -617,6 +617,7 @@ struct ata_host {
void *private_data; void *private_data;
struct ata_port_operations *ops; struct ata_port_operations *ops;
unsigned long flags; unsigned long flags;
struct kref kref;
struct mutex eh_mutex; struct mutex eh_mutex;
struct task_struct *eh_owner; struct task_struct *eh_owner;
......
...@@ -243,6 +243,8 @@ ...@@ -243,6 +243,8 @@
#define IMX6Q_GPR4_IPU_RD_CACHE_CTL BIT(0) #define IMX6Q_GPR4_IPU_RD_CACHE_CTL BIT(0)
#define IMX6Q_GPR5_L2_CLK_STOP BIT(8) #define IMX6Q_GPR5_L2_CLK_STOP BIT(8)
#define IMX6Q_GPR5_SATA_SW_PD BIT(10)
#define IMX6Q_GPR5_SATA_SW_RST BIT(11)
#define IMX6Q_GPR6_IPU1_ID00_WR_QOS_MASK (0xf << 0) #define IMX6Q_GPR6_IPU1_ID00_WR_QOS_MASK (0xf << 0)
#define IMX6Q_GPR6_IPU1_ID01_WR_QOS_MASK (0xf << 4) #define IMX6Q_GPR6_IPU1_ID01_WR_QOS_MASK (0xf << 4)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment