From d052ced874172e95fdc1d096205ac4dfe38907f3 Mon Sep 17 00:00:00 2001 From: Maurus Cuelenaere Date: Thu, 26 Nov 2009 16:57:30 +0000 Subject: Merge branch 'hotswap' git-svn-id: svn://svn.rockbox.org/rockbox/trunk@23759 a1c6a512-1295-4272-9138-f99709370657 --- .../target/mips/ingenic_jz47xx/ata-sd-jz4740.c | 335 ++++++++++++++------- .../mips/ingenic_jz47xx/onda_vx747/ata-sd-target.h | 13 +- .../target/mips/ingenic_jz47xx/system-target.h | 25 +- 3 files changed, 252 insertions(+), 121 deletions(-) (limited to 'firmware/target') diff --git a/firmware/target/mips/ingenic_jz47xx/ata-sd-jz4740.c b/firmware/target/mips/ingenic_jz47xx/ata-sd-jz4740.c index f3d67aec51..454d7a51f2 100644 --- a/firmware/target/mips/ingenic_jz47xx/ata-sd-jz4740.c +++ b/firmware/target/mips/ingenic_jz47xx/ata-sd-jz4740.c @@ -22,25 +22,40 @@ #include "config.h" #include "jz4740.h" #include "ata.h" +#include "ata_idle_notify.h" #include "ata-sd-target.h" +#include "disk.h" +#include "fat.h" +#include "led.h" +#include "hotswap.h" #include "logf.h" #include "sd.h" #include "system.h" #include "kernel.h" -#include "panic.h" -#include "debug.h" #include "storage.h" #include "string.h" -#include "led.h" +#include "usb.h" + +static long last_disk_activity = -1; +static int sd_drive_nr = 0; +static tCardInfo card; -static struct wakeup sd_wakeup; -static long last_disk_activity = -1; -static tCardInfo card; +static long sd_stack[(DEFAULT_STACK_SIZE*2 + 0x1c0)/sizeof(long)]; +static const char sd_thread_name[] = "ata/sd"; +static struct event_queue sd_queue; +static struct mutex sd_mtx; +static struct wakeup sd_wakeup; +static void sd_thread(void) __attribute__((noreturn)); + +static int use_4bit; +static int num_6; +static int sd2_0; //#define SD_DMA_ENABLE #define SD_DMA_INTERRUPT 0 -#define DEBUG(x...) logf(x) +//#define DEBUG(x...) logf(x) +#define DEBUG(x, ...) #define SD_INSERT_STATUS() __gpio_get_pin(MMC_CD_PIN) #define SD_RESET() __msc_reset() @@ -117,7 +132,6 @@ enum sd_rsp_t RESPONSE_R7 = 9, }; - /* MMC status in R1 Type @@ -199,10 +213,6 @@ struct sd_request #define SD_EVENT_TX_DATA_DONE 0x02 /* Tx data done */ #define SD_EVENT_PROG_DONE 0x04 /* Programming is done */ -static int use_4bit = 1; /* Use 4-bit data bus */ -static int num_6 = 0; -static int sd2_0 = 0; - /************************************************************************** * Utility functions **************************************************************************/ @@ -214,7 +224,7 @@ static int sd2_0 = 0; #define PARSE_U16(_buf,_index) \ (((unsigned short)_buf[_index]) << 8) | ((unsigned short)_buf[_index+1]); -int sd_unpack_r1(struct sd_request *request, struct sd_response_r1 *r1) +static int sd_unpack_r1(struct sd_request *request, struct sd_response_r1 *r1) { unsigned char *buf = request->response; @@ -253,32 +263,22 @@ int sd_unpack_r1(struct sd_request *request, struct sd_response_r1 *r1) return 0; } -int sd_unpack_scr(struct sd_request *request, struct sd_response_r1 *r1, unsigned int *scr) -{ - unsigned char *buf = request->response; - if (request->result) - return request->result; - - *scr = PARSE_U32(buf, 5); /* Save SCR returned by the SD Card */ - return sd_unpack_r1(request, r1); -} - -static inline int sd_unpack_r6(struct sd_request *request, struct sd_response_r1 *r1, unsigned long *rca) +static int sd_unpack_r6(struct sd_request *request, struct sd_response_r1 *r1, unsigned long *rca) { unsigned char *buf = request->response; if (request->result) return request->result; - + *rca = PARSE_U16(buf,1); /* Save RCA returned by the SD Card */ - + *(buf+1) = 0; *(buf+2) = 0; - + return sd_unpack_r1(request, r1); -} +} -int sd_unpack_r3(struct sd_request *request, struct sd_response_r3 *r3) +static int sd_unpack_r3(struct sd_request *request, struct sd_response_r3 *r3) { unsigned char *buf = request->response; @@ -287,7 +287,9 @@ int sd_unpack_r3(struct sd_request *request, struct sd_response_r3 *r3) r3->ocr = PARSE_U32(buf,1); DEBUG("sd_unpack_r3: ocr=%08x", r3->ocr); - if (buf[0] != 0x3f) return SD_ERROR_HEADER_MISMATCH; + if (buf[0] != 0x3f) + return SD_ERROR_HEADER_MISMATCH; + return 0; } @@ -917,7 +919,6 @@ static void jz_sd_tx_handler(unsigned int arg) } if (__dmac_channel_transmit_end_detected(arg)) { - __dmac_channel_clear_transmit_end(arg); OSSemPost(sd_dma_tx_sem); } @@ -945,6 +946,14 @@ void MSC(void) logf("MSC interrupt"); } +static void sd_gpio_setup_irq(bool inserted) +{ + if(inserted) + __gpio_as_irq_rise_edge(MMC_CD_PIN); + else + __gpio_as_irq_fall_edge(MMC_CD_PIN); +} + /******************************************************************************************************************* ** Name: void sd_hardware_init() ** Function: initialize the hardware condiction that access sd card @@ -954,7 +963,8 @@ void MSC(void) static void jz_sd_hardware_init(void) { __cpm_start_msc(); /* enable mmc clock */ - mmc_init_gpio(); /* init GPIO */ + sd_init_gpio(); /* init GPIO */ + sd_gpio_setup_irq(jz_sd_chkcard()); #ifdef SD_POWER_ON SD_POWER_ON(); /* turn on power of card */ #endif @@ -1000,7 +1010,6 @@ static void sd_simple_cmd(struct sd_request *request, int cmd, unsigned int arg, #define SD_INIT_DOING 0 #define SD_INIT_PASSED 1 #define SD_INIT_FAILED 2 - static int sd_init_card_state(struct sd_request *request) { struct sd_response_r1 r1; @@ -1026,41 +1035,42 @@ static int sd_init_card_state(struct sd_request *request) retval); limit_41++; sd_simple_cmd(request, SD_APP_OP_COND, ocr, RESPONSE_R3); - } else if (limit_41 < 100) { + } + else if (limit_41 < 100) + { limit_41++; sd_simple_cmd(request, SD_APP_OP_COND, ocr, RESPONSE_R3); - } else{ + } + else /* reset the card to idle*/ sd_simple_cmd(request, SD_GO_IDLE_STATE, 0, RESPONSE_NONE); - } break; case SD_APP_OP_COND: retval = sd_unpack_r3(request, &r3); if (retval) - { break; - } DEBUG("sd_init_card_state: read ocr value = 0x%08x", r3.ocr); card.ocr = r3.ocr; - if(!(r3.ocr & SD_CARD_BUSY || ocr == 0)){ - udelay(10000); + if(!(r3.ocr & SD_CARD_BUSY || ocr == 0)) + { + sleep(HZ / 100); sd_simple_cmd(request, SD_APP_CMD, 0, RESPONSE_R1); } else { - /* Set the data bus width to 4 bits */ - use_4bit = 1; - sd_simple_cmd(request, SD_ALL_SEND_CID, 0, RESPONSE_R2_CID); + /* Set the data bus width to 4 bits */ + use_4bit = 1; + sd_simple_cmd(request, SD_ALL_SEND_CID, 0, RESPONSE_R2_CID); } break; case SD_ALL_SEND_CID: for(i=0; i<4; i++) card.cid[i] = ((request->response[1+i*4]<<24) | (request->response[2+i*4]<<16) | - (request->response[3+i*4]<< 8) | request->response[4+i*4]); + (request->response[3+i*4]<< 8) | request->response[4+i*4]); logf("CID: %08lx%08lx%08lx%08lx", card.cid[0], card.cid[1], card.cid[2], card.cid[3]); sd_simple_cmd(request, SD_SEND_RELATIVE_ADDR, 0, RESPONSE_R6); @@ -1068,7 +1078,7 @@ static int sd_init_card_state(struct sd_request *request) case SD_SEND_RELATIVE_ADDR: retval = sd_unpack_r6(request, &r1, &card.rca); card.rca = card.rca << 16; - DEBUG("sd_init_card_state: Get RCA from SD: 0x%04x Status: %x", card.rca, r1.status); + DEBUG("sd_init_card_state: Get RCA from SD: 0x%04lx Status: %x", card.rca, r1.status); if (retval) { DEBUG("sd_init_card_state: unable to SET_RELATIVE_ADDR error=%d", @@ -1082,7 +1092,7 @@ static int sd_init_card_state(struct sd_request *request) case SD_SEND_CSD: for(i=0; i<4; i++) card.csd[i] = ((request->response[1+i*4]<<24) | (request->response[2+i*4]<<16) | - (request->response[3+i*4]<< 8) | request->response[4+i*4]); + (request->response[3+i*4]<< 8) | request->response[4+i*4]); sd_parse_csd(&card); sd2_0 = (card_extract_bits(card.csd, 127, 2) == 1); @@ -1091,6 +1101,7 @@ static int sd_init_card_state(struct sd_request *request) DEBUG("SD card is ready"); jz_sd_set_clock(SD_CLOCK_FAST); return SD_INIT_PASSED; + default: DEBUG("sd_init_card_state: error! Illegal last cmd %d", request->cmd); return SD_INIT_FAILED; @@ -1110,7 +1121,7 @@ static int sd_switch(struct sd_request *request, int mode, int group, arg &= ~(0xF << (group * 4)); arg |= value << (group * 4); sd_send_cmd(request, 6, arg, 1, 64, RESPONSE_R1, resp); - + return 0; } @@ -1123,7 +1134,7 @@ static int sd_read_switch(struct sd_request *request) memset((unsigned char *)status, 0, 64); sd_switch(request, 0, 0, 1, (unsigned char*) status); - + if (((unsigned char *)status)[13] & 0x02) return 0; else @@ -1141,7 +1152,7 @@ static int sd_switch_hs(struct sd_request *request) return 0; } -int sd_select_card(void) +static int sd_select_card(void) { struct sd_request request; struct sd_response_r1 r1; @@ -1173,31 +1184,57 @@ int sd_select_card(void) if (retval) return retval; + card.initialized = 1; + return 0; } -int sd_init(void) +static int sd_init_device(void) { int retval; - static bool inited = false; struct sd_request init_req; + + mutex_lock(&sd_mtx); + + /* Initialise card data as blank */ + memset(&card, 0, sizeof(tCardInfo)); + + sd2_0 = 0; + num_6 = 0; + use_4bit = 0; + + /* reset mmc/sd controller */ + jz_sd_hardware_init(); + + sd_simple_cmd(&init_req, SD_CIM_RESET, 0, RESPONSE_NONE); + sd_simple_cmd(&init_req, SD_GO_IDLE_STATE, 0, RESPONSE_NONE); + + sleep(HZ/2); /* Give the card/controller some rest */ + + while((retval = sd_init_card_state(&init_req)) == SD_INIT_DOING); + retval = (retval == SD_INIT_PASSED ? sd_select_card() : -1); + + mutex_unlock(&sd_mtx); + + return retval; +} + +int sd_init(void) +{ + static bool inited = false; if(!inited) { - jz_sd_hardware_init(); wakeup_init(&sd_wakeup); - num_6 = 0; + mutex_init(&sd_mtx); + queue_init(&sd_queue, true); + create_thread(sd_thread, sd_stack, sizeof(sd_stack), 0, + sd_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE) + IF_COP(, CPU)); + inited = true; } - - sd_simple_cmd(&init_req, SD_CIM_RESET, 0, RESPONSE_NONE); - sd_simple_cmd(&init_req, SD_GO_IDLE_STATE, 0, RESPONSE_NONE); - - while ((retval = sd_init_card_state(&init_req)) == SD_INIT_DOING); - if (retval == SD_INIT_PASSED) - return sd_select_card(); - else - return -1; + return sd_init_device(); } static inline bool card_detect_target(void) @@ -1205,20 +1242,6 @@ static inline bool card_detect_target(void) return (jz_sd_chkcard() == 1); } -#ifdef HAVE_HOTSWAP -void card_enable_monitoring_target(bool on) -{ - if(on) - { - - } - else - { - - } -} -#endif - tCardInfo* card_get_info_target(int card_no) { (void)card_no; @@ -1230,30 +1253,34 @@ int sd_read_sectors(IF_MV2(int drive,) unsigned long start, int count, void* buf #ifdef HAVE_MULTIVOLUME (void)drive; #endif + mutex_lock(&sd_mtx); led(true); struct sd_request request; struct sd_response_r1 r1; - int retval; + int retval = -1; if (!card_detect_target() || count == 0 || start > card.numblocks) - return -1; - + goto err; + + if(card.initialized == 0 && !sd_init_device()) + goto err; + sd_simple_cmd(&request, SD_SEND_STATUS, card.rca, RESPONSE_R1); retval = sd_unpack_r1(&request, &r1); if (retval && (retval != SD_ERROR_STATE_MISMATCH)) - return retval; - + goto err; + sd_simple_cmd(&request, SD_SET_BLOCKLEN, SD_BLOCK_SIZE, RESPONSE_R1); if ((retval = sd_unpack_r1(&request, &r1))) - return retval; - + goto err; + if (sd2_0) { sd_send_cmd(&request, SD_READ_MULTIPLE_BLOCK, start, count, SD_BLOCK_SIZE, RESPONSE_R1, buf); if ((retval = sd_unpack_r1(&request, &r1))) - return retval; + goto err; } else { @@ -1261,16 +1288,18 @@ int sd_read_sectors(IF_MV2(int drive,) unsigned long start, int count, void* buf start * SD_BLOCK_SIZE, count, SD_BLOCK_SIZE, RESPONSE_R1, buf); if ((retval = sd_unpack_r1(&request, &r1))) - return retval; + goto err; } - + last_disk_activity = current_tick; sd_simple_cmd(&request, SD_STOP_TRANSMISSION, 0, RESPONSE_R1B); if ((retval = sd_unpack_r1(&request, &r1))) - return retval; - + goto err; + +err: led(false); + mutex_unlock(&sd_mtx); return retval; } @@ -1280,23 +1309,27 @@ int sd_write_sectors(IF_MV2(int drive,) unsigned long start, int count, const vo #ifdef HAVE_MULTIVOLUME (void)drive; #endif + mutex_lock(&sd_mtx); led(true); struct sd_request request; struct sd_response_r1 r1; - int retval; + int retval = -1; if (!card_detect_target() || count == 0 || start > card.numblocks) - return -1; + goto err; + + if(card.initialized == 0 && !sd_init_device()) + goto err; sd_simple_cmd(&request, SD_SEND_STATUS, card.rca, RESPONSE_R1); retval = sd_unpack_r1(&request, &r1); if (retval && (retval != SD_ERROR_STATE_MISMATCH)) - return retval; + goto err; sd_simple_cmd(&request, SD_SET_BLOCKLEN, SD_BLOCK_SIZE, RESPONSE_R1); if ((retval = sd_unpack_r1(&request, &r1))) - return retval; + goto err; if (sd2_0) { @@ -1304,7 +1337,7 @@ int sd_write_sectors(IF_MV2(int drive,) unsigned long start, int count, const vo count, SD_BLOCK_SIZE, RESPONSE_R1, (void*)buf); if ((retval = sd_unpack_r1(&request, &r1))) - return retval; + goto err; } else { @@ -1312,13 +1345,18 @@ int sd_write_sectors(IF_MV2(int drive,) unsigned long start, int count, const vo start * SD_BLOCK_SIZE, count, SD_BLOCK_SIZE, RESPONSE_R1, (void*)buf); if ((retval = sd_unpack_r1(&request, &r1))) - return retval; + goto err; } + + last_disk_activity = current_tick; + sd_simple_cmd(&request, SD_STOP_TRANSMISSION, 0, RESPONSE_R1B); if ((retval = sd_unpack_r1(&request, &r1))) - return retval; + goto err; +err: led(false); + mutex_unlock(&sd_mtx); return retval; } @@ -1342,10 +1380,9 @@ void sd_sleepnow(void) { } -/* TODO */ bool sd_disk_is_active(void) { - return false; + return sd_mtx.locked; } int sd_soft_reset(void) @@ -1359,8 +1396,39 @@ bool sd_removable(IF_MV_NONVOID(int drive)) #ifdef HAVE_MULTIVOLUME (void)drive; #endif - //return true; - return false; + return true; +} + +void card_enable_monitoring_target(bool on) +{ + if(on) + sd_gpio_setup_irq(card_detect_target()); + else + __gpio_mask_irq(MMC_CD_PIN); +} + +static int sd_oneshot_callback(struct timeout *tmo) +{ + (void)tmo; + int state = card_detect_target(); + + /* This is called only if the state was stable for 300ms - check state + * and post appropriate event. */ + if (state) + queue_broadcast(SYS_HOTSWAP_INSERTED, 0); + else + queue_broadcast(SYS_HOTSWAP_EXTRACTED, 0); + + sd_gpio_setup_irq(state); + + return 0; +} + +/* called on insertion/removal interrupt */ +void MMC_CD_IRQ(void) +{ + static struct timeout sd_oneshot; + timeout_register(&sd_oneshot, sd_oneshot_callback, (3*HZ/10), 0); } #endif @@ -1375,9 +1443,72 @@ bool sd_present(IF_MV_NONVOID(int drive)) #ifdef CONFIG_STORAGE_MULTI int sd_num_drives(int first_drive) { - /* We don't care which logical drive number(s) we have been assigned */ - (void)first_drive; - + sd_drive_nr = first_drive; return 1; } #endif + +static void sd_thread(void) +{ + struct queue_event ev; + bool idle_notified = false; + + while (1) + { + queue_wait_w_tmo(&sd_queue, &ev, HZ); + + switch (ev.id) + { +#ifdef HAVE_HOTSWAP + case SYS_HOTSWAP_INSERTED: + case SYS_HOTSWAP_EXTRACTED: + fat_lock(); /* lock-out FAT activity first - + prevent deadlocking via disk_mount that + would cause a reverse-order attempt with + another thread */ + mutex_lock(&sd_mtx); /* lock-out card activity - direct calls + into driver that bypass the fat cache */ + + /* We now have exclusive control of fat cache and ata */ + + disk_unmount(sd_drive_nr); /* release "by force", ensure file + descriptors aren't leaked and any busy + ones are invalid if mounting */ + + /* Force card init for new card, re-init for re-inserted one or + * clear if the last attempt to init failed with an error. */ + card.initialized = 0; + + if(ev.id == SYS_HOTSWAP_INSERTED) + disk_mount(sd_drive_nr); + + queue_broadcast(SYS_FS_CHANGED, 0); + + /* Access is now safe */ + mutex_unlock(&sd_mtx); + fat_unlock(); + break; +#endif + case SYS_TIMEOUT: + if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ))) + idle_notified = false; + else + { + if (!idle_notified) + { + call_storage_idle_notifys(false); + idle_notified = true; + } + } + break; + case SYS_USB_CONNECTED: + usb_acknowledge(SYS_USB_CONNECTED_ACK); + /* Wait until the USB cable is extracted again */ + usb_wait_for_disconnect(&sd_queue); + break; + case SYS_USB_DISCONNECTED: + usb_acknowledge(SYS_USB_DISCONNECTED_ACK); + break; + } + } +} diff --git a/firmware/target/mips/ingenic_jz47xx/onda_vx747/ata-sd-target.h b/firmware/target/mips/ingenic_jz47xx/onda_vx747/ata-sd-target.h index c0f2c11956..757a12d9f2 100644 --- a/firmware/target/mips/ingenic_jz47xx/onda_vx747/ata-sd-target.h +++ b/firmware/target/mips/ingenic_jz47xx/onda_vx747/ata-sd-target.h @@ -22,20 +22,19 @@ #ifndef ATA_SD_TARGET_H #define ATA_SD_TARGET_H -#include "inttypes.h" -#include "hotswap.h" #include "jz4740.h" - -int _sd_read_sectors(unsigned long start, int count, void* buf); -int _sd_write_sectors(unsigned long start, int count, const void* buf); -int _sd_init(void); +#include "system.h" #define MMC_CD_PIN (32*1 + 29) /* Pin to check card insertion */ +#define MMC_CD_IRQ GPIO61 -static inline void mmc_init_gpio(void) +static inline void sd_init_gpio(void) { __gpio_as_msc(); + __gpio_enable_pull(MMC_CD_PIN); __gpio_as_input(MMC_CD_PIN); + __gpio_mask_irq(MMC_CD_PIN); + system_enable_irq(GPIO_IRQ(MMC_CD_PIN)); } #endif diff --git a/firmware/target/mips/ingenic_jz47xx/system-target.h b/firmware/target/mips/ingenic_jz47xx/system-target.h index b2d960ef54..232412d0c7 100644 --- a/firmware/target/mips/ingenic_jz47xx/system-target.h +++ b/firmware/target/mips/ingenic_jz47xx/system-target.h @@ -33,14 +33,14 @@ /* This one returns the old status */ static inline int set_interrupt_status(int status, int mask) { - unsigned int res, oldstatus; - - res = oldstatus = read_c0_status(); - res &= ~mask; - res |= (status & mask); - write_c0_status(res); - - return oldstatus; + unsigned int res, oldstatus; + + res = oldstatus = read_c0_status(); + res &= ~mask; + res |= (status & mask); + write_c0_status(res); + + return oldstatus; } static inline void enable_interrupt(void) @@ -71,9 +71,9 @@ static inline void restore_interrupt(int status) #define set_irq_level(status) set_interrupt_status((status), ST0_IE) #define disable_irq_save() disable_interrupt_save(ST0_IE) #define restore_irq(c0_status) restore_interrupt(c0_status) - -#define swap16(x) (((x) & 0xff) << 8 | ((x) >> 8) & 0xff) -#define swap32(x) (((x) & 0xff) << 24 | ((x) & 0xff00) << 8 | \ + +#define swap16(x) (((x) & 0xff) << 8 | ((x) >> 8) & 0xff) +#define swap32(x) (((x) & 0xff) << 24 | ((x) & 0xff00) << 8 | \ ((x) & 0xff0000) >> 8 | ((x) >> 24) & 0xff) #define UNCACHED_ADDRESS(addr) ((unsigned int)(addr) | 0xA0000000) @@ -94,6 +94,7 @@ void dma_disable(void); #define XDMA_CALLBACK(n) DMA ## n #define DMA_CALLBACK(n) XDMA_CALLBACK(n) -#define DMA_IRQ(n) (IRQ_DMA_0 + n) +#define DMA_IRQ(n) (IRQ_DMA_0 + (n)) +#define GPIO_IRQ(n) (IRQ_GPIO_0 + (n)) #endif /* __SYSTEM_TARGET_H_ */ -- cgit v1.2.3