Commit 4a23d179 authored by Marek Vasut's avatar Marek Vasut Committed by Tejun Heo

ahci: imx: Add i.MX53 support

Add minor adjustments to support i.MX53 SATA port as well as i.MX6Q one.
The difference here is mostly the clock which need to be enabled and also
the lack of need of programming IOMUXC registers on i.MX53. All of which
is well handles in the clock enable/disable functions. Note that this patch
also cleans up the names of the common functions, so they don't read imx6q_*
but imx_* instead.
Signed-off-by: default avatarMarek Vasut <marex@denx.de>
Reviewed-by: default avatarShawn Guo <shawn.guo@linaro.org>
Cc: Richard Zhu <r65037@freescale.com>
Cc: Linux-IDE <linux-ide@vger.kernel.org>
Signed-off-by: default avatarTejun Heo <tj@kernel.org>
parent 8403e2ec
...@@ -34,10 +34,21 @@ enum { ...@@ -34,10 +34,21 @@ enum {
HOST_TIMER1MS = 0xe0, /* Timer 1-ms */ HOST_TIMER1MS = 0xe0, /* Timer 1-ms */
}; };
enum ahci_imx_type {
AHCI_IMX53,
AHCI_IMX6Q,
};
struct imx_ahci_priv { struct imx_ahci_priv {
struct platform_device *ahci_pdev; struct platform_device *ahci_pdev;
enum ahci_imx_type type;
/* i.MX53 clock */
struct clk *sata_gate_clk;
/* Common clock */
struct clk *sata_ref_clk; struct clk *sata_ref_clk;
struct clk *ahb_clk; struct clk *ahb_clk;
struct regmap *gpr; struct regmap *gpr;
bool no_device; bool no_device;
bool first_time; bool first_time;
...@@ -52,29 +63,52 @@ static int imx_sata_clock_enable(struct device *dev) ...@@ -52,29 +63,52 @@ static int imx_sata_clock_enable(struct device *dev)
struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent); struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
int ret; int ret;
ret = clk_prepare_enable(imxpriv->sata_ref_clk); if (imxpriv->type == AHCI_IMX53) {
ret = clk_prepare_enable(imxpriv->sata_gate_clk);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "prepare-enable sata_ref clock err:%d\n", ret); dev_err(dev, "prepare-enable sata_gate clock err:%d\n",
ret);
return ret; return ret;
} }
}
ret = clk_prepare_enable(imxpriv->sata_ref_clk);
if (ret < 0) {
dev_err(dev, "prepare-enable sata_ref clock err:%d\n",
ret);
goto clk_err;
}
if (imxpriv->type == AHCI_IMX6Q) {
regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
IMX6Q_GPR13_SATA_MPLL_CLK_EN, IMX6Q_GPR13_SATA_MPLL_CLK_EN,
IMX6Q_GPR13_SATA_MPLL_CLK_EN); IMX6Q_GPR13_SATA_MPLL_CLK_EN);
}
usleep_range(1000, 2000); usleep_range(1000, 2000);
return 0; return 0;
clk_err:
if (imxpriv->type == AHCI_IMX53)
clk_disable_unprepare(imxpriv->sata_gate_clk);
return ret;
} }
static void imx_sata_clock_disable(struct device *dev) static void imx_sata_clock_disable(struct device *dev)
{ {
struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent); struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
if (imxpriv->type == AHCI_IMX6Q) {
regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
IMX6Q_GPR13_SATA_MPLL_CLK_EN, IMX6Q_GPR13_SATA_MPLL_CLK_EN,
!IMX6Q_GPR13_SATA_MPLL_CLK_EN); !IMX6Q_GPR13_SATA_MPLL_CLK_EN);
}
clk_disable_unprepare(imxpriv->sata_ref_clk); clk_disable_unprepare(imxpriv->sata_ref_clk);
if (imxpriv->type == AHCI_IMX53)
clk_disable_unprepare(imxpriv->sata_gate_clk);
} }
static void ahci_imx_error_handler(struct ata_port *ap) static void ahci_imx_error_handler(struct ata_port *ap)
...@@ -106,9 +140,25 @@ static void ahci_imx_error_handler(struct ata_port *ap) ...@@ -106,9 +140,25 @@ static void ahci_imx_error_handler(struct ata_port *ap)
imxpriv->no_device = true; imxpriv->no_device = true;
} }
int ahci_imx_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
struct ata_port *ap = link->ap;
struct imx_ahci_priv *imxpriv = dev_get_drvdata(ap->dev->parent);
int ret = -EIO;
if (imxpriv->type == AHCI_IMX53)
ret = ahci_pmp_retry_srst_ops.softreset(link, class, deadline);
else if (imxpriv->type == AHCI_IMX6Q)
ret = ahci_ops.softreset(link, class, deadline);
return ret;
}
static struct ata_port_operations ahci_imx_ops = { static struct ata_port_operations ahci_imx_ops = {
.inherits = &ahci_platform_ops, .inherits = &ahci_platform_ops,
.error_handler = ahci_imx_error_handler, .error_handler = ahci_imx_error_handler,
.softreset = ahci_imx_softreset,
}; };
static const struct ata_port_info ahci_imx_port_info = { static const struct ata_port_info ahci_imx_port_info = {
...@@ -118,7 +168,7 @@ static const struct ata_port_info ahci_imx_port_info = { ...@@ -118,7 +168,7 @@ static const struct ata_port_info ahci_imx_port_info = {
.port_ops = &ahci_imx_ops, .port_ops = &ahci_imx_ops,
}; };
static int imx6q_sata_init(struct device *dev, void __iomem *mmio) static int imx_sata_init(struct device *dev, void __iomem *mmio)
{ {
int ret = 0; int ret = 0;
unsigned int reg_val; unsigned int reg_val;
...@@ -152,7 +202,7 @@ static int imx6q_sata_init(struct device *dev, void __iomem *mmio) ...@@ -152,7 +202,7 @@ static int imx6q_sata_init(struct device *dev, void __iomem *mmio)
return 0; return 0;
} }
static void imx6q_sata_exit(struct device *dev) static void imx_sata_exit(struct device *dev)
{ {
imx_sata_clock_disable(dev); imx_sata_clock_disable(dev);
} }
...@@ -182,16 +232,18 @@ static int imx_ahci_resume(struct device *dev) ...@@ -182,16 +232,18 @@ static int imx_ahci_resume(struct device *dev)
return ret; return ret;
} }
static struct ahci_platform_data imx6q_sata_pdata = { static struct ahci_platform_data imx_sata_pdata = {
.init = imx6q_sata_init, .init = imx_sata_init,
.exit = imx6q_sata_exit, .exit = imx_sata_exit,
.ata_port_info = &ahci_imx_port_info, .ata_port_info = &ahci_imx_port_info,
.suspend = imx_ahci_suspend, .suspend = imx_ahci_suspend,
.resume = imx_ahci_resume, .resume = imx_ahci_resume,
}; };
static const struct of_device_id imx_ahci_of_match[] = { static const struct of_device_id imx_ahci_of_match[] = {
{ .compatible = "fsl,imx6q-ahci", .data = &imx6q_sata_pdata}, { .compatible = "fsl,imx53-ahci", .data = (void *)AHCI_IMX53 },
{ .compatible = "fsl,imx6q-ahci", .data = (void *)AHCI_IMX6Q },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, imx_ahci_of_match); MODULE_DEVICE_TABLE(of, imx_ahci_of_match);
...@@ -201,12 +253,20 @@ static int imx_ahci_probe(struct platform_device *pdev) ...@@ -201,12 +253,20 @@ static int imx_ahci_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct resource *mem, *irq, res[2]; struct resource *mem, *irq, res[2];
const struct of_device_id *of_id; const struct of_device_id *of_id;
enum ahci_imx_type type;
const struct ahci_platform_data *pdata = NULL; const struct ahci_platform_data *pdata = NULL;
struct imx_ahci_priv *imxpriv; struct imx_ahci_priv *imxpriv;
struct device *ahci_dev; struct device *ahci_dev;
struct platform_device *ahci_pdev; struct platform_device *ahci_pdev;
int ret; int ret;
of_id = of_match_device(imx_ahci_of_match, dev);
if (!of_id)
return -EINVAL;
type = (enum ahci_imx_type)of_id->data;
pdata = &imx_sata_pdata;
imxpriv = devm_kzalloc(dev, sizeof(*imxpriv), GFP_KERNEL); imxpriv = devm_kzalloc(dev, sizeof(*imxpriv), GFP_KERNEL);
if (!imxpriv) { if (!imxpriv) {
dev_err(dev, "can't alloc ahci_host_priv\n"); dev_err(dev, "can't alloc ahci_host_priv\n");
...@@ -222,6 +282,8 @@ static int imx_ahci_probe(struct platform_device *pdev) ...@@ -222,6 +282,8 @@ static int imx_ahci_probe(struct platform_device *pdev)
imxpriv->no_device = false; imxpriv->no_device = false;
imxpriv->first_time = true; imxpriv->first_time = true;
imxpriv->type = type;
imxpriv->ahb_clk = devm_clk_get(dev, "ahb"); imxpriv->ahb_clk = devm_clk_get(dev, "ahb");
if (IS_ERR(imxpriv->ahb_clk)) { if (IS_ERR(imxpriv->ahb_clk)) {
dev_err(dev, "can't get ahb clock.\n"); dev_err(dev, "can't get ahb clock.\n");
...@@ -229,6 +291,15 @@ static int imx_ahci_probe(struct platform_device *pdev) ...@@ -229,6 +291,15 @@ static int imx_ahci_probe(struct platform_device *pdev)
goto err_out; goto err_out;
} }
if (type == AHCI_IMX53) {
imxpriv->sata_gate_clk = devm_clk_get(dev, "sata_gate");
if (IS_ERR(imxpriv->sata_gate_clk)) {
dev_err(dev, "can't get sata_gate clock.\n");
ret = PTR_ERR(imxpriv->sata_gate_clk);
goto err_out;
}
}
imxpriv->sata_ref_clk = devm_clk_get(dev, "sata_ref"); imxpriv->sata_ref_clk = devm_clk_get(dev, "sata_ref");
if (IS_ERR(imxpriv->sata_ref_clk)) { if (IS_ERR(imxpriv->sata_ref_clk)) {
dev_err(dev, "can't get sata_ref clock.\n"); dev_err(dev, "can't get sata_ref clock.\n");
...@@ -239,14 +310,6 @@ static int imx_ahci_probe(struct platform_device *pdev) ...@@ -239,14 +310,6 @@ static int imx_ahci_probe(struct platform_device *pdev)
imxpriv->ahci_pdev = ahci_pdev; imxpriv->ahci_pdev = ahci_pdev;
platform_set_drvdata(pdev, imxpriv); platform_set_drvdata(pdev, imxpriv);
of_id = of_match_device(imx_ahci_of_match, dev);
if (of_id) {
pdata = of_id->data;
} else {
ret = -EINVAL;
goto err_out;
}
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!mem || !irq) { if (!mem || !irq) {
...@@ -262,19 +325,19 @@ static int imx_ahci_probe(struct platform_device *pdev) ...@@ -262,19 +325,19 @@ static int imx_ahci_probe(struct platform_device *pdev)
ahci_dev->dma_mask = &ahci_dev->coherent_dma_mask; ahci_dev->dma_mask = &ahci_dev->coherent_dma_mask;
ahci_dev->of_node = dev->of_node; ahci_dev->of_node = dev->of_node;
imxpriv->gpr = if (type == AHCI_IMX6Q) {
syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); imxpriv->gpr = syscon_regmap_lookup_by_compatible(
"fsl,imx6q-iomuxc-gpr");
if (IS_ERR(imxpriv->gpr)) { if (IS_ERR(imxpriv->gpr)) {
dev_err(dev, "failed to find fsl,imx6q-iomux-gpr regmap\n"); dev_err(dev,
ret = PTR_ERR(imxpriv->gpr); "failed to find fsl,imx6q-iomux-gpr regmap\n");
goto err_out; return PTR_ERR(imxpriv->gpr);
} }
/* /*
* Set PHY Paremeters, two steps to configure the GPR13, * Set PHY Paremeters, two steps to configure the GPR13,
* one write for rest of parameters, mask of first write * one write for rest of parameters, mask of first write
* is 0x07ffffff, and the other one write for setting * is 0x07fffffe, and the other one write for setting
* the mpll_clk_en happens in imx_sata_clock_enable(). * the mpll_clk_en happens in imx_sata_clock_enable().
*/ */
regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
...@@ -296,6 +359,7 @@ static int imx_ahci_probe(struct platform_device *pdev) ...@@ -296,6 +359,7 @@ static int imx_ahci_probe(struct platform_device *pdev)
IMX6Q_GPR13_SATA_TX_ATTEN_9_16 | IMX6Q_GPR13_SATA_TX_ATTEN_9_16 |
IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB | IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB |
IMX6Q_GPR13_SATA_TX_LVL_1_025_V); IMX6Q_GPR13_SATA_TX_LVL_1_025_V);
}
ret = platform_device_add_resources(ahci_pdev, res, 2); ret = platform_device_add_resources(ahci_pdev, res, 2);
if (ret) if (ret)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment