# HG changeset patch # User Paul Boddie # Date 1708207452 -3600 # Node ID 0299f4644db040e4ebbf216eb124840f3f166882 # Parent 18edc9c73263311ff180a612d33aa21a3b9001cf Introduced a common DMA region structure. Added clock frequency control to the MSC channel abstraction, along with adaptation to individual card speeds and some handling of different hardware behaviour (X1600 reset). diff -r 18edc9c73263 -r 0299f4644db0 pkg/devices/lcd/include/lcd-device.h --- a/pkg/devices/lcd/include/lcd-device.h Fri Feb 16 23:11:25 2024 +0100 +++ b/pkg/devices/lcd/include/lcd-device.h Sat Feb 17 23:04:12 2024 +0100 @@ -1,7 +1,7 @@ /* * LCD device support. * - * Copyright (C) 2018, 2020, 2023 Paul Boddie + * Copyright (C) 2018, 2020, 2023, 2024 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -21,6 +21,7 @@ #pragma once +#include #include #include @@ -45,14 +46,10 @@ Activation *_display; - /* Framebuffer virtual and physical addresses. */ + /* Framebuffer region providing virtual and physical addresses plus the memory + capability for the framebuffer. */ - l4_addr_t fb_vaddr; - l4re_dma_space_dma_addr_t fb_paddr; - - /* Memory capability for the framebuffer. */ - - l4re_ds_t _fbmem; + struct dma_region _fb_region; /* Display operations. */ @@ -66,18 +63,21 @@ : _chip(chip), _display(display) { /* Subclasses must set up any memory. */ + + _fb_region.vaddr = 0; + _fb_region.mem = L4_INVALID_CAP; } /* Framebuffer operations. */ virtual l4_addr_t get_framebuffer() { - return fb_vaddr; + return _fb_region.vaddr; } virtual l4re_ds_t get_framebuffer_cap() { - return _fbmem; + return _fb_region.mem; } /* Querying operations. */ diff -r 18edc9c73263 -r 0299f4644db0 pkg/devices/lcd/include/lcd-jz4740-device.h --- a/pkg/devices/lcd/include/lcd-jz4740-device.h Fri Feb 16 23:11:25 2024 +0100 +++ b/pkg/devices/lcd/include/lcd-jz4740-device.h Sat Feb 17 23:04:12 2024 +0100 @@ -1,7 +1,7 @@ /* * LCD device support for the JZ4740 and related SoCs. * - * Copyright (C) 2018, 2023 Paul Boddie + * Copyright (C) 2018, 2023, 2024 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -38,10 +38,9 @@ class Lcd_jz4740_device : public Lcd_device { - /* DMA descriptor virtual and physical addresses. */ + /* DMA region providing the DMA descriptor virtual and physical addresses. */ - l4_addr_t desc_vaddr; - l4re_dma_space_dma_addr_t desc_paddr; + struct dma_region _desc_region; protected: /* Device-specific memory allocation. */ diff -r 18edc9c73263 -r 0299f4644db0 pkg/devices/lcd/src/jz4740/lcd-jz4740-device.cc --- a/pkg/devices/lcd/src/jz4740/lcd-jz4740-device.cc Fri Feb 16 23:11:25 2024 +0100 +++ b/pkg/devices/lcd/src/jz4740/lcd-jz4740-device.cc Sat Feb 17 23:04:12 2024 +0100 @@ -1,7 +1,7 @@ /* * Common LCD device support for the JZ4740 and related SoCs. * - * Copyright (C) 2018, 2020, 2021, 2023 Paul Boddie + * Copyright (C) 2018, 2020, 2021, 2023, 2024 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -104,9 +104,9 @@ // Configure the controller. chip->disable(); - chip->config((struct Jz4740_lcd_descriptor *) desc_vaddr, - (struct Jz4740_lcd_descriptor *) desc_paddr, - fb_paddr); + chip->config((struct Jz4740_lcd_descriptor *) _desc_region.vaddr, + (struct Jz4740_lcd_descriptor *) _desc_region.paddr, + _fb_region.paddr); // Activate the display channel. @@ -125,7 +125,7 @@ { // Test for existing setup. - if (fb_vaddr) + if (_fb_region.vaddr) return 0; // Obtain the memory requirements. @@ -140,14 +140,13 @@ // Allocate memory for the framebuffer at 2**8 == 256 byte == 64 word // alignment, with 2**6 == 64 byte == 16 word alignment for the descriptors. - long err = get_dma_region(fb_size, 8, &fb_vaddr, &fb_paddr, &_fbmem); + struct dma_region region; + long err = get_dma_region(fb_size, 8, &_fb_region); if (err) return 1; - l4_cap_idx_t descmem; - - err = get_dma_region(desc_size, 6, &desc_vaddr, &desc_paddr, &descmem); + err = get_dma_region(desc_size, 6, &_desc_region); if (err) return 1; diff -r 18edc9c73263 -r 0299f4644db0 pkg/devices/lib/msc/include/msc-common.h --- a/pkg/devices/lib/msc/include/msc-common.h Fri Feb 16 23:11:25 2024 +0100 +++ b/pkg/devices/lib/msc/include/msc-common.h Sat Feb 17 23:04:12 2024 +0100 @@ -21,8 +21,10 @@ #pragma once +#include +#include +#include #include -#include #include #include @@ -42,6 +44,8 @@ l4_addr_t _msc_start; Hw::Register_block<32> _regs; l4_cap_idx_t _irq; + Cpm_chip *_cpm; + enum Clock_identifiers _clock; // Support eight cards. @@ -58,7 +62,10 @@ void ack_irq(uint32_t flags); void unmask_irq(uint32_t flags); - void reset(); + + virtual void reset(); + + bool set_clock_frequency(uint64_t frequency); void start_clock(); void stop_clock(); @@ -99,15 +106,16 @@ // Transfer operations. - uint32_t recv_data(l4re_dma_space_dma_addr_t paddr, uint32_t count); - uint32_t send_data(l4re_dma_space_dma_addr_t paddr, uint32_t count); + uint32_t recv_data(struct dma_region *region, uint32_t count); + uint32_t send_data(struct dma_region *region, uint32_t count); virtual uint32_t transfer(l4re_dma_space_dma_addr_t from_paddr, l4re_dma_space_dma_addr_t to_paddr, bool recv, uint32_t count) = 0; public: - explicit Msc_channel(l4_addr_t msc_start, l4_addr_t start, l4_cap_idx_t irq); + explicit Msc_channel(l4_addr_t msc_start, l4_addr_t start, l4_cap_idx_t irq, + Cpm_chip *cpm, enum Clock_identifiers clock); virtual ~Msc_channel(); @@ -117,7 +125,7 @@ uint8_t num_cards(); - uint32_t read_blocks(uint8_t card, l4re_dma_space_dma_addr_t paddr, + uint32_t read_blocks(uint8_t card, struct dma_region *region, uint32_t block_address, uint32_t block_count); }; @@ -129,11 +137,13 @@ { protected: l4_addr_t _msc_start, _start, _end; + Cpm_chip *_cpm; virtual unsigned int num_channels() = 0; public: - explicit Msc_chip(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end); + explicit Msc_chip(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end, + Cpm_chip *cpm); }; #endif /* __cplusplus */ diff -r 18edc9c73263 -r 0299f4644db0 pkg/devices/lib/msc/include/msc-defs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/msc/include/msc-defs.h Sat Feb 17 23:04:12 2024 +0100 @@ -0,0 +1,530 @@ +/* + * MSC (MMC/SD controller) peripheral support. + * + * Copyright (C) 2024 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include + + + +// Register locations for each channel. + +enum Regs : unsigned +{ + Msc_control = 0x000, // MSC_CTRL + Msc_status = 0x004, // MSC_STAT + Msc_clock_rate = 0x008, // MSC_CLKRT + Msc_command_data_control = 0x00c, // MSC_CMDAT + Msc_response_timeout = 0x010, // MSC_RESTO + Msc_read_timeout = 0x014, // MSC_RDTO + Msc_block_length = 0x018, // MSC_BLKLEN + Msc_block_count = 0x01c, // MSC_NOB + Msc_block_success_count = 0x020, // MSC_SNOB + Msc_interrupt_mask = 0x024, // MSC_IMASK + Msc_interrupt_flag = 0x028, // MSC_IFLG/MSC_IREG + Msc_command_index = 0x02c, // MSC_CMD + Msc_command_argument = 0x030, // MSC_ARG + Msc_response_fifo = 0x034, // MSC_RES + Msc_recv_data_fifo = 0x038, // MSC_RXFIFO + Msc_trans_data_fifo = 0x03c, // MSC_TXFIFO + + // JZ4780/X1600 only. + + Msc_low_power_mode = 0x040, // MSC_LPM + Msc_dma_control = 0x044, // MSC_DMAC + Msc_dma_descriptor_address = 0x048, // MSC_DMANDA + Msc_dma_data_address = 0x04c, // MSC_DMADA + Msc_dma_data_length = 0x050, // MSC_DMALEN + Msc_dma_command = 0x054, // MSC_DMACMD + Msc_control2 = 0x058, // MSC_CTRL2 + Msc_rtfifo_data_counter = 0x05c, // MSC_RTCNT + + // Channel block size/offset. + + Msc_channel_offset = 0x10000, +}; + +// Field definitions. + +enum Control_bits : unsigned +{ + // JZ4780/X1600 only. + + Control_send_ccsd = 0x8000, // SEND_CCSD + Control_send_ccsd_automatically = 0x4000, // SEND_CCSD + + // Common. + + Control_exit_multiple = 0x0080, // EXIT_MULTIPLE + Control_exit_transfer = 0x0040, // EXIT_TRANSFER + Control_start_read_wait = 0x0020, // START_READ_WAIT + Control_stop_read_wait = 0x0010, // STOP_READ_WAIT + Control_reset = 0x0008, // RESET + Control_start_operation = 0x0004, // START_OP + + Control_clock_control_field_mask = 0x3, // CLOCK_CTRL + Control_clock_control_start = 2, + Control_clock_control_stop = 1, + Control_clock_control_field_shift = 0, +}; + +enum Control2_bits : unsigned +{ + // JZ4780/X1600 only. + + Control2_pin_level_polarity_field_mask = 0x1f, // PIP + Control2_pin_level_polarity_field_shift = 24, + + // JZ4780 only. + + Control2_reset_enable = 0x00800000, // RST_EN + + // JZ4780/X1600 only. + + Control2_stop_read_operation_mode = 0x00000010, // STPRM + + // JZ4780 only. + + Control2_signal_voltage_change = 0x00000008, // SVC + + // JZ4780/X1600 only. + + Control2_speed_mode_field_mask = 0x7, // SMS + Control2_speed_mode_default = 0, // = 0 + Control2_speed_mode_high = 1, // = 1 + Control2_speed_mode_sdr12 = 2, // = 2 + Control2_speed_mode_sdr25 = 3, // = 3 + Control2_speed_mode_sdr50 = 4, // = 4 + Control2_speed_mode_field_shift = 0, +}; + +enum Status_bits : unsigned +{ + // JZ4780/X1600 only. + + Status_auto_cmd12_done = 0x80000000, // AUTO_CMD12_DONE + + // JZ4780 only. + + Status_auto_cmd23_done = 0x40000000, // AUTO_CMD23_DONE + Status_signal_voltage_change = 0x20000000, // SVS + + // JZ4780/X1600 only. + + Status_pin_level_field_mask = 0x1f, // PIN_LEVEL + Status_pin_level_field_shift = 24, + + Status_boot_crc_error = 0x00100000, // BCE + Status_boot_data_end = 0x00080000, // BDE + Status_boot_ack_error = 0x00040000, // BAE + Status_boot_ack_received = 0x00020000, // BAR + Status_dma_end = 0x00010000, // DMAEND + + // Common. + + Status_resetting = 0x8000, // IS_RESETTING + Status_sdio_interrupt_active = 0x4000, // SDIO_INT_ACTIVE + Status_programming_done = 0x2000, // PRG_DONE + Status_data_transfer_done = 0x1000, // DATA_TRAN_DONE + Status_end_command_response = 0x0800, // END_CMD_RES + Status_data_fifo_almost_full = 0x0400, // DATA_FIFO_AFULL + Status_read_wait = 0x0200, // IS_READWAIT + Status_clock_enabled = 0x0100, // CLK_EN + Status_data_fifo_full = 0x0080, // DATA_FIFO_FULL + Status_data_fifo_empty = 0x0040, // DATA_FIFO_EMPTY + Status_response_crc_error = 0x0020, // CRC_RES_ERR + Status_read_crc_error = 0x0010, // CRC_READ_ERROR + Status_write_crc_error_no_status = 0x0008, // CRC_WRITE_ERROR (2) + Status_write_crc_error_data = 0x0004, // CRC_WRITE_ERROR (1) + Status_timeout_response = 0x0002, // TIME_OUT_RES + Status_timeout_read = 0x0001, // TIME_OUT_READ +}; + +enum Clock_rate_bits : unsigned +{ + Clock_rate_field_mask = 0x7, // CLK_RATE + Clock_rate_field_shift = 0, +}; + +enum Command_data_control_bits : unsigned +{ + // JZ4780/X1600 only. + + Cdc_ccs_expected = 0x80000000, // CCS_EXPECTED + Cdc_read_ce_ata = 0x40000000, // READ_CEATA + Cdc_disable_boot = 0x08000000, // DIS_BOOT + Cdc_expect_boot_ack = 0x02000000, // EXP_BOOT_ACK + Cdc_alternative_boot_mode = 0x01000000, // BOOT_MODE + + // JZ4780 only. + + Cdc_auto_cmd23 = 0x00040000, // AUTO_CMD23 + + // JZ4780/X1600 only. + + Cdc_sdio_interrupt_2cycle = 0x00020000, // SDIO_PRDT + Cdc_auto_cmd12 = 0x00010000, // AUTO_CMD12 + + Cdc_recv_fifo_level_field_mask = 0x3, // RTRG + Cdc_fifo_level_16 = 0, + Cdc_fifo_level_32 = 1, + Cdc_fifo_level_64 = 2, + Cdc_fifo_level_96 = 3, + Cdc_recv_fifo_level_field_shift = 14, + + Cdc_trans_fifo_level_field_mask = 0x3, // TTRG + Cdc_trans_fifo_level_field_shift = 12, + + // Common. + + Cdc_io_abort = 0x0800, // IO_ABORT + + Cdc_bus_width_field_mask = 0x3, // BUS_WIDTH + Cdc_bus_width_field_1bit = 0, // = 0 + Cdc_bus_width_field_4bit = 2, // = 2 + Cdc_bus_width_field_shift = 9, + + // JZ4740 only. + + Cdc_dma_enable = 0x0100, // DMA_EN + Cdc_dma_disable = 0x0000, + + // Common. + + Cdc_init_sequence = 0x0080, // INIT + + Cdc_expect_busy = 0x0040, // BUSY + Cdc_do_not_expect_busy = 0x0000, + + Cdc_stream_block = 0x0020, // STREAM_BLOCK + Cdc_not_stream_block = 0x0000, + + Cdc_write_operation = 0x0010, // WRITE_READ + Cdc_read_operation = 0x0000, + + Cdc_data_with_command = 0x0008, // DATA_EN + Cdc_no_data_with_command = 0x0000, + + Cdc_response_format_field_mask = 0x7, // RESPONSE_FORMAT + Cdc_response_format_field_shift = 0, +}; + +enum Response_timeout_bits : unsigned +{ + // NOTE: 16-bit value in the JZ4780. + // NOTE: 32-bit value in the X1600. + + Response_timeout_mask = 0x000000ff, // RES_TO +}; + +enum Read_timeout_bits : unsigned +{ + // NOTE: 16-bit value prior to the JZ4780/X1600. + + Read_timeout_mask = 0xffffffff, // READ_TO +}; + +enum Block_length_bits : unsigned +{ + // NOTE: 16-bit value in the JZ4780/X1600. + + Block_length_mask = 0x00000fff, // BLK_LEN +}; + +enum Block_count_bits : unsigned +{ + Block_count_mask = 0x0000ffff, // NOB/SNOB +}; + +// Interrupt mask/flag bits. + +enum Interrupt_bits : unsigned +{ + // X1600 only. + + Int_dma_data_done = 0x80000000, // DMA_DATA_DONE + + // JZ4780 only. + + Int_auto_cmd23_done = 0x40000000, // AUTO_CMD23_DONE + Int_signal_voltage_change = 0x20000000, // SVS + + // JZ4780/X1600 only. + + Int_pin_level_field_mask = 0x1f, // PIN_LEVEL + Int_pin_level_field_shift = 24, + + // X1600 only. + + Int_write_request_all_done = 0x00800000, // WR_ALL_DONE + + // JZ4780/X1600 only. + + Int_boot_crc_error = 0x00100000, // BCE + Int_boot_data_end = 0x00080000, // BDE + Int_boot_ack_error = 0x00040000, // BAE + Int_boot_ack_received = 0x00020000, // BAR + Int_dma_end = 0x00010000, // DMAEND + Int_auto_cmd12_done = 0x00008000, // AUTO_CMD12_DONE + Int_data_fifo_full = 0x00004000, // DATA_FIFO_FULL + Int_data_fifo_empty = 0x00002000, // DATA_FIFO_EMP + Int_crc_response_error = 0x00001000, // CRC_RES_ERR + Int_crc_read_error = 0x00000800, // CRC_READ_ERR + Int_crc_write_error = 0x00000400, // CRC_WRITE_ERR + Int_response_timeout = 0x00000200, // TIME_OUT_RES + Int_read_timeout = 0x00000100, // TIME_OUT_READ + + // Common. + + Int_sdio = 0x80, // SDIO + Int_trans_fifo_write_request = 0x40, // TXFIFO_WR_REQ + Int_recv_fifo_read_request = 0x20, // RXFIFO_RD_REQ + Int_end_command_response = 0x04, // END_CMD_RES + Int_programming_done = 0x02, // PRG_DONE + Int_data_transfer_done = 0x01, // DATA_TRAN_DONE +}; + +enum Command_index_bits : unsigned +{ + Command_index_mask = 0x0000003f, // CMD_INDEX +}; + +enum Command_argument_bits : unsigned +{ + Command_argument_mask = 0xffffffff, // ARG +}; + +enum Response_fifo_bits : unsigned +{ + Response_fifo_mask = 0x0000ffff, // DATA +}; + +enum Recv_data_fifo_bits : unsigned +{ + Recv_data_fifo_mask = 0xffffffff, // DATA +}; + +enum Trans_data_fifo_bits : unsigned +{ + Trans_data_fifo_mask = 0xffffffff, // DATA +}; + +enum Low_power_mode_bits : unsigned +{ + Low_power_mode_enable = 0x00000001, // LPM +}; + +enum Dma_control_bits : unsigned +{ + Dma_mode_specify_transfer_length = 0x80, // MODE_SEL + + Dma_address_offset_field_mask = 0x3, // AOFST + Dma_address_offset_field_shift = 5, + + Dma_align_enable = 0x10, // ALIGNEN + + Dma_burst_type_field_mask = 0x3, // INCR + Dma_burst_type_incr16 = 0, + Dma_burst_type_incr32 = 1, + Dma_burst_type_incr64 = 2, + Dma_burst_type_field_shift = 2, + + Dma_select_common_dma = 0x02, // DMASEL + Dma_select_special_dma = 0x00, + + Dma_enable = 0x01, // DMAEN + Dma_disable = 0x00, +}; + + + +// Command indexes. + +enum Command_index : unsigned +{ + Command_go_idle_state = 0, + Command_send_op_cond = 1, + Command_all_send_cid = 2, + Command_send_relative_addr = 3, // SD + Command_set_relative_addr = 3, // MMC + Command_set_dsr = 4, + Command_io_send_op_cond = 5, // SDIO + Command_select_deselect_card = 7, + Command_send_if_cond = 8, + Command_send_csd = 9, + Command_send_cid = 10, + Command_read_dat_until_stop = 11, + Command_stop_transmission = 12, + Command_send_status = 13, + Command_go_inactive_state = 15, + Command_set_blocklen = 16, + Command_read_single_block = 17, + Command_read_multiple_block = 18, + Command_write_dat_until_stop = 20, + Command_set_block_count = 23, + Command_write_block = 24, + Command_write_multiple_block = 25, + Command_program_cid = 26, + Command_program_csd = 27, + Command_set_write_prot = 28, + Command_clr_write_prot = 29, + Command_send_write_prot = 30, + Command_tag_sector_start = 32, + Command_tag_sector_end = 33, + Command_untag_sector = 34, + Command_tag_erase_group_start = 35, + Command_tag_erase_group_end = 36, + Command_untag_erase_group = 37, + Command_erase = 38, + Command_fast_io = 39, + Command_go_irq_state = 40, + Command_lock_unlock = 42, + Command_io_rw_direct = 52, // SDIO + Command_app_cmd = 55, + Command_gen_cmd = 56, +}; + +// Application-specific command indexes, used by first issuing Command_app_cmd. + +enum App_command_index : unsigned +{ + App_command_set_bus_width = 6, + App_command_sd_status = 13, + App_command_send_num_wr_blocks = 22, + App_command_set_wr_block_erase_count = 23, + App_command_sd_send_op_cond = 41, + App_command_set_clr_card_detect = 42, + App_command_send_scr = 51, + App_command_read_ocr = 58, +}; + +enum Bus_width_bits : unsigned +{ + Bus_width_1bit = 0, + Bus_width_4bit = 2, +}; + +// Command response sizes in 16-bit units. + +enum Response_sizes : unsigned +{ + Response_size_R1 = 3, + Response_size_R2 = 8, // omits the CRC and end bit + Response_size_R3 = 3, + Response_size_R4 = 3, + Response_size_R5 = 3, + Response_size_R6 = 3, + Response_size_R7 = 3, +}; + +// SD_SEND_OP_COND argument flags. + +enum Ocr_argument_flags : unsigned +{ + Ocr_high_capacity_storage = 0x40000000, +}; + +// SD_SEND_OP_COND response flags (R3). + +enum Ocr_response_flags : unsigned +{ + Ocr_card_powered_up = 0x80000000, +}; + +// R1 status flags. + +enum R1_status_flags : unsigned +{ + R1_status_error_mask = 0xffff0000, +}; + + + +// 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,aligned(__alignof__(uint16_t)))); + +struct R2 +{ + // uint8_t end_crc; (not retrieved) + + union + { + uint8_t raw[15]; + struct CID cid; + struct CSD csd; + } payload; + + uint8_t reserved_trans_start; +} __attribute__((packed,aligned(__alignof__(uint16_t)))); + +struct R3 +{ + uint8_t end_reserved; + uint32_t ocr; + uint8_t reserved_trans_start; +} __attribute__((packed,aligned(__alignof__(uint16_t)))); + +// SDIO response structures. + +struct R4 +{ + 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,aligned(__alignof__(uint16_t)))); + +struct R5 +{ + uint8_t end_crc; + uint8_t data; + uint8_t out_of_range:1, invalid_function_number:1, reserved:1, error:1, + io_current_state:2, illegal_command:1, crc_error:1; + uint16_t stuff; + uint8_t index:6, trans_start:2; +} __attribute__((packed,aligned(__alignof__(uint16_t)))); + +struct R6 +{ + uint8_t end_crc; + uint16_t status; + uint16_t rca; + uint8_t index:6, trans_start:2; +} __attribute__((packed,aligned(__alignof__(uint16_t)))); + +struct R7 +{ + uint8_t end_crc; + + union + { + uint32_t check:8, voltage:4, reserved:20; + uint32_t raw; + } check_voltage; + + uint8_t index:6, trans_start:2; +} __attribute__((packed,aligned(__alignof__(uint16_t)))); diff -r 18edc9c73263 -r 0299f4644db0 pkg/devices/lib/msc/include/msc-jz4780.h --- a/pkg/devices/lib/msc/include/msc-jz4780.h Fri Feb 16 23:11:25 2024 +0100 +++ b/pkg/devices/lib/msc/include/msc-jz4780.h Sat Feb 17 23:04:12 2024 +0100 @@ -22,7 +22,6 @@ #pragma once #include -#include #include #include @@ -42,7 +41,9 @@ public: explicit Msc_jz4780_channel(l4_addr_t msc_start, l4_addr_t addr, - l4_cap_idx_t irq, Dma_jz4780_channel *dma, + l4_cap_idx_t irq, Cpm_chip *cpm, + enum Clock_identifiers clock, + Dma_jz4780_channel *dma, enum Dma_jz4780_request_type request_type_in, enum Dma_jz4780_request_type request_type_out); @@ -57,12 +58,22 @@ class Msc_jz4780_chip : public Msc_chip { -protected: +protected: + const enum Dma_jz4780_request_type _in_types[3] = + {Dma_request_msc0_in, Dma_request_msc1_in, Dma_request_msc2_in}; + + const enum Dma_jz4780_request_type _out_types[3] = + {Dma_request_msc0_out, Dma_request_msc1_out, Dma_request_msc2_out}; + + const enum Clock_identifiers _clocks[3] = + {Clock_msc0, Clock_msc1, Clock_msc2}; + unsigned int num_channels() { return 3; } public: - explicit Msc_jz4780_chip(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end); + explicit Msc_jz4780_chip(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end, + Cpm_chip *cpm); Msc_channel *get_channel(uint8_t channel, l4_cap_idx_t irq, Dma_jz4780_channel *dma); @@ -74,7 +85,8 @@ EXTERN_C_BEGIN -void *jz4780_msc_init(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end); +void *jz4780_msc_init(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end, + void *cpm); void *jz4780_msc_get_channel(void *msc, uint8_t channel, l4_cap_idx_t irq, void *dma); @@ -86,7 +98,7 @@ void jz4780_msc_enable(void *msc_channel); uint32_t jz4780_msc_read_blocks(void *msc_channel, uint8_t card, - l4re_dma_space_dma_addr_t paddr, + struct dma_region *region, uint32_t block_address, uint32_t block_count); EXTERN_C_END diff -r 18edc9c73263 -r 0299f4644db0 pkg/devices/lib/msc/include/msc-x1600.h --- a/pkg/devices/lib/msc/include/msc-x1600.h Fri Feb 16 23:11:25 2024 +0100 +++ b/pkg/devices/lib/msc/include/msc-x1600.h Sat Feb 17 23:04:12 2024 +0100 @@ -22,7 +22,6 @@ #pragma once #include -#include #include #include @@ -40,9 +39,15 @@ Dma_x1600_channel *_dma; enum Dma_x1600_request_type _request_type_in, _request_type_out; + // Special overridden method. + + void reset(); + public: explicit Msc_x1600_channel(l4_addr_t msc_start, l4_addr_t addr, - l4_cap_idx_t irq, Dma_x1600_channel *dma, + l4_cap_idx_t irq, Cpm_chip *cpm, + enum Clock_identifiers clock, + Dma_x1600_channel *dma, enum Dma_x1600_request_type request_type_in, enum Dma_x1600_request_type request_type_out); @@ -55,12 +60,22 @@ class Msc_x1600_chip : public Msc_chip { -protected: +protected: + const enum Dma_x1600_request_type _in_types[2] = + {Dma_request_msc0_in, Dma_request_msc1_in}; + + const enum Dma_x1600_request_type _out_types[2] = + {Dma_request_msc0_out, Dma_request_msc1_out}; + + const enum Clock_identifiers _clocks[2] = + {Clock_msc0, Clock_msc1}; + unsigned int num_channels() { return 2; } public: - explicit Msc_x1600_chip(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end); + explicit Msc_x1600_chip(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end, + Cpm_chip *cpm); Msc_channel *get_channel(uint8_t channel, l4_cap_idx_t irq, Dma_x1600_channel *dma); @@ -72,7 +87,8 @@ EXTERN_C_BEGIN -void *x1600_msc_init(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end); +void *x1600_msc_init(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end, + void *cpm); void *x1600_msc_get_channel(void *msc, uint8_t channel, l4_cap_idx_t irq, void *dma); @@ -84,7 +100,7 @@ void x1600_msc_enable(void *msc_channel); uint32_t x1600_msc_read_blocks(void *msc_channel, uint8_t card, - l4re_dma_space_dma_addr_t paddr, + struct dma_region *region, uint32_t block_address, uint32_t block_count); EXTERN_C_END diff -r 18edc9c73263 -r 0299f4644db0 pkg/devices/lib/msc/src/common.cc --- a/pkg/devices/lib/msc/src/common.cc Fri Feb 16 23:11:25 2024 +0100 +++ b/pkg/devices/lib/msc/src/common.cc Sat Feb 17 23:04:12 2024 +0100 @@ -23,515 +23,11 @@ #include #include +#include #include #include "msc-common.h" - - - -// Register locations for each channel. - -enum Regs : unsigned -{ - Msc_control = 0x000, // MSC_CTRL - Msc_status = 0x004, // MSC_STAT - Msc_clock_rate = 0x008, // MSC_CLKRT - Msc_command_data_control = 0x00c, // MSC_CMDAT - Msc_response_timeout = 0x010, // MSC_RESTO - Msc_read_timeout = 0x014, // MSC_RDTO - Msc_block_length = 0x018, // MSC_BLKLEN - Msc_block_count = 0x01c, // MSC_NOB - Msc_block_success_count = 0x020, // MSC_SNOB - Msc_interrupt_mask = 0x024, // MSC_IMASK - Msc_interrupt_flag = 0x028, // MSC_IFLG/MSC_IREG - Msc_command_index = 0x02c, // MSC_CMD - Msc_command_argument = 0x030, // MSC_ARG - Msc_response_fifo = 0x034, // MSC_RES - Msc_recv_data_fifo = 0x038, // MSC_RXFIFO - Msc_trans_data_fifo = 0x03c, // MSC_TXFIFO - - // JZ4780/X1600 only. - - Msc_low_power_mode = 0x040, // MSC_LPM - Msc_dma_control = 0x044, // MSC_DMAC - Msc_dma_descriptor_address = 0x048, // MSC_DMANDA - Msc_dma_data_address = 0x04c, // MSC_DMADA - Msc_dma_data_length = 0x050, // MSC_DMALEN - Msc_dma_command = 0x054, // MSC_DMACMD - Msc_control2 = 0x058, // MSC_CTRL2 - Msc_rtfifo_data_counter = 0x05c, // MSC_RTCNT - - // Channel block size/offset. - - Msc_channel_offset = 0x10000, -}; - -// Field definitions. - -enum Control_bits : unsigned -{ - // JZ4780/X1600 only. - - Control_send_ccsd = 0x8000, // SEND_CCSD - Control_send_ccsd_automatically = 0x4000, // SEND_CCSD - - // Common. - - Control_exit_multiple = 0x0080, // EXIT_MULTIPLE - Control_exit_transfer = 0x0040, // EXIT_TRANSFER - Control_start_read_wait = 0x0020, // START_READ_WAIT - Control_stop_read_wait = 0x0010, // STOP_READ_WAIT - Control_reset = 0x0008, // RESET - Control_start_operation = 0x0004, // START_OP - - Control_clock_control_field_mask = 0x3, // CLOCK_CTRL - Control_clock_control_start = 2, - Control_clock_control_stop = 1, - Control_clock_control_field_shift = 0, -}; - -enum Control2_bits : unsigned -{ - // JZ4780/X1600 only. - - Control2_pin_level_polarity_field_mask = 0x1f, // PIP - Control2_pin_level_polarity_field_shift = 24, - - // JZ4780 only. - - Control2_reset_enable = 0x00800000, // RST_EN - - // JZ4780/X1600 only. - - Control2_stop_read_operation_mode = 0x00000010, // STPRM - - // JZ4780 only. - - Control2_signal_voltage_change = 0x00000008, // SVC - - // JZ4780/X1600 only. - - Control2_speed_mode_field_mask = 0x7, // SMS - Control2_speed_mode_default = 0, // = 0 - Control2_speed_mode_high = 1, // = 1 - Control2_speed_mode_sdr12 = 2, // = 2 - Control2_speed_mode_sdr25 = 3, // = 3 - Control2_speed_mode_sdr50 = 4, // = 4 - Control2_speed_mode_field_shift = 0, -}; - -enum Status_bits : unsigned -{ - // JZ4780/X1600 only. - - Status_auto_cmd12_done = 0x80000000, // AUTO_CMD12_DONE - - // JZ4780 only. - - Status_auto_cmd23_done = 0x40000000, // AUTO_CMD23_DONE - Status_signal_voltage_change = 0x20000000, // SVS - - // JZ4780/X1600 only. - - Status_pin_level_field_mask = 0x1f, // PIN_LEVEL - Status_pin_level_field_shift = 24, - - Status_boot_crc_error = 0x00100000, // BCE - Status_boot_data_end = 0x00080000, // BDE - Status_boot_ack_error = 0x00040000, // BAE - Status_boot_ack_received = 0x00020000, // BAR - Status_dma_end = 0x00010000, // DMAEND - - // Common. - - Status_resetting = 0x8000, // IS_RESETTING - Status_sdio_interrupt_active = 0x4000, // SDIO_INT_ACTIVE - Status_programming_done = 0x2000, // PRG_DONE - Status_data_transfer_done = 0x1000, // DATA_TRAN_DONE - Status_end_command_response = 0x0800, // END_CMD_RES - Status_data_fifo_almost_full = 0x0400, // DATA_FIFO_AFULL - Status_read_wait = 0x0200, // IS_READWAIT - Status_clock_enabled = 0x0100, // CLK_EN - Status_data_fifo_full = 0x0080, // DATA_FIFO_FULL - Status_data_fifo_empty = 0x0040, // DATA_FIFO_EMPTY - Status_response_crc_error = 0x0020, // CRC_RES_ERR - Status_read_crc_error = 0x0010, // CRC_READ_ERROR - Status_write_crc_error_no_status = 0x0008, // CRC_WRITE_ERROR (2) - Status_write_crc_error_data = 0x0004, // CRC_WRITE_ERROR (1) - Status_timeout_response = 0x0002, // TIME_OUT_RES - Status_timeout_read = 0x0001, // TIME_OUT_READ -}; - -enum Clock_rate_bits : unsigned -{ - Clock_rate_field_mask = 0x7, // CLK_RATE - Clock_rate_field_shift = 0, -}; - -enum Command_data_control_bits : unsigned -{ - // JZ4780/X1600 only. - - Cdc_ccs_expected = 0x80000000, // CCS_EXPECTED - Cdc_read_ce_ata = 0x40000000, // READ_CEATA - Cdc_disable_boot = 0x08000000, // DIS_BOOT - Cdc_expect_boot_ack = 0x02000000, // EXP_BOOT_ACK - Cdc_alternative_boot_mode = 0x01000000, // BOOT_MODE - - // JZ4780 only. - - Cdc_auto_cmd23 = 0x00040000, // AUTO_CMD23 - - // JZ4780/X1600 only. - - Cdc_sdio_interrupt_2cycle = 0x00020000, // SDIO_PRDT - Cdc_auto_cmd12 = 0x00010000, // AUTO_CMD12 - - Cdc_recv_fifo_level_field_mask = 0x3, // RTRG - Cdc_fifo_level_16 = 0, - Cdc_fifo_level_32 = 1, - Cdc_fifo_level_64 = 2, - Cdc_fifo_level_96 = 3, - Cdc_recv_fifo_level_field_shift = 14, - - Cdc_trans_fifo_level_field_mask = 0x3, // TTRG - Cdc_trans_fifo_level_field_shift = 12, - - // Common. - - Cdc_io_abort = 0x0800, // IO_ABORT - - Cdc_bus_width_field_mask = 0x3, // BUS_WIDTH - Cdc_bus_width_field_1bit = 0, // = 0 - Cdc_bus_width_field_4bit = 2, // = 2 - Cdc_bus_width_field_shift = 9, - - // JZ4740 only. - - Cdc_dma_enable = 0x0100, // DMA_EN - Cdc_dma_disable = 0x0000, - - // Common. - - Cdc_init_sequence = 0x0080, // INIT - - Cdc_expect_busy = 0x0040, // BUSY - Cdc_do_not_expect_busy = 0x0000, - - Cdc_stream_block = 0x0020, // STREAM_BLOCK - Cdc_not_stream_block = 0x0000, - - Cdc_write_operation = 0x0010, // WRITE_READ - Cdc_read_operation = 0x0000, - - Cdc_data_with_command = 0x0008, // DATA_EN - Cdc_no_data_with_command = 0x0000, - - Cdc_response_format_field_mask = 0x7, // RESPONSE_FORMAT - Cdc_response_format_field_shift = 0, -}; - -enum Response_timeout_bits : unsigned -{ - // NOTE: 16-bit value in the JZ4780. - // NOTE: 32-bit value in the X1600. - - Response_timeout_mask = 0x000000ff, // RES_TO -}; - -enum Read_timeout_bits : unsigned -{ - // NOTE: 16-bit value prior to the JZ4780/X1600. - - Read_timeout_mask = 0xffffffff, // READ_TO -}; - -enum Block_length_bits : unsigned -{ - // NOTE: 16-bit value in the JZ4780/X1600. - - Block_length_mask = 0x00000fff, // BLK_LEN -}; - -enum Block_count_bits : unsigned -{ - Block_count_mask = 0x0000ffff, // NOB/SNOB -}; - -// Interrupt mask/flag bits. - -enum Interrupt_bits : unsigned -{ - // X1600 only. - - Int_dma_data_done = 0x80000000, // DMA_DATA_DONE - - // JZ4780 only. - - Int_auto_cmd23_done = 0x40000000, // AUTO_CMD23_DONE - Int_signal_voltage_change = 0x20000000, // SVS - - // JZ4780/X1600 only. - - Int_pin_level_field_mask = 0x1f, // PIN_LEVEL - Int_pin_level_field_shift = 24, - - // X1600 only. - - Int_write_request_all_done = 0x00800000, // WR_ALL_DONE - - // JZ4780/X1600 only. - - Int_boot_crc_error = 0x00100000, // BCE - Int_boot_data_end = 0x00080000, // BDE - Int_boot_ack_error = 0x00040000, // BAE - Int_boot_ack_received = 0x00020000, // BAR - Int_dma_end = 0x00010000, // DMAEND - Int_auto_cmd12_done = 0x00008000, // AUTO_CMD12_DONE - Int_data_fifo_full = 0x00004000, // DATA_FIFO_FULL - Int_data_fifo_empty = 0x00002000, // DATA_FIFO_EMP - Int_crc_response_error = 0x00001000, // CRC_RES_ERR - Int_crc_read_error = 0x00000800, // CRC_READ_ERR - Int_crc_write_error = 0x00000400, // CRC_WRITE_ERR - Int_response_timeout = 0x00000200, // TIME_OUT_RES - Int_read_timeout = 0x00000100, // TIME_OUT_READ - - // Common. - - Int_sdio = 0x80, // SDIO - Int_trans_fifo_write_request = 0x40, // TXFIFO_WR_REQ - Int_recv_fifo_read_request = 0x20, // RXFIFO_RD_REQ - Int_end_command_response = 0x04, // END_CMD_RES - Int_programming_done = 0x02, // PRG_DONE - Int_data_transfer_done = 0x01, // DATA_TRAN_DONE -}; - -enum Command_index_bits : unsigned -{ - Command_index_mask = 0x0000003f, // CMD_INDEX -}; - -enum Command_argument_bits : unsigned -{ - Command_argument_mask = 0xffffffff, // ARG -}; - -enum Response_fifo_bits : unsigned -{ - Response_fifo_mask = 0x0000ffff, // DATA -}; - -enum Recv_data_fifo_bits : unsigned -{ - Recv_data_fifo_mask = 0xffffffff, // DATA -}; - -enum Trans_data_fifo_bits : unsigned -{ - Trans_data_fifo_mask = 0xffffffff, // DATA -}; - -enum Low_power_mode_bits : unsigned -{ - Low_power_mode_enable = 0x00000001, // LPM -}; - -enum Dma_control_bits : unsigned -{ - Dma_mode_specify_transfer_length = 0x80, // MODE_SEL - - Dma_address_offset_field_mask = 0x3, // AOFST - Dma_address_offset_field_shift = 5, - - Dma_align_enable = 0x10, // ALIGNEN - - Dma_burst_type_field_mask = 0x3, // INCR - Dma_burst_type_incr16 = 0, - Dma_burst_type_incr32 = 1, - Dma_burst_type_incr64 = 2, - Dma_burst_type_field_shift = 2, - - Dma_select_common_dma = 0x02, // DMASEL - Dma_select_special_dma = 0x00, - - Dma_enable = 0x01, // DMAEN - Dma_disable = 0x00, -}; - - - -// Command indexes. - -enum Command_index : unsigned -{ - Command_go_idle_state = 0, - Command_send_op_cond = 1, - Command_all_send_cid = 2, - Command_send_relative_addr = 3, // SD - Command_set_relative_addr = 3, // MMC - Command_set_dsr = 4, - Command_io_send_op_cond = 5, // SDIO - Command_select_deselect_card = 7, - Command_send_if_cond = 8, - Command_send_csd = 9, - Command_send_cid = 10, - Command_read_dat_until_stop = 11, - Command_stop_transmission = 12, - Command_send_status = 13, - Command_go_inactive_state = 15, - Command_set_blocklen = 16, - Command_read_single_block = 17, - Command_read_multiple_block = 18, - Command_write_dat_until_stop = 20, - Command_set_block_count = 23, - Command_write_block = 24, - Command_write_multiple_block = 25, - Command_program_cid = 26, - Command_program_csd = 27, - Command_set_write_prot = 28, - Command_clr_write_prot = 29, - Command_send_write_prot = 30, - Command_tag_sector_start = 32, - Command_tag_sector_end = 33, - Command_untag_sector = 34, - Command_tag_erase_group_start = 35, - Command_tag_erase_group_end = 36, - Command_untag_erase_group = 37, - Command_erase = 38, - Command_fast_io = 39, - Command_go_irq_state = 40, - Command_lock_unlock = 42, - Command_io_rw_direct = 52, // SDIO - Command_app_cmd = 55, - Command_gen_cmd = 56, -}; - -// Application-specific command indexes, used by first issuing Command_app_cmd. - -enum App_command_index : unsigned -{ - App_command_set_bus_width = 6, - App_command_sd_status = 13, - App_command_send_num_wr_blocks = 22, - App_command_set_wr_block_erase_count = 23, - App_command_sd_send_op_cond = 41, - App_command_set_clr_card_detect = 42, - App_command_send_scr = 51, - App_command_read_ocr = 58, -}; - -enum Bus_width_bits : unsigned -{ - Bus_width_1bit = 0, - Bus_width_4bit = 2, -}; - -// Command response sizes in 16-bit units. - -enum Response_sizes : unsigned -{ - Response_size_R1 = 3, - Response_size_R2 = 8, // omits the CRC and end bit - Response_size_R3 = 3, - Response_size_R4 = 3, - Response_size_R5 = 3, - Response_size_R6 = 3, - Response_size_R7 = 3, -}; - -// SD_SEND_OP_COND argument flags. - -enum Ocr_argument_flags : unsigned -{ - Ocr_high_capacity_storage = 0x40000000, -}; - -// SD_SEND_OP_COND response flags (R3). - -enum Ocr_response_flags : unsigned -{ - Ocr_card_powered_up = 0x80000000, -}; - -// R1 status flags. - -enum R1_status_flags : unsigned -{ - R1_status_error_mask = 0xffff0000, -}; - - - -// 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,aligned(__alignof__(uint16_t)))); - -struct R2 -{ - // uint8_t end_crc; (not retrieved) - - union - { - uint8_t raw[15]; - struct CID cid; - struct CSD csd; - } payload; - - uint8_t reserved_trans_start; -} __attribute__((packed,aligned(__alignof__(uint16_t)))); - -struct R3 -{ - uint8_t end_reserved; - uint32_t ocr; - uint8_t reserved_trans_start; -} __attribute__((packed,aligned(__alignof__(uint16_t)))); - -// SDIO response structures. - -struct R4 -{ - 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,aligned(__alignof__(uint16_t)))); - -struct R5 -{ - uint8_t end_crc; - uint8_t data; - uint8_t out_of_range:1, invalid_function_number:1, reserved:1, error:1, - io_current_state:2, illegal_command:1, crc_error:1; - uint16_t stuff; - uint8_t index:6, trans_start:2; -} __attribute__((packed,aligned(__alignof__(uint16_t)))); - -struct R6 -{ - uint8_t end_crc; - uint16_t status; - uint16_t rca; - uint8_t index:6, trans_start:2; -} __attribute__((packed,aligned(__alignof__(uint16_t)))); - -struct R7 -{ - uint8_t end_crc; - - union - { - uint32_t check:8, voltage:4, reserved:20; - uint32_t raw; - } check_voltage; - - uint8_t index:6, trans_start:2; -} __attribute__((packed,aligned(__alignof__(uint16_t)))); +#include "msc-defs.h" @@ -580,8 +76,9 @@ // Channel abstraction. -Msc_channel::Msc_channel(l4_addr_t msc_start, l4_addr_t addr, l4_cap_idx_t irq) -: _msc_start(msc_start), _irq(irq) +Msc_channel::Msc_channel(l4_addr_t msc_start, l4_addr_t addr, l4_cap_idx_t irq, + Cpm_chip *cpm, enum Clock_identifiers clock) +: _msc_start(msc_start), _irq(irq), _cpm(cpm), _clock(clock) { _regs = new Hw::Mmio_register_block<32>(addr); } @@ -606,6 +103,64 @@ } bool +Msc_channel::set_clock_frequency(uint64_t frequency) +{ + uint64_t division = _cpm->get_frequency(_clock) / frequency; + double divider = ceil(log2(division)); + + if ((divider < 0) || (divider > Clock_rate_field_mask)) + return false; + + set_field(Msc_clock_rate, Clock_rate_field_mask, Clock_rate_field_shift, + (uint32_t) divider); + + return true; +} + +void +Msc_channel::reset() +{ + _regs[Msc_control] = _regs[Msc_control] | Control_reset; + + while (_regs[Msc_status] & Status_resetting); +} + +void +Msc_channel::start_clock() +{ + set_field(Msc_control, Control_clock_control_field_mask, + Control_clock_control_field_shift, Control_clock_control_start); + + while (!(_regs[Msc_status] & Status_clock_enabled)); +} + +void +Msc_channel::stop_clock() +{ + set_field(Msc_control, Control_clock_control_field_mask, + Control_clock_control_field_shift, Control_clock_control_stop); + + while (_regs[Msc_status] & Status_clock_enabled); +} + +void +Msc_channel::ack_irq(uint32_t flags) +{ + // Clear the flags by setting them. + + _regs[Msc_interrupt_flag] = _regs[Msc_interrupt_flag] | flags; +} + +void +Msc_channel::unmask_irq(uint32_t flags) +{ + ack_irq(flags); + + if (_regs[Msc_interrupt_mask] & flags) + _regs[Msc_interrupt_mask] = _regs[Msc_interrupt_mask] & ~flags; +} + +bool Msc_channel::command_will_write(uint8_t index) { // NOTE: Probably incomplete coverage. @@ -765,55 +320,6 @@ } } -void -Msc_channel::ack_irq(uint32_t flags) -{ - // Clear the flags by setting them. - - _regs[Msc_interrupt_flag] = _regs[Msc_interrupt_flag] | flags; -} - -void -Msc_channel::unmask_irq(uint32_t flags) -{ - ack_irq(flags); - - if (_regs[Msc_interrupt_mask] & flags) - _regs[Msc_interrupt_mask] = _regs[Msc_interrupt_mask] & ~flags; -} - -void -Msc_channel::reset() -{ - _regs[Msc_control] = _regs[Msc_control] | Control_reset; - - // NOTE: X1600 and other recent SoCs only. - - _regs[Msc_control] = _regs[Msc_control] & ~Control_reset; - - // Sufficient for other SoCs... - - while (_regs[Msc_status] & Status_resetting); -} - -void -Msc_channel::start_clock() -{ - set_field(Msc_control, Control_clock_control_field_mask, - Control_clock_control_field_shift, Control_clock_control_start); - - while (!(_regs[Msc_status] & Status_clock_enabled)); -} - -void -Msc_channel::stop_clock() -{ - set_field(Msc_control, Control_clock_control_field_mask, - Control_clock_control_field_shift, Control_clock_control_stop); - - while (_regs[Msc_status] & Status_clock_enabled); -} - // Send an application-specific command. bool @@ -1188,9 +694,10 @@ reset(); // Slow the clock for initialisation. - // NOTE: Should use the CPM module to deduce the appropriate divider value. + // NOTE: Should produce an error. - set_field(Msc_clock_rate, Clock_rate_field_mask, Clock_rate_field_shift, 7); + if (!set_clock_frequency(400000)) + return; send_command(Command_go_idle_state, 0); @@ -1204,11 +711,6 @@ identify_cards(); query_cards(); - // Restore the clock. - // NOTE: Should use the CPM module to deduce the appropriate divider value. - - set_field(Msc_clock_rate, Clock_rate_field_mask, Clock_rate_field_shift, 1); - // Initially, no card is selected. _card = -1; @@ -1233,13 +735,16 @@ // Receive data from the selected card. uint32_t -Msc_channel::recv_data(l4re_dma_space_dma_addr_t paddr, uint32_t count) +Msc_channel::recv_data(struct dma_region *region, uint32_t count) { + if (count > region->size) + return 0; + uint32_t flags = Int_data_transfer_done; unmask_irq(flags); - uint32_t to_transfer = transfer(_msc_start + Msc_recv_data_fifo, paddr, true, count); + uint32_t to_transfer = transfer(_msc_start + Msc_recv_data_fifo, region->paddr, true, count); wait_for_irq(flags); ack_irq(flags); @@ -1255,13 +760,16 @@ // Send data to the selected card. uint32_t -Msc_channel::send_data(l4re_dma_space_dma_addr_t paddr, uint32_t count) +Msc_channel::send_data(struct dma_region *region, uint32_t count) { + if (count > region->size) + return 0; + uint32_t flags = Int_data_transfer_done; unmask_irq(flags); - uint32_t to_transfer = transfer(paddr, _msc_start + Msc_trans_data_fifo, false, count); + uint32_t to_transfer = transfer(region->paddr, _msc_start + Msc_trans_data_fifo, false, count); wait_for_irq(flags); ack_irq(flags); @@ -1277,7 +785,7 @@ // 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, +Msc_channel::read_blocks(uint8_t card, struct dma_region *region, uint32_t block_address, uint32_t block_count) { uint32_t block_size = 1 << _cards[card].csd.read_blocklen; @@ -1287,6 +795,13 @@ if (_card != card) { + // Choose an appropriate clock frequency for the card. + // NOTE: Should produce an error. + + if (!set_clock_frequency(_cards[card].csd.tran_speed == 0x32 ? + 25000000 : 50000000)) + return 0; + if (!send_command(Command_select_deselect_card, _cards[card].rca << 16)) return 0; @@ -1346,7 +861,7 @@ // NOTE: Use Msc_block_success_count instead. - uint32_t transferred = recv_data(paddr, block_size * block_count); + uint32_t transferred = recv_data(region, block_size * block_count); if (block_count > 1) send_command(Command_stop_transmission, 0); @@ -1358,7 +873,8 @@ // Peripheral abstraction. -Msc_chip::Msc_chip(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end) -: _msc_start(msc_start), _start(start), _end(end) +Msc_chip::Msc_chip(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end, + Cpm_chip *cpm) +: _msc_start(msc_start), _start(start), _end(end), _cpm(cpm) { } diff -r 18edc9c73263 -r 0299f4644db0 pkg/devices/lib/msc/src/jz4780.cc --- a/pkg/devices/lib/msc/src/jz4780.cc Fri Feb 16 23:11:25 2024 +0100 +++ b/pkg/devices/lib/msc/src/jz4780.cc Sat Feb 17 23:04:12 2024 +0100 @@ -21,28 +21,20 @@ #include +#include "msc-defs.h" #include "msc-jz4780.h" -// Register locations for each channel. - -enum Regs : unsigned -{ - // Channel block size/offset. - - Msc_channel_offset = 0x10000, -}; - - - // Channel abstraction. Msc_jz4780_channel::Msc_jz4780_channel(l4_addr_t msc_start, l4_addr_t addr, - l4_cap_idx_t irq, Dma_jz4780_channel *dma, + l4_cap_idx_t irq, + Cpm_chip *cpm, enum Clock_identifiers clock, + Dma_jz4780_channel *dma, enum Dma_jz4780_request_type request_type_in, enum Dma_jz4780_request_type request_type_out) -: Msc_channel(msc_start, addr, irq), +: Msc_channel(msc_start, addr, irq, cpm, clock), _dma(dma), _request_type_in(request_type_in), _request_type_out(request_type_out) @@ -77,25 +69,20 @@ // Peripheral abstraction. -Msc_jz4780_chip::Msc_jz4780_chip(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end) -: Msc_chip(msc_start, start, end) +Msc_jz4780_chip::Msc_jz4780_chip(l4_addr_t msc_start, l4_addr_t start, + l4_addr_t end, Cpm_chip *cpm) +: Msc_chip(msc_start, start, end, cpm) { } Msc_channel *Msc_jz4780_chip::get_channel(uint8_t channel, l4_cap_idx_t irq, Dma_jz4780_channel *dma) { - const enum Dma_jz4780_request_type in_types[] = - {Dma_request_msc0_in, Dma_request_msc1_in, Dma_request_msc2_in}; - - const enum Dma_jz4780_request_type out_types[] = - {Dma_request_msc0_out, Dma_request_msc1_out, Dma_request_msc2_out}; - if (channel < num_channels()) return new Msc_jz4780_channel(_msc_start + channel * Msc_channel_offset, _start + channel * Msc_channel_offset, - irq, dma, - in_types[channel], out_types[channel]); + irq, _cpm, _clocks[channel], dma, + _in_types[channel], _out_types[channel]); else throw -L4_EINVAL; } @@ -104,9 +91,11 @@ // C language interface functions. -void *jz4780_msc_init(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end) +void *jz4780_msc_init(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end, + void *cpm) { - return (void *) new Msc_jz4780_chip(msc_start, start, end); + return (void *) new Msc_jz4780_chip(msc_start, start, end, + static_cast(cpm)); } void *jz4780_msc_get_channel(void *msc, uint8_t channel, l4_cap_idx_t irq, @@ -132,9 +121,9 @@ } uint32_t jz4780_msc_read_blocks(void *msc_channel, uint8_t card, - l4re_dma_space_dma_addr_t paddr, + struct dma_region *region, uint32_t block_address, uint32_t block_count) { - return static_cast(msc_channel)->read_blocks(card, paddr, + return static_cast(msc_channel)->read_blocks(card, region, block_address, block_count); } diff -r 18edc9c73263 -r 0299f4644db0 pkg/devices/lib/msc/src/x1600.cc --- a/pkg/devices/lib/msc/src/x1600.cc Fri Feb 16 23:11:25 2024 +0100 +++ b/pkg/devices/lib/msc/src/x1600.cc Sat Feb 17 23:04:12 2024 +0100 @@ -21,34 +21,43 @@ #include +#include "msc-defs.h" #include "msc-x1600.h" -// Register locations for each channel. - -enum Regs : unsigned -{ - // Channel block size/offset. - - Msc_channel_offset = 0x10000, -}; - - - // Channel abstraction. Msc_x1600_channel::Msc_x1600_channel(l4_addr_t msc_start, l4_addr_t addr, - l4_cap_idx_t irq, Dma_x1600_channel *dma, + l4_cap_idx_t irq, + Cpm_chip *cpm, enum Clock_identifiers clock, + Dma_x1600_channel *dma, enum Dma_x1600_request_type request_type_in, enum Dma_x1600_request_type request_type_out) -: Msc_channel(msc_start, addr, irq), +: Msc_channel(msc_start, addr, irq, cpm, clock), _dma(dma), _request_type_in(request_type_in), _request_type_out(request_type_out) { } +// Reset for X1600 and other recent SoCs only. + +void +Msc_x1600_channel::reset() +{ + _regs[Msc_control] = _regs[Msc_control] | Control_reset; + + // NOTE: On the X1600, Msc_control tends to read as zero, anyway, making this + // NOTE: equivalent to clearing the register. + + _regs[Msc_control] = _regs[Msc_control] & ~Control_reset; + + // Sufficient for other SoCs... + + while (_regs[Msc_status] & Status_resetting); +} + // Request the transfer of the indicated number of bytes between two physical // addresses in the indicated direction, returning the number of bytes to be // transferred. @@ -77,25 +86,20 @@ // Peripheral abstraction. -Msc_x1600_chip::Msc_x1600_chip(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end) -: Msc_chip(msc_start, start, end) +Msc_x1600_chip::Msc_x1600_chip(l4_addr_t msc_start, l4_addr_t start, + l4_addr_t end, Cpm_chip *cpm) +: Msc_chip(msc_start, start, end, cpm) { } Msc_channel *Msc_x1600_chip::get_channel(uint8_t channel, l4_cap_idx_t irq, Dma_x1600_channel *dma) { - const enum Dma_x1600_request_type in_types[] = - {Dma_request_msc0_in, Dma_request_msc1_in}; - - const enum Dma_x1600_request_type out_types[] = - {Dma_request_msc0_out, Dma_request_msc1_out}; - if (channel < num_channels()) return new Msc_x1600_channel(_msc_start + channel * Msc_channel_offset, _start + channel * Msc_channel_offset, - irq, dma, - in_types[channel], out_types[channel]); + irq, _cpm, _clocks[channel], dma, + _in_types[channel], _out_types[channel]); else throw -L4_EINVAL; } @@ -104,9 +108,11 @@ // C language interface functions. -void *x1600_msc_init(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end) +void *x1600_msc_init(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end, + void *cpm) { - return (void *) new Msc_x1600_chip(msc_start, start, end); + return (void *) new Msc_x1600_chip(msc_start, start, end, + static_cast(cpm)); } void *x1600_msc_get_channel(void *msc, uint8_t channel, l4_cap_idx_t irq, @@ -132,9 +138,9 @@ } uint32_t x1600_msc_read_blocks(void *msc_channel, uint8_t card, - l4re_dma_space_dma_addr_t paddr, + struct dma_region *region, uint32_t block_address, uint32_t block_count) { - return static_cast(msc_channel)->read_blocks(card, paddr, + return static_cast(msc_channel)->read_blocks(card, region, block_address, block_count); } diff -r 18edc9c73263 -r 0299f4644db0 pkg/devices/util/include/dma.h --- a/pkg/devices/util/include/dma.h Fri Feb 16 23:11:25 2024 +0100 +++ b/pkg/devices/util/include/dma.h Sat Feb 17 23:04:12 2024 +0100 @@ -1,7 +1,7 @@ /* * DMA-related memory allocation utility functions. * - * Copyright (C) 2023 Paul Boddie + * Copyright (C) 2023, 2024 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -24,9 +24,17 @@ #include #include +struct dma_region +{ + unsigned int size; + unsigned int align; + l4_addr_t vaddr; + l4re_dma_space_dma_addr_t paddr; + l4_cap_idx_t mem; +}; + EXTERN_C_BEGIN -long get_dma_region(unsigned long size, int align, l4_addr_t *vaddr, - l4re_dma_space_dma_addr_t *paddr, l4_cap_idx_t *mem); +long get_dma_region(unsigned long size, int align, struct dma_region *region); EXTERN_C_END diff -r 18edc9c73263 -r 0299f4644db0 pkg/devices/util/src/dma.cc --- a/pkg/devices/util/src/dma.cc Fri Feb 16 23:11:25 2024 +0100 +++ b/pkg/devices/util/src/dma.cc Sat Feb 17 23:04:12 2024 +0100 @@ -1,7 +1,7 @@ /* * DMA-related memory allocation utility functions. * - * Copyright (C) 2023 Paul Boddie + * Copyright (C) 2023, 2024 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -38,13 +38,15 @@ // Allocate a memory region of the given size for DMA. -long get_dma_region(unsigned long size, int align, l4_addr_t *vaddr, - l4re_dma_space_dma_addr_t *paddr, l4_cap_idx_t *mem) +long get_dma_region(unsigned long size, int align, struct dma_region *region) { // Memory allocation capabilities. l4_cap_idx_t dma, vbus; + region->size = 0; + region->align = 0; + // Obtain capabilities for the DMA region and the vbus. dma = ipc_cap_alloc(); @@ -82,21 +84,21 @@ // Map the allocated memory, obtaining a virtual address. - *vaddr = 0; + region->vaddr = 0; - if (ipc_new_dataspace(size, alloc_flags, align, mem)) + if (ipc_new_dataspace(size, alloc_flags, align, ®ion->mem)) return -L4_ENOMEM; - if (ipc_attach_dataspace_align(*mem, size, attach_flags, align, (void **) vaddr)) + if (ipc_attach_dataspace_align(region->mem, size, attach_flags, align, (void **) ®ion->vaddr)) return -L4_ENOMEM; // Obtain a physical address. l4_size_t size_out = size; - *paddr = 0; + region->paddr = 0; - if (l4re_dma_space_map(dma, *mem | L4_CAP_FPAGE_RW, 0, &size_out, 0, - L4RE_DMA_SPACE_TO_DEVICE, paddr)) + if (l4re_dma_space_map(dma, region->mem | L4_CAP_FPAGE_RW, 0, &size_out, 0, + L4RE_DMA_SPACE_TO_DEVICE, ®ion->paddr)) return -L4_ENOMEM; // Test the mapped region size. @@ -104,5 +106,8 @@ if (size_out != size) return -L4_ENOMEM; + region->size = size_out; + region->align = align; + return L4_EOK; } diff -r 18edc9c73263 -r 0299f4644db0 pkg/landfall-examples/hw_info/common.h --- a/pkg/landfall-examples/hw_info/common.h Fri Feb 16 23:11:25 2024 +0100 +++ b/pkg/landfall-examples/hw_info/common.h Sat Feb 17 23:04:12 2024 +0100 @@ -22,10 +22,10 @@ #pragma once -#include +#include +#include +#include #include -#include -#include #include @@ -168,7 +168,7 @@ /* MSC adapter functions. */ -void *msc_init(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end); +void *msc_init(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end, void *cpm); void *msc_get_channel(void *msc, uint8_t channel, l4_cap_idx_t irq, void *dma); @@ -179,7 +179,7 @@ void msc_enable(void *msc_channel); uint32_t msc_read_blocks(void *msc_channel, uint8_t card, - l4re_dma_space_dma_addr_t paddr, + struct dma_region *region, uint32_t block_address, uint32_t block_count); @@ -311,19 +311,6 @@ -/* DMA definitions. */ - -struct dma_region -{ - unsigned int size; - unsigned int align; - l4_addr_t vaddr; - l4re_dma_space_dma_addr_t paddr; - l4_cap_idx_t mem; -}; - - - /* GPIO definitions. */ struct gpio_port diff -r 18edc9c73263 -r 0299f4644db0 pkg/landfall-examples/hw_info/hw_info.c --- a/pkg/landfall-examples/hw_info/hw_info.c Fri Feb 16 23:11:25 2024 +0100 +++ b/pkg/landfall-examples/hw_info/hw_info.c Sat Feb 17 23:04:12 2024 +0100 @@ -582,7 +582,7 @@ if (!read_number("Alignment", ®ion->align)) return; - if (get_dma_region(region->size, region->align, ®ion->vaddr, ®ion->paddr, ®ion->mem)) + if (get_dma_region(region->size, region->align, region)) printf("Could not allocate region.\n"); } @@ -1185,7 +1185,7 @@ l4_cache_inv_data(dma_region->vaddr, dma_region->vaddr + dma_region->size); - transferred = msc_read_blocks(channel, (uint8_t) card, dma_region->paddr, 0, 1); + transferred = msc_read_blocks(channel, (uint8_t) card, dma_region, 0, 1); if (!transferred) { @@ -1306,7 +1306,7 @@ l4_cache_inv_data(dma_region->vaddr, dma_region->vaddr + dma_region->size); - transferred = msc_read_blocks(channel, (uint8_t) card, dma_region->paddr, + transferred = msc_read_blocks(channel, (uint8_t) card, dma_region, block_address, block_count); printf("Transferred: %d\n", transferred); @@ -2051,7 +2051,7 @@ printf("MSC at 0x%lx...0x%lx.\n", msc_base, msc_base_end); - msc = msc_init(msc_phys_base, msc_base, msc_base_end); + msc = msc_init(msc_phys_base, msc_base, msc_base_end, cpm); if (get_irq(io_memory_regions[MSC], &msc_irq_start, &msc_irq_end) < 0) return 1; diff -r 18edc9c73263 -r 0299f4644db0 pkg/landfall-examples/hw_info/jz4780.c --- a/pkg/landfall-examples/hw_info/jz4780.c Fri Feb 16 23:11:25 2024 +0100 +++ b/pkg/landfall-examples/hw_info/jz4780.c Sat Feb 17 23:04:12 2024 +0100 @@ -339,9 +339,9 @@ /* MSC adapter functions. */ -void *msc_init(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end) +void *msc_init(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end, void *cpm) { - return jz4780_msc_init(msc_start, start, end); + return jz4780_msc_init(msc_start, start, end, cpm); } void *msc_get_channel(void *msc, uint8_t channel, l4_cap_idx_t irq, void *dma) @@ -365,10 +365,10 @@ } uint32_t msc_read_blocks(void *msc_channel, uint8_t card, - l4re_dma_space_dma_addr_t paddr, + struct dma_region *region, uint32_t block_address, uint32_t block_count) { - return jz4780_msc_read_blocks(msc_channel, card, paddr, block_address, + return jz4780_msc_read_blocks(msc_channel, card, region, block_address, block_count); } diff -r 18edc9c73263 -r 0299f4644db0 pkg/landfall-examples/hw_info/x1600.c --- a/pkg/landfall-examples/hw_info/x1600.c Fri Feb 16 23:11:25 2024 +0100 +++ b/pkg/landfall-examples/hw_info/x1600.c Sat Feb 17 23:04:12 2024 +0100 @@ -328,9 +328,9 @@ /* MSC adapter functions. */ -void *msc_init(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end) +void *msc_init(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end, void *cpm) { - return x1600_msc_init(msc_start, start, end); + return x1600_msc_init(msc_start, start, end, cpm); } void *msc_get_channel(void *msc, uint8_t channel, l4_cap_idx_t irq, void *dma) @@ -354,10 +354,10 @@ } uint32_t msc_read_blocks(void *msc_channel, uint8_t card, - l4re_dma_space_dma_addr_t paddr, + struct dma_region *region, uint32_t block_address, uint32_t block_count) { - return x1600_msc_read_blocks(msc_channel, card, paddr, block_address, + return x1600_msc_read_blocks(msc_channel, card, region, block_address, block_count); } diff -r 18edc9c73263 -r 0299f4644db0 pkg/landfall-examples/letux400_dma/letux400_dma.cc --- a/pkg/landfall-examples/letux400_dma/letux400_dma.cc Fri Feb 16 23:11:25 2024 +0100 +++ b/pkg/landfall-examples/letux400_dma/letux400_dma.cc Sat Feb 17 23:04:12 2024 +0100 @@ -1,7 +1,7 @@ /* * Test DMA transfers. * - * Copyright (C) 2018, 2020, 2021, 2023 Paul Boddie + * Copyright (C) 2018, 2020, 2021, 2023, 2024 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -60,12 +60,9 @@ /* Allocate memory to test transfers. */ - l4_cap_idx_t ds0_mem, ds1_mem; - l4_size_t ds0_size = L4_PAGESIZE, ds1_size = L4_PAGESIZE; - l4_addr_t ds0_addr, ds1_addr; - l4re_dma_space_dma_addr_t ds0_paddr, ds1_paddr; + struct dma_region ds0_region, ds1_region; - err = get_dma_region(ds0_size, 8, &ds0_addr, &ds0_paddr, &ds0_mem); + err = get_dma_region(L4_PAGESIZE, 8, &ds0_region); if (err) { @@ -73,7 +70,7 @@ return 1; } - err = get_dma_region(ds1_size, 8, &ds1_addr, &ds1_paddr, &ds1_mem); + err = get_dma_region(L4_PAGESIZE, 8, &ds1_region); if (err) { @@ -83,10 +80,10 @@ /* Fill the allocated memory. */ - memset((void *) ds0_addr, 0, ds0_size); - memset((void *) ds1_addr, 0, ds1_size); + memset((void *) ds0_region.vaddr, 0, ds0_region.size); + memset((void *) ds1_region.vaddr, 0, ds1_region.size); - sprintf((char *) ds0_addr, "The quick brown fox jumped over the lazy dog.\n"); + sprintf((char *) ds0_region.vaddr, "The quick brown fox jumped over the lazy dog.\n"); /* Interrupts. */ @@ -186,12 +183,12 @@ /* Transfer data between the allocated memory regions. */ - printf("Transfer from %llx to %llx...\n", ds0_paddr, ds1_paddr); + printf("Transfer from %llx to %llx...\n", ds0_region.paddr, ds1_region.paddr); unsigned int count = L4_PAGESIZE / 4; - unsigned int to_transfer = jz4730_dma_transfer(dma0, (uint32_t) ds0_paddr, - (uint32_t) ds1_paddr, + unsigned int to_transfer = jz4730_dma_transfer(dma0, (uint32_t) ds0_region.paddr, + (uint32_t) ds1_region.paddr, count, 1, 1, 4, 4, @@ -201,8 +198,8 @@ unsigned int transferred = to_transfer ? count - jz4730_dma_wait(dma0) : 0; printf("Transferred: %d\n", transferred); - printf("Source: %s\n", (char *) ds0_addr); - printf("Destination: %s\n", (char *) ds1_addr); + printf("Source: %s\n", (char *) ds0_region.vaddr); + printf("Destination: %s\n", (char *) ds1_region.vaddr); /* Detach from the interrupt. */