Commit ba16db36 authored by Kedareswara rao Appana's avatar Kedareswara rao Appana Committed by Vinod Koul

dmaengine: vdma: Add clock support

Added basic clock support for axi dma's.
The clocks are requested at probe and released at remove.
Reviewed-by: default avatarShubhrajyoti Datta <shubhraj@xilinx.com>
Signed-off-by: default avatarKedareswara rao Appana <appanad@xilinx.com>
Signed-off-by: default avatarVinod Koul <vinod.koul@intel.com>
parent 4ac4e120
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/clk.h>
#include "../dmaengine.h" #include "../dmaengine.h"
...@@ -344,6 +345,9 @@ struct xilinx_dma_chan { ...@@ -344,6 +345,9 @@ struct xilinx_dma_chan {
struct xilinx_dma_config { struct xilinx_dma_config {
enum xdma_ip_type dmatype; enum xdma_ip_type dmatype;
int (*clk_init)(struct platform_device *pdev, struct clk **axi_clk,
struct clk **tx_clk, struct clk **txs_clk,
struct clk **rx_clk, struct clk **rxs_clk);
}; };
/** /**
...@@ -355,7 +359,13 @@ struct xilinx_dma_config { ...@@ -355,7 +359,13 @@ struct xilinx_dma_config {
* @has_sg: Specifies whether Scatter-Gather is present or not * @has_sg: Specifies whether Scatter-Gather is present or not
* @flush_on_fsync: Flush on frame sync * @flush_on_fsync: Flush on frame sync
* @ext_addr: Indicates 64 bit addressing is supported by dma device * @ext_addr: Indicates 64 bit addressing is supported by dma device
* @pdev: Platform device structure pointer
* @dma_config: DMA config structure * @dma_config: DMA config structure
* @axi_clk: DMA Axi4-lite interace clock
* @tx_clk: DMA mm2s clock
* @txs_clk: DMA mm2s stream clock
* @rx_clk: DMA s2mm clock
* @rxs_clk: DMA s2mm stream clock
*/ */
struct xilinx_dma_device { struct xilinx_dma_device {
void __iomem *regs; void __iomem *regs;
...@@ -365,7 +375,13 @@ struct xilinx_dma_device { ...@@ -365,7 +375,13 @@ struct xilinx_dma_device {
bool has_sg; bool has_sg;
u32 flush_on_fsync; u32 flush_on_fsync;
bool ext_addr; bool ext_addr;
struct platform_device *pdev;
const struct xilinx_dma_config *dma_config; const struct xilinx_dma_config *dma_config;
struct clk *axi_clk;
struct clk *tx_clk;
struct clk *txs_clk;
struct clk *rx_clk;
struct clk *rxs_clk;
}; };
/* Macros */ /* Macros */
...@@ -1756,6 +1772,195 @@ static void xilinx_dma_chan_remove(struct xilinx_dma_chan *chan) ...@@ -1756,6 +1772,195 @@ static void xilinx_dma_chan_remove(struct xilinx_dma_chan *chan)
list_del(&chan->common.device_node); list_del(&chan->common.device_node);
} }
static int axidma_clk_init(struct platform_device *pdev, struct clk **axi_clk,
struct clk **tx_clk, struct clk **rx_clk,
struct clk **sg_clk, struct clk **tmp_clk)
{
int err;
*tmp_clk = NULL;
*axi_clk = devm_clk_get(&pdev->dev, "s_axi_lite_aclk");
if (IS_ERR(*axi_clk)) {
err = PTR_ERR(*axi_clk);
dev_err(&pdev->dev, "failed to get axi_aclk (%u)\n", err);
return err;
}
*tx_clk = devm_clk_get(&pdev->dev, "m_axi_mm2s_aclk");
if (IS_ERR(*tx_clk))
*tx_clk = NULL;
*rx_clk = devm_clk_get(&pdev->dev, "m_axi_s2mm_aclk");
if (IS_ERR(*rx_clk))
*rx_clk = NULL;
*sg_clk = devm_clk_get(&pdev->dev, "m_axi_sg_aclk");
if (IS_ERR(*sg_clk))
*sg_clk = NULL;
err = clk_prepare_enable(*axi_clk);
if (err) {
dev_err(&pdev->dev, "failed to enable axi_clk (%u)\n", err);
return err;
}
err = clk_prepare_enable(*tx_clk);
if (err) {
dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err);
goto err_disable_axiclk;
}
err = clk_prepare_enable(*rx_clk);
if (err) {
dev_err(&pdev->dev, "failed to enable rx_clk (%u)\n", err);
goto err_disable_txclk;
}
err = clk_prepare_enable(*sg_clk);
if (err) {
dev_err(&pdev->dev, "failed to enable sg_clk (%u)\n", err);
goto err_disable_rxclk;
}
return 0;
err_disable_rxclk:
clk_disable_unprepare(*rx_clk);
err_disable_txclk:
clk_disable_unprepare(*tx_clk);
err_disable_axiclk:
clk_disable_unprepare(*axi_clk);
return err;
}
static int axicdma_clk_init(struct platform_device *pdev, struct clk **axi_clk,
struct clk **dev_clk, struct clk **tmp_clk,
struct clk **tmp1_clk, struct clk **tmp2_clk)
{
int err;
*tmp_clk = NULL;
*tmp1_clk = NULL;
*tmp2_clk = NULL;
*axi_clk = devm_clk_get(&pdev->dev, "s_axi_lite_aclk");
if (IS_ERR(*axi_clk)) {
err = PTR_ERR(*axi_clk);
dev_err(&pdev->dev, "failed to get axi_clk (%u)\n", err);
return err;
}
*dev_clk = devm_clk_get(&pdev->dev, "m_axi_aclk");
if (IS_ERR(*dev_clk)) {
err = PTR_ERR(*dev_clk);
dev_err(&pdev->dev, "failed to get dev_clk (%u)\n", err);
return err;
}
err = clk_prepare_enable(*axi_clk);
if (err) {
dev_err(&pdev->dev, "failed to enable axi_clk (%u)\n", err);
return err;
}
err = clk_prepare_enable(*dev_clk);
if (err) {
dev_err(&pdev->dev, "failed to enable dev_clk (%u)\n", err);
goto err_disable_axiclk;
}
return 0;
err_disable_axiclk:
clk_disable_unprepare(*axi_clk);
return err;
}
static int axivdma_clk_init(struct platform_device *pdev, struct clk **axi_clk,
struct clk **tx_clk, struct clk **txs_clk,
struct clk **rx_clk, struct clk **rxs_clk)
{
int err;
*axi_clk = devm_clk_get(&pdev->dev, "s_axi_lite_aclk");
if (IS_ERR(*axi_clk)) {
err = PTR_ERR(*axi_clk);
dev_err(&pdev->dev, "failed to get axi_aclk (%u)\n", err);
return err;
}
*tx_clk = devm_clk_get(&pdev->dev, "m_axi_mm2s_aclk");
if (IS_ERR(*tx_clk))
*tx_clk = NULL;
*txs_clk = devm_clk_get(&pdev->dev, "m_axis_mm2s_aclk");
if (IS_ERR(*txs_clk))
*txs_clk = NULL;
*rx_clk = devm_clk_get(&pdev->dev, "m_axi_s2mm_aclk");
if (IS_ERR(*rx_clk))
*rx_clk = NULL;
*rxs_clk = devm_clk_get(&pdev->dev, "s_axis_s2mm_aclk");
if (IS_ERR(*rxs_clk))
*rxs_clk = NULL;
err = clk_prepare_enable(*axi_clk);
if (err) {
dev_err(&pdev->dev, "failed to enable axi_clk (%u)\n", err);
return err;
}
err = clk_prepare_enable(*tx_clk);
if (err) {
dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err);
goto err_disable_axiclk;
}
err = clk_prepare_enable(*txs_clk);
if (err) {
dev_err(&pdev->dev, "failed to enable txs_clk (%u)\n", err);
goto err_disable_txclk;
}
err = clk_prepare_enable(*rx_clk);
if (err) {
dev_err(&pdev->dev, "failed to enable rx_clk (%u)\n", err);
goto err_disable_txsclk;
}
err = clk_prepare_enable(*rxs_clk);
if (err) {
dev_err(&pdev->dev, "failed to enable rxs_clk (%u)\n", err);
goto err_disable_rxclk;
}
return 0;
err_disable_rxclk:
clk_disable_unprepare(*rx_clk);
err_disable_txsclk:
clk_disable_unprepare(*txs_clk);
err_disable_txclk:
clk_disable_unprepare(*tx_clk);
err_disable_axiclk:
clk_disable_unprepare(*axi_clk);
return err;
}
static void xdma_disable_allclks(struct xilinx_dma_device *xdev)
{
clk_disable_unprepare(xdev->rxs_clk);
clk_disable_unprepare(xdev->rx_clk);
clk_disable_unprepare(xdev->txs_clk);
clk_disable_unprepare(xdev->tx_clk);
clk_disable_unprepare(xdev->axi_clk);
}
/** /**
* xilinx_dma_chan_probe - Per Channel Probing * xilinx_dma_chan_probe - Per Channel Probing
* It get channel features from the device tree entry and * It get channel features from the device tree entry and
...@@ -1899,14 +2104,17 @@ static struct dma_chan *of_dma_xilinx_xlate(struct of_phandle_args *dma_spec, ...@@ -1899,14 +2104,17 @@ static struct dma_chan *of_dma_xilinx_xlate(struct of_phandle_args *dma_spec,
static const struct xilinx_dma_config axidma_config = { static const struct xilinx_dma_config axidma_config = {
.dmatype = XDMA_TYPE_AXIDMA, .dmatype = XDMA_TYPE_AXIDMA,
.clk_init = axidma_clk_init,
}; };
static const struct xilinx_dma_config axicdma_config = { static const struct xilinx_dma_config axicdma_config = {
.dmatype = XDMA_TYPE_CDMA, .dmatype = XDMA_TYPE_CDMA,
.clk_init = axicdma_clk_init,
}; };
static const struct xilinx_dma_config axivdma_config = { static const struct xilinx_dma_config axivdma_config = {
.dmatype = XDMA_TYPE_VDMA, .dmatype = XDMA_TYPE_VDMA,
.clk_init = axivdma_clk_init,
}; };
static const struct of_device_id xilinx_dma_of_ids[] = { static const struct of_device_id xilinx_dma_of_ids[] = {
...@@ -1925,6 +2133,9 @@ MODULE_DEVICE_TABLE(of, xilinx_dma_of_ids); ...@@ -1925,6 +2133,9 @@ MODULE_DEVICE_TABLE(of, xilinx_dma_of_ids);
*/ */
static int xilinx_dma_probe(struct platform_device *pdev) static int xilinx_dma_probe(struct platform_device *pdev)
{ {
int (*clk_init)(struct platform_device *, struct clk **, struct clk **,
struct clk **, struct clk **, struct clk **)
= axivdma_clk_init;
struct device_node *node = pdev->dev.of_node; struct device_node *node = pdev->dev.of_node;
struct xilinx_dma_device *xdev; struct xilinx_dma_device *xdev;
struct device_node *child, *np = pdev->dev.of_node; struct device_node *child, *np = pdev->dev.of_node;
...@@ -1942,10 +2153,17 @@ static int xilinx_dma_probe(struct platform_device *pdev) ...@@ -1942,10 +2153,17 @@ static int xilinx_dma_probe(struct platform_device *pdev)
const struct of_device_id *match; const struct of_device_id *match;
match = of_match_node(xilinx_dma_of_ids, np); match = of_match_node(xilinx_dma_of_ids, np);
if (match && match->data) if (match && match->data) {
xdev->dma_config = match->data; xdev->dma_config = match->data;
clk_init = xdev->dma_config->clk_init;
}
} }
err = clk_init(pdev, &xdev->axi_clk, &xdev->tx_clk, &xdev->txs_clk,
&xdev->rx_clk, &xdev->rxs_clk);
if (err)
return err;
/* Request and map I/O memory */ /* Request and map I/O memory */
io = platform_get_resource(pdev, IORESOURCE_MEM, 0); io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
xdev->regs = devm_ioremap_resource(&pdev->dev, io); xdev->regs = devm_ioremap_resource(&pdev->dev, io);
...@@ -2018,7 +2236,7 @@ static int xilinx_dma_probe(struct platform_device *pdev) ...@@ -2018,7 +2236,7 @@ static int xilinx_dma_probe(struct platform_device *pdev)
for_each_child_of_node(node, child) { for_each_child_of_node(node, child) {
err = xilinx_dma_chan_probe(xdev, child); err = xilinx_dma_chan_probe(xdev, child);
if (err < 0) if (err < 0)
goto error; goto disable_clks;
} }
if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) { if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
...@@ -2042,6 +2260,8 @@ static int xilinx_dma_probe(struct platform_device *pdev) ...@@ -2042,6 +2260,8 @@ static int xilinx_dma_probe(struct platform_device *pdev)
return 0; return 0;
disable_clks:
xdma_disable_allclks(xdev);
error: error:
for (i = 0; i < XILINX_DMA_MAX_CHANS_PER_DEVICE; i++) for (i = 0; i < XILINX_DMA_MAX_CHANS_PER_DEVICE; i++)
if (xdev->chan[i]) if (xdev->chan[i])
...@@ -2069,6 +2289,8 @@ static int xilinx_dma_remove(struct platform_device *pdev) ...@@ -2069,6 +2289,8 @@ static int xilinx_dma_remove(struct platform_device *pdev)
if (xdev->chan[i]) if (xdev->chan[i])
xilinx_dma_chan_remove(xdev->chan[i]); xilinx_dma_chan_remove(xdev->chan[i]);
xdma_disable_allclks(xdev);
return 0; return 0;
} }
......
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