summaryrefslogtreecommitdiff
path: root/drivers/ata/ahci_imx.c
diff options
context:
space:
mode:
authorRichard Zhu <hongxing.zhu@nxp.com>2018-10-30 15:20:50 +0800
committerDong Aisheng <aisheng.dong@nxp.com>2019-11-25 15:45:47 +0800
commit0adaace11baee3348ab65e22b10c254ca69604ad (patch)
tree2249a2f71edadeda093e781e0de03cd91e5f5c9a /drivers/ata/ahci_imx.c
parentf32935f38771ef30990f49ba461da0cfef9603c3 (diff)
ata: imx: enhance the codes to enable imx8qm sata
- Add one ext_osc parameter for imx8qm ahci. Add one parameter to distinguish the different ref_clk source, internal pll or the external osc. NOTE: The value of the ext_osc should be aligned to the one of the PCIe's, since both of them share one ref_clk source. - Fix can't find ahb clk issue. The ahb clock is not mandatory required by iMX8QM SATA, fetch it only when there is "ahb" clock. - Specify the 32-bit dma limitation and the softreset for iMX8QM SATA. - Use the standard ahci_error_handler on iMX8QM SATA. Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
Diffstat (limited to 'drivers/ata/ahci_imx.c')
-rw-r--r--drivers/ata/ahci_imx.c105
1 files changed, 74 insertions, 31 deletions
diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c
index db01ede0fdc2..975ba760b546 100644
--- a/drivers/ata/ahci_imx.c
+++ b/drivers/ata/ahci_imx.c
@@ -139,6 +139,7 @@ struct imx_ahci_priv {
bool first_time;
u32 phy_params;
u32 imped_ratio;
+ u32 ext_osc;
};
void *sg_io_buffer_hack;
@@ -563,18 +564,32 @@ static int imx8_sata_enable(struct ahci_host_priv *hpriv)
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);
+ if (imxpriv->ext_osc) {
+ dev_info(dev, "external osc is used.\n");
+ /*
+ * bit0 rx ena 1, bit1 tx ena 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);
+ } else {
+ dev_info(dev, "internal pll is used.\n");
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_MISC_OFFSET,
+ IMX8QM_MISC_IOB_RXENA,
+ 0);
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_MISC_OFFSET,
+ IMX8QM_MISC_IOB_TXENA,
+ IMX8QM_MISC_IOB_TXENA);
+
+ }
regmap_update_bits(imxpriv->gpr,
IMX8QM_CSR_MISC_OFFSET,
IMX8QM_MISC_PHYX1_EPCS_SEL,
@@ -846,7 +861,8 @@ static void ahci_imx_error_handler(struct ata_port *ap)
ahci_error_handler(ap);
- if (!(imxpriv->first_time) || ahci_imx_hotplug)
+ if (!(imxpriv->first_time) || ahci_imx_hotplug ||
+ (imxpriv->type == AHCI_IMX8QM))
return;
imxpriv->first_time = false;
@@ -1072,13 +1088,29 @@ static struct scsi_host_template ahci_platform_sht = {
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))
+ if (!(dev->bus_dma_mask)) {
+ dev->bus_dma_mask = DMA_BIT_MASK(32);
+ dev_info(dev, "imx8qm sata only supports 32bit dma.\n");
+ }
+ if (of_property_read_u32(np, "ext_osc", &imxpriv->ext_osc) < 0) {
+ dev_info(dev, "ext_osc is not specified.\n");
+ /* Use the external osc as ref clk defaultly. */
+ imxpriv->ext_osc = 1;
+ }
+
+ if (of_property_read_u32(np, "fsl,phy-imp", &imxpriv->imped_ratio)) {
+ /*
+ * Regarding to the differnet Hw designs,
+ * Set the impedance ratio to 0x6c when 85OHM is used.
+ * Keep it to default value 0x80, when 100OHM is used.
+ */
+ dev_info(dev, "phy impedance ratio is not specified.\n");
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,
@@ -1127,15 +1159,9 @@ static int imx8_sata_probe(struct device *dev, struct imx_ahci_priv *imxpriv)
/* 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,
+ 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;
}
@@ -1275,12 +1301,6 @@ static int imx_ahci_probe(struct platform_device *pdev)
return PTR_ERR(imxpriv->sata_ref_clk);
}
- imxpriv->ahb_clk = devm_clk_get(dev, "ahb");
- if (IS_ERR(imxpriv->ahb_clk)) {
- dev_err(dev, "can't get ahb clock.\n");
- return PTR_ERR(imxpriv->ahb_clk);
- }
-
if (imxpriv->type == AHCI_IMX6Q || imxpriv->type == AHCI_IMX6QP) {
u32 reg_value;
@@ -1357,8 +1377,17 @@ static int imx_ahci_probe(struct platform_device *pdev)
writel(reg_val, hpriv->mmio + HOST_PORTS_IMPL);
}
- reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
- writel(reg_val, hpriv->mmio + IMX_TIMER1MS);
+ imxpriv->ahb_clk = devm_clk_get(dev, "ahb");
+ if (IS_ERR(imxpriv->ahb_clk)) {
+ dev_info(dev, "no ahb clock.\n");
+ } else {
+ /*
+ * AHB clock is only used to configure the vendor specified
+ * TIMER1MS register. Set it if the AHB clock is defined.
+ */
+ reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
+ writel(reg_val, hpriv->mmio + IMX_TIMER1MS);
+ }
/*
* Due to IP bug on the Synopsis 3.00 SATA version,
@@ -1462,7 +1491,21 @@ static struct platform_driver imx_ahci_driver = {
.pm = &ahci_imx_pm_ops,
},
};
-module_platform_driver(imx_ahci_driver);
+
+static int __init imx_ahci_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&imx_ahci_driver);
+ if (ret)
+ pr_err("Unable to initialize imx ahci driver\n");
+ else
+ pr_info("imx ahci driver is registered.\n");
+
+ return ret;
+}
+
+device_initcall(imx_ahci_init);
MODULE_DESCRIPTION("Freescale i.MX AHCI SATA platform driver");
MODULE_AUTHOR("Richard Zhu <Hong-Xing.Zhu@freescale.com>");