diff options
author | Andy Green <andy.green@linaro.org> | 2015-09-11 15:32:51 +0800 |
---|---|---|
committer | Andy Green <andy.green@linaro.org> | 2015-09-11 15:32:51 +0800 |
commit | 31bd15d170bacc9342a39e357ffb09cb9a8a0463 (patch) | |
tree | 261e241e6b3031b121520ff40a13b0d5f532ed94 | |
parent | a85ee022482a70c51e18e9be3cd2d4afa79b576d (diff) |
dma desc
Signed-off-by: Andy Green <andy.green@linaro.org>
-rw-r--r-- | arch/arm/boot/dts/zynq-7000.dtsi | 25 | ||||
-rw-r--r-- | arch/arm/boot/dts/zynq-zturn.dts | 29 | ||||
-rw-r--r-- | drivers/dma/xilinx/xilinx_dma.c | 102 | ||||
-rw-r--r-- | drivers/misc/hdmicap.c | 75 |
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); |