From eac9055c92641c67247b65fb0482e6393dc92240 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Thu, 19 Jul 2012 20:14:25 +0200 Subject: [PATCH] Operate SD card in 4-bit data mode --- os/src/drivers/sd_card/omap4/mmchs.h | 38 ++++++++++++----- os/src/drivers/sd_card/omap4/sd_card.h | 56 ++++++++++++++++++++------ 2 files changed, 73 insertions(+), 21 deletions(-) diff --git a/os/src/drivers/sd_card/omap4/mmchs.h b/os/src/drivers/sd_card/omap4/mmchs.h index 91cc6faefa..3b079dffb8 100644 --- a/os/src/drivers/sd_card/omap4/mmchs.h +++ b/os/src/drivers/sd_card/omap4/mmchs.h @@ -326,7 +326,7 @@ struct Mmchs : Genode::Mmio write(~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::ONE_BIT); break; - case BUS_WIDTH_8: - write(1); + case BUS_WIDTH_4: + write(0); + write(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(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); } diff --git a/os/src/drivers/sd_card/omap4/sd_card.h b/os/src/drivers/sd_card/omap4/sd_card.h index b370f34ec4..161e8cc511 100644 --- a/os/src/drivers/sd_card/omap4/sd_card.h +++ b/os/src/drivers/sd_card/omap4/sd_card.h @@ -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 + template struct Command : Command_base { enum { INDEX = _INDEX }; - Command() : Command_base(_INDEX, RSP_TYPE) { } + Command() : Command_base(_INDEX, RSP_TYPE, TRANSFER) { } }; - template + template 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 - bool issue_command(Prefixed_command const &command) + template + bool issue_command(Prefixed_command 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; }