summaryrefslogtreecommitdiff
path: root/firmware/target/arm
diff options
context:
space:
mode:
authorTomasz Moń <desowin@gmail.com>2011-11-16 14:08:01 +0000
committerTomasz Moń <desowin@gmail.com>2011-11-16 14:08:01 +0000
commite8a8a1be43afe63079ae48ce1a9eb3052df3b1a4 (patch)
tree084e1cdf27a339ce58e24cff8fec8c31432b52db /firmware/target/arm
parent992d4eb775cac48e107e18d72783ebfb39c4234f (diff)
downloadrockbox-e8a8a1be43afe63079ae48ce1a9eb3052df3b1a4.tar.gz
rockbox-e8a8a1be43afe63079ae48ce1a9eb3052df3b1a4.zip
Sandisk Sansa Connect port (FS #12363)
Included are drivers for buttons, backlight, lcd, audio and storage. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31000 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm')
-rw-r--r--firmware/target/arm/tms320dm320/app.lds2
-rw-r--r--firmware/target/arm/tms320dm320/boot.lds19
-rw-r--r--firmware/target/arm/tms320dm320/debug-dm320.c2
-rw-r--r--firmware/target/arm/tms320dm320/dma-dm320.c78
-rw-r--r--firmware/target/arm/tms320dm320/dma-target.h44
-rw-r--r--firmware/target/arm/tms320dm320/i2c-dm320.c138
-rw-r--r--firmware/target/arm/tms320dm320/kernel-dm320.c9
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/adc-sansaconnect.c35
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/adc-target.h25
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c461
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.h38
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/backlight-sansaconnect.c93
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/backlight-target.h33
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/button-target.h64
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/crt0-board.S238
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/lcd-sansaconnect.c273
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/lcd-target.h25
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/pcm-sansaconnect.c207
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/power-sansaconnect.c59
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/powermgmt-sansaconnect.c56
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/usb-sansaconnect.c53
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/usb-target.h32
-rw-r--r--firmware/target/arm/tms320dm320/sdmmc-dm320.c949
-rw-r--r--firmware/target/arm/tms320dm320/system-dm320.c33
-rw-r--r--firmware/target/arm/tms320dm320/system-target.h5
25 files changed, 2959 insertions, 12 deletions
diff --git a/firmware/target/arm/tms320dm320/app.lds b/firmware/target/arm/tms320dm320/app.lds
index 1e0d1839c0..4ea22a7902 100644
--- a/firmware/target/arm/tms320dm320/app.lds
+++ b/firmware/target/arm/tms320dm320/app.lds
@@ -29,7 +29,7 @@ STARTUP(target/arm/tms320dm320/crt0.o)
29 29
30#define DRAMSIZE (MEMORYSIZE * 0x100000) 30#define DRAMSIZE (MEMORYSIZE * 0x100000)
31 31
32#define DRAMORIG 0x00900000 32#define DRAMORIG CONFIG_SDRAM_START
33 33
34#define FLASHORIG 0x00100000 34#define FLASHORIG 0x00100000
35#define FLASHSIZE 0x00800000 35#define FLASHSIZE 0x00800000
diff --git a/firmware/target/arm/tms320dm320/boot.lds b/firmware/target/arm/tms320dm320/boot.lds
index 2b9f345a23..65649d7268 100644
--- a/firmware/target/arm/tms320dm320/boot.lds
+++ b/firmware/target/arm/tms320dm320/boot.lds
@@ -28,14 +28,27 @@ STARTUP(target/arm/tms320dm320/crt0.o)
28#define LCD_TTB_AREA 0x100000*((LCD_BUFFER_SIZE>>19)+1) 28#define LCD_TTB_AREA 0x100000*((LCD_BUFFER_SIZE>>19)+1)
29 29
30/* Bootloader only uses/knows about the upper 32 M */ 30/* Bootloader only uses/knows about the upper 32 M */
31#define DRAMORIG 0x02900000 31#define DRAMORIG CONFIG_SDRAM_START+0x02000000
32#define DRAMSIZE (MEMORYSIZE * 0x80000) 32#define DRAMSIZE (MEMORYSIZE * 0x80000)
33 33
34#define IRAMORIG 0x00000000 34#define IRAMORIG 0x00000000
35#define IRAMSIZE 0x4000 35#define IRAMSIZE 0x4000
36 36
37#ifdef SANSA_CONNECT
38/* Offset in flash from beginning, we don't want overwrite OF bootloader
39 due to recovery mode and more importantly - hardware block protection.
40 This offset makes Rockbox bootloader a replacement for OF vmlinux.
41 In .srr file header add any valid memory address from following
42 <0x1000000; 0x1300180) u (0x131EAF4; 0x1420000) u (0x1440000; 0x5000000>
43 ensuring that complete bootloader fits in.
44 Entry point in .srr file should be 0x120010. */
45#define FLASHOFFSET 0x20010
46#else
47#define FLASHOFFSET 0
48#endif
49
37#define FLASHORIG 0x00100000 50#define FLASHORIG 0x00100000
38#define FLASHSIZE 0x00800000 51#define FLASHSIZE 0x00800000-FLASHOFFSET
39 52
40PRO_STACK_SIZE = 0x2000; 53PRO_STACK_SIZE = 0x2000;
41IRQ_STACK_SIZE = 0x400; 54IRQ_STACK_SIZE = 0x400;
@@ -48,7 +61,7 @@ MEMORY
48{ 61{
49 DRAM : ORIGIN = DRAMORIG, LENGTH = DRAMSIZE 62 DRAM : ORIGIN = DRAMORIG, LENGTH = DRAMSIZE
50 IRAM : ORIGIN = IRAMORIG, LENGTH = IRAMSIZE 63 IRAM : ORIGIN = IRAMORIG, LENGTH = IRAMSIZE
51 FLASH : ORIGIN = FLASHORIG, LENGTH = FLASHSIZE 64 FLASH : ORIGIN = FLASHORIG+FLASHOFFSET, LENGTH = FLASHSIZE
52} 65}
53 66
54SECTIONS 67SECTIONS
diff --git a/firmware/target/arm/tms320dm320/debug-dm320.c b/firmware/target/arm/tms320dm320/debug-dm320.c
index de17d54843..262d843bfc 100644
--- a/firmware/target/arm/tms320dm320/debug-dm320.c
+++ b/firmware/target/arm/tms320dm320/debug-dm320.c
@@ -212,6 +212,7 @@ bool dbg_hw_info(void)
212 button = button_get(false); 212 button = button_get(false);
213 if(button & BUTTON_POWER) 213 if(button & BUTTON_POWER)
214 done = true; 214 done = true;
215#if defined(CREATIVE_ZVx)
215 else if(button & BUTTON_LEFT) 216 else if(button & BUTTON_LEFT)
216 lcd_set_direct_fb(false); 217 lcd_set_direct_fb(false);
217 else if(button & BUTTON_RIGHT) 218 else if(button & BUTTON_RIGHT)
@@ -222,6 +223,7 @@ bool dbg_hw_info(void)
222 (lcd_get_direct_fb() ? "yes" : "no")); 223 (lcd_get_direct_fb() ? "yes" : "no"));
223 line++; 224 line++;
224#endif 225#endif
226#endif
225 lcd_puts(0, line++, "[Rockbox info]"); 227 lcd_puts(0, line++, "[Rockbox info]");
226 lcd_putsf(0, line++, "current tick: %08x Seconds running: %08d", 228 lcd_putsf(0, line++, "current tick: %08x Seconds running: %08d",
227 (unsigned int)current_tick, (unsigned int)current_tick/100); 229 (unsigned int)current_tick, (unsigned int)current_tick/100);
diff --git a/firmware/target/arm/tms320dm320/dma-dm320.c b/firmware/target/arm/tms320dm320/dma-dm320.c
new file mode 100644
index 0000000000..e60102b6fb
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/dma-dm320.c
@@ -0,0 +1,78 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: $
9 *
10 * Copyright (C) 2011 by Tomasz Moń
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "config.h"
23#include "kernel.h"
24#include "thread.h"
25#include "system.h"
26#include "dma-target.h"
27#include "dm320.h"
28#include <stdbool.h>
29
30void dma_init(void)
31{
32 /* TODO */
33}
34
35/*
36 Requests channel for peripheral.
37 Returns channel assigned for caller which must be released after
38 transfer complete using dma_release_channel().
39*/
40int dma_request_channel(int peripheral, int mode)
41{
42 /* TODO: proper checking if channel is already taken
43 currently only SDMMC and DSP uses DMA on this target */
44 int channel = -1;
45
46 if (peripheral == DMA_PERIPHERAL_MMCSD)
47 {
48 /* Set first DMA channel */
49 IO_SDRAM_SDDMASEL = (IO_SDRAM_SDDMASEL & 0xFFE0) | peripheral |
50 (mode << 3);
51 channel = 1;
52 }
53 else if (peripheral == DMA_PERIPHERAL_DSP)
54 {
55 /* Set second DMA channel */
56 IO_SDRAM_SDDMASEL = (IO_SDRAM_SDDMASEL & 0xFC1F) |
57 (peripheral << 5) |
58 (mode << 8);
59 channel = 2;
60 }
61 else if (peripheral == DMA_PERIPHERAL_SIF)
62 {
63 IO_SDRAM_SDDMASEL = (IO_SDRAM_SDDMASEL & 0x83FF) |
64 (peripheral << 10) |
65 (mode << 13);
66 channel = 3;
67 }
68
69 return channel;
70}
71
72void dma_release_channel(int channel)
73{
74 (void)channel;
75 /* TODO */
76}
77
78
diff --git a/firmware/target/arm/tms320dm320/dma-target.h b/firmware/target/arm/tms320dm320/dma-target.h
new file mode 100644
index 0000000000..37053b319b
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/dma-target.h
@@ -0,0 +1,44 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: $
9 *
10 * Copyright (C) 2011 by Tomasz Moń
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef DMA_TARGET_H
23#define DMA_TARGET_H
24
25/* These defines match DMA Select bits */
26#define DMA_PERIPHERAL_MTC 0
27#define DMA_PERIPHERAL_SIF 1
28#define DMA_PERIPHERAL_MS 2
29#define DMA_PERIPHERAL_MMCSD 3
30#define DMA_PERIPHERAL_DSP 4
31
32/* These defines match DMA Burst bits */
33/* 1 burst DMA - address must be 4 byte aligned */
34#define DMA_MODE_1_BURST 0
35/* 4 burst DMA - address must be 16 byte aligned */
36#define DMA_MODE_4_BURST 1
37/* 8 burst DMA - address must be 32 byte aligned */
38#define DMA_MODE_8_BURST 2
39
40void dma_init(void);
41int dma_request_channel(int peripheral, int mode);
42void dma_release_channel(int channel);
43
44#endif
diff --git a/firmware/target/arm/tms320dm320/i2c-dm320.c b/firmware/target/arm/tms320dm320/i2c-dm320.c
index 8bcc84dd8f..990dad0721 100644
--- a/firmware/target/arm/tms320dm320/i2c-dm320.c
+++ b/firmware/target/arm/tms320dm320/i2c-dm320.c
@@ -7,6 +7,7 @@
7 * \/ \/ \/ \/ \/ 7 * \/ \/ \/ \/ \/
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (C) 2011 by Tomasz Moń
10 * Copyright (C) 2008 by Maurus Cuelenaere 11 * Copyright (C) 2008 by Maurus Cuelenaere
11 * 12 *
12 * DM320 I²C driver 13 * DM320 I²C driver
@@ -24,11 +25,11 @@
24#include "thread.h" 25#include "thread.h"
25#include "i2c-dm320.h" 26#include "i2c-dm320.h"
26 27
27#define I2C_SCS_COND_START 0x0001 28#ifdef HAVE_SOFTWARE_I2C
28#define I2C_SCS_COND_STOP 0x0002 29#include "generic_i2c.h"
29#define I2C_SCS_XMIT 0x0004 30#endif
30 31
31#define I2C_TX_ACK (1 << 8) 32#ifndef HAVE_SOFTWARE_I2C
32 33
33static struct mutex i2c_mtx; 34static struct mutex i2c_mtx;
34 35
@@ -42,6 +43,12 @@ static inline void i2c_end(void)
42 mutex_unlock(&i2c_mtx); 43 mutex_unlock(&i2c_mtx);
43} 44}
44 45
46#define I2C_SCS_COND_START 0x0001
47#define I2C_SCS_COND_STOP 0x0002
48#define I2C_SCS_XMIT 0x0004
49
50#define I2C_TX_ACK (1 << 8)
51
45static inline bool i2c_getack(void) 52static inline bool i2c_getack(void)
46{ 53{
47 return (IO_I2C_RXDATA >> 8) & 1; 54 return (IO_I2C_RXDATA >> 8) & 1;
@@ -158,3 +165,126 @@ void i2c_init(void)
158 IO_I2C_SCS &= ~0x8; //set clock to 100 kHz 165 IO_I2C_SCS &= ~0x8; //set clock to 100 kHz
159 IO_INTC_EINT2 &= ~INTR_EINT2_I2C; // disable I²C interrupt 166 IO_INTC_EINT2 &= ~INTR_EINT2_I2C; // disable I²C interrupt
160} 167}
168
169#else /* Software I2C implementation */
170
171#ifdef SANSA_CONNECT
172 /* SDA - GIO35 */
173 #define SDA_SET_REG IO_GIO_BITSET2
174 #define SDA_CLR_REG IO_GIO_BITCLR2
175 #define SOFTI2C_SDA (1 << 3)
176 /* SCL - GIO36 */
177 #define SCL_SET_REG IO_GIO_BITSET2
178 #define SCL_CLR_REG IO_GIO_BITCLR2
179 #define SOFTI2C_SCL (1 << 4)
180#else
181 #error Configure SDA and SCL lines
182#endif
183
184static int dm320_i2c_bus;
185
186static void dm320_scl_dir(bool out)
187{
188 if (out)
189 {
190 IO_GIO_DIR2 &= ~(SOFTI2C_SCL);
191 }
192 else
193 {
194 IO_GIO_DIR2 |= SOFTI2C_SCL;
195 }
196}
197
198static void dm320_sda_dir(bool out)
199{
200 if (out)
201 {
202 IO_GIO_DIR2 &= ~(SOFTI2C_SDA);
203 }
204 else
205 {
206 IO_GIO_DIR2 |= SOFTI2C_SDA;
207 }
208}
209
210static void dm320_scl_out(bool high)
211{
212 if (high)
213 {
214 SCL_SET_REG = SOFTI2C_SCL;
215 }
216 else
217 {
218 SCL_CLR_REG = SOFTI2C_SCL;
219 }
220}
221
222static void dm320_sda_out(bool high)
223{
224 if (high)
225 {
226 SDA_SET_REG = SOFTI2C_SDA;
227 }
228 else
229 {
230 SDA_CLR_REG = SOFTI2C_SDA;
231 }
232}
233
234static bool dm320_scl_in(void)
235{
236 return (SCL_SET_REG & SOFTI2C_SCL);
237}
238
239static bool dm320_sda_in(void)
240{
241 return (SDA_SET_REG & SOFTI2C_SDA);
242}
243
244/* simple delay */
245static void dm320_i2c_delay(int delay)
246{
247 udelay(delay);
248}
249
250/* interface towards the generic i2c driver */
251static const struct i2c_interface dm320_i2c_interface = {
252 .scl_dir = dm320_scl_dir,
253 .sda_dir = dm320_sda_dir,
254 .scl_out = dm320_scl_out,
255 .sda_out = dm320_sda_out,
256 .scl_in = dm320_scl_in,
257 .sda_in = dm320_sda_in,
258 .delay = dm320_i2c_delay,
259
260 /* uncalibrated */
261 .delay_hd_sta = 1,
262 .delay_hd_dat = 1,
263 .delay_su_dat = 1,
264 .delay_su_sto = 1,
265 .delay_su_sta = 1,
266 .delay_thigh = 1
267};
268
269void i2c_init(void)
270{
271#ifdef SANSA_CONNECT
272 IO_GIO_FSEL3 &= 0xFF0F; /* GIO35, GIO36 as normal GIO */
273 IO_GIO_INV2 &= ~(SOFTI2C_SDA | SOFTI2C_SCL); /* not inverted */
274#endif
275
276 /* generic_i2c takes care of setting direction */
277 dm320_i2c_bus = i2c_add_node(&dm320_i2c_interface);
278}
279
280int i2c_write(unsigned short address, const unsigned char* buf, int count)
281{
282 return i2c_write_data(dm320_i2c_bus, address, -1, buf, count);
283}
284
285int i2c_read(unsigned short address, unsigned char* buf, int count)
286{
287 return i2c_read_data(dm320_i2c_bus, address, -1, buf, count);
288}
289
290#endif
diff --git a/firmware/target/arm/tms320dm320/kernel-dm320.c b/firmware/target/arm/tms320dm320/kernel-dm320.c
index 08c50432e4..79206c3413 100644
--- a/firmware/target/arm/tms320dm320/kernel-dm320.c
+++ b/firmware/target/arm/tms320dm320/kernel-dm320.c
@@ -37,7 +37,7 @@ void tick_start(unsigned int interval_in_ms)
37 37
38 /* Setup the Divisor */ 38 /* Setup the Divisor */
39 IO_TIMER1_TMDIV = (TIMER_FREQ / (10*1000))*interval_in_ms - 1; 39 IO_TIMER1_TMDIV = (TIMER_FREQ / (10*1000))*interval_in_ms - 1;
40 40
41 /* Turn Timer1 to Free Run mode */ 41 /* Turn Timer1 to Free Run mode */
42 IO_TIMER1_TMMD = CONFIG_TIMER1_TMMD_FREE_RUN; 42 IO_TIMER1_TMMD = CONFIG_TIMER1_TMMD_FREE_RUN;
43 43
@@ -45,6 +45,13 @@ void tick_start(unsigned int interval_in_ms)
45 bitset16(&IO_INTC_EINT0, INTR_EINT0_TMR1); 45 bitset16(&IO_INTC_EINT0, INTR_EINT0_TMR1);
46} 46}
47 47
48#ifdef BOOTLOADER
49void tick_stop(void)
50{
51 bitclr16(&IO_CLK_MOD2, CLK_MOD2_TMR1); /* disable TIMER1 clock */
52}
53#endif
54
48void TIMER1(void) __attribute__ ((section(".icode"))); 55void TIMER1(void) __attribute__ ((section(".icode")));
49void TIMER1(void) 56void TIMER1(void)
50{ 57{
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/adc-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/adc-sansaconnect.c
new file mode 100644
index 0000000000..b3e427b9a5
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/adc-sansaconnect.c
@@ -0,0 +1,35 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: $
9 *
10 * Copyright (C) 2011 by Tomasz Moń
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "cpu.h"
23#include "adc.h"
24#include "adc-target.h"
25#include "kernel.h"
26
27void adc_init(void)
28{
29}
30
31/* Called to get the recent ADC reading */
32inline unsigned short adc_read(int channel)
33{
34 return (short)channel;
35}
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/adc-target.h b/firmware/target/arm/tms320dm320/sansa-connect/adc-target.h
new file mode 100644
index 0000000000..49244b4c3b
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/adc-target.h
@@ -0,0 +1,25 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: $
9 *
10 * Copyright (C) 2011 by Tomasz Moń
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef _ADC_TARGET_H_
23#define _ADC_TARGET_H_
24
25#endif
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c
new file mode 100644
index 0000000000..3a6a748621
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c
@@ -0,0 +1,461 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id: $
9*
10* Copyright (C) 2011 by Tomasz Moń
11*
12* This program is free software; you can redistribute it and/or
13* modify it under the terms of the GNU General Public License
14* as published by the Free Software Foundation; either version 2
15* of the License, or (at your option) any later version.
16*
17* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18* KIND, either express or implied.
19*
20****************************************************************************/
21
22#include <stdio.h>
23#include "config.h"
24#include "system.h"
25#include "kernel.h"
26#include "logf.h"
27#include "avr-sansaconnect.h"
28#include "uart-target.h"
29#include "button.h"
30#include "backlight.h"
31#include "powermgmt.h"
32
33//#define BUTTON_DEBUG
34
35#ifdef BUTTON_DEBUG
36#include "lcd-target.h"
37#include "lcd.h"
38#include "font.h"
39#include "common.h"
40#endif
41
42#ifdef BUTTON_DEBUG
43#define dbgprintf DEBUGF
44#else
45#define dbgprintf(...)
46#endif
47
48#define CMD_SYNC 0xAA
49#define CMD_CLOSE 0xCC
50#define CMD_LCM_POWER 0xC9
51#define LCM_POWER_OFF 0x00
52#define LCM_POWER_ON 0x01
53#define LCM_POWER_SLEEP 0x02
54#define LCM_POWER_WAKE 0x03
55#define LCM_REPOWER_ON 0x04
56
57#define CMD_STATE 0xBB
58#define CMD_VER 0xBC
59#define CMD_WHEEL_EN 0xD0
60#define CMD_SET_INTCHRG 0xD1
61#define CMD_CODEC_RESET 0xD7
62#define CMD_FILL 0xFF
63
64#define CMD_SYS_CTRL 0xDA
65#define SYS_CTRL_POWEROFF 0x00
66
67/* protects spi avr commands from concurrent access */
68static struct mutex avr_mtx;
69
70/* buttons thread */
71#define BTN_INTERRUPT 1
72static int btn = 0;
73static bool hold_switch;
74#ifndef BOOTLOADER
75static long btn_stack[DEFAULT_STACK_SIZE/sizeof(long)];
76static const char btn_thread_name[] = "buttons";
77static struct event_queue btn_queue;
78#endif
79
80static inline unsigned short be2short(unsigned char* buf)
81{
82 return (unsigned short)((buf[0] << 8) | buf[1]);
83}
84
85#define BUTTON_DIRECT_MASK (BUTTON_LEFT | BUTTON_UP | BUTTON_RIGHT | BUTTON_DOWN | BUTTON_SELECT | BUTTON_VOL_UP | BUTTON_VOL_DOWN | BUTTON_NEXT | BUTTON_PREV)
86
87#ifndef BOOTLOADER
88static void handle_wheel(unsigned char wheel)
89{
90 static int key = 0;
91 static unsigned char velocity = 0;
92 static unsigned long wheel_delta = 1ul << 24;
93 static unsigned char wheel_prev = 0;
94 static long next_backlight_on = 0;
95 static int prev_key = -1;
96 static int prev_key_post = 0;
97
98 if (TIME_AFTER(current_tick, next_backlight_on))
99 {
100 backlight_on();
101 reset_poweroff_timer();
102 next_backlight_on = current_tick + HZ/4;
103 }
104
105 if (wheel_prev < wheel)
106 {
107 key = BUTTON_SCROLL_FWD;
108 velocity = wheel - wheel_prev;
109 }
110 else if (wheel_prev > wheel)
111 {
112 key = BUTTON_SCROLL_BACK;
113 velocity = wheel_prev - wheel;
114 }
115
116 if (prev_key != key && velocity < 2 /* filter "rewinds" */)
117 {
118 /* direction reversal */
119 prev_key = key;
120 wheel_delta = 1ul << 24;
121 return;
122 }
123
124 /* TODO: take velocity into account */
125 if (queue_empty(&button_queue))
126 {
127 if (prev_key_post == key)
128 {
129 key |= BUTTON_REPEAT;
130 }
131
132 /* Post directly, don't update btn as avr doesn't give
133 interrupt on scroll stop */
134 queue_post(&button_queue, key, wheel_delta);
135
136 wheel_delta = 1ul << 24;
137
138 prev_key_post = key;
139 }
140 else
141 {
142 /* skipped post - increment delta and limit to 7 bits */
143 wheel_delta += 1ul << 24;
144
145 if (wheel_delta > (0x7ful << 24))
146 wheel_delta = 0x7ful << 24;
147 }
148
149 wheel_prev = wheel;
150
151 prev_key = key;
152}
153#endif
154
155/* buf must be 11-byte array of byte (reply from avr_hid_get_state() */
156static void parse_button_state(unsigned char *buf)
157{
158 unsigned short main_btns_state = be2short(&buf[4]);
159#ifdef BUTTON_DEBUG
160 unsigned short main_btns_changed = be2short(&buf[6]);
161#endif
162
163 /* make sure other bits doesn't conflict with our "free bits" buttons */
164 main_btns_state &= BUTTON_DIRECT_MASK;
165
166 if (buf[3] & 0x01) /* is power button pressed? */
167 {
168 main_btns_state |= BUTTON_POWER;
169 }
170
171 btn = main_btns_state;
172
173#ifndef BOOTLOADER
174 /* check if stored hold_switch state changed (prevents lost changes) */
175 if ((buf[3] & 0x20) /* hold change notification */ ||
176 (hold_switch != ((buf[3] & 0x02) >> 1)))
177 {
178#endif
179 hold_switch = (buf[3] & 0x02) >> 1;
180#ifdef BUTTON_DEBUG
181 dbgprintf("HOLD changed (%d)", hold_switch);
182#endif
183#ifndef BOOTLOADER
184 backlight_hold_changed(hold_switch);
185 }
186#endif
187#ifndef BOOTLOADER
188 if ((hold_switch == false) && (buf[3] & 0x80)) /* scrollwheel change */
189 {
190 handle_wheel(buf[2]);
191 }
192#endif
193
194#ifdef BUTTON_DEBUG
195 if (buf[3] & 0x10) /* power button change */
196 {
197 /* power button state has changed */
198 main_btns_changed |= BUTTON_POWER;
199 }
200
201 if (btn & BUTTON_LEFT) dbgprintf("LEFT");
202 if (btn & BUTTON_UP) dbgprintf("UP");
203 if (btn & BUTTON_RIGHT) dbgprintf("RIGHT");
204 if (btn & BUTTON_DOWN) dbgprintf("DOWN");
205 if (btn & BUTTON_SELECT) dbgprintf("SELECT");
206 if (btn & BUTTON_VOL_UP) dbgprintf("VOL UP");
207 if (btn & BUTTON_VOL_DOWN) dbgprintf("VOL DOWN");
208 if (btn & BUTTON_NEXT) dbgprintf("NEXT");
209 if (btn & BUTTON_PREV) dbgprintf("PREV");
210 if (btn & BUTTON_POWER) dbgprintf("POWER");
211 if (btn & BUTTON_HOLD) dbgprintf("HOLD");
212 if (btn & BUTTON_SCROLL_FWD) dbgprintf("SCROLL FWD");
213 if (btn & BUTTON_SCROLL_BACK) dbgprintf("SCROLL BACK");
214#endif
215}
216
217/* HID Slave Select - GIO14 */
218#define HID_SS (1<<14)
219
220static inline void select_hid(bool on)
221{
222 if (on == true)
223 {
224 /* SS is active low */
225 IO_GIO_BITCLR0 = HID_SS;
226 }
227 else
228 {
229 IO_GIO_BITSET0 = HID_SS;
230 }
231}
232
233static void spi_txrx(unsigned char *buf_tx, unsigned char *buf_rx, int n)
234{
235 int i;
236 unsigned short rxdata;
237
238 mutex_lock(&avr_mtx);
239
240 bitset16(&IO_CLK_MOD2, CLK_MOD2_SIF1);
241 IO_SERIAL1_TX_ENABLE = 0x0001;
242 select_hid(true);
243
244 for (i = 0; i<n; i++)
245 {
246 IO_SERIAL1_TX_DATA = buf_tx[i];
247 udelay(100);
248
249 do
250 {
251 rxdata = IO_SERIAL1_RX_DATA;
252 } while (rxdata & (1<<8));
253
254 if (buf_rx != NULL)
255 buf_rx[i] = rxdata & 0xFF;
256
257 //udelay(100);
258 }
259
260 select_hid(false);
261 IO_SERIAL1_TX_ENABLE = 0;
262 bitclr16(&IO_CLK_MOD2, CLK_MOD2_SIF1);
263
264 mutex_unlock(&avr_mtx);
265}
266
267static void avr_hid_sync(void)
268{
269 int i;
270 unsigned char prg[4] = {CMD_SYNC, CMD_VER, CMD_FILL, CMD_CLOSE};
271
272 /* Send SYNC three times */
273 for (i = 0; i<3; i++)
274 {
275 spi_txrx(prg, NULL, sizeof(prg));
276 }
277}
278
279void avr_hid_init(void)
280{
281 /*
282 setup alternate GIO functions:
283 GIO29 - SIF1 Enable
284 GIO30 - SIF1 Clock
285 GIO31 - SIF1 Data In
286 GIO32 - SIF1 Data Out
287 */
288 IO_GIO_FSEL2 = (IO_GIO_FSEL2 & 0x00FF) | 0xAA00;
289
290 bitclr16(&IO_GIO_DIR0, HID_SS); /* set GIO14 as output */
291
292 /* RATE = 219 (0xDB) -> 200 kHz */
293 IO_SERIAL1_MODE = 0x6DB;
294
295 mutex_init(&avr_mtx);
296
297 avr_hid_sync();
298}
299
300
301static void avr_hid_get_state(void)
302{
303 static unsigned char cmd[11] = {CMD_SYNC, CMD_STATE,
304 CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL,
305 CMD_CLOSE};
306
307 static unsigned char buf[11];
308 static unsigned char cmd_empty[1] = {0xCC};
309
310 spi_txrx(cmd, buf, sizeof(cmd));
311
312 spi_txrx(cmd_empty, NULL, 1); /* request interrupt on button press */
313
314 parse_button_state(buf);
315}
316
317static void avr_hid_enable_wheel(void)
318{
319 unsigned char wheel_en[4] = {CMD_SYNC, CMD_WHEEL_EN, 0x01, CMD_CLOSE};
320
321 spi_txrx(wheel_en, NULL, sizeof(wheel_en));
322}
323
324/* command that is sent by "hidtool -J 1" issued on every OF boot */
325void avr_hid_enable_charger(void)
326{
327 unsigned char charger_en[4] = {CMD_SYNC, CMD_SET_INTCHRG, 0x01, CMD_CLOSE};
328
329 spi_txrx(charger_en, NULL, sizeof(charger_en));
330}
331
332void avr_hid_lcm_sleep(void)
333{
334 unsigned char lcm_sleep[4] = {CMD_SYNC, CMD_LCM_POWER, LCM_POWER_SLEEP, CMD_CLOSE};
335
336 spi_txrx(lcm_sleep, NULL, sizeof(lcm_sleep));
337}
338
339
340void avr_hid_lcm_wake(void)
341{
342 unsigned char lcm_wake[4] = {CMD_SYNC, CMD_LCM_POWER, LCM_POWER_WAKE, CMD_CLOSE};
343
344 spi_txrx(lcm_wake, NULL, sizeof(lcm_wake));
345}
346
347void avr_hid_lcm_power_on(void)
348{
349 unsigned char lcm_power_on[4] = {CMD_SYNC, CMD_LCM_POWER, LCM_POWER_ON, CMD_CLOSE};
350
351 spi_txrx(lcm_power_on, NULL, sizeof(lcm_power_on));
352}
353
354void avr_hid_lcm_power_off(void)
355{
356 unsigned char lcm_power_off[4] = {CMD_SYNC, CMD_LCM_POWER, LCM_POWER_OFF, CMD_CLOSE};
357
358 spi_txrx(lcm_power_off, NULL, sizeof(lcm_power_off));
359}
360
361void avr_hid_reset_codec(void)
362{
363 unsigned char codec_reset[4] = {CMD_SYNC, CMD_CODEC_RESET, CMD_CLOSE, CMD_FILL};
364
365 spi_txrx(codec_reset, NULL, sizeof(codec_reset));
366}
367
368void avr_hid_power_off(void)
369{
370 unsigned char prg[4] = {CMD_SYNC, CMD_SYS_CTRL, SYS_CTRL_POWEROFF, CMD_CLOSE};
371
372 spi_txrx(prg, NULL, sizeof(prg));
373}
374
375#ifndef BOOTLOADER
376void btn_thread(void)
377{
378 struct queue_event ev;
379
380 while (1)
381 {
382 queue_wait(&btn_queue, &ev);
383
384 /* Ignore all messages except BTN_INTERRUPT */
385 if (ev.id != BTN_INTERRUPT)
386 continue;
387
388 /* Enable back button interrupt */
389 IO_INTC_EINT1 |= INTR_EINT1_EXT0;
390
391 /* Read buttons state */
392 avr_hid_get_state();
393
394 yield();
395
396 if (queue_empty(&btn_queue) && ((IO_GIO_BITSET0 & 0x1) == 0))
397 {
398 /* for some reason we have lost next interrupt */
399 queue_post(&btn_queue, BTN_INTERRUPT, 0);
400 }
401 }
402}
403
404void GIO0(void) __attribute__ ((section(".icode")));
405void GIO0(void)
406{
407 /* Clear interrupt */
408 IO_INTC_IRQ1 = (1 << 5);
409 /* Disable interrupt */
410 IO_INTC_EINT1 &= ~INTR_EINT1_EXT0;
411
412 /* interrupt will be enabled back after button read */
413 queue_post(&btn_queue, BTN_INTERRUPT, 0);
414}
415#endif
416
417void button_init_device(void)
418{
419 btn = 0;
420 hold_switch = false;
421#ifndef BOOTLOADER
422 queue_init(&btn_queue, true);
423 create_thread(btn_thread, btn_stack, sizeof(btn_stack), 0,
424 btn_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE)
425 IF_COP(, CPU));
426#endif
427 IO_GIO_DIR0 |= 0x01; /* Set GIO0 as input */
428
429 /* Enable wheel */
430 avr_hid_enable_wheel();
431 /* Read button status and tell avr we want interrupt on next change */
432 avr_hid_get_state();
433
434#ifndef BOOTLOADER
435 IO_GIO_IRQPORT |= 0x01; /* Enable GIO0 external interrupt */
436 IO_GIO_INV0 &= ~0x01; /* Clear INV for GIO0 (falling edge detection) */
437 IO_GIO_IRQEDGE &= ~0x01; /* Set edge detection (falling) */
438
439 /* Enable GIO0 interrupt */
440 IO_INTC_EINT1 |= INTR_EINT1_EXT0;
441#endif
442}
443
444int button_read_device(void)
445{
446 if(hold_switch)
447 return 0;
448 else
449 return btn;
450}
451
452bool button_hold(void)
453{
454 return hold_switch;
455}
456
457void lcd_enable(bool on)
458{
459 (void)on;
460}
461
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.h b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.h
new file mode 100644
index 0000000000..64b44675f7
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.h
@@ -0,0 +1,38 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id: $
9*
10* Copyright (C) 2011 by Tomasz Moń
11*
12* This program is free software; you can redistribute it and/or
13* modify it under the terms of the GNU General Public License
14* as published by the Free Software Foundation; either version 2
15* of the License, or (at your option) any later version.
16*
17* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18* KIND, either express or implied.
19*
20****************************************************************************/
21
22#ifndef _AVR_SANSACONNECT_H_
23#define _AVR_SANSACONNECT_H_
24
25#include "config.h"
26
27void avr_hid_init(void);
28
29void avr_hid_enable_charger(void);
30
31void avr_hid_lcm_sleep(void);
32void avr_hid_lcm_wake(void);
33void avr_hid_lcm_power_on(void);
34void avr_hid_lcm_power_off(void);
35void avr_hid_reset_codec(void);
36void avr_hid_power_off(void);
37
38#endif /* _AVR_SANSACONNECT_H_ */
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/backlight-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/backlight-sansaconnect.c
new file mode 100644
index 0000000000..b7989849d7
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/backlight-sansaconnect.c
@@ -0,0 +1,93 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: $
9 *
10 * Copyright (C) 2011 by Tomasz Moń
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "config.h"
23#include "cpu.h"
24#include "system.h"
25#include "backlight-target.h"
26#include "backlight.h"
27#include "lcd.h"
28#include "power.h"
29#include "spi-target.h"
30#include "lcd-target.h"
31
32static void _backlight_write_brightness(int brightness)
33{
34 /*
35 Maps brightness int to percentage value found in OF
36
37 OF PWM1H
38 5% 14
39 10% 140
40 15% 210
41 20% 280
42 ...
43 95% 1330
44 100% 1400
45 */
46 if (brightness > 20)
47 brightness = 20;
48 else if (brightness < 0)
49 brightness = 0;
50
51 IO_CLK_PWM1H = brightness*70;
52}
53
54void _backlight_on(void)
55{
56 /* set GIO34 as PWM1 */
57 IO_GIO_FSEL3 = (IO_GIO_FSEL3 & 0xFFF3) | (1 << 2);
58
59#if (CONFIG_BACKLIGHT_FADING == BACKLIGHT_NO_FADING)
60 _backlight_write_brightness(backlight_brightness);
61#endif
62}
63
64void _backlight_off(void)
65{
66 _backlight_write_brightness(0);
67
68 bitclr16(&IO_GIO_FSEL3, 0xC); /* set GIO34 to normal GIO */
69 bitclr16(&IO_GIO_INV2, (1 << 2)); /* make sure GIO34 is not inverted */
70 IO_GIO_BITCLR2 = (1 << 2); /* drive GIO34 low */
71}
72
73/* Assumes that the backlight has been initialized */
74void _backlight_set_brightness(int brightness)
75{
76 _backlight_write_brightness(brightness);
77}
78
79void __backlight_dim(bool dim_now)
80{
81 _backlight_set_brightness(dim_now ?
82 DEFAULT_BRIGHTNESS_SETTING :
83 DEFAULT_DIMNESS_SETTING);
84}
85
86bool _backlight_init(void)
87{
88 IO_CLK_PWM1C = 0x58D; /* as found in OF */
89
90 _backlight_set_brightness(backlight_brightness);
91 return true;
92}
93
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/backlight-target.h b/firmware/target/arm/tms320dm320/sansa-connect/backlight-target.h
new file mode 100644
index 0000000000..89bd837cee
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/backlight-target.h
@@ -0,0 +1,33 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: $
9 *
10 * Copyright (C) 2011 by Tomasz Moń
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef BACKLIGHT_TARGET_H
23#define BACKLIGHT_TARGET_H
24
25bool _backlight_init(void);
26void _backlight_on(void);
27void _backlight_off(void);
28void _backlight_set_brightness(int brightness);
29
30/* true: backlight fades off - false: backlight fades on */
31void __backlight_dim(bool dim);
32
33#endif
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/button-target.h b/firmware/target/arm/tms320dm320/sansa-connect/button-target.h
new file mode 100644
index 0000000000..2eb571ae68
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/button-target.h
@@ -0,0 +1,64 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id: $
9*
10* Copyright (C) 2011 by Tomasz Moń
11*
12* This program is free software; you can redistribute it and/or
13* modify it under the terms of the GNU General Public License
14* as published by the Free Software Foundation; either version 2
15* of the License, or (at your option) any later version.
16*
17* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18* KIND, either express or implied.
19*
20****************************************************************************/
21
22#ifndef _BUTTON_TARGET_H_
23#define _BUTTON_TARGET_H_
24
25#include "config.h"
26
27#define BUTTON_REMOTE 0
28
29/* these definitions match the avr hid reply */
30#define BUTTON_LEFT (1 << 2)
31#define BUTTON_UP (1 << 3)
32#define BUTTON_RIGHT (1 << 4)
33#define BUTTON_DOWN (1 << 5)
34#define BUTTON_SELECT (1 << 6)
35#define BUTTON_VOL_UP (1 << 10)
36#define BUTTON_VOL_DOWN (1 << 11)
37#define BUTTON_NEXT (1 << 13)
38#define BUTTON_PREV (1 << 14)
39
40/* following definitions use "free bits" from avr hid reply */
41#define BUTTON_POWER (1 << 0)
42#define BUTTON_HOLD (1 << 1)
43#define BUTTON_SCROLL_FWD (1 << 7)
44#define BUTTON_SCROLL_BACK (1 << 8)
45
46
47#define BUTTON_REMOTE 0
48#define BUTTON_MAIN (BUTTON_LEFT | BUTTON_UP | BUTTON_RIGHT | BUTTON_DOWN |\
49 BUTTON_SELECT | BUTTON_VOL_UP | BUTTON_VOL_DOWN |\
50 BUTTON_NEXT | BUTTON_PREV | BUTTON_POWER |\
51 BUTTON_SCROLL_FWD | BUTTON_SCROLL_BACK)
52
53#define POWEROFF_BUTTON BUTTON_POWER
54#define POWEROFF_COUNT 5
55
56#define HAS_BUTTON_HOLD
57
58void button_init_device(void);
59int button_read_device(void);
60bool button_hold(void);
61
62int get_debug_info(int choice);
63
64#endif /* _BUTTON_TARGET_H_ */
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/crt0-board.S b/firmware/target/arm/tms320dm320/sansa-connect/crt0-board.S
new file mode 100644
index 0000000000..debd2cd2be
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/crt0-board.S
@@ -0,0 +1,238 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: $
9 *
10 * Copyright (C) 2011 by Tomasz Moń
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "config.h"
22#include "cpu.h"
23
24/* Macro for reading a register */
25.macro mrh register
26 ldr r1, =\register
27 ldrh r0, [r1]
28.endm
29
30/* Macro for writing a register */
31.macro mwh register, value
32 ldr r0, =\value
33 ldr r1, =\register
34 strh r0, [r1]
35.endm
36
37/* This version uses a mov to save on the literal pool size. Otherwise it is
38 * functionally equivalent.
39 */
40.macro mwhm register, value
41 mov r0, #\value
42 ldr r1, =\register
43 strh r0, [r1]
44.endm
45
46 /*
47 * _init_board:
48 * This function initializes the specific board this SoC is on.
49 */
50.section .init, "ax"
51.code 32
52.align 0x04
53.global _init_board
54.type _init_board, %function
55
56_init_board:
57
58 /* Setup the EMIF interface timings */
59
60 /* FLASH interface:
61 * These are based on the OF setup
62 */
63 /* IO_EMIF_CS0CTRL1 and
64 * IO_EMIF_CS0CTRL2
65 */
66 mwh 0x30A00, 0x889A
67 mwh 0x30A02, 0x1110
68
69 mwhm 0x30A04, 0
70 mwh 0x30A06, 0x1415
71 mwh 0x30A08, 0x1109
72
73 mwh 0x30A0A, 0x1220
74 mwh 0x30A0C, 0x1104
75 mwh 0x30A0E, 0x0222
76
77 /* IO_EMIF_CS3CTRL1 and
78 * IO_EMIF_CS3CTRL2
79 */
80 mwh 0x30A10, 0x8899
81 mwh 0x30A12, 0x5110
82
83 /* USB interface */
84 /* IO_EMIF_CS4CTRL1 and
85 * IO_EMIF_CS4CTRL2
86 */
87 mwh 0x30A14, 0x77DF
88 mwh 0x30A16, 0x7740
89
90 /* IO_EMIF_BUSCTRL */
91 mwhm 0x30A18, 0
92 mwhm 0x30A1A, 0
93 mwhm 0x30A1C, 0
94 mwhm 0x30A1E, 0
95
96_clock_setup:
97 /* Clock initialization */
98
99 /* IO_CLK_BYP: Bypass the PLLs for the following changes */
100 mwh 0x30894, 0x1111
101
102 /*
103 * IO_CLK_PLLA
104 * IO_CLK_PLLB
105 */
106 mwhm 0x30880, 0x00A0
107 mwhm 0x30882, 0x1000
108
109 /* IO_CLK_SEL0 */
110 mwh 0x30884, 0x0066
111
112 /* IO_CLK_SEL1 */
113 mwhm 0x30886, 0x0003
114
115 # IO_CLK_SEL2: ARM, AXL, SDRAM and DSP are from PLLA */
116 mwh 0x30888, 0
117
118 /* IO_CLK_DIV0: Set the slow clock speed for the ARM/AHB */
119 mwh 0x3088A, 0x0101
120
121 /* IO_CLK_DIV1: Accelerator, SDRAM */
122 mwh 0x3088C, 0x0102
123
124 /* IO_CLK_DIV2: DSP, MS Clock */
125 mwhm 0x3088E, 0x0200
126
127 # PLLA &= ~0x1000 (BIC #0x1000)
128 mrh 0x30880
129 bic r0, r0, #0x1000
130 strh r0, [r1]
131
132 /* Wait for PLLs to lock before feeding them to the downstream devices */
133_plla_wait:
134 mrh 0x30880
135 bic r0, r0, #0x7F
136 tst r0, r0
137 beq _plla_wait
138
139 /* IO_CLK_BYP: Enable PLL feeds */
140 mwhm 0x30894, 0x0
141
142 /* IO_CLK_MOD0 */
143 mwh 0x30898, 0x01A7
144
145 /* IO_CLK_MOD1 */
146 mwhm 0x3089A, 0x18
147
148 /* IO_CLK_MOD2 */
149 mwhm 0x3089C, 0x4A0
150
151 /* Setup the SDRAM range on the AHB bus */
152 /* SDRAMSA */
153 mov r0, #0x60000
154 mov r1, #0x1000000
155 str r1, [r0, #0xF00]
156
157 /* SDRAMEA: 64MB */
158 mov r1, #0x5000000
159 str r1, [r0, #0xF04]
160
161 /* SDRC_REFCTL */
162 mwh 0x309A8, 0
163
164 ldr r0, =0x309A6
165 mov r2, #0x1380
166 orr r1, r2, #2
167 strh r1, [r0]
168 orr r1, r2, #4
169 strh r1, [r0]
170 strh r1, [r0]
171 strh r1, [r0]
172 strh r1, [r0]
173 strh r1, [r0]
174 strh r1, [r0]
175 strh r1, [r0]
176 strh r1, [r0]
177 orr r1, r2, #1
178 strh r1, [r0]
179 strh r2, [r0]
180 strh r2, [r0]
181
182 mwhm 0x309A8, 0x0140
183
184 mwhm 0x309BE, 0x4
185 mwhm 0x309BC, 0x2
186 ldr r0, =0x309C4
187 ldr r1, [r0]
188 orr r1, r1, #1
189 strh r1, [r0]
190
191 ldr r0, =0x309A6
192 mov r1, #0x1380
193 strh r1, [r0]
194 bic r1, r1, #0x80
195 strh r1, [r0]
196 orr r1, r1, #0x40
197 strh r1, [r0]
198
199 mwhm 0x309A8, 0x0140
200
201 /* Go through the GPIO initialization */
202 /* Warning: setting some of the functions wrong will make OF unable
203 to boot (freeze during startup) */
204 /* IO_GIO_FSEL0: Set up the GPIO pin functions 0-16 */
205 mwhm 0x305A4, 0xC000
206
207 /* IO_GIO_FSEL1: 17-24 */
208 mwh 0x305A6, 0xAAAA
209
210 /* IO_GIO_FSEL2: 18-32 */
211 mwh 0x305A8, 0xA80A
212
213 /* IO_GIO_FSEL3: 33-40 */
214 mwh 0x305AA, 0x1007
215
216 /* IO_GIO_DIR0 */
217 mwh 0x30580, 0xFF77
218
219 /* IO_GIO_DIR1 */
220 mwh 0x30582, 0xEFFE
221
222 /* IO_GIO_DIR2 */
223 mwh 0x30584, 0x01FD
224
225 /* IO_GIO_INV0 */
226 mwh 0x30586, 0x0000
227
228 /* IO_GIO_INV1 */
229 mwh 0x30588, 0x0000
230
231 /* IO_GIO_INV2 */
232 mwh 0x3058A, 0x0000
233
234 bx lr
235
236.ltorg
237.size _init_board, .-_init_board
238
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/lcd-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/lcd-sansaconnect.c
new file mode 100644
index 0000000000..fcfc82e876
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/lcd-sansaconnect.c
@@ -0,0 +1,273 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: $
9 *
10 * Copyright (C) 2011 by Tomasz Moń
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <sys/types.h>
23#include "config.h"
24#include "cpu.h"
25#include "string.h"
26#include "kernel.h"
27#include "system.h"
28#include "system-target.h"
29#include "lcd.h"
30#include "lcd-target.h"
31#include "avr-sansaconnect.h"
32
33/* Copies a rectangle from one framebuffer to another. Can be used in
34 single transfer mode with width = num pixels, and height = 1 which
35 allows a full-width rectangle to be copied more efficiently. */
36extern void lcd_copy_buffer_rect(fb_data *dst, const fb_data *src,
37 int width, int height);
38
39static bool lcd_on = true;
40
41bool lcd_active(void)
42{
43 return lcd_on;
44}
45
46#if defined(HAVE_LCD_SLEEP)
47void lcd_sleep(void)
48{
49 if (lcd_on)
50 {
51 lcd_on = false;
52 avr_hid_lcm_sleep();
53 sleep(HZ/20);
54
55 /* disable video encoder */
56 bitclr16(&IO_VID_ENC_VMOD, 0x01);
57
58 sleep(HZ/20);
59
60 /* disable video encoder clock */
61 bitclr16(&IO_CLK_MOD1, CLK_MOD1_VENC);
62 }
63}
64
65void lcd_awake(void)
66{
67 if (!lcd_on)
68 {
69 lcd_on = true;
70 /* enable video encoder clock */
71 bitset16(&IO_CLK_MOD1, CLK_MOD1_VENC);
72
73 /* enable video encoder */
74 bitset16(&IO_VID_ENC_VMOD, 0x01);
75
76 avr_hid_lcm_wake();
77
78 send_event(LCD_EVENT_ACTIVATION, NULL);
79
80 lcd_update();
81 }
82}
83#endif
84
85void lcd_init_device(void)
86{
87 unsigned int addr;
88
89 /* Disable Video Encoder clock */
90 bitclr16(&IO_CLK_MOD1, CLK_MOD1_VENC);
91
92 /* configure GIO39, GIO34 and GIO33 as outputs */
93 IO_GIO_DIR2 &= ~((1 << 7) /* GIO39 */ | (1 << 2) /* GIO34 */ |
94 (1 << 1) /* GIO33 */);
95
96 IO_GIO_FSEL3 = (IO_GIO_FSEL3 & ~(0x300F)) |
97 (0x1000) /* GIO39 - FIELD_VENC */ |
98 (0x3) /* GIO33 - CLKOUT1B (bootloader does this) */ |
99 (0x4); /* GIO34 - PWM1 (brightness control) */
100
101 /* OSD Clock = VENC Clock /2,
102 CCD clock PCLK,
103 VENC Clock from PLLA */
104 IO_CLK_SEL1 = 0x3;
105
106 /* Set VENC Clock Division to 11
107 OF bootloader sets division to 8, vmlinux sets it to 11 */
108 IO_CLK_DIV3 = (IO_CLK_DIV3 & ~(0x1F00)) | 0xB00;
109
110 /* Enable DAC and OSD clocks */
111 bitset16(&IO_CLK_MOD1, CLK_MOD1_DAC | CLK_MOD1_OSD);
112
113 /* magic values based on OF bootloader initialization */
114 IO_VID_ENC_VMOD = 0x2010;
115 IO_VID_ENC_VDPRO = 0x80;
116 IO_VID_ENC_HSPLS = 0x4;
117 IO_VID_ENC_HINT = 0x4B0;
118 IO_VID_ENC_HSTART = 0x88;
119 IO_VID_ENC_HVALID = 0x3C0;
120 IO_VID_ENC_HSDLY = 0;
121 IO_VID_ENC_VSPLS = 0x2;
122 IO_VID_ENC_VINT = 0x152;
123 IO_VID_ENC_VSTART = 0x6;
124 IO_VID_ENC_VVALID = 0x140;
125 IO_VID_ENC_VSDLY = 0;
126 IO_VID_ENC_DCLKCTL = 0x3;
127 IO_VID_ENC_DCLKPTN0 = 0xC;
128 IO_VID_ENC_VDCTL = 0x6000;
129 IO_VID_ENC_SYNCTL = 0x2;
130 IO_VID_ENC_LCDOUT = 0x101;
131 IO_VID_ENC_VMOD = 0x2011;
132
133 /* Copy Rockbox frame buffer to the second framebuffer */
134 lcd_update();
135
136 avr_hid_lcm_power_on();
137
138 /* set framebuffer address - OF sets RAM start address to 0x1000000 */
139 addr = ((int)FRAME-CONFIG_SDRAM_START)/32;
140
141 IO_OSD_OSDWINADH = addr >> 16;
142 IO_OSD_OSDWIN0ADL = addr & 0xFFFF;
143
144 IO_OSD_BASEPX = 0x44;
145 IO_OSD_BASEPY = 0x6;
146 IO_OSD_OSDWIN0XP = 0;
147 IO_OSD_OSDWIN0YP = 0;
148 IO_OSD_OSDWIN0XL = LCD_WIDTH*2; /* OF bootloader sets 480 */
149 IO_OSD_OSDWIN0YL = LCD_HEIGHT; /* OF bootloader sets 320 */
150 IO_OSD_OSDWIN0OFST = 0xF;
151 IO_OSD_OSDWINMD0 = 0x25FB;/* OF bootloader sets 25C3,
152 vmlinux changes this to 0x25FB */
153 IO_OSD_VIDWINMD = 0; /* disable video windows (OF sets 0x03) */
154
155 IO_OSD_OSDWINMD1 = 0; /* disable OSD window 1 */
156
157 /* Enable DAC, Video Encoder and OSD clocks */
158 bitset16(&IO_CLK_MOD1, CLK_MOD1_DAC | CLK_MOD1_VENC | CLK_MOD1_OSD);
159
160 /* Enable Video Encoder - RGB666, custom timing */
161 IO_VID_ENC_VMOD = 0x2011;
162 avr_hid_lcm_wake();
163}
164
165/* Update a fraction of the display. */
166void lcd_update_rect(int x, int y, int width, int height)
167 __attribute__ ((section(".icode")));
168void lcd_update_rect(int x, int y, int width, int height)
169{
170 register fb_data *dst, *src;
171
172 if (!lcd_on)
173 return;
174
175 if ((width | height) < 0)
176 return; /* Nothing left to do */
177
178 if (x + width > LCD_WIDTH)
179 width = LCD_WIDTH - x; /* Clip right */
180 if (x < 0)
181 width += x, x = 0; /* Clip left */
182
183 if (y + height > LCD_HEIGHT)
184 height = LCD_HEIGHT - y; /* Clip bottom */
185 if (y < 0)
186 height += y, y = 0; /* Clip top */
187
188 dst = FRAME + LCD_WIDTH*y + x;
189 src = &lcd_framebuffer[y][x];
190
191 /* Copy part of the Rockbox framebuffer to the second framebuffer */
192 if (width < LCD_WIDTH)
193 {
194 /* Not full width - do line-by-line */
195 lcd_copy_buffer_rect(dst, src, width, height);
196 }
197 else
198 {
199 /* Full width - copy as one line */
200 lcd_copy_buffer_rect(dst, src, LCD_WIDTH*height, 1);
201 }
202}
203
204/* Update the display.
205 This must be called after all other LCD functions that change the display. */
206void lcd_update(void) __attribute__ ((section(".icode")));
207void lcd_update(void)
208{
209 if (!lcd_on)
210 return;
211
212 lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT);
213}
214
215void lcd_set_contrast(int val) {
216 (void) val;
217 // TODO:
218}
219
220void lcd_set_invert_display(bool yesno) {
221 (void) yesno;
222 // TODO:
223}
224
225void lcd_set_flip(bool yesno) {
226 (void) yesno;
227 // TODO:
228}
229
230/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */
231extern void lcd_write_yuv420_lines(fb_data *dst,
232 unsigned char chroma_buf[LCD_HEIGHT/2*3],
233 unsigned char const * const src[3],
234 int width, int stride);
235
236/* Performance function to blit a YUV bitmap directly to the LCD */
237void lcd_blit_yuv(unsigned char * const src[3],
238 int src_x, int src_y, int stride,
239 int x, int y, int width, int height)
240{
241 /* Caches for chroma data so it only need be recalculated every other
242 line */
243 unsigned char chroma_buf[LCD_HEIGHT/2*3]; /* 480 bytes */
244 unsigned char const * yuv_src[3];
245 off_t z;
246
247 if (!lcd_on)
248 return;
249
250 /* Sorry, but width and height must be >= 2 or else */
251 width &= ~1;
252 height >>= 1;
253
254 fb_data *dst = (fb_data*)FRAME + x * LCD_WIDTH + (LCD_WIDTH - y) - 1;
255
256 z = stride*src_y;
257 yuv_src[0] = src[0] + z + src_x;
258 yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1);
259 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
260
261 do
262 {
263 lcd_write_yuv420_lines(dst, chroma_buf, yuv_src, width,
264 stride);
265
266 yuv_src[0] += stride << 1; /* Skip down two luma lines */
267 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
268 yuv_src[2] += stride >> 1;
269 dst -= 2;
270 }
271 while (--height > 0);
272}
273
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/lcd-target.h b/firmware/target/arm/tms320dm320/sansa-connect/lcd-target.h
new file mode 100644
index 0000000000..0c1ad0d5f5
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/lcd-target.h
@@ -0,0 +1,25 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: $
9 *
10 * Copyright (C) 2011 by Tomasz Moń
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef _LCD_TARGET_H_
23#define _LCD_TARGET_H_
24
25#endif
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/pcm-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/pcm-sansaconnect.c
new file mode 100644
index 0000000000..3f04838388
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/pcm-sansaconnect.c
@@ -0,0 +1,207 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: $
9 *
10 * Copyright (C) 2011 by Tomasz Moń
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdlib.h>
22#include "system.h"
23#include "kernel.h"
24#include "logf.h"
25#include "audio.h"
26#include "sound.h"
27#include "file.h"
28#include "dsp-target.h"
29#include "dsp/ipc.h"
30#include "mmu-arm.h"
31#include "pcm-internal.h"
32#include "dma-target.h"
33
34/* This is global to save some latency when pcm_play_dma_get_peak_buffer is
35 * called.
36 */
37static void *start;
38static int dma_channel;
39
40void pcm_play_dma_postinit(void)
41{
42 audiohw_postinit();
43}
44
45/* Return the current location in the SDRAM to SARAM transfer along with the
46 * number of bytes read in the current buffer (count). There is latency with
47 * this method equivalent to ~ the size of the SARAM buffer since there is
48 * another buffer between your ears and this calculation, but this works for
49 * key clicks and an approximate peak meter.
50 */
51const void * pcm_play_dma_get_peak_buffer(int *count)
52{
53 int cnt = DSP_(_sdem_level);
54
55 unsigned long addr = (unsigned long) start + cnt;
56
57 *count = (cnt & 0xFFFFF) >> 1;
58 return (void *)((addr + 2) & ~3);
59}
60
61void pcm_play_dma_init(void)
62{
63 /* GIO16 is DSP/AIC3X CLK */
64 IO_GIO_FSEL0 &= 0x3FFF;
65 IO_CLK_OSEL = (IO_CLK_OSEL & 0xFFF0) | 4; /* PLLIN clock */
66 IO_CLK_O0DIV = 7;
67 IO_GIO_DIR1 &= ~(1 << 0); /* GIO16 - output */
68 IO_GIO_FSEL0 |= 0xC000; /* GIO16 - CLKOUT0 */
69
70 audiohw_init();
71 audiohw_set_frequency(HW_FREQ_DEFAULT);
72
73 IO_INTC_IRQ0 = INTR_IRQ0_IMGBUF;
74 bitset16(&IO_INTC_EINT0, INTR_EINT0_IMGBUF);
75
76 /* Set this as a FIQ */
77 bitset16(&IO_INTC_FISEL0, INTR_EINT0_IMGBUF);
78
79 /* Enable the HPIB clock */
80 bitset16(&IO_CLK_MOD0, (CLK_MOD0_HPIB | CLK_MOD0_DSP));
81
82 /* Enable IMGBUF clock */
83 bitset16(&IO_CLK_MOD1, CLK_MOD1_IMGBUF);
84
85 dma_channel = dma_request_channel(DMA_PERIPHERAL_DSP,
86 DMA_MODE_1_BURST);
87
88 IO_DSPC_HPIB_CONTROL = 1 << 10 | 1 << 9 | 1 << 8 | 1 << 7 | 1 << 3 | 1 << 0;
89
90 dsp_reset();
91 dsp_load(dsp_image);
92
93 DSP_(_dma0_stopped)=1;
94 dsp_wake();
95}
96
97void pcm_dma_apply_settings(void)
98{
99 audiohw_set_frequency(pcm_fsel);
100}
101
102/* Note that size is actually limited to the size of a short right now due to
103 * the implementation on the DSP side (and the way that we access it)
104 */
105void pcm_play_dma_start(const void *addr, size_t size)
106{
107 unsigned long sdem_addr=(unsigned long)addr - CONFIG_SDRAM_START;
108 /* Initialize codec. */
109 DSP_(_sdem_addrl) = sdem_addr & 0xffff;
110 DSP_(_sdem_addrh) = sdem_addr >> 16;
111 DSP_(_sdem_dsp_size) = size;
112 DSP_(_dma0_stopped)=0;
113
114 dsp_wake();
115}
116
117void pcm_play_dma_stop(void)
118{
119 DSP_(_dma0_stopped)=1;
120 dsp_wake();
121}
122
123void pcm_play_lock(void)
124{
125
126}
127
128void pcm_play_unlock(void)
129{
130
131}
132
133void pcm_play_dma_pause(bool pause)
134{
135 if (pause)
136 {
137 DSP_(_dma0_stopped)=2;
138 dsp_wake();
139 }
140 else
141 {
142 DSP_(_dma0_stopped)=0;
143 dsp_wake();
144 }
145}
146
147size_t pcm_get_bytes_waiting(void)
148{
149 return DSP_(_sdem_dsp_size)-DSP_(_sdem_level);
150}
151
152/* Only used when debugging */
153static char buffer[80];
154
155void DSPHINT(void) __attribute__ ((section(".icode")));
156void DSPHINT(void)
157{
158 unsigned int i;
159 size_t size;
160
161 IO_INTC_FIQ0 = INTR_IRQ0_IMGBUF;
162
163 switch (dsp_message.msg)
164 {
165 case MSG_DEBUGF:
166 /* DSP stores one character per word. */
167 for (i = 0; i < sizeof(buffer); i++)
168 {
169 buffer[i] = dsp_message.payload.debugf.buffer[i];
170 }
171
172 DEBUGF("DSP: %s", buffer);
173 break;
174
175 case MSG_REFILL:
176 /* Buffer empty. Try to get more. */
177 pcm_play_get_more_callback(&start, &size);
178
179 if (size != 0)
180 {
181 unsigned long sdem_addr=(unsigned long)start - CONFIG_SDRAM_START;
182 /* Flush any pending cache writes */
183 clean_dcache_range(start, size);
184
185 /* set the new DMA values */
186 DSP_(_sdem_addrl) = sdem_addr & 0xffff;
187 DSP_(_sdem_addrh) = sdem_addr >> 16;
188 DSP_(_sdem_dsp_size) = size;
189
190 DEBUGF("pcm_sdram at 0x%08lx, sdem_addr 0x%08lx",
191 (unsigned long)start, (unsigned long)sdem_addr);
192
193 pcm_play_dma_started_callback();
194 }
195
196 break;
197 default:
198 DEBUGF("DSP: unknown msg 0x%04x", dsp_message.msg);
199 break;
200 }
201
202 /* Re-Activate the channel */
203 dsp_wake();
204
205 DEBUGF("DSP: %s", buffer);
206}
207
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/power-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/power-sansaconnect.c
new file mode 100644
index 0000000000..52ea9be1d9
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/power-sansaconnect.c
@@ -0,0 +1,59 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: $
9 *
10 * Copyright (C) 2011 by Tomasz Moń
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "config.h"
23#include "cpu.h"
24#include <stdbool.h>
25#include "kernel.h"
26#include "system.h"
27#include "power.h"
28#include "backlight.h"
29#include "backlight-target.h"
30#include "avr-sansaconnect.h"
31
32void power_init(void)
33{
34}
35
36void power_off(void)
37{
38 avr_hid_reset_codec();
39 avr_hid_power_off();
40}
41
42#if CONFIG_CHARGING
43unsigned int power_input_status(void)
44{
45 return POWER_INPUT_NONE;
46}
47
48/* Returns true if the unit is charging the batteries. */
49bool charging_state(void)
50{
51 return false;
52}
53#endif
54
55void ide_power_enable(bool on)
56{
57 (void)on;
58}
59
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/powermgmt-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/powermgmt-sansaconnect.c
new file mode 100644
index 0000000000..bd90c51072
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/powermgmt-sansaconnect.c
@@ -0,0 +1,56 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: $
9 *
10 * Copyright (C) 2011 by Tomasz Moń
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "config.h"
23#include "adc.h"
24#include "powermgmt.h"
25#include "kernel.h"
26
27/* THIS CONTAINS CURRENTLY DUMMY CODE! */
28
29static const unsigned short current_voltage = 3910;
30const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] =
31{
32 0
33};
34
35const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] =
36{
37 0
38};
39
40/* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */
41const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] =
42{
43 { 100, 300, 400, 500, 600, 700, 800, 900, 1000, 1200, 1320 },
44};
45
46/* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */
47const unsigned short percent_to_volt_charge[11] =
48{
49 100, 300, 400, 500, 600, 700, 800, 900, 1000, 1200, 1320,
50};
51
52/* Returns battery voltage from ADC [millivolts] */
53unsigned int battery_adc_voltage(void)
54{
55 return current_voltage;
56}
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/usb-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/usb-sansaconnect.c
new file mode 100644
index 0000000000..ab42beb2b4
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/usb-sansaconnect.c
@@ -0,0 +1,53 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: $
9 *
10 * Copyright (C) 2011 by Tomasz Moń
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "config.h"
23#include "system.h"
24#include "kernel.h"
25#include "usb.h"
26#ifdef HAVE_USBSTACK
27#include "usb_drv.h"
28#include "usb_core.h"
29#endif
30
31bool usb_drv_connected(void)
32{
33 return false;
34}
35
36int usb_detect(void)
37{
38 return USB_EXTRACTED;
39}
40
41void usb_init_device(void)
42{
43 return;
44}
45
46void usb_enable(bool on)
47{
48 (void)on;
49}
50
51void usb_attach(void)
52{
53}
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/usb-target.h b/firmware/target/arm/tms320dm320/sansa-connect/usb-target.h
new file mode 100644
index 0000000000..6142b09f0b
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/usb-target.h
@@ -0,0 +1,32 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: $
9 *
10 * Copyright (C) 2011 by Tomasz Moń
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef USB_TARGET_H
23#define USB_TARGET_H
24
25#include "dm320.h"
26
27#include <stdbool.h>
28int usb_detect(void);
29void usb_init_device(void);
30bool usb_drv_connected(void);
31
32#endif
diff --git a/firmware/target/arm/tms320dm320/sdmmc-dm320.c b/firmware/target/arm/tms320dm320/sdmmc-dm320.c
new file mode 100644
index 0000000000..307b90ec3b
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sdmmc-dm320.c
@@ -0,0 +1,949 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: $
9 *
10 * Copyright (C) 2011 by Tomasz Moń
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "sd.h"
23#include "system.h"
24#include <string.h>
25#include "gcc_extensions.h"
26#include "thread.h"
27#include "panic.h"
28#include "kernel.h"
29#include "dma-target.h"
30
31//#define SD_DEBUG
32
33#ifdef SD_DEBUG
34#include "lcd-target.h"
35#include "lcd.h"
36#include "font.h"
37#ifdef BOOTLOADER
38#include "common.h"
39#else
40#include "debug.h"
41#endif
42#endif
43#include "sdmmc.h"
44#include "disk.h"
45#include "fat.h"
46#include "system-target.h"
47
48/* The configuration method is not very flexible. */
49#define CARD_NUM_SLOT 1
50#define NUM_CARDS 2
51
52#define EC_OK 0
53#define EC_FAILED 1
54#define EC_NOCARD 2
55#define EC_WAIT_STATE_FAILED 3
56#define EC_POWER_UP 4
57#define EC_FIFO_WR_EMPTY 5
58#define EC_FIFO_WR_DONE 6
59#define EC_TRAN_READ_ENTRY 7
60#define EC_TRAN_READ_EXIT 8
61#define EC_TRAN_WRITE_ENTRY 9
62#define EC_TRAN_WRITE_EXIT 10
63#define EC_COMMAND 11
64#define EC_WRITE_PROTECT 12
65#define EC_DATA_TIMEOUT 13
66#define EC_RESP_TIMEOUT 14
67#define EC_CRC_ERROR 15
68#define NUM_EC 16
69
70#define MIN_YIELD_PERIOD 1000
71#define UNALIGNED_NUM_SECTORS 10
72#define MAX_TRANSFER_ERRORS 10
73
74#define SECTOR_SIZE 512
75#define BLOCKS_PER_BANK 0x7A7800
76
77/* command flags for send_cmd */
78#define SDHC_RESP_FMT_NONE 0x0000
79#define SDHC_RESP_FMT_1 0x0200
80#define SDHC_RESP_FMT_2 0x0400
81#define SDHC_RESP_FMT_3 0x0600
82
83#define INITIAL_CLK 312500 /* Initial clock */
84#define SD_CLK 24000000 /* Clock for SD cards */
85#define MMC_CLK 15000000 /* Clock for MMC cards */
86
87#ifdef SD_DEBUG
88#ifdef BOOTLOADER
89#define dbgprintf printf
90#else
91#define dbgprintf DEBUGF
92#endif
93#else
94#define dbgprintf(...)
95#endif
96
97struct sd_card_status
98{
99 int retry;
100 int retry_max;
101};
102
103/** static, private data **/
104
105/* for compatibility */
106static long last_disk_activity = -1;
107
108static bool initialized = false;
109static unsigned int sd_thread_id = 0;
110
111static bool sd_enabled = false;
112static long next_yield = 0;
113
114static tCardInfo card_info [NUM_CARDS];
115static tCardInfo *currcard;
116
117static struct sd_card_status sd_status[NUM_CARDS] =
118{
119#if NUM_CARDS > 1
120 {0, 10},
121#endif
122 {0, 10}
123};
124
125/* Shoot for around 75% usage */
126static long sd_stack [(DEFAULT_STACK_SIZE*2 + 0x1c0)/sizeof(long)];
127static const char sd_thread_name[] = "sd";
128static struct mutex sd_mtx SHAREDBSS_ATTR;
129static struct event_queue sd_queue;
130static volatile unsigned int transfer_error[NUM_DRIVES];
131/* align on cache line size */
132static unsigned char aligned_buffer[UNALIGNED_NUM_SECTORS * SD_BLOCK_SIZE]
133 __attribute__((aligned(32)));
134
135static void sd_card_mux(int card_no)
136{
137#ifdef HAVE_MULTIDRIVE
138#ifdef SANSA_CONNECT
139 /* GIO6 - select Card; GIO5 - select iNAND (both active low) */
140 if (card_no == CARD_NUM_SLOT)
141 {
142 IO_GIO_BITSET0 = (1 << 5); /* deselect iNAND (GIO5) */
143 IO_GIO_BITCLR0 = (1 << 6); /* select card (GIO6) */
144 }
145 else
146 {
147 IO_GIO_BITSET0 = (1 << 6); /* deselect card (GIO6) */
148 IO_GIO_BITCLR0 = (1 << 5); /* select iNAND (GIO5) */
149 }
150#else /* Different players */
151 (void)card_no;
152#endif
153#else /* No multidrive */
154 (void)card_no;
155#endif
156}
157
158
159void sd_enable(bool on)
160{
161 if (sd_enabled == on)
162 return; /* nothing to do */
163
164 if (on)
165 {
166 sd_enabled = true;
167 }
168 else
169 {
170 sd_enabled = false;
171 }
172}
173
174/* sets clock rate just like OF does */
175static void sd_set_clock_rate(unsigned long rate)
176{
177 unsigned char rate_val = 0;
178
179 if (rate == INITIAL_CLK)
180 {
181 rate_val = 0x3B;
182 }
183 else if (rate > INITIAL_CLK)
184 {
185 rate_val = 0;
186 }
187 else
188 {
189 rate_val = 0xFF;
190 }
191
192 IO_MMC_MEM_CLK_CONTROL = (IO_MMC_MEM_CLK_CONTROL & 0xFF00) | rate_val;
193}
194
195static int sd_poll_status(int st_reg_num, volatile unsigned int flag)
196{
197 unsigned int status;
198 unsigned int status1;
199 bool done;
200
201 do
202 {
203 long time = current_tick;
204
205 if (TIME_AFTER(time, next_yield))
206 {
207 long ty = current_tick;
208 yield();
209 next_yield = ty + MIN_YIELD_PERIOD;
210 }
211
212 status = IO_MMC_STATUS0;
213 status1 = IO_MMC_STATUS1;
214
215 if (status & MMC_ST0_CMD_TIMEOUT)
216 {
217 dbgprintf("CMD timeout");
218 return -EC_RESP_TIMEOUT;
219 }
220 if (status & MMC_ST0_DATA_TIMEOUT)
221 {
222 dbgprintf("DATA timeout");
223 return -EC_DATA_TIMEOUT;
224 }
225
226 if (status &
227 (MMC_ST0_WR_CRCERR | MMC_ST0_RD_CRCERR | MMC_ST0_RESP_CRCERR))
228 {
229 dbgprintf("CRC error");
230 return -EC_CRC_ERROR;
231 }
232
233 if (st_reg_num == 0)
234 {
235 done = status & flag;
236 }
237 else
238 {
239 done = status1 & flag;
240 }
241 } while (!done);
242
243 return EC_OK;
244}
245
246static int dma_wait_for_completion(void)
247{
248 unsigned short dma_status;
249
250 do
251 {
252 long time = current_tick;
253
254 if (TIME_AFTER(time, next_yield))
255 {
256 long ty = current_tick;
257 yield();
258 next_yield = ty + MIN_YIELD_PERIOD;
259 }
260
261 dma_status = IO_MMC_SD_DMA_STATUS1;
262 if (dma_status & (1 << 13))
263 {
264 return -EC_DATA_TIMEOUT;
265 }
266 } while (dma_status & (1 << 12));
267
268 return EC_OK;
269}
270
271static int sd_command(int cmd, unsigned long arg,
272 int cmdat, unsigned long *response)
273{
274 int ret;
275
276 /* Clear response registers */
277 IO_MMC_RESPONSE0 = 0;
278 IO_MMC_RESPONSE1 = 0;
279 IO_MMC_RESPONSE2 = 0;
280 IO_MMC_RESPONSE3 = 0;
281 IO_MMC_RESPONSE4 = 0;
282 IO_MMC_RESPONSE5 = 0;
283 IO_MMC_RESPONSE6 = 0;
284 IO_MMC_RESPONSE7 = 0;
285 IO_MMC_COMMAND_INDEX = 0;
286 IO_MMC_SPI_DATA = 0;
287
288 IO_MMC_ARG_LOW = (unsigned int)((arg & 0xFFFF));
289 IO_MMC_ARG_HI = (unsigned int)((arg & 0xFFFF0000) >> 16);
290
291 /* SD is always in push-pull mode */
292 cmdat |= MMC_CMD_PPLEN;
293
294 cmdat |= (cmd & MMC_CMD_CMD_MASK);
295
296 if (cmdat & MMC_CMD_DATA)
297 cmdat |= MMC_CMD_DCLR;
298
299 IO_MMC_COMMAND = cmdat;
300
301 if (cmdat & MMC_CMD_DATA)
302 {
303 /* Command requires data - do not wait for RSPDNE */
304 ret = EC_OK;
305 }
306 else
307 {
308 ret = sd_poll_status(0, MMC_ST0_RSPDNE);
309 }
310
311 if (ret != EC_OK)
312 {
313 dbgprintf("Command failed (ret %d)", ret);
314 return ret;
315 }
316
317 if (response == NULL)
318 {
319 /* discard response */
320 }
321 else if ((cmdat & SDHC_RESP_FMT_1) || (cmdat & SDHC_RESP_FMT_3))
322 {
323 response[0] = (IO_MMC_RESPONSE7 << 16) | IO_MMC_RESPONSE6;
324 }
325 else if (cmdat & SDHC_RESP_FMT_2)
326 {
327 response[0] = (IO_MMC_RESPONSE7 << 16) | IO_MMC_RESPONSE6;
328 response[1] = (IO_MMC_RESPONSE5 << 16) | IO_MMC_RESPONSE4;
329 response[2] = (IO_MMC_RESPONSE3 << 16) | IO_MMC_RESPONSE2;
330 response[3] = (IO_MMC_RESPONSE1 << 16) | IO_MMC_RESPONSE0;
331 }
332
333 return 0;
334}
335
336static int sd_init_card(const int card_no)
337{
338 bool sdhc = false;
339 unsigned long response[4];
340 int ret;
341 int i;
342
343 memset(currcard, 0, sizeof(*currcard));
344 sd_card_mux(card_no);
345
346 /* Set data bus width to 1 bit */
347 bitclr16(&IO_MMC_CONTROL, MMC_CTRL_WIDTH);
348 sd_set_clock_rate(INITIAL_CLK);
349
350 ret = sd_command(SD_GO_IDLE_STATE, 0, MMC_CMD_INITCLK, NULL);
351
352 if (ret < 0)
353 return -1;
354
355 ret = sd_command(SD_SEND_IF_COND, 0x1AA,
356 SDHC_RESP_FMT_3, response);
357 if ((response[0] & 0xFFF) == 0x1AA)
358 {
359 sdhc = true;
360 dbgprintf("found sdhc card");
361 }
362
363 while ((currcard->ocr & (1 << 31)) == 0) /* until card is powered up */
364 {
365 ret = sd_command(SD_APP_CMD, currcard->rca,
366 SDHC_RESP_FMT_1, NULL);
367 if (ret < 0)
368 {
369 dbgprintf("SD_APP_CMD failed");
370 return -1;
371 }
372
373 ret = sd_command(SD_APP_OP_COND,
374 (1 << 20) /* 3.2-3.3V */ |
375 (1 << 21) /* 3.3-3.4V */ |
376 (sdhc ? (1 << 30) : 0),
377 SDHC_RESP_FMT_3, &currcard->ocr);
378
379 if (ret < 0)
380 {
381 dbgprintf("SD_APP_OP_COND failed");
382 return -1;
383 }
384 }
385
386 dbgprintf("Card powered up");
387
388 ret = sd_command(SD_ALL_SEND_CID, 0,
389 SDHC_RESP_FMT_2, response);
390 if (ret < 0)
391 {
392 dbgprintf("SD_ALL_SEND_CID failed");
393 return -1;
394 }
395
396 for (i = 0; i<4; i++)
397 {
398 currcard->cid[i] = response[i];
399 }
400
401 ret = sd_command(SD_SEND_RELATIVE_ADDR, 0,
402 SDHC_RESP_FMT_1, &currcard->rca);
403 if (ret < 0)
404 {
405 dbgprintf("SD_SEND_RELATIVE_ADDR failed");
406 return -1;
407 }
408
409 ret = sd_command(SD_SEND_CSD, currcard->rca,
410 SDHC_RESP_FMT_2, response);
411 if (ret < 0)
412 {
413 dbgprintf("SD_SEND_CSD failed");
414 return -1;
415 }
416
417 for (i = 0; i<4; i++)
418 {
419 currcard->csd[i] = response[i];
420 }
421
422 sd_parse_csd(currcard);
423
424 sd_set_clock_rate(currcard->speed);
425
426 ret = sd_command(SD_SELECT_CARD, currcard->rca,
427 SDHC_RESP_FMT_1, NULL);
428 if (ret < 0)
429 {
430 dbgprintf("SD_SELECT_CARD failed");
431 return -1;
432 }
433
434 ret = sd_command(SD_APP_CMD, currcard->rca,
435 SDHC_RESP_FMT_1, NULL);
436 if (ret < 0)
437 {
438 dbgprintf("SD_APP_CMD failed");
439 return -1;
440 }
441
442 ret = sd_command(SD_SET_BUS_WIDTH, currcard->rca | 2,
443 SDHC_RESP_FMT_1, NULL); /* 4 bit */
444 if (ret < 0)
445 {
446 dbgprintf("SD_SET_BUS_WIDTH failed");
447 return -1;
448 }
449
450 /* Set data bus width to 4 bits */
451 bitset16(&IO_MMC_CONTROL, MMC_CTRL_WIDTH);
452
453 ret = sd_command(SD_SET_BLOCKLEN, currcard->blocksize,
454 SDHC_RESP_FMT_1, NULL);
455 if (ret < 0)
456 {
457 dbgprintf("SD_SET_BLOCKLEN failed");
458 return -1;
459 }
460
461 IO_MMC_BLOCK_LENGTH = currcard->blocksize;
462
463 dbgprintf("Card initialized");
464 currcard->initialized = 1;
465
466 return EC_OK;
467}
468
469/* lock must already by aquired */
470static void sd_select_device(int card_no)
471{
472 currcard = &card_info[card_no];
473
474 if (card_no == 0)
475 {
476 /* Main card always gets a chance */
477 sd_status[0].retry = 0;
478 }
479
480 if (currcard->initialized > 0)
481 {
482 /* This card is already initialized - switch to it */
483 sd_card_mux(card_no);
484 return;
485 }
486
487 if (currcard->initialized == 0)
488 {
489 /* Card needs (re)init */
490 sd_init_card(card_no);
491 }
492}
493
494static inline bool card_detect_target(void)
495{
496#ifdef SANSA_CONNECT
497 bool removed;
498
499 removed = IO_GIO_BITSET0 & (1 << 14);
500
501 return !removed;
502#else
503 return false;
504#endif
505}
506
507
508#ifdef HAVE_HOTSWAP
509
510static int sd1_oneshot_callback(struct timeout *tmo)
511{
512 (void)tmo;
513
514 /* This is called only if the state was stable for 300ms - check state
515 * and post appropriate event. */
516 if (card_detect_target())
517 {
518 queue_broadcast(SYS_HOTSWAP_INSERTED, 0);
519 }
520 else
521 queue_broadcast(SYS_HOTSWAP_EXTRACTED, 0);
522 return 0;
523}
524
525#ifdef SANSA_CONNECT
526void GIO14(void) __attribute__ ((section(".icode")));
527void GIO14(void)
528{
529 static struct timeout sd1_oneshot;
530
531 /* clear interrupt */
532 IO_INTC_IRQ2 = (1<<3);
533
534 timeout_register(&sd1_oneshot, sd1_oneshot_callback, (3*HZ/10), 0);
535}
536#endif
537
538bool sd_removable(IF_MD_NONVOID(int card_no))
539{
540#ifndef HAVE_MULTIDRIVE
541 const int card_no = 0;
542#endif
543
544 return (card_no == CARD_NUM_SLOT);
545}
546
547bool sd_present(IF_MD_NONVOID(int card_no))
548{
549#ifndef HAVE_MULTIDRIVE
550 const int card_no = 0;
551#endif
552
553 return (card_no == CARD_NUM_SLOT) ? card_detect_target() :
554#ifdef SANSA_CONNECT
555 true; /* iNAND is always present */
556#else
557 false;
558#endif
559}
560
561#else /* no hotswap */
562
563bool sd_removable(IF_MD_NONVOID(int card_no))
564{
565#ifdef HAVE_MULTIDRIVE
566 (void)card_no;
567#endif
568
569 /* not applicable */
570 return false;
571}
572
573#endif /* HAVE_HOTSWAP */
574
575static void sd_thread(void) NORETURN_ATTR;
576static void sd_thread(void)
577{
578 struct queue_event ev;
579
580 /* TODO */
581 while (1)
582 {
583 queue_wait_w_tmo(&sd_queue, &ev, HZ);
584 switch ( ev.id )
585 {
586#ifdef HAVE_HOTSWAP
587 case SYS_HOTSWAP_INSERTED:
588 case SYS_HOTSWAP_EXTRACTED:
589 {
590 int success = 1;
591 fat_lock(); /* lock-out FAT activity first -
592 prevent deadlocking via disk_mount that
593 would cause a reverse-order attempt with
594 another thread */
595 mutex_lock(&sd_mtx); /* lock-out card activity - direct calls
596 into driver that bypass the fat cache */
597
598 /* We now have exclusive control of fat cache and ata */
599
600 disk_unmount(0); /* release "by force", ensure file
601 descriptors aren't leaked and any busy
602 ones are invalid if mounting */
603
604 /* Force card init for new card, re-init for re-inserted one or
605 * clear if the last attempt to init failed with an error. */
606 card_info[0].initialized = 0;
607
608 if (ev.id == SYS_HOTSWAP_INSERTED)
609 {
610 /* FIXME: once sd_enabled is implement properly,
611 * reinitializing the controllers might be needed */
612 sd_enable(true);
613 if (success < 0) /* initialisation failed */
614 panicf("SD init failed : %d", success);
615 success = disk_mount(0); /* 0 if fail */
616 }
617
618 /* notify the system about the changed filesystems
619 */
620 if (success)
621 queue_broadcast(SYS_FS_CHANGED, 0);
622
623 /* Access is now safe */
624 mutex_unlock(&sd_mtx);
625 fat_unlock();
626 sd_enable(false);
627 }
628 break;
629#endif
630 }
631 }
632}
633
634static int sd_wait_for_state(unsigned int state)
635{
636 unsigned long response = 0;
637 unsigned int timeout = HZ; /* ticks */
638 long t = current_tick;
639
640 while (1)
641 {
642 long tick;
643 int ret = sd_command(SD_SEND_STATUS, currcard->rca,
644 SDHC_RESP_FMT_1, &response);
645 if (ret < 0)
646 return ret;
647
648 if ((SD_R1_CURRENT_STATE(response) == state))
649 {
650 return EC_OK;
651 }
652
653 if(TIME_AFTER(current_tick, t + timeout))
654 return -2;
655
656 if (TIME_AFTER((tick = current_tick), next_yield))
657 {
658 yield();
659 timeout += current_tick - tick;
660 next_yield = tick + MIN_YIELD_PERIOD;
661 }
662 }
663}
664
665static int sd_transfer_sectors(int card_no, unsigned long start,
666 int count, void *buffer, bool write)
667{
668 int ret;
669 unsigned long start_addr;
670 int dma_channel = -1;
671 bool use_direct_dma;
672 int count_per_dma;
673 unsigned long rel_addr;
674
675 dbgprintf("transfer %d %d %d", card_no, start, count);
676 mutex_lock(&sd_mtx);
677 sd_enable(true);
678
679sd_transfer_retry:
680 if (card_no == CARD_NUM_SLOT && !card_detect_target())
681 {
682 /* no external sd-card inserted */
683 ret = -EC_NOCARD;
684 goto sd_transfer_error;
685 }
686
687 sd_select_device(card_no);
688
689 if (currcard->initialized < 0)
690 {
691 ret = currcard->initialized;
692 goto sd_transfer_error;
693 }
694
695 last_disk_activity = current_tick;
696
697 ret = sd_wait_for_state(SD_TRAN);
698 if (ret < EC_OK)
699 {
700 goto sd_transfer_error;
701 }
702
703 IO_MMC_BLOCK_LENGTH = currcard->blocksize;
704
705 start_addr = start;
706
707 do
708 {
709 count_per_dma = count;
710
711 if (((unsigned long)buffer) & 0x1F)
712 {
713 /* MMC/SD interface requires 32-byte alignment of buffer */
714 use_direct_dma = false;
715 if (count > UNALIGNED_NUM_SECTORS)
716 {
717 count_per_dma = UNALIGNED_NUM_SECTORS;
718 }
719 }
720 else
721 {
722 use_direct_dma = true;
723 }
724
725 if (write == true)
726 {
727 if (use_direct_dma == false)
728 {
729 memcpy(aligned_buffer, buffer, count_per_dma*SD_BLOCK_SIZE);
730 }
731 commit_dcache_range(use_direct_dma ? buffer : aligned_buffer,
732 count_per_dma*SD_BLOCK_SIZE);
733 }
734
735 IO_MMC_NR_BLOCKS = count_per_dma;
736
737 /* Set start_addr to the correct unit (blocks or bytes) */
738 if (!(card_info[card_no].ocr & SD_OCR_CARD_CAPACITY_STATUS))
739 start_addr *= SD_BLOCK_SIZE; /* not SDHC */
740
741 ret = sd_command(write ? SD_WRITE_MULTIPLE_BLOCK : SD_READ_MULTIPLE_BLOCK,
742 start_addr, MMC_CMD_DCLR | MMC_CMD_DATA |
743 SDHC_RESP_FMT_1 | (write ? MMC_CMD_WRITE : 0),
744 NULL);
745
746 if (ret < 0)
747 goto sd_transfer_error;
748
749 /* other burst modes are not supported for this peripheral */
750 dma_channel = dma_request_channel(DMA_PERIPHERAL_MMCSD,
751 DMA_MODE_8_BURST);
752
753 if (use_direct_dma == true)
754 {
755 rel_addr = ((unsigned long)buffer)-CONFIG_SDRAM_START;
756 }
757 else
758 {
759 rel_addr = ((unsigned long)aligned_buffer)-CONFIG_SDRAM_START;
760 }
761
762 IO_MMC_SD_DMA_ADDR_LOW = rel_addr & 0xFFFF;
763 IO_MMC_SD_DMA_ADDR_HI = (rel_addr & 0xFFFF0000) >> 16;
764
765 IO_MMC_SD_DMA_MODE |= MMC_DMAMODE_ENABLE;
766 if (write == true)
767 {
768 IO_MMC_SD_DMA_MODE |= MMC_DMAMODE_WRITE;
769 }
770
771 IO_MMC_SD_DMA_TRIGGER = 1;
772
773 dbgprintf("SD DMA transfer in progress");
774
775 ret = dma_wait_for_completion();
776 dma_release_channel(dma_channel);
777
778 dbgprintf("SD DMA transfer complete");
779
780 if (ret != EC_OK)
781 {
782 goto sd_transfer_error;
783 }
784
785 count -= count_per_dma;
786
787 if (write == false)
788 {
789 discard_dcache_range(use_direct_dma ? buffer : aligned_buffer,
790 count_per_dma*SD_BLOCK_SIZE);
791
792 if (use_direct_dma == false)
793 {
794 memcpy(buffer, aligned_buffer, count_per_dma*SD_BLOCK_SIZE);
795 }
796 }
797
798 buffer += count_per_dma*SD_BLOCK_SIZE;
799 start_addr += count_per_dma;
800
801 last_disk_activity = current_tick;
802
803 ret = sd_command(SD_STOP_TRANSMISSION, 0, SDHC_RESP_FMT_1, NULL);
804 if (ret < 0)
805 {
806 goto sd_transfer_error;
807 }
808
809 ret = sd_wait_for_state(SD_TRAN);
810 if (ret < 0)
811 {
812 goto sd_transfer_error;
813 }
814 } while (count > 0);
815
816 while (1)
817 {
818 sd_enable(false);
819 mutex_unlock(&sd_mtx);
820
821 return ret;
822
823sd_transfer_error:
824 if (sd_status[card_no].retry < sd_status[card_no].retry_max
825 && ret != -EC_NOCARD)
826 {
827 sd_status[card_no].retry++;
828 currcard->initialized = 0;
829 goto sd_transfer_retry;
830 }
831 }
832}
833
834int sd_read_sectors(IF_MD2(int card_no,) unsigned long start, int incount,
835 void* inbuf)
836{
837#ifndef HAVE_MULTIDRIVE
838 const int card_no = 0;
839#endif
840 return sd_transfer_sectors(card_no, start, incount, inbuf, false);
841}
842
843int sd_write_sectors(IF_MD2(int card_no,) unsigned long start, int count,
844 const void* outbuf)
845{
846#ifndef BOOTLOADER
847#ifndef HAVE_MULTIDRIVE
848 const int card_no = 0;
849#endif
850 return sd_transfer_sectors(card_no, start, count, (void*)outbuf, true);
851#else /* we don't need write support in bootloader */
852#ifdef HAVE_MULTIDRIVE
853 (void)card_no;
854#endif
855 (void)start;
856 (void)count;
857 (void)outbuf;
858 return 0;
859#endif
860}
861
862int sd_init(void)
863{
864 int ret = EC_OK;
865
866#ifndef BOOTLOADER
867 sd_enabled = true;
868 sd_enable(false);
869#endif
870 mutex_init(&sd_mtx);
871
872 mutex_lock(&sd_mtx);
873 initialized = true;
874
875 /* based on linux/drivers/mmc/dm320mmc.c
876 Copyright (C) 2006 ZSI, All Rights Reserved.
877 Written by: Ben Bostwick */
878
879 bitclr16(&IO_CLK_MOD2, CLK_MOD2_MMC);
880 bitset16(&IO_CLK_INV, CLK_INV_MMC);
881
882 /* mmc module clock: 75 Mhz (AHB) / 2 = ~37.5 Mhz */
883 /* OF uses 1, but for some reason it freezes on us */
884 IO_CLK_DIV3 = (IO_CLK_DIV3 & 0xFF00) | 0x02;
885
886 bitset16(&IO_CLK_MOD2, CLK_MOD2_MMC);
887
888 /* set mmc module into reset */
889 bitset16(&IO_MMC_CONTROL, (MMC_CTRL_DATRST | MMC_CTRL_CMDRST));
890
891 /* set resp timeout to max */
892 IO_MMC_RESPONSE_TIMEOUT |= 0x1FFF;
893 IO_MMC_READ_TIMEOUT = 0xFFFF;
894
895 /* all done, take mmc module out of reset */
896 bitclr16(&IO_MMC_CONTROL, (MMC_CTRL_DATRST | MMC_CTRL_CMDRST));
897
898#ifdef SANSA_CONNECT
899 /* GIO37 - Power Card; GIO38 - Power iNAND (both active low) */
900 IO_GIO_DIR2 &= ~((1 << 5) /* GIO37 */ | (1 << 6) /* GIO38 */);
901 IO_GIO_INV2 &= ~((1 << 5) /* GIO37 */ | (1 << 6) /* GIO38 */);
902 IO_GIO_BITCLR2 = (1 << 5) | (1 << 6);
903
904 /* GIO6 - select Card; GIO5 - select iNAND (both active low) */
905 IO_GIO_DIR0 &= ~((1 << 6) /* GIO6 */ | (1 << 5) /* GIO5 */);
906 IO_GIO_INV0 &= ~((1 << 6) /* GIO6 */ | (1 << 5) /* GIO5 */);
907 IO_GIO_BITSET0 = (1 << 6) | (1 << 5);
908
909#ifdef HAVE_HOTSWAP
910 /* GIO14 is card detect */
911 IO_GIO_DIR0 |= (1 << 14); /* Set GIO14 as input */
912 IO_GIO_INV0 &= ~(1 << 14); /* GIO14 not inverted */
913 IO_GIO_IRQPORT |= (1 << 14); /* Enable GIO14 external interrupt */
914 IO_GIO_IRQEDGE |= (1 << 14); /* Any edge detection */
915
916 /* Enable GIO14 interrupt */
917 IO_INTC_EINT2 |= INTR_EINT2_EXT14;
918#endif
919#endif
920
921 sd_select_device(1);
922
923 /* Enable Memory Card CLK */
924 bitset16(&IO_MMC_MEM_CLK_CONTROL, (1 << 8));
925
926 queue_init(&sd_queue, true);
927 sd_thread_id = create_thread(sd_thread, sd_stack, sizeof(sd_stack),
928 0, sd_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE)
929 IF_COP(, CPU));
930
931 mutex_unlock(&sd_mtx);
932
933 return ret;
934}
935
936long sd_last_disk_activity(void)
937{
938 return last_disk_activity;
939}
940
941tCardInfo *card_get_info_target(int card_no)
942{
943 return &card_info[card_no];
944}
945
946void sd_sleepnow(void)
947{
948}
949
diff --git a/firmware/target/arm/tms320dm320/system-dm320.c b/firmware/target/arm/tms320dm320/system-dm320.c
index f2a4aacb68..528d442ce5 100644
--- a/firmware/target/arm/tms320dm320/system-dm320.c
+++ b/firmware/target/arm/tms320dm320/system-dm320.c
@@ -26,11 +26,16 @@
26#include "uart-target.h" 26#include "uart-target.h"
27#include "system-arm.h" 27#include "system-arm.h"
28#include "spi.h" 28#include "spi.h"
29#include "i2c.h"
29#ifdef CREATIVE_ZVx 30#ifdef CREATIVE_ZVx
30#include "dma-target.h" 31#include "dma-target.h"
31#else 32#endif
33#ifdef MROBE_500
32#include "usb-mr500.h" 34#include "usb-mr500.h"
33#endif 35#endif
36#ifdef SANSA_CONNECT
37#include "avr-sansaconnect.h"
38#endif
34 39
35static unsigned short clock_arm_slow = 0xFFFF; 40static unsigned short clock_arm_slow = 0xFFFF;
36static unsigned short clock_arm_fast = 0xFFFF; 41static unsigned short clock_arm_fast = 0xFFFF;
@@ -182,7 +187,12 @@ void system_exception_wait(void)
182 IO_INTC_EINT0 = 0; 187 IO_INTC_EINT0 = 0;
183 IO_INTC_EINT1 = 0; 188 IO_INTC_EINT1 = 0;
184 IO_INTC_EINT2 = 0; 189 IO_INTC_EINT2 = 0;
190#ifdef MROBE_500
185 while ((IO_GIO_BITSET0&0x01) != 0); /* Wait for power button */ 191 while ((IO_GIO_BITSET0&0x01) != 0); /* Wait for power button */
192#endif
193#ifdef SANSA_CONNECT
194 while (1); /* Holding power button for a while makes avr system reset */
195#endif
186} 196}
187 197
188void system_init(void) 198void system_init(void)
@@ -311,7 +321,7 @@ void system_init(void)
311 clock_arm_slow = (0 << 8) | 3; 321 clock_arm_slow = (0 << 8) | 3;
312 clock_arm_fast = (1 << 8) | 1; 322 clock_arm_fast = (1 << 8) | 1;
313 } 323 }
314 324
315 /* M48XI disabled, USB buffer powerdown */ 325 /* M48XI disabled, USB buffer powerdown */
316 IO_CLK_LPCTL1 = 0x11; /* I2C wodn't work with this disabled */ 326 IO_CLK_LPCTL1 = 0x11; /* I2C wodn't work with this disabled */
317 327
@@ -337,14 +347,22 @@ void system_init(void)
337 uart_init(); 347 uart_init();
338 spi_init(); 348 spi_init();
339 349
350#ifdef MROBE_500
340 /* Initialization is done so shut the front LED off so that the battery 351 /* Initialization is done so shut the front LED off so that the battery
341 * can charge. 352 * can charge.
342 */ 353 */
343 IO_GIO_BITCLR2 = 0x0001; 354 IO_GIO_BITCLR2 = 0x0001;
344 355#endif
356
345#ifdef CREATIVE_ZVx 357#ifdef CREATIVE_ZVx
346 dma_init(); 358 dma_init();
347#endif 359#endif
360
361#ifdef SANSA_CONNECT
362 i2c_init();
363 avr_hid_init();
364 avr_hid_enable_charger();
365#endif
348} 366}
349 367
350int system_memory_guard(int newmode) 368int system_memory_guard(int newmode)
@@ -388,4 +406,13 @@ void udelay(int usec) {
388 } 406 }
389} 407}
390 408
409#ifdef BOOTLOADER
410void system_prepare_fw_start(void)
411{
412 tick_stop();
413 IO_INTC_EINT0 = 0;
414 IO_INTC_EINT1 = 0;
415 IO_INTC_EINT2 = 0;
416}
417#endif
391 418
diff --git a/firmware/target/arm/tms320dm320/system-target.h b/firmware/target/arm/tms320dm320/system-target.h
index 22cf5546b2..59ae61f8df 100644
--- a/firmware/target/arm/tms320dm320/system-target.h
+++ b/firmware/target/arm/tms320dm320/system-target.h
@@ -41,4 +41,9 @@ void udelay(int usec);
41 true; }) /* handled here */ 41 true; }) /* handled here */
42#endif 42#endif
43 43
44#ifdef BOOTLOADER
45void tick_stop(void);
46void system_prepare_fw_start(void);
47#endif
48
44#endif /* SYSTEM_TARGET_H */ 49#endif /* SYSTEM_TARGET_H */