xref: /rk3399_rockchip-uboot/drivers/dma/lpc32xx_dma.c (revision 90aa625c9a9e1fb7a2f001fd8e50099bacaf92b8)
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