lcd now shows things on the old-style Meizu M3.
[kugel-rb.git] / firmware / target / arm / pcm-telechips.c
blobb3fd9216dcdbbe7dcd080fbfe641c1ff554910af
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 by Michael Sevakis
11 * Copyright (C) 2008 by Rob Purchase
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
22 #include <stdlib.h>
23 #include "system.h"
24 #include "kernel.h"
25 #include "logf.h"
26 #include "audio.h"
27 #include "sound.h"
28 #include "pcm.h"
30 /* Just for tests enable it to play simple tone */
31 //#define PCM_TELECHIPS_TEST
33 struct dma_data
35 /* NOTE: The order of size and p is important if you use assembler
36 optimised fiq handler, so don't change it. */
37 uint16_t *p;
38 size_t size;
39 #if NUM_CORES > 1
40 unsigned core;
41 #endif
42 int locked;
43 int state;
46 /****************************************************************************
47 ** Playback DMA transfer
48 **/
49 struct dma_data dma_play_data SHAREDBSS_ATTR =
51 /* Initialize to a locked, stopped state */
52 .p = NULL,
53 .size = 0,
54 #if NUM_CORES > 1
55 .core = 0x00,
56 #endif
57 .locked = 0,
58 .state = 0
61 static unsigned long pcm_freq SHAREDDATA_ATTR = HW_SAMPR_DEFAULT; /* 44.1 is default */
63 void pcm_postinit(void)
65 #if defined(IAUDIO_7)
66 audiohw_postinit(); /* implemented not for all codecs */
67 #endif
68 pcm_apply_settings();
71 const void * pcm_play_dma_get_peak_buffer(int *count)
73 unsigned long addr = (unsigned long)dma_play_data.p;
74 size_t cnt = dma_play_data.size;
75 *count = cnt >> 2;
76 return (void *)((addr + 2) & ~3);
79 void pcm_play_dma_init(void)
81 DAVC = 0x0; /* Digital Volume = max */
82 #ifdef COWON_D2
83 /* Set DAI clock divided from PLL0 (192MHz).
84 The best approximation of 256*44.1kHz is 11.291MHz. */
85 BCLKCTR &= ~DEV_DAI;
86 PCLK_DAI = (1<<28) | 61682; /* DCO mode */
87 BCLKCTR |= DEV_DAI;
89 /* Enable DAI block in Master mode, 256fs->32fs, 16bit LSB */
90 DAMR = 0x3c8e80;
91 #elif defined(IAUDIO_7)
92 BCLKCTR &= ~DEV_DAI;
93 PCLK_DAI = (0x800b << 16) | (PCLK_DAI & 0xffff);
94 BCLKCTR |= DEV_DAI;
95 /* Master mode, 256->64fs, 16bit LSB*/
96 DAMR = 0x3cce20;
97 #elif defined(LOGIK_DAX)
98 /* TODO */
99 #elif defined(SANSA_M200)
100 /* TODO */
101 #else
102 #error "Target isn't supported"
103 #endif
104 /* Set DAI interrupts as FIQs */
105 IRQSEL = ~(DAI_RX_IRQ_MASK | DAI_TX_IRQ_MASK);
107 pcm_set_frequency(SAMPR_44);
109 /* Initialize default register values. */
110 audiohw_init();
112 /* Power on */
113 audiohw_enable_output(true);
115 /* Unmute the master channel (DAC should be at zero point now). */
116 audiohw_mute(false);
118 dma_play_data.size = 0;
119 #if NUM_CORES > 1
120 dma_play_data.core = 0; /* no core in control */
121 #endif
124 void pcm_apply_settings(void)
126 pcm_curr_sampr = pcm_freq;
129 void pcm_set_frequency(unsigned int frequency)
131 (void) frequency;
132 pcm_freq = HW_SAMPR_DEFAULT;
135 static void play_start_pcm(void)
137 pcm_apply_settings();
139 DAMR &= ~(1<<14); /* disable tx */
140 dma_play_data.state = 1;
142 if (dma_play_data.size >= 16)
144 DADO_L(0) = *dma_play_data.p++;
145 DADO_R(0) = *dma_play_data.p++;
146 DADO_L(1) = *dma_play_data.p++;
147 DADO_R(1) = *dma_play_data.p++;
148 DADO_L(2) = *dma_play_data.p++;
149 DADO_R(2) = *dma_play_data.p++;
150 DADO_L(3) = *dma_play_data.p++;
151 DADO_R(3) = *dma_play_data.p++;
152 dma_play_data.size -= 16;
155 DAMR |= (1<<14); /* enable tx */
158 static void play_stop_pcm(void)
160 DAMR &= ~(1<<14); /* disable tx */
161 dma_play_data.state = 0;
164 void pcm_play_dma_start(const void *addr, size_t size)
166 dma_play_data.p = (void *)(((uintptr_t)addr + 2) & ~3);
167 dma_play_data.size = (size & ~3);
169 #if NUM_CORES > 1
170 /* This will become more important later - and different ! */
171 dma_play_data.core = processor_id(); /* save initiating core */
172 #endif
174 IEN |= DAI_TX_IRQ_MASK;
176 play_start_pcm();
179 void pcm_play_dma_stop(void)
181 play_stop_pcm();
182 dma_play_data.size = 0;
183 #if NUM_CORES > 1
184 dma_play_data.core = 0; /* no core in control */
185 #endif
188 void pcm_play_lock(void)
190 int status = disable_fiq_save();
192 if (++dma_play_data.locked == 1)
194 IEN &= ~DAI_TX_IRQ_MASK;
197 restore_fiq(status);
200 void pcm_play_unlock(void)
202 int status = disable_fiq_save();
204 if (--dma_play_data.locked == 0 && dma_play_data.state != 0)
206 IEN |= DAI_TX_IRQ_MASK;
209 restore_fiq(status);
212 void pcm_play_dma_pause(bool pause)
214 if (pause) {
215 play_stop_pcm();
216 } else {
217 play_start_pcm();
221 size_t pcm_get_bytes_waiting(void)
223 return dma_play_data.size & ~3;
226 #ifdef HAVE_RECORDING
227 /* TODO: implement */
228 void pcm_rec_dma_init(void)
232 void pcm_rec_dma_close(void)
236 void pcm_rec_dma_start(void *addr, size_t size)
238 (void) addr;
239 (void) size;
242 void pcm_rec_dma_stop(void)
246 void pcm_rec_lock(void)
250 void pcm_rec_unlock(void)
254 const void * pcm_rec_dma_get_peak_buffer(int *count)
256 *count = 0;
257 return NULL;
260 void pcm_record_more(void *start, size_t size)
262 (void) start;
263 (void) size;
265 #endif
267 #if defined(CPU_TCC77X) || defined(CPU_TCC780X)
268 void fiq_handler(void) ICODE_ATTR __attribute__((naked));
269 void fiq_handler(void)
271 /* r10 contains DADO_L0 base address (set in crt0.S to minimise code in the
272 * FIQ handler. r11 contains address of p (also set in crt0.S). Most other
273 * addresses we need are generated by using offsets with these two.
274 * r8 and r9 contains local copies of p and size respectively.
275 * r0-r3 and r12 is a working register.
277 asm volatile (
278 #if defined(CPU_TCC780X)
279 "mov r8, #0xc000 \n" /* DAI_TX_IRQ_MASK | DAI_RX_IRQ_MASK */
280 "ldr r9, =0xf3001004 \n" /* CREQ */
281 #elif defined(CPU_TCC77X)
282 "mov r8, #0x0030 \n" /* DAI_TX_IRQ_MASK | DAI_RX_IRQ_MASK */
283 "ldr r9, =0x80000104 \n" /* CREQ */
284 #endif
285 "str r8, [r9] \n" /* clear DAI IRQs */
286 "ldmia r11, { r8-r9 } \n" /* r8 = p, r9 = size */
287 "cmp r9, #0x10 \n" /* is size <16? */
288 "blt .more_data \n" /* if so, ask pcmbuf for more data */
290 ".fill_fifo: \n"
291 "ldr r12, [r8], #4 \n" /* load two samples */
292 "str r12, [r10, #0x0] \n" /* write top sample to DADO_L0 */
293 "mov r12, r12, lsr #16 \n" /* put right sample at the bottom */
294 "str r12, [r10, #0x4] \n" /* write low sample to DADO_R0*/
295 "ldr r12, [r8], #4 \n" /* load two samples */
296 "str r12, [r10, #0x8] \n" /* write top sample to DADO_L1 */
297 "mov r12, r12, lsr #16 \n" /* put right sample at the bottom */
298 "str r12, [r10, #0xc] \n" /* write low sample to DADO_R1*/
299 "ldr r12, [r8], #4 \n" /* load two samples */
300 "str r12, [r10, #0x10] \n" /* write top sample to DADO_L2 */
301 "mov r12, r12, lsr #16 \n" /* put right sample at the bottom */
302 "str r12, [r10, #0x14] \n" /* write low sample to DADO_R2*/
303 "ldr r12, [r8], #4 \n" /* load two samples */
304 "str r12, [r10, #0x18] \n" /* write top sample to DADO_L3 */
305 "mov r12, r12, lsr #16 \n" /* put right sample at the bottom */
306 "str r12, [r10, #0x1c] \n" /* write low sample to DADO_R3*/
307 "sub r9, r9, #0x10 \n" /* 4 words written */
308 "stmia r11, { r8-r9 } \n" /* save p and size */
310 ".exit: \n"
311 "subs pc, lr, #4 \n" /* FIQ specific return sequence */
313 ".more_data: \n"
314 "stmfd sp!, { r0-r3, lr } \n" /* stack scratch regs and lr */
315 "ldr r2, =pcm_callback_for_more \n"
316 "ldr r2, [r2] \n" /* get callback address */
317 "cmp r2, #0 \n" /* check for null pointer */
318 "movne r0, r11 \n" /* r0 = &p */
319 "addne r1, r11, #4 \n" /* r1 = &size */
320 "blxne r2 \n" /* call pcm_callback_for_more */
321 "ldmia r11, { r8-r9 } \n" /* reload p and size */
322 "cmp r9, #0x10 \n" /* did we actually get more data? */
323 "ldmgefd sp!, { r0-r3, lr } \n"
324 "bge .fill_fifo \n" /* yes: fill the fifo */
325 "ldr r12, =pcm_play_dma_stop \n"
326 "blx r12 \n" /* no: stop playback */
327 "ldr r12, =pcm_play_dma_stopped_callback \n"
328 "blx r12 \n"
329 "ldmfd sp!, { r0-r3, lr } \n"
330 "b .exit \n"
331 ".ltorg \n"
334 #else /* C version for reference */
335 void fiq_handler(void) ICODE_ATTR __attribute__((naked));
336 void fiq_handler(void)
338 asm volatile( "stmfd sp!, {r0-r7, ip, lr} \n" /* Store context */
339 "sub sp, sp, #8 \n"); /* Reserve stack */
341 register pcm_more_callback_type get_more;
343 if (dma_play_data.size < 16)
345 /* p is empty, get some more data */
346 get_more = pcm_callback_for_more;
347 if (get_more)
349 get_more((unsigned char**)&dma_play_data.p,
350 &dma_play_data.size);
354 if (dma_play_data.size >= 16)
356 DADO_L(0) = *dma_play_data.p++;
357 DADO_R(0) = *dma_play_data.p++;
358 DADO_L(1) = *dma_play_data.p++;
359 DADO_R(1) = *dma_play_data.p++;
360 DADO_L(2) = *dma_play_data.p++;
361 DADO_R(2) = *dma_play_data.p++;
362 DADO_L(3) = *dma_play_data.p++;
363 DADO_R(3) = *dma_play_data.p++;
365 dma_play_data.size -= 16;
367 else
369 /* No more data, so disable the FIFO/interrupt */
370 pcm_play_dma_stop();
371 pcm_play_dma_stopped_callback();
374 /* Clear FIQ status */
375 CREQ = DAI_TX_IRQ_MASK | DAI_RX_IRQ_MASK;
377 asm volatile( "add sp, sp, #8 \n" /* Cleanup stack */
378 "ldmfd sp!, {r0-r7, ip, lr} \n" /* Restore context */
379 "subs pc, lr, #4 \n"); /* Return from FIQ */
381 #endif
383 /* TODO: required by wm8531 codec, why not to implement */
384 void i2s_reset(void)
386 /* DAMR = 0; */
389 #ifdef PCM_TELECHIPS_TEST
390 #include "lcd.h"
391 #include "sprintf.h"
392 #include "backlight-target.h"
394 static int frame = 0;
395 static void test_callback_for_more(unsigned char **start, size_t *size)
397 static unsigned short data[8];
398 static int cntr = 0;
399 int i;
401 for (i = 0; i < 8; i ++) {
402 unsigned short val;
404 if (0x100 == (cntr & 0x100))
405 val = 0x0fff;
406 else
407 val = 0x0000;
408 data[i] = val;
409 cntr++;
412 *start = data;
413 *size = sizeof(data);
415 frame++;
418 void pcm_telechips_test(void)
420 static char buf[100];
421 unsigned char *data;
422 size_t size;
424 _backlight_on();
426 audiohw_preinit();
427 pcm_play_dma_init();
428 pcm_postinit();
430 audiohw_mute(false);
431 audiohw_set_master_vol(0x7f, 0x7f);
433 pcm_callback_for_more = test_callback_for_more;
434 test_callback_for_more(&data, &size);
435 pcm_play_dma_start(data, size);
437 while (1) {
438 int line = 0;
439 lcd_clear_display();
440 lcd_puts(0, line++, __func__);
441 snprintf(buf, sizeof(buf), "frame: %d", frame);
442 lcd_puts(0, line++, buf);
443 lcd_update();
444 sleep(1);
447 #endif