summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx233/ssp-imx233.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/imx233/ssp-imx233.c')
-rw-r--r--firmware/target/arm/imx233/ssp-imx233.c307
1 files changed, 307 insertions, 0 deletions
diff --git a/firmware/target/arm/imx233/ssp-imx233.c b/firmware/target/arm/imx233/ssp-imx233.c
new file mode 100644
index 0000000000..c6be869ce6
--- /dev/null
+++ b/firmware/target/arm/imx233/ssp-imx233.c
@@ -0,0 +1,307 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 by amaury Pouly
11 *
12 * Based on Rockbox iriver bootloader by Linus Nielsen Feltzing
13 * and the ipodlinux bootloader by Daniel Palffy and Bernard Leach
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24#include "system.h"
25#include "kernel.h"
26#include "ssp-imx233.h"
27#include "clkctrl-imx233.h"
28#include "pinctrl-imx233.h"
29#include "dma-imx233.h"
30
31/* Used for DMA */
32struct ssp_dma_command_t
33{
34 struct apb_dma_command_t dma;
35 /* PIO words */
36 uint32_t ctrl0;
37 uint32_t cmd0;
38 uint32_t cmd1;
39};
40
41static int ssp_in_use = 0;
42static struct mutex ssp_mutex[2];
43static struct semaphore ssp_sema[2];
44static struct ssp_dma_command_t ssp_dma_cmd[2];
45
46void INT_SSP(int ssp)
47{
48 /* reset dma channel on error */
49 if(imx233_dma_is_channel_error_irq(APB_SSP(ssp)))
50 imx233_dma_reset_channel(APB_SSP(ssp));
51 /* clear irq flags */
52 imx233_dma_clear_channel_interrupt(APB_SSP(ssp));
53 semaphore_release(&ssp_sema[ssp - 1]);
54}
55
56void INT_SSP1_DMA(void)
57{
58 INT_SSP(1);
59}
60
61void INT_SSP2_DMA(void)
62{
63 INT_SSP(2);
64}
65
66void INT_SSP1_ERROR(void)
67{
68 panicf("ssp1 error");
69}
70
71void INT_SSP2_ERROR(void)
72{
73 panicf("ssp2 error");
74}
75
76void imx233_ssp_init(void)
77{
78 /* power down */
79 __REG_SET(HW_SSP_CTRL0(1)) = __BLOCK_CLKGATE;
80 __REG_SET(HW_SSP_CTRL0(2)) = __BLOCK_CLKGATE;
81
82 ssp_in_use = 0;
83 semaphore_init(&ssp_sema[0], 1, 0);
84 semaphore_init(&ssp_sema[1], 1, 0);
85 mutex_init(&ssp_mutex[0]);
86 mutex_init(&ssp_mutex[1]);
87}
88
89void imx233_ssp_start(int ssp)
90{
91 /* Gate block */
92 __REG_CLR(HW_SSP_CTRL0(ssp)) = __BLOCK_CLKGATE;
93 while(HW_SSP_CTRL0(ssp) & __BLOCK_CLKGATE);
94 /* Gate dma channel */
95 imx233_dma_clkgate_channel(APB_SSP(ssp), true);
96 /* If first block to start, start SSP clock */
97 if(ssp_in_use == 0)
98 {
99 /* fracdiv = 18 => clk_io = pll = 480Mhz
100 * intdiv = 4 => clk_ssp = 120Mhz */
101 imx233_set_fractional_divisor(CLK_IO, 18);
102 imx233_enable_clock(CLK_SSP, false);
103 imx233_set_clock_divisor(CLK_SSP, 4);
104 imx233_set_bypass_pll(CLK_SSP, false); /* use IO */
105 imx233_enable_clock(CLK_SSP, true);
106 }
107 ssp_in_use++;
108}
109
110void imx233_ssp_stop(int ssp)
111{
112 /* Gate off */
113 __REG_SET(HW_SSP_CTRL0(ssp)) = __BLOCK_CLKGATE;
114 /* Gate off dma */
115 imx233_dma_clkgate_channel(APB_SSP(ssp), false);
116 /* If last block to stop, stop SSP clock */
117 ssp_in_use--;
118 if(ssp_in_use == 0)
119 {
120 imx233_enable_clock(CLK_SSP, false);
121 imx233_set_fractional_divisor(CLK_IO, 0);
122 }
123}
124
125void imx233_ssp_softreset(int ssp)
126{
127 imx233_reset_block(&HW_SSP_CTRL0(ssp));
128}
129
130void imx233_ssp_set_timings(int ssp, int divide, int rate)
131{
132 __REG_CLR(HW_SSP_TIMING(ssp)) =
133 HW_SSP_TIMING__CLOCK_DIVIDE_BM | HW_SSP_TIMING__CLOCK_RATE_BM;
134 __REG_SET(HW_SSP_TIMING(ssp)) =
135 divide << HW_SSP_TIMING__CLOCK_DIVIDE_BP | rate;
136}
137
138void imx233_ssp_set_timeout(int ssp, int timeout)
139{
140 __REG_CLR(HW_SSP_TIMING(ssp)) = HW_SSP_TIMING__CLOCK_TIMEOUT_BM;
141 __REG_SET(HW_SSP_TIMING(ssp)) =
142 timeout << HW_SSP_TIMING__CLOCK_TIMEOUT_BP;
143}
144
145#if 0
146static void setup_ssp_sd_pins(int ssp)
147{
148 imx233_set_pin_function(1, 29, PINCTRL_FUNCTION_GPIO);
149 imx233_enable_gpio_output(1, 29, true);
150 imx233_set_gpio_output(1, 29, false);
151
152 if(ssp == 1)
153 {
154 /* SSP_SCK: drive 8mA */
155 imx233_set_pin_drive_strength(2, 6, PINCTRL_DRIVE_8mA);
156 /* SSP_{SCK,DATA{3,2,1,0},DETECT,CMD} */
157 imx233_set_pin_function(2, 6, PINCTRL_FUNCTION_MAIN);
158 imx233_set_pin_function(2, 5, PINCTRL_FUNCTION_MAIN);
159 imx233_set_pin_function(2, 4, PINCTRL_FUNCTION_MAIN);
160 imx233_set_pin_function(2, 3, PINCTRL_FUNCTION_MAIN);
161 imx233_set_pin_function(2, 2, PINCTRL_FUNCTION_MAIN);
162 imx233_set_pin_function(2, 1, PINCTRL_FUNCTION_MAIN);
163 imx233_set_pin_function(2, 0, PINCTRL_FUNCTION_MAIN);
164 /* SSP_CMD: pullup */
165 imx233_enable_pin_pullup(2, 0, true);
166 imx233_enable_pin_pullup(2, 2, true);
167 imx233_enable_pin_pullup(2, 3, true);
168 imx233_enable_pin_pullup(2, 4, true);
169 imx233_enable_pin_pullup(2, 5, true);
170 }
171 else
172 {
173
174 }
175}
176#endif
177
178void imx233_ssp_setup_ssp2_sd_mmc_pins(bool enable_pullups, unsigned bus_width,
179 unsigned drive_strength)
180{
181 /* SSP_{CMD,SCK} */
182 imx233_set_pin_drive_strength(0, 20, drive_strength);
183 imx233_set_pin_drive_strength(0, 24, drive_strength);
184 imx233_set_pin_function(0, 20, PINCTRL_FUNCTION_ALT2);
185 imx233_set_pin_function(0, 24, PINCTRL_FUNCTION_ALT2);
186 imx233_enable_pin_pullup(0, 20, enable_pullups);
187 /* SSP_DATA{0-7}*/
188 imx233_set_pin_drive_strength(0, 0, drive_strength);
189 imx233_set_pin_function(0, 0, PINCTRL_FUNCTION_ALT2);
190 imx233_enable_pin_pullup(0, 0, enable_pullups);
191
192 if(bus_width >= 4)
193 {
194 imx233_set_pin_drive_strength(0, 1, drive_strength);
195 imx233_set_pin_drive_strength(0, 2, drive_strength);
196 imx233_set_pin_drive_strength(0, 3, drive_strength);
197 imx233_set_pin_function(0, 1, PINCTRL_FUNCTION_ALT2);
198 imx233_set_pin_function(0, 2, PINCTRL_FUNCTION_ALT2);
199 imx233_set_pin_function(0, 3, PINCTRL_FUNCTION_ALT2);
200 imx233_enable_pin_pullup(0, 1, enable_pullups);
201 imx233_enable_pin_pullup(0, 2, enable_pullups);
202 imx233_enable_pin_pullup(0, 3, enable_pullups);
203 }
204 if(bus_width >= 8)
205 {
206 imx233_set_pin_drive_strength(0, 4, drive_strength);
207 imx233_set_pin_drive_strength(0, 5, drive_strength);
208 imx233_set_pin_drive_strength(0, 6, drive_strength);
209 imx233_set_pin_drive_strength(0, 7, drive_strength);
210 imx233_set_pin_function(0, 4, PINCTRL_FUNCTION_ALT2);
211 imx233_set_pin_function(0, 5, PINCTRL_FUNCTION_ALT2);
212 imx233_set_pin_function(0, 6, PINCTRL_FUNCTION_ALT2);
213 imx233_set_pin_function(0, 7, PINCTRL_FUNCTION_ALT2);
214 imx233_enable_pin_pullup(0, 4, enable_pullups);
215 imx233_enable_pin_pullup(0, 5, enable_pullups);
216 imx233_enable_pin_pullup(0, 6, enable_pullups);
217 imx233_enable_pin_pullup(0, 7, enable_pullups);
218 }
219
220 imx233_enable_gpio_output_mask(0, 0x11000ff, false);
221 imx233_set_gpio_output_mask(0, 0x11000ff, false);
222}
223
224void imx233_ssp_set_mode(int ssp, unsigned mode)
225{
226 switch(mode)
227 {
228 case HW_SSP_CTRL1__SSP_MODE__SD_MMC:
229 /* clear mode and word length */
230 __REG_CLR(HW_SSP_CTRL1(ssp)) =
231 HW_SSP_CTRL1__SSP_MODE_BM | HW_SSP_CTRL1__WORD_LENGTH_BM;
232 /* set mode, set word length to 8-bit, polarity and enable dma */
233 __REG_SET(HW_SSP_CTRL1(ssp)) = mode |
234 HW_SSP_CTRL1__WORD_LENGTH__EIGHT_BITS << HW_SSP_CTRL1__WORD_LENGTH_BP |
235 HW_SSP_CTRL1__POLARITY | HW_SSP_CTRL1__DMA_ENABLE;
236 break;
237 default: return;
238 }
239}
240
241enum imx233_ssp_error_t imx233_ssp_sd_mmc_transfer(int ssp, uint8_t cmd, uint32_t cmd_arg,
242 enum imx233_ssp_resp_t resp, void *buffer, int xfer_size, bool read, uint32_t *resp_ptr)
243{
244 mutex_lock(&ssp_mutex[ssp - 1]);
245 /* Enable all interrupts */
246 imx233_enable_interrupt(INT_SRC_SSP_DMA(ssp), true);
247 imx233_dma_enable_channel_interrupt(APB_SSP(ssp), true);
248 /* Assume only one block so ignore block_count and block_size */
249 ssp_dma_cmd[ssp - 1].cmd0 = cmd | HW_SSP_CMD0__APPEND_8CYC;
250 ssp_dma_cmd[ssp - 1].cmd1 = cmd_arg;
251 /* setup all flags and run */
252 ssp_dma_cmd[ssp - 1].ctrl0 = xfer_size | HW_SSP_CTRL0__ENABLE |
253 HW_SSP_CTRL0__IGNORE_CRC |
254 (resp != SSP_NO_RESP ? HW_SSP_CTRL0__GET_RESP | HW_SSP_CTRL0__WAIT_FOR_IRQ : 0) |
255 (resp == SSP_LONG_RESP ? HW_SSP_CTRL0__LONG_RESP : 0) |
256 HW_SSP_CTRL0__BUS_WIDTH__ONE_BIT << HW_SSP_CTRL0__BUS_WIDTH_BP |
257 (buffer ? HW_SSP_CTRL0__DATA_XFER : 0) |
258 (read ? HW_SSP_CTRL0__READ : 0);
259 /* setup the dma parameters */
260 ssp_dma_cmd[ssp - 1].dma.buffer = buffer;
261 ssp_dma_cmd[ssp - 1].dma.next = NULL;
262 ssp_dma_cmd[ssp - 1].dma.cmd =
263 (buffer == NULL ? HW_APB_CHx_CMD__COMMAND__NO_XFER :
264 read ? HW_APB_CHx_CMD__COMMAND__WRITE : HW_APB_CHx_CMD__COMMAND__READ) |
265 HW_APB_CHx_CMD__IRQONCMPLT | HW_APB_CHx_CMD__SEMAPHORE |
266 HW_APB_CHx_CMD__WAIT4ENDCMD | HW_APB_CHx_CMD__HALTONTERMINATE |
267 (3 << HW_APB_CHx_CMD__CMDWORDS_BP) |
268 (xfer_size << HW_APB_CHx_CMD__XFER_COUNT_BP);
269
270 imx233_dma_start_command(APB_SSP(ssp), &ssp_dma_cmd[ssp - 1].dma);
271
272 /* the SSP hardware already has a timeout but we never know; 1 sec is a maximum
273 * for all operations */
274 enum imx233_ssp_error_t ret;
275
276 if(semaphore_wait(&ssp_sema[ssp - 1], HZ) == OBJ_WAIT_TIMEDOUT)
277 ret = SSP_TIMEOUT;
278 else if((HW_SSP_CTRL1(ssp) & HW_SSP_CTRL1__ALL_IRQ) == 0)
279 ret = SSP_SUCCESS;
280 else if(HW_SSP_CTRL1(ssp) & (HW_SSP_CTRL1__RESP_TIMEOUT_IRQ |
281 HW_SSP_CTRL1__DATA_TIMEOUT_IRQ | HW_SSP_CTRL1__RECV_TIMEOUT_IRQ))
282 ret = SSP_TIMEOUT;
283 else
284 ret = SSP_ERROR;
285
286 if(ret == SSP_SUCCESS && resp_ptr != NULL)
287 {
288 if(resp != SSP_NO_RESP)
289 *resp_ptr++ = HW_SSP_SDRESP0(ssp);
290 if(resp == SSP_LONG_RESP)
291 {
292 *resp_ptr++ = HW_SSP_SDRESP1(ssp);
293 *resp_ptr++ = HW_SSP_SDRESP2(ssp);
294 *resp_ptr++ = HW_SSP_SDRESP3(ssp);
295 }
296 }
297 mutex_unlock(&ssp_mutex[ssp - 1]);
298 return ret;
299}
300
301void imx233_ssp_sd_mmc_power_up_sequence(int ssp)
302{
303 __REG_CLR(HW_SSP_CMD0(ssp)) = HW_SSP_CMD0__SLOW_CLKING_EN;
304 __REG_SET(HW_SSP_CMD0(ssp)) = HW_SSP_CMD0__CONT_CLKING_EN;
305 mdelay(1);
306 __REG_CLR(HW_SSP_CMD0(ssp)) = HW_SSP_CMD0__CONT_CLKING_EN;
307}