mirror of
https://github.com/genodelabs/genode.git
synced 2025-05-07 02:58:38 +00:00
sd_card & imx53: fix multiblock write termination
The manual termination of multi-block writes via "Stop Transmission" commands seems to leave the card in a busy state sometimes. This causes errors on subsequent commands. Thus, we have to synchronize manually with the card-internal state via "Send State" commands. Additionally, the method for issuing the manual "Stop Transmission" commands was refined. Ref #1497
This commit is contained in:
parent
2b021ec54b
commit
a08358dce9
@ -22,6 +22,34 @@ namespace Sd_card {
|
|||||||
|
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structure of the first word of a native mode R1 response
|
||||||
|
*/
|
||||||
|
struct R1_response_0 : Register<32>
|
||||||
|
{
|
||||||
|
struct Ready_for_data : Bitfield<8, 1> { };
|
||||||
|
struct State : Bitfield<9, 4>
|
||||||
|
{
|
||||||
|
enum { PROGRAM = 7 };
|
||||||
|
};
|
||||||
|
struct Error : Bitfield<19, 1> { };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return wether the card is ready for data
|
||||||
|
*
|
||||||
|
* \param resp R1 response, word 0
|
||||||
|
*/
|
||||||
|
static bool card_ready(access_t const resp)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Check both ready bit and state because not all cards handle
|
||||||
|
* the status bits correctly.
|
||||||
|
*/
|
||||||
|
return Ready_for_data::get(resp) &&
|
||||||
|
State::get(resp) != State::PROGRAM;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returned by 'Sd_send_op_cond'
|
* Returned by 'Sd_send_op_cond'
|
||||||
*/
|
*/
|
||||||
@ -149,6 +177,14 @@ namespace Sd_card {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Send_status : Command<13, RESPONSE_48_BIT>
|
||||||
|
{
|
||||||
|
struct Arg : Sd_card::Arg
|
||||||
|
{
|
||||||
|
struct Rca : Bitfield<16, 16> { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
struct Select_card : Command<7, RESPONSE_48_BIT>
|
struct Select_card : Command<7, RESPONSE_48_BIT>
|
||||||
{
|
{
|
||||||
struct Arg : Sd_card::Arg
|
struct Arg : Sd_card::Arg
|
||||||
|
@ -177,6 +177,8 @@ struct Esdhcv2 : Genode::Mmio
|
|||||||
_48BIT_BUSY = 3,
|
_48BIT_BUSY = 3,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
struct Cccen : Bitfield<19, 1> { };
|
||||||
|
struct Cicen : Bitfield<20, 1> { };
|
||||||
struct Dpsel : Bitfield<21, 1> { };
|
struct Dpsel : Bitfield<21, 1> { };
|
||||||
struct Cmdtyp : Bitfield<22, 2>
|
struct Cmdtyp : Bitfield<22, 2>
|
||||||
{
|
{
|
||||||
@ -626,6 +628,57 @@ struct Esdhcv2_controller : private Esdhcv2, public Sd_card::Host_controller
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int _wait_for_card_ready_mbw()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Poll card status
|
||||||
|
*
|
||||||
|
* The maximum number of attempts and the delay between two attempts are
|
||||||
|
* freely chosen.
|
||||||
|
*/
|
||||||
|
using namespace Sd_card;
|
||||||
|
unsigned attempts = 5;
|
||||||
|
unsigned constexpr attempts_delay_us = 100000;
|
||||||
|
while (1) {
|
||||||
|
if (!attempts) {
|
||||||
|
PERR("Reading card status after multiblock write failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* assemble argument register value */
|
||||||
|
Send_status::Arg::access_t cmdarg = 0;
|
||||||
|
Send_status::Arg::Rca::set(cmdarg, _card_info.rca());
|
||||||
|
|
||||||
|
/* assemble command register value */
|
||||||
|
Xfertyp::access_t xfertyp = 0;
|
||||||
|
Xfertyp::Cmdinx::set(xfertyp, Send_status::INDEX);
|
||||||
|
Xfertyp::Cicen::set(xfertyp, 1);
|
||||||
|
Xfertyp::Cccen::set(xfertyp, 1);
|
||||||
|
Xfertyp::Rsptyp::set(xfertyp, Xfertyp::Rsptyp::_48BIT);
|
||||||
|
Xfertyp::Msbsel::set(xfertyp, 1);
|
||||||
|
Xfertyp::Bcen::set(xfertyp, 1);
|
||||||
|
Xfertyp::Dmaen::set(xfertyp, 1);
|
||||||
|
|
||||||
|
/* send command as soon as the host allows it */
|
||||||
|
if (_wait_for_cmd_allowed()) { return -1; }
|
||||||
|
write<Cmdarg>(cmdarg);
|
||||||
|
write<Xfertyp>(xfertyp);
|
||||||
|
|
||||||
|
/* wait for command completion */
|
||||||
|
if (_wait_for_cmd_complete()) { return -1; }
|
||||||
|
|
||||||
|
/* check for errors */
|
||||||
|
R1_response_0::access_t const resp = read<Cmdrsp0>();
|
||||||
|
if (R1_response_0::Error::get(resp)) {
|
||||||
|
PERR("Reading card status after multiblock write failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* if card is in a ready state, return success, retry otherwise */
|
||||||
|
if (R1_response_0::card_ready(resp)) { break; }
|
||||||
|
_delayer.usleep(attempts_delay_us);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abort transmission by manually issuing stop command
|
* Abort transmission by manually issuing stop command
|
||||||
*
|
*
|
||||||
@ -637,7 +690,12 @@ struct Esdhcv2_controller : private Esdhcv2, public Sd_card::Host_controller
|
|||||||
Xfertyp::access_t xfertyp = 0;
|
Xfertyp::access_t xfertyp = 0;
|
||||||
Xfertyp::Cmdinx::set(xfertyp, Sd_card::Stop_transmission::INDEX);
|
Xfertyp::Cmdinx::set(xfertyp, Sd_card::Stop_transmission::INDEX);
|
||||||
Xfertyp::Cmdtyp::set(xfertyp, Xfertyp::Cmdtyp::ABORT_CMD12);
|
Xfertyp::Cmdtyp::set(xfertyp, Xfertyp::Cmdtyp::ABORT_CMD12);
|
||||||
Xfertyp::Rsptyp::set(xfertyp, Xfertyp::Rsptyp::_48BIT);
|
Xfertyp::Cccen::set(xfertyp, 1);
|
||||||
|
Xfertyp::Cicen::set(xfertyp, 1);
|
||||||
|
Xfertyp::Rsptyp::set(xfertyp, Xfertyp::Rsptyp::_48BIT_BUSY);
|
||||||
|
Xfertyp::Msbsel::set(xfertyp, 1);
|
||||||
|
Xfertyp::Bcen::set(xfertyp, 1);
|
||||||
|
Xfertyp::Dmaen::set(xfertyp, 1);
|
||||||
write<Xfertyp>(xfertyp);
|
write<Xfertyp>(xfertyp);
|
||||||
return _wait_for_cmd_complete();
|
return _wait_for_cmd_complete();
|
||||||
}
|
}
|
||||||
@ -686,6 +744,7 @@ struct Esdhcv2_controller : private Esdhcv2, public Sd_card::Host_controller
|
|||||||
* manually.
|
* manually.
|
||||||
*/
|
*/
|
||||||
if (!_abort_transmission()) { return false; }
|
if (!_abort_transmission()) { return false; }
|
||||||
|
if (_wait_for_card_ready_mbw()) { return false; }
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user