提交 a23867f1 编写于 作者: L 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()
  ...
......@@ -30,6 +30,7 @@ compatible:
Optional properties:
- dma-coherent : Present if dma operations are coherent
- clocks : a list of phandle + clock specifier pairs
- resets : a list of phandle + reset specifier pairs
- target-supply : regulator for SATA target power
- phys : reference to the SATA PHY node
- phy-names : must be "sata-phy"
......
......@@ -7,6 +7,7 @@ Required properties:
- compatible : should be one of the following:
- "fsl,imx53-ahci" for i.MX53 SATA controller
- "fsl,imx6q-ahci" for i.MX6Q SATA controller
- "fsl,imx6qp-ahci" for i.MX6QP SATA controller
- interrupts : interrupt mapping for SATA IRQ
- reg : registers mapping
- clocks : list of clock specifiers, must contain an entry for each
......
Tegra124 SoC SATA AHCI controller
Tegra SoC SATA AHCI controller
Required properties :
- compatible : For Tegra124, must contain "nvidia,tegra124-ahci". Otherwise,
must contain '"nvidia,<chip>-ahci", "nvidia,tegra124-ahci"', where <chip>
is tegra132.
- compatible : Must be one of:
- Tegra124 : "nvidia,tegra124-ahci"
- Tegra132 : "nvidia,tegra132-ahci", "nvidia,tegra124-ahci"
- Tegra210 : "nvidia,tegra210-ahci"
- reg : Should contain 2 entries:
- AHCI register set (SATA BAR5)
- SATA register set
......@@ -13,8 +14,6 @@ Required properties :
- clock-names : Must include the following entries:
- sata
- sata-oob
- cml1
- pll_e
- resets : Must contain an entry for each entry in reset-names.
See ../reset/reset.txt for details.
- reset-names : Must include the following entries:
......@@ -24,9 +23,22 @@ Required properties :
- phys : Must contain an entry for each entry in phy-names.
See ../phy/phy-bindings.txt for details.
- phy-names : Must include the following entries:
- For Tegra124 and Tegra132:
- sata-phy : XUSB PADCTL SATA PHY
- hvdd-supply : Defines the SATA HVDD regulator
- vddio-supply : Defines the SATA VDDIO 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
- For Tegra124 and Tegra132:
- hvdd-supply : Defines the SATA HVDD regulator
- vddio-supply : Defines the SATA VDDIO 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
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
......
......@@ -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
......
......@@ -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
......
......@@ -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);
......
......@@ -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 @@ static int tegra_ahci_power_on(struct ahci_host_priv *hpriv)
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);
/* 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);
writel(0, tegra->sata_regs + SCFG_OFFSET + T_SATA0_INDEX);
if (tegra->soc->ops && tegra->soc->ops->init)
tegra->soc->ops->init(hpriv);
/* Program controller device ID */
/*
* 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 */
/* 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 = 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_AHCI_IDP1_DATA;
writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_AHCI_IDP1);
/* Program SATA MMIO */
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);
writel(0x10000 << SATA_FPCI_BAR5_START_SHIFT,
tegra->sata_regs + SATA_FPCI_BAR5);
/* 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");
......@@ -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);
/*
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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)
......
......@@ -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;
......
// 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");
// 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);
// 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)
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;
......
......@@ -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;
......
......@@ -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;
}
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -617,6 +617,7 @@ struct ata_host {
void *private_data;
struct ata_port_operations *ops;
unsigned long flags;
struct kref kref;
struct mutex eh_mutex;
struct task_struct *eh_owner;
......
......@@ -243,6 +243,8 @@
#define IMX6Q_GPR4_IPU_RD_CACHE_CTL BIT(0)
#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_ID01_WR_QOS_MASK (0xf << 4)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册