Commit e3468df8 authored by Ben Avison's avatar Ben Avison

Implement generic SDHCI version of SetSDCLK

The new SDHCI controller in the Pi 4 appears to follow the spec in this regard
also.
parent 029f88ff
......@@ -4,18 +4,18 @@
*
*/
#define Module_MajorVersion_CMHG 0.15
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 20 Jul 2019
#define Module_MinorVersion_CMHG GenericSDHCIFixes.1
#define Module_Date_CMHG 10 Aug 2019
#define Module_MajorVersion "0.15"
#define Module_Version 15
#define Module_MinorVersion ""
#define Module_Date "20 Jul 2019"
#define Module_MinorVersion "GenericSDHCIFixes.1"
#define Module_Date "10 Aug 2019"
#define Module_ApplicationDate "20-Jul-19"
#define Module_ApplicationDate "10-Aug-19"
#define Module_ComponentName "SDIODriver"
#define Module_FullVersion "0.15"
#define Module_HelpVersion "0.15 (20 Jul 2019)"
#define Module_FullVersion "0.15 (GenericSDHCIFixes.1)"
#define Module_HelpVersion "0.15 (10 Aug 2019) GenericSDHCIFixes.1"
#define Module_LibraryVersionInfo "0:15"
......@@ -48,6 +48,8 @@
#define CONTROLLER_RESET_TIMEOUT (1) /* in cs */
#define CARD_INIT_TIMEOUT (100) /* in cs */
#define DATA_TIMEOUT (500) /* data line timeout, in ms */
#define SDCLK_INHIBIT_TIMEOUT (100) /* in cs */
#define SDCLK_STABLE_TIMEOUT (2) /* in cs */
#define POST_SWITCH_DELAY (8 * 1000000 / 400) /* 8 clock cycles in us */
#define XPC_CURRENT_THRESHOLD (150) /* in mA */
#define FIRST_ASSIGNED_MMC_RCA (2) /* values 0 and 1 are special purpose */
......@@ -87,7 +89,73 @@ static uint32_t set_sdclk(ctrlnode_t *ctrl, uint32_t sloti, uint32_t freq_khz)
}
else
{
while (1); /* TODO: generic SDHCI implementation */
/* Generic SDHCI implementation */
uint8_t hcv = (REGISTER_READ(host_controller_version) & HCV_SREV_MASK) >> HCV_SREV_SHIFT;
uint32_t base_clock_khz = ((slot->caps[0] & CAP0_BCF_MASK) >> CAP0_BCF_SHIFT) * 1000;
uint32_t divisor = (base_clock_khz + freq_khz - 1) / freq_khz; /* round up */
/* Ensure no transactions are happening on the bus */
int32_t timeout, now;
_swix(OS_ReadMonotonicTime, _OUT(0), &timeout);
timeout += SDCLK_INHIBIT_TIMEOUT + 1;
do
_swix(OS_ReadMonotonicTime, _OUT(0), &now);
while (timeout - now > 0 && (REGISTER_READ(present_state) & (PS_DATI | PS_CMDI)) != 0);
/* Stop clock going to card */
uint16_t cc = REGISTER_READ(clock_control);
cc &= ~CC_SCE;
REGISTER_WRITE(clock_control, cc);
register_flush_buffer(dev, sloti, wrbuf);
/* Stop clock */
cc &= ~CC_ICE;
REGISTER_WRITE(clock_control, cc);
register_flush_buffer(dev, sloti, wrbuf);
cc &= ~(CC_SFS_MASK | CC_UBSFS_MASK | CC_CGS);
if (hcv < HCV_SREV_3_00)
{
/* Host controller versions 1.00 and 2.00 require 8-bit divided clock mode.
* Round up divisor to next power of 2. Store halved. */
--divisor;
divisor |= divisor >> 4;
divisor |= divisor >> 2;
divisor |= divisor >> 1;
++divisor;
if (divisor > 256)
divisor = 256;
sdclk = base_clock_khz / divisor;
divisor >>= 1;
cc |= divisor << CC_SFS_SHIFT;
}
else
{
/* Host controller version 3.00 must offer 10-bit divided clock mode.
* Some such controllers can optionally support programmable clock mode
* (as identified by non-zero CAP1_CM in capabilities[1]) but we are not
* required to use it. For 10-bit divided clock mode, we can either use
* base clock directly or divide by any multiple of 2. Stored halved. */
if (divisor > 2046)
divisor = 2046;
if (divisor > 1)
divisor = (divisor + 1) &~ 1;
sdclk = base_clock_khz / divisor;
divisor >>= 1;
cc |= (divisor << CC_SFS_SHIFT) & CC_SFS_MASK;
cc |= (divisor >> 8) << CC_UBSFS_SHIFT;
}
REGISTER_WRITE(clock_control, cc);
register_flush_buffer(dev, sloti, wrbuf);
/* Restart clock */
cc |= CC_ICE;
REGISTER_WRITE(clock_control, cc);
register_flush_buffer(dev, sloti, wrbuf);
/* Wait for up to 20 ms for the clock to stabilise */
_swix(OS_ReadMonotonicTime, _OUT(0), &timeout);
timeout += SDCLK_STABLE_TIMEOUT + 1;
do
_swix(OS_ReadMonotonicTime, _OUT(0), &now);
while (timeout - now > 0 && (REGISTER_READ(clock_control) & CC_ICS) == 0);
/* Send clock to card again */
cc |= CC_SCE;
REGISTER_WRITE(clock_control, cc);
}
/* Now we (at least for some platforms including OMAP and BCM2835) have to
......@@ -100,6 +168,7 @@ static uint32_t set_sdclk(ctrlnode_t *ctrl, uint32_t sloti, uint32_t freq_khz)
}
else
{
/* Generic SDHCI implementation */
tmclk = (slot->caps[0] & CAP0_TCF_MASK) >> CAP0_TCF_SHIFT;
if (slot->caps[0] & CAP0_TCU)
tmclk *= 1000;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment