diff options
author | Marcin Bukat <marcin.bukat@gmail.com> | 2011-05-30 21:10:37 +0000 |
---|---|---|
committer | Marcin Bukat <marcin.bukat@gmail.com> | 2011-05-30 21:10:37 +0000 |
commit | 976a1699da373f01dabc9353b34aef261ebf740f (patch) | |
tree | 5f1649ceb51d603471e6b1cf5dcb5192626897d6 /firmware/target/arm | |
parent | 8a5a2b82fd2d35e3eb7afa8f0dc875e3874988bb (diff) | |
download | rockbox-976a1699da373f01dabc9353b34aef261ebf740f.tar.gz rockbox-976a1699da373f01dabc9353b34aef261ebf740f.zip |
Rockchip rk27xx port initial commit. This is still work in progress.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29935 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm')
21 files changed, 2561 insertions, 1 deletions
diff --git a/firmware/target/arm/rk27xx/adc-rk27xx.c b/firmware/target/arm/rk27xx/adc-rk27xx.c new file mode 100644 index 0000000000..c8bbae7514 --- /dev/null +++ b/firmware/target/arm/rk27xx/adc-rk27xx.c | |||
@@ -0,0 +1,47 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 Marcin Bukat | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include "config.h" | ||
23 | #include "cpu.h" | ||
24 | #include "system.h" | ||
25 | #include "kernel.h" | ||
26 | #include "thread.h" | ||
27 | #include "adc.h" | ||
28 | |||
29 | unsigned int adc_scan(int channel) | ||
30 | { | ||
31 | ADC_CTRL = (1<<4) | (1<<3) | (channel & (NUM_ADC_CHANNELS - 1)); | ||
32 | |||
33 | /* wait for conversion ready ~10us */ | ||
34 | while (ADC_STAT & 0x01); | ||
35 | |||
36 | /* 10bits result */ | ||
37 | return (ADC_DATA & 0x3ff); | ||
38 | } | ||
39 | |||
40 | void adc_init(void) | ||
41 | { | ||
42 | /* ADC clock divider to reach max 1MHz */ | ||
43 | SCU_DIVCON1 = (SCU_DIVCON1 & ~(0xff<<10)) | (49<<10); | ||
44 | |||
45 | /* enable clocks for ADC */ | ||
46 | SCU_CLKCFG |= 3<<23; | ||
47 | } | ||
diff --git a/firmware/target/arm/rk27xx/adc-target.h b/firmware/target/arm/rk27xx/adc-target.h new file mode 100644 index 0000000000..f6b8c98bb9 --- /dev/null +++ b/firmware/target/arm/rk27xx/adc-target.h | |||
@@ -0,0 +1,33 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 by Marcin Bukat | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #ifndef _ADC_TARGET_H_ | ||
22 | #define _ADC_TARGET_H_ | ||
23 | |||
24 | #define NUM_ADC_CHANNELS 4 | ||
25 | |||
26 | #define ADC_BATTERY 0 | ||
27 | #define ADC_UNKNOWN_1 1 | ||
28 | #define ADC_UNKNOWN_2 2 | ||
29 | #define ADC_VREF 3 /* that is what datasheet says */ | ||
30 | |||
31 | #define ADC_UNREG_POWER ADC_BATTERY /* For compatibility */ | ||
32 | |||
33 | #endif | ||
diff --git a/firmware/target/arm/rk27xx/ata-nand-rk27xx.c b/firmware/target/arm/rk27xx/ata-nand-rk27xx.c new file mode 100644 index 0000000000..dad49d48d2 --- /dev/null +++ b/firmware/target/arm/rk27xx/ata-nand-rk27xx.c | |||
@@ -0,0 +1,118 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2007 Dave Chapman | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include "config.h" | ||
22 | #include "system.h" | ||
23 | #include <string.h> | ||
24 | #include "thread.h" | ||
25 | #include "disk.h" | ||
26 | #include "storage.h" | ||
27 | #include "panic.h" | ||
28 | #include "usb.h" | ||
29 | #include "ftl-target.h" | ||
30 | #include "nand-target.h" | ||
31 | |||
32 | /* This file provides only STUBS for now */ | ||
33 | |||
34 | /** static, private data **/ | ||
35 | static bool initialized = false; | ||
36 | |||
37 | /* API Functions */ | ||
38 | int nand_read_sectors(IF_MD2(int drive,) unsigned long start, int incount, | ||
39 | void* inbuf) | ||
40 | { | ||
41 | (void)drive; | ||
42 | return ftl_read(start, incount, inbuf); | ||
43 | } | ||
44 | |||
45 | int nand_write_sectors(IF_MD2(int drive,) unsigned long start, int count, | ||
46 | const void* outbuf) | ||
47 | { | ||
48 | (void)drive; | ||
49 | return ftl_write(start, count, outbuf); | ||
50 | } | ||
51 | |||
52 | void nand_spindown(int seconds) | ||
53 | { | ||
54 | (void)seconds; | ||
55 | } | ||
56 | |||
57 | void nand_sleep(void) | ||
58 | { | ||
59 | nand_power_down(); | ||
60 | } | ||
61 | |||
62 | void nand_sleepnow(void) | ||
63 | { | ||
64 | nand_power_down(); | ||
65 | } | ||
66 | |||
67 | void nand_spin(void) | ||
68 | { | ||
69 | nand_set_active(); | ||
70 | } | ||
71 | |||
72 | void nand_enable(bool on) | ||
73 | { | ||
74 | (void)on; | ||
75 | } | ||
76 | |||
77 | void nand_get_info(IF_MD2(int drive,) struct storage_info *info) | ||
78 | { | ||
79 | (void)drive; | ||
80 | uint32_t ppb = ftl_banks * (*ftl_nand_type).pagesperblock; | ||
81 | (*info).sector_size = SECTOR_SIZE; | ||
82 | (*info).num_sectors = (*ftl_nand_type).userblocks * ppb; | ||
83 | (*info).vendor = "Apple"; | ||
84 | (*info).product = "iPod Nano 2G"; | ||
85 | (*info).revision = "1.0"; | ||
86 | } | ||
87 | |||
88 | long nand_last_disk_activity(void) | ||
89 | { | ||
90 | return nand_last_activity(); | ||
91 | } | ||
92 | |||
93 | #ifdef HAVE_STORAGE_FLUSH | ||
94 | int nand_flush(void) | ||
95 | { | ||
96 | int rc = ftl_sync(); | ||
97 | if (rc != 0) panicf("Failed to unmount flash: %X", rc); | ||
98 | return rc; | ||
99 | } | ||
100 | #endif | ||
101 | |||
102 | int nand_init(void) | ||
103 | { | ||
104 | if (ftl_init()) return 1; | ||
105 | |||
106 | initialized = true; | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | #ifdef CONFIG_STORAGE_MULTI | ||
111 | int nand_num_drives(int first_drive) | ||
112 | { | ||
113 | /* We don't care which logical drive number(s) we have been assigned */ | ||
114 | (void)first_drive; | ||
115 | |||
116 | return 1; | ||
117 | } | ||
118 | #endif | ||
diff --git a/firmware/target/arm/rk27xx/backlight-rk27xx.c b/firmware/target/arm/rk27xx/backlight-rk27xx.c new file mode 100644 index 0000000000..0d871924ea --- /dev/null +++ b/firmware/target/arm/rk27xx/backlight-rk27xx.c | |||
@@ -0,0 +1,86 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 by Marcin Bukat | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include <stdbool.h> | ||
22 | |||
23 | #include "config.h" | ||
24 | #include "backlight.h" | ||
25 | #include "backlight-target.h" | ||
26 | #include "system.h" | ||
27 | |||
28 | bool _backlight_init(void) | ||
29 | { | ||
30 | /* configure PD4 as output */ | ||
31 | GPIO_PDCON |= (1<<4); | ||
32 | |||
33 | /* set PD4 low (backlight off) */ | ||
34 | GPIO_PDDR &= ~(1<<4); | ||
35 | |||
36 | /* IOMUXB - set PWM0 pin as GPIO */ | ||
37 | SCU_IOMUXB_CON &= ~(1 << 11); /* type<<11<<channel */ | ||
38 | |||
39 | /* setup pwm */ | ||
40 | PWMT0_CTRL = (0<<9) | (1<<7); | ||
41 | |||
42 | /* set pwm frequency ~10kHz */ | ||
43 | /* (apb_freq/pwm_freq)/pwm_div = (50 000 000/10 000)/2 */ | ||
44 | PWMT0_LRC = 2500; | ||
45 | PWMT0_HRC = 1; | ||
46 | |||
47 | PWMT0_CNTR = 0x00; | ||
48 | PWMT0_CTRL = (0<<9) | (1<<3) | (1<<0); | ||
49 | |||
50 | return true; | ||
51 | } | ||
52 | |||
53 | void _backlight_on(void) | ||
54 | { | ||
55 | /* enable PWM clock */ | ||
56 | SCU_CLKCFG &= ~(1<<29); | ||
57 | |||
58 | /* set output pin as PWM pin */ | ||
59 | SCU_IOMUXB_CON |= (1<<11); /* type<<11<<channel */ | ||
60 | |||
61 | /* 100% duty cycle. Other settings doesn't work for | ||
62 | * unknown reason | ||
63 | */ | ||
64 | PWMT0_HRC = PWMT0_LRC; | ||
65 | |||
66 | /* pwm enable */ | ||
67 | PWMT0_CTRL |= (1<<3) | (1<<0); | ||
68 | } | ||
69 | |||
70 | void _backlight_off(void) | ||
71 | { | ||
72 | /* setup PWM0 pin as GPIO which is pulled low */ | ||
73 | SCU_IOMUXB_CON &= ~(1<<11); | ||
74 | |||
75 | /* stop pwm timer */ | ||
76 | PWMT0_CTRL &= ~(1<<3) | (1<<0); | ||
77 | |||
78 | /* disable PWM clock */ | ||
79 | SCU_CLKCFG |= (1<<29); | ||
80 | } | ||
81 | |||
82 | void _backlight_set_brightness(int brightness) | ||
83 | { | ||
84 | (void)brightness; | ||
85 | /* doesn't work for unknown reason */ | ||
86 | } | ||
diff --git a/firmware/target/arm/rk27xx/backlight-target.h b/firmware/target/arm/rk27xx/backlight-target.h new file mode 100644 index 0000000000..91579b080d --- /dev/null +++ b/firmware/target/arm/rk27xx/backlight-target.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2008 by Marcoen Hirschberg | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #ifndef BACKLIGHT_TARGET_H | ||
22 | #define BACKLIGHT_TARGET_H | ||
23 | |||
24 | bool _backlight_init(void); | ||
25 | void _backlight_on(void); | ||
26 | void _backlight_off(void); | ||
27 | void _backlight_set_brightness(int brightness); | ||
28 | |||
29 | #endif | ||
diff --git a/firmware/target/arm/rk27xx/boot.lds b/firmware/target/arm/rk27xx/boot.lds new file mode 100644 index 0000000000..b7bc9beac0 --- /dev/null +++ b/firmware/target/arm/rk27xx/boot.lds | |||
@@ -0,0 +1,81 @@ | |||
1 | #include "config.h" | ||
2 | |||
3 | ENTRY(start) | ||
4 | #ifdef ROCKBOX_LITTLE_ENDIAN | ||
5 | OUTPUT_FORMAT(elf32-littlearm) | ||
6 | #else | ||
7 | OUTPUT_FORMAT(elf32-bigarm) | ||
8 | #endif | ||
9 | OUTPUT_ARCH(arm) | ||
10 | STARTUP(target/arm/rk27xx/crt0.o) | ||
11 | |||
12 | #define DRAMORIG 0x60000000 | ||
13 | #define DRAMSIZE (MEMORYSIZE * 0x100000) | ||
14 | |||
15 | #define IRAMORIG 0x00000000 | ||
16 | #define IRAMSIZE 4K | ||
17 | |||
18 | MEMORY | ||
19 | { | ||
20 | DRAM : ORIGIN = DRAMORIG, LENGTH = DRAMSIZE | ||
21 | IRAM : ORIGIN = IRAMORIG, LENGTH = IRAMSIZE | ||
22 | } | ||
23 | |||
24 | SECTIONS | ||
25 | { | ||
26 | .intvect : { | ||
27 | _intvectstart = . ; | ||
28 | *(.intvect) | ||
29 | _intvectend = _newstart ; | ||
30 | } > IRAM AT > DRAM | ||
31 | _intvectcopy = LOADADDR(.intvect) ; | ||
32 | |||
33 | .text : { | ||
34 | *(.init.text) | ||
35 | *(.text*) | ||
36 | *(.glue_7*) | ||
37 | } > DRAM | ||
38 | |||
39 | .data : { | ||
40 | *(.rodata*) | ||
41 | *(.data*) | ||
42 | *(.ncdata*); | ||
43 | . = ALIGN(0x4); | ||
44 | } > DRAM | ||
45 | |||
46 | .idata : { | ||
47 | _datastart = . ; | ||
48 | *(.irodata) | ||
49 | *(.icode) | ||
50 | *(.idata) | ||
51 | . = ALIGN(0x4); | ||
52 | _dataend = . ; | ||
53 | } > DRAM | ||
54 | _datacopy = LOADADDR(.idata) ; | ||
55 | |||
56 | .stack (NOLOAD) : | ||
57 | { | ||
58 | *(.stack) | ||
59 | _stackbegin = .; | ||
60 | stackbegin = .; | ||
61 | . += 0x2000; | ||
62 | _stackend = .; | ||
63 | stackend = .; | ||
64 | _irqstackbegin = .; | ||
65 | . += 0x400; | ||
66 | _irqstackend = .; | ||
67 | _fiqstackbegin = .; | ||
68 | . += 0x400; | ||
69 | _fiqstackend = .; | ||
70 | } > DRAM | ||
71 | |||
72 | .bss (NOLOAD) : { | ||
73 | _edata = .; | ||
74 | *(.bss*); | ||
75 | *(.ibss); | ||
76 | *(.ncbss*); | ||
77 | *(COMMON); | ||
78 | . = ALIGN(0x4); | ||
79 | _end = .; | ||
80 | } > DRAM | ||
81 | } | ||
diff --git a/firmware/target/arm/rk27xx/crt0.S b/firmware/target/arm/rk27xx/crt0.S new file mode 100644 index 0000000000..032c637458 --- /dev/null +++ b/firmware/target/arm/rk27xx/crt0.S | |||
@@ -0,0 +1,209 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: crt0.S 18776 2008-10-11 18:32:17Z gevaerts $ | ||
9 | * | ||
10 | * Copyright (C) 2008 by Marcoen Hirschberg | ||
11 | * Copyright (C) 2008 by Denes Balatoni | ||
12 | * Copyright (C) 2010 by Marcin Bukat | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | #define ASM | ||
24 | #include "config.h" | ||
25 | #include "cpu.h" | ||
26 | |||
27 | .section .intvect,"ax",%progbits | ||
28 | .global start | ||
29 | .global _newstart | ||
30 | /* Exception vectors */ | ||
31 | start: | ||
32 | b _newstart | ||
33 | ldr pc, =undef_instr_handler | ||
34 | ldr pc, =software_int_handler | ||
35 | ldr pc, =prefetch_abort_handler | ||
36 | ldr pc, =data_abort_handler | ||
37 | ldr pc, =reserved_handler | ||
38 | ldr pc, =irq_handler | ||
39 | ldr pc, =fiq_handler | ||
40 | .ltorg | ||
41 | _newstart: | ||
42 | ldr pc, =newstart2 | ||
43 | .section .init.text,"ax",%progbits | ||
44 | newstart2: | ||
45 | msr cpsr_c, #0xd3 /* enter supervisor mode, disable IRQ/FIQ */ | ||
46 | |||
47 | mov r0, #0x18000000 | ||
48 | add r0, r0, #0x1c000 | ||
49 | |||
50 | /* setup ARM core freq = 200MHz */ | ||
51 | /* AHB bus freq (HCLK) = 100MHz */ | ||
52 | /* APB bus freq (PCLK) = 50MHz */ | ||
53 | ldr r1, [r0,#0x14] /* SCU_DIVCON1 */ | ||
54 | orr r1, #9 /* ARM slow mode, HCLK:PCLK = 2:1 */ | ||
55 | str r1, [r0,#0x14] | ||
56 | |||
57 | ldr r1,=0x01970c70 /* (1<<24) | (1<<23) | (23<<16) | (199<<4) */ | ||
58 | str r1, [r0,#0x08] | ||
59 | |||
60 | ldr r2,=0x40000 | ||
61 | 1: | ||
62 | ldr r1, [r0,#0x2c] /* SCU_STATUS */ | ||
63 | tst r1, #1 /* ARM pll lock */ | ||
64 | bne 1f | ||
65 | subs r2, #1 | ||
66 | bne 1b | ||
67 | 1: | ||
68 | ldr r1, [r0,#0x14] /* SCU_DIVCON1 */ | ||
69 | bic r1, #5 /* leave ARM slow mode, ARMclk:HCLK = 2:1 */ | ||
70 | str r1, [r0,#0x14] | ||
71 | |||
72 | #if defined(BOOTLOADER) | ||
73 | /* remap iram to 0x00000000 */ | ||
74 | ldr r1,=0xdeadbeef | ||
75 | str r1, [r0, #4] | ||
76 | #endif | ||
77 | |||
78 | #if 0 | ||
79 | /* setup caches */ | ||
80 | ldr r0, =0xefff0000 /* cache controler base address */ | ||
81 | ldrh r1, [r0] | ||
82 | strh r1, [r0] /* global cache disable */ | ||
83 | |||
84 | /* setup uncached regions */ | ||
85 | mov r1, #0x18000000 | ||
86 | orr r1, r1, #0xfe | ||
87 | str r1, [r0,#0x10] /* MemMapA BUS0IP, 32MB */ | ||
88 | str r1, [r0,#0x14] /* MemMapB BUS0IP, 32MB */ | ||
89 | mov r1, #0x30000000 | ||
90 | orr r1, r1, #0xfe | ||
91 | str r1, [r0,#0x18] /* MemMapC DSPMEM, 32MB */ | ||
92 | mov r1, #0xee000000 /* 0xefff0000 & 0xfe000000 */ | ||
93 | orr r1, r1, #0xfe | ||
94 | str r1, [r0,#0x1c] /* MemMapD cache controller, 32MB */ | ||
95 | |||
96 | mov r1, #2 /* invalidate way opcode */ | ||
97 | str r1, [r0,#4] /* invalidate way0 */ | ||
98 | 1: | ||
99 | ldr r2, [r0,#4] | ||
100 | tst r2, #3 | ||
101 | bne 1b /* wait for invalidate to complete */ | ||
102 | |||
103 | orr r1, r1, #0x80000000 | ||
104 | str r1, [r0,#4] /* invalidate way1 */ | ||
105 | 1: | ||
106 | ldr r2, [r0,#4] | ||
107 | tst r2, #3 | ||
108 | bne 1b /* wait for invalidate to complete */ | ||
109 | |||
110 | ldr r1, [r0] | ||
111 | orr r1, r1, #0x80000000 | ||
112 | str r1, [r0] /* global cache enable */ | ||
113 | #endif | ||
114 | |||
115 | /* Copy interrupt vectors to iram */ | ||
116 | ldr r2, =_intvectstart | ||
117 | ldr r3, =_intvectend | ||
118 | ldr r4, =_intvectcopy | ||
119 | 1: | ||
120 | cmp r3, r2 | ||
121 | ldrhi r1, [r4], #4 | ||
122 | strhi r1, [r2], #4 | ||
123 | bhi 1b | ||
124 | |||
125 | /* Initialise bss section to zero */ | ||
126 | ldr r2, =_edata | ||
127 | ldr r3, =_end | ||
128 | mov r4, #0 | ||
129 | 1: | ||
130 | cmp r3, r2 | ||
131 | strhi r4, [r2], #4 | ||
132 | bhi 1b | ||
133 | |||
134 | #ifndef BOOTLOADER | ||
135 | /* Copy icode and data to ram */ | ||
136 | ldr r2, =_iramstart | ||
137 | ldr r3, =_iramend | ||
138 | ldr r4, =_iramcopy | ||
139 | 1: | ||
140 | cmp r3, r2 | ||
141 | ldrhi r1, [r4], #4 | ||
142 | strhi r1, [r2], #4 | ||
143 | bhi 1b | ||
144 | |||
145 | /* Initialise ibss section to zero */ | ||
146 | ldr r2, =_iedata | ||
147 | ldr r3, =_iend | ||
148 | mov r4, #0 | ||
149 | 1: | ||
150 | cmp r3, r2 | ||
151 | strhi r4, [r2], #4 | ||
152 | bhi 1b | ||
153 | #endif | ||
154 | |||
155 | /* Set up some stack and munge it with 0xdeadbeef */ | ||
156 | ldr sp, =stackend | ||
157 | ldr r2, =stackbegin | ||
158 | ldr r3, =0xdeadbeef | ||
159 | 1: | ||
160 | cmp sp, r2 | ||
161 | strhi r3, [r2], #4 | ||
162 | bhi 1b | ||
163 | |||
164 | /* Set up stack for IRQ mode */ | ||
165 | msr cpsr_c, #0xd2 | ||
166 | ldr sp, =_irqstackend | ||
167 | |||
168 | /* Set up stack for FIQ mode */ | ||
169 | msr cpsr_c, #0xd1 | ||
170 | ldr sp, =_fiqstackend | ||
171 | |||
172 | /* Let abort and undefined modes use IRQ stack */ | ||
173 | msr cpsr_c, #0xd7 | ||
174 | ldr sp, =_irqstackend | ||
175 | msr cpsr_c, #0xdb | ||
176 | ldr sp, =_irqstackend | ||
177 | |||
178 | /* Switch back to supervisor mode */ | ||
179 | msr cpsr_c, #0xd3 | ||
180 | |||
181 | bl main | ||
182 | |||
183 | .text | ||
184 | /* .global UIE*/ | ||
185 | |||
186 | /* All illegal exceptions call into UIE with exception address as first | ||
187 | * parameter. This is calculated differently depending on which exception | ||
188 | * we're in. Second parameter is exception number, used for a string lookup | ||
189 | * in UIE. */ | ||
190 | undef_instr_handler: | ||
191 | sub r0, lr, #4 | ||
192 | mov r1, #0 | ||
193 | b UIE | ||
194 | |||
195 | /* We run supervisor mode most of the time, and should never see a software | ||
196 | * exception being thrown. Perhaps make it illegal and call UIE? */ | ||
197 | software_int_handler: | ||
198 | reserved_handler: | ||
199 | movs pc, lr | ||
200 | |||
201 | prefetch_abort_handler: | ||
202 | sub r0, lr, #4 | ||
203 | mov r1, #1 | ||
204 | b UIE | ||
205 | |||
206 | data_abort_handler: | ||
207 | sub r0, lr, #8 | ||
208 | mov r1, #2 | ||
209 | b UIE | ||
diff --git a/firmware/target/arm/rk27xx/ftl-rk27xx.c b/firmware/target/arm/rk27xx/ftl-rk27xx.c new file mode 100644 index 0000000000..40248ab6f3 --- /dev/null +++ b/firmware/target/arm/rk27xx/ftl-rk27xx.c | |||
@@ -0,0 +1,56 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2010 by Bertrik Sikken | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include "config.h" | ||
23 | #include "ftl-target.h" | ||
24 | |||
25 | /* this file provides empty STUBS for now */ | ||
26 | |||
27 | uint32_t ftl_init(void) | ||
28 | { | ||
29 | /* TODO implement */ | ||
30 | return 0; | ||
31 | } | ||
32 | |||
33 | uint32_t ftl_read(uint32_t sector, uint32_t count, void* buffer) | ||
34 | { | ||
35 | /* TODO implement */ | ||
36 | (void)sector; | ||
37 | (void)count; | ||
38 | (void)buffer; | ||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | uint32_t ftl_write(uint32_t sector, uint32_t count, const void* buffer) | ||
43 | { | ||
44 | /* TODO implement */ | ||
45 | (void)sector; | ||
46 | (void)count; | ||
47 | (void)buffer; | ||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | uint32_t ftl_sync(void) | ||
52 | { | ||
53 | /* TODO implement */ | ||
54 | return 0; | ||
55 | } | ||
56 | |||
diff --git a/firmware/target/arm/rk27xx/ftl-target.h b/firmware/target/arm/rk27xx/ftl-target.h new file mode 100644 index 0000000000..ad4dc04db1 --- /dev/null +++ b/firmware/target/arm/rk27xx/ftl-target.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2009 by Michael Sparmann | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #ifndef __FTL_TARGET_H__ | ||
23 | #define __FTL_TARGET_H__ | ||
24 | |||
25 | #include "config.h" | ||
26 | #include "inttypes.h" | ||
27 | |||
28 | #ifdef BOOTLOADER | ||
29 | /* Bootloaders don't need write access */ | ||
30 | #define FTL_READONLY | ||
31 | #endif | ||
32 | |||
33 | /* Pointer to an info structure regarding the flash type used */ | ||
34 | const struct nand_device_info_type* ftl_nand_type; | ||
35 | |||
36 | /* Number of banks we detected a chip on */ | ||
37 | uint32_t ftl_banks; | ||
38 | |||
39 | uint32_t ftl_init(void); | ||
40 | uint32_t ftl_read(uint32_t sector, uint32_t count, void* buffer); | ||
41 | uint32_t ftl_write(uint32_t sector, uint32_t count, const void* buffer); | ||
42 | uint32_t ftl_sync(void); | ||
43 | |||
44 | |||
45 | #endif | ||
diff --git a/firmware/target/arm/rk27xx/i2c-rk27xx.c b/firmware/target/arm/rk27xx/i2c-rk27xx.c new file mode 100644 index 0000000000..34a6f49a32 --- /dev/null +++ b/firmware/target/arm/rk27xx/i2c-rk27xx.c | |||
@@ -0,0 +1,242 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 by Marcin Bukat | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include "config.h" | ||
23 | #include "system.h" | ||
24 | #include "kernel.h" | ||
25 | #include "i2c-rk27xx.h" | ||
26 | |||
27 | /* NOT TESTED YET */ | ||
28 | |||
29 | /* Driver for the rockchip rk27xx built-in I2C controller in master mode | ||
30 | |||
31 | Both the i2c_read and i2c_write function take the following arguments: | ||
32 | * slave, the address of the i2c slave device to read from / write to | ||
33 | * address, optional sub-address in the i2c slave (unused if -1) | ||
34 | * len, number of bytes to be transfered | ||
35 | * data, pointer to data to be transfered | ||
36 | A return value other than 0 indicates an error. | ||
37 | */ | ||
38 | |||
39 | static struct mutex i2c_mtx; | ||
40 | |||
41 | static bool i2c_write_byte(uint8_t data, bool start) | ||
42 | { | ||
43 | long timeout = current_tick + HZ / 50; | ||
44 | |||
45 | /* START */ | ||
46 | I2C_CONR |= (1<<3) | (1<<2); /* master port enable, transmit bit */ | ||
47 | I2C_MTXR = data; | ||
48 | |||
49 | if (start) | ||
50 | I2C_LCMR = (1<<2) | (1<<0); /* resume op, start bit */ | ||
51 | else | ||
52 | I2C_LCMR = (1<<2); /* resume op */ | ||
53 | |||
54 | I2C_CONR &= ~(1<<4); /* ACK enable */ | ||
55 | |||
56 | /* wait for ACK from slave */ | ||
57 | while ( !(I2C_ISR & (1<<0)) || (I2C_LSR & (1<<0)) ) | ||
58 | if (TIME_AFTER(current_tick, timeout)) | ||
59 | return false; | ||
60 | |||
61 | /* clear status bit */ | ||
62 | I2C_ISR &= ~(1<<0); | ||
63 | |||
64 | return true; | ||
65 | } | ||
66 | |||
67 | static bool i2c_read_byte(unsigned char *data) | ||
68 | { | ||
69 | long timeout = current_tick + HZ / 50; | ||
70 | |||
71 | I2C_LCMR = (1<<2); /* resume op */ | ||
72 | |||
73 | while (I2C_ISR & (1<<1)) | ||
74 | if (TIME_AFTER(current_tick, timeout)) | ||
75 | return false; | ||
76 | |||
77 | *data = I2C_MRXR; | ||
78 | |||
79 | /* clear status bit */ | ||
80 | I2C_ISR &= ~(1<<1); | ||
81 | |||
82 | return true; | ||
83 | } | ||
84 | |||
85 | static bool i2c_stop(void) | ||
86 | { | ||
87 | long timeout = current_tick + HZ / 50; | ||
88 | |||
89 | I2C_CONR &= ~(1<<4); | ||
90 | I2C_LCMR |= (1<<2) | (1<<1); /* resume op, stop */ | ||
91 | |||
92 | while (I2C_LCMR & (1<<1)) | ||
93 | if (TIME_AFTER(current_tick, timeout)) | ||
94 | return false; | ||
95 | |||
96 | return true; | ||
97 | } | ||
98 | |||
99 | /* route i2c bus to internal codec or external bus | ||
100 | * internal codec has 0x27 i2c slave address so | ||
101 | * access to this address is routed to internal bus. | ||
102 | * All other addresses are routed to external pads | ||
103 | */ | ||
104 | static void i2c_iomux(unsigned char slave) | ||
105 | { | ||
106 | unsigned long muxa = SCU_IOMUXA_CON & ~(0x1f<<14); | ||
107 | |||
108 | if (slave == (0x27<<1)) | ||
109 | { | ||
110 | /* internal codec */ | ||
111 | SCU_IOMUXA_CON = muxa | (1<<16) | (1<<14); | ||
112 | } | ||
113 | else | ||
114 | { | ||
115 | /* external I2C bus */ | ||
116 | SCU_IOMUXA_CON = muxa | (1<<18); | ||
117 | } | ||
118 | } | ||
119 | |||
120 | void i2c_init(void) | ||
121 | { | ||
122 | mutex_init(&i2c_mtx); | ||
123 | |||
124 | SCU_CLKCFG &= ~(1<< 20); | ||
125 | |||
126 | I2C_OPR |= (1<<7); /* reset state machine */ | ||
127 | sleep(HZ/100); | ||
128 | I2C_OPR &= ~((1<<7) | (1<<6)); /* clear ENABLE bit, deasert reset */ | ||
129 | |||
130 | /* set I2C divider to stay within allowed SCL freq limit | ||
131 | * APBfreq = 50Mhz | ||
132 | * SCLfreq = (APBfreq/5*(I2CCDVR[5:3] + 1) * 2^((I2CCDVR[2:0] + 1)) | ||
133 | */ | ||
134 | I2C_OPR = (I2C_OPR & ~(0x3F)) | (6<<3) | 1<<0; | ||
135 | |||
136 | I2C_IER = 0x00; | ||
137 | |||
138 | I2C_OPR |= (1<<6); /* enable i2c core */ | ||
139 | } | ||
140 | |||
141 | int i2c_write(unsigned char slave, int address, int len, | ||
142 | const unsigned char *data) | ||
143 | { | ||
144 | mutex_lock(&i2c_mtx); | ||
145 | |||
146 | i2c_iomux(slave); | ||
147 | |||
148 | /* START */ | ||
149 | if (! i2c_write_byte(slave & ~1, true)) | ||
150 | { | ||
151 | mutex_unlock(&i2c_mtx); | ||
152 | return 1; | ||
153 | } | ||
154 | |||
155 | if (address >= 0) | ||
156 | { | ||
157 | if (! i2c_write_byte(address, false)) | ||
158 | { | ||
159 | mutex_unlock(&i2c_mtx); | ||
160 | return 2; | ||
161 | } | ||
162 | } | ||
163 | |||
164 | /* write data */ | ||
165 | while (len--) | ||
166 | { | ||
167 | if (! i2c_write_byte(*data++, false)) | ||
168 | { | ||
169 | mutex_unlock(&i2c_mtx); | ||
170 | return 4; | ||
171 | } | ||
172 | } | ||
173 | |||
174 | /* STOP */ | ||
175 | if (! i2c_stop()) | ||
176 | { | ||
177 | mutex_unlock(&i2c_mtx); | ||
178 | return 5; | ||
179 | } | ||
180 | |||
181 | mutex_unlock(&i2c_mtx); | ||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | int i2c_read(unsigned char slave, int address, int len, unsigned char *data) | ||
186 | { | ||
187 | mutex_lock(&i2c_mtx); | ||
188 | |||
189 | i2c_iomux(slave); | ||
190 | |||
191 | if (address >= 0) | ||
192 | { | ||
193 | /* START */ | ||
194 | if (! i2c_write_byte(slave & ~1, true)) | ||
195 | { | ||
196 | mutex_unlock(&i2c_mtx); | ||
197 | return 1; | ||
198 | } | ||
199 | |||
200 | /* write address */ | ||
201 | if (! i2c_write_byte(address, false)) | ||
202 | { | ||
203 | mutex_unlock(&i2c_mtx); | ||
204 | return 2; | ||
205 | } | ||
206 | } | ||
207 | |||
208 | /* (repeated) START */ | ||
209 | if (! i2c_write_byte(slave | 1, true)) | ||
210 | { | ||
211 | mutex_unlock(&i2c_mtx); | ||
212 | return 3; | ||
213 | } | ||
214 | |||
215 | I2C_CONR &= ~(1<<3); /* clear transmit bit (switch to receive mode) */ | ||
216 | |||
217 | while (len) | ||
218 | { | ||
219 | if (! i2c_read_byte(data++)) | ||
220 | { | ||
221 | mutex_unlock(&i2c_mtx); | ||
222 | return 4; | ||
223 | } | ||
224 | |||
225 | if (len == 1) | ||
226 | I2C_CONR |= (1<<4); /* NACK */ | ||
227 | else | ||
228 | I2C_CONR &= ~(1<<4); /* ACK */ | ||
229 | |||
230 | len--; | ||
231 | } | ||
232 | |||
233 | /* STOP */ | ||
234 | if (! i2c_stop()) | ||
235 | { | ||
236 | mutex_unlock(&i2c_mtx); | ||
237 | return 5; | ||
238 | } | ||
239 | |||
240 | mutex_unlock(&i2c_mtx); | ||
241 | return 0; | ||
242 | } | ||
diff --git a/firmware/target/arm/rk27xx/kernel-rk27xx.c b/firmware/target/arm/rk27xx/kernel-rk27xx.c new file mode 100644 index 0000000000..d54a09dd1f --- /dev/null +++ b/firmware/target/arm/rk27xx/kernel-rk27xx.c | |||
@@ -0,0 +1,54 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 by Marcin Bukat | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include "config.h" | ||
22 | #include "system.h" | ||
23 | #include "kernel.h" | ||
24 | |||
25 | /* rockchip rk27xx driver for the kernel timer */ | ||
26 | |||
27 | /* sys timer ISR */ | ||
28 | void INT_TIMER0(void) | ||
29 | { | ||
30 | /* clear interrupt */ | ||
31 | TMR0CON &= ~0x04; | ||
32 | |||
33 | call_tick_tasks(); /* Run through the list of tick tasks */ | ||
34 | } | ||
35 | |||
36 | /* this assumes 50MHz APB bus frequency */ | ||
37 | void tick_start(unsigned int interval_in_ms) | ||
38 | { | ||
39 | unsigned int cycles = 50000 * interval_in_ms; | ||
40 | |||
41 | /* enable timer clock */ | ||
42 | SCU_CLKCFG &= (1<<28); | ||
43 | |||
44 | /* configure timer0 */ | ||
45 | TMR0LR = cycles; | ||
46 | TMR0CON = (1<<8) | (1<<7) | (1<<1); /* periodic, 1/1, interrupt enable */ | ||
47 | |||
48 | /* unmask timer0 interrupt */ | ||
49 | INTC_IMR |= 0x04; | ||
50 | |||
51 | /* enable timer0 interrupt */ | ||
52 | INTC_IECR |= 0x04; | ||
53 | } | ||
54 | |||
diff --git a/firmware/target/arm/rk27xx/lcd-rk27xx.c b/firmware/target/arm/rk27xx/lcd-rk27xx.c new file mode 100644 index 0000000000..bb71458195 --- /dev/null +++ b/firmware/target/arm/rk27xx/lcd-rk27xx.c | |||
@@ -0,0 +1,304 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 Marcin Bukat | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include "config.h" | ||
23 | #include "kernel.h" | ||
24 | #include "lcd.h" | ||
25 | #include "system.h" | ||
26 | #include "cpu.h" | ||
27 | #include "spfd5420a.h" | ||
28 | |||
29 | static inline void delay_nop(int cycles) | ||
30 | { | ||
31 | asm volatile ("1: subs %[n], %[n], #1 \n\t" | ||
32 | " bne 1b" | ||
33 | : | ||
34 | : [n] "r" (cycles)); | ||
35 | } | ||
36 | |||
37 | static unsigned int lcd_data_transform(unsigned int data) | ||
38 | { | ||
39 | /* 18 bit interface */ | ||
40 | unsigned int r, g, b; | ||
41 | r = (data & 0x0000fc00)<<8; | ||
42 | /* g = ((data & 0x00000300) >> 2) | ((data & 0x000000e0) >> 3); */ | ||
43 | g = ((data & 0x00000300) << 6) | ((data & 0x000000e0) << 5); | ||
44 | b = (data & 0x00000001f) << 3; | ||
45 | |||
46 | return (r | g | b); | ||
47 | } | ||
48 | |||
49 | /* converts RGB565 pixel into internal lcd bus format */ | ||
50 | static unsigned int lcd_pixel_transform(unsigned short rgb565) | ||
51 | { | ||
52 | unsigned int r, g, b; | ||
53 | b = rgb565 & 0x1f; | ||
54 | g = (rgb565 >> 5) & 0x3f; | ||
55 | r = (rgb565 >> 11) & 0x1f; | ||
56 | |||
57 | return r<<19 | g<<10 | b<<3; | ||
58 | } | ||
59 | |||
60 | static void lcd_cmd(unsigned int cmd) | ||
61 | { | ||
62 | LCD_COMMAND = lcd_data_transform(cmd); | ||
63 | } | ||
64 | |||
65 | static void lcd_data(unsigned int data) | ||
66 | { | ||
67 | LCD_DATA = lcd_data_transform(data); | ||
68 | } | ||
69 | |||
70 | static void lcd_write_reg(unsigned int reg, unsigned int val) | ||
71 | { | ||
72 | lcd_cmd(reg); | ||
73 | lcd_data(val); | ||
74 | } | ||
75 | |||
76 | static void lcdctrl_bypass(unsigned int on_off) | ||
77 | { | ||
78 | while (!(LCDC_STA & LCDC_MCU_IDLE)); | ||
79 | |||
80 | if (on_off) | ||
81 | MCU_CTRL |= MCU_CTRL_BYPASS; | ||
82 | else | ||
83 | MCU_CTRL &= ~MCU_CTRL_BYPASS; | ||
84 | } | ||
85 | |||
86 | /* This part is unclear. I am unable to use buffered/FIFO based writes | ||
87 | * to lcd. Depending on settings of IF I get various patterns on display | ||
88 | * but not what I want to display apparently. | ||
89 | */ | ||
90 | static void lcdctrl_init(void) | ||
91 | { | ||
92 | /* alpha b111 | ||
93 | * stop at current frame complete | ||
94 | * MCU mode | ||
95 | * 24b RGB | ||
96 | */ | ||
97 | LCDC_CTRL = ALPHA(7) | LCDC_STOP | LCDC_MCU | RGB24B; | ||
98 | MCU_CTRL = ALPHA_BASE(0x3f) | MCU_CTRL_BYPASS; | ||
99 | |||
100 | HOR_ACT = 400 + 3; /* define horizonatal active region */ | ||
101 | VERT_ACT = 240; /* define vertical active region */ | ||
102 | VERT_PERIOD = 0xfff; /* CSn/WEn/RDn signal timings */ | ||
103 | |||
104 | LINE0_YADDR = LINE_ALPHA_EN | 0x7fe; | ||
105 | LINE1_YADDR = LINE_ALPHA_EN | ((1 * 400) - 2); | ||
106 | LINE2_YADDR = LINE_ALPHA_EN | ((2 * 400) - 2); | ||
107 | LINE3_YADDR = LINE_ALPHA_EN | ((3 * 400) - 2); | ||
108 | |||
109 | LINE0_UVADDR = 0x7fe + 1; | ||
110 | LINE1_UVADDR = ((1 * 400) - 2 + 1); | ||
111 | LINE2_UVADDR = ((2 * 400) - 2 + 1); | ||
112 | LINE3_UVADDR = ((3 * 400) - 2 + 1); | ||
113 | |||
114 | #if 0 | ||
115 | LINE0_YADDR = 0; | ||
116 | LINE1_YADDR = (1 * 400); | ||
117 | LINE2_YADDR = (2 * 400); | ||
118 | LINE3_YADDR = (3 * 400); | ||
119 | |||
120 | LINE0_UVADDR = 1; | ||
121 | LINE1_UVADDR = (1 * 400) + 1; | ||
122 | LINE2_UVADDR = (2 * 400) + 1; | ||
123 | LINE3_UVADDR = (3 * 400) + 1; | ||
124 | |||
125 | START_X = 0; | ||
126 | START_Y = 0; | ||
127 | DELTA_X = 0x200; /* no scaling */ | ||
128 | DELTA_Y = 0x200; /* no scaling */ | ||
129 | #endif | ||
130 | LCDC_INTR_MASK = INTR_MASK_LINE; /* INTR_MASK_EVENLINE; */ | ||
131 | } | ||
132 | |||
133 | /* configure pins to drive lcd in 18bit mode */ | ||
134 | static void iomux_lcd(void) | ||
135 | { | ||
136 | unsigned long muxa; | ||
137 | |||
138 | muxa = SCU_IOMUXA_CON & ~(IOMUX_LCD_VSYNC|IOMUX_LCD_DEN|0xff); | ||
139 | muxa |= IOMUX_LCD_D18|IOMUX_LCD_D20|IOMUX_LCD_D22|IOMUX_LCD_D17|IOMUX_LCD_D16; | ||
140 | |||
141 | SCU_IOMUXA_CON = muxa; | ||
142 | SCU_IOMUXB_CON |= IOMUX_LCD_D815; | ||
143 | } | ||
144 | |||
145 | /* not tested */ | ||
146 | static void lcd_sleep(unsigned int sleep) | ||
147 | { | ||
148 | if (sleep) | ||
149 | { | ||
150 | /* enter sleep mode */ | ||
151 | lcd_write_reg(DISPLAY_CTRL1, 0x0170); | ||
152 | delay_nop(50); | ||
153 | lcd_write_reg(DISPLAY_CTRL1, 0x0000); | ||
154 | delay_nop(50); | ||
155 | lcd_write_reg(PWR_CTRL1, 0x14B4); | ||
156 | } | ||
157 | else | ||
158 | { | ||
159 | /* return to normal operation */ | ||
160 | lcd_write_reg(PWR_CTRL1, 0x14B0); | ||
161 | delay_nop(50); | ||
162 | lcd_write_reg(DISPLAY_CTRL1, 0x0173); | ||
163 | } | ||
164 | |||
165 | lcd_cmd(GRAM_WRITE); | ||
166 | } | ||
167 | |||
168 | void lcd_init_device() | ||
169 | { | ||
170 | unsigned int x, y; | ||
171 | |||
172 | iomux_lcd(); /* setup pins for 18bit lcd interface */ | ||
173 | lcdctrl_init(); /* basic lcdc module configuration */ | ||
174 | |||
175 | lcdctrl_bypass(1); /* run in bypass mode - all writes goes directly to lcd controller */ | ||
176 | |||
177 | lcd_write_reg(RESET, 0x0001); | ||
178 | delay_nop(10000); | ||
179 | lcd_write_reg(RESET, 0x0000); | ||
180 | delay_nop(10000); | ||
181 | lcd_write_reg(IF_ENDIAN, 0x0000); /* order of receiving data */ | ||
182 | lcd_write_reg(DRIVER_OUT_CTRL, 0x0000); | ||
183 | lcd_write_reg(ENTRY_MODE, 0x1038); | ||
184 | lcd_write_reg(WAVEFORM_CTRL, 0x0100); | ||
185 | lcd_write_reg(SHAPENING_CTRL, 0x0000); | ||
186 | lcd_write_reg(DISPLAY_CTRL2, 0x0808); | ||
187 | lcd_write_reg(LOW_PWR_CTRL1, 0x0001); | ||
188 | lcd_write_reg(LOW_PWR_CTRL2, 0x0010); | ||
189 | lcd_write_reg(EXT_DISP_CTRL1, 0x0000); | ||
190 | lcd_write_reg(EXT_DISP_CTRL2, 0x0000); | ||
191 | lcd_write_reg(BASE_IMG_SIZE, 0x3100); | ||
192 | lcd_write_reg(BASE_IMG_CTRL, 0x0001); | ||
193 | lcd_write_reg(VSCROLL_CTRL, 0x0000); | ||
194 | lcd_write_reg(PART1_POS, 0x0000); | ||
195 | lcd_write_reg(PART1_START, 0x0000); | ||
196 | lcd_write_reg(PART1_END, 0x018F); | ||
197 | lcd_write_reg(PART2_POS, 0x0000); | ||
198 | lcd_write_reg(PART2_START, 0x0000); | ||
199 | lcd_write_reg(PART2_END, 0x0000); | ||
200 | |||
201 | lcd_write_reg(PANEL_IF_CTRL1, 0x0011); | ||
202 | delay_nop(10000); | ||
203 | lcd_write_reg(PANEL_IF_CTRL2, 0x0202); | ||
204 | lcd_write_reg(PANEL_IF_CTRL3, 0x0300); | ||
205 | delay_nop(10000); | ||
206 | lcd_write_reg(PANEL_IF_CTRL4, 0x021E); | ||
207 | lcd_write_reg(PANEL_IF_CTRL5, 0x0202); | ||
208 | lcd_write_reg(PANEL_IF_CTRL6, 0x0100); | ||
209 | lcd_write_reg(FRAME_MKR_CTRL, 0x0000); | ||
210 | lcd_write_reg(MDDI_CTRL, 0x0000); | ||
211 | |||
212 | lcd_write_reg(GAMMA_CTRL1, 0x0101); | ||
213 | lcd_write_reg(GAMMA_CTRL2, 0x0000); | ||
214 | lcd_write_reg(GAMMA_CTRL3, 0x0016); | ||
215 | lcd_write_reg(GAMMA_CTRL4, 0x2913); | ||
216 | lcd_write_reg(GAMMA_CTRL5, 0x260B); | ||
217 | lcd_write_reg(GAMMA_CTRL6, 0x0101); | ||
218 | lcd_write_reg(GAMMA_CTRL7, 0x1204); | ||
219 | lcd_write_reg(GAMMA_CTRL8, 0x0415); | ||
220 | lcd_write_reg(GAMMA_CTRL9, 0x0205); | ||
221 | lcd_write_reg(GAMMA_CTRL10, 0x0303); | ||
222 | lcd_write_reg(GAMMA_CTRL11, 0x0E05); | ||
223 | lcd_write_reg(GAMMA_CTRL12, 0x0D01); | ||
224 | lcd_write_reg(GAMMA_CTRL13, 0x010D); | ||
225 | lcd_write_reg(GAMMA_CTRL14, 0x050E); | ||
226 | lcd_write_reg(GAMMA_CTRL15, 0x0303); | ||
227 | lcd_write_reg(GAMMA_CTRL16, 0x0502); | ||
228 | |||
229 | /* power on */ | ||
230 | lcd_write_reg(DISPLAY_CTRL1, 0x0001); | ||
231 | lcd_write_reg(PWR_CTRL6, 0x0001); | ||
232 | lcd_write_reg(PWR_CTRL7, 0x0060); | ||
233 | delay_nop(50000); | ||
234 | lcd_write_reg(PWR_CTRL1, 0x16B0); | ||
235 | delay_nop(10000); | ||
236 | lcd_write_reg(PWR_CTRL2, 0x0147); | ||
237 | delay_nop(10000); | ||
238 | lcd_write_reg(PWR_CTRL3, 0x0117); | ||
239 | delay_nop(10000); | ||
240 | lcd_write_reg(PWR_CTRL4, 0x2F00); | ||
241 | delay_nop(50000); | ||
242 | lcd_write_reg(VCOM_HV2, 0x0000); /* src 0x0090 */ | ||
243 | delay_nop(10000); | ||
244 | lcd_write_reg(VCOM_HV1, 0x0008); /* src 0x000A */ | ||
245 | lcd_write_reg(PWR_CTRL3, 0x01BE); | ||
246 | delay_nop(10000); | ||
247 | |||
248 | /* addresses setup */ | ||
249 | lcd_write_reg(WINDOW_H_START, 0x0000); | ||
250 | lcd_write_reg(WINDOW_H_END, 0x00EF); /* 239 */ | ||
251 | lcd_write_reg(WINDOW_V_START, 0x0000); | ||
252 | lcd_write_reg(WINDOW_V_END, 0x018F); /* 399 */ | ||
253 | lcd_write_reg(GRAM_H_ADDR, 0x0000); | ||
254 | lcd_write_reg(GRAM_V_ADDR, 0x0000); | ||
255 | |||
256 | /* display on */ | ||
257 | lcd_write_reg(DISPLAY_CTRL1, 0x0021); | ||
258 | delay_nop(40000); | ||
259 | lcd_write_reg(DISPLAY_CTRL1, 0x0061); | ||
260 | delay_nop(100000); | ||
261 | lcd_write_reg(DISPLAY_CTRL1, 0x0173); | ||
262 | delay_nop(300000); | ||
263 | |||
264 | |||
265 | /* clear screen */ | ||
266 | lcd_cmd(GRAM_WRITE); | ||
267 | |||
268 | for (x=0; x<400; x++) | ||
269 | for(y=0; y<240; y++) | ||
270 | lcd_data(0x000000); | ||
271 | |||
272 | lcd_sleep(0); | ||
273 | } | ||
274 | |||
275 | /* This is ugly hack. We drive lcd in bypass mode | ||
276 | * where all writes goes directly to lcd controller. | ||
277 | * This is suboptimal at best. IF module povides | ||
278 | * FIFO, internal sram buffer, hardware scaller, | ||
279 | * DMA signals, hardware alpha blending and more. | ||
280 | * BUT the fact is that I have no idea how to use | ||
281 | * this modes. Datasheet floating around is very | ||
282 | * unclean in this regard and OF uses ackward | ||
283 | * lcd update routines which are hard to understand. | ||
284 | * Moreover OF sets some bits in IF module registers | ||
285 | * which are referred as reseved in datasheet. | ||
286 | */ | ||
287 | void lcd_update() | ||
288 | { | ||
289 | unsigned int x,y; | ||
290 | |||
291 | for (y=0; y<240; y++) | ||
292 | for (x=0; x<400; x++) | ||
293 | LCD_DATA = lcd_pixel_transform(lcd_framebuffer[y][x]); | ||
294 | } | ||
295 | |||
296 | /* not implemented yet */ | ||
297 | void lcd_update_rect(int x, int y, int width, int height) | ||
298 | { | ||
299 | (void)x; | ||
300 | (void)y; | ||
301 | (void)width; | ||
302 | (void)height; | ||
303 | lcd_update(); | ||
304 | } | ||
diff --git a/firmware/target/arm/rk27xx/nand-target.h b/firmware/target/arm/rk27xx/nand-target.h new file mode 100644 index 0000000000..dee690e5e6 --- /dev/null +++ b/firmware/target/arm/rk27xx/nand-target.h | |||
@@ -0,0 +1,58 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2009 by Michael Sparmann | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #ifndef __NAND_TARGET_H__ | ||
23 | #define __NAND_TARGET_H__ | ||
24 | |||
25 | #include "config.h" | ||
26 | #include "inttypes.h" | ||
27 | |||
28 | |||
29 | struct nand_device_info_type | ||
30 | { | ||
31 | uint32_t id; | ||
32 | uint16_t blocks; | ||
33 | uint16_t userblocks; | ||
34 | uint16_t pagesperblock; | ||
35 | uint8_t blocksizeexponent; | ||
36 | uint8_t tunk1; | ||
37 | uint8_t twp; | ||
38 | uint8_t tunk2; | ||
39 | uint8_t tunk3; | ||
40 | } __attribute__((packed)); | ||
41 | |||
42 | uint32_t nand_read_page(uint32_t bank, uint32_t page, void* databuffer, | ||
43 | void* sparebuffer, uint32_t doecc, | ||
44 | uint32_t checkempty); | ||
45 | uint32_t nand_write_page(uint32_t bank, uint32_t page, void* databuffer, | ||
46 | void* sparebuffer, uint32_t doecc); | ||
47 | uint32_t nand_block_erase(uint32_t bank, uint32_t page); | ||
48 | |||
49 | const struct nand_device_info_type* nand_get_device_type(uint32_t bank); | ||
50 | uint32_t nand_reset(uint32_t bank); | ||
51 | uint32_t nand_device_init(void); | ||
52 | void nand_set_active(void); | ||
53 | long nand_last_activity(void); | ||
54 | void nand_power_up(void); | ||
55 | void nand_power_down(void); | ||
56 | |||
57 | |||
58 | #endif | ||
diff --git a/firmware/target/arm/rk27xx/rk27generic/button-rk27generic.c b/firmware/target/arm/rk27xx/rk27generic/button-rk27generic.c new file mode 100644 index 0000000000..cd60482b0f --- /dev/null +++ b/firmware/target/arm/rk27xx/rk27generic/button-rk27generic.c | |||
@@ -0,0 +1,39 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 Marcin Bukat | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include "config.h" | ||
23 | #include "cpu.h" | ||
24 | #include "system.h" | ||
25 | #include "button.h" | ||
26 | |||
27 | void button_init_device(void) | ||
28 | { | ||
29 | /* setup button gpios as input */ | ||
30 | GPIO_PCCON &= ~(BUTTON_MAIN); | ||
31 | } | ||
32 | |||
33 | /* | ||
34 | * Get button pressed from hardware | ||
35 | */ | ||
36 | int button_read_device(void) | ||
37 | { | ||
38 | return (GPIO_PCDR & BUTTON_MAIN); | ||
39 | } | ||
diff --git a/firmware/target/arm/rk27xx/rk27generic/button-target.h b/firmware/target/arm/rk27xx/rk27generic/button-target.h new file mode 100644 index 0000000000..cc14dfc32b --- /dev/null +++ b/firmware/target/arm/rk27xx/rk27generic/button-target.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 Marcin Bukat | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #ifndef _BUTTON_TARGET_H_ | ||
22 | #define _BUTTON_TARGET_H_ | ||
23 | |||
24 | #include <stdbool.h> | ||
25 | #include "config.h" | ||
26 | |||
27 | void button_init_device(void); | ||
28 | int button_read_device(void); | ||
29 | |||
30 | /* Main unit's buttons */ | ||
31 | /* values assigned corespond to GPIOs numbers */ | ||
32 | #define BUTTON_PLAY 0x00000002 | ||
33 | |||
34 | #define BUTTON_REW 0x00000008 | ||
35 | #define BUTTON_FF 0x00000004 | ||
36 | #define BUTTON_VOL 0x00000040 | ||
37 | #define BUTTON_M 0x00000010 | ||
38 | |||
39 | #define BUTTON_LEFT BUTTON_REW | ||
40 | #define BUTTON_RIGHT BUTTON_FF | ||
41 | #define BUTTON_ON BUTTON_PLAY | ||
42 | |||
43 | #define BUTTON_REMOTE 0 | ||
44 | |||
45 | #define BUTTON_MAIN (BUTTON_PLAY|BUTTON_REW|BUTTON_FF|\ | ||
46 | BUTTON_VOL|BUTTON_M) | ||
47 | |||
48 | #define POWEROFF_BUTTON BUTTON_PLAY | ||
49 | #define POWEROFF_COUNT 30 | ||
50 | |||
51 | #endif /* _BUTTON_TARGET_H_ */ | ||
diff --git a/firmware/target/arm/rk27xx/sd-rk27xx.c b/firmware/target/arm/rk27xx/sd-rk27xx.c new file mode 100644 index 0000000000..c5a23ad00d --- /dev/null +++ b/firmware/target/arm/rk27xx/sd-rk27xx.c | |||
@@ -0,0 +1,719 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006 Daniel Ankers | ||
11 | * Copyright © 2008-2009 Rafaël Carré | ||
12 | * Copyright (C) 2011 Marcin Bukat | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | #include "config.h" /* for HAVE_MULTIVOLUME */ | ||
25 | #include "fat.h" | ||
26 | #include "thread.h" | ||
27 | #include "gcc_extensions.h" | ||
28 | #include "led.h" | ||
29 | #include "sdmmc.h" | ||
30 | #include "system.h" | ||
31 | #include "kernel.h" | ||
32 | #include "cpu.h" | ||
33 | #include <stdio.h> | ||
34 | #include <stdlib.h> | ||
35 | #include <string.h> | ||
36 | #include "panic.h" | ||
37 | #include "stdbool.h" | ||
38 | #include "ata_idle_notify.h" | ||
39 | #include "sd.h" | ||
40 | #include "usb.h" | ||
41 | |||
42 | #ifdef HAVE_HOTSWAP | ||
43 | #include "disk.h" | ||
44 | #endif | ||
45 | |||
46 | #include "lcd.h" | ||
47 | #include <stdarg.h> | ||
48 | #include "sysfont.h" | ||
49 | |||
50 | #define RES_NO (-1) | ||
51 | |||
52 | static tCardInfo card_info; | ||
53 | |||
54 | /* for compatibility */ | ||
55 | static long last_disk_activity = -1; | ||
56 | |||
57 | static long sd_stack [(DEFAULT_STACK_SIZE*2 + 0x200)/sizeof(long)]; | ||
58 | static const char sd_thread_name[] = "ata/sd"; | ||
59 | static struct mutex sd_mtx SHAREDBSS_ATTR; | ||
60 | static struct event_queue sd_queue; | ||
61 | #ifndef BOOTLOADER | ||
62 | bool sd_enabled = false; | ||
63 | #endif | ||
64 | |||
65 | static struct semaphore transfer_completion_signal; | ||
66 | static struct semaphore command_completion_signal; | ||
67 | static volatile bool retry; | ||
68 | static volatile int cmd_error; | ||
69 | |||
70 | /* interrupt handler for SD */ | ||
71 | void INT_SD(void) | ||
72 | { | ||
73 | const int status = SD_INT; | ||
74 | |||
75 | SD_INT = 0; /* disable sd interrupts, clear pending interrupts */ | ||
76 | |||
77 | /* cmd and response status pending */ | ||
78 | if(status & CMD_RES_STAT) | ||
79 | { | ||
80 | /* get the status */ | ||
81 | cmd_error = SD_CMDRES; | ||
82 | semaphore_release(&command_completion_signal); | ||
83 | } | ||
84 | |||
85 | /* data transfer status pending */ | ||
86 | if(status & DATA_XFER_STAT) | ||
87 | { | ||
88 | cmd_error = SD_DATAT; | ||
89 | if (cmd_error & DATA_XFER_ERR) | ||
90 | retry = true; | ||
91 | |||
92 | semaphore_release(&transfer_completion_signal); | ||
93 | } | ||
94 | |||
95 | SD_INT = CMD_RES_INT_EN | DATA_XFER_INT_EN; | ||
96 | } | ||
97 | |||
98 | /* Exchange buffers - the one where SD module puts into/reads from | ||
99 | * data and the one controlled by MCU. This allows some overlap | ||
100 | * in transfer operations and should increase throuput. | ||
101 | */ | ||
102 | static void mmu_switch_buff(void) | ||
103 | { | ||
104 | static unsigned int i = 0; | ||
105 | |||
106 | if (i++ & 0x01) | ||
107 | { | ||
108 | MMU_CTRL = MMU_MMU0_BUFII | MMU_CPU_BUFI | MMU_BUFII_RESET | | ||
109 | MMU_BUFII_BYTE | MMU_BUFI_RESET | MMU_BUFI_WORD; | ||
110 | } | ||
111 | else | ||
112 | { | ||
113 | MMU_CTRL = MMU_MMU0_BUFI | MMU_CPU_BUFII | MMU_BUFII_RESET | | ||
114 | MMU_BUFII_WORD | MMU_BUFI_RESET | MMU_BUFI_BYTE; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | /* Reset internal pointers of the MMU submodule */ | ||
119 | static void mmu_buff_reset(void) | ||
120 | { | ||
121 | MMU_CTRL |= MMU_BUFII_RESET | MMU_BUFI_RESET; | ||
122 | } | ||
123 | |||
124 | /* My generic device uses PC7 pin, active low */ | ||
125 | static inline bool card_detect_target(void) | ||
126 | { | ||
127 | return !(GPIO_PCDR & 0x80); | ||
128 | } | ||
129 | |||
130 | /* Send command to the SD card. Command finish is signaled in ISR */ | ||
131 | static bool send_cmd(const int cmd, const int arg, const int res, | ||
132 | unsigned long *response) | ||
133 | { | ||
134 | SD_CMD = arg; | ||
135 | |||
136 | if (res > 0) | ||
137 | SD_CMDREST = CMD_XFER_START | RES_XFER_START | res | cmd; | ||
138 | else | ||
139 | SD_CMDREST = CMD_XFER_START | RES_XFER_END | RES_R1 | cmd; | ||
140 | |||
141 | semaphore_wait(&command_completion_signal, TIMEOUT_BLOCK); | ||
142 | |||
143 | /* Handle command responses & errors */ | ||
144 | if(res != RES_NO) | ||
145 | { | ||
146 | if(cmd_error & STAT_CMD_RES_ERR) | ||
147 | return false; | ||
148 | |||
149 | if(res == RES_R2) | ||
150 | { | ||
151 | response[0] = SD_RES3; | ||
152 | response[1] = SD_RES2; | ||
153 | response[2] = SD_RES1; | ||
154 | response[3] = SD_RES0; | ||
155 | } | ||
156 | else | ||
157 | response[0] = SD_RES3; | ||
158 | } | ||
159 | return true; | ||
160 | } | ||
161 | |||
162 | #if 0 | ||
163 | /* for some misterious reason the card does not report itself as being in TRAN | ||
164 | * but transfers are successful. Rockchip OF does not check the card state | ||
165 | * after SELECT. I checked two different cards. | ||
166 | */ | ||
167 | static void print_card_status(void) | ||
168 | { | ||
169 | unsigned long response; | ||
170 | send_cmd(SD_SEND_STATUS, card_info.rca, RES_R1, | ||
171 | &response); | ||
172 | |||
173 | printf("card status: 0x%0x, state: 0x%0x", response, (response>>9)&0xf); | ||
174 | } | ||
175 | |||
176 | static int sd_wait_for_tran_state(void) | ||
177 | { | ||
178 | unsigned long response; | ||
179 | unsigned int timeout = current_tick + 5*HZ; | ||
180 | int cmd_retry = 10; | ||
181 | |||
182 | while (1) | ||
183 | { | ||
184 | while (!send_cmd(SD_SEND_STATUS, card_info.rca, RES_R1, | ||
185 | &response) && cmd_retry > 0) | ||
186 | { | ||
187 | cmd_retry--; | ||
188 | } | ||
189 | |||
190 | if (cmd_retry <= 0) | ||
191 | { | ||
192 | return -1; | ||
193 | } | ||
194 | |||
195 | if (((response >> 9) & 0xf) == SD_TRAN) | ||
196 | { | ||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | if(TIME_AFTER(current_tick, timeout)) | ||
201 | { | ||
202 | return -10 * ((response >> 9) & 0xf); | ||
203 | } | ||
204 | |||
205 | last_disk_activity = current_tick; | ||
206 | } | ||
207 | } | ||
208 | #endif | ||
209 | |||
210 | static bool sd_wait_card_busy(void) | ||
211 | { | ||
212 | unsigned int timeout = current_tick + 5*HZ; | ||
213 | |||
214 | while (!(SD_CARD & SD_CARD_BSY)) | ||
215 | { | ||
216 | if(TIME_AFTER(current_tick, timeout)) | ||
217 | return false; | ||
218 | } | ||
219 | |||
220 | return true; | ||
221 | } | ||
222 | |||
223 | static int sd_init_card(void) | ||
224 | { | ||
225 | unsigned long response; | ||
226 | long init_timeout; | ||
227 | bool sd_v2 = false; | ||
228 | |||
229 | card_info.rca = 0; | ||
230 | |||
231 | /* assume 50 MHz APB freq / 125 = 400 kHz */ | ||
232 | SD_CTRL = (SD_CTRL & ~(0x7FF)) | 0x7D; | ||
233 | |||
234 | /* 100 - 400kHz clock required for Identification Mode */ | ||
235 | /* Start of Card Identification Mode ************************************/ | ||
236 | |||
237 | /* CMD0 Go Idle */ | ||
238 | if(!send_cmd(SD_GO_IDLE_STATE, 0, RES_NO, NULL)) | ||
239 | return -1; | ||
240 | |||
241 | sleep(1); | ||
242 | |||
243 | /* CMD8 Check for v2 sd card. Must be sent before using ACMD41 | ||
244 | Non v2 cards will not respond to this command*/ | ||
245 | if(send_cmd(SD_SEND_IF_COND, 0x1AA, RES_R6, &response)) | ||
246 | if((response & 0xFFF) == 0x1AA) | ||
247 | sd_v2 = true; | ||
248 | |||
249 | /* timeout for initialization is 1sec, from SD Specification 2.00 */ | ||
250 | init_timeout = current_tick + HZ; | ||
251 | |||
252 | do { | ||
253 | /* this timeout is the only valid error for this loop*/ | ||
254 | if(TIME_AFTER(current_tick, init_timeout)) | ||
255 | return -2; | ||
256 | |||
257 | if(!send_cmd(SD_APP_CMD, card_info.rca, RES_R1, &response)) | ||
258 | return -3; | ||
259 | |||
260 | sleep(1); /* bus conflict otherwise */ | ||
261 | |||
262 | /* ACMD41 For v2 cards set HCS bit[30] & send host voltage range to all */ | ||
263 | if(!send_cmd(SD_APP_OP_COND, (0x00FF8000 | (sd_v2 ? 1<<30 : 0)), | ||
264 | RES_R3, &card_info.ocr)) | ||
265 | return -4; | ||
266 | } while(!(card_info.ocr & (1<<31)) ); | ||
267 | |||
268 | /* CMD2 send CID */ | ||
269 | if(!send_cmd(SD_ALL_SEND_CID, 0, RES_R2, card_info.cid)) | ||
270 | return -5; | ||
271 | |||
272 | /* CMD3 send RCA */ | ||
273 | if(!send_cmd(SD_SEND_RELATIVE_ADDR, 0, RES_R6, &card_info.rca)) | ||
274 | return -6; | ||
275 | |||
276 | /* End of Card Identification Mode ************************************/ | ||
277 | |||
278 | /* Card back to full speed 25MHz*/ | ||
279 | SD_CTRL = (SD_CTRL & ~0x7FF) | 1; /* FIXME check this divider - OF uses 0 here*/ | ||
280 | |||
281 | /* CMD9 send CSD */ | ||
282 | if(!send_cmd(SD_SEND_CSD, card_info.rca, RES_R2, card_info.csd)) | ||
283 | return -11; | ||
284 | |||
285 | sd_parse_csd(&card_info); | ||
286 | |||
287 | if(!send_cmd(SD_SELECT_CARD, card_info.rca, RES_R1b, &response)) | ||
288 | return -20; | ||
289 | |||
290 | if (!sd_wait_card_busy()) | ||
291 | return -21; | ||
292 | |||
293 | card_info.initialized = 1; | ||
294 | |||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | static void sd_thread(void) NORETURN_ATTR; | ||
299 | static void sd_thread(void) | ||
300 | { | ||
301 | struct queue_event ev; | ||
302 | bool idle_notified = false; | ||
303 | |||
304 | while (1) | ||
305 | { | ||
306 | queue_wait_w_tmo(&sd_queue, &ev, HZ); | ||
307 | |||
308 | switch ( ev.id ) | ||
309 | { | ||
310 | #ifdef HAVE_HOTSWAP | ||
311 | case SYS_HOTSWAP_INSERTED: | ||
312 | case SYS_HOTSWAP_EXTRACTED: | ||
313 | { | ||
314 | int microsd_init = 1; | ||
315 | fat_lock(); /* lock-out FAT activity first - | ||
316 | prevent deadlocking via disk_mount that | ||
317 | would cause a reverse-order attempt with | ||
318 | another thread */ | ||
319 | mutex_lock(&sd_mtx); /* lock-out card activity - direct calls | ||
320 | into driver that bypass the fat cache */ | ||
321 | |||
322 | /* We now have exclusive control of fat cache and ata */ | ||
323 | |||
324 | disk_unmount(sd_first_drive); /* release "by force", ensure file | ||
325 | descriptors aren't leaked and any busy | ||
326 | ones are invalid if mounting */ | ||
327 | /* Force card init for new card, re-init for re-inserted one or | ||
328 | * clear if the last attempt to init failed with an error. */ | ||
329 | card_info.initialized = 0; | ||
330 | |||
331 | if (ev.id == SYS_HOTSWAP_INSERTED) | ||
332 | { | ||
333 | sd_enable(true); | ||
334 | microsd_init = sd_init_card(sd_first_drive); | ||
335 | if (microsd_init < 0) /* initialisation failed */ | ||
336 | panicf("microSD init failed : %d", microsd_init); | ||
337 | |||
338 | microsd_init = disk_mount(sd_first_drive); /* 0 if fail */ | ||
339 | } | ||
340 | |||
341 | /* | ||
342 | * Mount succeeded, or this was an EXTRACTED event, | ||
343 | * in both cases notify the system about the changed filesystems | ||
344 | */ | ||
345 | if (microsd_init) | ||
346 | queue_broadcast(SYS_FS_CHANGED, 0); | ||
347 | |||
348 | sd_enable(false); | ||
349 | |||
350 | /* Access is now safe */ | ||
351 | mutex_unlock(&sd_mtx); | ||
352 | fat_unlock(); | ||
353 | } | ||
354 | break; | ||
355 | #endif | ||
356 | case SYS_TIMEOUT: | ||
357 | if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ))) | ||
358 | { | ||
359 | idle_notified = false; | ||
360 | } | ||
361 | else if (!idle_notified) | ||
362 | { | ||
363 | call_storage_idle_notifys(false); | ||
364 | idle_notified = true; | ||
365 | } | ||
366 | break; | ||
367 | |||
368 | case SYS_USB_CONNECTED: | ||
369 | usb_acknowledge(SYS_USB_CONNECTED_ACK); | ||
370 | /* Wait until the USB cable is extracted again */ | ||
371 | usb_wait_for_disconnect(&sd_queue); | ||
372 | |||
373 | break; | ||
374 | } | ||
375 | } | ||
376 | } | ||
377 | |||
378 | static void init_controller(void) | ||
379 | { | ||
380 | /* reset SD module */ | ||
381 | SCU_RSTCFG |= (1<<9); | ||
382 | sleep(1); | ||
383 | SCU_RSTCFG &= ~(1<<9); | ||
384 | |||
385 | /* set pins functions as SD signals */ | ||
386 | SCU_IOMUXA_CON |= IOMUX_SD; | ||
387 | |||
388 | /* enable and unmask SD interrupts in interrupt controller */ | ||
389 | INTC_IMR |= (1<<10); | ||
390 | INTC_IECR |= (1<<10); | ||
391 | |||
392 | SD_CTRL = SD_PWR_CPU | SD_DETECT_MECH | SD_CLOCK_EN | 0x7D; | ||
393 | SD_INT = CMD_RES_INT_EN | DATA_XFER_INT_EN; | ||
394 | SD_CARD = SD_CARD_SELECT | SD_CARD_PWR_EN; | ||
395 | |||
396 | /* setup mmu buffers */ | ||
397 | MMU_PNRI = 0x1ff; | ||
398 | MMU_PNRII = 0x1ff; | ||
399 | MMU_CTRL = MMU_MMU0_BUFII | MMU_CPU_BUFI | MMU_BUFII_RESET | | ||
400 | MMU_BUFII_BYTE | MMU_BUFI_RESET | MMU_BUFI_WORD; | ||
401 | |||
402 | } | ||
403 | |||
404 | int sd_init(void) | ||
405 | { | ||
406 | int ret; | ||
407 | |||
408 | semaphore_init(&transfer_completion_signal, 1, 0); | ||
409 | semaphore_init(&command_completion_signal, 1, 0); | ||
410 | |||
411 | init_controller(); | ||
412 | |||
413 | ret = sd_init_card(); | ||
414 | if(ret < 0) | ||
415 | return ret; | ||
416 | |||
417 | /* init mutex */ | ||
418 | mutex_init(&sd_mtx); | ||
419 | |||
420 | queue_init(&sd_queue, true); | ||
421 | create_thread(sd_thread, sd_stack, sizeof(sd_stack), 0, | ||
422 | sd_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE) IF_COP(, CPU)); | ||
423 | |||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | int sd_read_sectors(IF_MD2(int drive,) unsigned long start, int count, | ||
428 | void* buf) | ||
429 | { | ||
430 | #ifdef HAVE_MULTIDRIVE | ||
431 | (void)drive; | ||
432 | #endif | ||
433 | unsigned long response; | ||
434 | unsigned int retry_cnt = 0; | ||
435 | int cnt, ret = 0; | ||
436 | unsigned char *dst; | ||
437 | |||
438 | mutex_lock(&sd_mtx); | ||
439 | sd_enable(true); | ||
440 | |||
441 | if (count <= 0 || start + count > card_info.numblocks) | ||
442 | return -1; | ||
443 | |||
444 | if(!(card_info.ocr & (1<<30))) | ||
445 | start <<= 9; /* not SDHC */ | ||
446 | |||
447 | /* setup A2A DMA CH0 */ | ||
448 | A2A_ISRC0 = (unsigned long)(&MMU_DATA); | ||
449 | A2A_ICNT0 = 512; | ||
450 | A2A_LCNT0 = 1; | ||
451 | A2A_DOMAIN = 0; | ||
452 | |||
453 | while (retry_cnt++ < 20) | ||
454 | { | ||
455 | cnt = count; | ||
456 | dst = (unsigned char *)buf; | ||
457 | |||
458 | ret = 0; | ||
459 | retry = false; /* reset retry flag */ | ||
460 | mmu_buff_reset(); /* reset recive buff state */ | ||
461 | |||
462 | /* issue read command to the card */ | ||
463 | if (!send_cmd(SD_READ_MULTIPLE_BLOCK, start, RES_R1, &response)) | ||
464 | { | ||
465 | ret = -4; | ||
466 | continue; | ||
467 | } | ||
468 | |||
469 | while (cnt > 0) | ||
470 | { | ||
471 | if (cnt == 1) | ||
472 | { | ||
473 | /* last block to tranfer */ | ||
474 | SD_DATAT = DATA_XFER_START | DATA_XFER_READ | | ||
475 | DATA_BUS_1LINE | DATA_XFER_DMA_DIS | | ||
476 | DATA_XFER_SINGLE; | ||
477 | } | ||
478 | else | ||
479 | { | ||
480 | /* more than one block to transfer */ | ||
481 | SD_DATAT = DATA_XFER_START | DATA_XFER_READ | | ||
482 | DATA_BUS_1LINE | DATA_XFER_DMA_DIS | | ||
483 | DATA_XFER_MULTI; | ||
484 | } | ||
485 | |||
486 | /* wait for transfer completion */ | ||
487 | semaphore_wait(&transfer_completion_signal, TIMEOUT_BLOCK); | ||
488 | |||
489 | if (retry) | ||
490 | { | ||
491 | /* data transfer error */ | ||
492 | ret = -5; | ||
493 | break; | ||
494 | } | ||
495 | |||
496 | /* exchange buffers */ | ||
497 | mmu_switch_buff(); | ||
498 | |||
499 | last_disk_activity = current_tick; | ||
500 | |||
501 | /* transfer data from receive buffer to the dest | ||
502 | * for (i=0; i<(512/4); i++) | ||
503 | * *dst++ = MMU_DATA; | ||
504 | * | ||
505 | * below is DMA version in software mode. | ||
506 | * SD module provides DMAreq signals and all this | ||
507 | * can be done in hardware in theory but I can't | ||
508 | * figure this out. OF doesn't use DMA at all. | ||
509 | */ | ||
510 | A2A_IDST0 = (unsigned long)dst; | ||
511 | A2A_CON0 = (3<<9) | (1<<6) | (1<<3) | (2<<1) | (1<<0); | ||
512 | |||
513 | /* wait for DMA engine to finish transfer */ | ||
514 | while (A2A_DMA_STS & 1); | ||
515 | |||
516 | dst += 512; | ||
517 | cnt--; | ||
518 | } /* while (cnt > 0) */ | ||
519 | |||
520 | if (!send_cmd(SD_STOP_TRANSMISSION, 0, RES_R1b, &response)) | ||
521 | ret = -6; | ||
522 | |||
523 | /* transfer successfull - leave retry loop */ | ||
524 | if (ret == 0) | ||
525 | break; | ||
526 | } | ||
527 | |||
528 | sd_enable(false); | ||
529 | mutex_unlock(&sd_mtx); | ||
530 | |||
531 | return ret; | ||
532 | } | ||
533 | |||
534 | /* Not tested */ | ||
535 | int sd_write_sectors(IF_MD2(int drive,) unsigned long start, int count, | ||
536 | const void* buf) | ||
537 | { | ||
538 | #ifdef HAVE_MULTIDRIVE | ||
539 | (void) drive; | ||
540 | #endif | ||
541 | #if defined(BOOTLOADER) /* we don't need write support in bootloader */ | ||
542 | (void) start; | ||
543 | (void) count; | ||
544 | (void) buf; | ||
545 | return -1; | ||
546 | #else | ||
547 | unsigned long response; | ||
548 | unsigned int retry_cnt = 0; | ||
549 | int cnt, ret = 0; | ||
550 | unsigned char *src; | ||
551 | bool card_selected = false; | ||
552 | |||
553 | mutex_lock(&sd_mtx); | ||
554 | sd_enable(true); | ||
555 | |||
556 | if (count <= 0 || start + count > card_info.numblocks) | ||
557 | return -1; | ||
558 | |||
559 | if(!(card_info.ocr & (1<<30))) | ||
560 | start <<= 9; /* not SDHC */ | ||
561 | |||
562 | /* setup A2A DMA CH0 */ | ||
563 | A2A_IDST0 = (unsigned long)(&MMU_DATA); | ||
564 | A2A_ICNT0 = 512; | ||
565 | A2A_LCNT0 = 1; | ||
566 | A2A_DOMAIN = 0; | ||
567 | |||
568 | while (retry_cnt++ < 20) | ||
569 | { | ||
570 | cnt = count; | ||
571 | src = (unsigned char *)buf; | ||
572 | |||
573 | ret = 0; | ||
574 | retry = false; /* reset retry flag */ | ||
575 | mmu_buff_reset(); /* reset recive buff state */ | ||
576 | |||
577 | if (!send_cmd(SD_WRITE_MULTIPLE_BLOCK, start, RES_R1, &response)) | ||
578 | { | ||
579 | ret = -3; | ||
580 | continue; | ||
581 | } | ||
582 | |||
583 | while (cnt > 0) | ||
584 | { | ||
585 | /* transfer data from receive buffer to the dest | ||
586 | * for (i=0; i<(512/4); i++) | ||
587 | * MMU_DATA = *src++; | ||
588 | * | ||
589 | * Below is DMA version in software mode. | ||
590 | */ | ||
591 | |||
592 | A2A_ISRC0 = (unsigned long)src; | ||
593 | A2A_CON0 = (3<<9) | (1<<5) | (1<<3) | (2<<1) | (1<<0); | ||
594 | |||
595 | while (A2A_DMA_STS & 1); | ||
596 | |||
597 | src += 512; | ||
598 | |||
599 | /* exchange buffers */ | ||
600 | mmu_switch_buff(); | ||
601 | |||
602 | if (cnt == 1) | ||
603 | { | ||
604 | /* last block to tranfer */ | ||
605 | SD_DATAT = DATA_XFER_START | DATA_XFER_WRITE | | ||
606 | DATA_BUS_1LINE | DATA_XFER_DMA_DIS | | ||
607 | DATA_XFER_SINGLE; | ||
608 | |||
609 | } | ||
610 | else | ||
611 | { | ||
612 | /* more than one block to transfer */ | ||
613 | SD_DATAT = DATA_XFER_START | DATA_XFER_WRITE | | ||
614 | DATA_BUS_1LINE | DATA_XFER_DMA_DIS | | ||
615 | DATA_XFER_MULTI; | ||
616 | |||
617 | } | ||
618 | |||
619 | /* wait for transfer completion */ | ||
620 | semaphore_wait(&transfer_completion_signal, TIMEOUT_BLOCK); | ||
621 | |||
622 | if (retry) | ||
623 | { | ||
624 | /* data transfer error */ | ||
625 | ret = -3; | ||
626 | break; | ||
627 | } | ||
628 | |||
629 | cnt--; | ||
630 | } /* while (cnt > 0) */ | ||
631 | |||
632 | if (!send_cmd(SD_STOP_TRANSMISSION, 0, RES_R1b, &response)) | ||
633 | ret = -4; | ||
634 | |||
635 | if (!sd_wait_card_busy()) | ||
636 | ret = -5; | ||
637 | |||
638 | /* transfer successfull - leave retry loop */ | ||
639 | if (ret == 0) | ||
640 | break; | ||
641 | } | ||
642 | |||
643 | sd_enable(false); | ||
644 | mutex_unlock(&sd_mtx); | ||
645 | |||
646 | return ret; | ||
647 | |||
648 | #endif /* defined(BOOTLOADER) */ | ||
649 | } | ||
650 | |||
651 | void sd_enable(bool on) | ||
652 | { | ||
653 | /* enable or disable clock signal for SD module */ | ||
654 | if (on) | ||
655 | { | ||
656 | SCU_CLKCFG &= ~(1<<22); | ||
657 | } | ||
658 | else | ||
659 | { | ||
660 | SCU_CLKCFG |= (1<<22); | ||
661 | } | ||
662 | } | ||
663 | |||
664 | #ifndef BOOTLOADER | ||
665 | long sd_last_disk_activity(void) | ||
666 | { | ||
667 | return last_disk_activity; | ||
668 | } | ||
669 | |||
670 | tCardInfo *card_get_info_target(int card_no) | ||
671 | { | ||
672 | (void)card_no; | ||
673 | return &card_info; | ||
674 | } | ||
675 | #endif /* BOOTLOADER */ | ||
676 | |||
677 | #ifdef HAVE_HOTSWAP | ||
678 | /* Not complete and disabled in config */ | ||
679 | bool sd_removable(IF_MD_NONVOID(int drive)) | ||
680 | { | ||
681 | (void)drive; | ||
682 | return true; | ||
683 | } | ||
684 | |||
685 | bool sd_present(IF_MD_NONVOID(int drive)) | ||
686 | { | ||
687 | (void)drive; | ||
688 | return card_detect_target(); | ||
689 | } | ||
690 | |||
691 | static int sd_oneshot_callback(struct timeout *tmo) | ||
692 | { | ||
693 | (void)tmo; | ||
694 | |||
695 | /* This is called only if the state was stable for 300ms - check state | ||
696 | * and post appropriate event. */ | ||
697 | if (card_detect_target()) | ||
698 | { | ||
699 | queue_broadcast(SYS_HOTSWAP_INSERTED, 0); | ||
700 | } | ||
701 | else | ||
702 | queue_broadcast(SYS_HOTSWAP_EXTRACTED, 0); | ||
703 | |||
704 | return 0; | ||
705 | } | ||
706 | |||
707 | /* interrupt handler for SD detect */ | ||
708 | |||
709 | #endif /* HAVE_HOTSWAP */ | ||
710 | |||
711 | #ifdef CONFIG_STORAGE_MULTI | ||
712 | int sd_num_drives(int first_drive) | ||
713 | { | ||
714 | (void)first_drive; | ||
715 | |||
716 | /* we have only one SD drive */ | ||
717 | return 1; | ||
718 | } | ||
719 | #endif /* CONFIG_STORAGE_MULTI */ | ||
diff --git a/firmware/target/arm/rk27xx/spfd5420a.h b/firmware/target/arm/rk27xx/spfd5420a.h new file mode 100644 index 0000000000..fcb998dfd1 --- /dev/null +++ b/firmware/target/arm/rk27xx/spfd5420a.h | |||
@@ -0,0 +1,107 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 Marcin Bukat | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #define ID_READ 0x000 | ||
23 | #define DRIVER_OUT_CTRL 0x001 | ||
24 | #define WAVEFORM_CTRL 0x002 | ||
25 | #define ENTRY_MODE 0x003 | ||
26 | /* 0x004 - 0x005 reserved */ | ||
27 | #define SHAPENING_CTRL 0x006 /* not present in datasheet */ | ||
28 | #define DISPLAY_CTRL1 0x007 | ||
29 | #define DISPLAY_CTRL2 0x008 | ||
30 | #define LOW_PWR_CTRL1 0x009 | ||
31 | /* 0x00A reserved */ | ||
32 | #define LOW_PWR_CTRL2 0x00B | ||
33 | #define EXT_DISP_CTRL1 0x00C | ||
34 | /* 0x00D - 0x00E reserved */ | ||
35 | #define EXT_DISP_CTRL2 0x00F | ||
36 | #define PANEL_IF_CTRL1 0x010 | ||
37 | #define PANEL_IF_CTRL2 0x011 | ||
38 | #define PANEL_IF_CTRL3 0x012 | ||
39 | /* 0x013 - 0x01F reserved */ | ||
40 | #define PANEL_IF_CTRL4 0x020 | ||
41 | #define PANEL_IF_CTRL5 0x021 | ||
42 | #define PANEL_IF_CTRL6 0x022 | ||
43 | /* 0x023 - 0x08F reserved */ | ||
44 | #define FRAME_MKR_CTRL 0x090 | ||
45 | /* 0x091 reserved */ | ||
46 | #define MDDI_CTRL 0x092 /* not present in datasheet */ | ||
47 | /* 0x093 - 0x0FF reserved */ | ||
48 | #define PWR_CTRL1 0x100 | ||
49 | #define PWR_CTRL2 0x101 | ||
50 | #define PWR_CTRL3 0x102 | ||
51 | #define PWR_CTRL4 0x103 /* amplitude to VCOM */ | ||
52 | /* 0x104 - 0x106 reserved */ | ||
53 | #define PWR_CTRL5 0x107 | ||
54 | /* 0x108 - 0x10F reserved */ | ||
55 | #define PWR_CTRL6 0x110 | ||
56 | #define PWR_CTRL7 0x112 /* not present in datasheet */ | ||
57 | /* 0x113 - 0x1FF reserved */ | ||
58 | #define GRAM_H_ADDR 0x200 | ||
59 | #define GRAM_V_ADDR 0x201 | ||
60 | #define GRAM_READ 0x202 | ||
61 | #define GRAM_WRITE 0x202 | ||
62 | /* 0x203 - 0x20F reserved */ | ||
63 | #define WINDOW_H_START 0x210 | ||
64 | #define WINDOW_H_END 0x211 | ||
65 | #define WINDOW_V_START 0x212 | ||
66 | #define WINDOW_V_END 0x213 | ||
67 | /* 0x214 - 0x27F reserved */ | ||
68 | #define NVM_READ 0x280 | ||
69 | #define NVM_WRITE 0x280 | ||
70 | #define VCOM_HV1 0x281 | ||
71 | #define VCOM_HV2 0x282 | ||
72 | /* 0x283 - 0x2FF reserved */ | ||
73 | #define GAMMA_CTRL1 0x300 | ||
74 | #define GAMMA_CTRL2 0x301 | ||
75 | #define GAMMA_CTRL3 0x302 | ||
76 | #define GAMMA_CTRL4 0x303 | ||
77 | #define GAMMA_CTRL5 0x304 | ||
78 | #define GAMMA_CTRL6 0x305 | ||
79 | #define GAMMA_CTRL7 0x306 | ||
80 | #define GAMMA_CTRL8 0x307 | ||
81 | #define GAMMA_CTRL9 0x308 | ||
82 | #define GAMMA_CTRL10 0x309 | ||
83 | #define GAMMA_CTRL11 0x30A | ||
84 | #define GAMMA_CTRL12 0x30B | ||
85 | #define GAMMA_CTRL13 0x30C | ||
86 | #define GAMMA_CTRL14 0x30D | ||
87 | #define GAMMA_CTRL15 0x30E | ||
88 | #define GAMMA_CTRL16 0x30F | ||
89 | /* 0x310 - 0x3FF reserved */ | ||
90 | #define BASE_IMG_SIZE 0x400 | ||
91 | #define BASE_IMG_CTRL 0x401 | ||
92 | /* 0x402 - 0x403 reserved */ | ||
93 | #define VSCROLL_CTRL 0x404 | ||
94 | /* 0x405 - 0x4FF reserved */ | ||
95 | #define PART1_POS 0x500 | ||
96 | #define PART1_START 0x501 | ||
97 | #define PART1_END 0x502 | ||
98 | #define PART2_POS 0x503 | ||
99 | #define PART2_START 0x504 | ||
100 | #define PART2_END 0x505 | ||
101 | /* 0x506 - 0x5FF reserved */ | ||
102 | #define RESET 0x600 /* not present in datasheet */ | ||
103 | /* 0x601 - 0x605 */ | ||
104 | #define IF_ENDIAN 0x606 | ||
105 | /* 0x607 - 0x6EF reserved */ | ||
106 | #define NVM_CTRL 0x6F0 | ||
107 | /* 0x6F1 - 0xFFF reserved */ | ||
diff --git a/firmware/target/arm/rk27xx/system-rk27xx.c b/firmware/target/arm/rk27xx/system-rk27xx.c new file mode 100644 index 0000000000..67024a5fea --- /dev/null +++ b/firmware/target/arm/rk27xx/system-rk27xx.c | |||
@@ -0,0 +1,164 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 by Marcin Bukat | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include "kernel.h" | ||
23 | #include "system.h" | ||
24 | #include "panic.h" | ||
25 | #include "system-target.h" | ||
26 | |||
27 | #define default_interrupt(name) \ | ||
28 | extern __attribute__((weak,alias("UIRQ"))) void name (void) | ||
29 | |||
30 | void irq_handler(void) __attribute__((interrupt ("IRQ"), naked)); | ||
31 | void fiq_handler(void) __attribute__((interrupt ("FIQ"), naked, \ | ||
32 | weak, alias("fiq_dummy"))); | ||
33 | |||
34 | default_interrupt(INT_UART0); | ||
35 | default_interrupt(INT_UART1); | ||
36 | default_interrupt(INT_TIMER0); | ||
37 | default_interrupt(INT_TIMER1); | ||
38 | default_interrupt(INT_TIMER2); | ||
39 | default_interrupt(INT_GPIO0); | ||
40 | default_interrupt(INT_SW_INT0); | ||
41 | default_interrupt(INT_AHB0_MAILBOX); | ||
42 | default_interrupt(INT_RTC); | ||
43 | default_interrupt(INT_SCU); | ||
44 | default_interrupt(INT_SD); | ||
45 | default_interrupt(INT_SPI); | ||
46 | default_interrupt(INT_HDMA); | ||
47 | default_interrupt(INT_A2A_BRIDGE); | ||
48 | default_interrupt(INT_I2C); | ||
49 | default_interrupt(INT_I2S); | ||
50 | default_interrupt(INT_UDC); | ||
51 | default_interrupt(INT_UHC); | ||
52 | default_interrupt(INT_PWM0); | ||
53 | default_interrupt(INT_PWM1); | ||
54 | default_interrupt(INT_PWM2); | ||
55 | default_interrupt(INT_ADC); | ||
56 | default_interrupt(INT_GPIO1); | ||
57 | default_interrupt(INT_VIP); | ||
58 | default_interrupt(INT_DWDMA); | ||
59 | default_interrupt(INT_NANDC); | ||
60 | default_interrupt(INT_LCDC); | ||
61 | default_interrupt(INT_DSP); | ||
62 | default_interrupt(INT_SW_INT1); | ||
63 | default_interrupt(INT_SW_INT2); | ||
64 | default_interrupt(INT_SW_INT3); | ||
65 | |||
66 | static void (* const irqvector[])(void) = | ||
67 | { | ||
68 | INT_UART0,INT_UART1,INT_TIMER0,INT_TIMER1,INT_TIMER2,INT_GPIO0,INT_SW_INT0,INT_AHB0_MAILBOX, | ||
69 | INT_RTC,INT_SCU,INT_SD,INT_SPI,INT_HDMA,INT_A2A_BRIDGE,INT_I2C, | ||
70 | INT_I2S,INT_UDC,INT_UHC,INT_PWM0,INT_PWM1,INT_PWM2,INT_ADC,INT_GPIO1, | ||
71 | INT_VIP,INT_DWDMA,INT_NANDC,INT_LCDC,INT_DSP,INT_SW_INT1,INT_SW_INT2,INT_SW_INT3 | ||
72 | }; | ||
73 | |||
74 | static const char * const irqname[] = | ||
75 | { | ||
76 | "INT_UART0","INT_UART1","INT_TIMER0","INT_TIMER1","INT_TIMER2","INT_GPIO0","INT_SW_INT0","INT_AHB0_MAILBOX", | ||
77 | "INT_RTC","INT_SCU","INT_SD","INT_SPI","INT_HDMA","INT_A2A_BRIDGE","INT_I2C", | ||
78 | "INT_I2S","INT_UDC","INT_UHC","INT_PWM0","INT_PWM1","INT_PWM2","INT_ADC","INT_GPIO1", | ||
79 | "INT_VIP","INT_DWDMA","INT_NANDC","INT_LCDC","INT_DSP","INT_SW_INT1","INT_SW_INT2","INT_SW_INT3" | ||
80 | }; | ||
81 | |||
82 | static void UIRQ(void) | ||
83 | { | ||
84 | unsigned int offset = INTC_ISR & 0x1f; | ||
85 | panicf("Unhandled IRQ %02X: %s", offset, irqname[offset]); | ||
86 | } | ||
87 | |||
88 | void irq_handler(void) | ||
89 | { | ||
90 | /* | ||
91 | * Based on: linux/arch/arm/kernel/entry-armv.S and system-meg-fx.c | ||
92 | */ | ||
93 | |||
94 | asm volatile( "stmfd sp!, {r0-r7, ip, lr} \n" /* Store context */ | ||
95 | "sub sp, sp, #8 \n"); /* Reserve stack */ | ||
96 | |||
97 | int irq_no = INTC_ISR & 0x1f; | ||
98 | |||
99 | irqvector[irq_no](); | ||
100 | |||
101 | /* clear interrupt */ | ||
102 | INTC_ICCR = (1 << irq_no); | ||
103 | |||
104 | asm volatile( "add sp, sp, #8 \n" /* Cleanup stack */ | ||
105 | "ldmfd sp!, {r0-r7, ip, lr} \n" /* Restore context */ | ||
106 | "subs pc, lr, #4 \n"); /* Return from IRQ */ | ||
107 | } | ||
108 | |||
109 | void fiq_dummy(void) | ||
110 | { | ||
111 | asm volatile ( | ||
112 | "subs pc, lr, #4 \r\n" | ||
113 | ); | ||
114 | } | ||
115 | |||
116 | |||
117 | void system_init(void) | ||
118 | { | ||
119 | return; | ||
120 | } | ||
121 | |||
122 | /* not tested */ | ||
123 | void system_reboot(void) | ||
124 | { | ||
125 | /* use Watchdog to reset */ | ||
126 | WDTLR = 1; | ||
127 | WDTCON = (1<<4) | (1<<3); | ||
128 | |||
129 | /* Wait for reboot to kick in */ | ||
130 | while(1); | ||
131 | } | ||
132 | |||
133 | void system_exception_wait(void) | ||
134 | { | ||
135 | while(1); | ||
136 | } | ||
137 | |||
138 | int system_memory_guard(int newmode) | ||
139 | { | ||
140 | (void)newmode; | ||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | /* usecs may be at most 2^32/200 (~21 seconds) for 200MHz max cpu freq */ | ||
145 | void udelay(unsigned usecs) | ||
146 | { | ||
147 | unsigned cycles_per_usec; | ||
148 | unsigned delay; | ||
149 | |||
150 | if (cpu_frequency == CPUFREQ_MAX) { | ||
151 | cycles_per_usec = (CPUFREQ_MAX + 999999) / 1000000; | ||
152 | } else { | ||
153 | cycles_per_usec = (CPUFREQ_NORMAL + 999999) / 1000000; | ||
154 | } | ||
155 | |||
156 | delay = (usecs * cycles_per_usec + 3) / 4; | ||
157 | |||
158 | asm volatile( | ||
159 | "1: subs %0, %0, #1 \n" /* 1 cycle */ | ||
160 | " bne 1b \n" /* 3 cycles */ | ||
161 | : : "r"(delay) | ||
162 | ); | ||
163 | } | ||
164 | |||
diff --git a/firmware/target/arm/rk27xx/system-target.h b/firmware/target/arm/rk27xx/system-target.h new file mode 100644 index 0000000000..fb904091b1 --- /dev/null +++ b/firmware/target/arm/rk27xx/system-target.h | |||
@@ -0,0 +1,44 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2008 Rafaël Carré | ||
11 | * Copyright (C) 2011 Marcin Bukat | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version 2 | ||
16 | * of the License, or (at your option) any later version. | ||
17 | * | ||
18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
19 | * KIND, either express or implied. | ||
20 | * | ||
21 | ****************************************************************************/ | ||
22 | #ifndef SYSTEM_TARGET_H | ||
23 | #define SYSTEM_TARGET_H | ||
24 | |||
25 | #include "system-arm.h" | ||
26 | #include "panic.h" | ||
27 | |||
28 | void udelay(unsigned usecs); | ||
29 | static inline void mdelay(unsigned msecs) | ||
30 | { | ||
31 | udelay(1000 * msecs); | ||
32 | } | ||
33 | |||
34 | /* this needs more testing */ | ||
35 | static inline void core_sleep(void) | ||
36 | { | ||
37 | enable_irq(); | ||
38 | SCU_CPUPD = 0xdeedbabe; | ||
39 | } | ||
40 | |||
41 | #define CPUFREQ_NORMAL 200000000 | ||
42 | #define CPUFREQ_MAX 200000000 | ||
43 | |||
44 | #endif /* SYSTEM_TARGET_H */ | ||
diff --git a/firmware/target/arm/rk27xx/timer-rk27xx.c b/firmware/target/arm/rk27xx/timer-rk27xx.c new file mode 100644 index 0000000000..4493ccdfa9 --- /dev/null +++ b/firmware/target/arm/rk27xx/timer-rk27xx.c | |||
@@ -0,0 +1,74 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 by Marcin Bukat | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include "config.h" | ||
23 | |||
24 | #include "inttypes.h" | ||
25 | #include "system.h" | ||
26 | #include "timer.h" | ||
27 | |||
28 | void INT_TIMER1(void) | ||
29 | { | ||
30 | /* clear interrupt */ | ||
31 | TMR1CON &= ~(1<<2); | ||
32 | |||
33 | if (pfn_timer != NULL) | ||
34 | { | ||
35 | pfn_timer(); | ||
36 | } | ||
37 | } | ||
38 | |||
39 | bool timer_set(long cycles, bool start) | ||
40 | { | ||
41 | /* optionally unregister any previously registered timer user */ | ||
42 | if (start) | ||
43 | { | ||
44 | if (pfn_unregister != NULL) | ||
45 | { | ||
46 | pfn_unregister(); | ||
47 | pfn_unregister = NULL; | ||
48 | } | ||
49 | } | ||
50 | |||
51 | TMR1LR = cycles; | ||
52 | TMR1CON = (1<<7) | (1<<1); /* periodic, 1/1 */ | ||
53 | |||
54 | /* unmask timer1 interrupt */ | ||
55 | INTC_IMR |= (1<<3); | ||
56 | |||
57 | /* enable timer1 interrupt */ | ||
58 | INTC_IECR |= (1<<3); | ||
59 | |||
60 | return true; | ||
61 | } | ||
62 | |||
63 | bool timer_start(void) | ||
64 | { | ||
65 | TMR1CON |= (1 << 8); /* timer1 enable */ | ||
66 | |||
67 | return true; | ||
68 | } | ||
69 | |||
70 | void timer_stop(void) | ||
71 | { | ||
72 | TMR1CON &= ~(1 << 8); /* timer1 disable */ | ||
73 | } | ||
74 | |||
diff --git a/firmware/target/arm/thread-arm.c b/firmware/target/arm/thread-arm.c index 84a3aecbd7..83bdb9288d 100644 --- a/firmware/target/arm/thread-arm.c +++ b/firmware/target/arm/thread-arm.c | |||
@@ -109,7 +109,7 @@ static inline void core_sleep(void) | |||
109 | } | 109 | } |
110 | #else | 110 | #else |
111 | /* Skip this if special code is required and implemented */ | 111 | /* Skip this if special code is required and implemented */ |
112 | #ifndef CPU_PP | 112 | #if !(defined(CPU_PP)) && CONFIG_CPU != RK27XX |
113 | static inline void core_sleep(void) | 113 | static inline void core_sleep(void) |
114 | { | 114 | { |
115 | #warning core_sleep not implemented, battery life will be decreased | 115 | #warning core_sleep not implemented, battery life will be decreased |