SD host controllers may be attached via a PCI bus as was anticipated by the SD standard. In this case, the SDIODriver would scan the PCI bus for devices of the appropriate class. It should be noted however that at the present time there are no RISC OS platforms with such an architecture, so this is considered a future enhancement.
Host controllers with alternate attachments are discovered via the HAL Device API. This potentially includes hot-pluggable host controllers, as is true of all HAL Devices. The HAL Device looks like this:
Offset | Bits | Value | Meaning |
---|---|---|---|
0 | Type: | ||
15 – 8 | 5 | Controller of peripheral buses | |
7 – 0 | 1 | For SDIO controller | |
2 | ID: | ||
15 – 0 | 1 | Generic SDHCI controller | |
4 | Location: | ||
31 – 28 | 5 | (interconnect) for OMAP3 | |
27 – 24 | 1 | (L4 interconnect) for OMAP3 | |
23 – 16 | 0 | 0 for OMAP3 | |
15 – 8 | 0 | 0 for OMAP3 | |
7 – 0 | 0 | 0 for OMAP3 | |
8 | Version: Only major version 0 has currently been defined. Within major version 0, minor version 1 indicates the presence of the TriggerCommand function pointer (which may still be NULL) | ||
12 | Description: | ||
16 | Address: | ||
20 | Reserved1: | ||
32 | Activate: | ||
36 | Deactivate: | ||
40 | Reset: | ||
44 | Sleep: | ||
48 | DeviceNumber: | ||
52 | TestIRQ: | ||
56 | ClearIRQ: | ||
60 | Reserved2: | ||
64 | Flags: | ||
31 – 3 | 0 | Reserved, must be zero | |
2 | 1 | the controller doesn’t set the error interrupt bit in the normal interrupt status register | |
1 | 1 | The controller doesn’t strip the byte containing the CRC and end bit from R2 responses before placing in the response registers | |
0 | 0 | All register reads and writes must use 32-bit accesses | |
68 | 31 – 0 | Number of slots supported by this host controller – or technically, the number of standard register sets it provides, which corresponds to the number of CMD lines it drives. Each slot is normally used to drive a single MMC or SD device, but it is possible that multiple devices can be driven by a single slot – for MMC buses this is achieved by the use of an identifying field, the RCA, in the command argument; for SD buses, a Shared Bus configuration can be implemented in hardware, with a separate CLK line for multiple devices that share the same CMD line | |
72 | 31 – 0 | Pointer to array of structures giving further information about each slot |
Type | Function Pointer | Meaning |
---|---|---|
void | WriteRegister(device *controller, uint32_t slot, void *address, uint32_t value, uint32_t width) | function pointer to a custom routine to write a register in the SDHCI controller. If flags bit 0 is set, then writes have already been amalgamated into 32-bit words and the address will be word aligned. Otherwise the fourth parameter represents the value to be written, zero-extended to a 32-bit value, and the fifth contains the width of the register in bytes. This entry is intended for controllers that have special requirements (such as the BCM2835 where the rate of register pokes must be strictly limited). In other cases, a null pointer can be given, and the register will be written using a simple data write operation |
uint64_t | GetCapabilities(device *controller, uint32_t slot) | function pointer to a custom routine to read the controller’s capabilities register. This is intended for controllers that do not implement this standard SDHCI register; if the register is implemented, you can use a null pointer instead. The value returned from this function should follow the bit layout as defined in the SDHCI standard |
uint32_t | GetVddCapabilities(device *controller, uint32_t slot) | function pointer to a custom routine to read which supply voltages are available. This is needed in cases where an external level-shifter is in use, which the controller itself cannot know about. If this is a null pointer, the availables voltages are determined from the capabilities register instead. Bits in the return value are defined as follows: bit 0 set => 3.3 V supported bit 1 set => 3.0 V supported bit 2 set => 1.8 V supported other bits reserved, should be 0 If you report more than one bit set, then you must also support 0 V (this is because cards must be powered down in order to change their operating voltage) |
void | SetVdd(device *controller, uint32_t slot, uint32_t voltage) | function pointer to a custom routine to set the supply voltage. This is needed if blocks other than the SDHCI controller are involved in power supply or level shifting; if this is not the case then you can use a null pointer and the SDHCI power control register will be used instead. The voltage is specified in mV, and may have value 0 to indicate that the bus should be powered down |
void | SetBusMode(device *controller, uint32_t slot, bool od_not_pp) | function pointer to switch the CMD line of the bus between open-drain and push-pull modes. With the MMC bus (unlike the SD bus), multiple cards may share both a CLK and CMD line, and may all simultaneously drive the shared CMD line in response to “bcr” type commands. These commands are used during device-identification mode, so during this mode, the CMD line must be set to open-drain. Push-pull mode is used in data-transfer mode for its speed advantage. A controller that only supports SD cards may use a null pointer for this entry |
void | PostPowerOn(device *controller, uint32_t slot) | function pointer which is called after power is supplied to the card. The controller in the OMAP3 has a special initialisation procedure that must be performed at this point – other cases will probably use a null pointer |
void | SetBusWidth(device_t *controller, uint32_t slot, uint32_t lines) | function pointer to a custom routine to set the number of DAT lines used by the controller (1, 4 or 8); may be a null pointer if the controller conforms to the SDHCI specification |
uint32_t | GetMaxCurrent(device *controller, uint32_t slot) | function pointer to find the maximum current that can supplied to the card at the presently selected voltage and bus width. This is needed if there are external power supplies or voltage shifters, or if the maximum current capabilities register is not implemented or reports value 0. You may use a null pointer otherwise. The value returned is in units of mA |
uint32_t | SetSDCLK(device *controller, uint32_t slot, uint32_t freq_khz) | function pointer to a custom routine set the SDCLK frequency (in units of 1 kHz) for all SDCLK lines driven by this slot; may be a null pointer if the controller conforms to the SDHCI specification. A controller may set any frequency below the one requested; the function returns the actual frequency used, in kHz, rounded down |
uint32_t | GetTMCLK(device *controller, uint32_t slot) | function pointer to a custom routine to read the timeout clock frequency (TMCLK) in units of 1 kHz; may be a null pointer if the controller conforms to the SDHCI specification and provides a non-zero value in the Timeout Clock Frequency field of the Capabilities register |
void | SetActivity(device *controller, uint32_t slot, uint32_t level) | function pointer to turn on or off the disc activity indicator LED for the specified slot on this controller (level 0 = off, level 1 = read access, level 2 = write access); may be a null pointer if the standard SDHCI mechanism is to be used instead |
bool | GetCardDetect(device *controller, uint32_t slot) | function pointer that returns the state of the hardware card-detect line for the card in this slot. When multiple MMC devices share the same CMD line, there is no way to associate a card’s bus address (RCA) with an independent card detect line, so detection is impossible and this function should return true. The SD Shared Bus configuration is only used in cases where the device is embedded and non-removable, so likewise this function should return true in such cases. Otherwise, this may be a null pointer if the standard SDHCI mechanism is to be used instead |
bool | GetWriteProtect(device * controller, uint32_t slot) | function pointer that returns whether the hardware write-protect switch is activated for this slot. Similar concerns regarding devices sharing a CMD line apply so in such cases you should always return false. Otherwise, this may be a null pointer if the standard SDHCI mechanism is to be used instead |
void | TriggerCommand(device *controller, uint32_t slot, uint16_t transfer_mode, uint16_t command) | function pointer that performs the equivalent of writes to the Transfer Mode and Command registers on a pure SDHCI controller, and thereby causes a command to be issued on the bus |
Further information on HAL Device Descriptor fields can be found here.
The structures pointed at by slotinfo have the following layout:
Offset | Bits | Meaning |
---|---|---|
0 | Flags: | |
31 – 8 | Reserved (must be zero) | |
7 | If set => all devices on this slot are integrated onto the board and so are not physically removable, but at least one of them provides a memory function (this flag is used by SDFS to assign a “hard disc” drive number) | |
6 | If set => the devices on this slot are removable but the card detect line is non-functional, so testing for device presence must be performed by a speculative command | |
5 – 3 | Number of SDCLK lines controlled by this slot, minus 1 | |
2 – 1 | Data bus width tracked out to device(s): | |
0 => 1 bit | ||
1 => 4 bits | ||
2 => 8 bits (MMC or embedded SD only) | ||
0 | If set => all devices on this slot are integrated onto the board and so are not physically removable (this flag is used to hide integrated SDIO devices from SDFS) | |
4 | stdregs: | |
31 – 0 | Logical base addresses of standard register set |
The OMAP3530 has 3 host controllers with one slot on each, but since the beagleboard only tracks out one of them to an SD connector, only this one will be reported by the HAL. For boards like the IGEPv2 which use 2 of the controllers, the HAL will instead report two devices. A driver for a beagleboard expansion card would announce the additional controller(s) once the expansion card had been detected – this is necessary since the HAL can’t be expected to have knowledge of how to detect every possible expansion card and how they route their SD buses.
(Actually, to simplify initial development, this device will be implemented in a module, so that complete ROM rebuilds are not required to test each incremental change, but when the code becomes stable it will be moved into the HAL proper.)
First, a note on controller and card addressing. There are a number of fields common to multiple parts of the API:
The SDIODriver is responsible for probing cards, to identify which are memory cards, which are IO cards and which are combo cards, and for IO cards, discovering the set of functions available and the Function Interface Code for each. However, it is not appropriate for it to create further HAL devices to describe functions because to do so would mean hard-coding knowledge of the meaning of each Function Interface Code into the SDIODriver, and additional codes could be allocated at any time; it is better that this knowledge is encapsulated within the driver module for that specific function.