Skip to content

Commit a8ecbde

Browse files
alees24elliotb-lowrisc
authored andcommitted
Software changes for SPI controller modifications
Modify SD card utilities to use the 'COPI Idle' configuration option when available. Software remains compatible with either version of the SPI controller.
1 parent 1b5675f commit a8ecbde

File tree

3 files changed

+53
-25
lines changed

3 files changed

+53
-25
lines changed

sw/cheri/checks/sdraw_check.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ extern "C" [[noreturn]] void entry_point(void *rwRoot) {
5959
WriteUart uart{uart0};
6060
Log log(uart);
6161

62-
// The SPI controller talkes to the microSD card in SPI mode.
62+
// The SPI controller talks to the microSD card in SPI mode.
6363
auto spi = spi_ptr(root, 2);
6464

6565
// We need to use the pinmux to select the microSD card for SPI controller 2 reads (CIPO),

sw/cheri/common/sdcard-utils.hh

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ class SdCard {
3333
bool crcOn;
3434
// Access to diagnostic logging.
3535
Log *log;
36+
// Does this SPI controller have the ability to control the idle state of the COPI line?
37+
bool idleControl;
3638

3739
// We need to clock the device repeatedly at startup; this test pattern is used to ensure that
3840
// we keep the COPI line high and it cannot be misinterpreted as a command.
@@ -94,6 +96,11 @@ class SdCard {
9496
// Every card tried seems to be more than capable of keeping up with 20Mbps.
9597
constexpr unsigned kSpiSpeed = 0u;
9698
spi->init(false, false, true, kSpiSpeed);
99+
// Can we control the idle state of the COPI line?
100+
// - keeping it high when not transmitting saves us the additional work of transmitting '0xff'
101+
// bytes
102+
spi->configuration |= (1U << 28);
103+
idleControl = ((spi->configuration & (1U << 28)) != 0u);
97104

98105
// Apparently we're required to send at least 74 SD CLK cycles with
99106
// the device _not_ selected before talking to it.
@@ -337,9 +344,13 @@ class SdCard {
337344
volatile uint8_t rd2;
338345
(void)get_response_R1();
339346
for (int r = 0; r < 4; ++r) {
340-
spi->transmitFifo = 0xffu;
341-
spi->control = SonataSpi::ControlTransmitEnable | SonataSpi::ControlReceiveEnable;
342-
spi->start = 1u;
347+
if (idleControl) {
348+
spi->control = SonataSpi::ControlReceiveEnable;
349+
} else {
350+
spi->transmitFifo = 0xffu;
351+
spi->control = SonataSpi::ControlTransmitEnable | SonataSpi::ControlReceiveEnable;
352+
}
353+
spi->start = 1u;
343354
spi->wait_idle();
344355
while ((spi->status & SonataSpi::StatusRxFifoLevel) == 0) {
345356
}
@@ -441,28 +452,45 @@ class SdCard {
441452
spi->wait_idle();
442453
// Do not attempt a zero-byte transfer; not supported by the controller.
443454
if (len) {
444-
spi->control = SonataSpi::ControlReceiveEnable | SonataSpi::ControlTransmitEnable;
445-
spi->start = len;
446-
447-
// In addition to keeping the COPI line high to avoid inducing failures we want
448-
// to keep the Tx FIFO populated so that the SPI controller remains active despite
449-
// having double the traffic between CPU and SPI (Tx and Rx).
450-
//
451-
// This expression of the code very nearly keeps the SPI controller running at
452-
// SysClkFreq/2 Mbps whilst reading data, so that the data block is retrieved as
453-
// quickly as possible.
454-
//
455-
// Prompt the retrieval of the first byte.
456-
spi->transmitFifo = 0xffu; // Keep COPI high, staying one byte ahead of reception.
457-
const uint8_t *end = data + len - 1;
458-
while (data < end) {
459-
// Prompt the retrieval of the next byte.
460-
spi->transmitFifo = 0xffu; // COPI high for the next byte.
461-
// Wait until it's available, and quickly capture it.
462-
while (spi->status & SonataSpi::StatusRxFifoEmpty) {
455+
if (idleControl) {
456+
// We need only be concerned with data reception since this controller can keep the
457+
// COPI line high when only reception is enabled.
458+
spi->control = SonataSpi::ControlReceiveEnable;
459+
spi->start = len;
460+
// Prompt the retrieval of the first byte.
461+
const uint8_t *end = data + len - 1;
462+
while (data < end) {
463+
// Wait until it's available, and quickly capture it.
464+
while (spi->status & SonataSpi::StatusRxFifoEmpty) {
465+
}
466+
*data++ = static_cast<uint8_t>(spi->receiveFifo);
467+
}
468+
} else {
469+
// Older SPI controllers cannot keep the COPI line high when not actively transmitting.
470+
spi->control = SonataSpi::ControlReceiveEnable | SonataSpi::ControlTransmitEnable;
471+
spi->start = len;
472+
473+
// In addition to keeping the COPI line high to avoid inducing failures we want
474+
// to keep the Tx FIFO populated so that the SPI controller remains active despite
475+
// having double the traffic between CPU and SPI (Tx and Rx).
476+
//
477+
// This expression of the code very nearly keeps the SPI controller running at
478+
// SysClkFreq/2 Mbps whilst reading data, so that the data block is retrieved as
479+
// quickly as possible.
480+
//
481+
// Prompt the retrieval of the first byte.
482+
spi->transmitFifo = 0xffu; // Keep COPI high, staying one byte ahead of reception.
483+
const uint8_t *end = data + len - 1;
484+
while (data < end) {
485+
// Prompt the retrieval of the next byte.
486+
spi->transmitFifo = 0xffu; // COPI high for the next byte.
487+
// Wait until it's available, and quickly capture it.
488+
while (spi->status & SonataSpi::StatusRxFifoEmpty) {
489+
}
490+
*data++ = static_cast<uint8_t>(spi->receiveFifo);
463491
}
464-
*data++ = static_cast<uint8_t>(spi->receiveFifo);
465492
}
493+
466494
// Collect the final byte.
467495
while (spi->status & SonataSpi::StatusRxFifoEmpty) {
468496
}

sw/cheri/tests/sdcard_tests.hh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ void sdcard_tests(CapRoot &root, Log &log) {
126126
log.println("The file should be 4,210 bytes in length.");
127127
}
128128

129-
// The SPI controller talkes to the microSD card in SPI mode.
129+
// The SPI controller talks to the microSD card in SPI mode.
130130
auto spi = spi_ptr(root, 2);
131131

132132
// We need to use the pinmux to select the microSD card for SPI controller 2 reads (CIPO),

0 commit comments

Comments
 (0)