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() ...
This commit is contained in:
Коммит
a23867f1d2
|
@ -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
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
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:
|
||||
- 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:
|
||||
- sata-phy : XUSB PADCTL SATA PHY
|
||||
- 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, ®);
|
||||
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 @@ disable_power:
|
|||
tegra_powergate_power_off(TEGRA_POWERGATE_SATA);
|
||||
|
||||
disable_regulators:
|
||||
regulator_bulk_disable(ARRAY_SIZE(tegra->supplies), tegra->supplies);
|
||||
regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -162,15 +291,14 @@ static void tegra_ahci_power_off(struct ahci_host_priv *hpriv)
|
|||
clk_disable_unprepare(tegra->sata_clk);
|
||||
tegra_powergate_power_off(TEGRA_POWERGATE_SATA);
|
||||
|
||||
regulator_bulk_disable(ARRAY_SIZE(tegra->supplies), tegra->supplies);
|
||||
regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies);
|
||||
}
|
||||
|
||||
static int tegra_ahci_controller_init(struct ahci_host_priv *hpriv)
|
||||
{
|
||||
struct tegra_ahci_priv *tegra = hpriv->plat_data;
|
||||
int ret;
|
||||
unsigned int val;
|
||||
struct sata_pad_calibration calib;
|
||||
u32 val;
|
||||
|
||||
ret = tegra_ahci_power_on(hpriv);
|
||||
if (ret) {
|
||||
|
@ -179,78 +307,115 @@ static int tegra_ahci_controller_init(struct ahci_host_priv *hpriv)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Program the following SATA IPFS registers to allow SW accesses to
|
||||
* SATA's MMIO register range.
|
||||
*/
|
||||
val = readl(tegra->sata_regs + SATA_FPCI_BAR5);
|
||||
val &= ~(SATA_FPCI_BAR5_START_MASK | SATA_FPCI_BAR5_ACCESS_TYPE);
|
||||
val |= SATA_FPCI_BAR5_START | SATA_FPCI_BAR5_ACCESS_TYPE;
|
||||
writel(val, tegra->sata_regs + SATA_FPCI_BAR5);
|
||||
|
||||
/* Program the following SATA IPFS register to enable the SATA */
|
||||
val = readl(tegra->sata_regs + SATA_CONFIGURATION_0);
|
||||
val |= SATA_CONFIGURATION_EN_FPCI;
|
||||
val |= SATA_CONFIGURATION_0_EN_FPCI;
|
||||
writel(val, tegra->sata_regs + SATA_CONFIGURATION_0);
|
||||
|
||||
/* Pad calibration */
|
||||
/* 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);
|
||||
|
||||
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;
|
||||
}
|
||||
/* For SQUELCH Filter & Gen3 drive getting detected as Gen1 drive */
|
||||
|
||||
calib = tegra124_pad_calibration[val & FUSE_SATA_CALIB_MASK];
|
||||
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);
|
||||
|
||||
writel(BIT(0), tegra->sata_regs + SCFG_OFFSET + T_SATA0_INDEX);
|
||||
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);
|
||||
|
||||
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);
|
||||
/*
|
||||
* 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);
|
||||
|
||||
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);
|
||||
if (tegra->soc->ops && tegra->soc->ops->init)
|
||||
tegra->soc->ops->init(hpriv);
|
||||
|
||||
writel(T_SATA0_CHX_PHY_CTRL11_GEN2_RX_EQ,
|
||||
tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL11);
|
||||
writel(T_SATA0_CHX_PHY_CTRL2_CDR_CNTL_GEN1,
|
||||
tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL2);
|
||||
|
||||
writel(0, tegra->sata_regs + SCFG_OFFSET + T_SATA0_INDEX);
|
||||
|
||||
/* Program controller device ID */
|
||||
/*
|
||||
* 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);
|
||||
|
||||
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);
|
||||
/* 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);
|
||||
|
||||
/* Program SATA MMIO */
|
||||
val = T_SATA0_AHCI_IDP1_DATA;
|
||||
writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_AHCI_IDP1);
|
||||
|
||||
writel(0x10000 << SATA_FPCI_BAR5_START_SHIFT,
|
||||
tegra->sata_regs + SATA_FPCI_BAR5);
|
||||
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(0x08000 << T_SATA0_CFG_9_BASE_ADDRESS_SHIFT,
|
||||
tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_9);
|
||||
/* 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);
|
||||
|
||||
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;
|
||||
|
||||
ret = devm_regulator_bulk_get(&pdev->dev, ARRAY_SIZE(tegra->supplies),
|
||||
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,
|
||||
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;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
/*
|
||||
* Palmchip BK3710 PATA controller driver
|
||||
*
|
||||
|
@ -8,10 +10,6 @@
|
|||
*
|
||||
* Copyright (C) 2006 Texas Instruments.
|
||||
* Copyright (C) 2007 MontaVista Software, Inc., <source@mvista.com>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <linux/ata.h>
|
||||
|
@ -379,4 +377,4 @@ static int __init pata_bk3710_init(void)
|
|||
}
|
||||
|
||||
module_init(pata_bk3710_init);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
/*
|
||||
* Atari Falcon PATA controller driver
|
||||
*
|
||||
|
@ -7,10 +9,6 @@
|
|||
* Based on falconide.c:
|
||||
*
|
||||
* Created 12 Jul 1997 by Geert Uytterhoeven
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
@ -180,5 +178,5 @@ module_init(pata_falcon_init_one);
|
|||
|
||||
MODULE_AUTHOR("Bartlomiej Zolnierkiewicz");
|
||||
MODULE_DESCRIPTION("low-level driver for Atari Falcon PATA");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
|
|
|
@ -0,0 +1,219 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
/*
|
||||
* Amiga Gayle PATA controller driver
|
||||
*
|
||||
* Copyright (c) 2018 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* Based on gayle.c:
|
||||
*
|
||||
* Created 12 Jul 1997 by Geert Uytterhoeven
|
||||
*/
|
||||
|
||||
#include <linux/ata.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/libata.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/zorro.h>
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
|
||||
#include <asm/amigahw.h>
|
||||
#include <asm/amigaints.h>
|
||||
#include <asm/amigayle.h>
|
||||
#include <asm/ide.h>
|
||||
#include <asm/setup.h>
|
||||
|
||||
#define DRV_NAME "pata_gayle"
|
||||
#define DRV_VERSION "0.1.0"
|
||||
|
||||
#define GAYLE_CONTROL 0x101a
|
||||
|
||||
static struct scsi_host_template pata_gayle_sht = {
|
||||
ATA_PIO_SHT(DRV_NAME),
|
||||
};
|
||||
|
||||
/* FIXME: is this needed? */
|
||||
static unsigned int pata_gayle_data_xfer(struct ata_queued_cmd *qc,
|
||||
unsigned char *buf,
|
||||
unsigned int buflen, int rw)
|
||||
{
|
||||
struct ata_device *dev = qc->dev;
|
||||
struct ata_port *ap = dev->link->ap;
|
||||
void __iomem *data_addr = ap->ioaddr.data_addr;
|
||||
unsigned int words = buflen >> 1;
|
||||
|
||||
/* Transfer multiple of 2 bytes */
|
||||
if (rw == READ)
|
||||
raw_insw((u16 *)data_addr, (u16 *)buf, words);
|
||||
else
|
||||
raw_outsw((u16 *)data_addr, (u16 *)buf, words);
|
||||
|
||||
/* Transfer trailing byte, if any. */
|
||||
if (unlikely(buflen & 0x01)) {
|
||||
unsigned char pad[2] = { };
|
||||
|
||||
/* Point buf to the tail of buffer */
|
||||
buf += buflen - 1;
|
||||
|
||||
if (rw == READ) {
|
||||
raw_insw((u16 *)data_addr, (u16 *)pad, 1);
|
||||
*buf = pad[0];
|
||||
} else {
|
||||
pad[0] = *buf;
|
||||
raw_outsw((u16 *)data_addr, (u16 *)pad, 1);
|
||||
}
|
||||
words++;
|
||||
}
|
||||
|
||||
return words << 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Provide our own set_mode() as we don't want to change anything that has
|
||||
* already been configured..
|
||||
*/
|
||||
static int pata_gayle_set_mode(struct ata_link *link,
|
||||
struct ata_device **unused)
|
||||
{
|
||||
struct ata_device *dev;
|
||||
|
||||
ata_for_each_dev(dev, link, ENABLED) {
|
||||
/* We don't really care */
|
||||
dev->pio_mode = dev->xfer_mode = XFER_PIO_0;
|
||||
dev->xfer_shift = ATA_SHIFT_PIO;
|
||||
dev->flags |= ATA_DFLAG_PIO;
|
||||
ata_dev_info(dev, "configured for PIO\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool pata_gayle_irq_check(struct ata_port *ap)
|
||||
{
|
||||
u8 ch;
|
||||
|
||||
ch = z_readb((unsigned long)ap->private_data);
|
||||
|
||||
return !!(ch & GAYLE_IRQ_IDE);
|
||||
}
|
||||
|
||||
static void pata_gayle_irq_clear(struct ata_port *ap)
|
||||
{
|
||||
(void)z_readb((unsigned long)ap->ioaddr.status_addr);
|
||||
z_writeb(0x7c, (unsigned long)ap->private_data);
|
||||
}
|
||||
|
||||
static struct ata_port_operations pata_gayle_a1200_ops = {
|
||||
.inherits = &ata_sff_port_ops,
|
||||
.sff_data_xfer = pata_gayle_data_xfer,
|
||||
.sff_irq_check = pata_gayle_irq_check,
|
||||
.sff_irq_clear = pata_gayle_irq_clear,
|
||||
.cable_detect = ata_cable_unknown,
|
||||
.set_mode = pata_gayle_set_mode,
|
||||
};
|
||||
|
||||
static struct ata_port_operations pata_gayle_a4000_ops = {
|
||||
.inherits = &ata_sff_port_ops,
|
||||
.sff_data_xfer = pata_gayle_data_xfer,
|
||||
.cable_detect = ata_cable_unknown,
|
||||
.set_mode = pata_gayle_set_mode,
|
||||
};
|
||||
|
||||
static int __init pata_gayle_init_one(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct gayle_ide_platform_data *pdata;
|
||||
struct ata_host *host;
|
||||
struct ata_port *ap;
|
||||
void __iomem *base;
|
||||
int ret;
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
|
||||
dev_info(&pdev->dev, "Amiga Gayle IDE controller (A%u style)\n",
|
||||
pdata->explicit_ack ? 1200 : 4000);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENODEV;
|
||||
|
||||
if (!devm_request_mem_region(&pdev->dev, res->start,
|
||||
resource_size(res), DRV_NAME)) {
|
||||
pr_err(DRV_NAME ": resources busy\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* allocate host */
|
||||
host = ata_host_alloc(&pdev->dev, 1);
|
||||
if (!host)
|
||||
return -ENOMEM;
|
||||
|
||||
ap = host->ports[0];
|
||||
|
||||
if (pdata->explicit_ack)
|
||||
ap->ops = &pata_gayle_a1200_ops;
|
||||
else
|
||||
ap->ops = &pata_gayle_a4000_ops;
|
||||
|
||||
ap->pio_mask = ATA_PIO4;
|
||||
ap->flags |= ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_IORDY;
|
||||
|
||||
base = ZTWO_VADDR(pdata->base);
|
||||
ap->ioaddr.data_addr = base;
|
||||
ap->ioaddr.error_addr = base + 2 + 1 * 4;
|
||||
ap->ioaddr.feature_addr = base + 2 + 1 * 4;
|
||||
ap->ioaddr.nsect_addr = base + 2 + 2 * 4;
|
||||
ap->ioaddr.lbal_addr = base + 2 + 3 * 4;
|
||||
ap->ioaddr.lbam_addr = base + 2 + 4 * 4;
|
||||
ap->ioaddr.lbah_addr = base + 2 + 5 * 4;
|
||||
ap->ioaddr.device_addr = base + 2 + 6 * 4;
|
||||
ap->ioaddr.status_addr = base + 2 + 7 * 4;
|
||||
ap->ioaddr.command_addr = base + 2 + 7 * 4;
|
||||
|
||||
ap->ioaddr.altstatus_addr = base + GAYLE_CONTROL;
|
||||
ap->ioaddr.ctl_addr = base + GAYLE_CONTROL;
|
||||
|
||||
ap->private_data = (void *)ZTWO_VADDR(pdata->irqport);
|
||||
|
||||
ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", pdata->base,
|
||||
pdata->base + GAYLE_CONTROL);
|
||||
|
||||
ret = ata_host_activate(host, IRQ_AMIGA_PORTS, ata_sff_interrupt,
|
||||
IRQF_SHARED, &pata_gayle_sht);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
platform_set_drvdata(pdev, host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __exit pata_gayle_remove_one(struct platform_device *pdev)
|
||||
{
|
||||
struct ata_host *host = platform_get_drvdata(pdev);
|
||||
|
||||
ata_host_detach(host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver pata_gayle_driver = {
|
||||
.remove = __exit_p(pata_gayle_remove_one),
|
||||
.driver = {
|
||||
.name = "amiga-gayle-ide",
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver_probe(pata_gayle_driver, pata_gayle_init_one);
|
||||
|
||||
MODULE_AUTHOR("Bartlomiej Zolnierkiewicz");
|
||||
MODULE_DESCRIPTION("low-level driver for Amiga Gayle PATA");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:amiga-gayle-ide");
|
||||
MODULE_VERSION(DRV_VERSION);
|
|
@ -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)
|
||||
|
|
Загрузка…
Ссылка в новой задаче