Operate SD card in 4-bit data mode

This commit is contained in:
Norman Feske 2012-07-19 20:14:25 +02:00
parent b37a28578c
commit eac9055c92
2 changed files with 73 additions and 21 deletions

View File

@ -326,7 +326,7 @@ struct Mmchs : Genode::Mmio
write<Stat>(~0);
}
enum Bus_width { BUS_WIDTH_1, BUS_WIDTH_8 };
enum Bus_width { BUS_WIDTH_1, BUS_WIDTH_4 };
void bus_width(Bus_width bus_width)
{
@ -336,8 +336,9 @@ struct Mmchs : Genode::Mmio
write<Hctl::Dtw>(Hctl::Dtw::ONE_BIT);
break;
case BUS_WIDTH_8:
write<Con::Dw8>(1);
case BUS_WIDTH_4:
write<Con::Dw8>(0);
write<Hctl::Dtw>(Hctl::Dtw::FOUR_BITS);
break;
}
}
@ -510,13 +511,30 @@ struct Omap4_hsmmc_controller : private Mmchs, public Sd_card::Host_controller
}
if (i == 0) {
PERR("Sd_send_op_cond timed out, could no power on SD card");
PERR("Sd_send_op_cond timed out, could no power-on SD card");
throw Detection_failed();
}
Card_info card_info = _detect();
write<Sysctl::Clkd>(0);
/*
* Switch card to use 4 data signals
*/
if (!issue_command(Set_bus_width(Set_bus_width::Arg::Bus_width::FOUR_BITS),
card_info.rca())) {
PWRN("Set_bus_width(FOUR_BITS) command failed");
throw Detection_failed();
}
bus_width(BUS_WIDTH_4);
_delayer.usleep(10*1000);
stop_clock();
if (!set_and_enable_clock(CLOCK_DIV_0, _delayer)) {
PERR("set_clock failed");
throw Detection_failed();
}
return card_info;
}
@ -555,16 +573,18 @@ struct Omap4_hsmmc_controller : private Mmchs, public Sd_card::Host_controller
/* assemble command register */
Cmd::access_t cmd = 0;
Cmd::Index::set(cmd, command.index);
if (command.index == Sd_card::Read_multiple_block::INDEX
|| command.index == Sd_card::Write_multiple_block::INDEX) {
if (command.transfer != Sd_card::TRANSFER_NONE) {
Cmd::Dp::set(cmd);
Cmd::Bce::set(cmd);
Cmd::Msbs::set(cmd);
Cmd::Acen::set(cmd);
if (command.index == Sd_card::Read_multiple_block::INDEX
|| command.index == Sd_card::Write_multiple_block::INDEX)
Cmd::Acen::set(cmd);
/* set data-direction bit depending on the command */
bool const read = command.index == Sd_card::Read_multiple_block::INDEX;
bool const read = command.transfer == Sd_card::TRANSFER_READ;
Cmd::Ddir::set(cmd, read ? Cmd::Ddir::READ : Cmd::Ddir::WRITE);
}

View File

@ -72,29 +72,32 @@ namespace Sd_card {
RESPONSE_48_BIT,
RESPONSE_48_BIT_WITH_BUSY };
enum Transfer { TRANSFER_NONE, TRANSFER_READ, TRANSFER_WRITE };
struct Command_base
{
unsigned index; /* command opcode */
Arg::access_t arg; /* argument */
Response rsp_type; /* response type */
Transfer transfer; /* data transfer type */
Command_base(unsigned op, Response rsp_type)
Command_base(unsigned op, Response rsp_type, Transfer transfer)
:
index(op), arg(0), rsp_type(rsp_type)
index(op), arg(0), rsp_type(rsp_type), transfer(transfer)
{ }
};
template <unsigned _INDEX, Response RSP_TYPE>
template <unsigned _INDEX, Response RSP_TYPE, Transfer TRANSFER = TRANSFER_NONE>
struct Command : Command_base
{
enum { INDEX = _INDEX };
Command() : Command_base(_INDEX, RSP_TYPE) { }
Command() : Command_base(_INDEX, RSP_TYPE, TRANSFER) { }
};
template <unsigned INDEX, Response RSP_TYPE>
template <unsigned INDEX, Response RSP_TYPE, Transfer TRANSFER = TRANSFER_NONE>
struct Prefixed_command : private Command_base
{
Prefixed_command() : Command_base(INDEX, RSP_TYPE) { }
Prefixed_command() : Command_base(INDEX, RSP_TYPE, TRANSFER) { }
using Command_base::arg;
@ -165,7 +168,7 @@ namespace Sd_card {
};
};
struct Read_multiple_block : Command<18, RESPONSE_48_BIT>
struct Read_multiple_block : Command<18, RESPONSE_48_BIT, TRANSFER_READ>
{
Read_multiple_block(unsigned long addr)
{
@ -173,7 +176,7 @@ namespace Sd_card {
}
};
struct Write_multiple_block : Command<25, RESPONSE_48_BIT>
struct Write_multiple_block : Command<25, RESPONSE_48_BIT, TRANSFER_WRITE>
{
Write_multiple_block(unsigned long addr)
{
@ -181,6 +184,22 @@ namespace Sd_card {
}
};
struct Set_bus_width : Prefixed_command<6, RESPONSE_48_BIT>
{
struct Arg : Sd_card::Arg
{
struct Bus_width : Bitfield<0, 2>
{
enum Width { ONE_BIT = 0, FOUR_BITS = 2 };
};
};
Set_bus_width(Arg::Bus_width::Width width)
{
Arg::Bus_width::set(arg, width);
}
};
struct Sd_send_op_cond : Prefixed_command<41, RESPONSE_48_BIT>
{
struct Arg : Sd_card::Arg
@ -203,8 +222,18 @@ namespace Sd_card {
}
};
struct Acmd_prefix : Command<55, RESPONSE_48_BIT> { };
struct Acmd_prefix : Command<55, RESPONSE_48_BIT>
{
struct Arg : Sd_card::Arg
{
struct Rca : Bitfield<16, 16> { };
};
Acmd_prefix(unsigned rca)
{
Arg::Rca::set(arg, rca);
}
};
class Card_info
{
@ -268,12 +297,15 @@ namespace Sd_card {
* This overload is selected if the supplied command type has
* 'Prefixed_command' as its base class. In this case, we need to
* issue a CMD55 as command prefix followed by the actual command.
*
* \param prefix_rca argument to CMD55 prefix command
*/
template <unsigned INDEX, Response RSP_TYPE>
bool issue_command(Prefixed_command<INDEX, RSP_TYPE> const &command)
template <unsigned INDEX, Response RSP_TYPE, Transfer TRANSFER>
bool issue_command(Prefixed_command<INDEX, RSP_TYPE, TRANSFER> const &command,
unsigned prefix_rca = 0)
{
/* send CMD55 prefix */
if (!_issue_command(Acmd_prefix())) {
if (!_issue_command(Acmd_prefix(prefix_rca))) {
PERR("prefix command timed out");
return false;
}