2010-10-08 16:30:53 +00:00
|
|
|
/*
|
|
|
|
* (C) Copyright 2010 Juergen Beisert, Pengutronix
|
|
|
|
*
|
|
|
|
* This code is havily inspired and in parts from the u-boot project:
|
|
|
|
*
|
|
|
|
* Copyright 2008, Freescale Semiconductor, Inc
|
|
|
|
* Andy Fleming
|
|
|
|
*
|
|
|
|
* Based vaguely on the Linux code
|
|
|
|
*
|
|
|
|
* See file CREDITS for list of people who contributed to this
|
|
|
|
* project.
|
|
|
|
*
|
|
|
|
* 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 program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
|
|
* MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* #define DEBUG */
|
|
|
|
|
|
|
|
#include <init.h>
|
|
|
|
#include <common.h>
|
|
|
|
#include <mci.h>
|
|
|
|
#include <malloc.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <asm-generic/div64.h>
|
|
|
|
#include <asm/byteorder.h>
|
2011-11-24 12:43:47 +00:00
|
|
|
#include <block.h>
|
|
|
|
#include <disks.h>
|
2010-10-08 16:30:53 +00:00
|
|
|
|
|
|
|
#define MAX_BUFFER_NUMBER 0xffffffff
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @file
|
|
|
|
* @brief Memory Card framework
|
|
|
|
*
|
|
|
|
* Checked with the following cards:
|
2010-10-11 12:53:22 +00:00
|
|
|
* - Canon MMC 16 MiB
|
2010-10-14 11:04:25 +00:00
|
|
|
* - Integral MicroSDHC, 8 GiB (Class 4)
|
2010-10-08 16:30:53 +00:00
|
|
|
* - Kingston 512 MiB
|
|
|
|
* - SanDisk 512 MiB
|
|
|
|
* - Transcend SD Ultra, 1 GiB (Industrial)
|
2010-10-14 11:04:25 +00:00
|
|
|
* - Transcend SDHC, 4 GiB (Class 6)
|
|
|
|
* - Transcend SDHC, 8 GiB (Class 6)
|
2010-10-08 16:30:53 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Call the MMC/SD instance driver to run the command on the MMC/SD card
|
|
|
|
* @param mci_dev MCI instance
|
|
|
|
* @param cmd The information about the command to run
|
|
|
|
* @param data The data according to the command (can be NULL)
|
|
|
|
* @return Driver's answer (0 on success)
|
|
|
|
*/
|
|
|
|
static int mci_send_cmd(struct device_d *mci_dev, struct mci_cmd *cmd, struct mci_data *data)
|
|
|
|
{
|
|
|
|
struct mci_host *host = GET_MCI_PDATA(mci_dev);
|
|
|
|
|
|
|
|
return host->send_cmd(host, cmd, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param p Command definition to setup
|
|
|
|
* @param cmd Valid SD/MMC command (refer MMC_CMD_* / SD_CMD_*)
|
|
|
|
* @param arg Argument for the command (optional)
|
|
|
|
* @param response Command's response type (refer MMC_RSP_*)
|
|
|
|
*
|
|
|
|
* Note: When calling, the 'response' must match command's requirements
|
|
|
|
*/
|
|
|
|
static void mci_setup_cmd(struct mci_cmd *p, unsigned cmd, unsigned arg, unsigned response)
|
|
|
|
{
|
|
|
|
p->cmdidx = cmd;
|
|
|
|
p->cmdarg = arg;
|
|
|
|
p->resp_type = response;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Setup SD/MMC card's blocklength to be used for future transmitts
|
|
|
|
* @param mci_dev MCI instance
|
|
|
|
* @param len Blocklength in bytes
|
|
|
|
* @return Transaction status (0 on success)
|
|
|
|
*/
|
|
|
|
static int mci_set_blocklen(struct device_d *mci_dev, unsigned len)
|
|
|
|
{
|
|
|
|
struct mci_cmd cmd;
|
|
|
|
|
|
|
|
mci_setup_cmd(&cmd, MMC_CMD_SET_BLOCKLEN, len, MMC_RSP_R1);
|
|
|
|
return mci_send_cmd(mci_dev, &cmd, NULL);
|
|
|
|
}
|
|
|
|
|
2010-10-11 08:47:50 +00:00
|
|
|
static void *sector_buf;
|
|
|
|
|
2010-10-08 16:30:53 +00:00
|
|
|
/**
|
|
|
|
* Write one block of data to the card
|
|
|
|
* @param mci_dev MCI instance
|
|
|
|
* @param src Where to read from to write to the card
|
|
|
|
* @param blocknum Block number to write
|
2011-11-24 12:43:47 +00:00
|
|
|
* @param blocks Block count to write
|
2010-10-08 16:30:53 +00:00
|
|
|
* @return Transaction status (0 on success)
|
|
|
|
*/
|
2011-11-24 12:43:47 +00:00
|
|
|
static int mci_block_write(struct device_d *mci_dev, const void *src, int blocknum,
|
2011-10-28 12:43:49 +00:00
|
|
|
int blocks)
|
2010-10-08 16:30:53 +00:00
|
|
|
{
|
|
|
|
struct mci *mci = GET_MCI_DATA(mci_dev);
|
|
|
|
struct mci_cmd cmd;
|
|
|
|
struct mci_data data;
|
2010-10-11 08:47:50 +00:00
|
|
|
const void *buf;
|
2011-10-28 12:43:49 +00:00
|
|
|
unsigned mmccmd;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (blocks > 1)
|
|
|
|
mmccmd = MMC_CMD_WRITE_MULTIPLE_BLOCK;
|
|
|
|
else
|
|
|
|
mmccmd = MMC_CMD_WRITE_SINGLE_BLOCK;
|
2010-10-11 08:47:50 +00:00
|
|
|
|
|
|
|
if ((unsigned long)src & 0x3) {
|
|
|
|
memcpy(sector_buf, src, 512);
|
|
|
|
buf = sector_buf;
|
|
|
|
} else {
|
|
|
|
buf = src;
|
|
|
|
}
|
2010-10-08 16:30:53 +00:00
|
|
|
|
|
|
|
mci_setup_cmd(&cmd,
|
2011-10-28 12:43:49 +00:00
|
|
|
mmccmd,
|
2010-10-08 16:30:53 +00:00
|
|
|
mci->high_capacity != 0 ? blocknum : blocknum * mci->write_bl_len,
|
|
|
|
MMC_RSP_R1);
|
|
|
|
|
2010-10-11 08:47:50 +00:00
|
|
|
data.src = buf;
|
2011-10-28 12:43:49 +00:00
|
|
|
data.blocks = blocks;
|
2010-10-08 16:30:53 +00:00
|
|
|
data.blocksize = mci->write_bl_len;
|
|
|
|
data.flags = MMC_DATA_WRITE;
|
|
|
|
|
2011-10-28 12:43:49 +00:00
|
|
|
ret = mci_send_cmd(mci_dev, &cmd, &data);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (blocks > 1) {
|
|
|
|
mci_setup_cmd(&cmd,
|
|
|
|
MMC_CMD_STOP_TRANSMISSION,
|
|
|
|
0, MMC_RSP_R1b);
|
|
|
|
ret = mci_send_cmd(mci_dev, &cmd, NULL);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2010-10-08 16:30:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Read one block of data from the card
|
|
|
|
* @param mci_dev MCI instance
|
|
|
|
* @param dst Where to store the data read from the card
|
|
|
|
* @param blocknum Block number to read
|
2010-10-21 06:59:37 +00:00
|
|
|
* @param blocks number of blocks to read
|
2010-10-08 16:30:53 +00:00
|
|
|
*/
|
2011-11-24 12:43:47 +00:00
|
|
|
static int mci_read_block(struct device_d *mci_dev, void *dst, int blocknum,
|
2010-10-21 06:59:37 +00:00
|
|
|
int blocks)
|
2010-10-08 16:30:53 +00:00
|
|
|
{
|
|
|
|
struct mci *mci = GET_MCI_DATA(mci_dev);
|
|
|
|
struct mci_cmd cmd;
|
|
|
|
struct mci_data data;
|
2010-10-21 06:59:37 +00:00
|
|
|
int ret;
|
|
|
|
unsigned mmccmd;
|
|
|
|
|
|
|
|
if (blocks > 1)
|
|
|
|
mmccmd = MMC_CMD_READ_MULTIPLE_BLOCK;
|
|
|
|
else
|
|
|
|
mmccmd = MMC_CMD_READ_SINGLE_BLOCK;
|
2010-10-08 16:30:53 +00:00
|
|
|
|
|
|
|
mci_setup_cmd(&cmd,
|
2010-10-21 06:59:37 +00:00
|
|
|
mmccmd,
|
2010-10-08 16:30:53 +00:00
|
|
|
mci->high_capacity != 0 ? blocknum : blocknum * mci->read_bl_len,
|
|
|
|
MMC_RSP_R1);
|
|
|
|
|
|
|
|
data.dest = dst;
|
2010-10-21 06:59:37 +00:00
|
|
|
data.blocks = blocks;
|
2010-10-08 16:30:53 +00:00
|
|
|
data.blocksize = mci->read_bl_len;
|
|
|
|
data.flags = MMC_DATA_READ;
|
|
|
|
|
2010-10-21 06:59:37 +00:00
|
|
|
ret = mci_send_cmd(mci_dev, &cmd, &data);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (blocks > 1) {
|
|
|
|
mci_setup_cmd(&cmd,
|
|
|
|
MMC_CMD_STOP_TRANSMISSION,
|
|
|
|
0,
|
|
|
|
MMC_RSP_R1b);
|
|
|
|
ret = mci_send_cmd(mci_dev, &cmd, NULL);
|
|
|
|
}
|
|
|
|
return ret;
|
2010-10-08 16:30:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reset the attached MMC/SD card
|
|
|
|
* @param mci_dev MCI instance
|
|
|
|
* @return Transaction status (0 on success)
|
|
|
|
*/
|
|
|
|
static int mci_go_idle(struct device_d *mci_dev)
|
|
|
|
{
|
|
|
|
struct mci_cmd cmd;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
udelay(1000);
|
|
|
|
|
|
|
|
mci_setup_cmd(&cmd, MMC_CMD_GO_IDLE_STATE, 0, MMC_RSP_NONE);
|
|
|
|
err = mci_send_cmd(mci_dev, &cmd, NULL);
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
pr_debug("Activating IDLE state failed: %d\n", err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
udelay(2000); /* WTF? */
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* FIXME
|
|
|
|
* @param mci_dev MCI instance
|
|
|
|
* @return Transaction status (0 on success)
|
|
|
|
*/
|
|
|
|
static int sd_send_op_cond(struct device_d *mci_dev)
|
|
|
|
{
|
|
|
|
struct mci *mci = GET_MCI_DATA(mci_dev);
|
|
|
|
struct mci_host *host = GET_MCI_PDATA(mci_dev);
|
|
|
|
struct mci_cmd cmd;
|
|
|
|
int timeout = 1000;
|
|
|
|
int err;
|
2011-03-18 12:43:23 +00:00
|
|
|
unsigned voltages;
|
2011-11-24 20:46:33 +00:00
|
|
|
unsigned busy;
|
2011-03-18 12:43:23 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Most cards do not answer if some reserved bits
|
|
|
|
* in the ocr are set. However, Some controller
|
|
|
|
* can set bit 7 (reserved for low voltages), but
|
|
|
|
* how to manage low voltages SD card is not yet
|
|
|
|
* specified.
|
|
|
|
*/
|
|
|
|
voltages = host->voltages & 0xff8000;
|
2010-10-08 16:30:53 +00:00
|
|
|
|
|
|
|
do {
|
|
|
|
mci_setup_cmd(&cmd, MMC_CMD_APP_CMD, 0, MMC_RSP_R1);
|
|
|
|
err = mci_send_cmd(mci_dev, &cmd, NULL);
|
|
|
|
if (err) {
|
|
|
|
pr_debug("Preparing SD for operating conditions failed: %d\n", err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
mci_setup_cmd(&cmd, SD_CMD_APP_SEND_OP_COND,
|
2011-11-24 20:46:33 +00:00
|
|
|
mmc_host_is_spi(host) ? 0 : (voltages | (mci->version == SD_VERSION_2 ? OCR_HCS : 0)),
|
2010-10-08 16:30:53 +00:00
|
|
|
MMC_RSP_R3);
|
|
|
|
err = mci_send_cmd(mci_dev, &cmd, NULL);
|
|
|
|
if (err) {
|
|
|
|
pr_debug("SD operation condition set failed: %d\n", err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
udelay(1000);
|
2011-11-24 20:46:33 +00:00
|
|
|
|
|
|
|
if (mmc_host_is_spi(host))
|
|
|
|
busy = cmd.response[0] & R1_SPI_IDLE;
|
|
|
|
else
|
|
|
|
busy = !(cmd.response[0] & OCR_BUSY);
|
|
|
|
|
|
|
|
} while (busy && timeout--);
|
2010-10-08 16:30:53 +00:00
|
|
|
|
|
|
|
if (timeout <= 0) {
|
|
|
|
pr_debug("SD operation condition set timed out\n");
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mci->version != SD_VERSION_2)
|
|
|
|
mci->version = SD_VERSION_1_0;
|
|
|
|
|
2011-11-24 20:46:33 +00:00
|
|
|
if (mmc_host_is_spi(host)) { /* read OCR for spi */
|
|
|
|
mci_setup_cmd(&cmd, MMC_CMD_SPI_READ_OCR, 0, MMC_RSP_R3);
|
|
|
|
err = mci_send_cmd(mci_dev, &cmd, NULL);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2010-10-08 16:30:53 +00:00
|
|
|
mci->ocr = cmd.response[0];
|
|
|
|
|
|
|
|
mci->high_capacity = ((mci->ocr & OCR_HCS) == OCR_HCS);
|
|
|
|
mci->rca = 0;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Setup the operation conditions to a MultiMediaCard
|
|
|
|
* @param mci_dev MCI instance
|
|
|
|
* @return Transaction status (0 on success)
|
|
|
|
*/
|
|
|
|
static int mmc_send_op_cond(struct device_d *mci_dev)
|
|
|
|
{
|
|
|
|
struct mci *mci = GET_MCI_DATA(mci_dev);
|
|
|
|
struct mci_host *host = GET_MCI_PDATA(mci_dev);
|
|
|
|
struct mci_cmd cmd;
|
|
|
|
int timeout = 1000;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
/* Some cards seem to need this */
|
|
|
|
mci_go_idle(mci_dev);
|
|
|
|
|
|
|
|
do {
|
|
|
|
mci_setup_cmd(&cmd, MMC_CMD_SEND_OP_COND, OCR_HCS |
|
|
|
|
host->voltages, MMC_RSP_R3);
|
|
|
|
err = mci_send_cmd(mci_dev, &cmd, NULL);
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
pr_debug("Preparing MMC for operating conditions failed: %d\n", err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
udelay(1000);
|
|
|
|
} while (!(cmd.response[0] & OCR_BUSY) && timeout--);
|
|
|
|
|
|
|
|
if (timeout <= 0) {
|
|
|
|
pr_debug("SD operation condition set timed out\n");
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
|
|
|
mci->version = MMC_VERSION_UNKNOWN;
|
|
|
|
mci->ocr = cmd.response[0];
|
|
|
|
|
|
|
|
mci->high_capacity = ((mci->ocr & OCR_HCS) == OCR_HCS);
|
|
|
|
mci->rca = 0;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* FIXME
|
|
|
|
* @param mci_dev MCI instance
|
|
|
|
* @param ext_csd Buffer for a 512 byte sized extended CSD
|
|
|
|
* @return Transaction status (0 on success)
|
|
|
|
*
|
|
|
|
* Note: Only cards newer than Version 1.1 (Physical Layer Spec) support
|
|
|
|
* this command
|
|
|
|
*/
|
|
|
|
static int mci_send_ext_csd(struct device_d *mci_dev, char *ext_csd)
|
|
|
|
{
|
|
|
|
struct mci_cmd cmd;
|
|
|
|
struct mci_data data;
|
|
|
|
|
|
|
|
/* Get the Card Status Register */
|
|
|
|
mci_setup_cmd(&cmd, MMC_CMD_SEND_EXT_CSD, 0, MMC_RSP_R1);
|
|
|
|
|
|
|
|
data.dest = ext_csd;
|
|
|
|
data.blocks = 1;
|
|
|
|
data.blocksize = 512;
|
|
|
|
data.flags = MMC_DATA_READ;
|
|
|
|
|
|
|
|
return mci_send_cmd(mci_dev, &cmd, &data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* FIXME
|
|
|
|
* @param mci_dev MCI instance
|
|
|
|
* @param set FIXME
|
|
|
|
* @param index FIXME
|
|
|
|
* @param value FIXME
|
|
|
|
* @return Transaction status (0 on success)
|
|
|
|
*/
|
|
|
|
static int mci_switch(struct device_d *mci_dev, unsigned set, unsigned index,
|
|
|
|
unsigned value)
|
|
|
|
{
|
|
|
|
struct mci_cmd cmd;
|
|
|
|
|
|
|
|
mci_setup_cmd(&cmd, MMC_CMD_SWITCH,
|
|
|
|
(MMC_SWITCH_MODE_WRITE_BYTE << 24) |
|
|
|
|
(index << 16) |
|
|
|
|
(value << 8),
|
|
|
|
MMC_RSP_R1b);
|
|
|
|
|
|
|
|
return mci_send_cmd(mci_dev, &cmd, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Change transfer frequency for an MMC card
|
|
|
|
* @param mci_dev MCI instance
|
|
|
|
* @return Transaction status (0 on success)
|
|
|
|
*/
|
|
|
|
static int mmc_change_freq(struct device_d *mci_dev)
|
|
|
|
{
|
|
|
|
struct mci *mci = GET_MCI_DATA(mci_dev);
|
2010-10-22 10:21:25 +00:00
|
|
|
char *ext_csd = sector_buf;
|
2010-10-08 16:30:53 +00:00
|
|
|
char cardtype;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
mci->card_caps = 0;
|
|
|
|
|
|
|
|
/* Only version 4 supports high-speed */
|
|
|
|
if (mci->version < MMC_VERSION_4)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
mci->card_caps |= MMC_MODE_4BIT;
|
|
|
|
|
|
|
|
err = mci_send_ext_csd(mci_dev, ext_csd);
|
|
|
|
if (err) {
|
|
|
|
pr_debug("Preparing for frequency setup failed: %d\n", err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ext_csd[212] || ext_csd[213] || ext_csd[214] || ext_csd[215])
|
|
|
|
mci->high_capacity = 1;
|
|
|
|
|
|
|
|
cardtype = ext_csd[196] & 0xf;
|
|
|
|
|
|
|
|
err = mci_switch(mci_dev, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
pr_debug("MMC frequency changing failed: %d\n", err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now check to see that it worked */
|
|
|
|
err = mci_send_ext_csd(mci_dev, ext_csd);
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
pr_debug("Verifying frequency change failed: %d\n", err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No high-speed support */
|
|
|
|
if (!ext_csd[185])
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* High Speed is set, there are two types: 52MHz and 26MHz */
|
|
|
|
if (cardtype & MMC_HS_52MHZ)
|
|
|
|
mci->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
|
|
|
|
else
|
|
|
|
mci->card_caps |= MMC_MODE_HS;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* FIXME
|
|
|
|
* @param mci_dev MCI instance
|
|
|
|
* @param mode FIXME
|
|
|
|
* @param group FIXME
|
|
|
|
* @param value FIXME
|
|
|
|
* @param resp FIXME
|
|
|
|
* @return Transaction status (0 on success)
|
|
|
|
*/
|
|
|
|
static int sd_switch(struct device_d *mci_dev, unsigned mode, unsigned group,
|
|
|
|
unsigned value, uint8_t *resp)
|
|
|
|
{
|
|
|
|
struct mci_cmd cmd;
|
|
|
|
struct mci_data data;
|
|
|
|
unsigned arg;
|
|
|
|
|
|
|
|
arg = (mode << 31) | 0xffffff;
|
|
|
|
arg &= ~(0xf << (group << 2));
|
|
|
|
arg |= value << (group << 2);
|
|
|
|
|
|
|
|
/* Switch the frequency */
|
|
|
|
mci_setup_cmd(&cmd, SD_CMD_SWITCH_FUNC, arg, MMC_RSP_R1);
|
|
|
|
|
|
|
|
data.dest = resp;
|
|
|
|
data.blocksize = 64;
|
|
|
|
data.blocks = 1;
|
|
|
|
data.flags = MMC_DATA_READ;
|
|
|
|
|
|
|
|
return mci_send_cmd(mci_dev, &cmd, &data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Change transfer frequency for an SD card
|
|
|
|
* @param mci_dev MCI instance
|
|
|
|
* @return Transaction status (0 on success)
|
|
|
|
*/
|
|
|
|
static int sd_change_freq(struct device_d *mci_dev)
|
|
|
|
{
|
|
|
|
struct mci *mci = GET_MCI_DATA(mci_dev);
|
|
|
|
struct mci_cmd cmd;
|
|
|
|
struct mci_data data;
|
2011-11-24 20:46:33 +00:00
|
|
|
#ifdef CONFIG_MCI_SPI
|
|
|
|
struct mci_host *host = GET_MCI_PDATA(mci_dev);
|
|
|
|
#endif
|
2010-10-22 10:21:25 +00:00
|
|
|
uint32_t *switch_status = sector_buf;
|
|
|
|
uint32_t *scr = sector_buf;
|
2010-10-08 16:30:53 +00:00
|
|
|
int timeout;
|
|
|
|
int err;
|
|
|
|
|
2011-11-24 20:46:33 +00:00
|
|
|
if (mmc_host_is_spi(host))
|
|
|
|
return 0;
|
|
|
|
|
2010-10-08 16:30:53 +00:00
|
|
|
pr_debug("Changing transfer frequency\n");
|
|
|
|
mci->card_caps = 0;
|
|
|
|
|
|
|
|
/* Read the SCR to find out if this card supports higher speeds */
|
|
|
|
mci_setup_cmd(&cmd, MMC_CMD_APP_CMD, mci->rca << 16, MMC_RSP_R1);
|
|
|
|
err = mci_send_cmd(mci_dev, &cmd, NULL);
|
|
|
|
if (err) {
|
|
|
|
pr_debug("Query SD card capabilities failed: %d\n", err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
mci_setup_cmd(&cmd, SD_CMD_APP_SEND_SCR, 0, MMC_RSP_R1);
|
|
|
|
|
|
|
|
timeout = 3;
|
|
|
|
|
|
|
|
retry_scr:
|
|
|
|
pr_debug("Trying to read the SCR (try %d of %d)\n", 4 - timeout, 3);
|
2010-10-22 10:21:25 +00:00
|
|
|
data.dest = (char *)scr;
|
2010-10-08 16:30:53 +00:00
|
|
|
data.blocksize = 8;
|
|
|
|
data.blocks = 1;
|
|
|
|
data.flags = MMC_DATA_READ;
|
|
|
|
|
|
|
|
err = mci_send_cmd(mci_dev, &cmd, &data);
|
|
|
|
if (err) {
|
|
|
|
pr_debug(" Catch error (%d)", err);
|
|
|
|
if (timeout--) {
|
|
|
|
pr_debug("-- retrying\n");
|
|
|
|
goto retry_scr;
|
|
|
|
}
|
|
|
|
pr_debug("-- giving up\n");
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
mci->scr[0] = __be32_to_cpu(scr[0]);
|
|
|
|
mci->scr[1] = __be32_to_cpu(scr[1]);
|
|
|
|
|
|
|
|
switch ((mci->scr[0] >> 24) & 0xf) {
|
|
|
|
case 0:
|
|
|
|
mci->version = SD_VERSION_1_0;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
mci->version = SD_VERSION_1_10;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
mci->version = SD_VERSION_2;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
mci->version = SD_VERSION_1_0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Version 1.0 doesn't support switching */
|
|
|
|
if (mci->version == SD_VERSION_1_0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
timeout = 4;
|
|
|
|
while (timeout--) {
|
|
|
|
err = sd_switch(mci_dev, SD_SWITCH_CHECK, 0, 1,
|
2010-10-22 10:21:25 +00:00
|
|
|
(uint8_t*)switch_status);
|
2010-10-08 16:30:53 +00:00
|
|
|
if (err) {
|
|
|
|
pr_debug("Checking SD transfer switch frequency feature failed: %d\n", err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The high-speed function is busy. Try again */
|
|
|
|
if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mci->scr[0] & SD_DATA_4BIT)
|
|
|
|
mci->card_caps |= MMC_MODE_4BIT;
|
|
|
|
|
|
|
|
/* If high-speed isn't supported, we return */
|
|
|
|
if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
|
|
|
|
return 0;
|
|
|
|
|
2010-10-22 10:21:25 +00:00
|
|
|
err = sd_switch(mci_dev, SD_SWITCH_SWITCH, 0, 1, (uint8_t*)switch_status);
|
2010-10-08 16:30:53 +00:00
|
|
|
if (err) {
|
|
|
|
pr_debug("Switching SD transfer frequency failed: %d\n", err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
|
|
|
|
mci->card_caps |= MMC_MODE_HS;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Setup host's interface bus width and transfer frequency
|
|
|
|
* @param mci_dev MCI instance
|
|
|
|
*/
|
|
|
|
static void mci_set_ios(struct device_d *mci_dev)
|
|
|
|
{
|
|
|
|
struct mci_host *host = GET_MCI_PDATA(mci_dev);
|
|
|
|
|
|
|
|
host->set_ios(host, mci_dev, host->bus_width, host->clock);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Setup host's interface transfer frequency
|
|
|
|
* @param mci_dev MCI instance
|
|
|
|
* @param clock New clock in Hz to set
|
|
|
|
*/
|
|
|
|
static void mci_set_clock(struct device_d *mci_dev, unsigned clock)
|
|
|
|
{
|
|
|
|
struct mci_host *host = GET_MCI_PDATA(mci_dev);
|
|
|
|
|
|
|
|
/* check against any given limits */
|
|
|
|
if (clock > host->f_max)
|
|
|
|
clock = host->f_max;
|
|
|
|
|
|
|
|
if (clock < host->f_min)
|
|
|
|
clock = host->f_min;
|
|
|
|
|
|
|
|
host->clock = clock; /* the new target frequency */
|
|
|
|
mci_set_ios(mci_dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Setup host's interface bus width
|
|
|
|
* @param mci_dev MCI instance
|
|
|
|
* @param width New interface bit width (1, 4 or 8)
|
|
|
|
*/
|
|
|
|
static void mci_set_bus_width(struct device_d *mci_dev, unsigned width)
|
|
|
|
{
|
|
|
|
struct mci_host *host = GET_MCI_PDATA(mci_dev);
|
|
|
|
|
|
|
|
host->bus_width = width; /* the new target bus width */
|
|
|
|
mci_set_ios(mci_dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Extract card's version from its CSD
|
|
|
|
* @param mci_dev MCI instance
|
|
|
|
* @return 0 on success
|
|
|
|
*/
|
|
|
|
static void mci_detect_version_from_csd(struct device_d *mci_dev)
|
|
|
|
{
|
|
|
|
struct mci *mci = GET_MCI_DATA(mci_dev);
|
|
|
|
int version;
|
2011-04-11 12:02:01 +00:00
|
|
|
char *vstr;
|
2010-10-08 16:30:53 +00:00
|
|
|
|
|
|
|
if (mci->version == MMC_VERSION_UNKNOWN) {
|
|
|
|
/* the version is coded in the bits 127:126 (left aligned) */
|
|
|
|
version = (mci->csd[0] >> 26) & 0xf; /* FIXME why other width? */
|
|
|
|
|
|
|
|
switch (version) {
|
|
|
|
case 0:
|
2011-04-11 12:02:01 +00:00
|
|
|
vstr = "1.2";
|
2010-10-08 16:30:53 +00:00
|
|
|
mci->version = MMC_VERSION_1_2;
|
|
|
|
break;
|
|
|
|
case 1:
|
2011-04-11 12:02:01 +00:00
|
|
|
vstr = "1.4";
|
2010-10-08 16:30:53 +00:00
|
|
|
mci->version = MMC_VERSION_1_4;
|
|
|
|
break;
|
|
|
|
case 2:
|
2011-04-11 12:02:01 +00:00
|
|
|
vstr = "2.2";
|
2010-10-08 16:30:53 +00:00
|
|
|
mci->version = MMC_VERSION_2_2;
|
|
|
|
break;
|
|
|
|
case 3:
|
2011-04-11 12:02:01 +00:00
|
|
|
vstr = "3.0";
|
2010-10-08 16:30:53 +00:00
|
|
|
mci->version = MMC_VERSION_3;
|
|
|
|
break;
|
|
|
|
case 4:
|
2011-04-11 12:02:01 +00:00
|
|
|
vstr = "4.0";
|
2010-10-08 16:30:53 +00:00
|
|
|
mci->version = MMC_VERSION_4;
|
|
|
|
break;
|
|
|
|
default:
|
2011-04-11 12:02:01 +00:00
|
|
|
vstr = "unknown, fallback to 1.2";
|
2010-10-08 16:30:53 +00:00
|
|
|
mci->version = MMC_VERSION_1_2;
|
|
|
|
break;
|
|
|
|
}
|
2011-04-11 12:02:01 +00:00
|
|
|
printf("detected card version %s\n", vstr);
|
2010-10-08 16:30:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* meaning of the encoded 'unit' bits in the CSD's field 'TRAN_SPEED'
|
|
|
|
* (divided by 10 to be nice to platforms without floating point)
|
|
|
|
*/
|
|
|
|
static const unsigned tran_speed_unit[] = {
|
|
|
|
[0] = 10000, /* 100 kbit/s */
|
|
|
|
[1] = 100000, /* 1 Mbit/s */
|
|
|
|
[2] = 1000000, /* 10 Mbit/s */
|
|
|
|
[3] = 10000000, /* 100 Mbit/s */
|
|
|
|
/* [4]...[7] are reserved */
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* meaning of the 'time' bits in the CSD's field 'TRAN_SPEED'
|
|
|
|
* (multiplied by 10 to be nice to platforms without floating point)
|
|
|
|
*/
|
|
|
|
static const unsigned char tran_speed_time[] = {
|
|
|
|
0, /* reserved */
|
|
|
|
10, /* 1.0 ns */
|
|
|
|
12, /* 1.2 ns */
|
|
|
|
13,
|
|
|
|
15,
|
|
|
|
20,
|
|
|
|
25,
|
|
|
|
30,
|
|
|
|
35,
|
|
|
|
40,
|
|
|
|
45,
|
|
|
|
50,
|
|
|
|
55,
|
|
|
|
60,
|
|
|
|
70, /* 7.0 ns */
|
|
|
|
80, /* 8.0 ns */
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Extract max. transfer speed from the CSD
|
|
|
|
* @param mci_dev MCI instance
|
|
|
|
*
|
|
|
|
* Encoded in bit 103:96 (103: reserved, 102:99: time, 98:96 unit)
|
|
|
|
*/
|
|
|
|
static void mci_extract_max_tran_speed_from_csd(struct device_d *mci_dev)
|
|
|
|
{
|
|
|
|
struct mci *mci = GET_MCI_DATA(mci_dev);
|
|
|
|
unsigned unit, time;
|
|
|
|
|
|
|
|
unit = tran_speed_unit[(mci->csd[0] & 0x7)];
|
|
|
|
time = tran_speed_time[((mci->csd[0] >> 3) & 0xf)];
|
|
|
|
if ((unit == 0) || (time == 0)) {
|
2011-04-11 12:02:37 +00:00
|
|
|
pr_debug("Unsupported 'TRAN_SPEED' unit/time value."
|
2010-10-08 16:30:53 +00:00
|
|
|
" Can't calculate card's max. transfer speed\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mci->tran_speed = time * unit;
|
|
|
|
pr_debug("Transfer speed: %u\n", mci->tran_speed);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Extract max read and write block length from the CSD
|
|
|
|
* @param mci_dev MCI instance
|
|
|
|
*
|
|
|
|
* Encoded in bit 83:80 (read) and 25:22 (write)
|
|
|
|
*/
|
|
|
|
static void mci_extract_block_lengths_from_csd(struct device_d *mci_dev)
|
|
|
|
{
|
|
|
|
struct mci *mci = GET_MCI_DATA(mci_dev);
|
|
|
|
|
|
|
|
mci->read_bl_len = 1 << ((mci->csd[1] >> 16) & 0xf);
|
|
|
|
|
|
|
|
if (IS_SD(mci))
|
|
|
|
mci->write_bl_len = mci->read_bl_len; /* FIXME why? */
|
|
|
|
else
|
|
|
|
mci->write_bl_len = 1 << ((mci->csd[3] >> 22) & 0xf);
|
|
|
|
|
|
|
|
pr_debug("Max. block length are: Write=%u, Read=%u Bytes\n",
|
|
|
|
mci->read_bl_len, mci->write_bl_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Extract card's capacitiy from the CSD
|
|
|
|
* @param mci_dev MCI instance
|
|
|
|
*/
|
|
|
|
static void mci_extract_card_capacity_from_csd(struct device_d *mci_dev)
|
|
|
|
{
|
|
|
|
struct mci *mci = GET_MCI_DATA(mci_dev);
|
|
|
|
uint64_t csize, cmult;
|
|
|
|
|
|
|
|
if (mci->high_capacity) {
|
|
|
|
csize = (mci->csd[1] & 0x3f) << 16 | (mci->csd[2] & 0xffff0000) >> 16;
|
|
|
|
cmult = 8;
|
|
|
|
} else {
|
|
|
|
csize = (mci->csd[1] & 0x3ff) << 2 | (mci->csd[2] & 0xc0000000) >> 30;
|
|
|
|
cmult = (mci->csd[2] & 0x00038000) >> 15;
|
|
|
|
}
|
|
|
|
|
|
|
|
mci->capacity = (csize + 1) << (cmult + 2);
|
|
|
|
mci->capacity *= mci->read_bl_len;
|
|
|
|
pr_debug("Capacity: %u MiB\n", (unsigned)mci->capacity >> 20);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Scan the given host interfaces and detect connected MMC/SD cards
|
|
|
|
* @param mci_dev MCI instance
|
|
|
|
* @return 0 on success, negative value else
|
|
|
|
*/
|
|
|
|
static int mci_startup(struct device_d *mci_dev)
|
|
|
|
{
|
|
|
|
struct mci *mci = GET_MCI_DATA(mci_dev);
|
|
|
|
struct mci_host *host = GET_MCI_PDATA(mci_dev);
|
|
|
|
struct mci_cmd cmd;
|
|
|
|
int err;
|
|
|
|
|
2011-11-24 20:46:33 +00:00
|
|
|
#ifdef CONFIG_MMC_SPI_CRC_ON
|
|
|
|
if (mmc_host_is_spi(host)) { /* enable CRC check for spi */
|
|
|
|
|
|
|
|
mci_setup_cmd(&cmd, MMC_CMD_SPI_CRC_ON_OFF, 1, MMC_RSP_R1);
|
|
|
|
err = mci_send_cmd(mci_dev, &cmd, NULL);
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
pr_debug("Can't enable CRC check : %d\n", err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-10-08 16:30:53 +00:00
|
|
|
pr_debug("Put the Card in Identify Mode\n");
|
|
|
|
|
|
|
|
/* Put the Card in Identify Mode */
|
2011-11-24 20:46:33 +00:00
|
|
|
mci_setup_cmd(&cmd, mmc_host_is_spi(host) ? MMC_CMD_SEND_CID : MMC_CMD_ALL_SEND_CID, 0, MMC_RSP_R2);
|
2010-10-08 16:30:53 +00:00
|
|
|
err = mci_send_cmd(mci_dev, &cmd, NULL);
|
|
|
|
if (err) {
|
|
|
|
pr_debug("Can't bring card into identify mode: %d\n", err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(mci->cid, cmd.response, 16);
|
|
|
|
|
|
|
|
pr_debug("Card's identification data is: %08X-%08X-%08X-%08X\n",
|
|
|
|
mci->cid[0], mci->cid[1], mci->cid[2], mci->cid[3]);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For MMC cards, set the Relative Address.
|
|
|
|
* For SD cards, get the Relatvie Address.
|
|
|
|
* This also puts the cards into Standby State
|
|
|
|
*/
|
2011-11-24 20:46:33 +00:00
|
|
|
if (!mmc_host_is_spi(host)) { /* cmd not supported in spi */
|
|
|
|
pr_debug("Get/Set relative address\n");
|
|
|
|
mci_setup_cmd(&cmd, SD_CMD_SEND_RELATIVE_ADDR, mci->rca << 16, MMC_RSP_R6);
|
|
|
|
err = mci_send_cmd(mci_dev, &cmd, NULL);
|
|
|
|
if (err) {
|
|
|
|
pr_debug("Get/Set relative address failed: %d\n", err);
|
|
|
|
return err;
|
|
|
|
}
|
2010-10-08 16:30:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_SD(mci))
|
|
|
|
mci->rca = (cmd.response[0] >> 16) & 0xffff;
|
|
|
|
|
|
|
|
pr_debug("Get card's specific data\n");
|
|
|
|
/* Get the Card-Specific Data */
|
|
|
|
mci_setup_cmd(&cmd, MMC_CMD_SEND_CSD, mci->rca << 16, MMC_RSP_R2);
|
|
|
|
err = mci_send_cmd(mci_dev, &cmd, NULL);
|
|
|
|
if (err) {
|
|
|
|
pr_debug("Getting card's specific data failed: %d\n", err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* CSD is of 128 bit */
|
|
|
|
memcpy(mci->csd, cmd.response, 16);
|
|
|
|
|
|
|
|
pr_debug("Card's specific data is: %08X-%08X-%08X-%08X\n",
|
|
|
|
mci->csd[0], mci->csd[1], mci->csd[2], mci->csd[3]);
|
|
|
|
|
|
|
|
mci_detect_version_from_csd(mci_dev);
|
|
|
|
mci_extract_max_tran_speed_from_csd(mci_dev);
|
|
|
|
mci_extract_block_lengths_from_csd(mci_dev);
|
|
|
|
mci_extract_card_capacity_from_csd(mci_dev);
|
|
|
|
|
|
|
|
/* sanitiy? */
|
2011-11-24 12:43:47 +00:00
|
|
|
if (mci->read_bl_len > SECTOR_SIZE) {
|
|
|
|
mci->read_bl_len = SECTOR_SIZE;
|
2011-04-11 12:02:37 +00:00
|
|
|
pr_debug("Limiting max. read block size down to %u\n",
|
2010-10-08 16:30:53 +00:00
|
|
|
mci->read_bl_len);
|
|
|
|
}
|
|
|
|
|
2011-11-24 12:43:47 +00:00
|
|
|
if (mci->write_bl_len > SECTOR_SIZE) {
|
|
|
|
mci->write_bl_len = SECTOR_SIZE;
|
2011-04-11 12:02:37 +00:00
|
|
|
pr_debug("Limiting max. write block size down to %u\n",
|
2010-10-08 16:30:53 +00:00
|
|
|
mci->read_bl_len);
|
|
|
|
}
|
|
|
|
pr_debug("Read block length: %u, Write block length: %u\n",
|
|
|
|
mci->read_bl_len, mci->write_bl_len);
|
|
|
|
|
2011-11-24 20:46:33 +00:00
|
|
|
if (!mmc_host_is_spi(host)) { /* cmd not supported in spi */
|
|
|
|
pr_debug("Select the card, and put it into Transfer Mode\n");
|
|
|
|
/* Select the card, and put it into Transfer Mode */
|
|
|
|
mci_setup_cmd(&cmd, MMC_CMD_SELECT_CARD, mci->rca << 16, MMC_RSP_R1b);
|
|
|
|
err = mci_send_cmd(mci_dev, &cmd, NULL);
|
|
|
|
if (err) {
|
|
|
|
pr_debug("Putting in transfer mode failed: %d\n", err);
|
|
|
|
return err;
|
|
|
|
}
|
2010-10-08 16:30:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_SD(mci))
|
|
|
|
err = sd_change_freq(mci_dev);
|
|
|
|
else
|
|
|
|
err = mmc_change_freq(mci_dev);
|
|
|
|
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
/* Restrict card's capabilities by what the host can do */
|
|
|
|
mci->card_caps &= host->host_caps;
|
|
|
|
|
|
|
|
if (IS_SD(mci)) {
|
|
|
|
if (mci->card_caps & MMC_MODE_4BIT) {
|
|
|
|
pr_debug("Prepare for bus width change\n");
|
|
|
|
mci_setup_cmd(&cmd, MMC_CMD_APP_CMD, mci->rca << 16, MMC_RSP_R1);
|
|
|
|
err = mci_send_cmd(mci_dev, &cmd, NULL);
|
|
|
|
if (err) {
|
|
|
|
pr_debug("Preparing SD for bus width change failed: %d\n", err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_debug("Set SD bus width to 4 bit\n");
|
|
|
|
mci_setup_cmd(&cmd, SD_CMD_APP_SET_BUS_WIDTH, 2, MMC_RSP_R1);
|
|
|
|
err = mci_send_cmd(mci_dev, &cmd, NULL);
|
|
|
|
if (err) {
|
|
|
|
pr_debug("Changing SD bus width failed: %d\n", err);
|
|
|
|
/* TODO continue with 1 bit? */
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
mci_set_bus_width(mci_dev, 4);
|
|
|
|
}
|
|
|
|
/* if possible, speed up the transfer */
|
|
|
|
if (mci->card_caps & MMC_MODE_HS)
|
|
|
|
mci_set_clock(mci_dev, 50000000);
|
|
|
|
else
|
|
|
|
mci_set_clock(mci_dev, 25000000);
|
|
|
|
} else {
|
|
|
|
if (mci->card_caps & MMC_MODE_4BIT) {
|
|
|
|
pr_debug("Set MMC bus width to 4 bit\n");
|
|
|
|
/* Set the card to use 4 bit*/
|
|
|
|
err = mci_switch(mci_dev, EXT_CSD_CMD_SET_NORMAL,
|
|
|
|
EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_4);
|
|
|
|
if (err) {
|
|
|
|
pr_debug("Changing MMC bus width failed: %d\n", err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
mci_set_bus_width(mci_dev, 4);
|
|
|
|
} else if (mci->card_caps & MMC_MODE_8BIT) {
|
|
|
|
pr_debug("Set MMC bus width to 8 bit\n");
|
|
|
|
/* Set the card to use 8 bit*/
|
|
|
|
err = mci_switch(mci_dev, EXT_CSD_CMD_SET_NORMAL,
|
|
|
|
EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_8);
|
|
|
|
if (err) {
|
|
|
|
pr_debug("Changing MMC bus width failed: %d\n", err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
mci_set_bus_width(mci_dev, 8);
|
|
|
|
}
|
|
|
|
/* if possible, speed up the transfer */
|
|
|
|
if (mci->card_caps & MMC_MODE_HS) {
|
|
|
|
if (mci->card_caps & MMC_MODE_HS_52MHz)
|
|
|
|
mci_set_clock(mci_dev, 52000000);
|
|
|
|
else
|
|
|
|
mci_set_clock(mci_dev, 26000000);
|
|
|
|
} else
|
|
|
|
mci_set_clock(mci_dev, 20000000);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we setup the blocklength only one times for all accesses to this media */
|
|
|
|
err = mci_set_blocklen(mci_dev, mci->read_bl_len);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Detect a SD 2.0 card and enable its features
|
|
|
|
* @param mci_dev MCI instance
|
|
|
|
* @return Transfer status (0 on success)
|
|
|
|
*
|
|
|
|
* By issuing the CMD8 command SDHC/SDXC cards realize that the host supports
|
|
|
|
* the Physical Layer Version 2.00 or later and the card can enable
|
|
|
|
* corresponding new functions.
|
|
|
|
*
|
|
|
|
* If this CMD8 command will end with a timeout it is a MultiMediaCard only.
|
|
|
|
*/
|
|
|
|
static int sd_send_if_cond(struct device_d *mci_dev)
|
|
|
|
{
|
|
|
|
struct mci *mci = GET_MCI_DATA(mci_dev);
|
|
|
|
struct mci_host *host = GET_MCI_PDATA(mci_dev);
|
|
|
|
struct mci_cmd cmd;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
mci_setup_cmd(&cmd, SD_CMD_SEND_IF_COND,
|
|
|
|
/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
|
|
|
|
((host->voltages & 0x00ff8000) != 0) << 8 | 0xaa,
|
|
|
|
MMC_RSP_R7);
|
|
|
|
err = mci_send_cmd(mci_dev, &cmd, NULL);
|
|
|
|
if (err) {
|
|
|
|
pr_debug("Query interface conditions failed: %d\n", err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((cmd.response[0] & 0xff) != 0xaa) {
|
|
|
|
pr_debug("Card cannot work with hosts supply voltages\n");
|
|
|
|
return -EINVAL;
|
|
|
|
} else {
|
|
|
|
pr_debug("SD Card Rev. 2.00 or later detected\n");
|
|
|
|
mci->version = SD_VERSION_2;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-11-24 12:43:47 +00:00
|
|
|
/* ------------------ attach to the blocklayer --------------------------- */
|
2010-10-08 16:30:53 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Write a chunk of sectors to media
|
2011-11-24 12:43:47 +00:00
|
|
|
* @param blk All info about the block device we need
|
2010-10-08 16:30:53 +00:00
|
|
|
* @param buffer Buffer to write from
|
2011-11-24 12:43:47 +00:00
|
|
|
* @param block Sector's number to start write to
|
|
|
|
* @param num_blocks Sector count to write
|
2010-10-08 16:30:53 +00:00
|
|
|
* @return 0 on success, anything else on failure
|
|
|
|
*
|
|
|
|
* This routine expects the buffer has the correct size to read all data!
|
|
|
|
*/
|
2011-11-24 12:43:47 +00:00
|
|
|
static int __maybe_unused mci_sd_write(struct block_device *blk,
|
|
|
|
const void *buffer, int block, int num_blocks)
|
2010-10-08 16:30:53 +00:00
|
|
|
{
|
2011-11-24 12:43:47 +00:00
|
|
|
struct device_d *mci_dev = blk->dev;
|
2010-10-08 16:30:53 +00:00
|
|
|
struct mci *mci = GET_MCI_DATA(mci_dev);
|
|
|
|
int rc;
|
|
|
|
|
2011-11-24 12:43:47 +00:00
|
|
|
pr_debug("%s: Write %d block(s), starting at %d\n",
|
|
|
|
__func__, num_blocks, block);
|
2010-10-08 16:30:53 +00:00
|
|
|
|
2011-11-24 12:43:47 +00:00
|
|
|
if (mci->write_bl_len != SECTOR_SIZE) {
|
|
|
|
pr_debug("MMC/SD block size is not %d bytes (its %u bytes instead)\n",
|
|
|
|
SECTOR_SIZE, mci->read_bl_len);
|
2010-10-08 16:30:53 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2011-10-28 12:44:09 +00:00
|
|
|
/* size of the block number field in the MMC/SD command is 32 bit only */
|
2011-11-24 12:43:47 +00:00
|
|
|
if (block > MAX_BUFFER_NUMBER) {
|
|
|
|
pr_debug("Cannot handle block number %d. Too large!\n", block);
|
2011-10-28 12:44:09 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2011-11-24 12:43:47 +00:00
|
|
|
rc = mci_block_write(mci_dev, buffer, block, num_blocks);
|
2011-10-28 12:44:09 +00:00
|
|
|
if (rc != 0) {
|
2011-11-24 12:43:47 +00:00
|
|
|
pr_debug("Writing block %d failed with %d\n", block, rc);
|
2011-10-28 12:44:09 +00:00
|
|
|
return rc;
|
2010-10-08 16:30:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-11-24 12:43:47 +00:00
|
|
|
* Read a chunk of sectors from the drive
|
|
|
|
* @param blk All info about the block device we need
|
2010-10-08 16:30:53 +00:00
|
|
|
* @param buffer Buffer to read into
|
2011-11-24 12:43:47 +00:00
|
|
|
* @param block Sector's LBA number to start read from
|
|
|
|
* @param num_blocks Sector count to read
|
2010-10-08 16:30:53 +00:00
|
|
|
* @return 0 on success, anything else on failure
|
|
|
|
*
|
|
|
|
* This routine expects the buffer has the correct size to store all data!
|
|
|
|
*/
|
2011-11-24 12:43:47 +00:00
|
|
|
static int mci_sd_read(struct block_device *blk, void *buffer, int block,
|
|
|
|
int num_blocks)
|
2010-10-08 16:30:53 +00:00
|
|
|
{
|
2011-11-24 12:43:47 +00:00
|
|
|
struct device_d *mci_dev = blk->dev;
|
2010-10-08 16:30:53 +00:00
|
|
|
struct mci *mci = GET_MCI_DATA(mci_dev);
|
|
|
|
int rc;
|
|
|
|
|
2011-11-24 12:43:47 +00:00
|
|
|
pr_debug("%s: Read %d block(s), starting at %d\n",
|
|
|
|
__func__, num_blocks, block);
|
2010-10-08 16:30:53 +00:00
|
|
|
|
|
|
|
if (mci->read_bl_len != 512) {
|
2011-04-11 12:02:37 +00:00
|
|
|
pr_debug("MMC/SD block size is not 512 bytes (its %u bytes instead)\n",
|
2010-10-08 16:30:53 +00:00
|
|
|
mci->read_bl_len);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2011-11-24 12:43:47 +00:00
|
|
|
if (block > MAX_BUFFER_NUMBER) {
|
|
|
|
pr_err("Cannot handle block number %d. Too large!\n", block);
|
2011-10-28 12:44:09 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2011-11-24 12:43:47 +00:00
|
|
|
rc = mci_read_block(mci_dev, buffer, block, num_blocks);
|
2011-10-28 12:44:09 +00:00
|
|
|
if (rc != 0) {
|
2011-11-24 12:43:47 +00:00
|
|
|
pr_debug("Reading block %d failed with %d\n", block, rc);
|
2011-10-28 12:44:09 +00:00
|
|
|
return rc;
|
2010-10-08 16:30:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------ attach to the device API --------------------------- */
|
|
|
|
|
|
|
|
#ifdef CONFIG_MCI_INFO
|
|
|
|
/**
|
|
|
|
* Extract the Manufacturer ID from the CID
|
|
|
|
* @param mci Instance data
|
|
|
|
*
|
|
|
|
* The 'MID' is encoded in bit 127:120 in the CID
|
|
|
|
*/
|
|
|
|
static unsigned extract_mid(struct mci *mci)
|
|
|
|
{
|
|
|
|
return mci->cid[0] >> 24;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Extract the OEM/Application ID from the CID
|
|
|
|
* @param mci Instance data
|
|
|
|
*
|
|
|
|
* The 'OID' is encoded in bit 119:104 in the CID
|
|
|
|
*/
|
|
|
|
static unsigned extract_oid(struct mci *mci)
|
|
|
|
{
|
|
|
|
return (mci->cid[0] >> 8) & 0xffff;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Extract the product revision from the CID
|
|
|
|
* @param mci Instance data
|
|
|
|
*
|
|
|
|
* The 'PRV' is encoded in bit 63:56 in the CID
|
|
|
|
*/
|
|
|
|
static unsigned extract_prv(struct mci *mci)
|
|
|
|
{
|
|
|
|
return mci->cid[2] >> 24;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Extract the product serial number from the CID
|
|
|
|
* @param mci Instance data
|
|
|
|
*
|
|
|
|
* The 'PSN' is encoded in bit 55:24 in the CID
|
|
|
|
*/
|
|
|
|
static unsigned extract_psn(struct mci *mci)
|
|
|
|
{
|
|
|
|
return (mci->cid[2] << 8) | (mci->cid[3] >> 24);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Extract the month of the manufacturing date from the CID
|
|
|
|
* @param mci Instance data
|
|
|
|
*
|
|
|
|
* The 'MTD' is encoded in bit 19:8 in the CID, month in 11:8
|
|
|
|
*/
|
|
|
|
static unsigned extract_mtd_month(struct mci *mci)
|
|
|
|
{
|
|
|
|
return (mci->cid[3] >> 8) & 0xf;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Extract the year of the manufacturing date from the CID
|
|
|
|
* @param mci Instance data
|
|
|
|
*
|
|
|
|
* The 'MTD' is encoded in bit 19:8 in the CID, year in 19:12
|
|
|
|
* An encoded 0 means the year 2000
|
|
|
|
*/
|
|
|
|
static unsigned extract_mtd_year(struct mci *mci)
|
|
|
|
{
|
|
|
|
return ((mci->cid[3] >> 12) & 0xff) + 2000U;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Output some valuable information when the user runs 'devinfo' on an MCI device
|
|
|
|
* @param mci_dev MCI device instance
|
|
|
|
*/
|
|
|
|
static void mci_info(struct device_d *mci_dev)
|
|
|
|
{
|
|
|
|
struct mci *mci = GET_MCI_DATA(mci_dev);
|
|
|
|
|
|
|
|
if (mci->ready_for_use == 0) {
|
|
|
|
printf(" No information available:\n MCI card not probed yet\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf(" Card:\n");
|
|
|
|
if (mci->version < SD_VERSION_SD) {
|
|
|
|
printf(" Attached is a MultiMediaCard (Version: %u.%u)\n",
|
|
|
|
(mci->version >> 4) & 0xf, mci->version & 0xf);
|
|
|
|
} else {
|
|
|
|
printf(" Attached is an SD Card (Version: %u.%u)\n",
|
|
|
|
(mci->version >> 4) & 0xf, mci->version & 0xf);
|
|
|
|
}
|
|
|
|
printf(" Capacity: %u MiB\n", (unsigned)(mci->capacity >> 20));
|
|
|
|
|
|
|
|
if (mci->high_capacity)
|
|
|
|
printf(" High capacity card\n");
|
|
|
|
printf(" CID: %08X-%08X-%08X-%08X\n", mci->cid[0], mci->cid[1],
|
|
|
|
mci->cid[2], mci->cid[3]);
|
|
|
|
printf(" CSD: %08X-%08X-%08X-%08X\n", mci->csd[0], mci->csd[1],
|
|
|
|
mci->csd[2], mci->csd[3]);
|
|
|
|
printf(" Max. transfer speed: %u Hz\n", mci->tran_speed);
|
|
|
|
printf(" Manufacturer ID: %02X\n", extract_mid(mci));
|
|
|
|
printf(" OEM/Application ID: %04X\n", extract_oid(mci));
|
|
|
|
printf(" Product name: '%c%c%c%c%c'\n", mci->cid[0] & 0xff,
|
|
|
|
(mci->cid[1] >> 24), (mci->cid[1] >> 16) & 0xff,
|
|
|
|
(mci->cid[1] >> 8) & 0xff, mci->cid[1] & 0xff);
|
|
|
|
printf(" Product revision: %u.%u\n", extract_prv(mci) >> 4,
|
|
|
|
extract_prv(mci) & 0xf);
|
|
|
|
printf(" Serial no: %0u\n", extract_psn(mci));
|
|
|
|
printf(" Manufacturing date: %u.%u\n", extract_mtd_month(mci),
|
|
|
|
extract_mtd_year(mci));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if the MCI card is already probed
|
|
|
|
* @param mci_dev MCI device instance
|
|
|
|
* @return 0 when not probed yet, -EPERM if already probed
|
|
|
|
*
|
|
|
|
* @a barebox cannot really cope with hot plugging. So, probing an attached
|
|
|
|
* MCI card is a one time only job. If its already done, there is no way to
|
|
|
|
* return.
|
|
|
|
*/
|
|
|
|
static int mci_check_if_already_initialized(struct device_d *mci_dev)
|
|
|
|
{
|
|
|
|
struct mci *mci = GET_MCI_DATA(mci_dev);
|
|
|
|
|
|
|
|
if (mci->ready_for_use != 0)
|
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-11-24 12:43:47 +00:00
|
|
|
static int mci_calc_blk_cnt(uint64_t cap, unsigned shift)
|
|
|
|
{
|
|
|
|
unsigned ret = cap >> shift;
|
|
|
|
|
|
|
|
if (ret > 0x7fffffff) {
|
|
|
|
pr_warn("Limiting card size due to 31 bit contraints\n");
|
|
|
|
return 0x7fffffff;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (int)ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct block_device_ops mci_ops = {
|
|
|
|
.read = mci_sd_read,
|
|
|
|
#ifdef CONFIG_BLOCK_WRITE
|
|
|
|
.write = mci_sd_write,
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
2010-10-08 16:30:53 +00:00
|
|
|
/**
|
|
|
|
* Probe an MCI card at the given host interface
|
|
|
|
* @param mci_dev MCI device instance
|
|
|
|
* @return 0 on success, negative values else
|
|
|
|
*/
|
|
|
|
static int mci_card_probe(struct device_d *mci_dev)
|
|
|
|
{
|
|
|
|
struct mci *mci = GET_MCI_DATA(mci_dev);
|
|
|
|
struct mci_host *host = GET_MCI_PDATA(mci_dev);
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
/* start with a host interface reset */
|
|
|
|
rc = (host->init)(host, mci_dev);
|
|
|
|
if (rc) {
|
|
|
|
pr_err("Cannot reset the SD/MMC interface\n");
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
mci_set_bus_width(mci_dev, 1);
|
|
|
|
mci_set_clock(mci_dev, 1); /* set the lowest available clock */
|
|
|
|
|
|
|
|
/* reset the card */
|
|
|
|
rc = mci_go_idle(mci_dev);
|
|
|
|
if (rc) {
|
2011-10-10 20:07:33 +00:00
|
|
|
pr_warning("Cannot reset the SD/MMC card\n");
|
2010-10-08 16:30:53 +00:00
|
|
|
goto on_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if this card can handle the "SD Card Physical Layer Specification 2.0" */
|
|
|
|
rc = sd_send_if_cond(mci_dev);
|
2010-10-11 08:45:36 +00:00
|
|
|
rc = sd_send_op_cond(mci_dev);
|
|
|
|
if (rc && rc == -ETIMEDOUT) {
|
2010-10-08 16:30:53 +00:00
|
|
|
/* If the command timed out, we check for an MMC card */
|
2010-10-11 08:45:36 +00:00
|
|
|
pr_debug("Card seems to be a MultiMediaCard\n");
|
|
|
|
rc = mmc_send_op_cond(mci_dev);
|
2010-10-08 16:30:53 +00:00
|
|
|
}
|
|
|
|
|
2010-10-11 08:45:36 +00:00
|
|
|
if (rc)
|
|
|
|
goto on_error;
|
|
|
|
|
2010-10-08 16:30:53 +00:00
|
|
|
rc = mci_startup(mci_dev);
|
|
|
|
if (rc) {
|
2011-04-11 12:02:37 +00:00
|
|
|
pr_debug("Card's startup fails with %d\n", rc);
|
2010-10-08 16:30:53 +00:00
|
|
|
goto on_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_debug("Card is up and running now, registering as a disk\n");
|
|
|
|
mci->ready_for_use = 1; /* TODO now or later? */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* An MMC/SD card acts like an ordinary disk.
|
|
|
|
* So, re-use the disk driver to gain access to this media
|
|
|
|
*/
|
2011-11-24 12:43:47 +00:00
|
|
|
mci->blk.dev = mci_dev;
|
|
|
|
mci->blk.ops = &mci_ops;
|
2010-10-08 16:30:53 +00:00
|
|
|
|
2011-11-24 12:43:47 +00:00
|
|
|
rc = cdev_find_free_index("disk");
|
|
|
|
if (rc == -1)
|
|
|
|
pr_err("Cannot find a free number for the disk node\n");
|
|
|
|
|
|
|
|
mci->blk.cdev.name = asprintf("disk%d", rc);
|
|
|
|
mci->blk.blockbits = SECTOR_SHIFT;
|
|
|
|
mci->blk.num_blocks = mci_calc_blk_cnt(mci->capacity, mci->blk.blockbits);
|
|
|
|
|
|
|
|
rc = blockdevice_register(&mci->blk);
|
|
|
|
if (rc != 0) {
|
|
|
|
dev_err(mci_dev, "Failed to register MCI/SD blockdevice\n");
|
|
|
|
goto on_error;
|
|
|
|
}
|
2010-10-08 16:30:53 +00:00
|
|
|
|
2011-11-24 12:43:47 +00:00
|
|
|
/* create partitions on demand */
|
|
|
|
rc = parse_partition_table(&mci->blk);
|
|
|
|
if (rc != 0) {
|
|
|
|
dev_warn(mci_dev, "No partition table found\n");
|
|
|
|
rc = 0; /* it's not a failure */
|
|
|
|
}
|
2010-10-08 16:30:53 +00:00
|
|
|
|
|
|
|
pr_debug("SD Card successfully added\n");
|
|
|
|
|
|
|
|
on_error:
|
|
|
|
if (rc != 0) {
|
|
|
|
host->clock = 0; /* disable the MCI clock */
|
|
|
|
mci_set_ios(mci_dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Trigger probing of an attached MCI card
|
|
|
|
* @param mci_dev MCI device instance
|
|
|
|
* @param param FIXME
|
|
|
|
* @param val "0" does nothing, a "1" will probe for a MCI card
|
|
|
|
* @return 0 on success
|
|
|
|
*/
|
|
|
|
static int mci_set_probe(struct device_d *mci_dev, struct param_d *param,
|
|
|
|
const char *val)
|
|
|
|
{
|
|
|
|
int rc, probe;
|
|
|
|
|
|
|
|
rc = mci_check_if_already_initialized(mci_dev);
|
|
|
|
if (rc != 0)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
probe = simple_strtoul(val, NULL, 0);
|
|
|
|
if (probe != 0) {
|
|
|
|
rc = mci_card_probe(mci_dev);
|
|
|
|
if (rc != 0)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
return dev_param_set_generic(mci_dev, param, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add parameter to the MCI device on demand
|
|
|
|
* @param mci_dev MCI device instance
|
|
|
|
* @return 0 on success
|
|
|
|
*
|
|
|
|
* This parameter is only available (or usefull) if MCI card probing is delayed
|
|
|
|
*/
|
|
|
|
static int add_mci_parameter(struct device_d *mci_dev)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
/* provide a 'probing right now' parameter for the user */
|
|
|
|
rc = dev_add_param(mci_dev, "probe", mci_set_probe, NULL, 0);
|
|
|
|
if (rc != 0)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
return dev_set_param(mci_dev, "probe", "0");
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Prepare for MCI card's usage
|
|
|
|
* @param mci_dev MCI device instance
|
|
|
|
* @return 0 on success
|
|
|
|
*
|
|
|
|
* This routine will probe an attached MCI card immediately or provide
|
|
|
|
* a parameter to do it later on user's demand.
|
|
|
|
*/
|
|
|
|
static int mci_probe(struct device_d *mci_dev)
|
|
|
|
{
|
|
|
|
struct mci *mci;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
mci = xzalloc(sizeof(struct mci));
|
|
|
|
mci_dev->priv = mci;
|
|
|
|
|
|
|
|
#ifdef CONFIG_MCI_STARTUP
|
|
|
|
/* if enabled, probe the attached card immediately */
|
|
|
|
rc = mci_card_probe(mci_dev);
|
|
|
|
if (rc == -ENODEV) {
|
|
|
|
/*
|
|
|
|
* If it fails, add the 'probe' parameter to give the user
|
|
|
|
* a chance to insert a card and try again. Note: This may fail
|
|
|
|
* systems that rely on the MCI card for startup (for the
|
|
|
|
* persistant environment for example)
|
|
|
|
*/
|
|
|
|
rc = add_mci_parameter(mci_dev);
|
|
|
|
if (rc != 0) {
|
2011-04-11 12:02:37 +00:00
|
|
|
pr_debug("Failed to add 'probe' parameter to the MCI device\n");
|
2010-10-08 16:30:53 +00:00
|
|
|
goto on_error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef CONFIG_MCI_STARTUP
|
|
|
|
/* add params on demand */
|
|
|
|
rc = add_mci_parameter(mci_dev);
|
|
|
|
if (rc != 0) {
|
2011-04-11 12:02:37 +00:00
|
|
|
pr_debug("Failed to add 'probe' parameter to the MCI device\n");
|
2010-10-08 16:30:53 +00:00
|
|
|
goto on_error;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
on_error:
|
|
|
|
free(mci);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct driver_d mci_driver = {
|
|
|
|
.name = "mci",
|
|
|
|
.probe = mci_probe,
|
2011-04-01 12:26:24 +00:00
|
|
|
#ifdef CONFIG_MCI_INFO
|
2010-10-08 16:30:53 +00:00
|
|
|
.info = mci_info,
|
2011-04-01 12:26:24 +00:00
|
|
|
#endif
|
2010-10-08 16:30:53 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static int mci_init(void)
|
|
|
|
{
|
2011-01-06 15:23:01 +00:00
|
|
|
sector_buf = xmemalign(32, 512);
|
2010-10-08 16:30:53 +00:00
|
|
|
return register_driver(&mci_driver);
|
|
|
|
}
|
|
|
|
|
|
|
|
device_initcall(mci_init);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a new mci device (for convenience)
|
2010-10-22 16:45:09 +00:00
|
|
|
* @param host mci_host for this MCI device
|
2010-10-08 16:30:53 +00:00
|
|
|
* @return 0 on success
|
|
|
|
*/
|
|
|
|
int mci_register(struct mci_host *host)
|
|
|
|
{
|
2011-11-24 12:43:47 +00:00
|
|
|
struct device_d *mci_dev = xzalloc(sizeof(struct device_d));
|
2010-10-08 16:30:53 +00:00
|
|
|
|
2011-11-24 12:43:47 +00:00
|
|
|
mci_dev->id = -1;
|
2010-10-08 16:30:53 +00:00
|
|
|
strcpy(mci_dev->name, mci_driver.name);
|
|
|
|
mci_dev->platform_data = (void*)host;
|
2011-08-15 07:44:04 +00:00
|
|
|
dev_add_child(host->hw_dev, mci_dev);
|
2010-10-08 16:30:53 +00:00
|
|
|
|
|
|
|
return register_device(mci_dev);
|
|
|
|
}
|