summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Green <andy.green@linaro.org>2015-09-11 15:32:51 +0800
committerAndy Green <andy.green@linaro.org>2015-09-11 15:32:51 +0800
commit31bd15d170bacc9342a39e357ffb09cb9a8a0463 (patch)
tree261e241e6b3031b121520ff40a13b0d5f532ed94
parenta85ee022482a70c51e18e9be3cd2d4afa79b576d (diff)
dma desc
Signed-off-by: Andy Green <andy.green@linaro.org>
-rw-r--r--arch/arm/boot/dts/zynq-7000.dtsi25
-rw-r--r--arch/arm/boot/dts/zynq-zturn.dts29
-rw-r--r--drivers/dma/xilinx/xilinx_dma.c102
-rw-r--r--drivers/misc/hdmicap.c75
4 files changed, 151 insertions, 80 deletions
diff --git a/arch/arm/boot/dts/zynq-7000.dtsi b/arch/arm/boot/dts/zynq-7000.dtsi
index d373b3860333..690e1bdb87ec 100644
--- a/arch/arm/boot/dts/zynq-7000.dtsi
+++ b/arch/arm/boot/dts/zynq-7000.dtsi
@@ -244,17 +244,20 @@
#clock-cells = <1>;
compatible = "xlnx,ps7-clkc";
fclk-enable = <0>;
- clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x",
- "cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x",
- "dci", "lqspi", "smc", "pcap", "gem0", "gem1",
- "fclk0", "fclk1", "fclk2", "fclk3", "can0", "can1",
- "sdio0", "sdio1", "uart0", "uart1", "spi0", "spi1",
- "dma", "usb0_aper", "usb1_aper", "gem0_aper",
- "gem1_aper", "sdio0_aper", "sdio1_aper",
- "spi0_aper", "spi1_aper", "can0_aper", "can1_aper",
- "i2c0_aper", "i2c1_aper", "uart0_aper", "uart1_aper",
- "gpio_aper", "lqspi_aper", "smc_aper", "swdt",
- "dbg_trc", "dbg_apb";
+ clock-output-names =
+ "armpll", "ddrpll", "iopll", "cpu_6or4x",
+ "cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x",
+ "ddr3x", "dci", "lqspi", "smc",
+ "pcap", "gem0", "gem1", "fclk0",
+
+ "fclk1", "fclk2", "fclk3", "can0",
+ "can1", "sdio0", "sdio1", "uart0",
+ "uart1", "spi0", "spi1", "dma",
+ "usb0_aper", "usb1_aper", "gem0_aper", "gem1_aper",
+ "sdio0_aper", "sdio1_aper", "spi0_aper", "spi1_aper",
+ "can0_aper", "can1_aper", "i2c0_aper", "i2c1_aper",
+ "uart0_aper", "uart1_aper", "gpio_aper", "lqspi_aper",
+ "smc_aper", "swdt", "dbg_trc", "dbg_apb";
reg = <0x100 0x100>;
};
diff --git a/arch/arm/boot/dts/zynq-zturn.dts b/arch/arm/boot/dts/zynq-zturn.dts
index f623be7f08e5..e07760229b63 100644
--- a/arch/arm/boot/dts/zynq-zturn.dts
+++ b/arch/arm/boot/dts/zynq-zturn.dts
@@ -172,28 +172,29 @@
};
&amba {
-axi_dma_0: axidma@40400000 {
- compatible = "xlnx,axi-dma-1.00.a";
- #dma-cells = <1>;
- reg = <0x40400000 0x10000>;
- dma-channel@40400030 {
- compatible = "xlnx,axi-dma-s2mm-channel";
- interrupt-parent = <&intc>;
- interrupts = <0 31 4>;
- xlnx,datawidth = <32>;
- //xlnx,include-sg;
- };
-};
+ axi_dma_0: axidma@40400000 {
+ compatible = "xlnx,axi-dma-1.00.a";
+ #dma-cells = <1>;
+ reg = <0x40400000 0x10000>;
+ xlnx,include-sg = <1>;
+ dma-channel@40400030 {
+ compatible = "xlnx,axi-dma-s2mm-channel";
+ interrupt-parent = <&intc>;
+ interrupts = <0 31 4>;
+ xlnx,datawidth = <32>;
+ };
+ };
hdmicap {
compatible = "linaro,hdmicap";
reg = <0x43c10000 0x1000>;
- clocks = <&clkc 15>, <&clkc 16>;
+ clocks = <&clkc 15>, <&clkc 16>, <&clkc 27>;
clock-names = "a", "b", "c", "d";
interrupt-parent = <&intc>;
interrupts = <0 29 4>;
- dma = <&axi_dma_0>;
+ dmas = <&axi_dma_0 1>;
+ dma-names = "xdma";
};
gpio-leds {
diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index 0e7cc3308939..84331438fcea 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -195,17 +195,26 @@ struct xilinx_dma_device {
/* IO accessors */
static inline void dma_write(struct xilinx_dma_chan *chan, u32 reg, u32 value)
{
+ pr_info("%s: val 0x%x -> +0x%x\n", __func__, value, reg);
iowrite32(value, chan->xdev->regs + reg);
}
static inline u32 dma_read(struct xilinx_dma_chan *chan, u32 reg)
{
- return ioread32(chan->xdev->regs + reg);
+ u32 n;
+ n = ioread32(chan->xdev->regs + reg);
+ pr_info("%s: +0x%x = 0x%x\n", __func__, reg, n);
+
+ return n;
}
static inline u32 dma_ctrl_read(struct xilinx_dma_chan *chan, u32 reg)
{
- return dma_read(chan, chan->ctrl_offset + reg);
+ u32 n;
+
+ n = dma_read(chan, chan->ctrl_offset + reg);
+
+ return n;
}
static inline void dma_ctrl_write(struct xilinx_dma_chan *chan, u32 reg,
@@ -462,9 +471,13 @@ static enum dma_status xilinx_dma_tx_status(struct dma_chan *dchan,
struct xilinx_dma_desc_hw *hw;
enum dma_status ret;
unsigned long flags;
- u32 residue;
+ u32 residue = 0;
ret = dma_cookie_status(dchan, cookie, txstate);
+
+ if (ret == DMA_COMPLETE && chan->err)
+ return DMA_ERROR;
+
if (ret == DMA_COMPLETE || !txstate)
return ret;
@@ -508,8 +521,12 @@ static bool xilinx_dma_is_running(struct xilinx_dma_chan *chan)
*/
static bool xilinx_dma_is_idle(struct xilinx_dma_chan *chan)
{
- return !!(dma_ctrl_read(chan, XILINX_DMA_REG_STATUS) &
- XILINX_DMA_SR_IDLE_MASK);
+ u32 status = dma_ctrl_read(chan, XILINX_DMA_REG_STATUS);
+
+ if (status & 1) // halted
+ return true;
+
+ return !!(status & XILINX_DMA_SR_IDLE_MASK);
}
/**
@@ -528,7 +545,7 @@ static void xilinx_dma_halt(struct xilinx_dma_chan *chan)
if (dma_ctrl_read(chan, XILINX_DMA_REG_STATUS) &
XILINX_DMA_SR_HALTED_MASK)
break;
- } while (loop--);
+ } while (--loop);
if (!loop) {
dev_err(chan->dev, "Cannot stop channel %p: %x\n",
@@ -543,23 +560,28 @@ static void xilinx_dma_halt(struct xilinx_dma_chan *chan)
*/
static void xilinx_dma_start(struct xilinx_dma_chan *chan)
{
- int loop = XILINX_DMA_LOOP_COUNT;
-
- dma_ctrl_set(chan, XILINX_DMA_REG_CONTROL,
- XILINX_DMA_CR_RUNSTOP_MASK);
+ int loop = 5; //XILINX_DMA_LOOP_COUNT;
/* Wait for the hardware to start */
do {
- if (!dma_ctrl_read(chan, XILINX_DMA_REG_STATUS) &
- XILINX_DMA_SR_HALTED_MASK)
+ // b0 = 1 = start
+ dma_ctrl_clr(chan, XILINX_DMA_REG_CONTROL,
+ XILINX_DMA_CR_RUNSTOP_MASK);
+ dma_ctrl_set(chan, XILINX_DMA_REG_CONTROL,
+ XILINX_DMA_CR_RUNSTOP_MASK);
+
+ // b0 = 1 = halted
+ if (!(dma_ctrl_read(chan, XILINX_DMA_REG_STATUS) &
+ XILINX_DMA_SR_HALTED_MASK))
break;
- } while (loop--);
+ } while (--loop);
if (!loop) {
dev_err(chan->dev, "Cannot start channel %p: %x\n",
chan, dma_ctrl_read(chan, XILINX_DMA_REG_STATUS));
chan->err = true;
- }
+ } else
+ pr_err("started OK\n");
}
/**
@@ -571,20 +593,29 @@ static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan)
struct xilinx_dma_tx_descriptor *desc;
struct xilinx_dma_tx_segment *head, *tail = NULL;
- if (chan->err)
+ if (chan->err) {
+ pr_err("%s: bailing because of chan->err\n", __func__);
return;
+ }
- if (list_empty(&chan->pending_list))
+ if (list_empty(&chan->pending_list)) {
+ pr_err("%s: bailing on no pending list\n", __func__);
return;
+ }
- if (!chan->idle)
+ if (!chan->idle) {
+ pr_err("%s: bailing on chan->idle flag set\n", __func__);
return;
+ }
+
+ pr_err("%s\n", __func__);
desc = list_first_entry(&chan->pending_list,
struct xilinx_dma_tx_descriptor, node);
if (chan->has_sg && xilinx_dma_is_running(chan) &&
!xilinx_dma_is_idle(chan)) {
+ pr_err(" writing TAILDESC\n");
tail = list_entry(desc->segments.prev,
struct xilinx_dma_tx_segment, node);
dma_ctrl_write(chan, XILINX_DMA_REG_TAILDESC, tail->phys);
@@ -596,6 +627,7 @@ static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan)
struct xilinx_dma_tx_segment, node);
tail = list_entry(desc->segments.prev,
struct xilinx_dma_tx_segment, node);
+ pr_err(" writing CURDESC\n");
dma_ctrl_write(chan, XILINX_DMA_REG_CURDESC, head->phys);
}
@@ -604,11 +636,14 @@ static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan)
XILINX_DMA_XR_IRQ_ALL_MASK);
xilinx_dma_start(chan);
- if (chan->err)
+ if (chan->err) {
+ pr_err("bailing on chan err\n");
return;
+ }
/* Start the transfer */
if (chan->has_sg) {
+ pr_err("uhhh writing TAILDESC\n");
dma_ctrl_write(chan, XILINX_DMA_REG_TAILDESC, tail->phys);
} else {
struct xilinx_dma_tx_segment *segment;
@@ -618,12 +653,18 @@ static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan)
struct xilinx_dma_tx_segment, node);
hw = &segment->hw;
- if (desc->direction == DMA_MEM_TO_DEV)
+ pr_err("segment...buf_addr=%x, status=%x\n",
+ hw->buf_addr, hw->status);
+
+ if (desc->direction == DMA_MEM_TO_DEV) {
+ pr_err("mem to dev\n");
dma_ctrl_write(chan, XILINX_DMA_REG_SRCADDR,
hw->buf_addr);
- else
+ } else {
+ pr_err("dev to mem\n");
dma_ctrl_write(chan, XILINX_DMA_REG_DSTADDR,
hw->buf_addr);
+ }
/* Start the transfer */
dma_ctrl_write(chan, XILINX_DMA_REG_BTT,
@@ -645,6 +686,8 @@ static void xilinx_dma_issue_pending(struct dma_chan *dchan)
struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
unsigned long flags;
+ pr_err("%s\n", __func__);
+
spin_lock_irqsave(&chan->lock, flags);
xilinx_dma_start_transfer(chan);
spin_unlock_irqrestore(&chan->lock, flags);
@@ -692,7 +735,7 @@ static int xilinx_dma_chan_reset(struct xilinx_dma_chan *chan)
do {
tmp = dma_ctrl_read(chan, XILINX_DMA_REG_CONTROL) &
XILINX_DMA_CR_RESET_MASK;
- } while (loop-- && tmp);
+ } while (--loop && tmp);
if (!loop) {
dev_err(chan->dev, "reset timeout, cr %x, sr %x\n",
@@ -700,8 +743,10 @@ static int xilinx_dma_chan_reset(struct xilinx_dma_chan *chan)
dma_ctrl_read(chan, XILINX_DMA_REG_STATUS));
return -EBUSY;
}
+ pr_err("reset OK\n");
chan->err = false;
+ chan->idle = true;
return 0;
}
@@ -720,6 +765,10 @@ static irqreturn_t xilinx_dma_irq_handler(int irq, void *data)
/* Read the status and ack the interrupts. */
status = dma_ctrl_read(chan, XILINX_DMA_REG_STATUS);
+dma_ctrl_read(chan, 0x58 - 0x30);
+
+ pr_err("***** status = 0x%x\n", status);
+
if (!(status & XILINX_DMA_XR_IRQ_ALL_MASK))
return IRQ_NONE;
@@ -746,7 +795,8 @@ static irqreturn_t xilinx_dma_irq_handler(int irq, void *data)
spin_lock(&chan->lock);
xilinx_dma_complete_descriptor(chan);
chan->idle = true;
- xilinx_dma_start_transfer(chan);
+ if (!chan->err)
+ xilinx_dma_start_transfer(chan);
spin_unlock(&chan->lock);
}
@@ -913,6 +963,10 @@ static int xilinx_dma_terminate_all(struct dma_chan *dchan)
{
struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
+ dma_ctrl_read(chan, XILINX_DMA_REG_STATUS);
+ dma_ctrl_read(chan, 0x30 - 0x30);
+ dma_ctrl_read(chan, 0x58 - 0x30);
+
/* Halt the DMA engine */
xilinx_dma_halt(chan);
@@ -934,11 +988,11 @@ int xilinx_dma_channel_set_config(struct dma_chan *dchan,
struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
u32 reg = dma_ctrl_read(chan, XILINX_DMA_REG_CONTROL);
+ if (cfg->reset)
+ return xilinx_dma_chan_reset(chan);
if (!xilinx_dma_is_idle(chan))
return -EBUSY;
- if (cfg->reset)
- return xilinx_dma_chan_reset(chan);
if (cfg->coalesc <= XILINX_DMA_CR_COALESCE_MAX)
reg |= cfg->coalesc << XILINX_DMA_CR_COALESCE_SHIFT;
diff --git a/drivers/misc/hdmicap.c b/drivers/misc/hdmicap.c
index bc6b87f51f8c..983db9fdd0b2 100644
--- a/drivers/misc/hdmicap.c
+++ b/drivers/misc/hdmicap.c
@@ -4,13 +4,14 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
+#include <linux/of_dma.h>
#include <linux/platform_device.h>
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
-#include <linux/amba/xilinx_dma.h>
+#include <linux/dma/xilinx_dma.h>
struct hdmicap_chip {
struct device *dev;
@@ -52,6 +53,8 @@ struct measurements {
int pixels_in_frame;
int data_in_frame;
int data_in_vb;
+ int control_in_frame;
+ int control_in_vb;
};
static int is_synchronized(struct hdmicap_chip *pc);
@@ -114,6 +117,9 @@ static int _get_measurements(struct hdmicap_chip *pc, struct measurements *m)
m->pixels_in_frame = readl(pc->base + 0x24) + 1;
m->data_in_vb = readl(pc->base + 0x20) + 1;
m->data_in_frame = readl(pc->base + 0x28) + 1;
+ m->control_in_vb = readl(pc->base + 0x58) + 1;
+ m->control_in_frame = readl(pc->base + 0x54) + 1;
+
/* capture / clear channel escape info */
writel(BIT(0), pc->base + 0x14);
@@ -274,14 +280,18 @@ static ssize_t hdmicap_attr_show(struct device *dev,
if (pc->sync_polarities & 2)
v = '+';
- return sprintf(buf, "H: %c (%d), V: %c (%d), "
- "H[tot:%d, act:%d, bl:%d, sa:%d, fp:%d, bp:%d], "
- "V[tot:%d, act:%d, bl:%d, sa:%d, fp:%d, bp:%d], "
- "%d.%dMHz, px in frame %d (%d.%03d x Htot), "
- "data in active frame %d (%d.%03d/line), (%d in VB), "
- "ch0: %d, ch1: %d, ch2: %d, (t=%d)"
- "0x%08x 0x%08X 0x%08x 0x%08x\n",
- h, m.h_line_measured, v, m.v_frame_measured,
+ return sprintf(buf,
+ "%dx%d, H%c V%c (%d %d)\n"
+ " H[tot:%d, act:%d, bl:%d, sa:%d, fp:%d, bp:%d]\n"
+ " V[tot:%d, act:%d, bl:%d, sa:%d, fp:%d, bp:%d]\n"
+ " %d.%dMHz, px in frame %d (%d.%03d x Htot)\n"
+ " data in active frame %d (%d.%03d/line), (%d in VB)\n"
+ " ctrl in active frame %d (%d.%03d/line), (%d in VB)\n"
+ " estimated video clocks: %d\n"
+ " ch0: %d, ch1: %d, ch2: %d, (t=%d)\n"
+ " 0x%08x 0x%08X 0x%08x 0x%08x\n",
+ m.hact, m.vact,
+ h, v, m.h_line_measured, m.v_frame_measured,
m.htotal, m.hact, m.hblank, m.hsa, m.hfp, m.hbp,
m.vtotal, m.vact, m.vblank, m.vsa, m.vfp, m.vbp,
m.pixel_clk_hz / 1000000, m.pixel_clk_hz % 1000000,
@@ -292,6 +302,12 @@ static ssize_t hdmicap_attr_show(struct device *dev,
(m.data_in_frame - m.data_in_vb) / m.vact,
(((m.data_in_frame - m.data_in_vb) * 1000) / m.vact) % 1000,
m.data_in_vb,
+ m.control_in_frame - m.control_in_vb,
+ (m.control_in_frame - m.control_in_vb) / m.vact,
+ (((m.control_in_frame - m.control_in_vb) * 1000) / m.vact) % 1000,
+ m.control_in_vb,
+ m.pixels_in_frame - m.data_in_frame - m.control_in_frame,
+
m.channel_escapes[0],
m.channel_escapes[1],
m.channel_escapes[2],
@@ -307,18 +323,6 @@ static ssize_t hdmicap_attr_show(struct device *dev,
return -ENOENT;
}
-static bool hdmicap_dma_filter_fn(struct dma_chan *chan, void *filter_param)
-{
- struct hdmicap_chip *pc = filter_param;
-
- if (chan->device->dev->of_node == pc->dma_node) {
- dev_err(chan->device->dev, "Selected DMA\n");
- return true;
- }
-
- return false;
-}
-
static void hdmicap_slave_callback(void *completion)
{
pr_err("completion\n");
@@ -344,16 +348,13 @@ static ssize_t hdmicap_attr_store(struct device *dev,
struct xilinx_dma_config config;
struct scatterlist sg[1];
struct completion comp;
- unsigned long tmo = msecs_to_jiffies(3000);
+ unsigned long tmo = msecs_to_jiffies(300);
if (!strcmp(attr->attr.name, "grab")) {
for (n = 0; n < 1024; n++)
((u32 *)pc->buf)[n] = 0x12345678;
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
- dma_cap_set(DMA_PRIVATE, mask);
- dc = dma_request_channel(mask, hdmicap_dma_filter_fn, pc);
+ dc = of_dma_request_slave_channel(pc->dev->of_node, "xdma");
if (!dc || IS_ERR(dc)) {
pr_err("failed to get dc\n");
return -ENOENT;
@@ -365,9 +366,12 @@ static ssize_t hdmicap_attr_store(struct device *dev,
pr_err("problems with dma mapping\n");
return -ENOENT;
}
+
+ pr_err("PA for buf is 0x%x\n", (u32)dma_handle);
+
sg_init_table(sg, 1);
sg_dma_address(&sg[0]) = dma_handle;
- sg_dma_len(&sg[0]) = size;
+ sg_dma_len(&sg[0]) = 0x80000; // size;
#if 0
memset(&dsc, 0, sizeof dsc);
@@ -389,10 +393,18 @@ static ssize_t hdmicap_attr_store(struct device *dev,
memset(&config, 0, sizeof config);
config.coalesc = 0;
config.delay = 0;
-// config.reset = 1;
-// xilinx_dma_channel_set_config(dc, &config);
+ config.reset = 1;
+ n = xilinx_dma_channel_set_config(dc, &config);
+ if (n < 0) {
+ pr_err("reset set_config told %d\n", n);
+ return -ENOENT;
+ }
config.reset = 0;
- xilinx_dma_channel_set_config(dc, &config);
+ n = xilinx_dma_channel_set_config(dc, &config);
+ if (n < 0) {
+ pr_err("mode set_config told %d\n", n);
+ return -ENOENT;
+ }
atd = dc->device->device_prep_slave_sg(dc, sg, 1,
DMA_DEV_TO_MEM,
@@ -432,7 +444,7 @@ static ssize_t hdmicap_attr_store(struct device *dev,
/* DMA length in 32-bit px */
- writel(3 /*(size >> 2) - 1*/, pc->base + 0x10);
+ writel(4 /*(size >> 2) - 2*/, pc->base + 0x10);
dma_async_issue_pending(dc);
#if 0
@@ -598,6 +610,7 @@ static int hdmicap_probe(struct platform_device *pdev)
devm_clk_get(pc->dev, "a");
devm_clk_get(pc->dev, "b");
+ devm_clk_get(pc->dev, "c");
dev_set_drvdata(&pdev->dev, pc);