diff options
author | Dominik Wenger <domonoky@googlemail.com> | 2009-10-22 17:45:02 +0000 |
---|---|---|
committer | Dominik Wenger <domonoky@googlemail.com> | 2009-10-22 17:45:02 +0000 |
commit | 5b4938a8ca8494afa560200b67eb76df4224caea (patch) | |
tree | a3051a2e0abf058d9b8a7b09483d3a3f381b8e50 | |
parent | 724d1e0f3cfba44d7aa4248d15c3ce35a718a91f (diff) | |
download | rockbox-5b4938a8ca8494afa560200b67eb76df4224caea.tar.gz rockbox-5b4938a8ca8494afa560200b67eb76df4224caea.zip |
Working Bootloader for mini2440.
Flyspray: FS#10701
Author: Bob Cousins
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@23316 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | bootloader/mini2440.c | 24 | ||||
-rw-r--r-- | firmware/SOURCES | 8 | ||||
-rw-r--r-- | firmware/export/s3c2440.h | 131 | ||||
-rw-r--r-- | firmware/export/sd.h | 43 | ||||
-rw-r--r-- | firmware/target/arm/s3c2440/dma-s3c2440.c | 207 | ||||
-rw-r--r-- | firmware/target/arm/s3c2440/dma-target.h | 59 | ||||
-rw-r--r-- | firmware/target/arm/s3c2440/sd-s3c2440.c | 911 | ||||
-rw-r--r-- | firmware/target/arm/s3c2440/uart-s3c2440.c | 248 | ||||
-rw-r--r-- | firmware/target/arm/s3c2440/uart-s3c2440.h | 48 |
9 files changed, 1655 insertions, 24 deletions
diff --git a/bootloader/mini2440.c b/bootloader/mini2440.c index c17f386b5b..dd811600f3 100644 --- a/bootloader/mini2440.c +++ b/bootloader/mini2440.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
7 | * \/ \/ \/ \/ \/ | 7 | * \/ \/ \/ \/ \/ |
8 | * | 8 | * $Id$ |
9 | * | 9 | * |
10 | * Copyright (C) 2009 by Bob Cousins, Lyre Project | 10 | * Copyright (C) 2009 by Bob Cousins, Lyre Project |
11 | * | 11 | * |
@@ -43,10 +43,8 @@ | |||
43 | #include "backlight-target.h" | 43 | #include "backlight-target.h" |
44 | #include "lcd-target.h" | 44 | #include "lcd-target.h" |
45 | #include "debug-target.h" | 45 | #include "debug-target.h" |
46 | #if 0 | ||
47 | #include "dma-target.h" | 46 | #include "dma-target.h" |
48 | #include "uart-s3c2440.h" | 47 | #include "uart-s3c2440.h" |
49 | #endif | ||
50 | #include "led-mini2440.h" | 48 | #include "led-mini2440.h" |
51 | 49 | ||
52 | /* Show the Rockbox logo - in show_logo.c */ | 50 | /* Show the Rockbox logo - in show_logo.c */ |
@@ -55,14 +53,11 @@ extern int show_logo(void); | |||
55 | 53 | ||
56 | int main(void) | 54 | int main(void) |
57 | { | 55 | { |
58 | #if 0 | ||
59 | /* required later */ | 56 | /* required later */ |
60 | unsigned char* loadbuffer; | 57 | unsigned char* loadbuffer; |
61 | int buffer_size; | 58 | int buffer_size; |
62 | int rc; | 59 | int rc; |
63 | int(*kernel_entry)(void); | 60 | int(*kernel_entry)(void); |
64 | #endif | ||
65 | int start, elapsed; | ||
66 | 61 | ||
67 | led_init(); | 62 | led_init(); |
68 | clear_leds(LED_ALL); | 63 | clear_leds(LED_ALL); |
@@ -74,20 +69,11 @@ int main(void) | |||
74 | lcd_init(); | 69 | lcd_init(); |
75 | lcd_setfont(FONT_SYSFIXED); | 70 | lcd_setfont(FONT_SYSFIXED); |
76 | button_init(); | 71 | button_init(); |
77 | #if 0 | ||
78 | dma_init(); | 72 | dma_init(); |
79 | uart_init_device(UART_DEBUG); | 73 | uart_init_device(UART_DEBUG); |
80 | #endif | ||
81 | /* mini2440_test(); */ | ||
82 | |||
83 | #if 1 | ||
84 | show_logo(); | ||
85 | /* pause here for now */ | ||
86 | led_flash(LED1|LED4, LED2|LED3); | ||
87 | #endif | ||
88 | 74 | ||
89 | 75 | /* mini2440_test(); */ | |
90 | #if 0 | 76 | |
91 | /* TODO */ | 77 | /* TODO */ |
92 | 78 | ||
93 | /* Show debug messages if button is pressed */ | 79 | /* Show debug messages if button is pressed */ |
@@ -130,15 +116,11 @@ int main(void) | |||
130 | 116 | ||
131 | if (rc == EOK) | 117 | if (rc == EOK) |
132 | { | 118 | { |
133 | uart_printf ("entering kernel\n"); | ||
134 | cpucache_invalidate(); | 119 | cpucache_invalidate(); |
135 | kernel_entry = (void*) loadbuffer; | 120 | kernel_entry = (void*) loadbuffer; |
136 | rc = kernel_entry(); | 121 | rc = kernel_entry(); |
137 | } | 122 | } |
138 | 123 | ||
139 | uart_printf ("stopping %d\n", rc); | ||
140 | #endif | ||
141 | |||
142 | /* end stop - should not get here */ | 124 | /* end stop - should not get here */ |
143 | led_flash(LED_ALL, LED_NONE); | 125 | led_flash(LED_ALL, LED_NONE); |
144 | while (1); /* avoid warning */ | 126 | while (1); /* avoid warning */ |
diff --git a/firmware/SOURCES b/firmware/SOURCES index a3c47a6ddb..5406b161ad 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES | |||
@@ -1399,24 +1399,26 @@ target/arm/at91sam/lyre_proto1/timer-lyre_proto1.c | |||
1399 | target/arm/lcd-as-memframe.S | 1399 | target/arm/lcd-as-memframe.S |
1400 | target/arm/mmu-arm.S | 1400 | target/arm/mmu-arm.S |
1401 | target/arm/s3c2440/debug-s3c2440.c | 1401 | target/arm/s3c2440/debug-s3c2440.c |
1402 | target/arm/s3c2440/dma-s3c2440.c | ||
1402 | target/arm/s3c2440/kernel-s3c2440.c | 1403 | target/arm/s3c2440/kernel-s3c2440.c |
1403 | target/arm/s3c2440/lcd-s3c2440.c | 1404 | target/arm/s3c2440/lcd-s3c2440.c |
1405 | target/arm/s3c2440/sd-s3c2440.c | ||
1404 | target/arm/s3c2440/system-s3c2440.c | 1406 | target/arm/s3c2440/system-s3c2440.c |
1407 | target/arm/s3c2440/uart-s3c2440.c | ||
1405 | target/arm/s3c2440/mini2440/backlight-mini2440.c | 1408 | target/arm/s3c2440/mini2440/backlight-mini2440.c |
1406 | target/arm/s3c2440/mini2440/button-mini2440.c | 1409 | target/arm/s3c2440/mini2440/button-mini2440.c |
1407 | target/arm/s3c2440/mini2440/led-mini2440.c | 1410 | target/arm/s3c2440/mini2440/led-mini2440.c |
1408 | target/arm/s3c2440/mini2440/power-mini2440.c | 1411 | target/arm/s3c2440/mini2440/power-mini2440.c |
1409 | #ifdef BOOTLOADER | 1412 | #ifdef BOOTLOADER |
1410 | /*target/arm/s3c2440/mini2440/mini2440_test.c*/ | ||
1411 | #endif | 1413 | #endif |
1412 | #ifndef BOOTLOADER | 1414 | #ifndef BOOTLOADER |
1413 | target/arm/s3c2440/mini2440/adc-mini2440.c | 1415 | target/arm/s3c2440/mini2440/adc-mini2440.c |
1414 | target/arm/s3c2440/mini2440/i2c-mini2440.c | 1416 | //target/arm/s3c2440/mini2440/i2c-mini2440.c |
1415 | target/arm/s3c2440/mini2440/pcm-mini2440.c | 1417 | target/arm/s3c2440/mini2440/pcm-mini2440.c |
1416 | target/arm/s3c2440/mini2440/powermgmt-mini2440.c | 1418 | target/arm/s3c2440/mini2440/powermgmt-mini2440.c |
1417 | target/arm/s3c2440/mini2440/power-mini2440.c | 1419 | target/arm/s3c2440/mini2440/power-mini2440.c |
1418 | target/arm/s3c2440/mini2440/timer-mini2440.c | 1420 | target/arm/s3c2440/mini2440/timer-mini2440.c |
1419 | target/arm/s3c2440/mini2440/usb-mini2440.c | 1421 | //target/arm/s3c2440/mini2440/usb-mini2440.c |
1420 | #endif | 1422 | #endif |
1421 | #endif /* SIMULATOR */ | 1423 | #endif /* SIMULATOR */ |
1422 | #endif /* MINI2440 */ | 1424 | #endif /* MINI2440 */ |
diff --git a/firmware/export/s3c2440.h b/firmware/export/s3c2440.h index 5f595214a1..c783b37f29 100644 --- a/firmware/export/s3c2440.h +++ b/firmware/export/s3c2440.h | |||
@@ -212,6 +212,41 @@ | |||
212 | #define DMASKTRIG_ON (1 << 1) | 212 | #define DMASKTRIG_ON (1 << 1) |
213 | #define DMASKTRIG_SW_TRIG (1 << 0) | 213 | #define DMASKTRIG_SW_TRIG (1 << 0) |
214 | 214 | ||
215 | /* Get DMA request source (HWSRCSEL) from the map for the specified channel */ | ||
216 | #define DMA_GET_SRC(map,channel) ( ((map) << (channel*8)) & 0xff) | ||
217 | |||
218 | #define DMA_CH0(x) (x<<0) | ||
219 | #define DMA_CH1(x) (x<<8) | ||
220 | #define DMA_CH2(x) (x<<16) | ||
221 | #define DMA_CH3(x) (x<<24) | ||
222 | |||
223 | #define DMA_INVALID 0xff | ||
224 | #define DMA_INV0 DMA_CH0(DMA_INVALID) | ||
225 | #define DMA_INV1 DMA_CH1(DMA_INVALID) | ||
226 | #define DMA_INV2 DMA_CH2(DMA_INVALID) | ||
227 | #define DMA_INV3 DMA_CH3(DMA_INVALID) | ||
228 | |||
229 | /* This map encodes the DMA request source field (HWSRCSEL) since it's value | ||
230 | * depends on channel number and peripheral type. | ||
231 | */ | ||
232 | #define DMA_SRC_MAP_XDREQ0 (DMA_CH0(0) | DMA_INV1 | DMA_INV2 | DMA_INV3) | ||
233 | #define DMA_SRC_MAP_XDREQ1 (DMA_INV0 | DMA_CH1(0) | DMA_INV2 | DMA_INV3) | ||
234 | #define DMA_SRC_MAP_USB_EP1 (DMA_CH0(4) | DMA_INV1 | DMA_INV2 | DMA_INV3) | ||
235 | #define DMA_SRC_MAP_USB_EP2 (DMA_INV0 | DMA_CH1(4) | DMA_INV2 | DMA_INV3) | ||
236 | #define DMA_SRC_MAP_USB_EP3 (DMA_INV0 | DMA_INV1 | DMA_CH2(4) | DMA_INV3) | ||
237 | #define DMA_SRC_MAP_USB_EP4 (DMA_INV0 | DMA_INV1 | DMA_INV2 | DMA_CH3(4)) | ||
238 | #define DMA_SRC_MAP_SDI (DMA_CH0(2) | DMA_CH1(6) | DMA_CH2(2) | DMA_CH3(1)) | ||
239 | #define DMA_SRC_MAP_UART0 (DMA_CH0(1) | DMA_INV1 | DMA_INV2 | DMA_INV3) | ||
240 | #define DMA_SRC_MAP_UART1 (DMA_INV0 | DMA_CH1(1) | DMA_INV2 | DMA_INV3) | ||
241 | #define DMA_SRC_MAP_UART2 (DMA_INV0 | DMA_INV1 | DMA_INV2 | DMA_CH3(0)) | ||
242 | #define DMA_SRC_MAP_I2SSDO (DMA_CH0(5) | DMA_INV1 | DMA_CH2(0) | DMA_INV3) | ||
243 | #define DMA_SRC_MAP_I2SSDI (DMA_INV0 | DMA_CH1(2) | DMA_CH2(1) | DMA_INV3) | ||
244 | #define DMA_SRC_MAP_PCMOUT (DMA_INV0 | DMA_CH1(5) | DMA_INV2 | DMA_CH3(6)) | ||
245 | #define DMA_SRC_MAP_PCMIN (DMA_CH0(6) | DMA_INV1 | DMA_CH2(5) | DMA_INV3) | ||
246 | #define DMA_SRC_MAP_MICIN (DMA_INV0 | DMA_INV1 | DMA_CH2(6) | DMA_CH3(5)) | ||
247 | #define DMA_SRC_MAP_SPI0 (DMA_INV0 | DMA_CH1(3) | DMA_INV2 | DMA_INV3) | ||
248 | #define DMA_SRC_MAP_SPI1 (DMA_INV0 | DMA_INV1 | DMA_INV2 | DMA_CH3(2)) | ||
249 | #define DMA_SRC_MAP_TIMER (DMA_CH0(3) | DMA_INV1 | DMA_CH2(3) | DMA_CH3(3)) | ||
215 | 250 | ||
216 | /* Clock & Power Management */ | 251 | /* Clock & Power Management */ |
217 | 252 | ||
@@ -543,6 +578,102 @@ | |||
543 | #define SDIDAT_HBE (*(volatile unsigned short *)0x5A000041) /* 16 */ | 578 | #define SDIDAT_HBE (*(volatile unsigned short *)0x5A000041) /* 16 */ |
544 | #define SDIDAT_BBE (*(volatile unsigned char *)0x5A000043) /* 8 */ | 579 | #define SDIDAT_BBE (*(volatile unsigned char *)0x5A000043) /* 8 */ |
545 | 580 | ||
581 | /* SDI register bit definitions. S3C2440 is a superset of S3C2410 */ | ||
582 | |||
583 | #define S3C2440_SDICON_SDRESET (1<<8) | ||
584 | #define S3C2440_SDICON_MMCCLOCK (1<<5) | ||
585 | #define S3C2410_SDICON_BYTEORDER (1<<4) | ||
586 | #define S3C2410_SDICON_SDIOIRQ (1<<3) | ||
587 | #define S3C2410_SDICON_RWAITEN (1<<2) | ||
588 | #define S3C2410_SDICON_FIFORESET (1<<1) | ||
589 | #define S3C2410_SDICON_CLOCKTYPE (1<<0) | ||
590 | |||
591 | #define S3C2410_SDICMDCON_ABORT (1<<12) | ||
592 | #define S3C2410_SDICMDCON_WITHDATA (1<<11) | ||
593 | #define S3C2410_SDICMDCON_LONGRSP (1<<10) | ||
594 | #define S3C2410_SDICMDCON_WAITRSP (1<<9) | ||
595 | #define S3C2410_SDICMDCON_CMDSTART (1<<8) | ||
596 | #define S3C2410_SDICMDCON_SENDERHOST (1<<6) | ||
597 | #define S3C2410_SDICMDCON_INDEX (0x3f) | ||
598 | |||
599 | #define S3C2410_SDICMDSTAT_CRCFAIL (1<<12) | ||
600 | #define S3C2410_SDICMDSTAT_CMDSENT (1<<11) | ||
601 | #define S3C2410_SDICMDSTAT_CMDTIMEOUT (1<<10) | ||
602 | #define S3C2410_SDICMDSTAT_RSPFIN (1<<9) | ||
603 | #define S3C2410_SDICMDSTAT_XFERING (1<<8) | ||
604 | #define S3C2410_SDICMDSTAT_INDEX (0xff) | ||
605 | |||
606 | #define S3C2440_SDIDCON_DS_BYTE (0<<22) | ||
607 | #define S3C2440_SDIDCON_DS_HALFWORD (1<<22) | ||
608 | #define S3C2440_SDIDCON_DS_WORD (2<<22) | ||
609 | #define S3C2410_SDIDCON_IRQPERIOD (1<<21) | ||
610 | #define S3C2410_SDIDCON_TXAFTERRESP (1<<20) | ||
611 | #define S3C2410_SDIDCON_RXAFTERCMD (1<<19) | ||
612 | #define S3C2410_SDIDCON_BUSYAFTERCMD (1<<18) | ||
613 | #define S3C2410_SDIDCON_BLOCKMODE (1<<17) | ||
614 | #define S3C2410_SDIDCON_WIDEBUS (1<<16) | ||
615 | #define S3C2410_SDIDCON_DMAEN (1<<15) | ||
616 | #define S3C2410_SDIDCON_STOP (0<<14) | ||
617 | #define S3C2440_SDIDCON_DATSTART (1<<14) | ||
618 | #define S3C2410_SDIDCON_DATMODE (3<<12) | ||
619 | #define S3C2410_SDIDCON_BLKNUM (0xfff) | ||
620 | |||
621 | /* constants for S3C2410_SDIDCON_DATMODE */ | ||
622 | #define S3C2410_SDIDCON_XFER_READY (0<<12) | ||
623 | #define S3C2410_SDIDCON_XFER_CHKSTART (1<<12) | ||
624 | #define S3C2410_SDIDCON_XFER_RXSTART (2<<12) | ||
625 | #define S3C2410_SDIDCON_XFER_TXSTART (3<<12) | ||
626 | |||
627 | #define S3C2410_SDIDCNT_BLKNUM_MASK (0xFFF) | ||
628 | #define S3C2410_SDIDCNT_BLKNUM_SHIFT (12) | ||
629 | |||
630 | #define S3C2410_SDIDSTA_RDYWAITREQ (1<<10) | ||
631 | #define S3C2410_SDIDSTA_SDIOIRQDETECT (1<<9) | ||
632 | #define S3C2410_SDIDSTA_FIFOFAIL (1<<8) /* reserved on 2440 */ | ||
633 | #define S3C2410_SDIDSTA_CRCFAIL (1<<7) | ||
634 | #define S3C2410_SDIDSTA_RXCRCFAIL (1<<6) | ||
635 | #define S3C2410_SDIDSTA_DATATIMEOUT (1<<5) | ||
636 | #define S3C2410_SDIDSTA_XFERFINISH (1<<4) | ||
637 | #define S3C2410_SDIDSTA_BUSYFINISH (1<<3) | ||
638 | #define S3C2410_SDIDSTA_SBITERR (1<<2) /* reserved on 2410a/2440 */ | ||
639 | #define S3C2410_SDIDSTA_TXDATAON (1<<1) | ||
640 | #define S3C2410_SDIDSTA_RXDATAON (1<<0) | ||
641 | |||
642 | #define S3C2410_SDIDSTA_CLEAR_BITS ( S3C2410_SDIDSTA_BUSYFINISH | \ | ||
643 | S3C2410_SDIDSTA_XFERFINISH | S3C2410_SDIDSTA_DATATIMEOUT | \ | ||
644 | S3C2410_SDIDSTA_RXCRCFAIL | S3C2410_SDIDSTA_CRCFAIL | \ | ||
645 | S3C2410_SDIDSTA_SDIOIRQDETECT | S3C2410_SDIDSTA_RDYWAITREQ ) | ||
646 | |||
647 | #define S3C2440_SDIFSTA_FIFORESET (1<<16) | ||
648 | #define S3C2440_SDIFSTA_FIFOFAIL (3<<14) /* 3 is correct (2 bits) */ | ||
649 | #define S3C2410_SDIFSTA_TFDET (1<<13) | ||
650 | #define S3C2410_SDIFSTA_RFDET (1<<12) | ||
651 | #define S3C2410_SDIFSTA_TFHALF (1<<11) | ||
652 | #define S3C2410_SDIFSTA_TFEMPTY (1<<10) | ||
653 | #define S3C2410_SDIFSTA_RFLAST (1<<9) | ||
654 | #define S3C2410_SDIFSTA_RFFULL (1<<8) | ||
655 | #define S3C2410_SDIFSTA_RFHALF (1<<7) | ||
656 | #define S3C2410_SDIFSTA_COUNTMASK (0x7f) | ||
657 | |||
658 | #define S3C2410_SDIIMSK_RESPONSECRC (1<<17) | ||
659 | #define S3C2410_SDIIMSK_CMDSENT (1<<16) | ||
660 | #define S3C2410_SDIIMSK_CMDTIMEOUT (1<<15) | ||
661 | #define S3C2410_SDIIMSK_RESPONSEND (1<<14) | ||
662 | #define S3C2410_SDIIMSK_READWAIT (1<<13) | ||
663 | #define S3C2410_SDIIMSK_SDIOIRQ (1<<12) | ||
664 | #define S3C2410_SDIIMSK_FIFOFAIL (1<<11) | ||
665 | #define S3C2410_SDIIMSK_CRCSTATUS (1<<10) | ||
666 | #define S3C2410_SDIIMSK_DATACRC (1<<9) | ||
667 | #define S3C2410_SDIIMSK_DATATIMEOUT (1<<8) | ||
668 | #define S3C2410_SDIIMSK_DATAFINISH (1<<7) | ||
669 | #define S3C2410_SDIIMSK_BUSYFINISH (1<<6) | ||
670 | #define S3C2410_SDIIMSK_SBITERR (1<<5) /* reserved 2440/2410a */ | ||
671 | #define S3C2410_SDIIMSK_TXFIFOHALF (1<<4) | ||
672 | #define S3C2410_SDIIMSK_TXFIFOEMPTY (1<<3) | ||
673 | #define S3C2410_SDIIMSK_RXFIFOLAST (1<<2) | ||
674 | #define S3C2410_SDIIMSK_RXFIFOFULL (1<<1) | ||
675 | #define S3C2410_SDIIMSK_RXFIFOHALF (1<<0) | ||
676 | |||
546 | /* AC97 Audio-CODEC Interface */ | 677 | /* AC97 Audio-CODEC Interface */ |
547 | 678 | ||
548 | #define AC_GLBCTRL (*(volatile unsigned long *)0x5B000000) /* AC97 global control register */ | 679 | #define AC_GLBCTRL (*(volatile unsigned long *)0x5B000000) /* AC97 global control register */ |
diff --git a/firmware/export/sd.h b/firmware/export/sd.h index 0b64bd768d..7204b1a0bf 100644 --- a/firmware/export/sd.h +++ b/firmware/export/sd.h | |||
@@ -100,4 +100,47 @@ int sd_num_drives(int first_drive); | |||
100 | #define SD_SEND_SCR 51 /* acmd51 */ | 100 | #define SD_SEND_SCR 51 /* acmd51 */ |
101 | #define SD_APP_CMD 55 | 101 | #define SD_APP_CMD 55 |
102 | 102 | ||
103 | /* | ||
104 | SD/MMC status in R1, for native mode (SPI bits are different) | ||
105 | Type | ||
106 | e : error bit | ||
107 | s : status bit | ||
108 | r : detected and set for the actual command response | ||
109 | x : detected and set during command execution. the host must poll | ||
110 | the card by sending status command in order to read these bits. | ||
111 | Clear condition | ||
112 | a : according to the card state | ||
113 | b : always related to the previous command. Reception of | ||
114 | a valid command will clear it (with a delay of one command) | ||
115 | c : clear by read | ||
116 | */ | ||
117 | |||
118 | #define SD_R1_OUT_OF_RANGE (1 << 31) /* erx, c */ | ||
119 | #define SD_R1_ADDRESS_ERROR (1 << 30) /* erx, c */ | ||
120 | #define SD_R1_BLOCK_LEN_ERROR (1 << 29) /* erx, c */ | ||
121 | #define SD_R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */ | ||
122 | #define SD_R1_ERASE_PARAM (1 << 27) /* exx, c */ | ||
123 | #define SD_R1_WP_VIOLATION (1 << 26) /* erx, c */ | ||
124 | #define SD_R1_CARD_IS_LOCKED (1 << 25) /* sx, a */ | ||
125 | #define SD_R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */ | ||
126 | #define SD_R1_COM_CRC_ERROR (1 << 23) /* er, b */ | ||
127 | #define SD_R1_ILLEGAL_COMMAND (1 << 22) /* er, b */ | ||
128 | #define SD_R1_CARD_ECC_FAILED (1 << 21) /* erx, c */ | ||
129 | #define SD_R1_CC_ERROR (1 << 20) /* erx, c */ | ||
130 | #define SD_R1_ERROR (1 << 19) /* erx, c */ | ||
131 | #define SD_R1_UNDERRUN (1 << 18) /* ex, c */ | ||
132 | #define SD_R1_OVERRUN (1 << 17) /* ex, c */ | ||
133 | #define SD_R1_CSD_OVERWRITE (1 << 16) /* erx, c */ | ||
134 | #define SD_R1_WP_ERASE_SKIP (1 << 15) /* erx, c */ | ||
135 | #define SD_R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */ | ||
136 | #define SD_R1_ERASE_RESET (1 << 13) /* sr, c */ | ||
137 | #define SD_R1_STATUS(x) (x & 0xFFFFE000) | ||
138 | #define SD_R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */ | ||
139 | #define SD_R1_READY_FOR_DATA (1 << 8) /* sx, a */ | ||
140 | #define SD_R1_APP_CMD (1 << 5) /* sr, c */ | ||
141 | #define SD_R1_AKE_SEQ_ERROR (1 << 3) /* er, c */ | ||
142 | |||
143 | /* SD OCR bits */ | ||
144 | #define SD_OCR_CARD_CAPACITY_STATUS (1 << 30) /* Card Capacity Status */ | ||
145 | |||
103 | #endif | 146 | #endif |
diff --git a/firmware/target/arm/s3c2440/dma-s3c2440.c b/firmware/target/arm/s3c2440/dma-s3c2440.c new file mode 100644 index 0000000000..b83897cb22 --- /dev/null +++ b/firmware/target/arm/s3c2440/dma-s3c2440.c | |||
@@ -0,0 +1,207 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright 2009 by Bob Cousins | ||
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 <stdbool.h> | ||
23 | #include "config.h" | ||
24 | #include "panic.h" | ||
25 | #include "system.h" | ||
26 | #include "mmu-arm.h" | ||
27 | #include "s3c2440.h" | ||
28 | #include "dma-target.h" | ||
29 | #include "system-target.h" | ||
30 | |||
31 | #define NUM_CHANNELS 4 | ||
32 | |||
33 | static int dma_used = 0; | ||
34 | |||
35 | /* Status flags */ | ||
36 | #define STATUS_CHANNEL_ACTIVE (1<<0) | ||
37 | |||
38 | struct dma_channel_state | ||
39 | { | ||
40 | volatile unsigned status; | ||
41 | void (*callback)(void); | ||
42 | } dma_state [NUM_CHANNELS]; | ||
43 | |||
44 | struct dma_channel_regs | ||
45 | { | ||
46 | volatile unsigned long disrc; | ||
47 | volatile unsigned long disrcc; | ||
48 | volatile unsigned long didst; | ||
49 | volatile unsigned long didstc; | ||
50 | volatile unsigned long dcon; | ||
51 | volatile unsigned long dstat; | ||
52 | volatile unsigned long dcsrc; | ||
53 | volatile unsigned long dcdst; | ||
54 | volatile unsigned long dmasktrig; | ||
55 | volatile unsigned long reserved [7]; /* pad to 0x40 bytes */ | ||
56 | }; | ||
57 | |||
58 | |||
59 | struct dma_channel_regs *dma_regs [4] = | ||
60 | { | ||
61 | (struct dma_channel_regs *) &DISRC0, | ||
62 | (struct dma_channel_regs *) &DISRC1, | ||
63 | (struct dma_channel_regs *) &DISRC2, | ||
64 | (struct dma_channel_regs *) &DISRC3 | ||
65 | } | ||
66 | ; | ||
67 | |||
68 | |||
69 | void dma_init(void) | ||
70 | { | ||
71 | /* TODO */ | ||
72 | |||
73 | /* Enable interupt on DMA Finish */ | ||
74 | /* Clear pending source */ | ||
75 | SRCPND = DMA0_MASK | DMA1_MASK | DMA2_MASK | DMA3_MASK; | ||
76 | INTPND = DMA0_MASK | DMA1_MASK | DMA2_MASK | DMA3_MASK; | ||
77 | |||
78 | /* Enable interrupt in controller */ | ||
79 | s3c_regclr32(&INTMOD, DMA0_MASK | DMA1_MASK | DMA2_MASK | DMA3_MASK); | ||
80 | s3c_regclr32(&INTMSK, DMA0_MASK | DMA1_MASK | DMA2_MASK | DMA3_MASK); | ||
81 | } | ||
82 | |||
83 | void dma_retain(void) | ||
84 | { | ||
85 | /* TODO */ | ||
86 | dma_used++; | ||
87 | if(dma_used > 0) | ||
88 | { | ||
89 | /* Enable DMA controller, clock? */ | ||
90 | } | ||
91 | } | ||
92 | |||
93 | void dma_release(void) | ||
94 | { | ||
95 | /* TODO */ | ||
96 | if (dma_used > 0) | ||
97 | dma_used--; | ||
98 | if(dma_used == 0) | ||
99 | { | ||
100 | /* Disable DMA */ | ||
101 | } | ||
102 | } | ||
103 | |||
104 | |||
105 | inline void dma_disable_channel(int channel) | ||
106 | { | ||
107 | struct dma_channel_regs *regs = dma_regs [channel]; | ||
108 | |||
109 | /* disable the specified channel */ | ||
110 | |||
111 | /* Reset the channel */ | ||
112 | regs->dmasktrig |= DMASKTRIG_STOP; | ||
113 | |||
114 | /* Wait for DMA controller to be ready */ | ||
115 | while(regs->dmasktrig & DMASKTRIG_ON) | ||
116 | ; | ||
117 | while(regs->dstat & DSTAT_STAT_BUSY) | ||
118 | ; | ||
119 | } | ||
120 | |||
121 | void dma_enable_channel(int channel, struct dma_request *request) | ||
122 | { | ||
123 | struct dma_channel_regs *regs = dma_regs [channel]; | ||
124 | |||
125 | /* TODO - transfer sizes (assumes word) */ | ||
126 | |||
127 | if (DMA_GET_SRC(request->source_map, channel) == DMA_INVALID) | ||
128 | panicf ("DMA: invalid channel"); | ||
129 | |||
130 | /* setup a transfer on specified channel */ | ||
131 | dma_disable_channel (channel); | ||
132 | |||
133 | if((unsigned long)request->source_addr < UNCACHED_BASE_ADDR) | ||
134 | regs->disrc = (unsigned long)request->source_addr + UNCACHED_BASE_ADDR; | ||
135 | else | ||
136 | regs->disrc = (unsigned long)request->source_addr; | ||
137 | regs->disrcc = request->source_control; | ||
138 | |||
139 | if((unsigned long)request->dest_addr < UNCACHED_BASE_ADDR) | ||
140 | regs->didst = (unsigned long)request->dest_addr + UNCACHED_BASE_ADDR; | ||
141 | else | ||
142 | regs->didst = (unsigned long)request->dest_addr; | ||
143 | regs->didstc = request->dest_control; | ||
144 | |||
145 | regs->dcon = request->control | request->count | | ||
146 | DMA_GET_SRC(request->source_map, channel) * DCON_HWSRCSEL; | ||
147 | |||
148 | dma_state [channel].callback = request->callback; | ||
149 | |||
150 | /* Activate the channel */ | ||
151 | invalidate_dcache_range((void *)request->dest_addr, request->count * 4); | ||
152 | |||
153 | dma_state [channel].status |= STATUS_CHANNEL_ACTIVE; | ||
154 | regs->dmasktrig = DMASKTRIG_ON; | ||
155 | |||
156 | if ((request->control & DCON_HW_SEL) == 0) | ||
157 | { | ||
158 | /* Start DMA */ | ||
159 | regs->dmasktrig |= DMASKTRIG_SW_TRIG; | ||
160 | } | ||
161 | |||
162 | } | ||
163 | |||
164 | /* ISRs */ | ||
165 | inline void generic_isr (unsigned channel) | ||
166 | { | ||
167 | if (dma_state [channel].status | STATUS_CHANNEL_ACTIVE) | ||
168 | { | ||
169 | if (dma_state [channel].callback) | ||
170 | /* call callback for relevant channel */ | ||
171 | dma_state [channel].callback(); | ||
172 | |||
173 | dma_state [channel].status &= ~STATUS_CHANNEL_ACTIVE; | ||
174 | } | ||
175 | } | ||
176 | |||
177 | void DMA0(void) | ||
178 | { | ||
179 | generic_isr (0); | ||
180 | /* Ack the interrupt */ | ||
181 | SRCPND = DMA0_MASK; | ||
182 | INTPND = DMA0_MASK; | ||
183 | } | ||
184 | |||
185 | void DMA1(void) | ||
186 | { | ||
187 | generic_isr (1); | ||
188 | /* Ack the interrupt */ | ||
189 | SRCPND = DMA1_MASK; | ||
190 | INTPND = DMA1_MASK; | ||
191 | } | ||
192 | |||
193 | void DMA2(void) | ||
194 | { | ||
195 | generic_isr (2); | ||
196 | /* Ack the interrupt */ | ||
197 | SRCPND = DMA2_MASK; | ||
198 | INTPND = DMA2_MASK; | ||
199 | } | ||
200 | |||
201 | void DMA3(void) | ||
202 | { | ||
203 | generic_isr (3); | ||
204 | /* Ack the interrupt */ | ||
205 | SRCPND = DMA3_MASK; | ||
206 | INTPND = DMA3_MASK; | ||
207 | } | ||
diff --git a/firmware/target/arm/s3c2440/dma-target.h b/firmware/target/arm/s3c2440/dma-target.h new file mode 100644 index 0000000000..1baf7feab5 --- /dev/null +++ b/firmware/target/arm/s3c2440/dma-target.h | |||
@@ -0,0 +1,59 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright © 2009 by Bob Cousins | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #ifndef _DMA_TARGET_H | ||
23 | #define _DMA_TARGET_H | ||
24 | |||
25 | #include <stdbool.h> | ||
26 | #include <stdlib.h> | ||
27 | |||
28 | /* DMA Channel assignments */ | ||
29 | #ifdef GIGABEAT_F | ||
30 | #define DMA_CHAN_ATA 0 | ||
31 | #define DMA_CHAN_AUDIO_OUT 2 | ||
32 | #elif defined(MINI2440) | ||
33 | #define DMA_CHAN_SD 0 | ||
34 | #define DMA_CHAN_AUDIO_OUT 2 | ||
35 | #else | ||
36 | #error Unsupported target | ||
37 | #endif | ||
38 | |||
39 | struct dma_request | ||
40 | { | ||
41 | volatile void *source_addr; | ||
42 | volatile void *dest_addr; | ||
43 | unsigned long count; | ||
44 | unsigned long source_control; | ||
45 | unsigned long dest_control; | ||
46 | unsigned long source_map; | ||
47 | unsigned long control; | ||
48 | void (*callback)(void); | ||
49 | }; | ||
50 | |||
51 | void dma_init(void); | ||
52 | void dma_enable_channel(int channel, struct dma_request *request); | ||
53 | |||
54 | inline void dma_disable_channel(int channel); | ||
55 | |||
56 | void dma_retain(void); | ||
57 | void dma_release(void); | ||
58 | |||
59 | #endif | ||
diff --git a/firmware/target/arm/s3c2440/sd-s3c2440.c b/firmware/target/arm/s3c2440/sd-s3c2440.c new file mode 100644 index 0000000000..78c9e9bf23 --- /dev/null +++ b/firmware/target/arm/s3c2440/sd-s3c2440.c | |||
@@ -0,0 +1,911 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2009 by Bob Cousins | ||
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 SD_DEBUG | ||
23 | |||
24 | #include "sd.h" | ||
25 | #include "system.h" | ||
26 | #include <string.h> | ||
27 | #include "hotswap.h" | ||
28 | #include "thread.h" | ||
29 | #include "panic.h" | ||
30 | |||
31 | #ifdef SD_DEBUG | ||
32 | #include "uart-s3c2440.h" | ||
33 | #endif | ||
34 | #include "dma-target.h" | ||
35 | #include "system-target.h" | ||
36 | #include "led-mini2440.h" | ||
37 | |||
38 | /* The configuration method is not very flexible. */ | ||
39 | #define CARD_NUM_SLOT 0 | ||
40 | #define NUM_CARDS 2 | ||
41 | |||
42 | #if NUM_CARDS < NUM_DRIVES | ||
43 | #error NUM_CARDS less than NUM_DRIVES | ||
44 | #endif | ||
45 | |||
46 | #define EC_OK 0 | ||
47 | #define EC_FAILED 1 | ||
48 | #define EC_NOCARD 2 | ||
49 | #define EC_WAIT_STATE_FAILED 3 | ||
50 | #define EC_POWER_UP 4 | ||
51 | #define EC_FIFO_WR_EMPTY 5 | ||
52 | #define EC_FIFO_WR_DONE 6 | ||
53 | #define EC_TRAN_READ_ENTRY 7 | ||
54 | #define EC_TRAN_READ_EXIT 8 | ||
55 | #define EC_TRAN_WRITE_ENTRY 9 | ||
56 | #define EC_TRAN_WRITE_EXIT 10 | ||
57 | #define EC_COMMAND 11 | ||
58 | #define EC_WRITE_PROTECT 12 | ||
59 | |||
60 | #define MIN_YIELD_PERIOD 1000 | ||
61 | #define UNALIGNED_NUM_SECTORS 10 | ||
62 | #define MAX_TRANSFER_ERRORS 10 | ||
63 | |||
64 | /* command flags for send_cmd */ | ||
65 | #define MCI_NO_FLAGS (0<<0) | ||
66 | #define MCI_RESP (1<<0) | ||
67 | #define MCI_LONG_RESP (1<<1) | ||
68 | #define MCI_ARG (1<<2) | ||
69 | |||
70 | #define INITIAL_CLK 400000 /* Initial clock */ | ||
71 | #define SD_CLK 24000000 /* Clock for SD cards */ | ||
72 | #define MMC_CLK 15000000 /* Clock for MMC cards */ | ||
73 | |||
74 | #define SD_ACTIVE_LED LED4 | ||
75 | |||
76 | #ifdef SD_DEBUG | ||
77 | #define dbgprintf uart_printf | ||
78 | #else | ||
79 | #define dbgprintf(...) | ||
80 | #endif | ||
81 | |||
82 | struct sd_card_status | ||
83 | { | ||
84 | int retry; | ||
85 | int retry_max; | ||
86 | }; | ||
87 | |||
88 | /** static, private data **/ | ||
89 | |||
90 | /* for compatibility */ | ||
91 | static long last_disk_activity = -1; | ||
92 | |||
93 | static bool initialized = false; | ||
94 | static bool sd_enabled = false; | ||
95 | static long next_yield = 0; | ||
96 | |||
97 | static tCardInfo card_info [NUM_CARDS]; | ||
98 | |||
99 | #ifdef HAVE_MULTIDRIVE | ||
100 | static int curr_card = 0; /* current active card */ | ||
101 | #if 0 | ||
102 | static struct sd_card_status sd_status[NUM_CARDS] = | ||
103 | { | ||
104 | #if NUM_CARDS > 1 | ||
105 | {0, 10}, | ||
106 | #endif | ||
107 | {0, 10} | ||
108 | }; | ||
109 | #endif | ||
110 | #endif | ||
111 | |||
112 | /* Shoot for around 75% usage */ | ||
113 | static long sd_stack [(DEFAULT_STACK_SIZE*2 + 0x1c0)/sizeof(long)]; | ||
114 | static const char sd_thread_name[] = "sd"; | ||
115 | static struct mutex sd_mtx SHAREDBSS_ATTR; | ||
116 | static struct event_queue sd_queue; | ||
117 | static struct wakeup transfer_completion_signal; | ||
118 | static volatile unsigned int transfer_error[NUM_VOLUMES]; | ||
119 | /* align on cache line size */ | ||
120 | static unsigned char aligned_buffer[UNALIGNED_NUM_SECTORS * SD_BLOCK_SIZE] | ||
121 | __attribute__((aligned(32))); | ||
122 | static unsigned char * uncached_buffer; | ||
123 | |||
124 | |||
125 | /* TODO: should be in target include file */ | ||
126 | /***************************************************************************** | ||
127 | Definitions specific to Mini2440 | ||
128 | *****************************************************************************/ | ||
129 | #define FCLK 405000000 | ||
130 | #define HCLK (FCLK/4) /* = 101,250,000 */ | ||
131 | #define PCLK (HCLK/2) /* = 50,625,000 */ | ||
132 | |||
133 | #define SD_CD (1<<8) /* Port G */ | ||
134 | #define SD_WP (1<<8) /* Port H */ | ||
135 | |||
136 | /***************************************************************************** | ||
137 | Functions specific to S3C2440 SoC | ||
138 | *****************************************************************************/ | ||
139 | static inline void mci_delay(void) | ||
140 | { | ||
141 | /* Does this get optimised out ? */ | ||
142 | int i = 0xffff; | ||
143 | while(i--) ; | ||
144 | } | ||
145 | |||
146 | #ifdef SD_DEBUG | ||
147 | static unsigned reg_copy[16], reg_copy2[16]; | ||
148 | static void get_regs (unsigned *regs) | ||
149 | { | ||
150 | unsigned j; | ||
151 | volatile unsigned long *sdi_reg = &SDICON; | ||
152 | |||
153 | for (j=0; j < 16;j++) | ||
154 | { | ||
155 | *regs++ = *sdi_reg++; | ||
156 | } | ||
157 | } | ||
158 | |||
159 | static void dump_regs (unsigned *regs1, unsigned *regs2) | ||
160 | { | ||
161 | unsigned j; | ||
162 | volatile unsigned long*sdi_reg = &SDICON; | ||
163 | unsigned long diff; | ||
164 | |||
165 | for (j=0; j < 16;j++) | ||
166 | { | ||
167 | diff = *regs1 ^ *regs2; | ||
168 | if (diff) | ||
169 | uart_printf ("%8x %8x %8x %8x\n", sdi_reg, *regs1, *regs2, diff ); | ||
170 | regs1++; | ||
171 | regs2++; | ||
172 | sdi_reg++; | ||
173 | } | ||
174 | } | ||
175 | #endif | ||
176 | |||
177 | static void debug_r1(int cmd) | ||
178 | { | ||
179 | #if defined(SD_DEBUG) | ||
180 | uart_printf("CMD%2.2d:SDICSTA=%04x [%c%c%c%c%c-%c%c%c%c%c%c%c] SDIRSP0=%08x [%d %s] \n", | ||
181 | cmd, | ||
182 | SDICSTA, | ||
183 | (SDICSTA & S3C2410_SDICMDSTAT_CRCFAIL) ? 'C' : ' ', | ||
184 | (SDICSTA & S3C2410_SDICMDSTAT_CMDSENT) ? 'S' : ' ', | ||
185 | (SDICSTA & S3C2410_SDICMDSTAT_CMDTIMEOUT) ? 'T' : ' ', | ||
186 | (SDICSTA & S3C2410_SDICMDSTAT_RSPFIN) ? 'R' : ' ', | ||
187 | (SDICSTA & S3C2410_SDICMDSTAT_XFERING) ? 'X' : ' ', | ||
188 | |||
189 | (SDICSTA & 0x40) ? 'P' : ' ', | ||
190 | (SDICSTA & 0x20) ? 'A' : ' ', | ||
191 | (SDICSTA & 0x10) ? 'E' : ' ', | ||
192 | (SDICSTA & 0x08) ? 'C' : ' ', | ||
193 | (SDICSTA & 0x04) ? 'I' : ' ', | ||
194 | (SDICSTA & 0x02) ? 'R' : ' ', | ||
195 | (SDICSTA & 0x01) ? 'Z' : ' ', | ||
196 | |||
197 | SDIRSP0, | ||
198 | SD_R1_CURRENT_STATE(SDIRSP0), | ||
199 | (SDIRSP0 & SD_R1_READY_FOR_DATA) ? "RDY " : " " | ||
200 | ); | ||
201 | #else | ||
202 | (void)cmd; | ||
203 | #endif | ||
204 | } | ||
205 | |||
206 | void SDI (void) | ||
207 | { | ||
208 | int status = SDIDSTA; | ||
209 | |||
210 | transfer_error[curr_card] = status | ||
211 | #if 0 | ||
212 | & ( S3C2410_SDIDSTA_CRCFAIL | S3C2410_SDIDSTA_RXCRCFAIL | | ||
213 | S3C2410_SDIDSTA_DATATIMEOUT ) | ||
214 | #endif | ||
215 | ; | ||
216 | |||
217 | SDIDSTA |= S3C2410_SDIDSTA_CLEAR_BITS; /* needed to clear int */ | ||
218 | |||
219 | dbgprintf ("SDI %x\n", transfer_error[curr_card]); | ||
220 | |||
221 | wakeup_signal(&transfer_completion_signal); | ||
222 | |||
223 | /* Ack the interrupt */ | ||
224 | SRCPND = SDI_MASK; | ||
225 | INTPND = SDI_MASK; | ||
226 | } | ||
227 | |||
228 | #if 0 | ||
229 | void dma_callback (void) | ||
230 | { | ||
231 | const int status = SDIDSTA; | ||
232 | |||
233 | transfer_error[0] = status & (S3C2410_SDIDSTA_CRCFAIL | | ||
234 | S3C2410_SDIDSTA_RXCRCFAIL | | ||
235 | S3C2410_SDIDSTA_DATATIMEOUT ); | ||
236 | |||
237 | SDIDSTA |= S3C2410_SDIDSTA_CLEAR_BITS; /* needed to clear int */ | ||
238 | |||
239 | dbgprintf ("dma_cb\n"); | ||
240 | wakeup_signal(&transfer_completion_signal); | ||
241 | } | ||
242 | #endif | ||
243 | |||
244 | static void init_sdi_controller(const int card_no) | ||
245 | { | ||
246 | (void)card_no; | ||
247 | |||
248 | /*****************************************************************************/ | ||
249 | #ifdef MINI2440 | ||
250 | /* Specific to Mini2440 */ | ||
251 | |||
252 | /* Enable pullups on SDCMD and SDDAT pins */ | ||
253 | S3C2440_GPIO_PULLUP (GPEUP, 6, GPIO_PULLUP_ENABLE); | ||
254 | S3C2440_GPIO_PULLUP (GPEUP, 7, GPIO_PULLUP_ENABLE); | ||
255 | S3C2440_GPIO_PULLUP (GPEUP, 8, GPIO_PULLUP_ENABLE); | ||
256 | S3C2440_GPIO_PULLUP (GPEUP, 9, GPIO_PULLUP_ENABLE); | ||
257 | S3C2440_GPIO_PULLUP (GPEUP, 10, GPIO_PULLUP_ENABLE); | ||
258 | |||
259 | /* Enable special function for SDCMD, SDCLK and SDDAT pins */ | ||
260 | S3C2440_GPIO_CONFIG (GPECON, 5, GPIO_FUNCTION); | ||
261 | S3C2440_GPIO_CONFIG (GPECON, 6, GPIO_FUNCTION); | ||
262 | S3C2440_GPIO_CONFIG (GPECON, 7, GPIO_FUNCTION); | ||
263 | S3C2440_GPIO_CONFIG (GPECON, 8, GPIO_FUNCTION); | ||
264 | S3C2440_GPIO_CONFIG (GPECON, 9, GPIO_FUNCTION); | ||
265 | S3C2440_GPIO_CONFIG (GPECON, 10, GPIO_FUNCTION); | ||
266 | |||
267 | /* Card Detect input */ | ||
268 | S3C2440_GPIO_CONFIG (GPGCON, 8, GPIO_INPUT); | ||
269 | |||
270 | /* Write Protect input */ | ||
271 | S3C2440_GPIO_CONFIG (GPHCON, 8, GPIO_INPUT); | ||
272 | /*****************************************************************************/ | ||
273 | #else | ||
274 | #error Unsupported target | ||
275 | #endif | ||
276 | /*****************************************************************************/ | ||
277 | |||
278 | /* About 400KHz for initial comms with card */ | ||
279 | SDIPRE = PCLK / INITIAL_CLK - 1; | ||
280 | /* Byte order=Type A (Little Endian), clock enable */ | ||
281 | SDICON = S3C2410_SDICON_CLOCKTYPE; | ||
282 | SDIFSTA |= S3C2440_SDIFSTA_FIFORESET; | ||
283 | SDIBSIZE = SD_BLOCK_SIZE; | ||
284 | SDIDTIMER= 0x7fffff; /* Set timeout count - max value */ | ||
285 | |||
286 | /* Enable interupt on Data Finish or data transfer error */ | ||
287 | /* Clear pending source */ | ||
288 | SRCPND = SDI_MASK; | ||
289 | INTPND = SDI_MASK; | ||
290 | |||
291 | #if 1 | ||
292 | /* Enable interrupt in controller */ | ||
293 | s3c_regclr32(&INTMOD, SDI_MASK); | ||
294 | s3c_regclr32(&INTMSK, SDI_MASK); | ||
295 | |||
296 | SDIIMSK |= S3C2410_SDIIMSK_DATAFINISH | ||
297 | | S3C2410_SDIIMSK_DATATIMEOUT | ||
298 | | S3C2410_SDIIMSK_DATACRC | ||
299 | | S3C2410_SDIIMSK_CRCSTATUS | ||
300 | | S3C2410_SDIIMSK_FIFOFAIL | ||
301 | ; | ||
302 | #endif | ||
303 | } | ||
304 | |||
305 | static bool send_cmd(const int card_no, const int cmd, const int arg, | ||
306 | const int flags, long *response) | ||
307 | { | ||
308 | bool ret; | ||
309 | unsigned val, status; | ||
310 | (void)card_no; | ||
311 | |||
312 | #ifdef SD_DEBUG | ||
313 | get_regs (reg_copy); | ||
314 | #endif | ||
315 | /* A major bodge. For some reason a delay is required here */ | ||
316 | mci_delay(); | ||
317 | dbgprintf ("send_cmd: c=%3.3d a=%08x f=%02x \n", cmd, arg, flags); | ||
318 | |||
319 | #ifdef SD_DEBUG | ||
320 | get_regs (reg_copy2); | ||
321 | dump_regs (reg_copy, reg_copy2); | ||
322 | #endif | ||
323 | |||
324 | #if 0 | ||
325 | while (SDICSTA & S3C2410_SDICMDSTAT_XFERING) | ||
326 | ; /* wait ?? */ | ||
327 | #endif | ||
328 | /* set up new command */ | ||
329 | |||
330 | if (flags & MCI_ARG) | ||
331 | SDICARG = arg; | ||
332 | else | ||
333 | SDICARG = 0; | ||
334 | |||
335 | val = cmd | S3C2410_SDICMDCON_CMDSTART | S3C2410_SDICMDCON_SENDERHOST; | ||
336 | if(flags & MCI_RESP) | ||
337 | { | ||
338 | val |= S3C2410_SDICMDCON_WAITRSP; | ||
339 | if(flags & MCI_LONG_RESP) | ||
340 | val |= S3C2410_SDICMDCON_LONGRSP; | ||
341 | } | ||
342 | |||
343 | /* Clear command/data status flags */ | ||
344 | SDICSTA |= 0x0f << 9; | ||
345 | SDIDSTA |= S3C2410_SDIDSTA_CLEAR_BITS; | ||
346 | |||
347 | /* Initiate the command */ | ||
348 | SDICCON = val; | ||
349 | |||
350 | if (flags & MCI_RESP) | ||
351 | { | ||
352 | /* wait for response or timeout */ | ||
353 | do | ||
354 | { | ||
355 | status = SDICSTA; | ||
356 | } while ( (status & (S3C2410_SDICMDSTAT_RSPFIN | | ||
357 | S3C2410_SDICMDSTAT_CMDTIMEOUT) ) == 0); | ||
358 | debug_r1(cmd); | ||
359 | if (status & S3C2410_SDICMDSTAT_CMDTIMEOUT) | ||
360 | ret = false; | ||
361 | else if (status & (S3C2410_SDICMDSTAT_RSPFIN)) | ||
362 | { | ||
363 | /* resp received */ | ||
364 | if(flags & MCI_LONG_RESP) | ||
365 | { | ||
366 | /* store the response in reverse word order */ | ||
367 | response[0] = SDIRSP3; | ||
368 | response[1] = SDIRSP2; | ||
369 | response[2] = SDIRSP1; | ||
370 | response[3] = SDIRSP0; | ||
371 | } | ||
372 | else | ||
373 | response[0] = SDIRSP0; | ||
374 | ret = true; | ||
375 | } | ||
376 | else | ||
377 | ret = true; | ||
378 | } | ||
379 | else | ||
380 | { | ||
381 | /* wait for command completion or timeout */ | ||
382 | do | ||
383 | { | ||
384 | status = SDICSTA; | ||
385 | } while ( (status & (S3C2410_SDICMDSTAT_CMDSENT | | ||
386 | S3C2410_SDICMDSTAT_CMDTIMEOUT)) == 0); | ||
387 | debug_r1(cmd); | ||
388 | if (status & S3C2410_SDICMDSTAT_CMDTIMEOUT) | ||
389 | ret = false; | ||
390 | else | ||
391 | ret = true; | ||
392 | } | ||
393 | |||
394 | /* Clear Command status flags */ | ||
395 | SDICSTA |= 0x0f << 9; | ||
396 | |||
397 | mci_delay(); | ||
398 | |||
399 | return ret; | ||
400 | } | ||
401 | |||
402 | static int sd_init_card(const int card_no) | ||
403 | { | ||
404 | unsigned long temp_reg[4]; | ||
405 | unsigned long response; | ||
406 | long init_timeout; | ||
407 | bool sdhc; | ||
408 | int i; | ||
409 | |||
410 | if(!send_cmd(card_no, SD_GO_IDLE_STATE, 0, MCI_NO_FLAGS, NULL)) | ||
411 | return -1; | ||
412 | |||
413 | mci_delay(); | ||
414 | |||
415 | sdhc = false; | ||
416 | if(send_cmd(card_no, SD_SEND_IF_COND, 0x1AA, MCI_RESP|MCI_ARG, &response)) | ||
417 | if((response & 0xFFF) == 0x1AA) | ||
418 | sdhc = true; | ||
419 | |||
420 | /* timeout for initialization is 1sec, from SD Specification 2.00 */ | ||
421 | init_timeout = current_tick + HZ; | ||
422 | |||
423 | do { | ||
424 | /* timeout */ | ||
425 | if(current_tick > init_timeout) | ||
426 | return -2; | ||
427 | |||
428 | /* app_cmd */ | ||
429 | if( !send_cmd(card_no, SD_APP_CMD, 0, MCI_RESP|MCI_ARG, &response) || | ||
430 | !(response & (1<<5)) ) | ||
431 | { | ||
432 | return -3; | ||
433 | } | ||
434 | |||
435 | /* acmd41 */ | ||
436 | if(!send_cmd(card_no, SD_APP_OP_COND, (sdhc ? 0x40FF8000 : (1<<23)), | ||
437 | MCI_RESP|MCI_ARG, &card_info[card_no].ocr)) | ||
438 | { | ||
439 | return -4; | ||
440 | } | ||
441 | |||
442 | } while(!(card_info[card_no].ocr & (1<<31))); | ||
443 | |||
444 | /* send CID */ | ||
445 | if(!send_cmd(card_no, SD_ALL_SEND_CID, 0, MCI_RESP|MCI_LONG_RESP|MCI_ARG, | ||
446 | temp_reg)) | ||
447 | return -5; | ||
448 | |||
449 | for(i=0; i<4; i++) | ||
450 | card_info[card_no].cid[3-i] = temp_reg[i]; | ||
451 | |||
452 | /* send RCA */ | ||
453 | if(!send_cmd(card_no, SD_SEND_RELATIVE_ADDR, 0, MCI_RESP|MCI_ARG, | ||
454 | &card_info[card_no].rca)) | ||
455 | return -6; | ||
456 | |||
457 | /* send CSD */ | ||
458 | if(!send_cmd(card_no, SD_SEND_CSD, card_info[card_no].rca, | ||
459 | MCI_RESP|MCI_LONG_RESP|MCI_ARG, temp_reg)) | ||
460 | return -7; | ||
461 | |||
462 | for(i=0; i<4; i++) | ||
463 | card_info[card_no].csd[3-i] = temp_reg[i]; | ||
464 | |||
465 | sd_parse_csd(&card_info[card_no]); | ||
466 | |||
467 | if(!send_cmd(card_no, SD_SELECT_CARD, card_info[card_no].rca, MCI_ARG, NULL)) | ||
468 | return -9; | ||
469 | |||
470 | if(!send_cmd(card_no, SD_APP_CMD, card_info[card_no].rca, MCI_ARG, NULL)) | ||
471 | return -10; | ||
472 | |||
473 | if(!send_cmd(card_no, SD_SET_BUS_WIDTH, card_info[card_no].rca | 2, MCI_ARG, NULL)) | ||
474 | return -11; | ||
475 | |||
476 | if(!send_cmd(card_no, SD_SET_BLOCKLEN, card_info[card_no].blocksize, MCI_ARG, | ||
477 | NULL)) | ||
478 | return -12; | ||
479 | |||
480 | card_info[card_no].initialized = 1; | ||
481 | |||
482 | /* full speed for controller clock */ | ||
483 | SDIPRE = PCLK / SD_CLK - 1; | ||
484 | mci_delay(); | ||
485 | |||
486 | return EC_OK; | ||
487 | } | ||
488 | |||
489 | /***************************************************************************** | ||
490 | Generic functions | ||
491 | *****************************************************************************/ | ||
492 | |||
493 | /*****************************************************************************/ | ||
494 | #ifdef HAVE_HOTSWAP | ||
495 | |||
496 | bool card_detect_target(void) | ||
497 | { | ||
498 | /* TODO - use interrupt on change? */ | ||
499 | #ifdef MINI2440 | ||
500 | return (GPGDAT & SD_CD) == 0; | ||
501 | #else | ||
502 | #error Unsupported target | ||
503 | #endif | ||
504 | } | ||
505 | |||
506 | void card_enable_monitoring_target(bool on) | ||
507 | { | ||
508 | (void)on; | ||
509 | /* TODO */ | ||
510 | } | ||
511 | |||
512 | #if 0 | ||
513 | void EXT0(void) | ||
514 | { | ||
515 | static struct timeout sd1_oneshot; | ||
516 | |||
517 | /* TODO */ | ||
518 | } | ||
519 | #endif | ||
520 | |||
521 | bool sd_removable(IF_MD_NONVOID(int card_no)) | ||
522 | { | ||
523 | #ifndef HAVE_MULTIDRIVE | ||
524 | const int card_no = 0; | ||
525 | #endif | ||
526 | dbgprintf ("sd_remov (hs) [%d] %d\n", card_no, card_no == CARD_NUM_SLOT ); | ||
527 | return (card_no == CARD_NUM_SLOT); | ||
528 | } | ||
529 | |||
530 | bool sd_present(IF_MD_NONVOID(int card_no)) | ||
531 | { | ||
532 | #ifdef HAVE_MULTIDRIVE | ||
533 | (void)card_no; | ||
534 | #endif | ||
535 | dbgprintf ("sd_pres (hs) [%d] %d\n", card_no, card_detect_target()); | ||
536 | return card_detect_target(); | ||
537 | } | ||
538 | |||
539 | /*****************************************************************************/ | ||
540 | #else | ||
541 | |||
542 | bool card_detect_target(void) | ||
543 | { | ||
544 | /* not applicable */ | ||
545 | return false; | ||
546 | } | ||
547 | |||
548 | bool sd_removable(IF_MD_NONVOID(int card_no)) | ||
549 | { | ||
550 | #ifndef HAVE_MULTIDRIVE | ||
551 | const int card_no = 0; | ||
552 | #endif | ||
553 | (void)card_no; | ||
554 | |||
555 | /* not applicable */ | ||
556 | dbgprintf ("sd_remov"); | ||
557 | return false; | ||
558 | } | ||
559 | |||
560 | #endif /* HAVE_HOTSWAP */ | ||
561 | /*****************************************************************************/ | ||
562 | |||
563 | static void sd_thread(void) __attribute__((noreturn)); | ||
564 | static void sd_thread(void) | ||
565 | { | ||
566 | struct queue_event ev; | ||
567 | |||
568 | /* TODO */ | ||
569 | while (1) | ||
570 | { | ||
571 | queue_wait_w_tmo(&sd_queue, &ev, HZ); | ||
572 | |||
573 | switch ( ev.id ) | ||
574 | { | ||
575 | } | ||
576 | } | ||
577 | } | ||
578 | |||
579 | static int sd_wait_for_state(const int card_no, unsigned int state) | ||
580 | { | ||
581 | unsigned long response = 0; | ||
582 | unsigned int timeout = HZ; /* ticks */ | ||
583 | long t = current_tick; | ||
584 | |||
585 | while (1) | ||
586 | { | ||
587 | long tick; | ||
588 | |||
589 | if(!send_cmd(card_no, SD_SEND_STATUS, card_info[card_no].rca, | ||
590 | MCI_RESP|MCI_ARG, &response)) | ||
591 | return -1; | ||
592 | |||
593 | if( (SD_R1_CURRENT_STATE(response) == state) ) | ||
594 | return 0; | ||
595 | |||
596 | if(TIME_AFTER(current_tick, t + timeout)) | ||
597 | return -2; | ||
598 | |||
599 | if (TIME_AFTER((tick = current_tick), next_yield)) | ||
600 | { | ||
601 | yield(); | ||
602 | timeout += current_tick - tick; | ||
603 | next_yield = tick + MIN_YIELD_PERIOD; | ||
604 | } | ||
605 | } | ||
606 | } | ||
607 | |||
608 | static int sd_transfer_sectors(IF_MD2(int card_no,) unsigned long start, | ||
609 | int count, void* buf, const bool write) | ||
610 | { | ||
611 | #ifndef HAVE_MULTIDRIVE | ||
612 | const int card_no = 0; | ||
613 | #endif | ||
614 | int ret = EC_OK; | ||
615 | unsigned loops = 0; | ||
616 | struct dma_request request; | ||
617 | |||
618 | mutex_lock(&sd_mtx); | ||
619 | sd_enable(true); | ||
620 | set_leds(SD_ACTIVE_LED); | ||
621 | |||
622 | curr_card = card_no; | ||
623 | if (card_info[card_no].initialized <= 0) | ||
624 | { | ||
625 | ret = sd_init_card(card_no); | ||
626 | if (!(card_info[card_no].initialized)) | ||
627 | goto sd_transfer_error; | ||
628 | } | ||
629 | |||
630 | last_disk_activity = current_tick; | ||
631 | |||
632 | ret = sd_wait_for_state(card_no, SD_TRAN); | ||
633 | if (ret < 0) | ||
634 | { | ||
635 | ret -= 20; | ||
636 | goto sd_transfer_error; | ||
637 | } | ||
638 | |||
639 | dma_retain(); | ||
640 | |||
641 | while(count) | ||
642 | { | ||
643 | /* 128 * 512 = 2^16, and doesn't fit in the 16 bits of DATA_LENGTH | ||
644 | * register, so we have to transfer maximum 127 sectors at a time. */ | ||
645 | unsigned int transfer = (count >= 128) ? 127 : count; /* sectors */ | ||
646 | void *dma_buf; | ||
647 | const int cmd = | ||
648 | write ? SD_WRITE_MULTIPLE_BLOCK : SD_READ_MULTIPLE_BLOCK; | ||
649 | unsigned long start_addr = start; | ||
650 | |||
651 | dma_buf = aligned_buffer; | ||
652 | if(transfer > UNALIGNED_NUM_SECTORS) | ||
653 | transfer = UNALIGNED_NUM_SECTORS; | ||
654 | if(write) | ||
655 | memcpy(uncached_buffer, buf, transfer * SD_BLOCK_SIZE); | ||
656 | |||
657 | /* Set start_addr to the correct unit (blocks or bytes) */ | ||
658 | if(!(card_info[card_no].ocr & SD_OCR_CARD_CAPACITY_STATUS))/* not SDHC */ | ||
659 | start_addr *= SD_BLOCK_SIZE; | ||
660 | |||
661 | /* TODO? */ | ||
662 | SDIFSTA = SDIFSTA | S3C2440_SDIFSTA_FIFORESET; | ||
663 | SDIDCON = S3C2440_SDIDCON_DS_WORD | | ||
664 | S3C2410_SDIDCON_BLOCKMODE | S3C2410_SDIDCON_WIDEBUS | | ||
665 | S3C2410_SDIDCON_DMAEN | | ||
666 | S3C2440_SDIDCON_DATSTART | | ||
667 | ( transfer << 0); | ||
668 | if (write) | ||
669 | SDIDCON |= S3C2410_SDIDCON_TXAFTERRESP | S3C2410_SDIDCON_XFER_TXSTART; | ||
670 | else | ||
671 | SDIDCON |= S3C2410_SDIDCON_RXAFTERCMD | S3C2410_SDIDCON_XFER_RXSTART; | ||
672 | |||
673 | SDIDSTA |= S3C2410_SDIDSTA_CLEAR_BITS; /* needed to clear int */ | ||
674 | SRCPND = SDI_MASK; | ||
675 | INTPND = SDI_MASK; | ||
676 | |||
677 | /* Initiate read/write command */ | ||
678 | if(!send_cmd(card_no, cmd, start_addr, MCI_ARG | MCI_RESP, NULL)) | ||
679 | { | ||
680 | ret -= 3*20; | ||
681 | goto sd_transfer_error; | ||
682 | } | ||
683 | |||
684 | if(write) | ||
685 | { | ||
686 | request.source_addr = dma_buf; | ||
687 | request.source_control = DISRCC_LOC_AHB | DISRCC_INC_AUTO; | ||
688 | request.dest_addr = &SDIDAT_LLE; | ||
689 | request.dest_control = DISRCC_LOC_APB | DISRCC_INC_FIXED; | ||
690 | request.count = transfer * SD_BLOCK_SIZE / sizeof(long); | ||
691 | request.source_map = DMA_SRC_MAP_SDI; | ||
692 | request.control = DCON_DMD_HS | DCON_SYNC_APB | | ||
693 | DCON_HW_SEL | | ||
694 | DCON_NO_RELOAD | DCON_DSZ_WORD; | ||
695 | request.callback = NULL; | ||
696 | |||
697 | dma_enable_channel(0, &request); | ||
698 | } | ||
699 | else | ||
700 | { | ||
701 | request.source_addr = &SDIDAT_LLE; | ||
702 | request.source_control = DISRCC_LOC_APB | DISRCC_INC_FIXED; | ||
703 | request.dest_addr = dma_buf; | ||
704 | request.dest_control = DISRCC_LOC_AHB | DISRCC_INC_AUTO; | ||
705 | request.count = transfer * SD_BLOCK_SIZE / sizeof(long); | ||
706 | request.source_map = DMA_SRC_MAP_SDI; | ||
707 | request.control = DCON_DMD_HS | DCON_SYNC_APB | | ||
708 | DCON_HW_SEL | | ||
709 | DCON_NO_RELOAD | DCON_DSZ_WORD; | ||
710 | request.callback = NULL; | ||
711 | |||
712 | dma_enable_channel(0, &request); | ||
713 | } | ||
714 | |||
715 | #if 0 | ||
716 | /* FIXME : we should check if the timeouts calculated from the card's | ||
717 | * CSD are lower, and use them if it is the case | ||
718 | * Note : the OF doesn't seem to use them anyway */ | ||
719 | MCI_DATA_TIMER(drive) = write ? | ||
720 | SD_MAX_WRITE_TIMEOUT : SD_MAX_READ_TIMEOUT; | ||
721 | MCI_DATA_LENGTH(drive) = transfer * card_info[drive].blocksize; | ||
722 | MCI_DATA_CTRL(drive) = (1<<0) /* enable */ | | ||
723 | (!write<<1) /* transfer direction */ | | ||
724 | (1<<3) /* DMA */ | | ||
725 | (9<<4) /* 2^9 = 512 */ ; | ||
726 | #endif | ||
727 | |||
728 | wakeup_wait(&transfer_completion_signal, 100 /*TIMEOUT_BLOCK*/); | ||
729 | |||
730 | /* wait for DMA to finish */ | ||
731 | while (DSTAT0 & DSTAT_STAT_BUSY) | ||
732 | ; | ||
733 | |||
734 | #if 0 | ||
735 | status = SDIDSTA; | ||
736 | while ((status & (S3C2410_SDIDSTA_DATATIMEOUT|S3C2410_SDIDSTA_XFERFINISH)) == 0) | ||
737 | { | ||
738 | status = SDIDSTA; | ||
739 | } | ||
740 | uart_printf("%x \n", status); | ||
741 | #endif | ||
742 | if( transfer_error[card_no] & S3C2410_SDIDSTA_XFERFINISH ) | ||
743 | { | ||
744 | if(!write) | ||
745 | memcpy(buf, uncached_buffer, transfer * SD_BLOCK_SIZE); | ||
746 | buf += transfer * SD_BLOCK_SIZE; | ||
747 | start += transfer; | ||
748 | count -= transfer; | ||
749 | loops = 0; /* reset errors counter */ | ||
750 | } | ||
751 | else | ||
752 | { | ||
753 | dbgprintf ("SD transfer error : 0x%x\n", transfer_error[card_no]); | ||
754 | |||
755 | if(loops++ > MAX_TRANSFER_ERRORS) | ||
756 | { | ||
757 | led_flash(LED1|LED2, LED3|LED4); | ||
758 | /* panicf("SD transfer error : 0x%x", transfer_error[card_no]); */ | ||
759 | } | ||
760 | } | ||
761 | |||
762 | last_disk_activity = current_tick; | ||
763 | |||
764 | if(!send_cmd(card_no, SD_STOP_TRANSMISSION, 0, MCI_RESP, NULL)) | ||
765 | { | ||
766 | ret = -4*20; | ||
767 | goto sd_transfer_error; | ||
768 | } | ||
769 | |||
770 | #if 0 | ||
771 | ret = sd_wait_for_state(card_no, SD_TRAN); | ||
772 | if (ret < 0) | ||
773 | { | ||
774 | ret -= 5*20; | ||
775 | goto sd_transfer_error; | ||
776 | } | ||
777 | #endif | ||
778 | } | ||
779 | |||
780 | ret = EC_OK; | ||
781 | |||
782 | sd_transfer_error: | ||
783 | |||
784 | dma_release(); | ||
785 | |||
786 | clear_leds(SD_ACTIVE_LED); | ||
787 | sd_enable(false); | ||
788 | |||
789 | if (ret) /* error */ | ||
790 | card_info[card_no].initialized = 0; | ||
791 | |||
792 | mutex_unlock(&sd_mtx); | ||
793 | return ret; | ||
794 | } | ||
795 | |||
796 | int sd_read_sectors(IF_MD2(int card_no,) unsigned long start, int incount, | ||
797 | void* inbuf) | ||
798 | { | ||
799 | int ret; | ||
800 | |||
801 | #ifdef HAVE_MULTIDRIVE | ||
802 | dbgprintf ("sd_read %d %x %d\n", card_no, start, incount); | ||
803 | #else | ||
804 | dbgprintf ("sd_read %x %d\n", start, incount); | ||
805 | #endif | ||
806 | ret = sd_transfer_sectors(IF_MD2(card_no,) start, incount, inbuf, false); | ||
807 | dbgprintf ("sd_read, ret=%d\n", ret); | ||
808 | return ret; | ||
809 | } | ||
810 | |||
811 | /*****************************************************************************/ | ||
812 | #ifndef X_BOOTLOADER | ||
813 | /* writing not required for Bootloader - or is it? */ | ||
814 | int sd_write_sectors(IF_MD2(int card_no,) unsigned long start, int count, | ||
815 | const void* outbuf) | ||
816 | { | ||
817 | dbgprintf ("sd_write %d %x %d\n", card_no, start, count); | ||
818 | |||
819 | return sd_transfer_sectors(IF_MD2(card_no,) start, count, outbuf, true); | ||
820 | } | ||
821 | #endif /* BOOTLOADER */ | ||
822 | /*****************************************************************************/ | ||
823 | |||
824 | void sd_enable(bool on) | ||
825 | { | ||
826 | dbgprintf ("sd_enable %d\n", on); | ||
827 | /* TODO: enable/disable SDI clock */ | ||
828 | |||
829 | if (sd_enabled == on) | ||
830 | return; /* nothing to do */ | ||
831 | if (on) | ||
832 | { | ||
833 | sd_enabled = true; | ||
834 | } | ||
835 | else | ||
836 | { | ||
837 | sd_enabled = false; | ||
838 | } | ||
839 | } | ||
840 | |||
841 | int sd_init(void) | ||
842 | { | ||
843 | int ret = EC_OK; | ||
844 | dbgprintf ("\n==============================\n"); | ||
845 | dbgprintf (" sd_init\n"); | ||
846 | dbgprintf ("==============================\n"); | ||
847 | |||
848 | init_sdi_controller (0); | ||
849 | #ifndef BOOTLOADER | ||
850 | sd_enabled = true; | ||
851 | sd_enable(false); | ||
852 | #endif | ||
853 | wakeup_init(&transfer_completion_signal); | ||
854 | /* init mutex */ | ||
855 | mutex_init(&sd_mtx); | ||
856 | queue_init(&sd_queue, true); | ||
857 | create_thread(sd_thread, sd_stack, sizeof(sd_stack), 0, | ||
858 | sd_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE) IF_COP(, CPU)); | ||
859 | |||
860 | uncached_buffer = UNCACHED_ADDR(&aligned_buffer[0]); | ||
861 | |||
862 | initialized = true; | ||
863 | return ret; | ||
864 | } | ||
865 | |||
866 | long sd_last_disk_activity(void) | ||
867 | { | ||
868 | return last_disk_activity; | ||
869 | } | ||
870 | |||
871 | tCardInfo *card_get_info_target(int card_no) | ||
872 | { | ||
873 | return &card_info[card_no]; | ||
874 | } | ||
875 | |||
876 | /*****************************************************************************/ | ||
877 | #ifdef CONFIG_STORAGE_MULTI | ||
878 | |||
879 | int sd_num_drives(int first_drive) | ||
880 | { | ||
881 | dbgprintf ("sd_num_drv"); | ||
882 | #if 0 | ||
883 | /* Store which logical drive number(s) we have been assigned */ | ||
884 | sd_first_drive = first_drive; | ||
885 | #endif | ||
886 | |||
887 | return NUM_CARDS; | ||
888 | } | ||
889 | |||
890 | void sd_sleepnow(void) | ||
891 | { | ||
892 | } | ||
893 | |||
894 | bool sd_disk_is_active(void) | ||
895 | { | ||
896 | return false; | ||
897 | } | ||
898 | |||
899 | int sd_soft_reset(void) | ||
900 | { | ||
901 | return 0; | ||
902 | } | ||
903 | |||
904 | int sd_spinup_time(void) | ||
905 | { | ||
906 | return 0; | ||
907 | } | ||
908 | |||
909 | #endif /* CONFIG_STORAGE_MULTI */ | ||
910 | /*****************************************************************************/ | ||
911 | |||
diff --git a/firmware/target/arm/s3c2440/uart-s3c2440.c b/firmware/target/arm/s3c2440/uart-s3c2440.c new file mode 100644 index 0000000000..2a61b61a39 --- /dev/null +++ b/firmware/target/arm/s3c2440/uart-s3c2440.c | |||
@@ -0,0 +1,248 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2009 by Bob Cousins | ||
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 Standard files */ | ||
23 | #include <stdlib.h> | ||
24 | #include <stdio.h> | ||
25 | #include <stdarg.h> | ||
26 | #include "inttypes.h" | ||
27 | #include "string.h" | ||
28 | #include "cpu.h" | ||
29 | #include "system.h" | ||
30 | #include "kernel.h" | ||
31 | #include "thread.h" | ||
32 | |||
33 | #include "uart-s3c2440.h" | ||
34 | |||
35 | #define FCLK 405000000 | ||
36 | #define HCLK (FCLK/4) /* = 101,250,000 */ | ||
37 | #define PCLK (HCLK/2) /* = 50,625,000 */ | ||
38 | |||
39 | #define MAX_TX_BUF 1024 | ||
40 | |||
41 | |||
42 | /**************************************************************************** | ||
43 | * General purpose debug function | ||
44 | ****************************************************************************/ | ||
45 | |||
46 | void uart_printf (const char *format, ...) | ||
47 | { | ||
48 | static bool debug_uart_init = false; | ||
49 | static char tx_buf [MAX_TX_BUF]; | ||
50 | |||
51 | int len; | ||
52 | unsigned char *ptr; | ||
53 | va_list ap; | ||
54 | va_start(ap, format); | ||
55 | |||
56 | ptr = tx_buf; | ||
57 | len = vsnprintf(ptr, sizeof(tx_buf), format, ap); | ||
58 | va_end(ap); | ||
59 | |||
60 | if (!debug_uart_init) | ||
61 | { | ||
62 | uart_init_device(UART_DEBUG); | ||
63 | debug_uart_init = true; | ||
64 | } | ||
65 | |||
66 | uart_send (UART_DEBUG, tx_buf, len); | ||
67 | } | ||
68 | |||
69 | /**************************************************************************** | ||
70 | * Device level functions specific to S3C2440 | ||
71 | *****************************************************************************/ | ||
72 | |||
73 | bool uart_init (void) | ||
74 | { | ||
75 | /* anything ? */ | ||
76 | return true; | ||
77 | } | ||
78 | |||
79 | bool uart_init_device (unsigned dev) | ||
80 | { | ||
81 | /* set GPIOs, clock enable? etc */ | ||
82 | |||
83 | switch (dev) | ||
84 | { | ||
85 | case 0: | ||
86 | { | ||
87 | S3C2440_GPIO_CONFIG (GPHCON, 2, GPIO_FUNCTION); | ||
88 | S3C2440_GPIO_CONFIG (GPHCON, 3, GPIO_FUNCTION); | ||
89 | S3C2440_GPIO_PULLUP (GPHUP, 2, GPIO_PULLUP_DISABLE); | ||
90 | S3C2440_GPIO_PULLUP (GPHUP, 3, GPIO_PULLUP_DISABLE); | ||
91 | break; | ||
92 | } | ||
93 | case 1: | ||
94 | { | ||
95 | S3C2440_GPIO_CONFIG (GPHCON, 4, GPIO_FUNCTION); | ||
96 | S3C2440_GPIO_CONFIG (GPHCON, 5, GPIO_FUNCTION); | ||
97 | S3C2440_GPIO_PULLUP (GPHUP, 4, GPIO_PULLUP_DISABLE); | ||
98 | S3C2440_GPIO_PULLUP (GPHUP, 5, GPIO_PULLUP_DISABLE); | ||
99 | break; | ||
100 | } | ||
101 | case 2: | ||
102 | { | ||
103 | S3C2440_GPIO_CONFIG (GPHCON, 6, GPIO_FUNCTION); | ||
104 | S3C2440_GPIO_CONFIG (GPHCON, 7, GPIO_FUNCTION); | ||
105 | S3C2440_GPIO_PULLUP (GPHUP, 6, GPIO_PULLUP_DISABLE); | ||
106 | S3C2440_GPIO_PULLUP (GPHUP, 7, GPIO_PULLUP_DISABLE); | ||
107 | break; | ||
108 | } | ||
109 | default: | ||
110 | return false; | ||
111 | } | ||
112 | |||
113 | /* set a default configuration */ | ||
114 | uart_config (dev, 115200, 8, UART_NO_PARITY, UART_1_STOP_BIT); | ||
115 | return true; | ||
116 | } | ||
117 | |||
118 | bool uart_config (unsigned dev, unsigned speed, unsigned num_bits, | ||
119 | unsigned parity, unsigned stop_bits) | ||
120 | { | ||
121 | switch (dev) | ||
122 | { | ||
123 | case 0: | ||
124 | ULCON0 = (parity << 3) + (stop_bits << 2) + (num_bits-5); | ||
125 | UCON0 = (1 << 2) + (1 << 0); /* enable TX, RX, use PCLK */ | ||
126 | UBRDIV0 = PCLK / (speed*16); | ||
127 | break; | ||
128 | |||
129 | case 1: | ||
130 | ULCON1 = (parity << 3) + (stop_bits << 2) + (num_bits-5); | ||
131 | UCON1 = (1 << 2) + (1 << 0); /* enable TX, RX, use PCLK */ | ||
132 | UBRDIV1 = PCLK / (speed*16); | ||
133 | break; | ||
134 | |||
135 | case 2: | ||
136 | ULCON2 = (parity << 3) + (stop_bits << 2) + (num_bits-5); | ||
137 | UCON2 = (1 << 2) + (1 << 0); /* enable TX, RX, use PCLK */ | ||
138 | UBRDIV2 = PCLK / (speed*16); | ||
139 | break; | ||
140 | } | ||
141 | |||
142 | return true; | ||
143 | } | ||
144 | |||
145 | bool uart_send_byte (unsigned dev, char ch) | ||
146 | { | ||
147 | switch (dev) | ||
148 | { | ||
149 | case 0: | ||
150 | /* wait for transmit buffer empty */ | ||
151 | while ((UTRSTAT0 & 0x02) == 0) | ||
152 | ; | ||
153 | UTXH0 = ch; | ||
154 | break; | ||
155 | |||
156 | case 1: | ||
157 | /* wait for transmit buffer empty */ | ||
158 | while ((UTRSTAT1 & 0x02) == 0) | ||
159 | ; | ||
160 | UTXH1 = ch; | ||
161 | break; | ||
162 | |||
163 | case 2: | ||
164 | /* wait for transmit buffer empty */ | ||
165 | while ((UTRSTAT2 & 0x02) == 0) | ||
166 | ; | ||
167 | UTXH2 = ch; | ||
168 | break; | ||
169 | } | ||
170 | |||
171 | return true; | ||
172 | } | ||
173 | |||
174 | char uart_rx_ready (unsigned dev) | ||
175 | { | ||
176 | switch (dev) | ||
177 | { | ||
178 | case 0: | ||
179 | /* wait for receive buffer data ready */ | ||
180 | if (UTRSTAT0 & 0x01) | ||
181 | return true; | ||
182 | else | ||
183 | return false; | ||
184 | break; | ||
185 | case 1: | ||
186 | /* wait for receive buffer data ready */ | ||
187 | if (UTRSTAT1 & 0x01) | ||
188 | return true; | ||
189 | else | ||
190 | return false; | ||
191 | break; | ||
192 | case 2: | ||
193 | /* wait for receive buffer data ready */ | ||
194 | if (UTRSTAT2 & 0x01) | ||
195 | return true; | ||
196 | else | ||
197 | return false; | ||
198 | break; | ||
199 | } | ||
200 | return false; | ||
201 | } | ||
202 | |||
203 | char uart_read_byte (unsigned dev) | ||
204 | { | ||
205 | switch (dev) | ||
206 | { | ||
207 | case 0: | ||
208 | while (!uart_rx_ready(dev)) | ||
209 | ; | ||
210 | return URXH0; | ||
211 | break; | ||
212 | case 1: | ||
213 | while (!uart_rx_ready(dev)) | ||
214 | ; | ||
215 | return URXH1; | ||
216 | break; | ||
217 | case 2: | ||
218 | while (!uart_rx_ready(dev)) | ||
219 | ; | ||
220 | return URXH2; | ||
221 | break; | ||
222 | } | ||
223 | |||
224 | return true; | ||
225 | } | ||
226 | |||
227 | /**************************************************************************** | ||
228 | * General | ||
229 | *****************************************************************************/ | ||
230 | |||
231 | bool uart_send (unsigned dev, char *buf, unsigned len) | ||
232 | { | ||
233 | unsigned index=0; | ||
234 | while (index<len) | ||
235 | { | ||
236 | uart_send_byte (dev, buf[index]); | ||
237 | |||
238 | /* hack for ASCII terminals */ | ||
239 | if (buf[index] == '\n') | ||
240 | uart_send_byte (dev, '\r'); | ||
241 | |||
242 | index++; | ||
243 | } | ||
244 | return true; | ||
245 | } | ||
246 | |||
247 | |||
248 | /****************************************************************************/ | ||
diff --git a/firmware/target/arm/s3c2440/uart-s3c2440.h b/firmware/target/arm/s3c2440/uart-s3c2440.h new file mode 100644 index 0000000000..01a8f67ea1 --- /dev/null +++ b/firmware/target/arm/s3c2440/uart-s3c2440.h | |||
@@ -0,0 +1,48 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * | ||
10 | * Copyright (C) 2009 by Bob Cousins | ||
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 __UART_S3C2440_H__ | ||
23 | #define __UART_S3C2440_H__ | ||
24 | |||
25 | #define UART_DEBUG 0 | ||
26 | |||
27 | #define UART_NO_PARITY 0 | ||
28 | #define UART_ODD_PARITY 4 | ||
29 | #define UART_EVEN_PARITY 5 | ||
30 | #define UART_MARK_PARITY 6 | ||
31 | #define UART_SPACE_PARITY 7 | ||
32 | |||
33 | #define UART_1_STOP_BIT 0 | ||
34 | #define UART_2_STOP_BIT 1 | ||
35 | |||
36 | bool uart_init (void); | ||
37 | void uart_printf (const char *format, ...); | ||
38 | |||
39 | /* low level routines */ | ||
40 | bool uart_init_device (unsigned dev); | ||
41 | bool uart_config (unsigned dev, unsigned speed, unsigned num_bits, unsigned parity, unsigned stop_bits); | ||
42 | bool uart_send (unsigned dev, char *buf, unsigned len); | ||
43 | |||
44 | char uart_read_byte (unsigned dev); | ||
45 | char uart_rx_ready (unsigned dev); | ||
46 | |||
47 | |||
48 | #endif | ||