diff options
author | Marcoen Hirschberg <marcoen@gmail.com> | 2007-04-18 12:22:27 +0000 |
---|---|---|
committer | Marcoen Hirschberg <marcoen@gmail.com> | 2007-04-18 12:22:27 +0000 |
commit | f44f961812c059b69df19ac5bd828986ba10513f (patch) | |
tree | 9b19de69126ed041992f31a7c690db841a36af6f /firmware/target/arm/s3c2440 | |
parent | c3dcc87aa494934943769b70fd752af1271d196a (diff) | |
download | rockbox-f44f961812c059b69df19ac5bd828986ba10513f.tar.gz rockbox-f44f961812c059b69df19ac5bd828986ba10513f.zip |
move the Gigabeat from gigabeat/meg-fx to s3c2440/gigabeat-fx to avoid problems with possible ports in the future: Gigabeat S/V (i.mx31 based) and Kenwood HD20GA7/HD20GA9 (s3c2440 based)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13200 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm/s3c2440')
26 files changed, 3521 insertions, 0 deletions
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/adc-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/adc-meg-fx.c new file mode 100644 index 0000000000..4c448c2e41 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/adc-meg-fx.c | |||
@@ -0,0 +1,144 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006 by Wade Brown | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #include "cpu.h" | ||
20 | #include "adc-target.h" | ||
21 | #include "kernel.h" | ||
22 | |||
23 | |||
24 | |||
25 | static unsigned short adc_readings[NUM_ADC_CHANNELS]; | ||
26 | |||
27 | /* prototypes */ | ||
28 | static unsigned short __adc_read(int channel); | ||
29 | static void adc_tick(void); | ||
30 | |||
31 | |||
32 | |||
33 | void adc_init(void) | ||
34 | { | ||
35 | int i; | ||
36 | |||
37 | /* Turn on the ADC PCLK */ | ||
38 | CLKCON |= (1<<15); | ||
39 | |||
40 | /* Set channel 0, normal mode, disable "start by read" */ | ||
41 | ADCCON &= ~(0x3F); | ||
42 | |||
43 | /* No start delay. Use normal conversion mode. */ | ||
44 | ADCDLY = 0x1; | ||
45 | |||
46 | /* Set and enable the prescaler */ | ||
47 | ADCCON = (ADCCON & ~(0xff<<6)) | (0x19<<6); | ||
48 | ADCCON |= (1<<14); | ||
49 | |||
50 | /* prefill the adc channels */ | ||
51 | for (i = 0; i < NUM_ADC_CHANNELS; i++) | ||
52 | { | ||
53 | adc_readings[i] = __adc_read(i); | ||
54 | } | ||
55 | |||
56 | /* start at zero so when the tick starts it is at zero */ | ||
57 | adc_readings[0] = __adc_read(0); | ||
58 | |||
59 | /* attach the adc reading to the tick */ | ||
60 | tick_add_task(adc_tick); | ||
61 | |||
62 | |||
63 | } | ||
64 | |||
65 | |||
66 | |||
67 | /* Called to get the recent ADC reading */ | ||
68 | inline unsigned short adc_read(int channel) | ||
69 | { | ||
70 | return adc_readings[channel]; | ||
71 | } | ||
72 | |||
73 | |||
74 | |||
75 | /** | ||
76 | * Read the ADC by polling | ||
77 | * @param channel The ADC channel to read | ||
78 | * @return 10bit reading from ADC channel or ADC_READ_ERROR if timeout | ||
79 | */ | ||
80 | static unsigned short __adc_read(int channel) | ||
81 | { | ||
82 | int i; | ||
83 | |||
84 | /* Set the channel */ | ||
85 | ADCCON = (ADCCON & ~(0x7<<3)) | (channel<<3); | ||
86 | |||
87 | /* Start the conversion process */ | ||
88 | ADCCON |= 0x1; | ||
89 | |||
90 | /* Wait for a low Enable_start */ | ||
91 | for (i = 20000;;) { | ||
92 | if(0 == (ADCCON & 0x1)) { | ||
93 | break; | ||
94 | } | ||
95 | else { | ||
96 | i--; | ||
97 | if (0 == i) { | ||
98 | /* Ran out of time */ | ||
99 | return ADC_READ_ERROR; | ||
100 | } | ||
101 | } | ||
102 | } | ||
103 | |||
104 | /* Wait for high End_of_Conversion */ | ||
105 | for(i = 20000;;) { | ||
106 | if(ADCCON & (1<<15)) { | ||
107 | break; | ||
108 | } | ||
109 | else { | ||
110 | i--; | ||
111 | if(0 == i) { | ||
112 | /* Ran out of time */ | ||
113 | return ADC_READ_ERROR; | ||
114 | } | ||
115 | } | ||
116 | } | ||
117 | |||
118 | return (ADCDAT0 & 0x3ff); | ||
119 | } | ||
120 | |||
121 | |||
122 | |||
123 | /* add this to the tick so that the ADC converts are done in the background */ | ||
124 | static void adc_tick(void) | ||
125 | { | ||
126 | static unsigned channel; | ||
127 | |||
128 | /* Check if the End Of Conversion is set */ | ||
129 | if (ADCCON & (1<<15)) | ||
130 | { | ||
131 | adc_readings[channel] = (ADCDAT0 & 0x3FF); | ||
132 | if (++channel >= NUM_ADC_CHANNELS) | ||
133 | { | ||
134 | channel = 0; | ||
135 | } | ||
136 | |||
137 | /* setup the next conversion and start it*/ | ||
138 | ADCCON = (ADCCON & ~(0x7<<3)) | (channel<<3) | 0x01; | ||
139 | } | ||
140 | } | ||
141 | |||
142 | |||
143 | |||
144 | |||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/adc-target.h b/firmware/target/arm/s3c2440/gigabeat-fx/adc-target.h new file mode 100644 index 0000000000..8d2beaf320 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/adc-target.h | |||
@@ -0,0 +1,37 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006 by Barry Wardell | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #ifndef _ADC_TARGET_H_ | ||
20 | #define _ADC_TARGET_H_ | ||
21 | |||
22 | /* only two channels used by the Gigabeat */ | ||
23 | #define NUM_ADC_CHANNELS 2 | ||
24 | |||
25 | #define ADC_BATTERY 0 | ||
26 | #define ADC_HPREMOTE 1 | ||
27 | #define ADC_UNKNOWN_3 2 | ||
28 | #define ADC_UNKNOWN_4 3 | ||
29 | #define ADC_UNKNOWN_5 4 | ||
30 | #define ADC_UNKNOWN_6 5 | ||
31 | #define ADC_UNKNOWN_7 6 | ||
32 | #define ADC_UNKNOWN_8 7 | ||
33 | |||
34 | #define ADC_UNREG_POWER ADC_BATTERY /* For compatibility */ | ||
35 | #define ADC_READ_ERROR 0xFFFF | ||
36 | |||
37 | #endif | ||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/ata-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/ata-meg-fx.c new file mode 100644 index 0000000000..bc2b53d776 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/ata-meg-fx.c | |||
@@ -0,0 +1,143 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id $ | ||
9 | * | ||
10 | * Copyright (C) 2006,2007 by Marcoen Hirschberg | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #include "config.h" | ||
20 | #include "cpu.h" | ||
21 | #include <stdbool.h> | ||
22 | #include "kernel.h" | ||
23 | #include "system.h" | ||
24 | #include "power.h" | ||
25 | #include "panic.h" | ||
26 | #include "pcf50606.h" | ||
27 | #include "ata-target.h" | ||
28 | #include "mmu-meg-fx.h" | ||
29 | #include "backlight-target.h" | ||
30 | |||
31 | /* ARESET on C7C68300 and RESET on ATA interface (Active Low) */ | ||
32 | #define ATA_RESET_ENABLE GPGDAT &= ~(1 << 10) | ||
33 | #define ATA_RESET_DISABLE GPGDAT |= (1 << 10) | ||
34 | |||
35 | /* ATA_EN on C7C68300 */ | ||
36 | #define USB_ATA_ENABLE GPBDAT |= (1 << 5) | ||
37 | #define USB_ATA_DISABLE GPBDAT &= ~(1 << 5) | ||
38 | |||
39 | void ata_reset(void) | ||
40 | { | ||
41 | ATA_RESET_ENABLE; | ||
42 | sleep(1); /* > 25us */ | ||
43 | ATA_RESET_DISABLE; | ||
44 | sleep(1); /* > 2ms */ | ||
45 | } | ||
46 | |||
47 | /* This function is called before enabling the USB bus */ | ||
48 | void ata_enable(bool on) | ||
49 | { | ||
50 | if(on) | ||
51 | USB_ATA_DISABLE; | ||
52 | else | ||
53 | USB_ATA_ENABLE; | ||
54 | |||
55 | GPBCON=( GPGCON&~(1<<11) ) | (1<<10); /* Make the pin an output */ | ||
56 | // GPBUP|=1<<5; /* Disable pullup in SOC as we are now driving */ | ||
57 | } | ||
58 | |||
59 | bool ata_is_coldstart(void) | ||
60 | { | ||
61 | /* Check the pin configuration - return true when pin is unconfigured */ | ||
62 | return (GPGCON & 0x00300000) == 0; | ||
63 | } | ||
64 | |||
65 | void ata_device_init(void) | ||
66 | { | ||
67 | /* ATA reset */ | ||
68 | ATA_RESET_DISABLE; /* Set the pin to disable an active low reset */ | ||
69 | GPGCON=( GPGCON&~(1<<21) ) | (1<<20); /* Make the pin an output */ | ||
70 | GPGUP |= 1<<10; /* Disable pullup in SOC as we are now driving */ | ||
71 | } | ||
72 | |||
73 | #if !defined(BOOTLOADER) | ||
74 | void copy_read_sectors(unsigned char* buf, int wordcount) | ||
75 | { | ||
76 | __buttonlight_trigger(); | ||
77 | |||
78 | /* Unaligned transfer - slow copy */ | ||
79 | if ( (unsigned long)buf & 1) | ||
80 | { /* not 16-bit aligned, copy byte by byte */ | ||
81 | unsigned short tmp = 0; | ||
82 | unsigned char* bufend = buf + wordcount*2; | ||
83 | do | ||
84 | { | ||
85 | tmp = ATA_DATA; | ||
86 | *buf++ = tmp & 0xff; /* I assume big endian */ | ||
87 | *buf++ = tmp >> 8; /* and don't use the SWAB16 macro */ | ||
88 | } while (buf < bufend); /* tail loop is faster */ | ||
89 | return; | ||
90 | } | ||
91 | /* This should never happen, but worth watching for */ | ||
92 | if(wordcount > (1 << 18)) | ||
93 | panicf("atd-meg-fx.c: copy_read_sectors: too many sectors per read!"); | ||
94 | |||
95 | //#define GIGABEAT_DEBUG_ATA | ||
96 | #ifdef GIGABEAT_DEBUG_ATA | ||
97 | static int line = 0; | ||
98 | static char str[256]; | ||
99 | snprintf(str, sizeof(str), "ODD DMA to %08x, %d", buf, wordcount); | ||
100 | lcd_puts(10, line, str); | ||
101 | line = (line+1) % 32; | ||
102 | lcd_update(); | ||
103 | #endif | ||
104 | /* Reset the channel */ | ||
105 | DMASKTRIG0 |= 4; | ||
106 | /* Wait for DMA controller to be ready */ | ||
107 | while(DMASKTRIG0 & 0x2) | ||
108 | ; | ||
109 | while(DSTAT0 & (1 << 20)) | ||
110 | ; | ||
111 | /* Source is ATA_DATA, on AHB Bus, Fixed */ | ||
112 | DISRC0 = (int) 0x18000000; | ||
113 | DISRCC0 = 0x1; | ||
114 | /* Dest mapped to physical address, on AHB bus, increment */ | ||
115 | DIDST0 = (int) buf; | ||
116 | if(DIDST0 < 0x30000000) | ||
117 | DIDST0 += 0x30000000; | ||
118 | DIDSTC0 = 0; | ||
119 | |||
120 | /* DACK/DREQ Sync to AHB, Int on Transfer complete, Whole service, No reload, 16-bit transfers */ | ||
121 | DCON0 = ((1 << 30) | (1<< 29) | (1<<27) | (1<<22) | (1<<20)) | wordcount; | ||
122 | |||
123 | /* Activate the channel */ | ||
124 | DMASKTRIG0 = 0x2; | ||
125 | |||
126 | invalidate_dcache_range((void *)buf, wordcount*2); | ||
127 | |||
128 | INTMSK &= ~(1<<17); /* unmask the interrupt */ | ||
129 | SRCPND = (1<<17); /* clear any pending interrupts */ | ||
130 | /* Start DMA */ | ||
131 | DMASKTRIG0 |= 0x1; | ||
132 | |||
133 | /* Wait for transfer to complete */ | ||
134 | while((DSTAT0 & 0x000fffff)) | ||
135 | yield(); | ||
136 | /* Dump cache for the buffer */ | ||
137 | } | ||
138 | #endif | ||
139 | void dma0(void) | ||
140 | { | ||
141 | } | ||
142 | |||
143 | |||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/ata-target.h b/firmware/target/arm/s3c2440/gigabeat-fx/ata-target.h new file mode 100644 index 0000000000..95e3e110f2 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/ata-target.h | |||
@@ -0,0 +1,70 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006 by Linus Nielsen Feltzing | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #ifndef ATA_TARGET_H | ||
20 | #define ATA_TARGET_H | ||
21 | |||
22 | /* Plain C read & write loops */ | ||
23 | #define PREFER_C_READING | ||
24 | #define PREFER_C_WRITING | ||
25 | #if !defined(BOOTLOADER) | ||
26 | #define ATA_OPTIMIZED_READING | ||
27 | void copy_read_sectors(unsigned char* buf, int wordcount); | ||
28 | #endif | ||
29 | |||
30 | #define ATA_IOBASE 0x18000000 | ||
31 | #define ATA_DATA (*((volatile unsigned short*)(ATA_IOBASE))) | ||
32 | #define ATA_ERROR (*((volatile unsigned char*)(ATA_IOBASE + 0x02))) | ||
33 | #define ATA_NSECTOR (*((volatile unsigned char*)(ATA_IOBASE + 0x04))) | ||
34 | #define ATA_SECTOR (*((volatile unsigned char*)(ATA_IOBASE + 0x06))) | ||
35 | #define ATA_LCYL (*((volatile unsigned char*)(ATA_IOBASE + 0x08))) | ||
36 | #define ATA_HCYL (*((volatile unsigned char*)(ATA_IOBASE + 0x0A))) | ||
37 | #define ATA_SELECT (*((volatile unsigned char*)(ATA_IOBASE + 0x0C))) | ||
38 | #define ATA_COMMAND (*((volatile unsigned char*)(ATA_IOBASE + 0x0E))) | ||
39 | #define ATA_CONTROL (*((volatile unsigned char*)(0x20000000 + 0x1C))) | ||
40 | |||
41 | #define STATUS_BSY 0x80 | ||
42 | #define STATUS_RDY 0x40 | ||
43 | #define STATUS_DF 0x20 | ||
44 | #define STATUS_DRQ 0x08 | ||
45 | #define STATUS_ERR 0x01 | ||
46 | #define ERROR_ABRT 0x04 | ||
47 | |||
48 | #define WRITE_PATTERN1 0xa5 | ||
49 | #define WRITE_PATTERN2 0x5a | ||
50 | #define WRITE_PATTERN3 0xaa | ||
51 | #define WRITE_PATTERN4 0x55 | ||
52 | |||
53 | #define READ_PATTERN1 0xa5 | ||
54 | #define READ_PATTERN2 0x5a | ||
55 | #define READ_PATTERN3 0xaa | ||
56 | #define READ_PATTERN4 0x55 | ||
57 | |||
58 | #define READ_PATTERN1_MASK 0xff | ||
59 | #define READ_PATTERN2_MASK 0xff | ||
60 | #define READ_PATTERN3_MASK 0xff | ||
61 | #define READ_PATTERN4_MASK 0xff | ||
62 | |||
63 | #define SET_REG(reg,val) reg = (val) | ||
64 | #define SET_16BITREG(reg,val) reg = (val) | ||
65 | |||
66 | void ata_reset(void); | ||
67 | void ata_device_init(void); | ||
68 | bool ata_is_coldstart(void); | ||
69 | |||
70 | #endif | ||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/backlight-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/backlight-meg-fx.c new file mode 100644 index 0000000000..a1b6a8a583 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/backlight-meg-fx.c | |||
@@ -0,0 +1,692 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006 by Linus Nielsen Feltzing | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #include "config.h" | ||
20 | #include "cpu.h" | ||
21 | #include "system.h" | ||
22 | #include "backlight-target.h" | ||
23 | #include "backlight.h" | ||
24 | #include "lcd.h" | ||
25 | #include "sc606-meg-fx.h" | ||
26 | #include "power.h" | ||
27 | |||
28 | |||
29 | #define FLICKER_PERIOD 15 | ||
30 | #define BUTTONLIGHT_MENU (SC606_LED_B1) | ||
31 | #define BUTTONLIGHT_ALL (SC606_LED_B1 | SC606_LED_B2 | SC606_LED_C1 | SC606_LED_C2) | ||
32 | |||
33 | static void led_control_service(void); | ||
34 | static unsigned short backlight_brightness; | ||
35 | static unsigned short backlight_current; | ||
36 | static unsigned short backlight_target; | ||
37 | static unsigned short time_til_fade; | ||
38 | static unsigned short fade_interval; | ||
39 | static unsigned short initial_tick_delay; | ||
40 | static unsigned char backlight_leds; | ||
41 | |||
42 | static enum backlight_states | ||
43 | { | ||
44 | BACKLIGHT_CONTROL_IDLE, | ||
45 | BACKLIGHT_CONTROL_OFF, | ||
46 | BACKLIGHT_CONTROL_ON, | ||
47 | BACKLIGHT_CONTROL_SET, | ||
48 | BACKLIGHT_CONTROL_FADE_OFF, | ||
49 | BACKLIGHT_CONTROL_FADE_ON, | ||
50 | BACKLIGHT_CONTROL_FADE_ON_FROM_OFF | ||
51 | } backlight_control; | ||
52 | |||
53 | |||
54 | |||
55 | enum buttonlight_states | ||
56 | { | ||
57 | /* turn button lights off */ | ||
58 | BUTTONLIGHT_MODE_OFF_ENTRY, | ||
59 | BUTTONLIGHT_MODE_OFF, | ||
60 | |||
61 | /* turns button lights on to setting */ | ||
62 | BUTTONLIGHT_MODE_ON_ENTRY, | ||
63 | BUTTONLIGHT_MODE_ON, | ||
64 | |||
65 | /* turns button lights on to minimum */ | ||
66 | BUTTONLIGHT_MODE_FAINT_ENTRY, | ||
67 | BUTTONLIGHT_MODE_FAINT, | ||
68 | |||
69 | /* allows button lights to flicker when triggered */ | ||
70 | BUTTONLIGHT_MODE_FLICKER_ENTRY, | ||
71 | BUTTONLIGHT_MODE_FLICKER, | ||
72 | BUTTONLIGHT_MODE_FLICKERING, | ||
73 | |||
74 | /* button lights solid */ | ||
75 | BUTTONLIGHT_MODE_SOLID_ENTRY, | ||
76 | BUTTONLIGHT_MODE_SOLID, | ||
77 | |||
78 | /* button light charing */ | ||
79 | BUTTONLIGHT_MODE_CHARGING_ENTRY, | ||
80 | BUTTONLIGHT_MODE_CHARGING, | ||
81 | BUTTONLIGHT_MODE_CHARGING_WAIT, | ||
82 | |||
83 | /* internal use only */ | ||
84 | BUTTONLIGHT_HELPER_SET, | ||
85 | BUTTONLIGHT_HELPER_SET_FINAL, | ||
86 | BUTTONLIGHT_MODE_STOP, | ||
87 | |||
88 | /* buttonlights follow the backlight settings */ | ||
89 | BUTTONLIGHT_MODE_FOLLOW_ENTRY, | ||
90 | BUTTONLIGHT_MODE_FOLLOW, | ||
91 | }; | ||
92 | |||
93 | |||
94 | |||
95 | static char buttonlight_leds; | ||
96 | static unsigned short buttonlight_setting; | ||
97 | static unsigned short buttonlight_current; | ||
98 | static unsigned char buttonlight_selected; | ||
99 | static enum buttonlight_states buttonlight_state; | ||
100 | static enum buttonlight_states buttonlight_saved_state; | ||
101 | static unsigned short buttonlight_flickering; | ||
102 | |||
103 | static unsigned short buttonlight_trigger_now; | ||
104 | static unsigned short buttonlight_trigger_brightness; | ||
105 | |||
106 | |||
107 | |||
108 | static unsigned short charging_led_index; | ||
109 | static unsigned short buttonlight_charging_counter; | ||
110 | |||
111 | #define CHARGING_LED_COUNT 60 | ||
112 | unsigned char charging_leds[] = { 0x00, 0x20, 0x38, 0x3C }; | ||
113 | |||
114 | |||
115 | |||
116 | bool __backlight_init(void) | ||
117 | { | ||
118 | backlight_control = BACKLIGHT_CONTROL_IDLE; | ||
119 | |||
120 | backlight_current = DEFAULT_BRIGHTNESS_SETTING; | ||
121 | |||
122 | buttonlight_state = BUTTONLIGHT_MODE_OFF; | ||
123 | |||
124 | buttonlight_selected = 0x04; | ||
125 | |||
126 | /* delay 4 seconds before any fading */ | ||
127 | initial_tick_delay = 400; | ||
128 | /* put the led control on the tick list */ | ||
129 | tick_add_task(led_control_service); | ||
130 | |||
131 | return true; | ||
132 | } | ||
133 | |||
134 | |||
135 | |||
136 | void __backlight_on(void) | ||
137 | { | ||
138 | /* now go turn the backlight on */ | ||
139 | backlight_control = BACKLIGHT_CONTROL_ON; | ||
140 | } | ||
141 | |||
142 | |||
143 | |||
144 | void __backlight_off(void) | ||
145 | { | ||
146 | backlight_control = BACKLIGHT_CONTROL_OFF; | ||
147 | } | ||
148 | |||
149 | |||
150 | |||
151 | /* Assumes that the backlight has been initialized */ | ||
152 | void __backlight_set_brightness(int brightness) | ||
153 | { | ||
154 | /* stop the interrupt from messing us up */ | ||
155 | backlight_control = BACKLIGHT_CONTROL_IDLE; | ||
156 | |||
157 | backlight_brightness = brightness + 1; | ||
158 | |||
159 | /* only set the brightness if it is different from the current */ | ||
160 | if (backlight_brightness != backlight_current) | ||
161 | { | ||
162 | backlight_control = BACKLIGHT_CONTROL_SET; | ||
163 | } | ||
164 | } | ||
165 | |||
166 | |||
167 | |||
168 | /* only works if the buttonlight mode is set to triggered mode */ | ||
169 | void __buttonlight_trigger(void) | ||
170 | { | ||
171 | buttonlight_trigger_now = 1; | ||
172 | } | ||
173 | |||
174 | |||
175 | |||
176 | |||
177 | /* map the mode from the command into the state machine entries */ | ||
178 | void __buttonlight_mode(enum buttonlight_mode mode, | ||
179 | enum buttonlight_selection selection, | ||
180 | unsigned short brightness) | ||
181 | { | ||
182 | /* choose stop to setup mode */ | ||
183 | buttonlight_state = BUTTONLIGHT_MODE_STOP; | ||
184 | |||
185 | |||
186 | /* clip brightness */ | ||
187 | if (brightness > MAX_BRIGHTNESS_SETTING) | ||
188 | { | ||
189 | brightness = MAX_BRIGHTNESS_SETTING; | ||
190 | } | ||
191 | |||
192 | brightness++; | ||
193 | |||
194 | /* Select which LEDs to use */ | ||
195 | switch (selection) | ||
196 | { | ||
197 | case BUTTONLIGHT_LED_ALL: | ||
198 | buttonlight_selected = BUTTONLIGHT_ALL; | ||
199 | break; | ||
200 | |||
201 | case BUTTONLIGHT_LED_MENU: | ||
202 | buttonlight_selected = BUTTONLIGHT_MENU; | ||
203 | break; | ||
204 | } | ||
205 | |||
206 | /* which mode to use */ | ||
207 | switch (mode) | ||
208 | { | ||
209 | case BUTTONLIGHT_OFF: | ||
210 | buttonlight_state = BUTTONLIGHT_MODE_OFF_ENTRY; | ||
211 | break; | ||
212 | |||
213 | case BUTTONLIGHT_ON: | ||
214 | buttonlight_trigger_brightness = brightness; | ||
215 | buttonlight_state = BUTTONLIGHT_MODE_ON_ENTRY; | ||
216 | break; | ||
217 | |||
218 | /* faint is just a quick way to set ON to 1 */ | ||
219 | case BUTTONLIGHT_FAINT: | ||
220 | buttonlight_trigger_brightness = 1; | ||
221 | buttonlight_state = BUTTONLIGHT_MODE_ON_ENTRY; | ||
222 | break; | ||
223 | |||
224 | case BUTTONLIGHT_FLICKER: | ||
225 | buttonlight_trigger_brightness = brightness; | ||
226 | buttonlight_state = BUTTONLIGHT_MODE_FLICKER_ENTRY; | ||
227 | break; | ||
228 | |||
229 | case BUTTONLIGHT_SIGNAL: | ||
230 | buttonlight_trigger_brightness = brightness; | ||
231 | buttonlight_state = BUTTONLIGHT_MODE_SOLID_ENTRY; | ||
232 | break; | ||
233 | |||
234 | case BUTTONLIGHT_FOLLOW: | ||
235 | buttonlight_state = BUTTONLIGHT_MODE_FOLLOW_ENTRY; | ||
236 | break; | ||
237 | |||
238 | case BUTTONLIGHT_CHARGING: | ||
239 | buttonlight_state = BUTTONLIGHT_MODE_CHARGING_ENTRY; | ||
240 | break; | ||
241 | |||
242 | default: | ||
243 | return; /* unknown mode */ | ||
244 | } | ||
245 | |||
246 | |||
247 | } | ||
248 | |||
249 | |||
250 | |||
251 | /* | ||
252 | * The button lights have 'modes' of operation. Each mode must setup and | ||
253 | * execute its own operation - taking care that this is all done in an ISR. | ||
254 | * | ||
255 | */ | ||
256 | |||
257 | |||
258 | |||
259 | /* led_control_service runs in interrupt context - be brief! | ||
260 | * This service is called once per interrupt timer tick - 100 times a second. | ||
261 | * | ||
262 | * There should be at most only one i2c operation per call - if more are need | ||
263 | * the calls should be spread across calls. | ||
264 | * | ||
265 | * Putting all led servicing in one thread means that we wont step on any | ||
266 | * i2c operations - they are all serialized here in the ISR tick. It also | ||
267 | * insures that we get called at equal timing for good visual effect. | ||
268 | * | ||
269 | * The buttonlight service runs only after all backlight services have finished. | ||
270 | * Fading the buttonlights is possible, but not recommended because of the | ||
271 | * additional calls needed during the ISR | ||
272 | */ | ||
273 | static void led_control_service(void) | ||
274 | { | ||
275 | if(initial_tick_delay) { | ||
276 | initial_tick_delay--; | ||
277 | return; | ||
278 | } | ||
279 | switch (backlight_control) | ||
280 | { | ||
281 | case BACKLIGHT_CONTROL_IDLE: | ||
282 | switch (buttonlight_state) | ||
283 | { | ||
284 | case BUTTONLIGHT_MODE_STOP: break; | ||
285 | |||
286 | /* Buttonlight mode: OFF */ | ||
287 | case BUTTONLIGHT_MODE_OFF_ENTRY: | ||
288 | if (buttonlight_current) | ||
289 | { | ||
290 | buttonlight_leds = 0x00; | ||
291 | sc606_write(SC606_REG_CONF, backlight_leds); | ||
292 | buttonlight_current = 0; | ||
293 | } | ||
294 | buttonlight_state = BUTTONLIGHT_MODE_OFF; | ||
295 | break; | ||
296 | |||
297 | case BUTTONLIGHT_MODE_OFF: | ||
298 | break; | ||
299 | |||
300 | |||
301 | /* button mode: CHARGING - show charging sequence */ | ||
302 | case BUTTONLIGHT_MODE_CHARGING_ENTRY: | ||
303 | /* start turned off */ | ||
304 | buttonlight_leds = 0x00; | ||
305 | sc606_write(SC606_REG_CONF, backlight_leds); | ||
306 | buttonlight_current = 0; | ||
307 | |||
308 | /* temporary save for the next mode - then to do settings */ | ||
309 | buttonlight_setting = DEFAULT_BRIGHTNESS_SETTING; | ||
310 | buttonlight_saved_state = BUTTONLIGHT_MODE_CHARGING_WAIT; | ||
311 | buttonlight_state = BUTTONLIGHT_HELPER_SET; | ||
312 | break; | ||
313 | |||
314 | |||
315 | case BUTTONLIGHT_MODE_CHARGING: | ||
316 | if (--buttonlight_charging_counter == 0) | ||
317 | { | ||
318 | /* change led */ | ||
319 | if (charging_state()) | ||
320 | { | ||
321 | buttonlight_leds = charging_leds[charging_led_index]; | ||
322 | if (++charging_led_index >= sizeof(charging_leds)) | ||
323 | { | ||
324 | charging_led_index = 0; | ||
325 | } | ||
326 | sc606_write(SC606_REG_CONF, backlight_leds | buttonlight_leds); | ||
327 | buttonlight_charging_counter = CHARGING_LED_COUNT; | ||
328 | } | ||
329 | else | ||
330 | { | ||
331 | buttonlight_state = BUTTONLIGHT_MODE_CHARGING_ENTRY; | ||
332 | } | ||
333 | } | ||
334 | break; | ||
335 | |||
336 | /* wait for the charget to be plugged in */ | ||
337 | case BUTTONLIGHT_MODE_CHARGING_WAIT: | ||
338 | if (charging_state()) | ||
339 | { | ||
340 | charging_led_index = 0; | ||
341 | buttonlight_charging_counter = CHARGING_LED_COUNT; | ||
342 | buttonlight_state = BUTTONLIGHT_MODE_CHARGING; | ||
343 | } | ||
344 | break; | ||
345 | |||
346 | |||
347 | /* Buttonlight mode: FOLLOW - try to stay current with backlight | ||
348 | * since this runs in the idle of the backlight it will not really | ||
349 | * follow in real time | ||
350 | */ | ||
351 | case BUTTONLIGHT_MODE_FOLLOW_ENTRY: | ||
352 | /* case 1 - backlight on, but buttonlight is off */ | ||
353 | if (backlight_current) | ||
354 | { | ||
355 | /* Turn the buttonlights on */ | ||
356 | buttonlight_leds = buttonlight_selected; | ||
357 | sc606_write(SC606_REG_CONF, backlight_leds | buttonlight_leds); | ||
358 | |||
359 | /* temporary save for the next mode - then to do settings */ | ||
360 | buttonlight_setting = backlight_current; | ||
361 | buttonlight_saved_state = BUTTONLIGHT_MODE_FOLLOW; | ||
362 | buttonlight_state = BUTTONLIGHT_HELPER_SET; | ||
363 | } | ||
364 | /* case 2 - backlight off, but buttonlight is on */ | ||
365 | else | ||
366 | { | ||
367 | buttonlight_current = 0; | ||
368 | buttonlight_leds = 0x00; | ||
369 | sc606_write(SC606_REG_CONF, backlight_leds); | ||
370 | buttonlight_state = BUTTONLIGHT_MODE_FOLLOW; | ||
371 | } | ||
372 | break; | ||
373 | |||
374 | case BUTTONLIGHT_MODE_FOLLOW: | ||
375 | if (buttonlight_current != backlight_current) | ||
376 | { | ||
377 | /* case 1 - backlight on, but buttonlight is off */ | ||
378 | if (backlight_current) | ||
379 | { | ||
380 | if (0 == buttonlight_current) | ||
381 | { | ||
382 | /* Turn the buttonlights on */ | ||
383 | buttonlight_leds = buttonlight_selected; | ||
384 | sc606_write(SC606_REG_CONF, backlight_leds | buttonlight_leds); | ||
385 | } | ||
386 | |||
387 | /* temporary save for the next mode - then to do settings */ | ||
388 | buttonlight_setting = backlight_current; | ||
389 | buttonlight_saved_state = BUTTONLIGHT_MODE_FOLLOW; | ||
390 | buttonlight_state = BUTTONLIGHT_HELPER_SET; | ||
391 | } | ||
392 | |||
393 | /* case 2 - backlight off, but buttonlight is on */ | ||
394 | else | ||
395 | { | ||
396 | buttonlight_current = 0; | ||
397 | buttonlight_leds = 0x00; | ||
398 | sc606_write(SC606_REG_CONF, backlight_leds); | ||
399 | } | ||
400 | |||
401 | } | ||
402 | break; | ||
403 | |||
404 | |||
405 | |||
406 | /* Buttonlight mode: ON - stays at the set brightness */ | ||
407 | case BUTTONLIGHT_MODE_ON_ENTRY: | ||
408 | buttonlight_leds = buttonlight_selected; | ||
409 | sc606_write(SC606_REG_CONF, backlight_leds | buttonlight_leds); | ||
410 | |||
411 | /* temporary save for the next mode - then to do settings */ | ||
412 | buttonlight_setting = buttonlight_trigger_brightness; | ||
413 | buttonlight_saved_state = BUTTONLIGHT_MODE_ON; | ||
414 | buttonlight_state = BUTTONLIGHT_HELPER_SET; | ||
415 | break; | ||
416 | |||
417 | case BUTTONLIGHT_MODE_ON: | ||
418 | break; | ||
419 | |||
420 | |||
421 | |||
422 | /* Buttonlight mode: FLICKER */ | ||
423 | case BUTTONLIGHT_MODE_FLICKER_ENTRY: | ||
424 | /* already on? turn it off */ | ||
425 | if (buttonlight_current) | ||
426 | { | ||
427 | buttonlight_leds = 0x00; | ||
428 | sc606_write(SC606_REG_CONF, backlight_leds); | ||
429 | buttonlight_current = 0; | ||
430 | } | ||
431 | |||
432 | /* set the brightness if not already set */ | ||
433 | if (buttonlight_current != buttonlight_trigger_brightness) | ||
434 | { | ||
435 | /* temporary save for the next mode - then to do settings */ | ||
436 | buttonlight_setting = buttonlight_trigger_brightness; | ||
437 | buttonlight_saved_state = BUTTONLIGHT_MODE_FLICKER; | ||
438 | buttonlight_state = BUTTONLIGHT_HELPER_SET; | ||
439 | } | ||
440 | else buttonlight_state = BUTTONLIGHT_MODE_FLICKER; | ||
441 | break; | ||
442 | |||
443 | |||
444 | case BUTTONLIGHT_MODE_FLICKER: | ||
445 | /* wait for the foreground to trigger flickering */ | ||
446 | if (buttonlight_trigger_now) | ||
447 | { | ||
448 | /* turn them on */ | ||
449 | buttonlight_leds = buttonlight_selected; | ||
450 | buttonlight_current = buttonlight_setting; | ||
451 | sc606_write(SC606_REG_CONF, backlight_leds | buttonlight_leds); | ||
452 | |||
453 | /* reset the trigger and go flicker the LEDs */ | ||
454 | buttonlight_trigger_now = 0; | ||
455 | buttonlight_flickering = FLICKER_PERIOD; | ||
456 | buttonlight_state = BUTTONLIGHT_MODE_FLICKERING; | ||
457 | } | ||
458 | break; | ||
459 | |||
460 | |||
461 | case BUTTONLIGHT_MODE_FLICKERING: | ||
462 | /* flicker the LEDs for as long as we get triggered */ | ||
463 | if (buttonlight_flickering) | ||
464 | { | ||
465 | /* turn the leds off if they are on */ | ||
466 | if (buttonlight_current) | ||
467 | { | ||
468 | buttonlight_leds = 0x00; | ||
469 | sc606_write(SC606_REG_CONF, backlight_leds); | ||
470 | buttonlight_current = 0; | ||
471 | } | ||
472 | |||
473 | buttonlight_flickering--; | ||
474 | } | ||
475 | else | ||
476 | { | ||
477 | /* is flickering triggered again? */ | ||
478 | if (!buttonlight_trigger_now) | ||
479 | { | ||
480 | /* completed a cycle - no new triggers - go back and wait */ | ||
481 | buttonlight_state = BUTTONLIGHT_MODE_FLICKER; | ||
482 | } | ||
483 | else | ||
484 | { | ||
485 | /* reset flickering */ | ||
486 | buttonlight_trigger_now = 0; | ||
487 | buttonlight_flickering = FLICKER_PERIOD; | ||
488 | |||
489 | /* turn buttonlights on */ | ||
490 | buttonlight_leds = buttonlight_selected; | ||
491 | buttonlight_current = buttonlight_setting; | ||
492 | sc606_write(SC606_REG_CONF, backlight_leds | buttonlight_leds); | ||
493 | } | ||
494 | } | ||
495 | break; | ||
496 | |||
497 | |||
498 | /* Buttonlight mode: SIGNAL / SOLID */ | ||
499 | case BUTTONLIGHT_MODE_SOLID_ENTRY: | ||
500 | /* already on? turn it off */ | ||
501 | if (buttonlight_current) | ||
502 | { | ||
503 | buttonlight_leds = 0x00; | ||
504 | sc606_write(SC606_REG_CONF, backlight_leds); | ||
505 | buttonlight_current = 0; | ||
506 | } | ||
507 | |||
508 | /* set the brightness if not already set */ | ||
509 | /* temporary save for the next mode - then to do settings */ | ||
510 | buttonlight_setting = buttonlight_trigger_brightness; | ||
511 | buttonlight_saved_state = BUTTONLIGHT_MODE_SOLID; | ||
512 | buttonlight_state = BUTTONLIGHT_HELPER_SET; | ||
513 | break; | ||
514 | |||
515 | |||
516 | case BUTTONLIGHT_MODE_SOLID: | ||
517 | /* wait for the foreground to trigger */ | ||
518 | if (buttonlight_trigger_now) | ||
519 | { | ||
520 | /* turn them on if not already on */ | ||
521 | if (0 == buttonlight_current) | ||
522 | { | ||
523 | buttonlight_leds = buttonlight_selected; | ||
524 | buttonlight_current = buttonlight_setting; | ||
525 | sc606_write(SC606_REG_CONF, backlight_leds | buttonlight_leds); | ||
526 | } | ||
527 | |||
528 | /* reset the trigger */ | ||
529 | buttonlight_trigger_now = 0; | ||
530 | } | ||
531 | else | ||
532 | { | ||
533 | if (buttonlight_current) | ||
534 | { | ||
535 | buttonlight_leds = 0x00; | ||
536 | sc606_write(SC606_REG_CONF, backlight_leds); | ||
537 | buttonlight_current = 0; | ||
538 | } | ||
539 | } | ||
540 | break; | ||
541 | |||
542 | |||
543 | /* set the brightness for the buttonlights - takes 2 passes */ | ||
544 | case BUTTONLIGHT_HELPER_SET: | ||
545 | sc606_write(SC606_REG_B, buttonlight_setting-1); | ||
546 | buttonlight_state = BUTTONLIGHT_HELPER_SET_FINAL; | ||
547 | break; | ||
548 | |||
549 | case BUTTONLIGHT_HELPER_SET_FINAL: | ||
550 | sc606_write(SC606_REG_C, buttonlight_setting-1); | ||
551 | buttonlight_current = buttonlight_setting; | ||
552 | buttonlight_state = buttonlight_saved_state; | ||
553 | break; | ||
554 | |||
555 | default: | ||
556 | break; | ||
557 | |||
558 | } | ||
559 | break; | ||
560 | |||
561 | |||
562 | case BACKLIGHT_CONTROL_FADE_ON_FROM_OFF: | ||
563 | backlight_leds = 0x03; | ||
564 | sc606_write(SC606_REG_CONF, 0x03 | buttonlight_leds); | ||
565 | backlight_control = BACKLIGHT_CONTROL_FADE_ON; | ||
566 | break; | ||
567 | |||
568 | |||
569 | case BACKLIGHT_CONTROL_OFF: | ||
570 | backlight_current = 0; | ||
571 | backlight_leds = 0x00; | ||
572 | sc606_write(SC606_REG_CONF, buttonlight_leds); | ||
573 | backlight_control = BACKLIGHT_CONTROL_IDLE; | ||
574 | |||
575 | break; | ||
576 | |||
577 | |||
578 | case BACKLIGHT_CONTROL_ON: | ||
579 | backlight_leds = 0x03; | ||
580 | sc606_write(SC606_REG_CONF, 0x03 | buttonlight_leds); | ||
581 | backlight_current = backlight_brightness; | ||
582 | backlight_control = BACKLIGHT_CONTROL_IDLE; | ||
583 | break; | ||
584 | |||
585 | |||
586 | case BACKLIGHT_CONTROL_SET: | ||
587 | /* The SC606 LED driver can set the brightness in 64 steps */ | ||
588 | sc606_write(SC606_REG_A, backlight_brightness-1); | ||
589 | |||
590 | /* if we were turned off - turn the backlight on */ | ||
591 | if (backlight_current) | ||
592 | { | ||
593 | backlight_current = backlight_brightness; | ||
594 | backlight_control = BACKLIGHT_CONTROL_IDLE; | ||
595 | } | ||
596 | else | ||
597 | { | ||
598 | backlight_control = BACKLIGHT_CONTROL_ON; | ||
599 | } | ||
600 | break; | ||
601 | |||
602 | |||
603 | case BACKLIGHT_CONTROL_FADE_ON: | ||
604 | if (--time_til_fade) return; | ||
605 | |||
606 | /* The SC606 LED driver can set the brightness in 64 steps */ | ||
607 | sc606_write(SC606_REG_A, backlight_current++); | ||
608 | |||
609 | /* have we hit the target? */ | ||
610 | if (backlight_current == backlight_target) | ||
611 | { | ||
612 | backlight_control = BACKLIGHT_CONTROL_IDLE; | ||
613 | } | ||
614 | else | ||
615 | { | ||
616 | time_til_fade = fade_interval; | ||
617 | } | ||
618 | break; | ||
619 | |||
620 | |||
621 | case BACKLIGHT_CONTROL_FADE_OFF: | ||
622 | if (--time_til_fade) return; | ||
623 | |||
624 | /* The SC606 LED driver can set the brightness in 64 steps */ | ||
625 | sc606_write(SC606_REG_A, --backlight_current); | ||
626 | |||
627 | /* have we hit the target? */ | ||
628 | if (backlight_current == backlight_target) | ||
629 | { | ||
630 | if (backlight_current) | ||
631 | { | ||
632 | backlight_control = BACKLIGHT_CONTROL_IDLE; | ||
633 | } | ||
634 | else | ||
635 | { | ||
636 | backlight_control = BACKLIGHT_CONTROL_OFF; | ||
637 | } | ||
638 | |||
639 | } | ||
640 | else | ||
641 | { | ||
642 | time_til_fade = fade_interval; | ||
643 | } | ||
644 | break; | ||
645 | } | ||
646 | |||
647 | if(backlight_current) | ||
648 | lcd_enable(true); | ||
649 | else | ||
650 | lcd_enable(false); | ||
651 | } | ||
652 | |||
653 | |||
654 | |||
655 | |||
656 | |||
657 | void __backlight_dim(bool dim_now) | ||
658 | { | ||
659 | unsigned short target; | ||
660 | |||
661 | /* dont let the interrupt tick happen */ | ||
662 | backlight_control = BACKLIGHT_CONTROL_IDLE; | ||
663 | |||
664 | target = (dim_now == true) ? 0 : backlight_brightness; | ||
665 | |||
666 | /* only try and fade if the target is different */ | ||
667 | if (backlight_current != target) | ||
668 | { | ||
669 | backlight_target = target; | ||
670 | |||
671 | if (backlight_current > backlight_target) | ||
672 | { | ||
673 | time_til_fade = fade_interval = 4; | ||
674 | backlight_control = BACKLIGHT_CONTROL_FADE_OFF; | ||
675 | } | ||
676 | else | ||
677 | { | ||
678 | time_til_fade = fade_interval = 1; | ||
679 | if (backlight_current) | ||
680 | { | ||
681 | backlight_control = BACKLIGHT_CONTROL_FADE_ON; | ||
682 | } | ||
683 | else | ||
684 | { | ||
685 | backlight_control = BACKLIGHT_CONTROL_FADE_ON_FROM_OFF; | ||
686 | } | ||
687 | } | ||
688 | } | ||
689 | |||
690 | } | ||
691 | |||
692 | |||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/backlight-target.h b/firmware/target/arm/s3c2440/gigabeat-fx/backlight-target.h new file mode 100644 index 0000000000..5f92cee935 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/backlight-target.h | |||
@@ -0,0 +1,87 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006 by Linus Nielsen Feltzing | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #ifndef BACKLIGHT_TARGET_H | ||
20 | #define BACKLIGHT_TARGET_H | ||
21 | |||
22 | |||
23 | /* select the led */ | ||
24 | enum buttonlight_selection | ||
25 | { | ||
26 | /* all leds */ | ||
27 | BUTTONLIGHT_LED_ALL, | ||
28 | |||
29 | /* only the menu/power led (two buttons for one LED) */ | ||
30 | BUTTONLIGHT_LED_MENU | ||
31 | }; | ||
32 | |||
33 | |||
34 | /* Use these to set the buttonlight mode */ | ||
35 | enum buttonlight_mode | ||
36 | { | ||
37 | /* ON follows the setting */ | ||
38 | BUTTONLIGHT_ON, | ||
39 | |||
40 | /* buttonlights always off */ | ||
41 | BUTTONLIGHT_OFF, | ||
42 | |||
43 | /* buttonlights always on but set at lowest brightness */ | ||
44 | BUTTONLIGHT_FAINT, | ||
45 | |||
46 | /* buttonlights flicker when triggered - continues to flicker | ||
47 | * even if the flicker is still asserted. | ||
48 | */ | ||
49 | BUTTONLIGHT_FLICKER, | ||
50 | |||
51 | /* buttonlights solid for as long as triggered */ | ||
52 | BUTTONLIGHT_SIGNAL, | ||
53 | |||
54 | /* buttonlights follow backlight */ | ||
55 | BUTTONLIGHT_FOLLOW, | ||
56 | |||
57 | /* buttonlights show battery charging */ | ||
58 | BUTTONLIGHT_CHARGING, | ||
59 | }; | ||
60 | |||
61 | |||
62 | /* Call this to flicker or signal the button lights. Only is effective for | ||
63 | * modes that take a trigger input. | ||
64 | */ | ||
65 | void __buttonlight_trigger(void); | ||
66 | |||
67 | |||
68 | /* select which led to use on the button lights. Other combinations are | ||
69 | * possible, but don't look very good. | ||
70 | */ | ||
71 | |||
72 | /* map the mode from the command into the state machine entries */ | ||
73 | /* See enum buttonlight_mode for available functions */ | ||
74 | void __buttonlight_mode(enum buttonlight_mode mode, | ||
75 | enum buttonlight_selection selection, | ||
76 | unsigned short brightness); | ||
77 | |||
78 | |||
79 | bool __backlight_init(void); | ||
80 | void __backlight_on(void); | ||
81 | void __backlight_off(void); | ||
82 | void __backlight_set_brightness(int val); | ||
83 | |||
84 | /* true: backlight fades off - false: backlight fades on */ | ||
85 | void __backlight_dim(bool dim); | ||
86 | |||
87 | #endif | ||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/button-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/button-meg-fx.c new file mode 100644 index 0000000000..71d45c385c --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/button-meg-fx.c | |||
@@ -0,0 +1,157 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006 by Linus Nielsen Feltzing | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #include <stdlib.h> | ||
21 | #include "config.h" | ||
22 | #include "cpu.h" | ||
23 | #include "system.h" | ||
24 | #include "button.h" | ||
25 | #include "kernel.h" | ||
26 | #include "backlight.h" | ||
27 | #include "adc.h" | ||
28 | #include "system.h" | ||
29 | #include "backlight-target.h" | ||
30 | |||
31 | static bool headphones_detect; | ||
32 | static bool hold_button = false; | ||
33 | |||
34 | static int const remote_buttons[] = | ||
35 | { | ||
36 | BUTTON_NONE, /* Headphones connected - remote disconnected */ | ||
37 | BUTTON_SELECT, | ||
38 | BUTTON_MENU, /* could be changed to BUTTON_A */ | ||
39 | BUTTON_LEFT, | ||
40 | BUTTON_RIGHT, | ||
41 | BUTTON_UP, /* could be changed to BUTTON_VOL_UP */ | ||
42 | BUTTON_DOWN, /* could be changed to BUTTON_VOL_DOWN */ | ||
43 | BUTTON_NONE, /* Remote control attached - no buttons pressed */ | ||
44 | BUTTON_NONE, /* Nothing in the headphone socket */ | ||
45 | }; | ||
46 | |||
47 | |||
48 | |||
49 | |||
50 | |||
51 | void button_init_device(void) | ||
52 | { | ||
53 | /* Power, Remote Play & Hold switch */ | ||
54 | } | ||
55 | |||
56 | |||
57 | |||
58 | inline bool button_hold(void) | ||
59 | { | ||
60 | return (GPGDAT & (1 << 15)); | ||
61 | } | ||
62 | |||
63 | |||
64 | |||
65 | int button_read_device(void) | ||
66 | { | ||
67 | int touchpad; | ||
68 | int buttons; | ||
69 | static int lastbutton; | ||
70 | unsigned short remote_adc; | ||
71 | int btn = BUTTON_NONE; | ||
72 | bool hold_button_old; | ||
73 | |||
74 | /* normal buttons */ | ||
75 | hold_button_old = hold_button; | ||
76 | hold_button = button_hold(); | ||
77 | |||
78 | #ifndef BOOTLOADER | ||
79 | /* give BL notice if HB state chaged */ | ||
80 | if (hold_button != hold_button_old) | ||
81 | backlight_hold_changed(hold_button); | ||
82 | #endif | ||
83 | |||
84 | /* See header for ADC values when remote control buttons are pressed */ | ||
85 | /* Only one button can be sensed at a time on the remote. */ | ||
86 | /* Need to filter the remote button because the ADC is so fast */ | ||
87 | remote_adc = adc_read(ADC_HPREMOTE); | ||
88 | btn = remote_buttons[(remote_adc + 64) / 128]; | ||
89 | if (btn != lastbutton) | ||
90 | { | ||
91 | /* if the buttons dont agree twice in a row, then its none */ | ||
92 | lastbutton = btn; | ||
93 | btn = BUTTON_NONE; | ||
94 | } | ||
95 | |||
96 | /* Check for hold first - exit if asserted with no button pressed */ | ||
97 | if (hold_button) | ||
98 | return btn; | ||
99 | |||
100 | /* the side buttons - Check before doing all of the work on each bit */ | ||
101 | buttons = GPGDAT & 0x1F; | ||
102 | if (buttons) | ||
103 | { | ||
104 | if (buttons & (1 << 0)) | ||
105 | btn |= BUTTON_POWER; | ||
106 | |||
107 | if (buttons & (1 << 1)) | ||
108 | btn |= BUTTON_MENU; | ||
109 | |||
110 | if (buttons & (1 << 2)) | ||
111 | btn |= BUTTON_VOL_UP; | ||
112 | |||
113 | if (buttons & (1 << 3)) | ||
114 | btn |= BUTTON_VOL_DOWN; | ||
115 | |||
116 | if (buttons & (1 << 4)) | ||
117 | btn |= BUTTON_A; | ||
118 | } | ||
119 | |||
120 | /* the touchpad */ | ||
121 | touchpad = GPJDAT & 0x10C9; | ||
122 | if (touchpad) | ||
123 | { | ||
124 | if (touchpad & (1 << 0)) | ||
125 | btn |= BUTTON_UP; | ||
126 | |||
127 | if (touchpad & (1 << 12)) | ||
128 | btn |= BUTTON_RIGHT; | ||
129 | |||
130 | if (touchpad & (1 << 6)) | ||
131 | btn |= BUTTON_DOWN; | ||
132 | |||
133 | if (touchpad & (1 << 7)) | ||
134 | btn |= BUTTON_LEFT; | ||
135 | |||
136 | if (touchpad & (1 << 3)) | ||
137 | btn |= BUTTON_SELECT; | ||
138 | } | ||
139 | |||
140 | return btn; | ||
141 | } | ||
142 | |||
143 | |||
144 | |||
145 | bool headphones_inserted(void) | ||
146 | { | ||
147 | unsigned short remote_adc = adc_read(ADC_HPREMOTE); | ||
148 | if (remote_adc != ADC_READ_ERROR) | ||
149 | { | ||
150 | /* If there is nothing in the headphone socket, the ADC reads high */ | ||
151 | if (remote_adc < 940) | ||
152 | headphones_detect = true; | ||
153 | else | ||
154 | headphones_detect = false; | ||
155 | } | ||
156 | return headphones_detect; | ||
157 | } | ||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/button-target.h b/firmware/target/arm/s3c2440/gigabeat-fx/button-target.h new file mode 100644 index 0000000000..ab68e8050f --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/button-target.h | |||
@@ -0,0 +1,89 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006 by Linus Nielsen Feltzing | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #ifndef _BUTTON_TARGET_H_ | ||
20 | #define _BUTTON_TARGET_H_ | ||
21 | |||
22 | #include <stdbool.h> | ||
23 | #include "config.h" | ||
24 | |||
25 | #define HAS_BUTTON_HOLD | ||
26 | |||
27 | bool button_hold(void); | ||
28 | void button_init_device(void); | ||
29 | int button_read_device(void); | ||
30 | |||
31 | /* Toshiba Gigabeat specific button codes */ | ||
32 | |||
33 | #define BUTTON_POWER 0x00000001 | ||
34 | #define BUTTON_MENU 0x00000002 | ||
35 | |||
36 | #define BUTTON_LEFT 0x00000004 | ||
37 | #define BUTTON_RIGHT 0x00000008 | ||
38 | #define BUTTON_UP 0x00000010 | ||
39 | #define BUTTON_DOWN 0x00000020 | ||
40 | |||
41 | #define BUTTON_VOL_UP 0x00000040 | ||
42 | #define BUTTON_VOL_DOWN 0x00000080 | ||
43 | |||
44 | #define BUTTON_SELECT 0x00000100 | ||
45 | #define BUTTON_A 0x00000200 | ||
46 | |||
47 | |||
48 | /* Toshiba Gigabeat specific remote button ADC values */ | ||
49 | /* The remote control uses ADC 1 to emulate button pushes | ||
50 | Reading (approx) Button HP plugged in? Remote plugged in? | ||
51 | 0 N/A Yes No | ||
52 | 125 Play/Pause Cant tell Yes | ||
53 | 241 Speaker+ Cant tell Yes | ||
54 | 369 Rewind Cant tell Yes | ||
55 | 492 Fast Fwd Cant tell Yes | ||
56 | 616 Vol + Cant tell Yes | ||
57 | 742 Vol - Cant tell Yes | ||
58 | 864 None Cant tell Yes | ||
59 | 1023 N/A No No | ||
60 | */ | ||
61 | |||
62 | /* | ||
63 | Notes: | ||
64 | |||
65 | Buttons on the remote are translated into equivalent button presses just | ||
66 | as if you were pressing them on the Gigabeat itself. | ||
67 | |||
68 | We cannot tell if the hold is asserted on the remote. The Hold function on | ||
69 | the remote is to block the output of the buttons changing. | ||
70 | |||
71 | Only one button can be sensed at a time. If another is pressed, the button | ||
72 | with the lowest reading is dominant. So, if Rewind and Vol + are pressed | ||
73 | at the same time, Rewind value is the one that is read. | ||
74 | */ | ||
75 | |||
76 | |||
77 | |||
78 | |||
79 | #define BUTTON_MAIN (BUTTON_POWER|BUTTON_MENU|BUTTON_LEFT|BUTTON_RIGHT\ | ||
80 | |BUTTON_UP|BUTTON_DOWN|BUTTON_VOL_UP|BUTTON_VOL_DOWN\ | ||
81 | |BUTTON_SELECT|BUTTON_A) | ||
82 | |||
83 | |||
84 | #define BUTTON_REMOTE 0 | ||
85 | |||
86 | #define POWEROFF_BUTTON BUTTON_POWER | ||
87 | #define POWEROFF_COUNT 10 | ||
88 | |||
89 | #endif /* _BUTTON_TARGET_H_ */ | ||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/dma_start.c b/firmware/target/arm/s3c2440/gigabeat-fx/dma_start.c new file mode 100644 index 0000000000..c1ab6c15cb --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/dma_start.c | |||
@@ -0,0 +1,8 @@ | |||
1 | #include <sys/types.h> | ||
2 | |||
3 | void dma_start(const void* addr, size_t size) { | ||
4 | (void) addr; | ||
5 | (void) size; | ||
6 | //TODO: | ||
7 | } | ||
8 | |||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c new file mode 100644 index 0000000000..670d6cd04c --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c | |||
@@ -0,0 +1,134 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006 by Linus Nielsen Feltzing | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #include "config.h" | ||
20 | #include "cpu.h" | ||
21 | #include <stdbool.h> | ||
22 | #include "kernel.h" | ||
23 | #include "system.h" | ||
24 | #include "logf.h" | ||
25 | #include "debug.h" | ||
26 | #include "string.h" | ||
27 | #include "generic_i2c.h" | ||
28 | |||
29 | static void i2c_sda_output(void) | ||
30 | { | ||
31 | GPECON |= (1 << 30); | ||
32 | } | ||
33 | |||
34 | static void i2c_sda_input(void) | ||
35 | { | ||
36 | GPECON &= ~(3 << 30); | ||
37 | } | ||
38 | |||
39 | static void i2c_sda_lo(void) | ||
40 | { | ||
41 | GPEDAT &= ~(1 << 15); | ||
42 | } | ||
43 | |||
44 | static void i2c_sda_hi(void) | ||
45 | { | ||
46 | GPEDAT |= (1 << 15); | ||
47 | } | ||
48 | |||
49 | static int i2c_sda(void) | ||
50 | { | ||
51 | return GPEDAT & (1 << 15); | ||
52 | } | ||
53 | |||
54 | static void i2c_scl_output(void) | ||
55 | { | ||
56 | GPECON |= (1 << 28); | ||
57 | } | ||
58 | |||
59 | static void i2c_scl_input(void) | ||
60 | { | ||
61 | GPECON &= ~(3 << 28); | ||
62 | } | ||
63 | |||
64 | static void i2c_scl_lo(void) | ||
65 | { | ||
66 | GPEDAT &= ~(1 << 14); | ||
67 | } | ||
68 | |||
69 | static int i2c_scl(void) | ||
70 | { | ||
71 | return GPEDAT & (1 << 14); | ||
72 | } | ||
73 | |||
74 | static void i2c_scl_hi(void) | ||
75 | { | ||
76 | i2c_scl_input(); | ||
77 | while(!i2c_scl()); | ||
78 | GPEDAT |= (1 << 14); | ||
79 | i2c_scl_output(); | ||
80 | } | ||
81 | |||
82 | |||
83 | |||
84 | static void i2c_delay(void) | ||
85 | { | ||
86 | unsigned _x; | ||
87 | |||
88 | /* The i2c can clock at 500KHz: 2uS period -> 1uS half period */ | ||
89 | /* about 30 cycles overhead + X * 7 */ | ||
90 | /* 300MHz: 1000nS @3.36nS/cyc = 297cyc: X = 38*/ | ||
91 | /* 100MHz: 1000nS @10nS/cyc = 100cyc : X = 10 */ | ||
92 | for (_x = 38; _x; _x--) | ||
93 | { | ||
94 | /* burn CPU cycles */ | ||
95 | /* gcc makes it an inc loop - check with objdump for asm timing */ | ||
96 | } | ||
97 | } | ||
98 | |||
99 | |||
100 | |||
101 | struct i2c_interface s3c2440_i2c = { | ||
102 | 0x34, /* Address */ | ||
103 | |||
104 | /* Bit-banged interface definitions */ | ||
105 | i2c_scl_hi, /* Drive SCL high, might sleep on clk stretch */ | ||
106 | i2c_scl_lo, /* Drive SCL low */ | ||
107 | i2c_sda_hi, /* Drive SDA high */ | ||
108 | i2c_sda_lo, /* Drive SDA low */ | ||
109 | i2c_sda_input, /* Set SDA as input */ | ||
110 | i2c_sda_output, /* Set SDA as output */ | ||
111 | i2c_scl_input, /* Set SCL as input */ | ||
112 | i2c_scl_output, /* Set SCL as output */ | ||
113 | i2c_scl, /* Read SCL, returns 0 or nonzero */ | ||
114 | i2c_sda, /* Read SDA, returns 0 or nonzero */ | ||
115 | |||
116 | i2c_delay, /* START SDA hold time (tHD:SDA) */ | ||
117 | i2c_delay, /* SDA hold time (tHD:DAT) */ | ||
118 | i2c_delay, /* SDA setup time (tSU:DAT) */ | ||
119 | i2c_delay, /* STOP setup time (tSU:STO) */ | ||
120 | i2c_delay, /* Rep. START setup time (tSU:STA) */ | ||
121 | i2c_delay, /* SCL high period (tHIGH) */ | ||
122 | }; | ||
123 | |||
124 | void i2c_init(void) | ||
125 | { | ||
126 | /* Set GPE15 (SDA) and GPE14 (SCL) to 1 */ | ||
127 | GPECON = (GPECON & ~(0xF<<28)) | 5<<28; | ||
128 | i2c_add_node(&s3c2440_i2c); | ||
129 | } | ||
130 | |||
131 | void i2c_send(int bus_address, int reg_address, const unsigned char buf) | ||
132 | { | ||
133 | i2c_write_data(bus_address, reg_address, &buf, 1); | ||
134 | } | ||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.h b/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.h new file mode 100644 index 0000000000..cf69230487 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.h | |||
@@ -0,0 +1,22 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006 by Linus Nielsen Feltzing | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | /* chip-specific i2c functions */ | ||
21 | |||
22 | void i2c_send(int bus_address, int reg_address, const unsigned char buf); | ||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c new file mode 100644 index 0000000000..9df90a2344 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c | |||
@@ -0,0 +1,25 @@ | |||
1 | #include "kernel.h" | ||
2 | #include "thread.h" | ||
3 | |||
4 | #include <stdio.h> | ||
5 | #include "lcd.h" | ||
6 | |||
7 | extern void (*tick_funcs[MAX_NUM_TICK_TASKS])(void); | ||
8 | |||
9 | void timer4(void) { | ||
10 | int i; | ||
11 | /* Run through the list of tick tasks */ | ||
12 | for(i = 0; i < MAX_NUM_TICK_TASKS; i++) | ||
13 | { | ||
14 | if(tick_funcs[i]) | ||
15 | { | ||
16 | tick_funcs[i](); | ||
17 | } | ||
18 | } | ||
19 | |||
20 | current_tick++; | ||
21 | |||
22 | /* following needs to be fixed. */ | ||
23 | /*wake_up_thread();*/ | ||
24 | } | ||
25 | |||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/lcd-as-meg-fx.S b/firmware/target/arm/s3c2440/gigabeat-fx/lcd-as-meg-fx.S new file mode 100644 index 0000000000..d431c95f29 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/lcd-as-meg-fx.S | |||
@@ -0,0 +1,222 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Michael Sevakis | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #include "config.h" | ||
21 | #include "cpu.h" | ||
22 | |||
23 | /**************************************************************************** | ||
24 | * void lcd_write_yuv_420_lines(fb_data *dst, | ||
25 | * unsigned char chroma_buf[LCD_HEIGHT/2*3], | ||
26 | unsigned char const * const src[3], | ||
27 | * int width, | ||
28 | * int stride); | ||
29 | * | ||
30 | * |R| |1.000000 -0.000001 1.402000| |Y'| | ||
31 | * |G| = |1.000000 -0.334136 -0.714136| |Pb| | ||
32 | * |B| |1.000000 1.772000 0.000000| |Pr| | ||
33 | * Scaled, normalized, rounded and tweaked to yield RGB 565: | ||
34 | * |R| |74 0 101| |Y' - 16| >> 9 | ||
35 | * |G| = |74 -24 -51| |Cb - 128| >> 8 | ||
36 | * |B| |74 128 0| |Cr - 128| >> 9 | ||
37 | */ | ||
38 | .section .icode, "ax", %progbits | ||
39 | .align 2 | ||
40 | .global lcd_write_yuv420_lines | ||
41 | .type lcd_write_yuv420_lines, %function | ||
42 | lcd_write_yuv420_lines: | ||
43 | @ r0 = dst | ||
44 | @ r1 = chroma_buf | ||
45 | @ r2 = yuv_src | ||
46 | @ r3 = width | ||
47 | @ [sp] = stride | ||
48 | stmdb sp!, { r4-r12, lr } @ save non-scratch | ||
49 | stmdb sp!, { r0, r3 } @ save dst and width | ||
50 | mov r14, #74 @ r14 = Y factor | ||
51 | ldmia r2, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p | ||
52 | @ r5 = yuv_src[1] = Cb_p | ||
53 | @ r6 = yuv_src[2] = Cr_p | ||
54 | 10: @ loop line 1 @ | ||
55 | ldrb r2, [r4], #1 @ r2 = *Y'_p++; | ||
56 | ldrb r8, [r5], #1 @ r8 = *Cb_p++; | ||
57 | ldrb r11, [r6], #1 @ r11 = *Cr_p++; | ||
58 | @ | ||
59 | @ compute Y | ||
60 | sub r2, r2, #16 @ r7 = Y = (Y' - 16)*74 | ||
61 | mul r7, r2, r14 @ | ||
62 | @ | ||
63 | sub r8, r8, #128 @ Cb -= 128 | ||
64 | sub r11, r11, #128 @ Cr -= 128 | ||
65 | @ | ||
66 | mvn r2, #24 @ compute guv | ||
67 | mul r10, r2, r8 @ r10 = Cb*-24 | ||
68 | mvn r2, #51 @ | ||
69 | mla r10, r2, r11, r10 @ r10 = r10 + Cr*-51 | ||
70 | @ | ||
71 | mov r2, #101 @ compute rv | ||
72 | mul r9, r11, r2 @ r9 = rv = Cr*101 | ||
73 | @ | ||
74 | @ store chromas in line buffer | ||
75 | add r8, r8, #2 @ bu = (Cb + 2) >> 2 | ||
76 | mov r8, r8, asr #2 @ | ||
77 | strb r8, [r1], #1 @ | ||
78 | add r9, r9, #256 @ rv = (Cr + 256) >> 9 | ||
79 | mov r9, r9, asr #9 @ | ||
80 | strb r9, [r1], #1 @ | ||
81 | mov r10, r10, asr #8 @ guv >>= 8 | ||
82 | strb r10, [r1], #1 @ | ||
83 | @ compute R, G, and B | ||
84 | add r2, r8, r7, asr #9 @ r2 = b = (Y >> 9) + bu | ||
85 | add r11, r9, r7, asr #9 @ r11 = r = (Y >> 9) + rv | ||
86 | add r7, r10, r7, asr #8 @ r7 = g = (Y >> 8) + guv | ||
87 | @ | ||
88 | orr r12, r2, r11 @ check if clamping is needed... | ||
89 | orr r12, r12, r7, asr #1 @ ...at all | ||
90 | cmp r12, #31 @ | ||
91 | bls 15f @ no clamp @ | ||
92 | mov r12, #31 @ | ||
93 | cmp r12, r2 @ clamp b | ||
94 | andlo r2, r12, r2, asr #31 @ | ||
95 | eorlo r2, r2, r12 @ | ||
96 | cmp r12, r11 @ clamp r | ||
97 | andlo r11, r12, r11, asr #31 @ | ||
98 | eorlo r11, r11, r12 @ | ||
99 | cmp r12, r7, asr #1 @ clamp g | ||
100 | andlo r7, r12, r7, asr #31 @ | ||
101 | eorlo r7, r7, r12 @ | ||
102 | orrlo r7, r7, r7, asl #1 @ | ||
103 | 15: @ no clamp @ | ||
104 | @ | ||
105 | orr r12, r2, r7, lsl #5 @ r4 |= (g << 5) | ||
106 | ldrb r2, [r4], #1 @ r2 = Y' = *Y'_p++ | ||
107 | orr r12, r12, r11, lsl #11 @ r4 = b | (r << 11) | ||
108 | strh r12, [r0], #240 @ store pixel | ||
109 | @ | ||
110 | sub r2, r2, #16 @ r7 = Y = (Y' - 16)*74 | ||
111 | mul r7, r2, r14 @ next Y | ||
112 | @ compute R, G, and B | ||
113 | add r2, r8, r7, asr #9 @ r2 = b = (Y >> 9) + bu | ||
114 | add r11, r9, r7, asr #9 @ r11 = r = (Y >> 9) + rv | ||
115 | add r7, r10, r7, asr #8 @ r7 = g = (Y >> 8) + guv | ||
116 | @ | ||
117 | orr r12, r2, r11 @ check if clamping is needed... | ||
118 | orr r12, r12, r7, asr #1 @ ...at all | ||
119 | cmp r12, #31 @ | ||
120 | bls 15f @ no clamp @ | ||
121 | mov r12, #31 @ | ||
122 | cmp r12, r2 @ clamp b | ||
123 | andlo r2, r12, r2, asr #31 @ | ||
124 | eorlo r2, r2, r12 @ | ||
125 | cmp r12, r11 @ clamp r | ||
126 | andlo r11, r12, r11, asr #31 @ | ||
127 | eorlo r11, r11, r12 @ | ||
128 | cmp r12, r7, asr #1 @ clamp g | ||
129 | andlo r7, r12, r7, asr #31 @ | ||
130 | eorlo r7, r7, r12 @ | ||
131 | orrlo r7, r7, r7, asl #1 @ | ||
132 | 15: @ no clamp @ | ||
133 | @ | ||
134 | orr r12, r2, r11, lsl #11 @ r4 = b | (r << 11) | ||
135 | orr r12, r12, r7, lsl #5 @ r4 |= (g << 5) | ||
136 | strh r12, [r0, #240]! @ store pixel | ||
137 | add r0, r0, #2*240 @ | ||
138 | @ | ||
139 | subs r3, r3, #2 @ | ||
140 | bgt 10b @ loop line 1 @ | ||
141 | @ do second line | ||
142 | @ | ||
143 | ldmia sp!, { r0, r3 } @ pop dst and width | ||
144 | sub r0, r0, #2 @ set dst to start of next line | ||
145 | sub r1, r1, r3, asl #1 @ rewind chroma pointer... | ||
146 | ldr r2, [sp, #40] @ r2 = stride | ||
147 | add r1, r1, r3, asr #1 @ ... (r1 -= width/2*3) | ||
148 | @ move sources to start of next line | ||
149 | sub r2, r2, r3 @ r2 = skip = stride - width | ||
150 | add r4, r4, r2 @ r4 = Y'_p + skip | ||
151 | @ | ||
152 | 20: @ loop line 2 @ | ||
153 | ldrb r2, [r4], #1 @ r7 = Y' = *Y'_p++ | ||
154 | ldrsb r8, [r1], #1 @ reload saved chromas | ||
155 | ldrsb r9, [r1], #1 @ | ||
156 | ldrsb r10, [r1], #1 @ | ||
157 | @ | ||
158 | sub r2, r2, #16 @ r2 = Y = (Y' - 16)*74 | ||
159 | mul r7, r2, r14 @ | ||
160 | @ compute R, G, and B | ||
161 | add r2, r8, r7, asr #9 @ r2 = b = (Y >> 9) + bu | ||
162 | add r11, r9, r7, asr #9 @ r11 = r = (Y >> 9) + rv | ||
163 | add r7, r10, r7, asr #8 @ r7 = g = (Y >> 8) + guv | ||
164 | @ | ||
165 | orr r12, r2, r11 @ check if clamping is needed... | ||
166 | orr r12, r12, r7, asr #1 @ ...at all | ||
167 | cmp r12, #31 @ | ||
168 | bls 25f @ no clamp @ | ||
169 | mov r12, #31 @ | ||
170 | cmp r12, r2 @ clamp b | ||
171 | andlo r2, r12, r2, asr #31 @ | ||
172 | eorlo r2, r2, r12 @ | ||
173 | cmp r12, r11 @ clamp r | ||
174 | andlo r11, r12, r11, asr #31 @ | ||
175 | eorlo r11, r11, r12 @ | ||
176 | cmp r12, r7, asr #1 @ clamp g | ||
177 | andlo r7, r12, r7, asr #31 @ | ||
178 | eorlo r7, r7, r12 @ | ||
179 | orrlo r7, r7, r7, asl #1 @ | ||
180 | 25: @ no clamp @ | ||
181 | @ | ||
182 | orr r12, r2, r11, lsl #11 @ r4 = b | (r << 11) | ||
183 | ldrb r2, [r4], #1 @ r2 = Y' = *Y'_p++ | ||
184 | orr r12, r12, r7, lsl #5 @ r4 |= (g << 5) | ||
185 | strh r12, [r0], #240 @ store pixel | ||
186 | @ | ||
187 | @ do second pixel | ||
188 | @ | ||
189 | sub r2, r2, #16 @ r2 = Y = (Y' - 16)*74 | ||
190 | mul r7, r2, r14 @ | ||
191 | @ compute R, G, and B | ||
192 | add r2, r8, r7, asr #9 @ r2 = b = (Y >> 9) + bu | ||
193 | add r11, r9, r7, asr #9 @ r11 = r = (Y >> 9) + rv | ||
194 | add r7, r10, r7, asr #8 @ r7 = g = (Y >> 8) + guv | ||
195 | @ | ||
196 | orr r12, r2, r11 @ check if clamping is needed... | ||
197 | orr r12, r12, r7, asr #1 @ ...at all | ||
198 | cmp r12, #31 @ | ||
199 | bls 25f @ no clamp @ | ||
200 | mov r12, #31 @ | ||
201 | cmp r12, r2 @ clamp b | ||
202 | andlo r2, r12, r2, asr #31 @ | ||
203 | eorlo r2, r2, r12 @ | ||
204 | cmp r12, r11 @ clamp r | ||
205 | andlo r11, r12, r11, asr #31 @ | ||
206 | eorlo r11, r11, r12 @ | ||
207 | cmp r12, r7, asr #1 @ clamp g | ||
208 | andlo r7, r12, r7, asr #31 @ | ||
209 | eorlo r7, r7, r12 @ | ||
210 | orrlo r7, r7, r7, asl #1 @ | ||
211 | 25: @ no clamp @ | ||
212 | @ | ||
213 | orr r12, r2, r11, lsl #11 @ r4 = b | (r << 11) | ||
214 | orr r12, r12, r7, lsl #5 @ r4 |= (g << 5) | ||
215 | strh r12, [r0, #240]! @ store pixel | ||
216 | add r0, r0, #2*240 @ | ||
217 | @ | ||
218 | subs r3, r3, #2 @ | ||
219 | bgt 20b @ loop line 2 @ | ||
220 | @ | ||
221 | ldmia sp!, { r4-r12, pc } @ restore registers and return | ||
222 | .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines | ||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/lcd-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/lcd-meg-fx.c new file mode 100644 index 0000000000..1bb68f9686 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/lcd-meg-fx.c | |||
@@ -0,0 +1,367 @@ | |||
1 | #include "config.h" | ||
2 | #include <string.h> | ||
3 | #include "cpu.h" | ||
4 | #include "lcd.h" | ||
5 | #include "kernel.h" | ||
6 | #include "system.h" | ||
7 | #include "mmu-meg-fx.h" | ||
8 | #include <stdlib.h> | ||
9 | #include "memory.h" | ||
10 | #include "lcd-target.h" | ||
11 | #include "font.h" | ||
12 | #include "rbunicode.h" | ||
13 | #include "bidi.h" | ||
14 | |||
15 | #define LCDADDR(x, y) (&lcd_framebuffer[(y)][(x)]) | ||
16 | /* | ||
17 | ** We prepare foreground and background fills ahead of time - DMA fills in 16 byte groups | ||
18 | */ | ||
19 | unsigned long fg_pattern_blit[4]; | ||
20 | unsigned long bg_pattern_blit[4]; | ||
21 | |||
22 | volatile bool use_dma_blit = false; | ||
23 | static volatile bool lcd_on = true; | ||
24 | volatile bool lcd_poweroff = false; | ||
25 | /* | ||
26 | ** These are imported from lcd-16bit.c | ||
27 | */ | ||
28 | extern unsigned fg_pattern; | ||
29 | extern unsigned bg_pattern; | ||
30 | |||
31 | bool lcd_enabled() | ||
32 | { | ||
33 | return lcd_on; | ||
34 | } | ||
35 | |||
36 | unsigned int LCDBANK(unsigned int address) | ||
37 | { | ||
38 | return ((address >> 22) & 0xff); | ||
39 | } | ||
40 | |||
41 | unsigned int LCDBASEU(unsigned int address) | ||
42 | { | ||
43 | return (address & ((1 << 22)-1)) >> 1; | ||
44 | } | ||
45 | |||
46 | unsigned int LCDBASEL(unsigned int address) | ||
47 | { | ||
48 | address += 320*240*2; | ||
49 | return (address & ((1 << 22)-1)) >> 1; | ||
50 | } | ||
51 | |||
52 | |||
53 | /* LCD init */ | ||
54 | void lcd_init_device(void) | ||
55 | { | ||
56 | LCDSADDR1 = (LCDBANK((unsigned)FRAME) << 21) | (LCDBASEU((unsigned)FRAME)); | ||
57 | LCDSADDR2 = LCDBASEL((unsigned)FRAME); | ||
58 | LCDSADDR3 = 0x000000F0; | ||
59 | |||
60 | LCDCON5 |= 1 << 11; /* Switch from 555I mode to 565 mode */ | ||
61 | |||
62 | #if !defined(BOOTLOADER) | ||
63 | memset16(fg_pattern_blit, fg_pattern, sizeof(fg_pattern_blit)/2); | ||
64 | memset16(bg_pattern_blit, bg_pattern, sizeof(bg_pattern_blit)/2); | ||
65 | clean_dcache_range((void *)fg_pattern_blit, sizeof(fg_pattern_blit)); | ||
66 | clean_dcache_range((void *)bg_pattern_blit, sizeof(bg_pattern_blit)); | ||
67 | use_dma_blit = true; | ||
68 | lcd_poweroff = false; | ||
69 | #endif | ||
70 | } | ||
71 | |||
72 | /* Update a fraction of the display. */ | ||
73 | void lcd_update_rect(int x, int y, int width, int height) | ||
74 | { | ||
75 | (void)x; | ||
76 | (void)width; | ||
77 | (void)y; | ||
78 | (void)height; | ||
79 | |||
80 | if(!lcd_on) | ||
81 | { | ||
82 | sleep(200); | ||
83 | return; | ||
84 | } | ||
85 | if (use_dma_blit) | ||
86 | { | ||
87 | /* Wait for this controller to stop pending transfer */ | ||
88 | while((DSTAT1 & 0x000fffff)) | ||
89 | CLKCON |= (1 << 2); /* set IDLE bit */ | ||
90 | |||
91 | /* Flush DCache */ | ||
92 | invalidate_dcache_range((void *)(((int) &lcd_framebuffer[0][0])+(y * sizeof(fb_data) * LCD_WIDTH)), (height * sizeof(fb_data) * LCD_WIDTH)); | ||
93 | |||
94 | /* set DMA dest */ | ||
95 | DIDST1 = ((int) FRAME) + (y * sizeof(fb_data) * LCD_WIDTH); | ||
96 | |||
97 | /* FRAME on AHB buf, increment */ | ||
98 | DIDSTC1 = 0; | ||
99 | /* Handshake on AHB, Burst transfer, Whole service, Don't reload, transfer 32-bits */ | ||
100 | DCON1 = ((1<<30) | (1<<28) | (1<<27) | (1<<22) | (2<<20)) | ((height * sizeof(fb_data) * LCD_WIDTH) >> 4); | ||
101 | |||
102 | /* set DMA source */ | ||
103 | DISRC1 = ((int) &lcd_framebuffer[0][0]) + (y * sizeof(fb_data) * LCD_WIDTH) + 0x30000000; | ||
104 | /* memory is on AHB bus, increment addresses */ | ||
105 | DISRCC1 = 0x00; | ||
106 | |||
107 | /* Activate the channel */ | ||
108 | DMASKTRIG1 = 0x2; | ||
109 | |||
110 | /* Start DMA */ | ||
111 | DMASKTRIG1 |= 0x1; | ||
112 | |||
113 | /* Wait for transfer to complete */ | ||
114 | while((DSTAT1 & 0x000fffff)) | ||
115 | CLKCON |= (1 << 2); /* set IDLE bit */ | ||
116 | } | ||
117 | else | ||
118 | memcpy(((char*)FRAME) + (y * sizeof(fb_data) * LCD_WIDTH), ((char *)&lcd_framebuffer) + (y * sizeof(fb_data) * LCD_WIDTH), ((height * sizeof(fb_data) * LCD_WIDTH))); | ||
119 | } | ||
120 | |||
121 | |||
122 | void lcd_enable(bool state) | ||
123 | { | ||
124 | if(!lcd_poweroff) | ||
125 | return; | ||
126 | if(state) { | ||
127 | if(!lcd_on) { | ||
128 | lcd_on = true; | ||
129 | memcpy(FRAME, lcd_framebuffer, LCD_WIDTH*LCD_HEIGHT*2); | ||
130 | LCDCON1 |= 1; | ||
131 | } | ||
132 | } | ||
133 | else { | ||
134 | if(lcd_on) { | ||
135 | lcd_on = false; | ||
136 | LCDCON1 &= ~1; | ||
137 | } | ||
138 | } | ||
139 | } | ||
140 | |||
141 | void lcd_set_foreground(unsigned color) | ||
142 | { | ||
143 | fg_pattern = color; | ||
144 | |||
145 | memset16(fg_pattern_blit, fg_pattern, sizeof(fg_pattern_blit)/2); | ||
146 | invalidate_dcache_range((void *)fg_pattern_blit, sizeof(fg_pattern_blit)); | ||
147 | } | ||
148 | |||
149 | void lcd_set_background(unsigned color) | ||
150 | { | ||
151 | bg_pattern = color; | ||
152 | memset16(bg_pattern_blit, bg_pattern, sizeof(bg_pattern_blit)/2); | ||
153 | invalidate_dcache_range((void *)bg_pattern_blit, sizeof(bg_pattern_blit)); | ||
154 | } | ||
155 | |||
156 | void lcd_device_prepare_backdrop(fb_data* backdrop) | ||
157 | { | ||
158 | if(backdrop) | ||
159 | invalidate_dcache_range((void *)backdrop, (LCD_HEIGHT * sizeof(fb_data) * LCD_WIDTH)); | ||
160 | } | ||
161 | |||
162 | void lcd_clear_display_dma(void) | ||
163 | { | ||
164 | void *src; | ||
165 | bool inc = false; | ||
166 | |||
167 | if(!lcd_on) { | ||
168 | sleep(200); | ||
169 | } | ||
170 | if (lcd_get_drawmode() & DRMODE_INVERSEVID) | ||
171 | src = fg_pattern_blit; | ||
172 | else | ||
173 | { | ||
174 | fb_data* lcd_backdrop = lcd_get_backdrop(); | ||
175 | |||
176 | if (!lcd_backdrop) | ||
177 | src = bg_pattern_blit; | ||
178 | else | ||
179 | { | ||
180 | src = lcd_backdrop; | ||
181 | inc = true; | ||
182 | } | ||
183 | } | ||
184 | /* Wait for any pending transfer to complete */ | ||
185 | while((DSTAT3 & 0x000fffff)) | ||
186 | CLKCON |= (1 << 2); /* set IDLE bit */ | ||
187 | DMASKTRIG3 |= 0x4; /* Stop controller */ | ||
188 | DIDST3 = ((int) &lcd_framebuffer[0][0]) + 0x30000000; /* set DMA dest, physical address */ | ||
189 | DIDSTC3 = 0; /* Dest on AHB, increment */ | ||
190 | |||
191 | DISRC3 = ((int) src) + 0x30000000; /* Set source, in physical space */ | ||
192 | DISRCC3 = inc ? 0x00 : 0x01; /* memory is on AHB bus, increment addresses based on backdrop */ | ||
193 | |||
194 | /* Handshake on AHB, Burst mode, whole service mode, no reload, move 32-bits */ | ||
195 | DCON3 = ((1<<30) | (1<<28) | (1<<27) | (1<<22) | (2<<20)) | ((LCD_WIDTH*LCD_HEIGHT*sizeof(fb_data)) >> 4); | ||
196 | |||
197 | /* Dump DCache for dest, we are about to overwrite it with DMA */ | ||
198 | invalidate_dcache_range((void *)lcd_framebuffer, sizeof(lcd_framebuffer)); | ||
199 | /* Activate the channel */ | ||
200 | DMASKTRIG3 = 2; | ||
201 | /* Start DMA */ | ||
202 | DMASKTRIG3 |= 1; | ||
203 | |||
204 | /* Wait for transfer to complete */ | ||
205 | while((DSTAT3 & 0x000fffff)) | ||
206 | CLKCON |= (1 << 2); /* set IDLE bit */ | ||
207 | } | ||
208 | |||
209 | void lcd_clear_display(void) | ||
210 | { | ||
211 | lcd_stop_scroll(); | ||
212 | |||
213 | if(use_dma_blit) | ||
214 | { | ||
215 | lcd_clear_display_dma(); | ||
216 | return; | ||
217 | } | ||
218 | |||
219 | fb_data *dst = &lcd_framebuffer[0][0]; | ||
220 | |||
221 | if (lcd_get_drawmode() & DRMODE_INVERSEVID) | ||
222 | { | ||
223 | memset16(dst, fg_pattern, LCD_WIDTH*LCD_HEIGHT); | ||
224 | } | ||
225 | else | ||
226 | { | ||
227 | fb_data* lcd_backdrop = lcd_get_backdrop(); | ||
228 | if (!lcd_backdrop) | ||
229 | memset16(dst, bg_pattern, LCD_WIDTH*LCD_HEIGHT); | ||
230 | else | ||
231 | memcpy(dst, lcd_backdrop, sizeof(lcd_framebuffer)); | ||
232 | } | ||
233 | } | ||
234 | |||
235 | |||
236 | /* Update the display. | ||
237 | This must be called after all other LCD functions that change the display. */ | ||
238 | void lcd_update(void) | ||
239 | { | ||
240 | lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); | ||
241 | } | ||
242 | |||
243 | void lcd_bitmap_transparent_part(const fb_data *src, int src_x, int src_y, | ||
244 | int stride, int x, int y, int width, | ||
245 | int height) | ||
246 | { | ||
247 | fb_data *dst, *dst_end; | ||
248 | unsigned int transcolor; | ||
249 | |||
250 | /* nothing to draw? */ | ||
251 | if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) | ||
252 | || (x + width <= 0) || (y + height <= 0)) | ||
253 | return; | ||
254 | |||
255 | /* clipping */ | ||
256 | if (x < 0) | ||
257 | { | ||
258 | width += x; | ||
259 | src_x -= x; | ||
260 | x = 0; | ||
261 | } | ||
262 | if (y < 0) | ||
263 | { | ||
264 | height += y; | ||
265 | src_y -= y; | ||
266 | y = 0; | ||
267 | } | ||
268 | if (x + width > LCD_WIDTH) | ||
269 | width = LCD_WIDTH - x; | ||
270 | if (y + height > LCD_HEIGHT) | ||
271 | height = LCD_HEIGHT - y; | ||
272 | |||
273 | src += stride * src_y + src_x; /* move starting point */ | ||
274 | dst = &lcd_framebuffer[(y)][(x)]; | ||
275 | dst_end = dst + height * LCD_WIDTH; | ||
276 | width *= 2; | ||
277 | stride *= 2; | ||
278 | transcolor = TRANSPARENT_COLOR; | ||
279 | asm volatile( | ||
280 | "rowstart: \n" | ||
281 | "mov r0, #0 \n" | ||
282 | "nextpixel: \n" | ||
283 | "ldrh r1, [%0, r0] \n" /* Load word src+r0 */ | ||
284 | "cmp r1, %5 \n" /* Compare to transparent color */ | ||
285 | "strneh r1, [%1, r0] \n" /* Store dst+r0 if not transparent */ | ||
286 | "add r0, r0, #2 \n" | ||
287 | "cmp r0, %2 \n" /* r0 == width? */ | ||
288 | "bne nextpixel \n" /* More in this row? */ | ||
289 | "add %0, %0, %4 \n" /* src += stride */ | ||
290 | "add %1, %1, #480 \n" /* dst += LCD_WIDTH (x2) */ | ||
291 | "cmp %1, %3 \n" | ||
292 | "bne rowstart \n" /* if(dst != dst_end), keep going */ | ||
293 | : : "r" (src), "r" (dst), "r" (width), "r" (dst_end), "r" (stride), "r" (transcolor) : "r0", "r1" ); | ||
294 | } | ||
295 | |||
296 | /* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */ | ||
297 | extern void lcd_write_yuv420_lines(fb_data *dst, | ||
298 | unsigned char chroma_buf[LCD_HEIGHT/2*3], | ||
299 | unsigned char const * const src[3], | ||
300 | int width, | ||
301 | int stride); | ||
302 | /* Performance function to blit a YUV bitmap directly to the LCD */ | ||
303 | /* For the Gigabeat - show it rotated */ | ||
304 | /* So the LCD_WIDTH is now the height */ | ||
305 | void lcd_yuv_blit(unsigned char * const src[3], | ||
306 | int src_x, int src_y, int stride, | ||
307 | int x, int y, int width, int height) | ||
308 | { | ||
309 | /* Caches for chroma data so it only need be recaculated every other | ||
310 | line */ | ||
311 | unsigned char chroma_buf[LCD_HEIGHT/2*3]; /* 480 bytes */ | ||
312 | unsigned char const * yuv_src[3]; | ||
313 | off_t z; | ||
314 | |||
315 | if (!lcd_on) | ||
316 | return; | ||
317 | |||
318 | /* Sorry, but width and height must be >= 2 or else */ | ||
319 | width &= ~1; | ||
320 | height >>= 1; | ||
321 | |||
322 | fb_data *dst = (fb_data*)FRAME + x * LCD_WIDTH + (LCD_WIDTH - y) - 1; | ||
323 | |||
324 | z = stride*src_y; | ||
325 | yuv_src[0] = src[0] + z + src_x; | ||
326 | yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1); | ||
327 | yuv_src[2] = src[2] + (yuv_src[1] - src[1]); | ||
328 | |||
329 | do | ||
330 | { | ||
331 | lcd_write_yuv420_lines(dst, chroma_buf, yuv_src, width, | ||
332 | stride); | ||
333 | yuv_src[0] += stride << 1; /* Skip down two luma lines */ | ||
334 | yuv_src[1] += stride >> 1; /* Skip down one chroma line */ | ||
335 | yuv_src[2] += stride >> 1; | ||
336 | dst -= 2; | ||
337 | } | ||
338 | while (--height > 0); | ||
339 | } | ||
340 | |||
341 | void lcd_set_contrast(int val) { | ||
342 | (void) val; | ||
343 | // TODO: | ||
344 | } | ||
345 | |||
346 | void lcd_set_invert_display(bool yesno) { | ||
347 | (void) yesno; | ||
348 | // TODO: | ||
349 | } | ||
350 | |||
351 | void lcd_blit(const fb_data* data, int bx, int y, int bwidth, | ||
352 | int height, int stride) | ||
353 | { | ||
354 | (void) data; | ||
355 | (void) bx; | ||
356 | (void) y; | ||
357 | (void) bwidth; | ||
358 | (void) height; | ||
359 | (void) stride; | ||
360 | //TODO: | ||
361 | } | ||
362 | |||
363 | void lcd_set_flip(bool yesno) { | ||
364 | (void) yesno; | ||
365 | // TODO: | ||
366 | } | ||
367 | |||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/lcd-target.h b/firmware/target/arm/s3c2440/gigabeat-fx/lcd-target.h new file mode 100644 index 0000000000..cb2a89f349 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/lcd-target.h | |||
@@ -0,0 +1,21 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id $ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Greg White | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | extern void lcd_enable(bool state); | ||
21 | |||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/mmu-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/mmu-meg-fx.c new file mode 100644 index 0000000000..6142213f0c --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/mmu-meg-fx.c | |||
@@ -0,0 +1,222 @@ | |||
1 | #include <string.h> | ||
2 | #include "s3c2440.h" | ||
3 | #include "mmu-meg-fx.h" | ||
4 | #include "panic.h" | ||
5 | |||
6 | void map_memory(void); | ||
7 | static void enable_mmu(void); | ||
8 | static void set_ttb(void); | ||
9 | static void set_page_tables(void); | ||
10 | static void map_section(unsigned int pa, unsigned int va, int mb, int cache_flags); | ||
11 | |||
12 | #define SECTION_ADDRESS_MASK (-1 << 20) | ||
13 | #define CACHE_ALL (1 << 3 | 1 << 2 ) | ||
14 | #define CACHE_NONE 0 | ||
15 | #define BUFFERED (1 << 2) | ||
16 | #define MB (1 << 20) | ||
17 | |||
18 | void map_memory(void) { | ||
19 | set_ttb(); | ||
20 | set_page_tables(); | ||
21 | enable_mmu(); | ||
22 | } | ||
23 | |||
24 | unsigned int* ttb_base = (unsigned int *) TTB_BASE; | ||
25 | const int ttb_size = 4096; | ||
26 | |||
27 | void set_ttb() { | ||
28 | int i; | ||
29 | int* ttbPtr; | ||
30 | int domain_access; | ||
31 | |||
32 | /* must be 16Kb (0x4000) aligned */ | ||
33 | ttb_base = (int*) TTB_BASE; | ||
34 | for (i=0; i<ttb_size; i++,ttbPtr++) | ||
35 | ttbPtr = 0; | ||
36 | asm volatile("mcr p15, 0, %0, c2, c0, 0" : : "r" (ttb_base)); | ||
37 | |||
38 | /* set domain D0 to "client" permission access */ | ||
39 | |||
40 | domain_access = 3; | ||
41 | asm volatile("mcr p15, 0, %0, c3, c0, 0" : : "r" (domain_access)); | ||
42 | |||
43 | } | ||
44 | |||
45 | void set_page_tables() { | ||
46 | |||
47 | map_section(0, 0, 0x1000, CACHE_NONE); /* map every memory region to itself */ | ||
48 | map_section(0x30000000, 0, 32, CACHE_ALL); /* map RAM to 0 and enable caching for it */ | ||
49 | map_section((int)FRAME, (int)FRAME, 1, BUFFERED); /* enable buffered writing for the framebuffer */ | ||
50 | } | ||
51 | |||
52 | void map_section(unsigned int pa, unsigned int va, int mb, int cache_flags) { | ||
53 | unsigned int* ttbPtr; | ||
54 | int i; | ||
55 | int section_no; | ||
56 | |||
57 | section_no = va >> 20; /* sections are 1Mb size */ | ||
58 | ttbPtr = ttb_base + section_no; | ||
59 | pa &= SECTION_ADDRESS_MASK; /* align to 1Mb */ | ||
60 | for(i=0; i<mb; i++, pa += MB) { | ||
61 | *(ttbPtr + i) = | ||
62 | pa | | ||
63 | 1 << 10 | /* superuser - r/w, user - no access */ | ||
64 | 0 << 5 | /* domain 0th */ | ||
65 | 1 << 4 | /* should be "1" */ | ||
66 | cache_flags | | ||
67 | 1 << 1; /* Section signature */ | ||
68 | } | ||
69 | } | ||
70 | |||
71 | static void enable_mmu(void) { | ||
72 | asm volatile("mov r0, #0\n" | ||
73 | "mcr p15, 0, r0, c8, c7, 0\n" /* invalidate TLB */ | ||
74 | |||
75 | "mcr p15, 0, r0, c7, c7,0\n" /* invalidate both icache and dcache */ | ||
76 | |||
77 | "mrc p15, 0, r0, c1, c0, 0\n" | ||
78 | "orr r0, r0, #1<<0\n" /* enable mmu bit, icache and dcache */ | ||
79 | "orr r0, r0, #1<<2\n" /* enable dcache */ | ||
80 | "orr r0, r0, #1<<12\n" /* enable icache */ | ||
81 | "mcr p15, 0, r0, c1, c0, 0" : : : "r0"); | ||
82 | asm volatile("nop \n nop \n nop \n nop"); | ||
83 | } | ||
84 | |||
85 | /* Invalidate DCache for this range */ | ||
86 | /* Will do write back */ | ||
87 | void invalidate_dcache_range(const void *base, unsigned int size) { | ||
88 | unsigned int addr = (((int) base) & ~31); /* Align start to cache line*/ | ||
89 | unsigned int end = ((addr+size) & ~31)+64; /* Align end to cache line, pad */ | ||
90 | asm volatile( | ||
91 | "inv_start: \n" | ||
92 | "mcr p15, 0, %0, c7, c14, 1 \n" /* Clean and invalidate this line */ | ||
93 | "add %0, %0, #32 \n" | ||
94 | "cmp %0, %1 \n" | ||
95 | "mcrne p15, 0, %0, c7, c14, 1 \n" /* Clean and invalidate this line */ | ||
96 | "addne %0, %0, #32 \n" | ||
97 | "cmpne %0, %1 \n" | ||
98 | "mcrne p15, 0, %0, c7, c14, 1 \n" /* Clean and invalidate this line */ | ||
99 | "addne %0, %0, #32 \n" | ||
100 | "cmpne %0, %1 \n" | ||
101 | "mcrne p15, 0, %0, c7, c14, 1 \n" /* Clean and invalidate this line */ | ||
102 | "addne %0, %0, #32 \n" | ||
103 | "cmpne %0, %1 \n" | ||
104 | "mcrne p15, 0, %0, c7, c14, 1 \n" /* Clean and invalidate this line */ | ||
105 | "addne %0, %0, #32 \n" | ||
106 | "cmpne %0, %1 \n" | ||
107 | "mcrne p15, 0, %0, c7, c14, 1 \n" /* Clean and invalidate this line */ | ||
108 | "addne %0, %0, #32 \n" | ||
109 | "cmpne %0, %1 \n" | ||
110 | "mcrne p15, 0, %0, c7, c14, 1 \n" /* Clean and invalidate this line */ | ||
111 | "addne %0, %0, #32 \n" | ||
112 | "cmpne %0, %1 \n" | ||
113 | "mcrne p15, 0, %0, c7, c14, 1 \n" /* Clean and invalidate this line */ | ||
114 | "addne %0, %0, #32 \n" | ||
115 | "cmpne %0, %1 \n" | ||
116 | "bne inv_start \n" | ||
117 | "mov %0, #0\n" | ||
118 | "mcr p15,0,%0,c7,c10,4\n" /* Drain write buffer */ | ||
119 | : : "r" (addr), "r" (end)); | ||
120 | } | ||
121 | |||
122 | /* clean DCache for this range */ | ||
123 | /* forces DCache writeback for the specified range */ | ||
124 | void clean_dcache_range(const void *base, unsigned int size) { | ||
125 | unsigned int addr = (int) base; | ||
126 | unsigned int end = addr+size+32; | ||
127 | asm volatile( | ||
128 | "bic %0, %0, #31 \n" | ||
129 | "clean_start: \n" | ||
130 | "mcr p15, 0, %0, c7, c10, 1 \n" /* Clean this line */ | ||
131 | "add %0, %0, #32 \n" | ||
132 | "cmp %0, %1 \n" | ||
133 | "mcrlo p15, 0, %0, c7, c10, 1 \n" /* Clean this line */ | ||
134 | "addlo %0, %0, #32 \n" | ||
135 | "cmplo %0, %1 \n" | ||
136 | "mcrlo p15, 0, %0, c7, c10, 1 \n" /* Clean this line */ | ||
137 | "addlo %0, %0, #32 \n" | ||
138 | "cmplo %0, %1 \n" | ||
139 | "mcrlo p15, 0, %0, c7, c10, 1 \n" /* Clean this line */ | ||
140 | "addlo %0, %0, #32 \n" | ||
141 | "cmplo %0, %1 \n" | ||
142 | "mcrlo p15, 0, %0, c7, c10, 1 \n" /* Clean this line */ | ||
143 | "addlo %0, %0, #32 \n" | ||
144 | "cmplo %0, %1 \n" | ||
145 | "mcrlo p15, 0, %0, c7, c10, 1 \n" /* Clean this line */ | ||
146 | "addlo %0, %0, #32 \n" | ||
147 | "cmplo %0, %1 \n" | ||
148 | "mcrlo p15, 0, %0, c7, c10, 1 \n" /* Clean this line */ | ||
149 | "addlo %0, %0, #32 \n" | ||
150 | "cmplo %0, %1 \n" | ||
151 | "mcrlo p15, 0, %0, c7, c10, 1 \n" /* Clean this line */ | ||
152 | "addlo %0, %0, #32 \n" | ||
153 | "cmplo %0, %1 \n" | ||
154 | "blo clean_start \n" | ||
155 | "mov %0, #0\n" | ||
156 | "mcr p15,0,%0,c7,c10,4 \n" /* Drain write buffer */ | ||
157 | : : "r" (addr), "r" (end)); | ||
158 | } | ||
159 | |||
160 | /* Dump DCache for this range */ | ||
161 | /* Will *NOT* do write back */ | ||
162 | void dump_dcache_range(const void *base, unsigned int size) { | ||
163 | unsigned int addr = (int) base; | ||
164 | unsigned int end = addr+size; | ||
165 | asm volatile( | ||
166 | "tst %0, #31 \n" /* Check to see if low five bits are set */ | ||
167 | "bic %0, %0, #31 \n" /* Clear them */ | ||
168 | "mcrne p15, 0, %0, c7, c14, 1 \n" /* Clean and invalidate this line, if those bits were set */ | ||
169 | "add %0, %0, #32 \n" /* Move to the next cache line */ | ||
170 | "tst %1, #31 \n" /* Check last line for bits set */ | ||
171 | "bic %1, %1, #31 \n" /* Clear those bits */ | ||
172 | "mcrne p15, 0, %1, c7, c14, 1 \n" /* Clean and invalidate this line, if not cache aligned */ | ||
173 | "dump_start: \n" | ||
174 | "mcr p15, 0, %0, c7, c6, 1 \n" /* Invalidate this line */ | ||
175 | "add %0, %0, #32 \n" /* Next cache line */ | ||
176 | "cmp %0, %1 \n" | ||
177 | "bne dump_start \n" | ||
178 | "dump_end: \n" | ||
179 | "mcr p15,0,%0,c7,c10,4 \n" /* Drain write buffer */ | ||
180 | : : "r" (addr), "r" (end)); | ||
181 | } | ||
182 | /* Cleans entire DCache */ | ||
183 | void clean_dcache(void) | ||
184 | { | ||
185 | unsigned int index, addr; | ||
186 | |||
187 | for(index = 0; index <= 63; index++) { | ||
188 | addr = (0 << 5) | (index << 26); | ||
189 | asm volatile( | ||
190 | "mcr p15, 0, %0, c7, c10, 2 \n" /* Clean this entry by index */ | ||
191 | : : "r" (addr)); | ||
192 | addr = (1 << 5) | (index << 26); | ||
193 | asm volatile( | ||
194 | "mcr p15, 0, %0, c7, c10, 2 \n" /* Clean this entry by index */ | ||
195 | : : "r" (addr)); | ||
196 | addr = (2 << 5) | (index << 26); | ||
197 | asm volatile( | ||
198 | "mcr p15, 0, %0, c7, c10, 2 \n" /* Clean this entry by index */ | ||
199 | : : "r" (addr)); | ||
200 | addr = (3 << 5) | (index << 26); | ||
201 | asm volatile( | ||
202 | "mcr p15, 0, %0, c7, c10, 2 \n" /* Clean this entry by index */ | ||
203 | : : "r" (addr)); | ||
204 | addr = (4 << 5) | (index << 26); | ||
205 | asm volatile( | ||
206 | "mcr p15, 0, %0, c7, c10, 2 \n" /* Clean this entry by index */ | ||
207 | : : "r" (addr)); | ||
208 | addr = (5 << 5) | (index << 26); | ||
209 | asm volatile( | ||
210 | "mcr p15, 0, %0, c7, c10, 2 \n" /* Clean this entry by index */ | ||
211 | : : "r" (addr)); | ||
212 | addr = (6 << 5) | (index << 26); | ||
213 | asm volatile( | ||
214 | "mcr p15, 0, %0, c7, c10, 2 \n" /* Clean this entry by index */ | ||
215 | : : "r" (addr)); | ||
216 | addr = (7 << 5) | (index << 26); | ||
217 | asm volatile( | ||
218 | "mcr p15, 0, %0, c7, c10, 2 \n" /* Clean this entry by index */ | ||
219 | : : "r" (addr)); | ||
220 | } | ||
221 | } | ||
222 | |||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/mmu-meg-fx.h b/firmware/target/arm/s3c2440/gigabeat-fx/mmu-meg-fx.h new file mode 100644 index 0000000000..71b1b83801 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/mmu-meg-fx.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006,2007 by Greg White | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | /* Invalidate DCache for this range */ | ||
21 | /* Will do write back */ | ||
22 | void invalidate_dcache_range(const void *base, unsigned int size); | ||
23 | |||
24 | /* clean DCache for this range */ | ||
25 | /* forces DCache writeback for the specified range */ | ||
26 | void clean_dcache_range(const void *base, unsigned int size); | ||
27 | |||
28 | /* Dump DCache for this range */ | ||
29 | /* Will *NOT* do write back */ | ||
30 | void dump_dcache_range(const void *base, unsigned int size); | ||
31 | |||
32 | /* Cleans entire DCache */ | ||
33 | void clean_dcache(void); | ||
34 | |||
35 | |||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c new file mode 100644 index 0000000000..0f22aa5c5c --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c | |||
@@ -0,0 +1,376 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006 by Michael Sevakis | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #include "system.h" | ||
20 | #include "kernel.h" | ||
21 | #include "logf.h" | ||
22 | #include "audio.h" | ||
23 | #include "sound.h" | ||
24 | #include "file.h" | ||
25 | #include "mmu-meg-fx.h" | ||
26 | |||
27 | static int pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */ | ||
28 | |||
29 | #define GIGABEAT_8000HZ 0x4d | ||
30 | #define GIGABEAT_11025HZ 0x32 | ||
31 | #define GIGABEAT_12000HZ 0x61 | ||
32 | #define GIGABEAT_16000HZ 0x55 | ||
33 | #define GIGABEAT_22050HZ 0x36 | ||
34 | #define GIGABEAT_24000HZ 0x79 | ||
35 | #define GIGABEAT_32000HZ 0x59 | ||
36 | #define GIGABEAT_44100HZ 0x22 | ||
37 | #define GIGABEAT_48000HZ 0x41 | ||
38 | #define GIGABEAT_88200HZ 0x3e | ||
39 | #define GIGABEAT_96000HZ 0x5d | ||
40 | |||
41 | #define FIFO_COUNT ((IISFCON >> 6) & 0x01F) | ||
42 | |||
43 | /* number of bytes in FIFO */ | ||
44 | #define IIS_FIFO_SIZE 64 | ||
45 | |||
46 | /* Setup for the DMA controller */ | ||
47 | #define DMA_CONTROL_SETUP ((1<<31) | (1<<29) | (1<<23) | (1<<22) | (1<<20)) | ||
48 | |||
49 | unsigned short * p; | ||
50 | size_t p_size; | ||
51 | |||
52 | |||
53 | |||
54 | /* DMA count has hit zero - no more data */ | ||
55 | /* Get more data from the callback and top off the FIFO */ | ||
56 | //void fiq(void) __attribute__ ((interrupt ("naked"))); | ||
57 | void fiq(void) ICODE_ATTR __attribute__ ((interrupt ("FIQ"))); | ||
58 | void fiq(void) | ||
59 | { | ||
60 | /* clear any pending interrupt */ | ||
61 | SRCPND = (1<<19); | ||
62 | |||
63 | /* Buffer empty. Try to get more. */ | ||
64 | if (pcm_callback_for_more) | ||
65 | { | ||
66 | pcm_callback_for_more((unsigned char**)&p, &p_size); | ||
67 | } | ||
68 | else | ||
69 | { | ||
70 | /* callback func is missing? */ | ||
71 | pcm_play_dma_stop(); | ||
72 | return; | ||
73 | } | ||
74 | |||
75 | if (p_size) | ||
76 | { | ||
77 | /* Flush any pending cache writes */ | ||
78 | clean_dcache_range(p, p_size); | ||
79 | |||
80 | /* set the new DMA values */ | ||
81 | DCON2 = DMA_CONTROL_SETUP | (p_size >> 1); | ||
82 | DISRC2 = (int)p + 0x30000000; | ||
83 | |||
84 | /* Re-Activate the channel */ | ||
85 | DMASKTRIG2 = 0x2; | ||
86 | } | ||
87 | else | ||
88 | { | ||
89 | /* No more DMA to do */ | ||
90 | pcm_play_dma_stop(); | ||
91 | } | ||
92 | |||
93 | } | ||
94 | |||
95 | |||
96 | |||
97 | void pcm_init(void) | ||
98 | { | ||
99 | pcm_playing = false; | ||
100 | pcm_paused = false; | ||
101 | pcm_callback_for_more = NULL; | ||
102 | |||
103 | audiohw_init(); | ||
104 | audiohw_enable_output(true); | ||
105 | |||
106 | /* cannot use the WM8975 defaults since our clock is not the same */ | ||
107 | /* the input master clock is 16.9344MHz - we can divide exact for that */ | ||
108 | pcm_set_frequency(SAMPR_44); | ||
109 | |||
110 | /* init GPIO */ | ||
111 | GPCCON = (GPCCON & ~(3<<14)) | (1<<14); | ||
112 | GPCDAT |= 1<<7; | ||
113 | GPECON |= 0x2aa; | ||
114 | |||
115 | /* Do not service DMA requests, yet */ | ||
116 | /* clear any pending int and mask it */ | ||
117 | INTMSK |= (1<<19); /* mask the interrupt */ | ||
118 | SRCPND = (1<<19); /* clear any pending interrupts */ | ||
119 | INTMOD |= (1<<19); /* connect to FIQ */ | ||
120 | |||
121 | } | ||
122 | |||
123 | void pcm_postinit(void) | ||
124 | { | ||
125 | audiohw_postinit(); | ||
126 | } | ||
127 | |||
128 | void pcm_play_dma_start(const void *addr, size_t size) | ||
129 | { | ||
130 | /* sanity check: bad pointer or too small file */ | ||
131 | if (NULL == addr || size <= IIS_FIFO_SIZE) return; | ||
132 | |||
133 | p = (unsigned short *)addr; | ||
134 | p_size = size; | ||
135 | |||
136 | /* Enable the IIS clock */ | ||
137 | CLKCON |= (1<<17); | ||
138 | |||
139 | /* IIS interface setup and set to idle */ | ||
140 | IISCON = (1<<5) | (1<<3); | ||
141 | |||
142 | /* slave, transmit mode, 16 bit samples - 384fs - use 16.9344Mhz */ | ||
143 | IISMOD = (1<<9) | (1<<8) | (2<<6) | (1<<3) | (1<<2); | ||
144 | |||
145 | /* connect DMA to the FIFO and enable the FIFO */ | ||
146 | IISFCON = (1<<15) | (1<<13); | ||
147 | |||
148 | /* set DMA dest */ | ||
149 | DIDST2 = (int)&IISFIFO; | ||
150 | |||
151 | /* IIS is on the APB bus, INT when TC reaches 0, fixed dest addr */ | ||
152 | DIDSTC2 = 0x03; | ||
153 | |||
154 | /* How many transfers to make - we transfer half-word at a time = 2 bytes */ | ||
155 | /* DMA control: CURR_TC int, single service mode, I2SSDO int, HW trig */ | ||
156 | /* no auto-reload, half-word (16bit) */ | ||
157 | DCON2 = DMA_CONTROL_SETUP | (p_size / 2); | ||
158 | |||
159 | /* set DMA source and options */ | ||
160 | DISRC2 = (int)p + 0x30000000; | ||
161 | DISRCC2 = 0x00; /* memory is on AHB bus, increment addresses */ | ||
162 | |||
163 | /* clear pending DMA interrupt */ | ||
164 | SRCPND = 1<<19; | ||
165 | |||
166 | set_fiq_handler(fiq); | ||
167 | enable_fiq(); | ||
168 | |||
169 | /* unmask the DMA interrupt */ | ||
170 | INTMSK &= ~(1<<19); | ||
171 | |||
172 | /* Flush any pending writes */ | ||
173 | clean_dcache_range(addr, size); | ||
174 | |||
175 | /* Activate the channel */ | ||
176 | DMASKTRIG2 = 0x2; | ||
177 | |||
178 | /* turn off the idle */ | ||
179 | IISCON &= ~(1<<3); | ||
180 | |||
181 | pcm_playing = true; | ||
182 | |||
183 | /* start the IIS */ | ||
184 | IISCON |= (1<<0); | ||
185 | |||
186 | } | ||
187 | |||
188 | |||
189 | |||
190 | /* Disconnect the DMA and wait for the FIFO to clear */ | ||
191 | void pcm_play_dma_stop(void) | ||
192 | { | ||
193 | /* mask the DMA interrupt */ | ||
194 | INTMSK |= (1<<19); | ||
195 | |||
196 | /* are we playing? wait for the chunk to finish */ | ||
197 | if (pcm_playing) | ||
198 | { | ||
199 | /* wait for the FIFO to empty before turning things off */ | ||
200 | while (IISCON & (1<<7)) ; | ||
201 | |||
202 | pcm_playing = false; | ||
203 | } | ||
204 | |||
205 | /* De-Activate the DMA channel */ | ||
206 | DMASKTRIG2 = 0x4; | ||
207 | |||
208 | /* Disconnect the IIS clock */ | ||
209 | CLKCON &= ~(1<<17); | ||
210 | |||
211 | disable_fiq(); | ||
212 | |||
213 | } | ||
214 | |||
215 | |||
216 | |||
217 | void pcm_play_pause_pause(void) | ||
218 | { | ||
219 | /* stop servicing refills */ | ||
220 | INTMSK |= (1<<19); | ||
221 | } | ||
222 | |||
223 | |||
224 | |||
225 | void pcm_play_pause_unpause(void) | ||
226 | { | ||
227 | /* refill buffer and keep going */ | ||
228 | INTMSK &= ~(1<<19); | ||
229 | } | ||
230 | |||
231 | void pcm_set_frequency(unsigned int frequency) | ||
232 | { | ||
233 | int sr_ctrl; | ||
234 | |||
235 | switch(frequency) | ||
236 | { | ||
237 | case SAMPR_8: | ||
238 | sr_ctrl = GIGABEAT_8000HZ; | ||
239 | break; | ||
240 | case SAMPR_11: | ||
241 | sr_ctrl = GIGABEAT_11025HZ; | ||
242 | break; | ||
243 | case SAMPR_12: | ||
244 | sr_ctrl = GIGABEAT_12000HZ; | ||
245 | break; | ||
246 | case SAMPR_16: | ||
247 | sr_ctrl = GIGABEAT_16000HZ; | ||
248 | break; | ||
249 | case SAMPR_22: | ||
250 | sr_ctrl = GIGABEAT_22050HZ; | ||
251 | break; | ||
252 | case SAMPR_24: | ||
253 | sr_ctrl = GIGABEAT_24000HZ; | ||
254 | break; | ||
255 | case SAMPR_32: | ||
256 | sr_ctrl = GIGABEAT_32000HZ; | ||
257 | break; | ||
258 | default: | ||
259 | frequency = SAMPR_44; | ||
260 | case SAMPR_44: | ||
261 | sr_ctrl = GIGABEAT_44100HZ; | ||
262 | break; | ||
263 | case SAMPR_48: | ||
264 | sr_ctrl = GIGABEAT_48000HZ; | ||
265 | break; | ||
266 | case SAMPR_88: | ||
267 | sr_ctrl = GIGABEAT_88200HZ; | ||
268 | break; | ||
269 | case SAMPR_96: | ||
270 | sr_ctrl = GIGABEAT_96000HZ; | ||
271 | break; | ||
272 | } | ||
273 | |||
274 | audiohw_set_sample_rate(sr_ctrl); | ||
275 | pcm_freq = frequency; | ||
276 | } | ||
277 | |||
278 | |||
279 | |||
280 | size_t pcm_get_bytes_waiting(void) | ||
281 | { | ||
282 | return (DSTAT2 & 0xFFFFF) * 2; | ||
283 | } | ||
284 | |||
285 | |||
286 | |||
287 | /* dummy functions for those not actually supporting all this yet */ | ||
288 | void pcm_apply_settings(void) | ||
289 | { | ||
290 | } | ||
291 | |||
292 | void pcm_set_monitor(int monitor) | ||
293 | { | ||
294 | (void)monitor; | ||
295 | } | ||
296 | /** **/ | ||
297 | |||
298 | void pcm_mute(bool mute) | ||
299 | { | ||
300 | audiohw_mute(mute); | ||
301 | if (mute) | ||
302 | sleep(HZ/16); | ||
303 | } | ||
304 | |||
305 | /* | ||
306 | * This function goes directly into the DMA buffer to calculate the left and | ||
307 | * right peak values. To avoid missing peaks it tries to look forward two full | ||
308 | * peek periods (2/HZ sec, 100% overlap), although it's always possible that | ||
309 | * the entire period will not be visible. To reduce CPU load it only looks at | ||
310 | * every third sample, and this can be reduced even further if needed (even | ||
311 | * every tenth sample would still be pretty accurate). | ||
312 | */ | ||
313 | |||
314 | /* Check for a peak every PEAK_STRIDE samples */ | ||
315 | #define PEAK_STRIDE 3 | ||
316 | /* Up to 1/50th of a second of audio for peak calculation */ | ||
317 | /* This should use NATIVE_FREQUENCY, or eventually an adjustable freq. value */ | ||
318 | #define PEAK_SAMPLES (44100/50) | ||
319 | void pcm_calculate_peaks(int *left, int *right) | ||
320 | { | ||
321 | short *addr; | ||
322 | short *end; | ||
323 | { | ||
324 | size_t samples = p_size / 4; | ||
325 | addr = p; | ||
326 | |||
327 | if (samples > PEAK_SAMPLES) | ||
328 | samples = PEAK_SAMPLES - (PEAK_STRIDE - 1); | ||
329 | else | ||
330 | samples -= MIN(PEAK_STRIDE - 1, samples); | ||
331 | |||
332 | end = &addr[samples * 2]; | ||
333 | } | ||
334 | |||
335 | if (left && right) { | ||
336 | int left_peak = 0, right_peak = 0; | ||
337 | |||
338 | while (addr < end) { | ||
339 | int value; | ||
340 | if ((value = addr [0]) > left_peak) | ||
341 | left_peak = value; | ||
342 | else if (-value > left_peak) | ||
343 | left_peak = -value; | ||
344 | |||
345 | if ((value = addr [PEAK_STRIDE | 1]) > right_peak) | ||
346 | right_peak = value; | ||
347 | else if (-value > right_peak) | ||
348 | right_peak = -value; | ||
349 | |||
350 | addr = &addr[PEAK_STRIDE * 2]; | ||
351 | } | ||
352 | |||
353 | *left = left_peak; | ||
354 | *right = right_peak; | ||
355 | } | ||
356 | else if (left || right) { | ||
357 | int peak_value = 0, value; | ||
358 | |||
359 | if (right) | ||
360 | addr += (PEAK_STRIDE | 1); | ||
361 | |||
362 | while (addr < end) { | ||
363 | if ((value = addr [0]) > peak_value) | ||
364 | peak_value = value; | ||
365 | else if (-value > peak_value) | ||
366 | peak_value = -value; | ||
367 | |||
368 | addr += PEAK_STRIDE * 2; | ||
369 | } | ||
370 | |||
371 | if (left) | ||
372 | *left = peak_value; | ||
373 | else | ||
374 | *right = peak_value; | ||
375 | } | ||
376 | } | ||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/power-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/power-meg-fx.c new file mode 100644 index 0000000000..eb2ffb5238 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/power-meg-fx.c | |||
@@ -0,0 +1,90 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006 by Linus Nielsen Feltzing | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #include "config.h" | ||
20 | #include "cpu.h" | ||
21 | #include <stdbool.h> | ||
22 | #include "kernel.h" | ||
23 | #include "system.h" | ||
24 | #include "power.h" | ||
25 | #include "pcf50606.h" | ||
26 | #include "backlight.h" | ||
27 | #include "backlight-target.h" | ||
28 | |||
29 | #ifndef SIMULATOR | ||
30 | |||
31 | void power_init(void) | ||
32 | { | ||
33 | /* Charger detect */ | ||
34 | } | ||
35 | |||
36 | bool charger_inserted(void) | ||
37 | { | ||
38 | return (GPFDAT & (1 << 4)) ? false : true; | ||
39 | } | ||
40 | |||
41 | /* Returns true if the unit is charging the batteries. */ | ||
42 | bool charging_state(void) { | ||
43 | return (GPGDAT & (1 << 8)) ? false : true; | ||
44 | } | ||
45 | |||
46 | void ide_power_enable(bool on) | ||
47 | { | ||
48 | if (on) | ||
49 | GPGDAT |= (1 << 11); | ||
50 | else | ||
51 | GPGDAT &= ~(1 << 11); | ||
52 | } | ||
53 | |||
54 | bool ide_powered(void) | ||
55 | { | ||
56 | return (GPGDAT & (1 << 11)) != 0; | ||
57 | } | ||
58 | |||
59 | void power_off(void) | ||
60 | { | ||
61 | /* turn off backlight and wait for 1 second */ | ||
62 | __backlight_off(); | ||
63 | sleep(HZ/2); | ||
64 | /* set SLEEP bit to on in CLKCON to turn off */ | ||
65 | CLKCON |=(1<<3); | ||
66 | } | ||
67 | |||
68 | #else /* SIMULATOR */ | ||
69 | |||
70 | bool charger_inserted(void) | ||
71 | { | ||
72 | return false; | ||
73 | } | ||
74 | |||
75 | void charger_enable(bool on) | ||
76 | { | ||
77 | (void)on; | ||
78 | } | ||
79 | |||
80 | void power_off(void) | ||
81 | { | ||
82 | } | ||
83 | |||
84 | void ide_power_enable(bool on) | ||
85 | { | ||
86 | (void)on; | ||
87 | } | ||
88 | |||
89 | #endif /* SIMULATOR */ | ||
90 | |||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.c new file mode 100644 index 0000000000..e69eab432a --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.c | |||
@@ -0,0 +1,225 @@ | |||
1 | #include "config.h" | ||
2 | #include "cpu.h" | ||
3 | #include <stdbool.h> | ||
4 | #include "kernel.h" | ||
5 | #include "system.h" | ||
6 | #include "logf.h" | ||
7 | #include "debug.h" | ||
8 | #include "string.h" | ||
9 | |||
10 | #define SLAVE_ADDRESS 0xCC | ||
11 | |||
12 | #define SDA_LO (GPHDAT &= ~(1 << 9)) | ||
13 | #define SDA_HI (GPHDAT |= (1 << 9)) | ||
14 | #define SDA_INPUT (GPHCON &= ~(3 << 18)) | ||
15 | #define SDA_OUTPUT (GPHCON |= (1 << 18)) | ||
16 | #define SDA (GPHDAT & (1 << 9)) | ||
17 | |||
18 | #define SCL_LO (GPHDAT &= ~(1 << 10)) | ||
19 | #define SCL_HI (GPHDAT |= (1 << 10)) | ||
20 | #define SCL_INPUT (GPHCON &= ~(3 << 20)) | ||
21 | #define SCL_OUTPUT (GPHCON |= (1 << 20)) | ||
22 | #define SCL (GPHDAT & (1 << 10)) | ||
23 | |||
24 | #define SCL_SDA_HI (GPHDAT |= (3 << 9)) | ||
25 | |||
26 | /* The SC606 can clock at 400KHz: */ | ||
27 | /* Clock period high is 600nS and low is 1300nS */ | ||
28 | /* The high and low times are different enough to need different timings */ | ||
29 | /* cycles delayed = 30 + 7 * loops */ | ||
30 | /* 100MHz = 10nS per cycle: LO:1300nS=130:14 HI:600nS=60:9 */ | ||
31 | /* 300MHz = 3.36nS per cycle: LO:1300nS=387:51 HI:600nS=179:21 */ | ||
32 | #define DELAY_LO do{int x;for(x=51;x;x--);} while (0) | ||
33 | #define DELAY do{int x;for(x=35;x;x--);} while (0) | ||
34 | #define DELAY_HI do{int x;for(x=21;x;x--);} while (0) | ||
35 | |||
36 | |||
37 | |||
38 | static void sc606_i2c_start(void) | ||
39 | { | ||
40 | SCL_SDA_HI; | ||
41 | DELAY; | ||
42 | SDA_LO; | ||
43 | DELAY; | ||
44 | SCL_LO; | ||
45 | } | ||
46 | |||
47 | static void sc606_i2c_restart(void) | ||
48 | { | ||
49 | SCL_SDA_HI; | ||
50 | DELAY; | ||
51 | SDA_LO; | ||
52 | DELAY; | ||
53 | SCL_LO; | ||
54 | } | ||
55 | |||
56 | static void sc606_i2c_stop(void) | ||
57 | { | ||
58 | SDA_LO; | ||
59 | SCL_HI; | ||
60 | DELAY_HI; | ||
61 | SDA_HI; | ||
62 | } | ||
63 | |||
64 | static void sc606_i2c_ack(void) | ||
65 | { | ||
66 | |||
67 | SDA_LO; | ||
68 | SCL_HI; | ||
69 | DELAY_HI; | ||
70 | SCL_LO; | ||
71 | } | ||
72 | |||
73 | |||
74 | |||
75 | static int sc606_i2c_getack(void) | ||
76 | { | ||
77 | int ret; | ||
78 | |||
79 | /* Don't need a delay since follows a data bit with a delay on the end */ | ||
80 | SDA_INPUT; /* And set to input */ | ||
81 | DELAY; | ||
82 | SCL_HI; | ||
83 | |||
84 | ret = (SDA != 0); /* ack failed if SDA is not low */ | ||
85 | DELAY_HI; | ||
86 | |||
87 | SCL_LO; | ||
88 | DELAY_LO; | ||
89 | |||
90 | SDA_HI; | ||
91 | SDA_OUTPUT; | ||
92 | DELAY_LO; | ||
93 | |||
94 | return ret; | ||
95 | } | ||
96 | |||
97 | |||
98 | |||
99 | static void sc606_i2c_outb(unsigned char byte) | ||
100 | { | ||
101 | int i; | ||
102 | |||
103 | /* clock out each bit, MSB first */ | ||
104 | for (i = 0x80; i; i >>= 1) | ||
105 | { | ||
106 | if (i & byte) | ||
107 | { | ||
108 | SDA_HI; | ||
109 | } | ||
110 | else | ||
111 | { | ||
112 | SDA_LO; | ||
113 | } | ||
114 | DELAY; | ||
115 | |||
116 | SCL_HI; | ||
117 | DELAY_HI; | ||
118 | |||
119 | SCL_LO; | ||
120 | DELAY_LO; | ||
121 | } | ||
122 | |||
123 | SDA_HI; | ||
124 | |||
125 | } | ||
126 | |||
127 | |||
128 | |||
129 | static unsigned char sc606_i2c_inb(void) | ||
130 | { | ||
131 | int i; | ||
132 | unsigned char byte = 0; | ||
133 | |||
134 | SDA_INPUT; /* And set to input */ | ||
135 | /* clock in each bit, MSB first */ | ||
136 | for (i = 0x80; i; i >>= 1) { | ||
137 | SCL_HI; | ||
138 | |||
139 | if (SDA) | ||
140 | byte |= i; | ||
141 | |||
142 | SCL_LO; | ||
143 | } | ||
144 | SDA_OUTPUT; | ||
145 | |||
146 | sc606_i2c_ack(); | ||
147 | |||
148 | return byte; | ||
149 | } | ||
150 | |||
151 | |||
152 | |||
153 | /* returns number of acks that were bad */ | ||
154 | int sc606_write(unsigned char reg, unsigned char data) | ||
155 | { | ||
156 | int x; | ||
157 | |||
158 | sc606_i2c_start(); | ||
159 | |||
160 | sc606_i2c_outb(SLAVE_ADDRESS); | ||
161 | x = sc606_i2c_getack(); | ||
162 | |||
163 | sc606_i2c_outb(reg); | ||
164 | x += sc606_i2c_getack(); | ||
165 | |||
166 | sc606_i2c_restart(); | ||
167 | |||
168 | sc606_i2c_outb(SLAVE_ADDRESS); | ||
169 | x += sc606_i2c_getack(); | ||
170 | |||
171 | sc606_i2c_outb(data); | ||
172 | x += sc606_i2c_getack(); | ||
173 | |||
174 | sc606_i2c_stop(); | ||
175 | |||
176 | return x; | ||
177 | } | ||
178 | |||
179 | |||
180 | |||
181 | int sc606_read(unsigned char reg, unsigned char* data) | ||
182 | { | ||
183 | int x; | ||
184 | |||
185 | sc606_i2c_start(); | ||
186 | sc606_i2c_outb(SLAVE_ADDRESS); | ||
187 | x = sc606_i2c_getack(); | ||
188 | |||
189 | sc606_i2c_outb(reg); | ||
190 | x += sc606_i2c_getack(); | ||
191 | |||
192 | sc606_i2c_restart(); | ||
193 | sc606_i2c_outb(SLAVE_ADDRESS | 1); | ||
194 | x += sc606_i2c_getack(); | ||
195 | |||
196 | *data = sc606_i2c_inb(); | ||
197 | sc606_i2c_stop(); | ||
198 | |||
199 | return x; | ||
200 | } | ||
201 | |||
202 | |||
203 | |||
204 | void sc606_init(void) | ||
205 | { | ||
206 | volatile int i; | ||
207 | |||
208 | /* Set GPB2 (EN) to 1 */ | ||
209 | GPBCON = (GPBCON & ~(3<<4)) | 1<<4; | ||
210 | |||
211 | /* Turn enable line on */ | ||
212 | GPBDAT |= 1<<2; | ||
213 | /* OFF GPBDAT &= ~(1 << 2); */ | ||
214 | |||
215 | /* About 400us - needs 350us */ | ||
216 | for (i = 200; i; i--) | ||
217 | { | ||
218 | DELAY_LO; | ||
219 | } | ||
220 | |||
221 | /* Set GPH9 (SDA) and GPH10 (SCL) to 1 */ | ||
222 | GPHUP &= ~(3<<9); | ||
223 | GPHCON = (GPHCON & ~(0xF<<18)) | 5<<18; | ||
224 | } | ||
225 | |||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.h b/firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.h new file mode 100644 index 0000000000..3ea0917e86 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.h | |||
@@ -0,0 +1,28 @@ | |||
1 | #include "config.h" | ||
2 | #include "cpu.h" | ||
3 | #include <stdbool.h> | ||
4 | #include "kernel.h" | ||
5 | #include "system.h" | ||
6 | #include "logf.h" | ||
7 | #include "debug.h" | ||
8 | #include "string.h" | ||
9 | |||
10 | #define SC606_REG_A 0 | ||
11 | #define SC606_REG_B 1 | ||
12 | #define SC606_REG_C 2 | ||
13 | #define SC606_REG_CONF 3 | ||
14 | |||
15 | #define SC606_LED_A1 (1 << 0) | ||
16 | #define SC606_LED_A2 (1 << 1) | ||
17 | #define SC606_LED_B1 (1 << 2) | ||
18 | #define SC606_LED_B2 (1 << 3) | ||
19 | #define SC606_LED_C1 (1 << 4) | ||
20 | #define SC606_LED_C2 (1 << 5) | ||
21 | |||
22 | #define SC606_LOW_FREQ (1 << 6) | ||
23 | |||
24 | int sc606_write(unsigned char reg, unsigned char data); | ||
25 | |||
26 | int sc606_read(unsigned char reg, unsigned char* data); | ||
27 | |||
28 | void sc606_init(void); | ||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/system-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/system-meg-fx.c new file mode 100644 index 0000000000..b7e59e66ea --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/system-meg-fx.c | |||
@@ -0,0 +1,96 @@ | |||
1 | #include "kernel.h" | ||
2 | #include "system.h" | ||
3 | #include "panic.h" | ||
4 | |||
5 | #include "lcd.h" | ||
6 | #include <stdio.h> | ||
7 | |||
8 | const int TIMER4_MASK = (1 << 14); | ||
9 | const int LCD_MASK = (1 << 16); | ||
10 | const int DMA0_MASK = (1 << 17); | ||
11 | const int DMA1_MASK = (1 << 18); | ||
12 | const int DMA2_MASK = (1 << 19); | ||
13 | const int DMA3_MASK = (1 << 20); | ||
14 | |||
15 | int system_memory_guard(int newmode) | ||
16 | { | ||
17 | (void)newmode; | ||
18 | return 0; | ||
19 | } | ||
20 | |||
21 | extern void timer4(void); | ||
22 | extern void dma0(void); | ||
23 | extern void dma1(void); | ||
24 | extern void dma3(void); | ||
25 | |||
26 | void irq(void) | ||
27 | { | ||
28 | int intpending = INTPND; | ||
29 | |||
30 | SRCPND = intpending; /* Clear this interrupt. */ | ||
31 | INTPND = intpending; /* Clear this interrupt. */ | ||
32 | |||
33 | /* Timer 4 */ | ||
34 | if ((intpending & TIMER4_MASK) != 0) | ||
35 | timer4(); | ||
36 | else if ((intpending & DMA0_MASK) != 0) | ||
37 | dma0(); | ||
38 | else | ||
39 | { | ||
40 | /* unexpected interrupt */ | ||
41 | } | ||
42 | } | ||
43 | |||
44 | void system_reboot(void) | ||
45 | { | ||
46 | WTCON = 0; | ||
47 | WTCNT = WTDAT = 1 ; | ||
48 | WTCON = 0x21; | ||
49 | for(;;) | ||
50 | ; | ||
51 | } | ||
52 | |||
53 | void system_init(void) | ||
54 | { | ||
55 | /* Turn off un-needed devices */ | ||
56 | |||
57 | /* Turn off all of the UARTS */ | ||
58 | CLKCON &= ~( (1<<10) | (1<<11) |(1<<12) ); | ||
59 | |||
60 | /* Turn off AC97 and Camera */ | ||
61 | CLKCON &= ~( (1<<19) | (1<<20) ); | ||
62 | |||
63 | /* Turn off USB host */ | ||
64 | CLKCON &= ~(1 << 6); | ||
65 | |||
66 | /* Turn off NAND flash controller */ | ||
67 | CLKCON &= ~(1 << 4); | ||
68 | |||
69 | } | ||
70 | |||
71 | |||
72 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | ||
73 | |||
74 | void set_cpu_frequency(long frequency) | ||
75 | { | ||
76 | if (frequency == CPUFREQ_MAX) | ||
77 | { | ||
78 | asm volatile("mov r0, #0\n" | ||
79 | "mrc p15, 0, r0, c1, c0, 0\n" | ||
80 | "orr r0, r0, #3<<30\n" /* set to Asynchronous mode*/ | ||
81 | "mcr p15, 0, r0, c1, c0, 0" : : : "r0"); | ||
82 | |||
83 | FREQ = CPUFREQ_MAX; | ||
84 | } | ||
85 | else | ||
86 | { | ||
87 | asm volatile("mov r0, #0\n" | ||
88 | "mrc p15, 0, r0, c1, c0, 0\n" | ||
89 | "bic r0, r0, #3<<30\n" /* set to FastBus mode*/ | ||
90 | "mcr p15, 0, r0, c1, c0, 0" : : : "r0"); | ||
91 | |||
92 | FREQ = CPUFREQ_NORMAL; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | #endif | ||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/system-target.h b/firmware/target/arm/s3c2440/gigabeat-fx/system-target.h new file mode 100644 index 0000000000..215b5a4daa --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/system-target.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Greg White | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #ifndef SYSTEM_TARGET_H | ||
20 | #define SYSTEM_TARGET_H | ||
21 | |||
22 | #include "mmu-meg-fx.h" | ||
23 | #include "system-arm.h" | ||
24 | |||
25 | #define CPUFREQ_DEFAULT 98784000 | ||
26 | #define CPUFREQ_NORMAL 98784000 | ||
27 | #define CPUFREQ_MAX 296352000 | ||
28 | |||
29 | #define HAVE_INVALIDATE_ICACHE | ||
30 | static inline void invalidate_icache(void) | ||
31 | { | ||
32 | clean_dcache(); | ||
33 | asm volatile( | ||
34 | "mov r0, #0 \n" | ||
35 | "mcr p15, 0, r0, c7, c5, 0 \n" | ||
36 | : : : "r0" | ||
37 | ); | ||
38 | } | ||
39 | |||
40 | #endif /* SYSTEM_TARGET_H */ | ||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/usb-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/usb-meg-fx.c new file mode 100644 index 0000000000..3aed8c3256 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/usb-meg-fx.c | |||
@@ -0,0 +1,94 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006 by Linus Nielsen Feltzing | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #include "config.h" | ||
20 | #include <stdbool.h> | ||
21 | #include "cpu.h" | ||
22 | #include "system.h" | ||
23 | #include "kernel.h" | ||
24 | #include "ata.h" | ||
25 | |||
26 | #define USB_RST_ASSERT GPBDAT &= ~(1 << 4) | ||
27 | #define USB_RST_DEASSERT GPBDAT |= (1 << 4) | ||
28 | |||
29 | #define USB_VPLUS_PWR_ASSERT GPBDAT |= (1 << 6) | ||
30 | #define USB_VPLUS_PWR_DEASSERT GPBDAT &= ~(1 << 6) | ||
31 | |||
32 | #define USB_UNIT_IS_PRESENT !(GPFDAT & 0x01) | ||
33 | #define USB_CRADLE_IS_PRESENT ((GPFDAT &0x02)&&!(GPGDAT&1<<14)) | ||
34 | |||
35 | #define USB_CRADLE_BUS_ENABLE GPHDAT |= (1 << 8) | ||
36 | #define USB_CRADLE_BUS_DISABLE GPHDAT &= ~(1 << 8) | ||
37 | |||
38 | /* The usb detect is one pin to the cpu active low */ | ||
39 | inline bool usb_detect(void) | ||
40 | { | ||
41 | return USB_UNIT_IS_PRESENT | USB_CRADLE_IS_PRESENT; | ||
42 | } | ||
43 | |||
44 | void usb_init_device(void) | ||
45 | { | ||
46 | /* Input is the default configuration, only pullups need to be disabled */ | ||
47 | GPFUP|=0x02; | ||
48 | |||
49 | USB_VPLUS_PWR_ASSERT; | ||
50 | GPBCON=( GPBCON&~(1<<13) ) | (1 << 12); | ||
51 | |||
52 | sleep(HZ/20); | ||
53 | |||
54 | /* Reset the usb port */ | ||
55 | USB_RST_ASSERT; | ||
56 | GPBCON = (GPBCON & ~0x200) | 0x100; /* Make sure reset line is an output */ | ||
57 | |||
58 | sleep(HZ/25); | ||
59 | USB_RST_DEASSERT; | ||
60 | |||
61 | /* needed to complete the reset */ | ||
62 | ata_enable(false); | ||
63 | |||
64 | sleep(HZ/15); /* 66ms */ | ||
65 | |||
66 | ata_enable(true); | ||
67 | |||
68 | sleep(HZ/25); | ||
69 | |||
70 | /* leave chip in low power mode */ | ||
71 | USB_VPLUS_PWR_DEASSERT; | ||
72 | |||
73 | sleep(HZ/25); | ||
74 | } | ||
75 | |||
76 | void usb_enable(bool on) | ||
77 | { | ||
78 | if (on) | ||
79 | { | ||
80 | USB_VPLUS_PWR_ASSERT; | ||
81 | if(USB_CRADLE_IS_PRESENT) USB_CRADLE_BUS_ENABLE; | ||
82 | } | ||
83 | else | ||
84 | { | ||
85 | if(USB_CRADLE_IS_PRESENT) USB_CRADLE_BUS_DISABLE; | ||
86 | USB_VPLUS_PWR_DEASSERT; | ||
87 | } | ||
88 | |||
89 | /* Make sure USB_CRADLE_BUS pin is an output */ | ||
90 | GPHCON=( GPHCON&~(1<<17) ) | (1<<16); /* Make the pin an output */ | ||
91 | GPHUP|=1<<8; /* Disable pullup in SOC as we are now driving */ | ||
92 | |||
93 | sleep(HZ/20); // > 50ms for detecting the enable state change | ||
94 | } | ||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/usb-target.h b/firmware/target/arm/s3c2440/gigabeat-fx/usb-target.h new file mode 100644 index 0000000000..baeb539b38 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/usb-target.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006 by Linus Nielsen Feltzing | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #ifndef USB_TARGET_H | ||
20 | #define USB_TARGET_H | ||
21 | |||
22 | bool usb_init_device(void); | ||
23 | bool usb_detect(void); | ||
24 | void usb_enable(bool on); | ||
25 | |||
26 | #endif | ||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c new file mode 100644 index 0000000000..fe42b7527a --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c | |||
@@ -0,0 +1,71 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Gigabeat specific code for the Wolfson codec | ||
11 | * | ||
12 | * Based on code from the ipodlinux project - http://ipodlinux.org/ | ||
13 | * Adapted for Rockbox in December 2005 | ||
14 | * | ||
15 | * Original file: linux/arch/armnommu/mach-ipod/audio.c | ||
16 | * | ||
17 | * Copyright (c) 2003-2005 Bernard Leach (leachbj@bouncycastle.org) | ||
18 | * | ||
19 | * All files in this archive are subject to the GNU General Public License. | ||
20 | * See the file COPYING in the source tree root for full license agreement. | ||
21 | * | ||
22 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
23 | * KIND, either express or implied. | ||
24 | * | ||
25 | ****************************************************************************/ | ||
26 | #include "lcd.h" | ||
27 | #include "cpu.h" | ||
28 | #include "kernel.h" | ||
29 | #include "thread.h" | ||
30 | #include "power.h" | ||
31 | #include "debug.h" | ||
32 | #include "system.h" | ||
33 | #include "sprintf.h" | ||
34 | #include "button.h" | ||
35 | #include "string.h" | ||
36 | #include "file.h" | ||
37 | #include "buffer.h" | ||
38 | #include "audio.h" | ||
39 | #include "i2c.h" | ||
40 | #include "i2c-meg-fx.h" | ||
41 | /* | ||
42 | * Reset the I2S BIT.FORMAT I2S, 16bit, FIFO.FORMAT 32bit | ||
43 | */ | ||
44 | void i2s_reset(void) | ||
45 | { | ||
46 | } | ||
47 | |||
48 | /* | ||
49 | * Initialise the WM8975 for playback via headphone and line out. | ||
50 | * Note, I'm using the WM8750 datasheet as its apparently close. | ||
51 | */ | ||
52 | int audiohw_init(void) { | ||
53 | /* reset I2C */ | ||
54 | i2c_init(); | ||
55 | |||
56 | /* GPC5 controls headphone output */ | ||
57 | GPCCON &= ~(0x3 << 10); | ||
58 | GPCCON |= (1 << 10); | ||
59 | GPCDAT |= (1 << 5); | ||
60 | |||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | void audiohw_postinit(void) | ||
65 | { | ||
66 | } | ||
67 | |||
68 | void wmcodec_write(int reg, int data) | ||
69 | { | ||
70 | i2c_send(0x34, (reg<<1) | ((data&0x100)>>8), data&0xff); | ||
71 | } | ||