1980db8caSSylvain Lemieux /*
2980db8caSSylvain Lemieux * Copyright (C) 2008 by NXP Semiconductors
3980db8caSSylvain Lemieux * @Author: Kevin Wells
4980db8caSSylvain Lemieux * @Descr: LPC3250 DMA controller interface support functions
5980db8caSSylvain Lemieux *
6980db8caSSylvain Lemieux * Copyright (c) 2015 Tyco Fire Protection Products.
7980db8caSSylvain Lemieux *
8980db8caSSylvain Lemieux * SPDX-License-Identifier: GPL-2.0+
9980db8caSSylvain Lemieux */
10980db8caSSylvain Lemieux
11980db8caSSylvain Lemieux #include <common.h>
12980db8caSSylvain Lemieux #include <errno.h>
13980db8caSSylvain Lemieux #include <asm/arch/dma.h>
14980db8caSSylvain Lemieux #include <asm/arch/cpu.h>
15980db8caSSylvain Lemieux #include <asm/arch/clk.h>
16980db8caSSylvain Lemieux #include <asm/arch/sys_proto.h>
17980db8caSSylvain Lemieux #include <asm/io.h>
18980db8caSSylvain Lemieux
19980db8caSSylvain Lemieux /* DMA controller channel register structure */
20980db8caSSylvain Lemieux struct dmac_chan_reg {
21980db8caSSylvain Lemieux u32 src_addr;
22980db8caSSylvain Lemieux u32 dest_addr;
23980db8caSSylvain Lemieux u32 lli;
24980db8caSSylvain Lemieux u32 control;
25980db8caSSylvain Lemieux u32 config_ch;
26980db8caSSylvain Lemieux u32 reserved[3];
27980db8caSSylvain Lemieux };
28980db8caSSylvain Lemieux
29980db8caSSylvain Lemieux /* DMA controller register structures */
30980db8caSSylvain Lemieux struct dma_reg {
31980db8caSSylvain Lemieux u32 int_stat;
32980db8caSSylvain Lemieux u32 int_tc_stat;
33980db8caSSylvain Lemieux u32 int_tc_clear;
34980db8caSSylvain Lemieux u32 int_err_stat;
35980db8caSSylvain Lemieux u32 int_err_clear;
36980db8caSSylvain Lemieux u32 raw_tc_stat;
37980db8caSSylvain Lemieux u32 raw_err_stat;
38980db8caSSylvain Lemieux u32 chan_enable;
39980db8caSSylvain Lemieux u32 sw_burst_req;
40980db8caSSylvain Lemieux u32 sw_single_req;
41980db8caSSylvain Lemieux u32 sw_last_burst_req;
42980db8caSSylvain Lemieux u32 sw_last_single_req;
43980db8caSSylvain Lemieux u32 config;
44980db8caSSylvain Lemieux u32 sync;
45980db8caSSylvain Lemieux u32 reserved[50];
46980db8caSSylvain Lemieux struct dmac_chan_reg dma_chan[8];
47980db8caSSylvain Lemieux };
48980db8caSSylvain Lemieux
49980db8caSSylvain Lemieux #define DMA_NO_OF_CHANNELS 8
50980db8caSSylvain Lemieux
51980db8caSSylvain Lemieux /* config register definitions */
52980db8caSSylvain Lemieux #define DMAC_CTRL_ENABLE (1 << 0) /* For enabling the DMA controller */
53980db8caSSylvain Lemieux
54980db8caSSylvain Lemieux static u32 alloc_ch;
55980db8caSSylvain Lemieux
56980db8caSSylvain Lemieux static struct dma_reg *dma = (struct dma_reg *)DMA_BASE;
57980db8caSSylvain Lemieux
lpc32xx_dma_get_channel(void)58980db8caSSylvain Lemieux int lpc32xx_dma_get_channel(void)
59980db8caSSylvain Lemieux {
60980db8caSSylvain Lemieux int i;
61980db8caSSylvain Lemieux
62980db8caSSylvain Lemieux if (!alloc_ch) { /* First time caller */
63980db8caSSylvain Lemieux /*
64980db8caSSylvain Lemieux * DMA clock are enable by "lpc32xx_dma_init()" and should
65980db8caSSylvain Lemieux * be call by board "board_early_init_f()" function.
66980db8caSSylvain Lemieux */
67980db8caSSylvain Lemieux
68980db8caSSylvain Lemieux /*
69980db8caSSylvain Lemieux * Make sure DMA controller and all channels are disabled.
70980db8caSSylvain Lemieux * Controller is in little-endian mode. Disable sync signals.
71980db8caSSylvain Lemieux */
72980db8caSSylvain Lemieux writel(0, &dma->config);
73980db8caSSylvain Lemieux writel(0, &dma->sync);
74980db8caSSylvain Lemieux
75980db8caSSylvain Lemieux /* Clear interrupt and error statuses */
76980db8caSSylvain Lemieux writel(0xFF, &dma->int_tc_clear);
77980db8caSSylvain Lemieux writel(0xFF, &dma->raw_tc_stat);
78980db8caSSylvain Lemieux writel(0xFF, &dma->int_err_clear);
79980db8caSSylvain Lemieux writel(0xFF, &dma->raw_err_stat);
80980db8caSSylvain Lemieux
81980db8caSSylvain Lemieux /* Enable DMA controller */
82980db8caSSylvain Lemieux writel(DMAC_CTRL_ENABLE, &dma->config);
83980db8caSSylvain Lemieux }
84980db8caSSylvain Lemieux
85980db8caSSylvain Lemieux i = ffz(alloc_ch);
86980db8caSSylvain Lemieux
87980db8caSSylvain Lemieux /* Check if all the available channels are busy */
88980db8caSSylvain Lemieux if (unlikely(i == DMA_NO_OF_CHANNELS))
89980db8caSSylvain Lemieux return -1;
90980db8caSSylvain Lemieux alloc_ch |= BIT_MASK(i);
91980db8caSSylvain Lemieux return i;
92980db8caSSylvain Lemieux }
93980db8caSSylvain Lemieux
lpc32xx_dma_start_xfer(unsigned int channel,const struct lpc32xx_dmac_ll * desc,u32 config)94980db8caSSylvain Lemieux int lpc32xx_dma_start_xfer(unsigned int channel,
95980db8caSSylvain Lemieux const struct lpc32xx_dmac_ll *desc, u32 config)
96980db8caSSylvain Lemieux {
97980db8caSSylvain Lemieux if (unlikely(((BIT_MASK(channel) & alloc_ch) == 0) ||
98980db8caSSylvain Lemieux (channel >= DMA_NO_OF_CHANNELS))) {
99*90aa625cSMasahiro Yamada pr_err("Request for xfer on unallocated channel %d", channel);
100980db8caSSylvain Lemieux return -1;
101980db8caSSylvain Lemieux }
102980db8caSSylvain Lemieux writel(BIT_MASK(channel), &dma->int_tc_clear);
103980db8caSSylvain Lemieux writel(BIT_MASK(channel), &dma->int_err_clear);
104980db8caSSylvain Lemieux writel(desc->dma_src, &dma->dma_chan[channel].src_addr);
105980db8caSSylvain Lemieux writel(desc->dma_dest, &dma->dma_chan[channel].dest_addr);
106980db8caSSylvain Lemieux writel(desc->next_lli, &dma->dma_chan[channel].lli);
107980db8caSSylvain Lemieux writel(desc->next_ctrl, &dma->dma_chan[channel].control);
108980db8caSSylvain Lemieux writel(config, &dma->dma_chan[channel].config_ch);
109980db8caSSylvain Lemieux
110980db8caSSylvain Lemieux return 0;
111980db8caSSylvain Lemieux }
112980db8caSSylvain Lemieux
lpc32xx_dma_wait_status(unsigned int channel)113980db8caSSylvain Lemieux int lpc32xx_dma_wait_status(unsigned int channel)
114980db8caSSylvain Lemieux {
115980db8caSSylvain Lemieux unsigned long start;
116980db8caSSylvain Lemieux u32 reg;
117980db8caSSylvain Lemieux
118980db8caSSylvain Lemieux /* Check if given channel is valid */
119980db8caSSylvain Lemieux if (unlikely(channel >= DMA_NO_OF_CHANNELS)) {
120*90aa625cSMasahiro Yamada pr_err("Request for status on unallocated channel %d", channel);
121980db8caSSylvain Lemieux return -1;
122980db8caSSylvain Lemieux }
123980db8caSSylvain Lemieux
124980db8caSSylvain Lemieux start = get_timer(0);
125980db8caSSylvain Lemieux while (1) {
126980db8caSSylvain Lemieux reg = readl(&dma->raw_tc_stat);
127980db8caSSylvain Lemieux reg |= readl(dma->raw_err_stat);
128980db8caSSylvain Lemieux if (reg & BIT_MASK(channel))
129980db8caSSylvain Lemieux break;
130980db8caSSylvain Lemieux
131980db8caSSylvain Lemieux if (get_timer(start) > CONFIG_SYS_HZ) {
132*90aa625cSMasahiro Yamada pr_err("DMA status timeout channel %d\n", channel);
133980db8caSSylvain Lemieux return -ETIMEDOUT;
134980db8caSSylvain Lemieux }
135980db8caSSylvain Lemieux udelay(1);
136980db8caSSylvain Lemieux }
137980db8caSSylvain Lemieux
138980db8caSSylvain Lemieux if (unlikely(readl(&dma->raw_err_stat) & BIT_MASK(channel))) {
139980db8caSSylvain Lemieux setbits_le32(&dma->int_err_clear, BIT_MASK(channel));
140980db8caSSylvain Lemieux setbits_le32(&dma->raw_err_stat, BIT_MASK(channel));
141*90aa625cSMasahiro Yamada pr_err("DMA error on channel %d\n", channel);
142980db8caSSylvain Lemieux return -1;
143980db8caSSylvain Lemieux }
144980db8caSSylvain Lemieux setbits_le32(&dma->int_tc_clear, BIT_MASK(channel));
145980db8caSSylvain Lemieux setbits_le32(&dma->raw_tc_stat, BIT_MASK(channel));
146980db8caSSylvain Lemieux return 0;
147980db8caSSylvain Lemieux }
148