rockbox/firmware/target/arm/imx233/sd-imx233.c
Amaury Pouly 7d4fed53cc imx233:fuze+: major memory and usb rework
- now identity map dram uncached and have a cached and buffered virtual alias
- rework dma to handle virtual to physical pointers conversion
- fix lcd frame pointer
- implement usb detection properly
- implement bootloader usb properly
- allow the bootloader to disable MMC windowing (useful for recovery)

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30432 a1c6a512-1295-4272-9138-f99709370657
2011-09-05 11:29:32 +00:00

235 lines
6.7 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2011 by Amaury Pouly
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "config.h"
#include "system.h"
#include "sd.h"
#include "sdmmc.h"
#include "ssp-imx233.h"
#include "pinctrl-imx233.h"
#include "button-target.h"
#include "fat.h"
#include "disk.h"
#include "usb.h"
#include "debug.h"
/**
* This code assumes a single SD card slot
*/
#ifdef SANSA_FUZEPLUS
#define SD_SSP 1
#else
#error You need to configure the ssp to use
#endif
static tCardInfo card_info;
static long sd_stack [(DEFAULT_STACK_SIZE*2 + 0x200)/sizeof(long)];
static struct mutex sd_mutex;
static const char sd_thread_name[] = "sd";
static struct event_queue sd_queue;
static int sd_first_drive;
static int last_disk_activity;
static void sd_detect_callback(int ssp)
{
(void)ssp;
/* This is called only if the state was stable for 300ms - check state
* and post appropriate event. */
if(imx233_ssp_sdmmc_detect(SD_SSP))
queue_broadcast(SYS_HOTSWAP_INSERTED, 0);
else
queue_broadcast(SYS_HOTSWAP_EXTRACTED, 0);
imx233_ssp_sdmmc_setup_detect(SD_SSP, true, sd_detect_callback);
}
void sd_enable(bool on)
{
static bool sd_enable = false;
if(sd_enable == on)
return;
mutex_lock(&sd_mutex);
if(on)
imx233_ssp_start(SD_SSP);
else
imx233_ssp_stop(SD_SSP);
mutex_unlock(&sd_mutex);
sd_enable = on;
}
static int sd_init_card(void)
{
imx233_ssp_start(SD_SSP);
imx233_ssp_softreset(SD_SSP);
imx233_ssp_set_mode(SD_SSP, HW_SSP_CTRL1__SSP_MODE__SD_MMC);
/* SSPCLK @ 96MHz
* gives bitrate of 96000 / 240 / 1 = 400kHz */
imx233_ssp_set_timings(SD_SSP, 240, 0, 0xffff);
imx233_ssp_set_bus_width(SD_SSP, 1);
imx233_ssp_set_block_size(SD_SSP, 9);
card_info.rca = 0;
bool is_v2 = false;
uint32_t resp;
/* go to idle state */
int ret = imx233_ssp_sd_mmc_transfer(SD_SSP, SD_GO_IDLE_STATE, 0, SSP_NO_RESP, NULL, 0, false, false, NULL);
if(ret != 0)
return -1;
/* CMD8 Check for v2 sd card. Must be sent before using ACMD41
Non v2 cards will not respond to this command*/
ret = imx233_ssp_sd_mmc_transfer(SD_SSP, SD_SEND_IF_COND, 0x1AA, SSP_SHORT_RESP, NULL, 0, false, false, &resp);
if(ret == 0 && (resp & 0xFFF) == 0x1AA)
is_v2 = true;
return -10;
}
static void sd_thread(void) NORETURN_ATTR;
static void sd_thread(void)
{
struct queue_event ev;
while (1)
{
queue_wait_w_tmo(&sd_queue, &ev, HZ);
switch(ev.id)
{
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_mutex); /* lock-out card activity - direct calls
into driver that bypass the fat cache */
/* We now have exclusive control of fat cache and sd */
disk_unmount(sd_first_drive); /* 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_info.initialized = 0;
if(ev.id == SYS_HOTSWAP_INSERTED)
{
int ret = sd_init_card();
if(ret == 0)
{
ret = disk_mount(sd_first_drive); /* 0 if fail */
if(ret < 0)
DEBUGF("disk_mount failed: %d", ret);
}
else
DEBUGF("sd_init_card failed: %d", ret);
}
/*
* Mount succeeded, or this was an EXTRACTED event,
* in both cases notify the system about the changed filesystems
*/
if(card_info.initialized)
queue_broadcast(SYS_FS_CHANGED, 0);
/* Access is now safe */
mutex_unlock(&sd_mutex);
fat_unlock();
}
break;
case SYS_TIMEOUT:
if(!TIME_BEFORE(current_tick, last_disk_activity+(3*HZ)))
sd_enable(false);
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;
}
}
}
int sd_init(void)
{
mutex_init(&sd_mutex);
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));
#ifdef SANSA_FUZEPLUS
imx233_ssp_setup_ssp1_sd_mmc_pins(true, 4, PINCTRL_DRIVE_8mA, false);
#endif
imx233_ssp_sdmmc_setup_detect(SD_SSP, true, sd_detect_callback);
if(imx233_ssp_sdmmc_detect(SD_SSP))
queue_broadcast(SYS_HOTSWAP_INSERTED, 0);
return 0;
}
int sd_read_sectors(IF_MD2(int drive,) unsigned long start, int count,
void* buf)
{
IF_MD((void) drive);
(void) start;
(void) count;
(void) buf;
return -1;
}
int sd_write_sectors(IF_MD2(int drive,) unsigned long start, int count,
const void* buf)
{
IF_MD((void) drive);
(void) start;
(void) count;
(void) buf;
return -1;
}
tCardInfo *card_get_info_target(int card_no)
{
(void)card_no;
return NULL;
}
int sd_num_drives(int first_drive)
{
sd_first_drive = first_drive;
return 1;
}
bool sd_present(IF_MD(int drive))
{
IF_MD((void) drive);
return imx233_ssp_sdmmc_detect(SD_SSP);
}
bool sd_removable(IF_MD(int drive))
{
IF_MD((void) drive);
return true;
}