1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/pkg/devices/lib/msc/src/common.cc Sun Feb 11 00:39:56 2024 +0100
1.3 @@ -0,0 +1,1232 @@
1.4 +/*
1.5 + * MSC (MMC/SD controller) peripheral support.
1.6 + *
1.7 + * Copyright (C) 2024 Paul Boddie <paul@boddie.org.uk>
1.8 + *
1.9 + * This program is free software; you can redistribute it and/or
1.10 + * modify it under the terms of the GNU General Public License as
1.11 + * published by the Free Software Foundation; either version 2 of
1.12 + * the License, or (at your option) any later version.
1.13 + *
1.14 + * This program is distributed in the hope that it will be useful,
1.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.17 + * GNU General Public License for more details.
1.18 + *
1.19 + * You should have received a copy of the GNU General Public License
1.20 + * along with this program; if not, write to the Free Software
1.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
1.22 + * Boston, MA 02110-1301, USA
1.23 + */
1.24 +
1.25 +#include <l4/devices/hw_mmio_register_block.h>
1.26 +#include <l4/sys/irq.h>
1.27 +#include <l4/util/util.h>
1.28 +
1.29 +#include <stdio.h>
1.30 +#include <string.h>
1.31 +
1.32 +#include "msc-common.h"
1.33 +
1.34 +
1.35 +
1.36 +// Register locations for each channel.
1.37 +
1.38 +enum Regs : unsigned
1.39 +{
1.40 + Msc_control = 0x000, // MSC_CTRL
1.41 + Msc_status = 0x004, // MSC_STAT
1.42 + Msc_clock_rate = 0x008, // MSC_CLKRT
1.43 + Msc_command_data_control = 0x00c, // MSC_CMDAT
1.44 + Msc_response_timeout = 0x010, // MSC_RESTO
1.45 + Msc_read_timeout = 0x014, // MSC_RDTO
1.46 + Msc_block_length = 0x018, // MSC_BLKLEN
1.47 + Msc_block_count = 0x01c, // MSC_NOB
1.48 + Msc_block_success_count = 0x020, // MSC_SNOB
1.49 + Msc_interrupt_mask = 0x024, // MSC_IMASK
1.50 + Msc_interrupt_flag = 0x028, // MSC_IFLG/MSC_IREG
1.51 + Msc_command_index = 0x02c, // MSC_CMD
1.52 + Msc_command_argument = 0x030, // MSC_ARG
1.53 + Msc_response_fifo = 0x034, // MSC_RES
1.54 + Msc_recv_data_fifo = 0x038, // MSC_RXFIFO
1.55 + Msc_trans_data_fifo = 0x03c, // MSC_TXFIFO
1.56 +
1.57 + // JZ4780/X1600 only.
1.58 +
1.59 + Msc_low_power_mode = 0x040, // MSC_LPM
1.60 + Msc_dma_control = 0x044, // MSC_DMAC
1.61 + Msc_dma_descriptor_address = 0x048, // MSC_DMANDA
1.62 + Msc_dma_data_address = 0x04c, // MSC_DMADA
1.63 + Msc_dma_data_length = 0x050, // MSC_DMALEN
1.64 + Msc_dma_command = 0x054, // MSC_DMACMD
1.65 + Msc_control2 = 0x058, // MSC_CTRL2
1.66 + Msc_rtfifo_data_counter = 0x05c, // MSC_RTCNT
1.67 +
1.68 + // Channel block size/offset.
1.69 +
1.70 + Msc_channel_offset = 0x10000,
1.71 +};
1.72 +
1.73 +// Field definitions.
1.74 +
1.75 +enum Control_bits : unsigned
1.76 +{
1.77 + // JZ4780/X1600 only.
1.78 +
1.79 + Control_send_ccsd = 0x8000, // SEND_CCSD
1.80 + Control_send_ccsd_automatically = 0x4000, // SEND_CCSD
1.81 +
1.82 + // Common.
1.83 +
1.84 + Control_exit_multiple = 0x0080, // EXIT_MULTIPLE
1.85 + Control_exit_transfer = 0x0040, // EXIT_TRANSFER
1.86 + Control_start_read_wait = 0x0020, // START_READ_WAIT
1.87 + Control_stop_read_wait = 0x0010, // STOP_READ_WAIT
1.88 + Control_reset = 0x0008, // RESET
1.89 + Control_start_operation = 0x0004, // START_OP
1.90 +
1.91 + Control_clock_control_field_mask = 0x3, // CLOCK_CTRL
1.92 + Control_clock_control_start = 2,
1.93 + Control_clock_control_stop = 1,
1.94 + Control_clock_control_field_shift = 0,
1.95 +};
1.96 +
1.97 +enum Control2_bits : unsigned
1.98 +{
1.99 + // JZ4780/X1600 only.
1.100 +
1.101 + Control2_pin_level_polarity_field_mask = 0x1f, // PIP
1.102 + Control2_pin_level_polarity_field_shift = 24,
1.103 +
1.104 + // JZ4780 only.
1.105 +
1.106 + Control2_reset_enable = 0x00800000, // RST_EN
1.107 +
1.108 + // JZ4780/X1600 only.
1.109 +
1.110 + Control2_stop_read_operation_mode = 0x00000010, // STPRM
1.111 +
1.112 + // JZ4780 only.
1.113 +
1.114 + Control2_signal_voltage_change = 0x00000008, // SVC
1.115 +
1.116 + // JZ4780/X1600 only.
1.117 +
1.118 + Control2_speed_mode_field_mask = 0x7, // SMS
1.119 + Control2_speed_mode_default = 0, // = 0
1.120 + Control2_speed_mode_high = 1, // = 1
1.121 + Control2_speed_mode_sdr12 = 2, // = 2
1.122 + Control2_speed_mode_sdr25 = 3, // = 3
1.123 + Control2_speed_mode_sdr50 = 4, // = 4
1.124 + Control2_speed_mode_field_shift = 0,
1.125 +};
1.126 +
1.127 +enum Status_bits : unsigned
1.128 +{
1.129 + // JZ4780/X1600 only.
1.130 +
1.131 + Status_auto_cmd12_done = 0x80000000, // AUTO_CMD12_DONE
1.132 +
1.133 + // JZ4780 only.
1.134 +
1.135 + Status_auto_cmd23_done = 0x40000000, // AUTO_CMD23_DONE
1.136 + Status_signal_voltage_change = 0x20000000, // SVS
1.137 +
1.138 + // JZ4780/X1600 only.
1.139 +
1.140 + Status_pin_level_field_mask = 0x1f, // PIN_LEVEL
1.141 + Status_pin_level_field_shift = 24,
1.142 +
1.143 + Status_boot_crc_error = 0x00100000, // BCE
1.144 + Status_boot_data_end = 0x00080000, // BDE
1.145 + Status_boot_ack_error = 0x00040000, // BAE
1.146 + Status_boot_ack_received = 0x00020000, // BAR
1.147 + Status_dma_end = 0x00010000, // DMAEND
1.148 +
1.149 + // Common.
1.150 +
1.151 + Status_resetting = 0x8000, // IS_RESETTING
1.152 + Status_sdio_interrupt_active = 0x4000, // SDIO_INT_ACTIVE
1.153 + Status_programming_done = 0x2000, // PRG_DONE
1.154 + Status_data_transfer_done = 0x1000, // DATA_TRAN_DONE
1.155 + Status_end_command_response = 0x0800, // END_CMD_RES
1.156 + Status_data_fifo_almost_full = 0x0400, // DATA_FIFO_AFULL
1.157 + Status_read_wait = 0x0200, // IS_READWAIT
1.158 + Status_clock_enabled = 0x0100, // CLK_EN
1.159 + Status_data_fifo_full = 0x0080, // DATA_FIFO_FULL
1.160 + Status_data_fifo_empty = 0x0040, // DATA_FIFO_EMPTY
1.161 + Status_response_crc_error = 0x0020, // CRC_RES_ERR
1.162 + Status_read_crc_error = 0x0010, // CRC_READ_ERROR
1.163 + Status_write_crc_error_no_status = 0x0008, // CRC_WRITE_ERROR (2)
1.164 + Status_write_crc_error_data = 0x0004, // CRC_WRITE_ERROR (1)
1.165 + Status_timeout_response = 0x0002, // TIME_OUT_RES
1.166 + Status_timeout_read = 0x0001, // TIME_OUT_READ
1.167 +};
1.168 +
1.169 +enum Clock_rate_bits : unsigned
1.170 +{
1.171 + Clock_rate_field_mask = 0x7, // CLK_RATE
1.172 + Clock_rate_field_shift = 0,
1.173 +};
1.174 +
1.175 +enum Command_data_control_bits : unsigned
1.176 +{
1.177 + // JZ4780/X1600 only.
1.178 +
1.179 + Cdc_ccs_expected = 0x80000000, // CCS_EXPECTED
1.180 + Cdc_read_ce_ata = 0x40000000, // READ_CEATA
1.181 + Cdc_disable_boot = 0x08000000, // DIS_BOOT
1.182 + Cdc_expect_boot_ack = 0x02000000, // EXP_BOOT_ACK
1.183 + Cdc_alternative_boot_mode = 0x01000000, // BOOT_MODE
1.184 +
1.185 + // JZ4780 only.
1.186 +
1.187 + Cdc_auto_cmd23 = 0x00040000, // AUTO_CMD23
1.188 +
1.189 + // JZ4780/X1600 only.
1.190 +
1.191 + Cdc_sdio_interrupt_2cycle = 0x00020000, // SDIO_PRDT
1.192 + Cdc_auto_cmd12 = 0x00010000, // AUTO_CMD12
1.193 +
1.194 + Cdc_recv_fifo_level_field_mask = 0x3, // RTRG
1.195 + Cdc_fifo_level_16 = 0,
1.196 + Cdc_fifo_level_32 = 1,
1.197 + Cdc_fifo_level_64 = 2,
1.198 + Cdc_fifo_level_96 = 3,
1.199 + Cdc_recv_fifo_level_field_shift = 14,
1.200 +
1.201 + Cdc_trans_fifo_level_field_mask = 0x3, // TTRG
1.202 + Cdc_trans_fifo_level_field_shift = 12,
1.203 +
1.204 + // Common.
1.205 +
1.206 + Cdc_io_abort = 0x0800, // IO_ABORT
1.207 +
1.208 + Cdc_bus_width_field_mask = 0x3, // BUS_WIDTH
1.209 + Cdc_bus_width_field_1bit = 0, // = 0
1.210 + Cdc_bus_width_field_4bit = 2, // = 2
1.211 + Cdc_bus_width_field_shift = 9,
1.212 +
1.213 + // JZ4740 only.
1.214 +
1.215 + Cdc_dma_enable = 0x0100, // DMA_EN
1.216 + Cdc_dma_disable = 0x0000,
1.217 +
1.218 + // Common.
1.219 +
1.220 + Cdc_init_sequence = 0x0080, // INIT
1.221 +
1.222 + Cdc_expect_busy = 0x0040, // BUSY
1.223 + Cdc_do_not_expect_busy = 0x0000,
1.224 +
1.225 + Cdc_stream_block = 0x0020, // STREAM_BLOCK
1.226 + Cdc_not_stream_block = 0x0000,
1.227 +
1.228 + Cdc_write_operation = 0x0010, // WRITE_READ
1.229 + Cdc_read_operation = 0x0000,
1.230 +
1.231 + Cdc_data_with_command = 0x0008, // DATA_EN
1.232 + Cdc_no_data_with_command = 0x0000,
1.233 +
1.234 + Cdc_response_format_field_mask = 0x7, // RESPONSE_FORMAT
1.235 + Cdc_response_format_field_shift = 0,
1.236 +};
1.237 +
1.238 +enum Response_timeout_bits : unsigned
1.239 +{
1.240 + // NOTE: 16-bit value in the JZ4780.
1.241 + // NOTE: 32-bit value in the X1600.
1.242 +
1.243 + Response_timeout_mask = 0x000000ff, // RES_TO
1.244 +};
1.245 +
1.246 +enum Read_timeout_bits : unsigned
1.247 +{
1.248 + // NOTE: 16-bit value prior to the JZ4780/X1600.
1.249 +
1.250 + Read_timeout_mask = 0xffffffff, // READ_TO
1.251 +};
1.252 +
1.253 +enum Block_length_bits : unsigned
1.254 +{
1.255 + // NOTE: 16-bit value in the JZ4780/X1600.
1.256 +
1.257 + Block_length_mask = 0x00000fff, // BLK_LEN
1.258 +};
1.259 +
1.260 +enum Block_count_bits : unsigned
1.261 +{
1.262 + Block_count_mask = 0x0000ffff, // NOB/SNOB
1.263 +};
1.264 +
1.265 +// Interrupt mask/flag bits.
1.266 +
1.267 +enum Interrupt_bits : unsigned
1.268 +{
1.269 + // X1600 only.
1.270 +
1.271 + Int_dma_data_done = 0x80000000, // DMA_DATA_DONE
1.272 +
1.273 + // JZ4780 only.
1.274 +
1.275 + Int_auto_cmd23_done = 0x40000000, // AUTO_CMD23_DONE
1.276 + Int_signal_voltage_change = 0x20000000, // SVS
1.277 +
1.278 + // JZ4780/X1600 only.
1.279 +
1.280 + Int_pin_level_field_mask = 0x1f, // PIN_LEVEL
1.281 + Int_pin_level_field_shift = 24,
1.282 +
1.283 + // X1600 only.
1.284 +
1.285 + Int_write_request_all_done = 0x00800000, // WR_ALL_DONE
1.286 +
1.287 + // JZ4780/X1600 only.
1.288 +
1.289 + Int_boot_crc_error = 0x00100000, // BCE
1.290 + Int_boot_data_end = 0x00080000, // BDE
1.291 + Int_boot_ack_error = 0x00040000, // BAE
1.292 + Int_boot_ack_received = 0x00020000, // BAR
1.293 + Int_dma_end = 0x00010000, // DMAEND
1.294 + Int_auto_cmd12_done = 0x00008000, // AUTO_CMD12_DONE
1.295 + Int_data_fifo_full = 0x00004000, // DATA_FIFO_FULL
1.296 + Int_data_fifo_empty = 0x00002000, // DATA_FIFO_EMP
1.297 + Int_crc_response_error = 0x00001000, // CRC_RES_ERR
1.298 + Int_crc_read_error = 0x00000800, // CRC_READ_ERR
1.299 + Int_crc_write_error = 0x00000400, // CRC_WRITE_ERR
1.300 + Int_response_timeout = 0x00000200, // TIME_OUT_RES
1.301 + Int_read_timeout = 0x00000100, // TIME_OUT_READ
1.302 +
1.303 + // Common.
1.304 +
1.305 + Int_sdio = 0x80, // SDIO
1.306 + Int_trans_fifo_write_request = 0x40, // TXFIFO_WR_REQ
1.307 + Int_recv_fifo_read_request = 0x20, // RXFIFO_RD_REQ
1.308 + Int_end_command_response = 0x04, // END_CMD_RES
1.309 + Int_programming_done = 0x02, // PRG_DONE
1.310 + Int_data_transfer_done = 0x01, // DATA_TRAN_DONE
1.311 +};
1.312 +
1.313 +enum Command_index_bits : unsigned
1.314 +{
1.315 + Command_index_mask = 0x0000003f, // CMD_INDEX
1.316 +};
1.317 +
1.318 +enum Command_argument_bits : unsigned
1.319 +{
1.320 + Command_argument_mask = 0xffffffff, // ARG
1.321 +};
1.322 +
1.323 +enum Response_fifo_bits : unsigned
1.324 +{
1.325 + Response_fifo_mask = 0x0000ffff, // DATA
1.326 +};
1.327 +
1.328 +enum Recv_data_fifo_bits : unsigned
1.329 +{
1.330 + Recv_data_fifo_mask = 0xffffffff, // DATA
1.331 +};
1.332 +
1.333 +enum Trans_data_fifo_bits : unsigned
1.334 +{
1.335 + Trans_data_fifo_mask = 0xffffffff, // DATA
1.336 +};
1.337 +
1.338 +enum Low_power_mode_bits : unsigned
1.339 +{
1.340 + Low_power_mode_enable = 0x00000001, // LPM
1.341 +};
1.342 +
1.343 +enum Dma_control_bits : unsigned
1.344 +{
1.345 + Dma_mode_specify_transfer_length = 0x80, // MODE_SEL
1.346 +
1.347 + Dma_address_offset_field_mask = 0x3, // AOFST
1.348 + Dma_address_offset_field_shift = 5,
1.349 +
1.350 + Dma_align_enable = 0x10, // ALIGNEN
1.351 +
1.352 + Dma_burst_type_field_mask = 0x3, // INCR
1.353 + Dma_burst_type_incr16 = 0,
1.354 + Dma_burst_type_incr32 = 1,
1.355 + Dma_burst_type_incr64 = 2,
1.356 + Dma_burst_type_field_shift = 2,
1.357 +
1.358 + Dma_select_common_dma = 0x02, // DMASEL
1.359 + Dma_select_special_dma = 0x00,
1.360 +
1.361 + Dma_enable = 0x01, // DMAEN
1.362 + Dma_disable = 0x00,
1.363 +};
1.364 +
1.365 +
1.366 +
1.367 +// Command indexes.
1.368 +
1.369 +enum Command_index : unsigned
1.370 +{
1.371 + Command_go_idle_state = 0,
1.372 + Command_send_op_cond = 1,
1.373 + Command_all_send_cid = 2,
1.374 + Command_send_relative_addr = 3, // SD
1.375 + Command_set_relative_addr = 3, // MMC
1.376 + Command_set_dsr = 4,
1.377 + Command_io_send_op_cond = 5, // SDIO
1.378 + Command_select_deselect_card = 7,
1.379 + Command_send_if_cond = 8,
1.380 + Command_send_csd = 9,
1.381 + Command_send_cid = 10,
1.382 + Command_read_dat_until_stop = 11,
1.383 + Command_stop_transmission = 12,
1.384 + Command_send_status = 13,
1.385 + Command_go_inactive_state = 15,
1.386 + Command_set_blocklen = 16,
1.387 + Command_read_single_block = 17,
1.388 + Command_read_multiple_block = 18,
1.389 + Command_write_dat_until_stop = 20,
1.390 + Command_set_block_count = 23,
1.391 + Command_write_block = 24,
1.392 + Command_write_multiple_block = 25,
1.393 + Command_program_cid = 26,
1.394 + Command_program_csd = 27,
1.395 + Command_set_write_prot = 28,
1.396 + Command_clr_write_prot = 29,
1.397 + Command_send_write_prot = 30,
1.398 + Command_tag_sector_start = 32,
1.399 + Command_tag_sector_end = 33,
1.400 + Command_untag_sector = 34,
1.401 + Command_tag_erase_group_start = 35,
1.402 + Command_tag_erase_group_end = 36,
1.403 + Command_untag_erase_group = 37,
1.404 + Command_erase = 38,
1.405 + Command_fast_io = 39,
1.406 + Command_go_irq_state = 40,
1.407 + Command_lock_unlock = 42,
1.408 + Command_io_rw_direct = 52, // SDIO
1.409 + Command_app_cmd = 55,
1.410 + Command_gen_cmd = 56,
1.411 +};
1.412 +
1.413 +// Application-specific command indexes, used by first issuing Command_app_cmd.
1.414 +
1.415 +enum App_command_index : unsigned
1.416 +{
1.417 + App_command_set_bus_width = 6,
1.418 + App_command_sd_status = 13,
1.419 + App_command_send_num_wr_blocks = 22,
1.420 + App_command_set_wr_block_erase_count = 23,
1.421 + App_command_sd_send_op_cond = 41,
1.422 + App_command_set_clr_card_detect = 42,
1.423 + App_command_send_scr = 51,
1.424 + App_command_read_ocr = 58,
1.425 +};
1.426 +
1.427 +enum Bus_width_bits : unsigned
1.428 +{
1.429 + Bus_width_1bit = 0,
1.430 + Bus_width_4bit = 2,
1.431 +};
1.432 +
1.433 +// Command response sizes in 16-bit units.
1.434 +
1.435 +enum Response_sizes : unsigned
1.436 +{
1.437 + Response_size_R1 = 3,
1.438 + Response_size_R2 = 8, // omits the CRC and end bit
1.439 + Response_size_R3 = 3,
1.440 + Response_size_R4 = 3,
1.441 + Response_size_R5 = 3,
1.442 + Response_size_R6 = 3,
1.443 + Response_size_R7 = 3,
1.444 +};
1.445 +
1.446 +// SD_SEND_OP_COND argument flags.
1.447 +
1.448 +enum Ocr_argument_flags : unsigned
1.449 +{
1.450 + Ocr_high_capacity_storage = 0x40000000,
1.451 +};
1.452 +
1.453 +// SD_SEND_OP_COND response flags (R3).
1.454 +
1.455 +enum Ocr_response_flags : unsigned
1.456 +{
1.457 + Ocr_card_powered_up = 0x80000000,
1.458 +};
1.459 +
1.460 +// R1 status flags.
1.461 +
1.462 +enum R1_status_flags : unsigned
1.463 +{
1.464 + R1_status_error_mask = 0xffff0000,
1.465 +};
1.466 +
1.467 +
1.468 +
1.469 +// MMC response structures.
1.470 +
1.471 +struct R1
1.472 +{
1.473 + uint8_t end_crc;
1.474 + uint32_t status;
1.475 + uint8_t index:6, trans_start:2;
1.476 +} __attribute__((packed));
1.477 +
1.478 +struct R2
1.479 +{
1.480 + // uint8_t end_crc; (not retrieved)
1.481 +
1.482 + union
1.483 + {
1.484 + uint8_t raw[15];
1.485 + struct CID cid;
1.486 + struct CSD csd;
1.487 + } payload;
1.488 +
1.489 + uint8_t reserved_trans_start;
1.490 +} __attribute__((packed));
1.491 +
1.492 +struct R3
1.493 +{
1.494 + uint8_t end_reserved;
1.495 + uint32_t ocr;
1.496 + uint8_t reserved_trans_start;
1.497 +} __attribute__((packed));
1.498 +
1.499 +// SDIO response structures.
1.500 +
1.501 +struct R4
1.502 +{
1.503 + uint8_t end_reserved;
1.504 + uint32_t ocr:24, stuff:3, memory_present:1, number_io_functions:3, ready:1;
1.505 + uint8_t reserved_trans_start;
1.506 +} __attribute__((packed));
1.507 +
1.508 +struct R5
1.509 +{
1.510 + uint8_t end_crc;
1.511 + uint8_t data;
1.512 + uint8_t out_of_range:1, invalid_function_number:1, reserved:1, error:1,
1.513 + io_current_state:2, illegal_command:1, crc_error:1;
1.514 + uint16_t stuff;
1.515 + uint8_t index:6, trans_start:2;
1.516 +} __attribute__((packed));
1.517 +
1.518 +struct R6
1.519 +{
1.520 + uint8_t end_crc;
1.521 + uint16_t status;
1.522 + uint16_t rca;
1.523 + uint8_t index:6, trans_start:2;
1.524 +} __attribute__((packed));
1.525 +
1.526 +struct R7
1.527 +{
1.528 + uint8_t end_crc;
1.529 +
1.530 + union
1.531 + {
1.532 + uint32_t check:8, voltage:4, reserved:20;
1.533 + uint32_t raw;
1.534 + } check_voltage;
1.535 +
1.536 + uint8_t index:6, trans_start:2;
1.537 +} __attribute__((packed));
1.538 +
1.539 +
1.540 +
1.541 +// Command frame:
1.542 +// byte: start (1), direction (1), command (6)
1.543 +// 4 bytes: argument
1.544 +// byte: CRC (7), end (1)
1.545 +
1.546 +// IO_RW_DIRECT argument:
1.547 +// Argument MSB to LSB: R/W (1), function number (3), read after write flag (1),
1.548 +// stuff (1), register address (17), stuff (1),
1.549 +// write data or stuff (8)
1.550 +// 0x88000c08: W, function = 0, read after write, register address = 6 (CCCR),
1.551 +// data = 8 (reset)
1.552 +
1.553 +const uint32_t Io_rw_direct_reset = 0x88000c08;
1.554 +
1.555 +// (IO_)SEND_OP_COND argument and default voltage range expected in R3, R4:
1.556 +// Argument MSB to LSB: stuff (8), voltage range (16), reserved (8)
1.557 +// 0x00ff8000: voltage range 2.7 - 3.6V
1.558 +
1.559 +const uint32_t Ocr_default_voltage_range = 0x00ff8000;
1.560 +
1.561 +// SEND_IF_COND argument and default voltage range expected in R7:
1.562 +// Argument MSB to LSB: stuff (20), voltage supplied (4), check (8)
1.563 +// 0x000001aa: voltage range 2.7 - 3.6V, check = 0b10101010
1.564 +
1.565 +const uint32_t If_cond_default_voltage_range = 0x000001aa;
1.566 +
1.567 +
1.568 +
1.569 +// Channel abstraction.
1.570 +
1.571 +Msc_channel::Msc_channel(l4_addr_t msc_start, l4_addr_t addr, l4_cap_idx_t irq)
1.572 +: _msc_start(msc_start), _irq(irq)
1.573 +{
1.574 + _regs = new Hw::Mmio_register_block<32>(addr);
1.575 +}
1.576 +
1.577 +Msc_channel::~Msc_channel()
1.578 +{
1.579 +}
1.580 +
1.581 +// Utility methods.
1.582 +// NOTE: Also defined in the CPM abstraction, should be consolidated.
1.583 +
1.584 +uint32_t
1.585 +Msc_channel::get_field(uint32_t reg, uint32_t mask, uint8_t shift)
1.586 +{
1.587 + return (_regs[reg] & (mask << shift)) >> shift;
1.588 +}
1.589 +
1.590 +void
1.591 +Msc_channel::set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value)
1.592 +{
1.593 + _regs[reg] = (_regs[reg] & (~(mask << shift))) | ((mask & value) << shift);
1.594 +}
1.595 +
1.596 +bool
1.597 +Msc_channel::command_will_write(uint8_t index)
1.598 +{
1.599 + // NOTE: Probably incomplete coverage.
1.600 +
1.601 + switch (index)
1.602 + {
1.603 + case Command_write_dat_until_stop: return true;
1.604 + case Command_write_block: return true;
1.605 + case Command_write_multiple_block: return true;
1.606 + case Command_program_cid: return true;
1.607 + case Command_program_csd: return true;
1.608 + case Command_lock_unlock: return true;
1.609 + default: return false;
1.610 + }
1.611 +}
1.612 +
1.613 +bool
1.614 +Msc_channel::command_with_data(uint8_t index)
1.615 +{
1.616 + // NOTE: Probably incomplete coverage.
1.617 +
1.618 + switch (index)
1.619 + {
1.620 + case Command_read_dat_until_stop: return true;
1.621 + case Command_read_single_block: return true;
1.622 + case Command_read_multiple_block: return true;
1.623 + case Command_write_dat_until_stop: return true;
1.624 + case Command_write_block: return true;
1.625 + case Command_write_multiple_block: return true;
1.626 + case Command_program_cid: return true;
1.627 + case Command_program_csd: return true;
1.628 + case Command_lock_unlock: return true;
1.629 + default: return false;
1.630 + }
1.631 +}
1.632 +
1.633 +bool
1.634 +Msc_channel::command_uses_busy(uint8_t index)
1.635 +{
1.636 + // NOTE: Probably incomplete coverage.
1.637 +
1.638 + switch (index)
1.639 + {
1.640 + case Command_select_deselect_card: return true;
1.641 + case Command_stop_transmission: return true;
1.642 + default: return false;
1.643 + }
1.644 +}
1.645 +
1.646 +uint8_t
1.647 +Msc_channel::get_response_format(uint8_t index)
1.648 +{
1.649 + // NOTE: Probably incomplete coverage.
1.650 +
1.651 + switch (index)
1.652 + {
1.653 + // Common commands without response.
1.654 +
1.655 + case Command_go_idle_state: return 0;
1.656 + case Command_set_dsr: return 0;
1.657 + case Command_go_inactive_state: return 0;
1.658 +
1.659 + // Common commands with response.
1.660 +
1.661 + case Command_send_op_cond: return 3;
1.662 + case Command_all_send_cid: return 2;
1.663 + case Command_send_csd: return 2;
1.664 + case Command_send_cid: return 2;
1.665 +
1.666 + // SDIO only.
1.667 +
1.668 + case Command_io_send_op_cond: return 4;
1.669 + case Command_io_rw_direct: return 5;
1.670 +
1.671 + // SDMEM only.
1.672 +
1.673 + case Command_send_relative_addr: return 6;
1.674 + case Command_send_if_cond: return 7;
1.675 +
1.676 + // All other commands.
1.677 +
1.678 + default: return 1;
1.679 + }
1.680 +}
1.681 +
1.682 +uint8_t
1.683 +Msc_channel::get_app_response_format(uint8_t index)
1.684 +{
1.685 + // NOTE: Probably incomplete coverage.
1.686 +
1.687 + switch (index)
1.688 + {
1.689 + // SDMEM only.
1.690 +
1.691 + case App_command_sd_send_op_cond: return 3;
1.692 +
1.693 + // All other commands.
1.694 +
1.695 + default: return 1;
1.696 + }
1.697 +}
1.698 +
1.699 +// Read a response directly from the FIFO.
1.700 +
1.701 +void
1.702 +Msc_channel::read_response(uint16_t *buffer, uint8_t units)
1.703 +{
1.704 + uint8_t unit = units;
1.705 +
1.706 + while (unit > 0)
1.707 + {
1.708 + uint32_t data = _regs[Msc_response_fifo];
1.709 +
1.710 + // Ignore the upper byte of the last unit in small transfers since it is the
1.711 + // lower byte from the previous unit not shifted out of the register.
1.712 +
1.713 + unit--;
1.714 +
1.715 + if ((unit == 0) && (units == 3))
1.716 + buffer[unit] = (data & 0xff) << 8;
1.717 + else
1.718 + buffer[unit] = data;
1.719 + }
1.720 +}
1.721 +
1.722 +void
1.723 +Msc_channel::ack_irq(uint32_t flags)
1.724 +{
1.725 + // Clear the flags by setting them.
1.726 +
1.727 + _regs[Msc_interrupt_flag] = _regs[Msc_interrupt_flag] | flags;
1.728 +}
1.729 +
1.730 +void
1.731 +Msc_channel::unmask_irq(uint32_t flags)
1.732 +{
1.733 + ack_irq(flags);
1.734 +
1.735 + if (_regs[Msc_interrupt_mask] & flags)
1.736 + _regs[Msc_interrupt_mask] = _regs[Msc_interrupt_mask] & ~flags;
1.737 +}
1.738 +
1.739 +void
1.740 +Msc_channel::reset()
1.741 +{
1.742 + _regs[Msc_control] = _regs[Msc_control] | Control_reset;
1.743 +
1.744 + // NOTE: X1600 and other recent SoCs only.
1.745 +
1.746 + _regs[Msc_control] = _regs[Msc_control] & ~Control_reset;
1.747 +
1.748 + // Sufficient for other SoCs...
1.749 +
1.750 + while (_regs[Msc_status] & Status_resetting);
1.751 +}
1.752 +
1.753 +void
1.754 +Msc_channel::start_clock()
1.755 +{
1.756 + set_field(Msc_control, Control_clock_control_field_mask,
1.757 + Control_clock_control_field_shift, Control_clock_control_start);
1.758 +
1.759 + while (!(_regs[Msc_status] & Status_clock_enabled));
1.760 +}
1.761 +
1.762 +void
1.763 +Msc_channel::stop_clock()
1.764 +{
1.765 + set_field(Msc_control, Control_clock_control_field_mask,
1.766 + Control_clock_control_field_shift, Control_clock_control_stop);
1.767 +
1.768 + while (_regs[Msc_status] & Status_clock_enabled);
1.769 +}
1.770 +
1.771 +uint32_t
1.772 +Msc_channel::get_status()
1.773 +{
1.774 + return _regs[Msc_status];
1.775 +}
1.776 +
1.777 +// Send an application-specific command.
1.778 +
1.779 +bool
1.780 +Msc_channel::send_app_command(uint8_t index, uint32_t arg)
1.781 +{
1.782 + if (!send_command(Command_app_cmd, 0, get_app_response_format(index),
1.783 + false, false, false))
1.784 + return false;
1.785 +
1.786 + return send_command(index, arg);
1.787 +}
1.788 +
1.789 +// Send a common MMC/SD command.
1.790 +
1.791 +bool
1.792 +Msc_channel::send_command(uint8_t index, uint32_t arg)
1.793 +{
1.794 + return send_command(index, arg, get_response_format(index),
1.795 + command_with_data(index), command_will_write(index),
1.796 + command_uses_busy(index));
1.797 +}
1.798 +
1.799 +// Initiate a command having the given index and using the given argument,
1.800 +// employing the specified response format and involving a data transfer if
1.801 +// indicated.
1.802 +
1.803 +bool
1.804 +Msc_channel::send_command(uint8_t index, uint32_t arg, uint8_t response_format,
1.805 + bool data, bool write, bool busy)
1.806 +{
1.807 + stop_clock();
1.808 +
1.809 + // Enable DMA for data transfers.
1.810 + // NOTE: Needed for JZ4780 and later SoCs.
1.811 +
1.812 + _regs[Msc_dma_control] = (data ? Dma_select_common_dma | Dma_enable : Dma_disable);
1.813 +
1.814 + // Set the command index and argument.
1.815 +
1.816 + _regs[Msc_command_index] = index;
1.817 + _regs[Msc_command_argument] = arg;
1.818 +
1.819 + // Configure the response format and data bus width.
1.820 +
1.821 + set_field(Msc_command_data_control, Cdc_response_format_field_mask,
1.822 + Cdc_response_format_field_shift, response_format);
1.823 +
1.824 + // NOTE: May need to set the SD bus width.
1.825 +
1.826 + set_field(Msc_command_data_control, Cdc_bus_width_field_mask,
1.827 + Cdc_bus_width_field_shift, Cdc_bus_width_field_1bit);
1.828 +
1.829 + set_field(Msc_command_data_control, Cdc_recv_fifo_level_field_mask,
1.830 + Cdc_recv_fifo_level_field_shift, Cdc_fifo_level_16);
1.831 +
1.832 + set_field(Msc_command_data_control, Cdc_trans_fifo_level_field_mask,
1.833 + Cdc_trans_fifo_level_field_shift, Cdc_fifo_level_16);
1.834 +
1.835 + // Set and clear control bits appropriate to the command.
1.836 + // NOTE: Pre-JZ4780 SoCs enable DMA in this register.
1.837 +
1.838 + _regs[Msc_command_data_control] = _regs[Msc_command_data_control] |
1.839 + // (data ? Cdc_dma_enable : Cdc_dma_disable) |
1.840 + (busy ? Cdc_expect_busy : Cdc_do_not_expect_busy) |
1.841 + (data ? Cdc_data_with_command : Cdc_no_data_with_command) |
1.842 + (write ? Cdc_write_operation : Cdc_read_operation);
1.843 +
1.844 + _regs[Msc_command_data_control] = _regs[Msc_command_data_control] &
1.845 + ~(
1.846 + // (data ? Cdc_dma_disable : Cdc_dma_enable) |
1.847 + (busy ? Cdc_do_not_expect_busy : Cdc_expect_busy) |
1.848 + (data ? Cdc_no_data_with_command : Cdc_data_with_command) |
1.849 + (write ? Cdc_read_operation : Cdc_write_operation) |
1.850 + Cdc_stream_block | Cdc_init_sequence);
1.851 +
1.852 + // Unmask interrupts, start the clock, then initiate the command.
1.853 +
1.854 + uint32_t flags = Int_end_command_response | Int_response_timeout;
1.855 +
1.856 + unmask_irq(flags);
1.857 + start_clock();
1.858 +
1.859 + _regs[Msc_control] = _regs[Msc_control] | Control_start_operation;
1.860 +
1.861 + // Wait for command completion.
1.862 +
1.863 + if (!wait_for_irq(flags))
1.864 + return false;
1.865 +
1.866 + // Determine whether a timeout occurred.
1.867 +
1.868 + bool have_response = !(_regs[Msc_interrupt_flag] & Int_response_timeout);
1.869 +
1.870 + // Acknowledge the interrupts and return the status.
1.871 +
1.872 + ack_irq(flags);
1.873 + return have_response;
1.874 +}
1.875 +
1.876 +void
1.877 +Msc_channel::enable()
1.878 +{
1.879 + // NOTE: X1600 and other recent SoCs only.
1.880 +
1.881 + _regs[Msc_low_power_mode] = _regs[Msc_low_power_mode] & ~Low_power_mode_enable;
1.882 +
1.883 + stop_clock();
1.884 + reset();
1.885 +
1.886 + // Slow the clock for initialisation.
1.887 + // NOTE: Should use the CPM module to deduce the appropriate divider value.
1.888 +
1.889 + set_field(Msc_clock_rate, Clock_rate_field_mask, Clock_rate_field_shift, 7);
1.890 +
1.891 + send_command(Command_go_idle_state, 0);
1.892 +
1.893 + if (check_sd())
1.894 + {
1.895 + init_sdio();
1.896 + init_sdmem();
1.897 + }
1.898 +
1.899 + init_mmc();
1.900 + identify_cards();
1.901 + query_cards();
1.902 +
1.903 + // Restore the clock.
1.904 + // NOTE: Should use the CPM module to deduce the appropriate divider value.
1.905 +
1.906 + set_field(Msc_clock_rate, Clock_rate_field_mask, Clock_rate_field_shift, 1);
1.907 +
1.908 + _current_rca = 0;
1.909 +}
1.910 +
1.911 +// Check the voltage range of the SD card, potentially establishing that it is
1.912 +// a high capacity card. Return false if the voltage range is incompatible.
1.913 +
1.914 +bool
1.915 +Msc_channel::check_sd()
1.916 +{
1.917 + uint16_t buffer[Response_size_R7];
1.918 + struct R7 *r = (struct R7 *) buffer;
1.919 +
1.920 + // Send an interface condition command.
1.921 + // A card may not respond to this command.
1.922 +
1.923 + if (!send_command(Command_send_if_cond, If_cond_default_voltage_range))
1.924 + return true;
1.925 +
1.926 + read_response(buffer, Response_size_R7);
1.927 +
1.928 + // Reject any card not supporting the default voltage range.
1.929 +
1.930 + if (r->check_voltage.raw != If_cond_default_voltage_range)
1.931 + return false;
1.932 +
1.933 + return true;
1.934 +}
1.935 +
1.936 +// Check the voltage range of the SDIO card, inactivating it if incompatible.
1.937 +
1.938 +void
1.939 +Msc_channel::init_sdio()
1.940 +{
1.941 + uint16_t buffer[Response_size_R4];
1.942 + struct R4 *r = (struct R4 *) buffer;
1.943 + uint32_t ocr = 0;
1.944 +
1.945 + // Reset any SDIO card or IO unit in a combined memory/IO card.
1.946 + // A non-SDIO card may not respond to this command.
1.947 +
1.948 + if (!send_command(Command_io_rw_direct, Io_rw_direct_reset))
1.949 + return;
1.950 +
1.951 + // Attempt to assert the operating conditions.
1.952 +
1.953 + do
1.954 + {
1.955 + // Obtain OCR (operating conditions register) values for any IO card.
1.956 + // Without a response, the card may have inactivated itself due to voltage
1.957 + // range incompatibility reasons.
1.958 +
1.959 + if (!send_command(Command_io_send_op_cond, ocr))
1.960 + return;
1.961 +
1.962 + read_response(buffer, Response_size_R4);
1.963 +
1.964 + // Finish if no IO functions provided.
1.965 + // NOTE: Should only need to check this the first time.
1.966 +
1.967 + if (r->number_io_functions == 0)
1.968 + return;
1.969 +
1.970 + if (r->ocr != Ocr_default_voltage_range)
1.971 + {
1.972 + ocr = Ocr_default_voltage_range;
1.973 + continue;
1.974 + }
1.975 + }
1.976 + while (!r->ready);
1.977 +}
1.978 +
1.979 +void
1.980 +Msc_channel::init_sdmem()
1.981 +{
1.982 + uint16_t buffer[Response_size_R3];
1.983 + struct R3 *r = (struct R3 *) buffer;
1.984 +
1.985 + // Incorporate the HCS bit into the OCR for SDMEM.
1.986 +
1.987 + uint32_t ocr = Ocr_high_capacity_storage;
1.988 +
1.989 + do
1.990 + {
1.991 + if (!send_app_command(App_command_sd_send_op_cond, ocr))
1.992 + return;
1.993 +
1.994 + read_response(buffer, Response_size_R3);
1.995 +
1.996 + if (r->ocr != Ocr_default_voltage_range)
1.997 + {
1.998 + ocr = Ocr_default_voltage_range | Ocr_high_capacity_storage;
1.999 + continue;
1.1000 + }
1.1001 + }
1.1002 + while (!(r->ocr & Ocr_card_powered_up));
1.1003 +}
1.1004 +
1.1005 +void
1.1006 +Msc_channel::init_mmc()
1.1007 +{
1.1008 + // Obtain OCR (operating conditions register) values for each card using
1.1009 + // send_op_cond command variants without argument, or assert operating
1.1010 + // conditions with argument to avoid handling card responses. Where responses
1.1011 + // are solicited, the host must determine a suitable argument and reissue the
1.1012 + // command.
1.1013 +
1.1014 + uint16_t buffer[Response_size_R3];
1.1015 + struct R3 *r = (struct R3 *) buffer;
1.1016 + uint32_t ocr = 0;
1.1017 +
1.1018 + do
1.1019 + {
1.1020 + if (!send_command(Command_send_op_cond, ocr))
1.1021 + return;
1.1022 +
1.1023 + read_response(buffer, Response_size_R3);
1.1024 +
1.1025 + if (r->ocr != Ocr_default_voltage_range)
1.1026 + {
1.1027 + ocr = Ocr_default_voltage_range;
1.1028 + continue;
1.1029 + }
1.1030 + }
1.1031 + while (!(r->ocr & Ocr_card_powered_up));
1.1032 +}
1.1033 +
1.1034 +void
1.1035 +Msc_channel::identify_cards()
1.1036 +{
1.1037 + uint16_t buffer[Response_size_R2];
1.1038 + struct R2 *r = (struct R2 *) buffer;
1.1039 +
1.1040 + _cards = 0;
1.1041 +
1.1042 + while (send_command(Command_all_send_cid, 0))
1.1043 + {
1.1044 + read_response(buffer, Response_size_R2);
1.1045 +
1.1046 + memcpy(&_cid[_cards], r->payload.raw, sizeof(r->payload.raw));
1.1047 +
1.1048 + printf("card: %d\n", _cards);
1.1049 + printf("date: %d %d\n", r->payload.cid.month, r->payload.cid.year);
1.1050 + printf("serial: %d\n", r->payload.cid.serial);
1.1051 + printf("revision: %d\n", r->payload.cid.revision);
1.1052 + printf("name: %c%c%c%c%c\n", r->payload.cid.name[4], r->payload.cid.name[3],
1.1053 + r->payload.cid.name[2], r->payload.cid.name[1],
1.1054 + r->payload.cid.name[0]);
1.1055 + printf("oem: %d\n", r->payload.cid.oem);
1.1056 + printf("manufacturer: %d\n", r->payload.cid.manufacturer);
1.1057 +
1.1058 + // Try and obtain a card-issued address.
1.1059 +
1.1060 + if (send_command(Command_send_relative_addr, 0))
1.1061 + {
1.1062 + uint16_t addr_buffer[Response_size_R6];
1.1063 + struct R6 *ar = (struct R6 *) addr_buffer;
1.1064 +
1.1065 + read_response(addr_buffer, Response_size_R6);
1.1066 +
1.1067 + memcpy(&_rca[_cards], &ar->rca, sizeof(ar->rca));
1.1068 + }
1.1069 +
1.1070 + // Try and assign an address.
1.1071 + // Employ 1-based relative addressing.
1.1072 +
1.1073 + else if (send_command(Command_set_relative_addr, _cards + 1))
1.1074 + _rca[_cards] = _cards + 1;
1.1075 +
1.1076 + // Otherwise, stop identification.
1.1077 +
1.1078 + else
1.1079 + return;
1.1080 +
1.1081 + _cards++;
1.1082 + }
1.1083 +}
1.1084 +
1.1085 +void
1.1086 +Msc_channel::query_cards()
1.1087 +{
1.1088 + uint16_t buffer[Response_size_R2];
1.1089 + struct R2 *r = (struct R2 *) buffer;
1.1090 + uint8_t card;
1.1091 +
1.1092 + for (card = 0; card < _cards; card++)
1.1093 + {
1.1094 + // Employ 1-based relative addressing.
1.1095 +
1.1096 + if (!send_command(Command_send_csd, _rca[card] << 16))
1.1097 + return;
1.1098 +
1.1099 + read_response(buffer, Response_size_R2);
1.1100 +
1.1101 + memcpy(&_csd[card], r->payload.raw, sizeof(r->payload.raw));
1.1102 +
1.1103 + printf("card: %d\n", card);
1.1104 + printf("csd: %d\n", r->payload.csd.csd);
1.1105 + printf("copy: %s\n", r->payload.csd.copy ? "copied" : "original");
1.1106 + printf("card command classes: %03x\n", r->payload.csd.card_command_classes);
1.1107 + printf("device (size multiplier): %d %d\n", r->payload.csd.device_size + 1,
1.1108 + 1 << (r->payload.csd.device_size_multiplier + 2));
1.1109 + printf("device size: %d\n", (1 << r->payload.csd.read_blocklen) *
1.1110 + (r->payload.csd.device_size + 1) *
1.1111 + (1 << (r->payload.csd.device_size_multiplier + 2)));
1.1112 + printf("transfer speed: %d MHz\n", r->payload.csd.tran_speed == 0x32 ? 25 : 50);
1.1113 + printf("format group: %d %d\n", r->payload.csd.format, r->payload.csd.format_group);
1.1114 + printf("write time factor: %d\n", 1 << r->payload.csd.write_time_factor);
1.1115 + printf("write protect (temp perm): %s %s\n", r->payload.csd.temp_write_prot ? "yes" : "no",
1.1116 + r->payload.csd.perm_write_prot ? "yes" : "no");
1.1117 + printf("write protect group (enable size): %s %d\n", r->payload.csd.write_prot_group_enable ? "yes" : "no",
1.1118 + r->payload.csd.write_prot_group_size + 1);
1.1119 + printf("write block (partial length): %s %d\n", r->payload.csd.write_block_partial ? "yes" : "no",
1.1120 + 1 << r->payload.csd.write_blocklen);
1.1121 + printf("read block (partial length): %s %d\n", r->payload.csd.read_block_partial ? "yes" : "no",
1.1122 + 1 << r->payload.csd.read_blocklen);
1.1123 + printf("erase: sector single: %d %s\n", r->payload.csd.erase_sector_size + 1,
1.1124 + r->payload.csd.erase_single_block_enable ? "yes" : "no");
1.1125 + printf("misalign: read write: %s %s\n", r->payload.csd.read_block_misalign ? "yes" : "no",
1.1126 + r->payload.csd.write_block_misalign ? "yes" : "no");
1.1127 + printf("max read current (min max): %d %d\n", r->payload.csd.max_read_current_min,
1.1128 + r->payload.csd.max_read_current_max);
1.1129 + printf("max write current (min max): %d %d\n", r->payload.csd.max_write_current_min,
1.1130 + r->payload.csd.max_write_current_max);
1.1131 + printf("read access time (1 2): %d %d\n", r->payload.csd.data_read_access_time_1,
1.1132 + r->payload.csd.data_read_access_time_2);
1.1133 + printf("DSR: %s\n", r->payload.csd.dsr_implemented ? "yes" : "no");
1.1134 + }
1.1135 +}
1.1136 +
1.1137 +uint32_t
1.1138 +Msc_channel::recv_data(l4re_dma_space_dma_addr_t paddr, uint32_t count)
1.1139 +{
1.1140 + return transfer(_msc_start + Msc_recv_data_fifo, paddr, true, count);
1.1141 +}
1.1142 +
1.1143 +uint32_t
1.1144 +Msc_channel::send_data(l4re_dma_space_dma_addr_t paddr, uint32_t count)
1.1145 +{
1.1146 + return transfer(paddr, _msc_start + Msc_trans_data_fifo, false, count);
1.1147 +}
1.1148 +
1.1149 +uint32_t
1.1150 +Msc_channel::read_block(uint8_t card, l4re_dma_space_dma_addr_t paddr)
1.1151 +{
1.1152 + uint32_t block_size = 1 << _csd[card].read_blocklen;
1.1153 + uint16_t buffer[Response_size_R1];
1.1154 + struct R1 *r = (struct R1 *) buffer;
1.1155 +
1.1156 + //printf("read_block: card %d -> %d\n", card, _rca[card]);
1.1157 +
1.1158 + // Select the requested card.
1.1159 +
1.1160 + if (_current_rca != _rca[card])
1.1161 + {
1.1162 + if (!send_command(Command_select_deselect_card, _rca[card] << 16))
1.1163 + return 0;
1.1164 +
1.1165 + read_response(buffer, Response_size_R1);
1.1166 +
1.1167 + if (r->status & R1_status_error_mask)
1.1168 + return 0;
1.1169 +
1.1170 + _current_rca = _rca[card];
1.1171 + }
1.1172 +
1.1173 +#if 0
1.1174 + // NOTE: SMEM cards should allow bus width setting.
1.1175 + // NOTE: SDIO cards have their bus width set in CCCR via CMD52.
1.1176 +
1.1177 + printf("set bus width -> %s\n",
1.1178 + send_app_command(App_command_set_bus_width, Bus_width_4bit) ? "set" : "not set");
1.1179 +#endif
1.1180 +
1.1181 + if (!send_command(Command_set_blocklen, block_size))
1.1182 + return 0;
1.1183 +
1.1184 + read_response(buffer, Response_size_R1);
1.1185 +
1.1186 + if (r->status & R1_status_error_mask)
1.1187 + return 0;
1.1188 +
1.1189 + // Apply block count and size properties to the issued command.
1.1190 +
1.1191 + _regs[Msc_block_count] = 1;
1.1192 + _regs[Msc_block_length] = block_size;
1.1193 +
1.1194 + // NOTE: Support an actual address.
1.1195 + // NOTE: Where CCS = 0, byte addressing is used. Otherwise, block addressing is used.
1.1196 +
1.1197 + if (!send_command(Command_read_single_block, 0))
1.1198 + return 0;
1.1199 +
1.1200 + read_response(buffer, Response_size_R1);
1.1201 +
1.1202 + if (r->status & R1_status_error_mask)
1.1203 + return 0;
1.1204 +
1.1205 + return recv_data(paddr, block_size);
1.1206 +}
1.1207 +
1.1208 +// Wait indefinitely for an interrupt request, returning true if one was delivered.
1.1209 +
1.1210 +bool
1.1211 +Msc_channel::wait_for_irq(uint32_t flags)
1.1212 +{
1.1213 + return !l4_error(l4_irq_receive(_irq, L4_IPC_NEVER)) &&
1.1214 + (_regs[Msc_interrupt_flag] & flags);
1.1215 +}
1.1216 +
1.1217 +// Wait up to the given timeout (in microseconds) for an interrupt request,
1.1218 +// returning true if one was delivered.
1.1219 +
1.1220 +bool
1.1221 +Msc_channel::wait_for_irq(uint32_t flags, unsigned int timeout)
1.1222 +{
1.1223 + return !l4_error(l4_irq_receive(_irq, l4_timeout(L4_IPC_TIMEOUT_NEVER,
1.1224 + l4util_micros2l4to(timeout)))) &&
1.1225 + (_regs[Msc_interrupt_flag] & flags);
1.1226 +}
1.1227 +
1.1228 +
1.1229 +
1.1230 +// Peripheral abstraction.
1.1231 +
1.1232 +Msc_chip::Msc_chip(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end)
1.1233 +: _msc_start(msc_start), _start(start), _end(end)
1.1234 +{
1.1235 +}