# HG changeset patch # User Paul Boddie # Date 1708041351 -3600 # Node ID 408e9bad9e9bc845c2865b3f466bab1d5315598f # Parent 902a8354a7b38b2a0ad53b1932dfb516bc7557e2 Adjusted response processing to employ structure types directly. diff -r 902a8354a7b3 -r 408e9bad9e9b pkg/devices/lib/msc/include/msc-common.h --- a/pkg/devices/lib/msc/include/msc-common.h Thu Feb 15 23:18:09 2024 +0100 +++ b/pkg/devices/lib/msc/include/msc-common.h Fri Feb 16 00:55:51 2024 +0100 @@ -27,13 +27,7 @@ -#ifdef __cplusplus - -#include - - - -// MMC/SD structures. +/* MMC/SD structures. */ struct CID { @@ -61,6 +55,25 @@ +/* Generic card structure. */ + +struct msc_card +{ + uint16_t rca; + uint32_t ocr; + uint8_t bus_width; + struct CID cid; + struct CSD csd; +}; + + + +#ifdef __cplusplus + +#include + + + // MMC/SD controller channel. class Msc_channel @@ -70,13 +83,11 @@ Hw::Register_block<32> _regs; l4_cap_idx_t _irq; - // Support eight CID/CSD entries of 120 bits and RCA entries of 16 bits. + // Support eight cards. - struct CID _cid[8]; - struct CSD _csd[8]; - uint16_t _rca[8], _current_rca; - uint8_t _bus_width[8], _current_bus_width; - uint8_t _cards; + struct msc_card _cards[8]; + uint8_t _num_cards; + int _card; // Utility methods. diff -r 902a8354a7b3 -r 408e9bad9e9b pkg/devices/lib/msc/src/common.cc --- a/pkg/devices/lib/msc/src/common.cc Thu Feb 15 23:18:09 2024 +0100 +++ b/pkg/devices/lib/msc/src/common.cc Fri Feb 16 00:55:51 2024 +0100 @@ -24,7 +24,6 @@ #include #include -#include #include "msc-common.h" @@ -464,13 +463,14 @@ // MMC response structures. +// These are 16-bit aligned to permit conversion to 16-bit arrays. struct R1 { uint8_t end_crc; uint32_t status; uint8_t index:6, trans_start:2; -} __attribute__((packed)); +} __attribute__((packed,aligned(__alignof__(uint16_t)))); struct R2 { @@ -484,14 +484,14 @@ } payload; uint8_t reserved_trans_start; -} __attribute__((packed)); +} __attribute__((packed,aligned(__alignof__(uint16_t)))); struct R3 { uint8_t end_reserved; uint32_t ocr; uint8_t reserved_trans_start; -} __attribute__((packed)); +} __attribute__((packed,aligned(__alignof__(uint16_t)))); // SDIO response structures. @@ -500,7 +500,7 @@ uint8_t end_reserved; uint32_t ocr:24, stuff:3, memory_present:1, number_io_functions:3, ready:1; uint8_t reserved_trans_start; -} __attribute__((packed)); +} __attribute__((packed,aligned(__alignof__(uint16_t)))); struct R5 { @@ -510,7 +510,7 @@ io_current_state:2, illegal_command:1, crc_error:1; uint16_t stuff; uint8_t index:6, trans_start:2; -} __attribute__((packed)); +} __attribute__((packed,aligned(__alignof__(uint16_t)))); struct R6 { @@ -518,7 +518,7 @@ uint16_t status; uint16_t rca; uint8_t index:6, trans_start:2; -} __attribute__((packed)); +} __attribute__((packed,aligned(__alignof__(uint16_t)))); struct R7 { @@ -531,7 +531,7 @@ } check_voltage; uint8_t index:6, trans_start:2; -} __attribute__((packed)); +} __attribute__((packed,aligned(__alignof__(uint16_t)))); @@ -825,7 +825,7 @@ bool Msc_channel::send_app_command(uint8_t index, uint32_t arg) { - if (!send_command(Command_app_cmd, _current_rca << 16)) + if (!send_command(Command_app_cmd, _cards[_card].rca << 16)) return false; return send_command(index, arg, get_app_response_format(index), @@ -873,7 +873,7 @@ // NOTE: May need to set the SD bus width. set_field(Msc_command_data_control, Cdc_bus_width_field_mask, - Cdc_bus_width_field_shift, encode_bus_width(_current_bus_width)); + Cdc_bus_width_field_shift, encode_bus_width(_cards[_card].bus_width)); set_field(Msc_command_data_control, Cdc_recv_fifo_level_field_mask, Cdc_recv_fifo_level_field_shift, Cdc_fifo_level_16); @@ -924,6 +924,30 @@ return have_response; } +// Wait indefinitely for an interrupt request, returning true if one was delivered. + +bool +Msc_channel::wait_for_irq(uint32_t flags) +{ + return !l4_error(l4_irq_receive(_irq, L4_IPC_NEVER)) && + (_regs[Msc_interrupt_flag] & flags); +} + +// Wait up to the given timeout (in microseconds) for an interrupt request, +// returning true if one was delivered. + +bool +Msc_channel::wait_for_irq(uint32_t flags, unsigned int timeout) +{ + return !l4_error(l4_irq_receive(_irq, l4_timeout(L4_IPC_TIMEOUT_NEVER, + l4util_micros2l4to(timeout)))) && + (_regs[Msc_interrupt_flag] & flags); +} + + + +// Enable the controller and identify cards. + void Msc_channel::enable() { @@ -956,7 +980,9 @@ set_field(Msc_clock_rate, Clock_rate_field_mask, Clock_rate_field_shift, 1); - _current_rca = 0; + // Initially, no card is selected. + + _card = -1; } // Check the voltage range of the SD card, potentially establishing that it is @@ -965,8 +991,7 @@ bool Msc_channel::check_sd() { - uint16_t buffer[Response_size_R7]; - struct R7 *r = (struct R7 *) buffer; + struct R7 r7; // Send an interface condition command. // A card may not respond to this command. @@ -974,11 +999,11 @@ if (!send_command(Command_send_if_cond, If_cond_default_voltage_range)) return true; - read_response(buffer, Response_size_R7); + read_response((uint16_t *) &r7, Response_size_R7); // Reject any card not supporting the default voltage range. - if (r->check_voltage.raw != If_cond_default_voltage_range) + if (r7.check_voltage.raw != If_cond_default_voltage_range) return false; return true; @@ -989,8 +1014,7 @@ void Msc_channel::init_sdio() { - uint16_t buffer[Response_size_R4]; - struct R4 *r = (struct R4 *) buffer; + struct R4 r4; uint32_t ocr = 0; // Reset any SDIO card or IO unit in a combined memory/IO card. @@ -1010,28 +1034,27 @@ if (!send_command(Command_io_send_op_cond, ocr)) return; - read_response(buffer, Response_size_R4); + read_response((uint16_t *) &r4, Response_size_R4); // Finish if no IO functions provided. // NOTE: Should only need to check this the first time. - if (r->number_io_functions == 0) + if (r4.number_io_functions == 0) return; - if (r->ocr != Ocr_default_voltage_range) + if (r4.ocr != Ocr_default_voltage_range) { ocr = Ocr_default_voltage_range; continue; } } - while (!r->ready); + while (!r4.ready); } void Msc_channel::init_sdmem() { - uint16_t buffer[Response_size_R3]; - struct R3 *r = (struct R3 *) buffer; + struct R3 r3; // Incorporate the HCS bit into the OCR for SDMEM. @@ -1042,15 +1065,15 @@ if (!send_app_command(App_command_sd_send_op_cond, ocr)) return; - read_response(buffer, Response_size_R3); + read_response((uint16_t *) &r3, Response_size_R3); - if (r->ocr != Ocr_default_voltage_range) + if (r3.ocr != Ocr_default_voltage_range) { ocr = Ocr_default_voltage_range | Ocr_high_capacity_storage; continue; } } - while (!(r->ocr & Ocr_card_powered_up)); + while (!(r3.ocr & Ocr_card_powered_up)); } void @@ -1062,8 +1085,7 @@ // are solicited, the host must determine a suitable argument and reissue the // command. - uint16_t buffer[Response_size_R3]; - struct R3 *r = (struct R3 *) buffer; + struct R3 r3; uint32_t ocr = 0; do @@ -1071,124 +1093,133 @@ if (!send_command(Command_send_op_cond, ocr)) return; - read_response(buffer, Response_size_R3); + read_response((uint16_t *) &r3, Response_size_R3); - if (r->ocr != Ocr_default_voltage_range) + if (r3.ocr != Ocr_default_voltage_range) { ocr = Ocr_default_voltage_range; continue; } } - while (!(r->ocr & Ocr_card_powered_up)); + while (!(r3.ocr & Ocr_card_powered_up)); } void Msc_channel::identify_cards() { - uint16_t buffer[Response_size_R2]; - struct R2 *r = (struct R2 *) buffer; + struct R2 r2; + struct R6 r6; - _cards = 0; + _num_cards = 0; while (send_command(Command_all_send_cid, 0)) { - read_response(buffer, Response_size_R2); + read_response((uint16_t *) &r2, Response_size_R2); - memcpy(&_cid[_cards], r->payload.raw, sizeof(r->payload.raw)); + _cards[_num_cards].cid = r2.payload.cid; - printf("card: %d\n", _cards); - printf("date: %d %d\n", r->payload.cid.month, r->payload.cid.year); - printf("serial: %d\n", r->payload.cid.serial); - printf("revision: %d\n", r->payload.cid.revision); - printf("name: %c%c%c%c%c\n", r->payload.cid.name[4], r->payload.cid.name[3], - r->payload.cid.name[2], r->payload.cid.name[1], - r->payload.cid.name[0]); - printf("oem: %d\n", r->payload.cid.oem); - printf("manufacturer: %d\n", r->payload.cid.manufacturer); + printf("card: %d\n", _num_cards); + printf("date: %d %d\n", r2.payload.cid.month, r2.payload.cid.year); + printf("serial: %d\n", r2.payload.cid.serial); + printf("revision: %d\n", r2.payload.cid.revision); + printf("name: %c%c%c%c%c\n", r2.payload.cid.name[4], r2.payload.cid.name[3], + r2.payload.cid.name[2], r2.payload.cid.name[1], + r2.payload.cid.name[0]); + printf("oem: %d\n", r2.payload.cid.oem); + printf("manufacturer: %d\n", r2.payload.cid.manufacturer); // Try and obtain a card-issued address. if (send_command(Command_send_relative_addr, 0)) { - uint16_t addr_buffer[Response_size_R6]; - struct R6 *ar = (struct R6 *) addr_buffer; - - read_response(addr_buffer, Response_size_R6); - - memcpy(&_rca[_cards], &ar->rca, sizeof(ar->rca)); + read_response((uint16_t *) &r6, Response_size_R6); + _cards[_num_cards].rca = r6.rca; } // Try and assign an address. // Employ 1-based relative addressing. - else if (send_command(Command_set_relative_addr, _cards + 1)) - _rca[_cards] = _cards + 1; + else if (send_command(Command_set_relative_addr, _num_cards + 1)) + _cards[_num_cards].rca = _num_cards + 1; // Otherwise, stop identification. else return; - // Set the default bus width. + // Set the default bus width to be determined. - _bus_width[_cards] = 0; + _cards[_num_cards].bus_width = 0; - _cards++; + _num_cards++; } } void Msc_channel::query_cards() { - uint16_t buffer[Response_size_R2]; - struct R2 *r = (struct R2 *) buffer; + struct R2 r2; + struct R3 r3; uint8_t card; - for (card = 0; card < _cards; card++) + for (card = 0; card < _num_cards; card++) { // Employ 1-based relative addressing. - if (!send_command(Command_send_csd, _rca[card] << 16)) + if (!send_command(Command_send_csd, _cards[card].rca << 16)) return; - read_response(buffer, Response_size_R2); + read_response((uint16_t *) &r2, Response_size_R2); - memcpy(&_csd[card], r->payload.raw, sizeof(r->payload.raw)); + _cards[card].csd = r2.payload.csd; printf("card: %d\n", card); - printf("csd: %d\n", r->payload.csd.csd); - printf("copy: %s\n", r->payload.csd.copy ? "copied" : "original"); - printf("card command classes: %03x\n", r->payload.csd.card_command_classes); - printf("device (size multiplier): %d %d\n", r->payload.csd.device_size + 1, - 1 << (r->payload.csd.device_size_multiplier + 2)); - printf("device size: %d\n", (1 << r->payload.csd.read_blocklen) * - (r->payload.csd.device_size + 1) * - (1 << (r->payload.csd.device_size_multiplier + 2))); - printf("transfer speed: %d MHz\n", r->payload.csd.tran_speed == 0x32 ? 25 : 50); - printf("format group: %d %d\n", r->payload.csd.format, r->payload.csd.format_group); - printf("write time factor: %d\n", 1 << r->payload.csd.write_time_factor); - printf("write protect (temp perm): %s %s\n", r->payload.csd.temp_write_prot ? "yes" : "no", - r->payload.csd.perm_write_prot ? "yes" : "no"); - printf("write protect group (enable size): %s %d\n", r->payload.csd.write_prot_group_enable ? "yes" : "no", - r->payload.csd.write_prot_group_size + 1); - printf("write block (partial length): %s %d\n", r->payload.csd.write_block_partial ? "yes" : "no", - 1 << r->payload.csd.write_blocklen); - printf("read block (partial length): %s %d\n", r->payload.csd.read_block_partial ? "yes" : "no", - 1 << r->payload.csd.read_blocklen); - printf("erase: sector single: %d %s\n", r->payload.csd.erase_sector_size + 1, - r->payload.csd.erase_single_block_enable ? "yes" : "no"); - printf("misalign: read write: %s %s\n", r->payload.csd.read_block_misalign ? "yes" : "no", - r->payload.csd.write_block_misalign ? "yes" : "no"); - printf("max read current (min max): %d %d\n", r->payload.csd.max_read_current_min, - r->payload.csd.max_read_current_max); - printf("max write current (min max): %d %d\n", r->payload.csd.max_write_current_min, - r->payload.csd.max_write_current_max); - printf("read access time (1 2): %d %d\n", r->payload.csd.data_read_access_time_1, - r->payload.csd.data_read_access_time_2); - printf("DSR: %s\n", r->payload.csd.dsr_implemented ? "yes" : "no"); + printf("csd: %d\n", r2.payload.csd.csd); + printf("copy: %s\n", r2.payload.csd.copy ? "copied" : "original"); + printf("card command classes: %03x\n", r2.payload.csd.card_command_classes); + printf("device (size multiplier): %d %d\n", r2.payload.csd.device_size + 1, + 1 << (r2.payload.csd.device_size_multiplier + 2)); + printf("device size: %d\n", (1 << r2.payload.csd.read_blocklen) * + (r2.payload.csd.device_size + 1) * + (1 << (r2.payload.csd.device_size_multiplier + 2))); + printf("transfer speed: %d MHz\n", r2.payload.csd.tran_speed == 0x32 ? 25 : 50); + printf("format group: %d %d\n", r2.payload.csd.format, r2.payload.csd.format_group); + printf("write time factor: %d\n", 1 << r2.payload.csd.write_time_factor); + printf("write protect (temp perm): %s %s\n", r2.payload.csd.temp_write_prot ? "yes" : "no", + r2.payload.csd.perm_write_prot ? "yes" : "no"); + printf("write protect group (enable size): %s %d\n", r2.payload.csd.write_prot_group_enable ? "yes" : "no", + r2.payload.csd.write_prot_group_size + 1); + printf("write block (partial length): %s %d\n", r2.payload.csd.write_block_partial ? "yes" : "no", + 1 << r2.payload.csd.write_blocklen); + printf("read block (partial length): %s %d\n", r2.payload.csd.read_block_partial ? "yes" : "no", + 1 << r2.payload.csd.read_blocklen); + printf("erase: sector single: %d %s\n", r2.payload.csd.erase_sector_size + 1, + r2.payload.csd.erase_single_block_enable ? "yes" : "no"); + printf("misalign: read write: %s %s\n", r2.payload.csd.read_block_misalign ? "yes" : "no", + r2.payload.csd.write_block_misalign ? "yes" : "no"); + printf("max read current (min max): %d %d\n", r2.payload.csd.max_read_current_min, + r2.payload.csd.max_read_current_max); + printf("max write current (min max): %d %d\n", r2.payload.csd.max_write_current_min, + r2.payload.csd.max_write_current_max); + printf("read access time (1 2): %d %d\n", r2.payload.csd.data_read_access_time_1, + r2.payload.csd.data_read_access_time_2); + printf("DSR: %s\n", r2.payload.csd.dsr_implemented ? "yes" : "no"); + + // Query the OCR again now that we can associate it with a specific card. + + if (!send_app_command(App_command_read_ocr, 0)) + return; + + read_response((uint16_t *) &r3, Response_size_R3); + + _cards[card].ocr = r3.ocr; } } + + +// Receive data from the selected card. + uint32_t Msc_channel::recv_data(l4re_dma_space_dma_addr_t paddr, uint32_t count) { @@ -1209,6 +1240,8 @@ return to_transfer; } +// Send data to the selected card. + uint32_t Msc_channel::send_data(l4re_dma_space_dma_addr_t paddr, uint32_t count) { @@ -1229,49 +1262,48 @@ return to_transfer; } +// Read blocks from the indicated card into a memory region. + uint32_t Msc_channel::read_blocks(uint8_t card, l4re_dma_space_dma_addr_t paddr, uint32_t block_address, uint32_t block_count) { - uint32_t block_size = 1 << _csd[card].read_blocklen; - uint16_t buffer[Response_size_R1]; - struct R1 *r = (struct R1 *) buffer; + uint32_t block_size = 1 << _cards[card].csd.read_blocklen; + struct R1 r1; // Select the requested card. - if (_current_rca != _rca[card]) + if (_card != card) { - if (!send_command(Command_select_deselect_card, _rca[card] << 16)) + if (!send_command(Command_select_deselect_card, _cards[card].rca << 16)) return 0; - read_response(buffer, Response_size_R1); + read_response((uint16_t *) &r1, Response_size_R1); - if (r->status & R1_status_error_mask) + if (r1.status & R1_status_error_mask) return 0; - _current_rca = _rca[card]; + _card = card; } // NOTE: SMEM cards should allow bus width setting with the SCR register // NOTE: describing the permitted values. // NOTE: SDIO cards have their bus width set in CCCR via CMD52. - if (!_bus_width[card]) + if (!_cards[card].bus_width) { if (send_app_command(App_command_set_bus_width, Bus_width_4bit)) - _bus_width[card] = 4; + _cards[card].bus_width = 4; else - _bus_width[card] = 1; + _cards[card].bus_width = 1; } - _current_bus_width = _bus_width[card]; - if (!send_command(Command_set_blocklen, block_size)) return 0; - read_response(buffer, Response_size_R1); + read_response((uint16_t *) &r1, Response_size_R1); - if (r->status & R1_status_error_mask) + if (r1.status & R1_status_error_mask) return 0; // NOTE: Consider issuing a predefined block count command to any multiple @@ -1288,9 +1320,9 @@ : Command_read_multiple_block, block_address)) return 0; - read_response(buffer, Response_size_R1); + read_response((uint16_t *) &r1, Response_size_R1); - if (r->status & R1_status_error_mask) + if (r1.status & R1_status_error_mask) return 0; // NOTE: Use Msc_block_success_count instead. @@ -1303,26 +1335,6 @@ return transferred; } -// Wait indefinitely for an interrupt request, returning true if one was delivered. - -bool -Msc_channel::wait_for_irq(uint32_t flags) -{ - return !l4_error(l4_irq_receive(_irq, L4_IPC_NEVER)) && - (_regs[Msc_interrupt_flag] & flags); -} - -// Wait up to the given timeout (in microseconds) for an interrupt request, -// returning true if one was delivered. - -bool -Msc_channel::wait_for_irq(uint32_t flags, unsigned int timeout) -{ - return !l4_error(l4_irq_receive(_irq, l4_timeout(L4_IPC_TIMEOUT_NEVER, - l4util_micros2l4to(timeout)))) && - (_regs[Msc_interrupt_flag] & flags); -} - // Peripheral abstraction.