Commit a23867f1 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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