Commit 31650d64a8fca2e5acf4dfe2b4f2a9ba9df2147c
Committed by
Stefano Babic
1 parent
ec33de3d12
Exists in
master
and in
54 other branches
iMX28: Add APBH DMA driver
Signed-off-by: Marek Vasut <marek.vasut@gmail.com> Cc: Stefano Babic <sbabic@denx.de> Cc: Wolfgang Denk <wd@denx.de> Cc: Detlev Zundel <dzu@denx.de>
Showing 5 changed files with 1329 additions and 0 deletions Side-by-side Diff
arch/arm/include/asm/arch-mx28/dma.h
1 | +/* | |
2 | + * Freescale i.MX28 APBH DMA | |
3 | + * | |
4 | + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> | |
5 | + * on behalf of DENX Software Engineering GmbH | |
6 | + * | |
7 | + * Based on code from LTIB: | |
8 | + * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. | |
9 | + * | |
10 | + * This program is free software; you can redistribute it and/or modify | |
11 | + * it under the terms of the GNU General Public License as published by | |
12 | + * the Free Software Foundation; either version 2 of the License, or | |
13 | + * (at your option) any later version. | |
14 | + * | |
15 | + * This program is distributed in the hope that it will be useful, | |
16 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | + * GNU General Public License for more details. | |
19 | + * | |
20 | + * You should have received a copy of the GNU General Public License | |
21 | + * along with this program; if not, write to the Free Software | |
22 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
23 | + * | |
24 | + */ | |
25 | + | |
26 | +#ifndef __DMA_H__ | |
27 | +#define __DMA_H__ | |
28 | + | |
29 | +#include <linux/list.h> | |
30 | + | |
31 | +#ifndef CONFIG_ARCH_DMA_PIO_WORDS | |
32 | +#define DMA_PIO_WORDS 15 | |
33 | +#else | |
34 | +#define DMA_PIO_WORDS CONFIG_ARCH_DMA_PIO_WORDS | |
35 | +#endif | |
36 | + | |
37 | +#define MXS_DMA_ALIGNMENT 32 | |
38 | + | |
39 | +/* | |
40 | + * MXS DMA channels | |
41 | + */ | |
42 | +enum { | |
43 | + MXS_DMA_CHANNEL_AHB_APBH_SSP0 = 0, | |
44 | + MXS_DMA_CHANNEL_AHB_APBH_SSP1, | |
45 | + MXS_DMA_CHANNEL_AHB_APBH_SSP2, | |
46 | + MXS_DMA_CHANNEL_AHB_APBH_SSP3, | |
47 | + MXS_DMA_CHANNEL_AHB_APBH_GPMI0, | |
48 | + MXS_DMA_CHANNEL_AHB_APBH_GPMI1, | |
49 | + MXS_DMA_CHANNEL_AHB_APBH_GPMI2, | |
50 | + MXS_DMA_CHANNEL_AHB_APBH_GPMI3, | |
51 | + MXS_DMA_CHANNEL_AHB_APBH_GPMI4, | |
52 | + MXS_DMA_CHANNEL_AHB_APBH_GPMI5, | |
53 | + MXS_DMA_CHANNEL_AHB_APBH_GPMI6, | |
54 | + MXS_DMA_CHANNEL_AHB_APBH_GPMI7, | |
55 | + MXS_DMA_CHANNEL_AHB_APBH_SSP, | |
56 | + MXS_MAX_DMA_CHANNELS, | |
57 | +}; | |
58 | + | |
59 | +/* | |
60 | + * MXS DMA hardware command. | |
61 | + * | |
62 | + * This structure describes the in-memory layout of an entire DMA command, | |
63 | + * including space for the maximum number of PIO accesses. See the appropriate | |
64 | + * reference manual for a detailed description of what these fields mean to the | |
65 | + * DMA hardware. | |
66 | + */ | |
67 | +#define MXS_DMA_DESC_COMMAND_MASK 0x3 | |
68 | +#define MXS_DMA_DESC_COMMAND_OFFSET 0 | |
69 | +#define MXS_DMA_DESC_COMMAND_NO_DMAXFER 0x0 | |
70 | +#define MXS_DMA_DESC_COMMAND_DMA_WRITE 0x1 | |
71 | +#define MXS_DMA_DESC_COMMAND_DMA_READ 0x2 | |
72 | +#define MXS_DMA_DESC_COMMAND_DMA_SENSE 0x3 | |
73 | +#define MXS_DMA_DESC_CHAIN (1 << 2) | |
74 | +#define MXS_DMA_DESC_IRQ (1 << 3) | |
75 | +#define MXS_DMA_DESC_NAND_LOCK (1 << 4) | |
76 | +#define MXS_DMA_DESC_NAND_WAIT_4_READY (1 << 5) | |
77 | +#define MXS_DMA_DESC_DEC_SEM (1 << 6) | |
78 | +#define MXS_DMA_DESC_WAIT4END (1 << 7) | |
79 | +#define MXS_DMA_DESC_HALT_ON_TERMINATE (1 << 8) | |
80 | +#define MXS_DMA_DESC_TERMINATE_FLUSH (1 << 9) | |
81 | +#define MXS_DMA_DESC_PIO_WORDS_MASK (0xf << 12) | |
82 | +#define MXS_DMA_DESC_PIO_WORDS_OFFSET 12 | |
83 | +#define MXS_DMA_DESC_BYTES_MASK (0xffff << 16) | |
84 | +#define MXS_DMA_DESC_BYTES_OFFSET 16 | |
85 | + | |
86 | +struct mxs_dma_cmd { | |
87 | + unsigned long next; | |
88 | + unsigned long data; | |
89 | + union { | |
90 | + dma_addr_t address; | |
91 | + unsigned long alternate; | |
92 | + }; | |
93 | + unsigned long pio_words[DMA_PIO_WORDS]; | |
94 | +}; | |
95 | + | |
96 | +/* | |
97 | + * MXS DMA command descriptor. | |
98 | + * | |
99 | + * This structure incorporates an MXS DMA hardware command structure, along | |
100 | + * with metadata. | |
101 | + */ | |
102 | +#define MXS_DMA_DESC_FIRST (1 << 0) | |
103 | +#define MXS_DMA_DESC_LAST (1 << 1) | |
104 | +#define MXS_DMA_DESC_READY (1 << 31) | |
105 | + | |
106 | +struct mxs_dma_desc { | |
107 | + struct mxs_dma_cmd cmd; | |
108 | + unsigned int flags; | |
109 | + dma_addr_t address; | |
110 | + void *buffer; | |
111 | + struct list_head node; | |
112 | +}; | |
113 | + | |
114 | +/** | |
115 | + * MXS DMA channel | |
116 | + * | |
117 | + * This structure represents a single DMA channel. The MXS platform code | |
118 | + * maintains an array of these structures to represent every DMA channel in the | |
119 | + * system (see mxs_dma_channels). | |
120 | + */ | |
121 | +#define MXS_DMA_FLAGS_IDLE 0 | |
122 | +#define MXS_DMA_FLAGS_BUSY (1 << 0) | |
123 | +#define MXS_DMA_FLAGS_FREE 0 | |
124 | +#define MXS_DMA_FLAGS_ALLOCATED (1 << 16) | |
125 | +#define MXS_DMA_FLAGS_VALID (1 << 31) | |
126 | + | |
127 | +struct mxs_dma_chan { | |
128 | + const char *name; | |
129 | + unsigned long dev; | |
130 | + struct mxs_dma_device *dma; | |
131 | + unsigned int flags; | |
132 | + unsigned int active_num; | |
133 | + unsigned int pending_num; | |
134 | + struct list_head active; | |
135 | + struct list_head done; | |
136 | +}; | |
137 | + | |
138 | +/* Hardware management ops */ | |
139 | +int mxs_dma_enable(int channel); | |
140 | +int mxs_dma_disable(int channel); | |
141 | +int mxs_dma_reset(int channel); | |
142 | +int mxs_dma_freeze(int channel); | |
143 | +int mxs_dma_unfreeze(int channel); | |
144 | +int mxs_dma_read_semaphore(int channel); | |
145 | +int mxs_dma_enable_irq(int channel, int enable); | |
146 | +int mxs_dma_irq_is_pending(int channel); | |
147 | +int mxs_dma_ack_irq(int channel); | |
148 | + | |
149 | +/* Channel management ops */ | |
150 | +int mxs_dma_request(int channel); | |
151 | +int mxs_dma_release(int channel); | |
152 | + | |
153 | +/* Descriptor management ops */ | |
154 | +struct mxs_dma_desc *mxs_dma_desc_alloc(void); | |
155 | +void mxs_dma_desc_free(struct mxs_dma_desc *); | |
156 | + | |
157 | +unsigned int mxs_dma_cmd_address(struct mxs_dma_desc *desc); | |
158 | +int mxs_dma_desc_pending(struct mxs_dma_desc *pdesc); | |
159 | + | |
160 | +int mxs_dma_desc_append(int channel, struct mxs_dma_desc *pdesc); | |
161 | + | |
162 | +int mxs_dma_get_finished(int channel, struct list_head *head); | |
163 | +int mxs_dma_finish(int channel, struct list_head *head); | |
164 | + | |
165 | +int mxs_dma_wait_complete(uint32_t timeout, unsigned int chan); | |
166 | +int mxs_dma_go(int chan); | |
167 | + | |
168 | +int mxs_dma_init(void); | |
169 | + | |
170 | +#endif /* __DMA_H__ */ |
arch/arm/include/asm/arch-mx28/imx-regs.h
arch/arm/include/asm/arch-mx28/regs-apbh.h
1 | +/* | |
2 | + * Freescale i.MX28 APBH Register Definitions | |
3 | + * | |
4 | + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> | |
5 | + * on behalf of DENX Software Engineering GmbH | |
6 | + * | |
7 | + * Based on code from LTIB: | |
8 | + * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. | |
9 | + * | |
10 | + * This program is free software; you can redistribute it and/or modify | |
11 | + * it under the terms of the GNU General Public License as published by | |
12 | + * the Free Software Foundation; either version 2 of the License, or | |
13 | + * (at your option) any later version. | |
14 | + * | |
15 | + * This program is distributed in the hope that it will be useful, | |
16 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | + * GNU General Public License for more details. | |
19 | + * | |
20 | + * You should have received a copy of the GNU General Public License | |
21 | + * along with this program; if not, write to the Free Software | |
22 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
23 | + * | |
24 | + */ | |
25 | + | |
26 | +#ifndef __REGS_APBH_H__ | |
27 | +#define __REGS_APBH_H__ | |
28 | + | |
29 | +#include <asm/arch/regs-common.h> | |
30 | + | |
31 | +#ifndef __ASSEMBLY__ | |
32 | +struct mx28_apbh_regs { | |
33 | + mx28_reg(hw_apbh_ctrl0) | |
34 | + mx28_reg(hw_apbh_ctrl1) | |
35 | + mx28_reg(hw_apbh_ctrl2) | |
36 | + mx28_reg(hw_apbh_channel_ctrl) | |
37 | + mx28_reg(hw_apbh_devsel) | |
38 | + mx28_reg(hw_apbh_dma_burst_size) | |
39 | + mx28_reg(hw_apbh_debug) | |
40 | + | |
41 | + uint32_t reserved[36]; | |
42 | + | |
43 | + union { | |
44 | + struct { | |
45 | + mx28_reg(hw_apbh_ch_curcmdar) | |
46 | + mx28_reg(hw_apbh_ch_nxtcmdar) | |
47 | + mx28_reg(hw_apbh_ch_cmd) | |
48 | + mx28_reg(hw_apbh_ch_bar) | |
49 | + mx28_reg(hw_apbh_ch_sema) | |
50 | + mx28_reg(hw_apbh_ch_debug1) | |
51 | + mx28_reg(hw_apbh_ch_debug2) | |
52 | + } ch[16]; | |
53 | + struct { | |
54 | + mx28_reg(hw_apbh_ch0_curcmdar) | |
55 | + mx28_reg(hw_apbh_ch0_nxtcmdar) | |
56 | + mx28_reg(hw_apbh_ch0_cmd) | |
57 | + mx28_reg(hw_apbh_ch0_bar) | |
58 | + mx28_reg(hw_apbh_ch0_sema) | |
59 | + mx28_reg(hw_apbh_ch0_debug1) | |
60 | + mx28_reg(hw_apbh_ch0_debug2) | |
61 | + mx28_reg(hw_apbh_ch1_curcmdar) | |
62 | + mx28_reg(hw_apbh_ch1_nxtcmdar) | |
63 | + mx28_reg(hw_apbh_ch1_cmd) | |
64 | + mx28_reg(hw_apbh_ch1_bar) | |
65 | + mx28_reg(hw_apbh_ch1_sema) | |
66 | + mx28_reg(hw_apbh_ch1_debug1) | |
67 | + mx28_reg(hw_apbh_ch1_debug2) | |
68 | + mx28_reg(hw_apbh_ch2_curcmdar) | |
69 | + mx28_reg(hw_apbh_ch2_nxtcmdar) | |
70 | + mx28_reg(hw_apbh_ch2_cmd) | |
71 | + mx28_reg(hw_apbh_ch2_bar) | |
72 | + mx28_reg(hw_apbh_ch2_sema) | |
73 | + mx28_reg(hw_apbh_ch2_debug1) | |
74 | + mx28_reg(hw_apbh_ch2_debug2) | |
75 | + mx28_reg(hw_apbh_ch3_curcmdar) | |
76 | + mx28_reg(hw_apbh_ch3_nxtcmdar) | |
77 | + mx28_reg(hw_apbh_ch3_cmd) | |
78 | + mx28_reg(hw_apbh_ch3_bar) | |
79 | + mx28_reg(hw_apbh_ch3_sema) | |
80 | + mx28_reg(hw_apbh_ch3_debug1) | |
81 | + mx28_reg(hw_apbh_ch3_debug2) | |
82 | + mx28_reg(hw_apbh_ch4_curcmdar) | |
83 | + mx28_reg(hw_apbh_ch4_nxtcmdar) | |
84 | + mx28_reg(hw_apbh_ch4_cmd) | |
85 | + mx28_reg(hw_apbh_ch4_bar) | |
86 | + mx28_reg(hw_apbh_ch4_sema) | |
87 | + mx28_reg(hw_apbh_ch4_debug1) | |
88 | + mx28_reg(hw_apbh_ch4_debug2) | |
89 | + mx28_reg(hw_apbh_ch5_curcmdar) | |
90 | + mx28_reg(hw_apbh_ch5_nxtcmdar) | |
91 | + mx28_reg(hw_apbh_ch5_cmd) | |
92 | + mx28_reg(hw_apbh_ch5_bar) | |
93 | + mx28_reg(hw_apbh_ch5_sema) | |
94 | + mx28_reg(hw_apbh_ch5_debug1) | |
95 | + mx28_reg(hw_apbh_ch5_debug2) | |
96 | + mx28_reg(hw_apbh_ch6_curcmdar) | |
97 | + mx28_reg(hw_apbh_ch6_nxtcmdar) | |
98 | + mx28_reg(hw_apbh_ch6_cmd) | |
99 | + mx28_reg(hw_apbh_ch6_bar) | |
100 | + mx28_reg(hw_apbh_ch6_sema) | |
101 | + mx28_reg(hw_apbh_ch6_debug1) | |
102 | + mx28_reg(hw_apbh_ch6_debug2) | |
103 | + mx28_reg(hw_apbh_ch7_curcmdar) | |
104 | + mx28_reg(hw_apbh_ch7_nxtcmdar) | |
105 | + mx28_reg(hw_apbh_ch7_cmd) | |
106 | + mx28_reg(hw_apbh_ch7_bar) | |
107 | + mx28_reg(hw_apbh_ch7_sema) | |
108 | + mx28_reg(hw_apbh_ch7_debug1) | |
109 | + mx28_reg(hw_apbh_ch7_debug2) | |
110 | + mx28_reg(hw_apbh_ch8_curcmdar) | |
111 | + mx28_reg(hw_apbh_ch8_nxtcmdar) | |
112 | + mx28_reg(hw_apbh_ch8_cmd) | |
113 | + mx28_reg(hw_apbh_ch8_bar) | |
114 | + mx28_reg(hw_apbh_ch8_sema) | |
115 | + mx28_reg(hw_apbh_ch8_debug1) | |
116 | + mx28_reg(hw_apbh_ch8_debug2) | |
117 | + mx28_reg(hw_apbh_ch9_curcmdar) | |
118 | + mx28_reg(hw_apbh_ch9_nxtcmdar) | |
119 | + mx28_reg(hw_apbh_ch9_cmd) | |
120 | + mx28_reg(hw_apbh_ch9_bar) | |
121 | + mx28_reg(hw_apbh_ch9_sema) | |
122 | + mx28_reg(hw_apbh_ch9_debug1) | |
123 | + mx28_reg(hw_apbh_ch9_debug2) | |
124 | + mx28_reg(hw_apbh_ch10_curcmdar) | |
125 | + mx28_reg(hw_apbh_ch10_nxtcmdar) | |
126 | + mx28_reg(hw_apbh_ch10_cmd) | |
127 | + mx28_reg(hw_apbh_ch10_bar) | |
128 | + mx28_reg(hw_apbh_ch10_sema) | |
129 | + mx28_reg(hw_apbh_ch10_debug1) | |
130 | + mx28_reg(hw_apbh_ch10_debug2) | |
131 | + mx28_reg(hw_apbh_ch11_curcmdar) | |
132 | + mx28_reg(hw_apbh_ch11_nxtcmdar) | |
133 | + mx28_reg(hw_apbh_ch11_cmd) | |
134 | + mx28_reg(hw_apbh_ch11_bar) | |
135 | + mx28_reg(hw_apbh_ch11_sema) | |
136 | + mx28_reg(hw_apbh_ch11_debug1) | |
137 | + mx28_reg(hw_apbh_ch11_debug2) | |
138 | + mx28_reg(hw_apbh_ch12_curcmdar) | |
139 | + mx28_reg(hw_apbh_ch12_nxtcmdar) | |
140 | + mx28_reg(hw_apbh_ch12_cmd) | |
141 | + mx28_reg(hw_apbh_ch12_bar) | |
142 | + mx28_reg(hw_apbh_ch12_sema) | |
143 | + mx28_reg(hw_apbh_ch12_debug1) | |
144 | + mx28_reg(hw_apbh_ch12_debug2) | |
145 | + mx28_reg(hw_apbh_ch13_curcmdar) | |
146 | + mx28_reg(hw_apbh_ch13_nxtcmdar) | |
147 | + mx28_reg(hw_apbh_ch13_cmd) | |
148 | + mx28_reg(hw_apbh_ch13_bar) | |
149 | + mx28_reg(hw_apbh_ch13_sema) | |
150 | + mx28_reg(hw_apbh_ch13_debug1) | |
151 | + mx28_reg(hw_apbh_ch13_debug2) | |
152 | + mx28_reg(hw_apbh_ch14_curcmdar) | |
153 | + mx28_reg(hw_apbh_ch14_nxtcmdar) | |
154 | + mx28_reg(hw_apbh_ch14_cmd) | |
155 | + mx28_reg(hw_apbh_ch14_bar) | |
156 | + mx28_reg(hw_apbh_ch14_sema) | |
157 | + mx28_reg(hw_apbh_ch14_debug1) | |
158 | + mx28_reg(hw_apbh_ch14_debug2) | |
159 | + mx28_reg(hw_apbh_ch15_curcmdar) | |
160 | + mx28_reg(hw_apbh_ch15_nxtcmdar) | |
161 | + mx28_reg(hw_apbh_ch15_cmd) | |
162 | + mx28_reg(hw_apbh_ch15_bar) | |
163 | + mx28_reg(hw_apbh_ch15_sema) | |
164 | + mx28_reg(hw_apbh_ch15_debug1) | |
165 | + mx28_reg(hw_apbh_ch15_debug2) | |
166 | + }; | |
167 | + }; | |
168 | + mx28_reg(hw_apbh_version) | |
169 | +}; | |
170 | +#endif | |
171 | + | |
172 | +#define APBH_CTRL0_SFTRST (1 << 31) | |
173 | +#define APBH_CTRL0_CLKGATE (1 << 30) | |
174 | +#define APBH_CTRL0_AHB_BURST8_EN (1 << 29) | |
175 | +#define APBH_CTRL0_APB_BURST_EN (1 << 28) | |
176 | +#define APBH_CTRL0_RSVD0_MASK (0xfff << 16) | |
177 | +#define APBH_CTRL0_RSVD0_OFFSET 16 | |
178 | +#define APBH_CTRL0_CLKGATE_CHANNEL_MASK 0xffff | |
179 | +#define APBH_CTRL0_CLKGATE_CHANNEL_OFFSET 0 | |
180 | +#define APBH_CTRL0_CLKGATE_CHANNEL_SSP0 0x0001 | |
181 | +#define APBH_CTRL0_CLKGATE_CHANNEL_SSP1 0x0002 | |
182 | +#define APBH_CTRL0_CLKGATE_CHANNEL_SSP2 0x0004 | |
183 | +#define APBH_CTRL0_CLKGATE_CHANNEL_SSP3 0x0008 | |
184 | +#define APBH_CTRL0_CLKGATE_CHANNEL_NAND0 0x0010 | |
185 | +#define APBH_CTRL0_CLKGATE_CHANNEL_NAND1 0x0020 | |
186 | +#define APBH_CTRL0_CLKGATE_CHANNEL_NAND2 0x0040 | |
187 | +#define APBH_CTRL0_CLKGATE_CHANNEL_NAND3 0x0080 | |
188 | +#define APBH_CTRL0_CLKGATE_CHANNEL_NAND4 0x0100 | |
189 | +#define APBH_CTRL0_CLKGATE_CHANNEL_NAND5 0x0200 | |
190 | +#define APBH_CTRL0_CLKGATE_CHANNEL_NAND6 0x0400 | |
191 | +#define APBH_CTRL0_CLKGATE_CHANNEL_NAND7 0x0800 | |
192 | +#define APBH_CTRL0_CLKGATE_CHANNEL_HSADC 0x1000 | |
193 | +#define APBH_CTRL0_CLKGATE_CHANNEL_LCDIF 0x2000 | |
194 | + | |
195 | +#define APBH_CTRL1_CH15_CMDCMPLT_IRQ_EN (1 << 31) | |
196 | +#define APBH_CTRL1_CH14_CMDCMPLT_IRQ_EN (1 << 30) | |
197 | +#define APBH_CTRL1_CH13_CMDCMPLT_IRQ_EN (1 << 29) | |
198 | +#define APBH_CTRL1_CH12_CMDCMPLT_IRQ_EN (1 << 28) | |
199 | +#define APBH_CTRL1_CH11_CMDCMPLT_IRQ_EN (1 << 27) | |
200 | +#define APBH_CTRL1_CH10_CMDCMPLT_IRQ_EN (1 << 26) | |
201 | +#define APBH_CTRL1_CH9_CMDCMPLT_IRQ_EN (1 << 25) | |
202 | +#define APBH_CTRL1_CH8_CMDCMPLT_IRQ_EN (1 << 24) | |
203 | +#define APBH_CTRL1_CH7_CMDCMPLT_IRQ_EN (1 << 23) | |
204 | +#define APBH_CTRL1_CH6_CMDCMPLT_IRQ_EN (1 << 22) | |
205 | +#define APBH_CTRL1_CH5_CMDCMPLT_IRQ_EN (1 << 21) | |
206 | +#define APBH_CTRL1_CH4_CMDCMPLT_IRQ_EN (1 << 20) | |
207 | +#define APBH_CTRL1_CH3_CMDCMPLT_IRQ_EN (1 << 19) | |
208 | +#define APBH_CTRL1_CH2_CMDCMPLT_IRQ_EN (1 << 18) | |
209 | +#define APBH_CTRL1_CH1_CMDCMPLT_IRQ_EN (1 << 17) | |
210 | +#define APBH_CTRL1_CH0_CMDCMPLT_IRQ_EN (1 << 16) | |
211 | +#define APBH_CTRL1_CH_CMDCMPLT_IRQ_EN_OFFSET 16 | |
212 | +#define APBH_CTRL1_CH_CMDCMPLT_IRQ_EN_MASK (0xffff << 16) | |
213 | +#define APBH_CTRL1_CH15_CMDCMPLT_IRQ (1 << 15) | |
214 | +#define APBH_CTRL1_CH14_CMDCMPLT_IRQ (1 << 14) | |
215 | +#define APBH_CTRL1_CH13_CMDCMPLT_IRQ (1 << 13) | |
216 | +#define APBH_CTRL1_CH12_CMDCMPLT_IRQ (1 << 12) | |
217 | +#define APBH_CTRL1_CH11_CMDCMPLT_IRQ (1 << 11) | |
218 | +#define APBH_CTRL1_CH10_CMDCMPLT_IRQ (1 << 10) | |
219 | +#define APBH_CTRL1_CH9_CMDCMPLT_IRQ (1 << 9) | |
220 | +#define APBH_CTRL1_CH8_CMDCMPLT_IRQ (1 << 8) | |
221 | +#define APBH_CTRL1_CH7_CMDCMPLT_IRQ (1 << 7) | |
222 | +#define APBH_CTRL1_CH6_CMDCMPLT_IRQ (1 << 6) | |
223 | +#define APBH_CTRL1_CH5_CMDCMPLT_IRQ (1 << 5) | |
224 | +#define APBH_CTRL1_CH4_CMDCMPLT_IRQ (1 << 4) | |
225 | +#define APBH_CTRL1_CH3_CMDCMPLT_IRQ (1 << 3) | |
226 | +#define APBH_CTRL1_CH2_CMDCMPLT_IRQ (1 << 2) | |
227 | +#define APBH_CTRL1_CH1_CMDCMPLT_IRQ (1 << 1) | |
228 | +#define APBH_CTRL1_CH0_CMDCMPLT_IRQ (1 << 0) | |
229 | + | |
230 | +#define APBH_CTRL2_CH15_ERROR_STATUS (1 << 31) | |
231 | +#define APBH_CTRL2_CH14_ERROR_STATUS (1 << 30) | |
232 | +#define APBH_CTRL2_CH13_ERROR_STATUS (1 << 29) | |
233 | +#define APBH_CTRL2_CH12_ERROR_STATUS (1 << 28) | |
234 | +#define APBH_CTRL2_CH11_ERROR_STATUS (1 << 27) | |
235 | +#define APBH_CTRL2_CH10_ERROR_STATUS (1 << 26) | |
236 | +#define APBH_CTRL2_CH9_ERROR_STATUS (1 << 25) | |
237 | +#define APBH_CTRL2_CH8_ERROR_STATUS (1 << 24) | |
238 | +#define APBH_CTRL2_CH7_ERROR_STATUS (1 << 23) | |
239 | +#define APBH_CTRL2_CH6_ERROR_STATUS (1 << 22) | |
240 | +#define APBH_CTRL2_CH5_ERROR_STATUS (1 << 21) | |
241 | +#define APBH_CTRL2_CH4_ERROR_STATUS (1 << 20) | |
242 | +#define APBH_CTRL2_CH3_ERROR_STATUS (1 << 19) | |
243 | +#define APBH_CTRL2_CH2_ERROR_STATUS (1 << 18) | |
244 | +#define APBH_CTRL2_CH1_ERROR_STATUS (1 << 17) | |
245 | +#define APBH_CTRL2_CH0_ERROR_STATUS (1 << 16) | |
246 | +#define APBH_CTRL2_CH15_ERROR_IRQ (1 << 15) | |
247 | +#define APBH_CTRL2_CH14_ERROR_IRQ (1 << 14) | |
248 | +#define APBH_CTRL2_CH13_ERROR_IRQ (1 << 13) | |
249 | +#define APBH_CTRL2_CH12_ERROR_IRQ (1 << 12) | |
250 | +#define APBH_CTRL2_CH11_ERROR_IRQ (1 << 11) | |
251 | +#define APBH_CTRL2_CH10_ERROR_IRQ (1 << 10) | |
252 | +#define APBH_CTRL2_CH9_ERROR_IRQ (1 << 9) | |
253 | +#define APBH_CTRL2_CH8_ERROR_IRQ (1 << 8) | |
254 | +#define APBH_CTRL2_CH7_ERROR_IRQ (1 << 7) | |
255 | +#define APBH_CTRL2_CH6_ERROR_IRQ (1 << 6) | |
256 | +#define APBH_CTRL2_CH5_ERROR_IRQ (1 << 5) | |
257 | +#define APBH_CTRL2_CH4_ERROR_IRQ (1 << 4) | |
258 | +#define APBH_CTRL2_CH3_ERROR_IRQ (1 << 3) | |
259 | +#define APBH_CTRL2_CH2_ERROR_IRQ (1 << 2) | |
260 | +#define APBH_CTRL2_CH1_ERROR_IRQ (1 << 1) | |
261 | +#define APBH_CTRL2_CH0_ERROR_IRQ (1 << 0) | |
262 | + | |
263 | +#define APBH_CHANNEL_CTRL_RESET_CHANNEL_MASK (0xffff << 16) | |
264 | +#define APBH_CHANNEL_CTRL_RESET_CHANNEL_OFFSET 16 | |
265 | +#define APBH_CHANNEL_CTRL_RESET_CHANNEL_SSP0 (0x0001 << 16) | |
266 | +#define APBH_CHANNEL_CTRL_RESET_CHANNEL_SSP1 (0x0002 << 16) | |
267 | +#define APBH_CHANNEL_CTRL_RESET_CHANNEL_SSP2 (0x0004 << 16) | |
268 | +#define APBH_CHANNEL_CTRL_RESET_CHANNEL_SSP3 (0x0008 << 16) | |
269 | +#define APBH_CHANNEL_CTRL_RESET_CHANNEL_NAND0 (0x0010 << 16) | |
270 | +#define APBH_CHANNEL_CTRL_RESET_CHANNEL_NAND1 (0x0020 << 16) | |
271 | +#define APBH_CHANNEL_CTRL_RESET_CHANNEL_NAND2 (0x0040 << 16) | |
272 | +#define APBH_CHANNEL_CTRL_RESET_CHANNEL_NAND3 (0x0080 << 16) | |
273 | +#define APBH_CHANNEL_CTRL_RESET_CHANNEL_NAND4 (0x0100 << 16) | |
274 | +#define APBH_CHANNEL_CTRL_RESET_CHANNEL_NAND5 (0x0200 << 16) | |
275 | +#define APBH_CHANNEL_CTRL_RESET_CHANNEL_NAND6 (0x0400 << 16) | |
276 | +#define APBH_CHANNEL_CTRL_RESET_CHANNEL_NAND7 (0x0800 << 16) | |
277 | +#define APBH_CHANNEL_CTRL_RESET_CHANNEL_HSADC (0x1000 << 16) | |
278 | +#define APBH_CHANNEL_CTRL_RESET_CHANNEL_LCDIF (0x2000 << 16) | |
279 | +#define APBH_CHANNEL_CTRL_FREEZE_CHANNEL_MASK 0xffff | |
280 | +#define APBH_CHANNEL_CTRL_FREEZE_CHANNEL_OFFSET 0 | |
281 | +#define APBH_CHANNEL_CTRL_FREEZE_CHANNEL_SSP0 0x0001 | |
282 | +#define APBH_CHANNEL_CTRL_FREEZE_CHANNEL_SSP1 0x0002 | |
283 | +#define APBH_CHANNEL_CTRL_FREEZE_CHANNEL_SSP2 0x0004 | |
284 | +#define APBH_CHANNEL_CTRL_FREEZE_CHANNEL_SSP3 0x0008 | |
285 | +#define APBH_CHANNEL_CTRL_FREEZE_CHANNEL_NAND0 0x0010 | |
286 | +#define APBH_CHANNEL_CTRL_FREEZE_CHANNEL_NAND1 0x0020 | |
287 | +#define APBH_CHANNEL_CTRL_FREEZE_CHANNEL_NAND2 0x0040 | |
288 | +#define APBH_CHANNEL_CTRL_FREEZE_CHANNEL_NAND3 0x0080 | |
289 | +#define APBH_CHANNEL_CTRL_FREEZE_CHANNEL_NAND4 0x0100 | |
290 | +#define APBH_CHANNEL_CTRL_FREEZE_CHANNEL_NAND5 0x0200 | |
291 | +#define APBH_CHANNEL_CTRL_FREEZE_CHANNEL_NAND6 0x0400 | |
292 | +#define APBH_CHANNEL_CTRL_FREEZE_CHANNEL_NAND7 0x0800 | |
293 | +#define APBH_CHANNEL_CTRL_FREEZE_CHANNEL_HSADC 0x1000 | |
294 | +#define APBH_CHANNEL_CTRL_FREEZE_CHANNEL_LCDIF 0x2000 | |
295 | + | |
296 | +#define APBH_DEVSEL_CH15_MASK (0x3 << 30) | |
297 | +#define APBH_DEVSEL_CH15_OFFSET 30 | |
298 | +#define APBH_DEVSEL_CH14_MASK (0x3 << 28) | |
299 | +#define APBH_DEVSEL_CH14_OFFSET 28 | |
300 | +#define APBH_DEVSEL_CH13_MASK (0x3 << 26) | |
301 | +#define APBH_DEVSEL_CH13_OFFSET 26 | |
302 | +#define APBH_DEVSEL_CH12_MASK (0x3 << 24) | |
303 | +#define APBH_DEVSEL_CH12_OFFSET 24 | |
304 | +#define APBH_DEVSEL_CH11_MASK (0x3 << 22) | |
305 | +#define APBH_DEVSEL_CH11_OFFSET 22 | |
306 | +#define APBH_DEVSEL_CH10_MASK (0x3 << 20) | |
307 | +#define APBH_DEVSEL_CH10_OFFSET 20 | |
308 | +#define APBH_DEVSEL_CH9_MASK (0x3 << 18) | |
309 | +#define APBH_DEVSEL_CH9_OFFSET 18 | |
310 | +#define APBH_DEVSEL_CH8_MASK (0x3 << 16) | |
311 | +#define APBH_DEVSEL_CH8_OFFSET 16 | |
312 | +#define APBH_DEVSEL_CH7_MASK (0x3 << 14) | |
313 | +#define APBH_DEVSEL_CH7_OFFSET 14 | |
314 | +#define APBH_DEVSEL_CH6_MASK (0x3 << 12) | |
315 | +#define APBH_DEVSEL_CH6_OFFSET 12 | |
316 | +#define APBH_DEVSEL_CH5_MASK (0x3 << 10) | |
317 | +#define APBH_DEVSEL_CH5_OFFSET 10 | |
318 | +#define APBH_DEVSEL_CH4_MASK (0x3 << 8) | |
319 | +#define APBH_DEVSEL_CH4_OFFSET 8 | |
320 | +#define APBH_DEVSEL_CH3_MASK (0x3 << 6) | |
321 | +#define APBH_DEVSEL_CH3_OFFSET 6 | |
322 | +#define APBH_DEVSEL_CH2_MASK (0x3 << 4) | |
323 | +#define APBH_DEVSEL_CH2_OFFSET 4 | |
324 | +#define APBH_DEVSEL_CH1_MASK (0x3 << 2) | |
325 | +#define APBH_DEVSEL_CH1_OFFSET 2 | |
326 | +#define APBH_DEVSEL_CH0_MASK (0x3 << 0) | |
327 | +#define APBH_DEVSEL_CH0_OFFSET 0 | |
328 | + | |
329 | +#define APBH_DMA_BURST_SIZE_CH15_MASK (0x3 << 30) | |
330 | +#define APBH_DMA_BURST_SIZE_CH15_OFFSET 30 | |
331 | +#define APBH_DMA_BURST_SIZE_CH14_MASK (0x3 << 28) | |
332 | +#define APBH_DMA_BURST_SIZE_CH14_OFFSET 28 | |
333 | +#define APBH_DMA_BURST_SIZE_CH13_MASK (0x3 << 26) | |
334 | +#define APBH_DMA_BURST_SIZE_CH13_OFFSET 26 | |
335 | +#define APBH_DMA_BURST_SIZE_CH12_MASK (0x3 << 24) | |
336 | +#define APBH_DMA_BURST_SIZE_CH12_OFFSET 24 | |
337 | +#define APBH_DMA_BURST_SIZE_CH11_MASK (0x3 << 22) | |
338 | +#define APBH_DMA_BURST_SIZE_CH11_OFFSET 22 | |
339 | +#define APBH_DMA_BURST_SIZE_CH10_MASK (0x3 << 20) | |
340 | +#define APBH_DMA_BURST_SIZE_CH10_OFFSET 20 | |
341 | +#define APBH_DMA_BURST_SIZE_CH9_MASK (0x3 << 18) | |
342 | +#define APBH_DMA_BURST_SIZE_CH9_OFFSET 18 | |
343 | +#define APBH_DMA_BURST_SIZE_CH8_MASK (0x3 << 16) | |
344 | +#define APBH_DMA_BURST_SIZE_CH8_OFFSET 16 | |
345 | +#define APBH_DMA_BURST_SIZE_CH8_BURST0 (0x0 << 16) | |
346 | +#define APBH_DMA_BURST_SIZE_CH8_BURST4 (0x1 << 16) | |
347 | +#define APBH_DMA_BURST_SIZE_CH8_BURST8 (0x2 << 16) | |
348 | +#define APBH_DMA_BURST_SIZE_CH7_MASK (0x3 << 14) | |
349 | +#define APBH_DMA_BURST_SIZE_CH7_OFFSET 14 | |
350 | +#define APBH_DMA_BURST_SIZE_CH6_MASK (0x3 << 12) | |
351 | +#define APBH_DMA_BURST_SIZE_CH6_OFFSET 12 | |
352 | +#define APBH_DMA_BURST_SIZE_CH5_MASK (0x3 << 10) | |
353 | +#define APBH_DMA_BURST_SIZE_CH5_OFFSET 10 | |
354 | +#define APBH_DMA_BURST_SIZE_CH4_MASK (0x3 << 8) | |
355 | +#define APBH_DMA_BURST_SIZE_CH4_OFFSET 8 | |
356 | +#define APBH_DMA_BURST_SIZE_CH3_MASK (0x3 << 6) | |
357 | +#define APBH_DMA_BURST_SIZE_CH3_OFFSET 6 | |
358 | +#define APBH_DMA_BURST_SIZE_CH3_BURST0 (0x0 << 6) | |
359 | +#define APBH_DMA_BURST_SIZE_CH3_BURST4 (0x1 << 6) | |
360 | +#define APBH_DMA_BURST_SIZE_CH3_BURST8 (0x2 << 6) | |
361 | + | |
362 | +#define APBH_DMA_BURST_SIZE_CH2_MASK (0x3 << 4) | |
363 | +#define APBH_DMA_BURST_SIZE_CH2_OFFSET 4 | |
364 | +#define APBH_DMA_BURST_SIZE_CH2_BURST0 (0x0 << 4) | |
365 | +#define APBH_DMA_BURST_SIZE_CH2_BURST4 (0x1 << 4) | |
366 | +#define APBH_DMA_BURST_SIZE_CH2_BURST8 (0x2 << 4) | |
367 | +#define APBH_DMA_BURST_SIZE_CH1_MASK (0x3 << 2) | |
368 | +#define APBH_DMA_BURST_SIZE_CH1_OFFSET 2 | |
369 | +#define APBH_DMA_BURST_SIZE_CH1_BURST0 (0x0 << 2) | |
370 | +#define APBH_DMA_BURST_SIZE_CH1_BURST4 (0x1 << 2) | |
371 | +#define APBH_DMA_BURST_SIZE_CH1_BURST8 (0x2 << 2) | |
372 | + | |
373 | +#define APBH_DMA_BURST_SIZE_CH0_MASK 0x3 | |
374 | +#define APBH_DMA_BURST_SIZE_CH0_OFFSET 0 | |
375 | +#define APBH_DMA_BURST_SIZE_CH0_BURST0 0x0 | |
376 | +#define APBH_DMA_BURST_SIZE_CH0_BURST4 0x1 | |
377 | +#define APBH_DMA_BURST_SIZE_CH0_BURST8 0x2 | |
378 | + | |
379 | +#define APBH_DEBUG_GPMI_ONE_FIFO (1 << 0) | |
380 | + | |
381 | +#define APBH_CHn_CURCMDAR_CMD_ADDR_MASK 0xffffffff | |
382 | +#define APBH_CHn_CURCMDAR_CMD_ADDR_OFFSET 0 | |
383 | + | |
384 | +#define APBH_CHn_NXTCMDAR_CMD_ADDR_MASK 0xffffffff | |
385 | +#define APBH_CHn_NXTCMDAR_CMD_ADDR_OFFSET 0 | |
386 | + | |
387 | +#define APBH_CHn_CMD_XFER_COUNT_MASK (0xffff << 16) | |
388 | +#define APBH_CHn_CMD_XFER_COUNT_OFFSET 16 | |
389 | +#define APBH_CHn_CMD_CMDWORDS_MASK (0xf << 12) | |
390 | +#define APBH_CHn_CMD_CMDWORDS_OFFSET 12 | |
391 | +#define APBH_CHn_CMD_HALTONTERMINATE (1 << 8) | |
392 | +#define APBH_CHn_CMD_WAIT4ENDCMD (1 << 7) | |
393 | +#define APBH_CHn_CMD_SEMAPHORE (1 << 6) | |
394 | +#define APBH_CHn_CMD_NANDWAIT4READY (1 << 5) | |
395 | +#define APBH_CHn_CMD_NANDLOCK (1 << 4) | |
396 | +#define APBH_CHn_CMD_IRQONCMPLT (1 << 3) | |
397 | +#define APBH_CHn_CMD_CHAIN (1 << 2) | |
398 | +#define APBH_CHn_CMD_COMMAND_MASK 0x3 | |
399 | +#define APBH_CHn_CMD_COMMAND_OFFSET 0 | |
400 | +#define APBH_CHn_CMD_COMMAND_NO_DMA_XFER 0x0 | |
401 | +#define APBH_CHn_CMD_COMMAND_DMA_WRITE 0x1 | |
402 | +#define APBH_CHn_CMD_COMMAND_DMA_READ 0x2 | |
403 | +#define APBH_CHn_CMD_COMMAND_DMA_SENSE 0x3 | |
404 | + | |
405 | +#define APBH_CHn_BAR_ADDRESS_MASK 0xffffffff | |
406 | +#define APBH_CHn_BAR_ADDRESS_OFFSET 0 | |
407 | + | |
408 | +#define APBH_CHn_SEMA_RSVD2_MASK (0xff << 24) | |
409 | +#define APBH_CHn_SEMA_RSVD2_OFFSET 24 | |
410 | +#define APBH_CHn_SEMA_PHORE_MASK (0xff << 16) | |
411 | +#define APBH_CHn_SEMA_PHORE_OFFSET 16 | |
412 | +#define APBH_CHn_SEMA_RSVD1_MASK (0xff << 8) | |
413 | +#define APBH_CHn_SEMA_RSVD1_OFFSET 8 | |
414 | +#define APBH_CHn_SEMA_INCREMENT_SEMA_MASK (0xff << 0) | |
415 | +#define APBH_CHn_SEMA_INCREMENT_SEMA_OFFSET 0 | |
416 | + | |
417 | +#define APBH_CHn_DEBUG1_REQ (1 << 31) | |
418 | +#define APBH_CHn_DEBUG1_BURST (1 << 30) | |
419 | +#define APBH_CHn_DEBUG1_KICK (1 << 29) | |
420 | +#define APBH_CHn_DEBUG1_END (1 << 28) | |
421 | +#define APBH_CHn_DEBUG1_SENSE (1 << 27) | |
422 | +#define APBH_CHn_DEBUG1_READY (1 << 26) | |
423 | +#define APBH_CHn_DEBUG1_LOCK (1 << 25) | |
424 | +#define APBH_CHn_DEBUG1_NEXTCMDADDRVALID (1 << 24) | |
425 | +#define APBH_CHn_DEBUG1_RD_FIFO_EMPTY (1 << 23) | |
426 | +#define APBH_CHn_DEBUG1_RD_FIFO_FULL (1 << 22) | |
427 | +#define APBH_CHn_DEBUG1_WR_FIFO_EMPTY (1 << 21) | |
428 | +#define APBH_CHn_DEBUG1_WR_FIFO_FULL (1 << 20) | |
429 | +#define APBH_CHn_DEBUG1_RSVD1_MASK (0x7fff << 5) | |
430 | +#define APBH_CHn_DEBUG1_RSVD1_OFFSET 5 | |
431 | +#define APBH_CHn_DEBUG1_STATEMACHINE_MASK 0x1f | |
432 | +#define APBH_CHn_DEBUG1_STATEMACHINE_OFFSET 0 | |
433 | +#define APBH_CHn_DEBUG1_STATEMACHINE_IDLE 0x00 | |
434 | +#define APBH_CHn_DEBUG1_STATEMACHINE_REQ_CMD1 0x01 | |
435 | +#define APBH_CHn_DEBUG1_STATEMACHINE_REQ_CMD3 0x02 | |
436 | +#define APBH_CHn_DEBUG1_STATEMACHINE_REQ_CMD2 0x03 | |
437 | +#define APBH_CHn_DEBUG1_STATEMACHINE_XFER_DECODE 0x04 | |
438 | +#define APBH_CHn_DEBUG1_STATEMACHINE_REQ_WAIT 0x05 | |
439 | +#define APBH_CHn_DEBUG1_STATEMACHINE_REQ_CMD4 0x06 | |
440 | +#define APBH_CHn_DEBUG1_STATEMACHINE_PIO_REQ 0x07 | |
441 | +#define APBH_CHn_DEBUG1_STATEMACHINE_READ_FLUSH 0x08 | |
442 | +#define APBH_CHn_DEBUG1_STATEMACHINE_READ_WAIT 0x09 | |
443 | +#define APBH_CHn_DEBUG1_STATEMACHINE_WRITE 0x0c | |
444 | +#define APBH_CHn_DEBUG1_STATEMACHINE_READ_REQ 0x0d | |
445 | +#define APBH_CHn_DEBUG1_STATEMACHINE_CHECK_CHAIN 0x0e | |
446 | +#define APBH_CHn_DEBUG1_STATEMACHINE_XFER_COMPLETE 0x0f | |
447 | +#define APBH_CHn_DEBUG1_STATEMACHINE_TERMINATE 0x14 | |
448 | +#define APBH_CHn_DEBUG1_STATEMACHINE_WAIT_END 0x15 | |
449 | +#define APBH_CHn_DEBUG1_STATEMACHINE_WRITE_WAIT 0x1c | |
450 | +#define APBH_CHn_DEBUG1_STATEMACHINE_HALT_AFTER_TERM 0x1d | |
451 | +#define APBH_CHn_DEBUG1_STATEMACHINE_CHECK_WAIT 0x1e | |
452 | +#define APBH_CHn_DEBUG1_STATEMACHINE_WAIT_READY 0x1f | |
453 | + | |
454 | +#define APBH_CHn_DEBUG2_APB_BYTES_MASK (0xffff << 16) | |
455 | +#define APBH_CHn_DEBUG2_APB_BYTES_OFFSET 16 | |
456 | +#define APBH_CHn_DEBUG2_AHB_BYTES_MASK 0xffff | |
457 | +#define APBH_CHn_DEBUG2_AHB_BYTES_OFFSET 0 | |
458 | + | |
459 | +#define APBH_VERSION_MAJOR_MASK (0xff << 24) | |
460 | +#define APBH_VERSION_MAJOR_OFFSET 24 | |
461 | +#define APBH_VERSION_MINOR_MASK (0xff << 16) | |
462 | +#define APBH_VERSION_MINOR_OFFSET 16 | |
463 | +#define APBH_VERSION_STEP_MASK 0xffff | |
464 | +#define APBH_VERSION_STEP_OFFSET 0 | |
465 | + | |
466 | +#endif /* __REGS_APBH_H__ */ |
drivers/dma/Makefile
drivers/dma/apbh_dma.c
1 | +/* | |
2 | + * Freescale i.MX28 APBH DMA driver | |
3 | + * | |
4 | + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> | |
5 | + * on behalf of DENX Software Engineering GmbH | |
6 | + * | |
7 | + * Based on code from LTIB: | |
8 | + * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved. | |
9 | + * | |
10 | + * This program is free software; you can redistribute it and/or modify | |
11 | + * it under the terms of the GNU General Public License as published by | |
12 | + * the Free Software Foundation; either version 2 of the License, or | |
13 | + * (at your option) any later version. | |
14 | + * | |
15 | + * This program is distributed in the hope that it will be useful, | |
16 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | + * GNU General Public License for more details. | |
19 | + * | |
20 | + * You should have received a copy of the GNU General Public License along | |
21 | + * with this program; if not, write to the Free Software Foundation, Inc., | |
22 | + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
23 | + */ | |
24 | + | |
25 | +#include <linux/list.h> | |
26 | + | |
27 | +#include <common.h> | |
28 | +#include <malloc.h> | |
29 | +#include <asm/errno.h> | |
30 | +#include <asm/io.h> | |
31 | +#include <asm/arch/clock.h> | |
32 | +#include <asm/arch/imx-regs.h> | |
33 | +#include <asm/arch/sys_proto.h> | |
34 | +#include <asm/arch/dma.h> | |
35 | + | |
36 | +static struct mxs_dma_chan mxs_dma_channels[MXS_MAX_DMA_CHANNELS]; | |
37 | + | |
38 | +/* | |
39 | + * Test is the DMA channel is valid channel | |
40 | + */ | |
41 | +int mxs_dma_validate_chan(int channel) | |
42 | +{ | |
43 | + struct mxs_dma_chan *pchan; | |
44 | + | |
45 | + if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS)) | |
46 | + return -EINVAL; | |
47 | + | |
48 | + pchan = mxs_dma_channels + channel; | |
49 | + if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED)) | |
50 | + return -EINVAL; | |
51 | + | |
52 | + return 0; | |
53 | +} | |
54 | + | |
55 | +/* | |
56 | + * Enable a DMA channel. | |
57 | + * | |
58 | + * If the given channel has any DMA descriptors on its active list, this | |
59 | + * function causes the DMA hardware to begin processing them. | |
60 | + * | |
61 | + * This function marks the DMA channel as "busy," whether or not there are any | |
62 | + * descriptors to process. | |
63 | + */ | |
64 | +int mxs_dma_enable(int channel) | |
65 | +{ | |
66 | + struct mx28_apbh_regs *apbh_regs = | |
67 | + (struct mx28_apbh_regs *)MXS_APBH_BASE; | |
68 | + unsigned int sem; | |
69 | + struct mxs_dma_chan *pchan; | |
70 | + struct mxs_dma_desc *pdesc; | |
71 | + int ret; | |
72 | + | |
73 | + ret = mxs_dma_validate_chan(channel); | |
74 | + if (ret) | |
75 | + return ret; | |
76 | + | |
77 | + pchan = mxs_dma_channels + channel; | |
78 | + | |
79 | + if (pchan->pending_num == 0) { | |
80 | + pchan->flags |= MXS_DMA_FLAGS_BUSY; | |
81 | + return 0; | |
82 | + } | |
83 | + | |
84 | + pdesc = list_first_entry(&pchan->active, struct mxs_dma_desc, node); | |
85 | + if (pdesc == NULL) | |
86 | + return -EFAULT; | |
87 | + | |
88 | + if (pchan->flags & MXS_DMA_FLAGS_BUSY) { | |
89 | + if (!(pdesc->cmd.data & MXS_DMA_DESC_CHAIN)) | |
90 | + return 0; | |
91 | + | |
92 | + sem = mxs_dma_read_semaphore(channel); | |
93 | + if (sem == 0) | |
94 | + return 0; | |
95 | + | |
96 | + if (sem == 1) { | |
97 | + pdesc = list_entry(pdesc->node.next, | |
98 | + struct mxs_dma_desc, node); | |
99 | + writel(mxs_dma_cmd_address(pdesc), | |
100 | + &apbh_regs->ch[channel].hw_apbh_ch_nxtcmdar); | |
101 | + } | |
102 | + writel(pchan->pending_num, | |
103 | + &apbh_regs->ch[channel].hw_apbh_ch_sema); | |
104 | + pchan->active_num += pchan->pending_num; | |
105 | + pchan->pending_num = 0; | |
106 | + } else { | |
107 | + pchan->active_num += pchan->pending_num; | |
108 | + pchan->pending_num = 0; | |
109 | + writel(mxs_dma_cmd_address(pdesc), | |
110 | + &apbh_regs->ch[channel].hw_apbh_ch_nxtcmdar); | |
111 | + writel(pchan->active_num, | |
112 | + &apbh_regs->ch[channel].hw_apbh_ch_sema); | |
113 | + writel(1 << (channel + APBH_CTRL0_CLKGATE_CHANNEL_OFFSET), | |
114 | + &apbh_regs->hw_apbh_ctrl0_clr); | |
115 | + } | |
116 | + | |
117 | + pchan->flags |= MXS_DMA_FLAGS_BUSY; | |
118 | + return 0; | |
119 | +} | |
120 | + | |
121 | +/* | |
122 | + * Disable a DMA channel. | |
123 | + * | |
124 | + * This function shuts down a DMA channel and marks it as "not busy." Any | |
125 | + * descriptors on the active list are immediately moved to the head of the | |
126 | + * "done" list, whether or not they have actually been processed by the | |
127 | + * hardware. The "ready" flags of these descriptors are NOT cleared, so they | |
128 | + * still appear to be active. | |
129 | + * | |
130 | + * This function immediately shuts down a DMA channel's hardware, aborting any | |
131 | + * I/O that may be in progress, potentially leaving I/O hardware in an undefined | |
132 | + * state. It is unwise to call this function if there is ANY chance the hardware | |
133 | + * is still processing a command. | |
134 | + */ | |
135 | +int mxs_dma_disable(int channel) | |
136 | +{ | |
137 | + struct mxs_dma_chan *pchan; | |
138 | + struct mx28_apbh_regs *apbh_regs = | |
139 | + (struct mx28_apbh_regs *)MXS_APBH_BASE; | |
140 | + int ret; | |
141 | + | |
142 | + ret = mxs_dma_validate_chan(channel); | |
143 | + if (ret) | |
144 | + return ret; | |
145 | + | |
146 | + pchan = mxs_dma_channels + channel; | |
147 | + | |
148 | + if (!(pchan->flags & MXS_DMA_FLAGS_BUSY)) | |
149 | + return -EINVAL; | |
150 | + | |
151 | + writel(1 << (channel + APBH_CTRL0_CLKGATE_CHANNEL_OFFSET), | |
152 | + &apbh_regs->hw_apbh_ctrl0_set); | |
153 | + | |
154 | + pchan->flags &= ~MXS_DMA_FLAGS_BUSY; | |
155 | + pchan->active_num = 0; | |
156 | + pchan->pending_num = 0; | |
157 | + list_splice_init(&pchan->active, &pchan->done); | |
158 | + | |
159 | + return 0; | |
160 | +} | |
161 | + | |
162 | +/* | |
163 | + * Resets the DMA channel hardware. | |
164 | + */ | |
165 | +int mxs_dma_reset(int channel) | |
166 | +{ | |
167 | + struct mx28_apbh_regs *apbh_regs = | |
168 | + (struct mx28_apbh_regs *)MXS_APBH_BASE; | |
169 | + int ret; | |
170 | + | |
171 | + ret = mxs_dma_validate_chan(channel); | |
172 | + if (ret) | |
173 | + return ret; | |
174 | + | |
175 | + writel(1 << (channel + APBH_CHANNEL_CTRL_RESET_CHANNEL_OFFSET), | |
176 | + &apbh_regs->hw_apbh_channel_ctrl_set); | |
177 | + | |
178 | + return 0; | |
179 | +} | |
180 | + | |
181 | +/* | |
182 | + * Freeze a DMA channel. | |
183 | + * | |
184 | + * This function causes the channel to continuously fail arbitration for bus | |
185 | + * access, which halts all forward progress without losing any state. A call to | |
186 | + * mxs_dma_unfreeze() will cause the channel to continue its current operation | |
187 | + * with no ill effect. | |
188 | + */ | |
189 | +int mxs_dma_freeze(int channel) | |
190 | +{ | |
191 | + struct mx28_apbh_regs *apbh_regs = | |
192 | + (struct mx28_apbh_regs *)MXS_APBH_BASE; | |
193 | + int ret; | |
194 | + | |
195 | + ret = mxs_dma_validate_chan(channel); | |
196 | + if (ret) | |
197 | + return ret; | |
198 | + | |
199 | + writel(1 << (channel + APBH_CHANNEL_CTRL_FREEZE_CHANNEL_OFFSET), | |
200 | + &apbh_regs->hw_apbh_channel_ctrl_set); | |
201 | + | |
202 | + return 0; | |
203 | +} | |
204 | + | |
205 | +/* | |
206 | + * Unfreeze a DMA channel. | |
207 | + * | |
208 | + * This function reverses the effect of mxs_dma_freeze(), enabling the DMA | |
209 | + * channel to continue from where it was frozen. | |
210 | + */ | |
211 | +int mxs_dma_unfreeze(int channel) | |
212 | +{ | |
213 | + struct mx28_apbh_regs *apbh_regs = | |
214 | + (struct mx28_apbh_regs *)MXS_APBH_BASE; | |
215 | + int ret; | |
216 | + | |
217 | + ret = mxs_dma_validate_chan(channel); | |
218 | + if (ret) | |
219 | + return ret; | |
220 | + | |
221 | + writel(1 << (channel + APBH_CHANNEL_CTRL_FREEZE_CHANNEL_OFFSET), | |
222 | + &apbh_regs->hw_apbh_channel_ctrl_clr); | |
223 | + | |
224 | + return 0; | |
225 | +} | |
226 | + | |
227 | +/* | |
228 | + * Read a DMA channel's hardware semaphore. | |
229 | + * | |
230 | + * As used by the MXS platform's DMA software, the DMA channel's hardware | |
231 | + * semaphore reflects the number of DMA commands the hardware will process, but | |
232 | + * has not yet finished. This is a volatile value read directly from hardware, | |
233 | + * so it must be be viewed as immediately stale. | |
234 | + * | |
235 | + * If the channel is not marked busy, or has finished processing all its | |
236 | + * commands, this value should be zero. | |
237 | + * | |
238 | + * See mxs_dma_append() for details on how DMA command blocks must be configured | |
239 | + * to maintain the expected behavior of the semaphore's value. | |
240 | + */ | |
241 | +int mxs_dma_read_semaphore(int channel) | |
242 | +{ | |
243 | + struct mx28_apbh_regs *apbh_regs = | |
244 | + (struct mx28_apbh_regs *)MXS_APBH_BASE; | |
245 | + uint32_t tmp; | |
246 | + int ret; | |
247 | + | |
248 | + ret = mxs_dma_validate_chan(channel); | |
249 | + if (ret) | |
250 | + return ret; | |
251 | + | |
252 | + tmp = readl(&apbh_regs->ch[channel].hw_apbh_ch_sema); | |
253 | + | |
254 | + tmp &= APBH_CHn_SEMA_PHORE_MASK; | |
255 | + tmp >>= APBH_CHn_SEMA_PHORE_OFFSET; | |
256 | + | |
257 | + return tmp; | |
258 | +} | |
259 | + | |
260 | +/* | |
261 | + * Enable or disable DMA interrupt. | |
262 | + * | |
263 | + * This function enables the given DMA channel to interrupt the CPU. | |
264 | + */ | |
265 | +int mxs_dma_enable_irq(int channel, int enable) | |
266 | +{ | |
267 | + struct mx28_apbh_regs *apbh_regs = | |
268 | + (struct mx28_apbh_regs *)MXS_APBH_BASE; | |
269 | + int ret; | |
270 | + | |
271 | + ret = mxs_dma_validate_chan(channel); | |
272 | + if (ret) | |
273 | + return ret; | |
274 | + | |
275 | + if (enable) | |
276 | + writel(1 << (channel + APBH_CTRL1_CH_CMDCMPLT_IRQ_EN_OFFSET), | |
277 | + &apbh_regs->hw_apbh_ctrl1_set); | |
278 | + else | |
279 | + writel(1 << (channel + APBH_CTRL1_CH_CMDCMPLT_IRQ_EN_OFFSET), | |
280 | + &apbh_regs->hw_apbh_ctrl1_clr); | |
281 | + | |
282 | + return 0; | |
283 | +} | |
284 | + | |
285 | +/* | |
286 | + * Check if a DMA interrupt is pending. | |
287 | + */ | |
288 | +int mxs_dma_irq_is_pending(int channel) | |
289 | +{ | |
290 | + struct mx28_apbh_regs *apbh_regs = | |
291 | + (struct mx28_apbh_regs *)MXS_APBH_BASE; | |
292 | + uint32_t tmp; | |
293 | + int ret; | |
294 | + | |
295 | + ret = mxs_dma_validate_chan(channel); | |
296 | + if (ret) | |
297 | + return ret; | |
298 | + | |
299 | + tmp = readl(&apbh_regs->hw_apbh_ctrl1); | |
300 | + tmp |= readl(&apbh_regs->hw_apbh_ctrl2); | |
301 | + | |
302 | + return (tmp >> channel) & 1; | |
303 | +} | |
304 | + | |
305 | +/* | |
306 | + * Clear DMA interrupt. | |
307 | + * | |
308 | + * The software that is using the DMA channel must register to receive its | |
309 | + * interrupts and, when they arrive, must call this function to clear them. | |
310 | + */ | |
311 | +int mxs_dma_ack_irq(int channel) | |
312 | +{ | |
313 | + struct mx28_apbh_regs *apbh_regs = | |
314 | + (struct mx28_apbh_regs *)MXS_APBH_BASE; | |
315 | + int ret; | |
316 | + | |
317 | + ret = mxs_dma_validate_chan(channel); | |
318 | + if (ret) | |
319 | + return ret; | |
320 | + | |
321 | + writel(1 << channel, &apbh_regs->hw_apbh_ctrl1_clr); | |
322 | + writel(1 << channel, &apbh_regs->hw_apbh_ctrl2_clr); | |
323 | + | |
324 | + return 0; | |
325 | +} | |
326 | + | |
327 | +/* | |
328 | + * Request to reserve a DMA channel | |
329 | + */ | |
330 | +int mxs_dma_request(int channel) | |
331 | +{ | |
332 | + struct mxs_dma_chan *pchan; | |
333 | + | |
334 | + if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS)) | |
335 | + return -EINVAL; | |
336 | + | |
337 | + pchan = mxs_dma_channels + channel; | |
338 | + if ((pchan->flags & MXS_DMA_FLAGS_VALID) != MXS_DMA_FLAGS_VALID) | |
339 | + return -ENODEV; | |
340 | + | |
341 | + if (pchan->flags & MXS_DMA_FLAGS_ALLOCATED) | |
342 | + return -EBUSY; | |
343 | + | |
344 | + pchan->flags |= MXS_DMA_FLAGS_ALLOCATED; | |
345 | + pchan->active_num = 0; | |
346 | + pchan->pending_num = 0; | |
347 | + | |
348 | + INIT_LIST_HEAD(&pchan->active); | |
349 | + INIT_LIST_HEAD(&pchan->done); | |
350 | + | |
351 | + return 0; | |
352 | +} | |
353 | + | |
354 | +/* | |
355 | + * Release a DMA channel. | |
356 | + * | |
357 | + * This function releases a DMA channel from its current owner. | |
358 | + * | |
359 | + * The channel will NOT be released if it's marked "busy" (see | |
360 | + * mxs_dma_enable()). | |
361 | + */ | |
362 | +int mxs_dma_release(int channel) | |
363 | +{ | |
364 | + struct mxs_dma_chan *pchan; | |
365 | + int ret; | |
366 | + | |
367 | + ret = mxs_dma_validate_chan(channel); | |
368 | + if (ret) | |
369 | + return ret; | |
370 | + | |
371 | + pchan = mxs_dma_channels + channel; | |
372 | + | |
373 | + if (pchan->flags & MXS_DMA_FLAGS_BUSY) | |
374 | + return -EBUSY; | |
375 | + | |
376 | + pchan->dev = 0; | |
377 | + pchan->active_num = 0; | |
378 | + pchan->pending_num = 0; | |
379 | + pchan->flags &= ~MXS_DMA_FLAGS_ALLOCATED; | |
380 | + | |
381 | + return 0; | |
382 | +} | |
383 | + | |
384 | +/* | |
385 | + * Allocate DMA descriptor | |
386 | + */ | |
387 | +struct mxs_dma_desc *mxs_dma_desc_alloc(void) | |
388 | +{ | |
389 | + struct mxs_dma_desc *pdesc; | |
390 | + | |
391 | + pdesc = memalign(MXS_DMA_ALIGNMENT, sizeof(struct mxs_dma_desc)); | |
392 | + | |
393 | + if (pdesc == NULL) | |
394 | + return NULL; | |
395 | + | |
396 | + memset(pdesc, 0, sizeof(*pdesc)); | |
397 | + pdesc->address = (dma_addr_t)pdesc; | |
398 | + | |
399 | + return pdesc; | |
400 | +}; | |
401 | + | |
402 | +/* | |
403 | + * Free DMA descriptor | |
404 | + */ | |
405 | +void mxs_dma_desc_free(struct mxs_dma_desc *pdesc) | |
406 | +{ | |
407 | + if (pdesc == NULL) | |
408 | + return; | |
409 | + | |
410 | + free(pdesc); | |
411 | +} | |
412 | + | |
413 | +/* | |
414 | + * Return the address of the command within a descriptor. | |
415 | + */ | |
416 | +unsigned int mxs_dma_cmd_address(struct mxs_dma_desc *desc) | |
417 | +{ | |
418 | + return desc->address + offsetof(struct mxs_dma_desc, cmd); | |
419 | +} | |
420 | + | |
421 | +/* | |
422 | + * Check if descriptor is on a channel's active list. | |
423 | + * | |
424 | + * This function returns the state of a descriptor's "ready" flag. This flag is | |
425 | + * usually set only if the descriptor appears on a channel's active list. The | |
426 | + * descriptor may or may not have already been processed by the hardware. | |
427 | + * | |
428 | + * The "ready" flag is set when the descriptor is submitted to a channel by a | |
429 | + * call to mxs_dma_append() or mxs_dma_append_list(). The "ready" flag is | |
430 | + * cleared when a processed descriptor is moved off the active list by a call | |
431 | + * to mxs_dma_finish(). The "ready" flag is NOT cleared if the descriptor is | |
432 | + * aborted by a call to mxs_dma_disable(). | |
433 | + */ | |
434 | +int mxs_dma_desc_pending(struct mxs_dma_desc *pdesc) | |
435 | +{ | |
436 | + return pdesc->flags & MXS_DMA_DESC_READY; | |
437 | +} | |
438 | + | |
439 | +/* | |
440 | + * Add a DMA descriptor to a channel. | |
441 | + * | |
442 | + * If the descriptor list for this channel is not empty, this function sets the | |
443 | + * CHAIN bit and the NEXTCMD_ADDR fields in the last descriptor's DMA command so | |
444 | + * it will chain to the new descriptor's command. | |
445 | + * | |
446 | + * Then, this function marks the new descriptor as "ready," adds it to the end | |
447 | + * of the active descriptor list, and increments the count of pending | |
448 | + * descriptors. | |
449 | + * | |
450 | + * The MXS platform DMA software imposes some rules on DMA commands to maintain | |
451 | + * important invariants. These rules are NOT checked, but they must be carefully | |
452 | + * applied by software that uses MXS DMA channels. | |
453 | + * | |
454 | + * Invariant: | |
455 | + * The DMA channel's hardware semaphore must reflect the number of DMA | |
456 | + * commands the hardware will process, but has not yet finished. | |
457 | + * | |
458 | + * Explanation: | |
459 | + * A DMA channel begins processing commands when its hardware semaphore is | |
460 | + * written with a value greater than zero, and it stops processing commands | |
461 | + * when the semaphore returns to zero. | |
462 | + * | |
463 | + * When a channel finishes a DMA command, it will decrement its semaphore if | |
464 | + * the DECREMENT_SEMAPHORE bit is set in that command's flags bits. | |
465 | + * | |
466 | + * In principle, it's not necessary for the DECREMENT_SEMAPHORE to be set, | |
467 | + * unless it suits the purposes of the software. For example, one could | |
468 | + * construct a series of five DMA commands, with the DECREMENT_SEMAPHORE | |
469 | + * bit set only in the last one. Then, setting the DMA channel's hardware | |
470 | + * semaphore to one would cause the entire series of five commands to be | |
471 | + * processed. However, this example would violate the invariant given above. | |
472 | + * | |
473 | + * Rule: | |
474 | + * ALL DMA commands MUST have the DECREMENT_SEMAPHORE bit set so that the DMA | |
475 | + * channel's hardware semaphore will be decremented EVERY time a command is | |
476 | + * processed. | |
477 | + */ | |
478 | +int mxs_dma_desc_append(int channel, struct mxs_dma_desc *pdesc) | |
479 | +{ | |
480 | + struct mxs_dma_chan *pchan; | |
481 | + struct mxs_dma_desc *last; | |
482 | + int ret; | |
483 | + | |
484 | + ret = mxs_dma_validate_chan(channel); | |
485 | + if (ret) | |
486 | + return ret; | |
487 | + | |
488 | + pchan = mxs_dma_channels + channel; | |
489 | + | |
490 | + pdesc->cmd.next = mxs_dma_cmd_address(pdesc); | |
491 | + pdesc->flags |= MXS_DMA_DESC_FIRST | MXS_DMA_DESC_LAST; | |
492 | + | |
493 | + if (!list_empty(&pchan->active)) { | |
494 | + last = list_entry(pchan->active.prev, struct mxs_dma_desc, | |
495 | + node); | |
496 | + | |
497 | + pdesc->flags &= ~MXS_DMA_DESC_FIRST; | |
498 | + last->flags &= ~MXS_DMA_DESC_LAST; | |
499 | + | |
500 | + last->cmd.next = mxs_dma_cmd_address(pdesc); | |
501 | + last->cmd.data |= MXS_DMA_DESC_CHAIN; | |
502 | + } | |
503 | + pdesc->flags |= MXS_DMA_DESC_READY; | |
504 | + if (pdesc->flags & MXS_DMA_DESC_FIRST) | |
505 | + pchan->pending_num++; | |
506 | + list_add_tail(&pdesc->node, &pchan->active); | |
507 | + | |
508 | + return ret; | |
509 | +} | |
510 | + | |
511 | +/* | |
512 | + * Retrieve processed DMA descriptors. | |
513 | + * | |
514 | + * This function moves all the descriptors from the DMA channel's "done" list to | |
515 | + * the head of the given list. | |
516 | + */ | |
517 | +int mxs_dma_get_finished(int channel, struct list_head *head) | |
518 | +{ | |
519 | + struct mxs_dma_chan *pchan; | |
520 | + int ret; | |
521 | + | |
522 | + ret = mxs_dma_validate_chan(channel); | |
523 | + if (ret) | |
524 | + return ret; | |
525 | + | |
526 | + if (head == NULL) | |
527 | + return 0; | |
528 | + | |
529 | + pchan = mxs_dma_channels + channel; | |
530 | + | |
531 | + list_splice(&pchan->done, head); | |
532 | + | |
533 | + return 0; | |
534 | +} | |
535 | + | |
536 | +/* | |
537 | + * Clean up processed DMA descriptors. | |
538 | + * | |
539 | + * This function removes processed DMA descriptors from the "active" list. Pass | |
540 | + * in a non-NULL list head to get the descriptors moved to your list. Pass NULL | |
541 | + * to get the descriptors moved to the channel's "done" list. Descriptors on | |
542 | + * the "done" list can be retrieved with mxs_dma_get_finished(). | |
543 | + * | |
544 | + * This function marks the DMA channel as "not busy" if no unprocessed | |
545 | + * descriptors remain on the "active" list. | |
546 | + */ | |
547 | +int mxs_dma_finish(int channel, struct list_head *head) | |
548 | +{ | |
549 | + int sem; | |
550 | + struct mxs_dma_chan *pchan; | |
551 | + struct list_head *p, *q; | |
552 | + struct mxs_dma_desc *pdesc; | |
553 | + int ret; | |
554 | + | |
555 | + ret = mxs_dma_validate_chan(channel); | |
556 | + if (ret) | |
557 | + return ret; | |
558 | + | |
559 | + pchan = mxs_dma_channels + channel; | |
560 | + | |
561 | + sem = mxs_dma_read_semaphore(channel); | |
562 | + if (sem < 0) | |
563 | + return sem; | |
564 | + | |
565 | + if (sem == pchan->active_num) | |
566 | + return 0; | |
567 | + | |
568 | + list_for_each_safe(p, q, &pchan->active) { | |
569 | + if ((pchan->active_num) <= sem) | |
570 | + break; | |
571 | + | |
572 | + pdesc = list_entry(p, struct mxs_dma_desc, node); | |
573 | + pdesc->flags &= ~MXS_DMA_DESC_READY; | |
574 | + | |
575 | + if (head) | |
576 | + list_move_tail(p, head); | |
577 | + else | |
578 | + list_move_tail(p, &pchan->done); | |
579 | + | |
580 | + if (pdesc->flags & MXS_DMA_DESC_LAST) | |
581 | + pchan->active_num--; | |
582 | + } | |
583 | + | |
584 | + if (sem == 0) | |
585 | + pchan->flags &= ~MXS_DMA_FLAGS_BUSY; | |
586 | + | |
587 | + return 0; | |
588 | +} | |
589 | + | |
590 | +/* | |
591 | + * Wait for DMA channel to complete | |
592 | + */ | |
593 | +int mxs_dma_wait_complete(uint32_t timeout, unsigned int chan) | |
594 | +{ | |
595 | + struct mx28_apbh_regs *apbh_regs = | |
596 | + (struct mx28_apbh_regs *)MXS_APBH_BASE; | |
597 | + int ret; | |
598 | + | |
599 | + ret = mxs_dma_validate_chan(chan); | |
600 | + if (ret) | |
601 | + return ret; | |
602 | + | |
603 | + if (mx28_wait_mask_set(&apbh_regs->hw_apbh_ctrl1_reg, | |
604 | + 1 << chan, timeout)) { | |
605 | + ret = -ETIMEDOUT; | |
606 | + mxs_dma_reset(chan); | |
607 | + } | |
608 | + | |
609 | + return 0; | |
610 | +} | |
611 | + | |
612 | +/* | |
613 | + * Execute the DMA channel | |
614 | + */ | |
615 | +int mxs_dma_go(int chan) | |
616 | +{ | |
617 | + uint32_t timeout = 10000; | |
618 | + int ret; | |
619 | + | |
620 | + LIST_HEAD(tmp_desc_list); | |
621 | + | |
622 | + mxs_dma_enable_irq(chan, 1); | |
623 | + mxs_dma_enable(chan); | |
624 | + | |
625 | + /* Wait for DMA to finish. */ | |
626 | + ret = mxs_dma_wait_complete(timeout, chan); | |
627 | + | |
628 | + /* Clear out the descriptors we just ran. */ | |
629 | + mxs_dma_finish(chan, &tmp_desc_list); | |
630 | + | |
631 | + /* Shut the DMA channel down. */ | |
632 | + mxs_dma_ack_irq(chan); | |
633 | + mxs_dma_reset(chan); | |
634 | + mxs_dma_enable_irq(chan, 0); | |
635 | + mxs_dma_disable(chan); | |
636 | + | |
637 | + return ret; | |
638 | +} | |
639 | + | |
640 | +/* | |
641 | + * Initialize the DMA hardware | |
642 | + */ | |
643 | +int mxs_dma_init(void) | |
644 | +{ | |
645 | + struct mx28_apbh_regs *apbh_regs = | |
646 | + (struct mx28_apbh_regs *)MXS_APBH_BASE; | |
647 | + struct mxs_dma_chan *pchan; | |
648 | + int ret, channel; | |
649 | + | |
650 | + mx28_reset_block(&apbh_regs->hw_apbh_ctrl0_reg); | |
651 | + | |
652 | +#ifdef CONFIG_APBH_DMA_BURST8 | |
653 | + writel(APBH_CTRL0_AHB_BURST8_EN, | |
654 | + &apbh_regs->hw_apbh_ctrl0_set); | |
655 | +#else | |
656 | + writel(APBH_CTRL0_AHB_BURST8_EN, | |
657 | + &apbh_regs->hw_apbh_ctrl0_clr); | |
658 | +#endif | |
659 | + | |
660 | +#ifdef CONFIG_APBH_DMA_BURST | |
661 | + writel(APBH_CTRL0_APB_BURST_EN, | |
662 | + &apbh_regs->hw_apbh_ctrl0_set); | |
663 | +#else | |
664 | + writel(APBH_CTRL0_APB_BURST_EN, | |
665 | + &apbh_regs->hw_apbh_ctrl0_clr); | |
666 | +#endif | |
667 | + | |
668 | + for (channel = 0; channel < MXS_MAX_DMA_CHANNELS; channel++) { | |
669 | + pchan = mxs_dma_channels + channel; | |
670 | + pchan->flags = MXS_DMA_FLAGS_VALID; | |
671 | + | |
672 | + ret = mxs_dma_request(channel); | |
673 | + | |
674 | + if (ret) { | |
675 | + printf("MXS DMA: Can't acquire DMA channel %i\n", | |
676 | + channel); | |
677 | + | |
678 | + goto err; | |
679 | + } | |
680 | + | |
681 | + mxs_dma_reset(channel); | |
682 | + mxs_dma_ack_irq(channel); | |
683 | + } | |
684 | + | |
685 | + return 0; | |
686 | + | |
687 | +err: | |
688 | + while (--channel >= 0) | |
689 | + mxs_dma_release(channel); | |
690 | + return ret; | |
691 | +} |