1.1 --- a/conf/landfall-examples/mips-x1600-info.io Sun Feb 11 00:36:08 2024 +0100 1.2 +++ b/conf/landfall-examples/mips-x1600-info.io Sun Feb 11 00:39:56 2024 +0100 1.3 @@ -10,6 +10,7 @@ 1.4 DMA = wrap(hw:match("x1600-dma")); 1.5 GPIO = wrap(hw:match("x1600-gpio")); 1.6 I2C = wrap(hw:match("x1600-i2c")); 1.7 + MSC = wrap(hw:match("x1600-msc")); 1.8 RTC = wrap(hw:match("x1600-rtc")); 1.9 SSI = wrap(hw:match("x1600-ssi")); 1.10 TCU = wrap(hw:match("x1600-tcu"));
2.1 --- a/pkg/devices/Control Sun Feb 11 00:36:08 2024 +0100 2.2 +++ b/pkg/devices/Control Sun Feb 11 00:39:56 2024 +0100 2.3 @@ -34,6 +34,7 @@ 2.4 provides: libdrivers-keypad-qi_lb60 2.5 provides: libdrivers-lcd-headers 2.6 provides: libdrivers-lcd-jz4740 2.7 +provides: libdrivers-msc 2.8 provides: libdrivers-panel-ci20 2.9 provides: libdrivers-panel-headers 2.10 provides: libdrivers-panel-letux400
3.1 --- a/pkg/devices/lib/Makefile Sun Feb 11 00:36:08 2024 +0100 3.2 +++ b/pkg/devices/lib/Makefile Sun Feb 11 00:39:56 2024 +0100 3.3 @@ -1,7 +1,7 @@ 3.4 PKGDIR ?= .. 3.5 L4DIR ?= $(PKGDIR)/../.. 3.6 3.7 -TARGET := aic common cpm dma gpio hdmi i2c keypad lcd panel pwm rtc spi tcu 3.8 +TARGET := aic common cpm dma gpio hdmi i2c keypad lcd msc panel pwm rtc spi tcu 3.9 3.10 include $(L4DIR)/mk/subdir.mk 3.11 3.12 @@ -13,6 +13,7 @@ 3.13 i2c: cpm dma gpio 3.14 keypad: common 3.15 lcd: common 3.16 +msc: common 3.17 panel: lcd 3.18 pwm: common 3.19 rtc: common
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/pkg/devices/lib/msc/Makefile Sun Feb 11 00:39:56 2024 +0100 4.3 @@ -0,0 +1,8 @@ 4.4 +PKGDIR ?= ../.. 4.5 +L4DIR ?= $(PKGDIR)/../.. 4.6 + 4.7 +TARGET := include src 4.8 + 4.9 +include $(L4DIR)/mk/subdir.mk 4.10 + 4.11 +src: include
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/pkg/devices/lib/msc/include/Makefile Sun Feb 11 00:39:56 2024 +0100 5.3 @@ -0,0 +1,4 @@ 5.4 +PKGDIR = ../../.. 5.5 +L4DIR ?= $(PKGDIR)/../.. 5.6 + 5.7 +include $(L4DIR)/mk/include.mk
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/pkg/devices/lib/msc/include/msc-common.h Sun Feb 11 00:39:56 2024 +0100 6.3 @@ -0,0 +1,160 @@ 6.4 +/* 6.5 + * MSC (MMC/SD controller) peripheral support. 6.6 + * 6.7 + * Copyright (C) 2024 Paul Boddie <paul@boddie.org.uk> 6.8 + * 6.9 + * This program is free software; you can redistribute it and/or 6.10 + * modify it under the terms of the GNU General Public License as 6.11 + * published by the Free Software Foundation; either version 2 of 6.12 + * the License, or (at your option) any later version. 6.13 + * 6.14 + * This program is distributed in the hope that it will be useful, 6.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 6.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 6.17 + * GNU General Public License for more details. 6.18 + * 6.19 + * You should have received a copy of the GNU General Public License 6.20 + * along with this program; if not, write to the Free Software 6.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, 6.22 + * Boston, MA 02110-1301, USA 6.23 + */ 6.24 + 6.25 +#pragma once 6.26 + 6.27 +#include <l4/re/c/dma_space.h> 6.28 +#include <l4/sys/types.h> 6.29 +#include <stdint.h> 6.30 + 6.31 + 6.32 + 6.33 +#ifdef __cplusplus 6.34 + 6.35 +#include <l4/devices/hw_mmio_register_block.h> 6.36 + 6.37 + 6.38 + 6.39 +// MMC/SD structures. 6.40 + 6.41 +struct CID 6.42 +{ 6.43 + uint16_t month:4, year:8, reserved:4; 6.44 + uint32_t serial; 6.45 + uint8_t revision; 6.46 + char name[5]; 6.47 + uint16_t oem; 6.48 + uint8_t manufacturer; 6.49 +} __attribute__((packed)); 6.50 + 6.51 +struct CSD 6.52 +{ 6.53 + uint8_t reserved0:2, format:2, temp_write_prot:1, perm_write_prot:1, copy:1, format_group:1; 6.54 + uint16_t reserved1:5, write_block_partial:1, write_blocklen:4, write_time_factor:3, 6.55 + reserved2:2, write_prot_group_enable:1; 6.56 + uint64_t write_prot_group_size:7, erase_sector_size:7, erase_single_block_enable:1, 6.57 + device_size_multiplier:3, max_write_current_max:3, max_write_current_min:3, 6.58 + max_read_current_max:3, max_read_current_min:3, device_size:12, 6.59 + reserved3:2, dsr_implemented:1, read_block_misalign:1, write_block_misalign:1, 6.60 + read_block_partial:1, read_blocklen:4, card_command_classes:12; 6.61 + uint8_t tran_speed, data_read_access_time_2, data_read_access_time_1, 6.62 + reserved4:6, csd:2; 6.63 +} __attribute__((packed)); 6.64 + 6.65 + 6.66 + 6.67 +// MMC/SD controller channel. 6.68 + 6.69 +class Msc_channel 6.70 +{ 6.71 +protected: 6.72 + l4_addr_t _msc_start; 6.73 + Hw::Register_block<32> _regs; 6.74 + l4_cap_idx_t _irq; 6.75 + 6.76 + // Support eight CID/CSD entries of 120 bits and RCA entries of 16 bits. 6.77 + 6.78 + struct CID _cid[8]; 6.79 + struct CSD _csd[8]; 6.80 + uint16_t _rca[8], _current_rca; 6.81 + uint8_t _cards; 6.82 + 6.83 + // Utility methods. 6.84 + 6.85 + uint32_t get_field(uint32_t reg, uint32_t mask, uint8_t shift); 6.86 + void set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value); 6.87 + 6.88 + // Low-level operations. 6.89 + 6.90 + void ack_irq(uint32_t flags); 6.91 + void unmask_irq(uint32_t flags); 6.92 + void reset(); 6.93 + void start_clock(); 6.94 + void stop_clock(); 6.95 + 6.96 + // Command properties. 6.97 + 6.98 + bool command_will_write(uint8_t index); 6.99 + bool command_with_data(uint8_t index); 6.100 + bool command_uses_busy(uint8_t index); 6.101 + uint8_t get_response_format(uint8_t index); 6.102 + uint8_t get_app_response_format(uint8_t index); 6.103 + 6.104 + // Command initiation. 6.105 + 6.106 + bool send_app_command(uint8_t index, uint32_t arg); 6.107 + bool send_command(uint8_t index, uint32_t arg); 6.108 + bool send_command(uint8_t index, uint32_t arg, uint8_t response_format, 6.109 + bool data, bool write, bool busy); 6.110 + 6.111 + // Response handling. 6.112 + 6.113 + bool have_response(); 6.114 + void read_response(uint16_t *buffer, uint8_t units); 6.115 + bool wait_for_irq(uint32_t flags); 6.116 + bool wait_for_irq(uint32_t flags, unsigned int timeout); 6.117 + 6.118 + // Initialisation operations. 6.119 + 6.120 + bool check_sd(); 6.121 + void init_sdio(); 6.122 + void init_sdmem(); 6.123 + void init_mmc(); 6.124 + void identify_cards(); 6.125 + void query_cards(); 6.126 + 6.127 + // Transfer operations. 6.128 + 6.129 + uint32_t recv_data(l4re_dma_space_dma_addr_t paddr, uint32_t count); 6.130 + uint32_t send_data(l4re_dma_space_dma_addr_t paddr, uint32_t count); 6.131 + 6.132 + virtual uint32_t transfer(l4re_dma_space_dma_addr_t from_paddr, 6.133 + l4re_dma_space_dma_addr_t to_paddr, 6.134 + bool recv, uint32_t count) = 0; 6.135 + 6.136 +public: 6.137 + explicit Msc_channel(l4_addr_t msc_start, l4_addr_t start, l4_cap_idx_t irq); 6.138 + 6.139 + virtual ~Msc_channel(); 6.140 + 6.141 + void enable(); 6.142 + 6.143 + uint32_t get_status(); 6.144 + 6.145 + uint32_t read_block(uint8_t card, l4re_dma_space_dma_addr_t paddr); 6.146 +}; 6.147 + 6.148 + 6.149 + 6.150 +// MMC/SD controller device control. 6.151 + 6.152 +class Msc_chip 6.153 +{ 6.154 +protected: 6.155 + l4_addr_t _msc_start, _start, _end; 6.156 + 6.157 + virtual unsigned int num_channels() = 0; 6.158 + 6.159 +public: 6.160 + explicit Msc_chip(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end); 6.161 +}; 6.162 + 6.163 +#endif /* __cplusplus */
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/pkg/devices/lib/msc/include/msc-jz4780.h Sun Feb 11 00:39:56 2024 +0100 7.3 @@ -0,0 +1,89 @@ 7.4 +/* 7.5 + * MSC (MMC/SD controller) peripheral support. 7.6 + * 7.7 + * Copyright (C) 2024 Paul Boddie <paul@boddie.org.uk> 7.8 + * 7.9 + * This program is free software; you can redistribute it and/or 7.10 + * modify it under the terms of the GNU General Public License as 7.11 + * published by the Free Software Foundation; either version 2 of 7.12 + * the License, or (at your option) any later version. 7.13 + * 7.14 + * This program is distributed in the hope that it will be useful, 7.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 7.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 7.17 + * GNU General Public License for more details. 7.18 + * 7.19 + * You should have received a copy of the GNU General Public License 7.20 + * along with this program; if not, write to the Free Software 7.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, 7.22 + * Boston, MA 02110-1301, USA 7.23 + */ 7.24 + 7.25 +#pragma once 7.26 + 7.27 +#include <l4/re/c/dma_space.h> 7.28 +#include <l4/sys/types.h> 7.29 +#include <stdint.h> 7.30 + 7.31 + 7.32 + 7.33 +#ifdef __cplusplus 7.34 + 7.35 +#include <l4/devices/dma-jz4780.h> 7.36 +#include <l4/devices/msc-common.h> 7.37 + 7.38 +// MMC/SD controller channel. 7.39 + 7.40 +class Msc_jz4780_channel : public Msc_channel 7.41 +{ 7.42 +protected: 7.43 + Dma_jz4780_channel *_dma; 7.44 + enum Dma_jz4780_request_type _request_type_in, _request_type_out; 7.45 + 7.46 +public: 7.47 + explicit Msc_jz4780_channel(l4_addr_t msc_start, l4_addr_t addr, 7.48 + l4_cap_idx_t irq, Dma_jz4780_channel *dma, 7.49 + enum Dma_jz4780_request_type request_type_in, 7.50 + enum Dma_jz4780_request_type request_type_out); 7.51 + 7.52 + uint32_t transfer(l4re_dma_space_dma_addr_t from_paddr, 7.53 + l4re_dma_space_dma_addr_t to_paddr, 7.54 + bool recv, uint32_t count); 7.55 +}; 7.56 + 7.57 + 7.58 + 7.59 +// MMC/SD controller device control. 7.60 + 7.61 +class Msc_jz4780_chip : public Msc_chip 7.62 +{ 7.63 +protected: 7.64 + unsigned int num_channels() 7.65 + { return 3; } 7.66 + 7.67 +public: 7.68 + explicit Msc_jz4780_chip(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end); 7.69 + 7.70 + Msc_channel *get_channel(uint8_t channel, l4_cap_idx_t irq, 7.71 + Dma_jz4780_channel *dma); 7.72 +}; 7.73 + 7.74 +#endif /* __cplusplus */ 7.75 + 7.76 +/* C language interface. */ 7.77 + 7.78 +EXTERN_C_BEGIN 7.79 + 7.80 +void *jz4780_msc_init(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end); 7.81 + 7.82 +void *jz4780_msc_get_channel(void *msc, uint8_t channel, l4_cap_idx_t irq, 7.83 + void *dma); 7.84 + 7.85 +uint32_t jz4780_msc_get_status(void *msc_channel); 7.86 + 7.87 +void jz4780_msc_enable(void *msc_channel); 7.88 + 7.89 +uint32_t jz4780_msc_read_block(void *msc_channel, uint8_t card, 7.90 + l4re_dma_space_dma_addr_t paddr); 7.91 + 7.92 +EXTERN_C_END
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/pkg/devices/lib/msc/include/msc-x1600.h Sun Feb 11 00:39:56 2024 +0100 8.3 @@ -0,0 +1,87 @@ 8.4 +/* 8.5 + * MSC (MMC/SD controller) peripheral support. 8.6 + * 8.7 + * Copyright (C) 2024 Paul Boddie <paul@boddie.org.uk> 8.8 + * 8.9 + * This program is free software; you can redistribute it and/or 8.10 + * modify it under the terms of the GNU General Public License as 8.11 + * published by the Free Software Foundation; either version 2 of 8.12 + * the License, or (at your option) any later version. 8.13 + * 8.14 + * This program is distributed in the hope that it will be useful, 8.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 8.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 8.17 + * GNU General Public License for more details. 8.18 + * 8.19 + * You should have received a copy of the GNU General Public License 8.20 + * along with this program; if not, write to the Free Software 8.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, 8.22 + * Boston, MA 02110-1301, USA 8.23 + */ 8.24 + 8.25 +#pragma once 8.26 + 8.27 +#include <l4/re/c/dma_space.h> 8.28 +#include <l4/sys/types.h> 8.29 +#include <stdint.h> 8.30 + 8.31 + 8.32 + 8.33 +#ifdef __cplusplus 8.34 + 8.35 +#include <l4/devices/dma-x1600.h> 8.36 +#include <l4/devices/msc-common.h> 8.37 + 8.38 +// MMC/SD controller channel. 8.39 + 8.40 +class Msc_x1600_channel : public Msc_channel 8.41 +{ 8.42 +protected: 8.43 + Dma_x1600_channel *_dma; 8.44 + enum Dma_x1600_request_type _request_type_in, _request_type_out; 8.45 + 8.46 +public: 8.47 + explicit Msc_x1600_channel(l4_addr_t msc_start, l4_addr_t addr, 8.48 + l4_cap_idx_t irq, Dma_x1600_channel *dma, 8.49 + enum Dma_x1600_request_type request_type_in, 8.50 + enum Dma_x1600_request_type request_type_out); 8.51 + 8.52 + uint32_t transfer(l4re_dma_space_dma_addr_t from_paddr, 8.53 + l4re_dma_space_dma_addr_t to_paddr, 8.54 + bool recv, uint32_t count); 8.55 +}; 8.56 + 8.57 +// MMC/SD controller device control. 8.58 + 8.59 +class Msc_x1600_chip : public Msc_chip 8.60 +{ 8.61 +protected: 8.62 + unsigned int num_channels() 8.63 + { return 2; } 8.64 + 8.65 +public: 8.66 + explicit Msc_x1600_chip(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end); 8.67 + 8.68 + Msc_channel *get_channel(uint8_t channel, l4_cap_idx_t irq, 8.69 + Dma_x1600_channel *dma); 8.70 +}; 8.71 + 8.72 +#endif /* __cplusplus */ 8.73 + 8.74 +/* C language interface. */ 8.75 + 8.76 +EXTERN_C_BEGIN 8.77 + 8.78 +void *x1600_msc_init(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end); 8.79 + 8.80 +void *x1600_msc_get_channel(void *msc, uint8_t channel, l4_cap_idx_t irq, 8.81 + void *dma); 8.82 + 8.83 +uint32_t x1600_msc_get_status(void *msc_channel); 8.84 + 8.85 +void x1600_msc_enable(void *msc_channel); 8.86 + 8.87 +uint32_t x1600_msc_read_block(void *msc_channel, uint8_t card, 8.88 + l4re_dma_space_dma_addr_t paddr); 8.89 + 8.90 +EXTERN_C_END
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/pkg/devices/lib/msc/src/Makefile Sun Feb 11 00:39:56 2024 +0100 9.3 @@ -0,0 +1,13 @@ 9.4 +PKGDIR ?= ../../.. 9.5 +L4DIR ?= $(PKGDIR)/../.. 9.6 + 9.7 +TARGET = libmsc.o.a libmsc.o.so 9.8 +PC_FILENAME := libdrivers-msc 9.9 + 9.10 +SRC_CC := common.cc jz4780.cc x1600.cc 9.11 + 9.12 +PRIVATE_INCDIR += $(PKGDIR)/lib/msc/include 9.13 + 9.14 +REQUIRES_LIBS := l4re_c l4re_c-util libdrivers-common 9.15 + 9.16 +include $(L4DIR)/mk/lib.mk
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 10.2 +++ b/pkg/devices/lib/msc/src/common.cc Sun Feb 11 00:39:56 2024 +0100 10.3 @@ -0,0 +1,1232 @@ 10.4 +/* 10.5 + * MSC (MMC/SD controller) peripheral support. 10.6 + * 10.7 + * Copyright (C) 2024 Paul Boddie <paul@boddie.org.uk> 10.8 + * 10.9 + * This program is free software; you can redistribute it and/or 10.10 + * modify it under the terms of the GNU General Public License as 10.11 + * published by the Free Software Foundation; either version 2 of 10.12 + * the License, or (at your option) any later version. 10.13 + * 10.14 + * This program is distributed in the hope that it will be useful, 10.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10.17 + * GNU General Public License for more details. 10.18 + * 10.19 + * You should have received a copy of the GNU General Public License 10.20 + * along with this program; if not, write to the Free Software 10.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, 10.22 + * Boston, MA 02110-1301, USA 10.23 + */ 10.24 + 10.25 +#include <l4/devices/hw_mmio_register_block.h> 10.26 +#include <l4/sys/irq.h> 10.27 +#include <l4/util/util.h> 10.28 + 10.29 +#include <stdio.h> 10.30 +#include <string.h> 10.31 + 10.32 +#include "msc-common.h" 10.33 + 10.34 + 10.35 + 10.36 +// Register locations for each channel. 10.37 + 10.38 +enum Regs : unsigned 10.39 +{ 10.40 + Msc_control = 0x000, // MSC_CTRL 10.41 + Msc_status = 0x004, // MSC_STAT 10.42 + Msc_clock_rate = 0x008, // MSC_CLKRT 10.43 + Msc_command_data_control = 0x00c, // MSC_CMDAT 10.44 + Msc_response_timeout = 0x010, // MSC_RESTO 10.45 + Msc_read_timeout = 0x014, // MSC_RDTO 10.46 + Msc_block_length = 0x018, // MSC_BLKLEN 10.47 + Msc_block_count = 0x01c, // MSC_NOB 10.48 + Msc_block_success_count = 0x020, // MSC_SNOB 10.49 + Msc_interrupt_mask = 0x024, // MSC_IMASK 10.50 + Msc_interrupt_flag = 0x028, // MSC_IFLG/MSC_IREG 10.51 + Msc_command_index = 0x02c, // MSC_CMD 10.52 + Msc_command_argument = 0x030, // MSC_ARG 10.53 + Msc_response_fifo = 0x034, // MSC_RES 10.54 + Msc_recv_data_fifo = 0x038, // MSC_RXFIFO 10.55 + Msc_trans_data_fifo = 0x03c, // MSC_TXFIFO 10.56 + 10.57 + // JZ4780/X1600 only. 10.58 + 10.59 + Msc_low_power_mode = 0x040, // MSC_LPM 10.60 + Msc_dma_control = 0x044, // MSC_DMAC 10.61 + Msc_dma_descriptor_address = 0x048, // MSC_DMANDA 10.62 + Msc_dma_data_address = 0x04c, // MSC_DMADA 10.63 + Msc_dma_data_length = 0x050, // MSC_DMALEN 10.64 + Msc_dma_command = 0x054, // MSC_DMACMD 10.65 + Msc_control2 = 0x058, // MSC_CTRL2 10.66 + Msc_rtfifo_data_counter = 0x05c, // MSC_RTCNT 10.67 + 10.68 + // Channel block size/offset. 10.69 + 10.70 + Msc_channel_offset = 0x10000, 10.71 +}; 10.72 + 10.73 +// Field definitions. 10.74 + 10.75 +enum Control_bits : unsigned 10.76 +{ 10.77 + // JZ4780/X1600 only. 10.78 + 10.79 + Control_send_ccsd = 0x8000, // SEND_CCSD 10.80 + Control_send_ccsd_automatically = 0x4000, // SEND_CCSD 10.81 + 10.82 + // Common. 10.83 + 10.84 + Control_exit_multiple = 0x0080, // EXIT_MULTIPLE 10.85 + Control_exit_transfer = 0x0040, // EXIT_TRANSFER 10.86 + Control_start_read_wait = 0x0020, // START_READ_WAIT 10.87 + Control_stop_read_wait = 0x0010, // STOP_READ_WAIT 10.88 + Control_reset = 0x0008, // RESET 10.89 + Control_start_operation = 0x0004, // START_OP 10.90 + 10.91 + Control_clock_control_field_mask = 0x3, // CLOCK_CTRL 10.92 + Control_clock_control_start = 2, 10.93 + Control_clock_control_stop = 1, 10.94 + Control_clock_control_field_shift = 0, 10.95 +}; 10.96 + 10.97 +enum Control2_bits : unsigned 10.98 +{ 10.99 + // JZ4780/X1600 only. 10.100 + 10.101 + Control2_pin_level_polarity_field_mask = 0x1f, // PIP 10.102 + Control2_pin_level_polarity_field_shift = 24, 10.103 + 10.104 + // JZ4780 only. 10.105 + 10.106 + Control2_reset_enable = 0x00800000, // RST_EN 10.107 + 10.108 + // JZ4780/X1600 only. 10.109 + 10.110 + Control2_stop_read_operation_mode = 0x00000010, // STPRM 10.111 + 10.112 + // JZ4780 only. 10.113 + 10.114 + Control2_signal_voltage_change = 0x00000008, // SVC 10.115 + 10.116 + // JZ4780/X1600 only. 10.117 + 10.118 + Control2_speed_mode_field_mask = 0x7, // SMS 10.119 + Control2_speed_mode_default = 0, // = 0 10.120 + Control2_speed_mode_high = 1, // = 1 10.121 + Control2_speed_mode_sdr12 = 2, // = 2 10.122 + Control2_speed_mode_sdr25 = 3, // = 3 10.123 + Control2_speed_mode_sdr50 = 4, // = 4 10.124 + Control2_speed_mode_field_shift = 0, 10.125 +}; 10.126 + 10.127 +enum Status_bits : unsigned 10.128 +{ 10.129 + // JZ4780/X1600 only. 10.130 + 10.131 + Status_auto_cmd12_done = 0x80000000, // AUTO_CMD12_DONE 10.132 + 10.133 + // JZ4780 only. 10.134 + 10.135 + Status_auto_cmd23_done = 0x40000000, // AUTO_CMD23_DONE 10.136 + Status_signal_voltage_change = 0x20000000, // SVS 10.137 + 10.138 + // JZ4780/X1600 only. 10.139 + 10.140 + Status_pin_level_field_mask = 0x1f, // PIN_LEVEL 10.141 + Status_pin_level_field_shift = 24, 10.142 + 10.143 + Status_boot_crc_error = 0x00100000, // BCE 10.144 + Status_boot_data_end = 0x00080000, // BDE 10.145 + Status_boot_ack_error = 0x00040000, // BAE 10.146 + Status_boot_ack_received = 0x00020000, // BAR 10.147 + Status_dma_end = 0x00010000, // DMAEND 10.148 + 10.149 + // Common. 10.150 + 10.151 + Status_resetting = 0x8000, // IS_RESETTING 10.152 + Status_sdio_interrupt_active = 0x4000, // SDIO_INT_ACTIVE 10.153 + Status_programming_done = 0x2000, // PRG_DONE 10.154 + Status_data_transfer_done = 0x1000, // DATA_TRAN_DONE 10.155 + Status_end_command_response = 0x0800, // END_CMD_RES 10.156 + Status_data_fifo_almost_full = 0x0400, // DATA_FIFO_AFULL 10.157 + Status_read_wait = 0x0200, // IS_READWAIT 10.158 + Status_clock_enabled = 0x0100, // CLK_EN 10.159 + Status_data_fifo_full = 0x0080, // DATA_FIFO_FULL 10.160 + Status_data_fifo_empty = 0x0040, // DATA_FIFO_EMPTY 10.161 + Status_response_crc_error = 0x0020, // CRC_RES_ERR 10.162 + Status_read_crc_error = 0x0010, // CRC_READ_ERROR 10.163 + Status_write_crc_error_no_status = 0x0008, // CRC_WRITE_ERROR (2) 10.164 + Status_write_crc_error_data = 0x0004, // CRC_WRITE_ERROR (1) 10.165 + Status_timeout_response = 0x0002, // TIME_OUT_RES 10.166 + Status_timeout_read = 0x0001, // TIME_OUT_READ 10.167 +}; 10.168 + 10.169 +enum Clock_rate_bits : unsigned 10.170 +{ 10.171 + Clock_rate_field_mask = 0x7, // CLK_RATE 10.172 + Clock_rate_field_shift = 0, 10.173 +}; 10.174 + 10.175 +enum Command_data_control_bits : unsigned 10.176 +{ 10.177 + // JZ4780/X1600 only. 10.178 + 10.179 + Cdc_ccs_expected = 0x80000000, // CCS_EXPECTED 10.180 + Cdc_read_ce_ata = 0x40000000, // READ_CEATA 10.181 + Cdc_disable_boot = 0x08000000, // DIS_BOOT 10.182 + Cdc_expect_boot_ack = 0x02000000, // EXP_BOOT_ACK 10.183 + Cdc_alternative_boot_mode = 0x01000000, // BOOT_MODE 10.184 + 10.185 + // JZ4780 only. 10.186 + 10.187 + Cdc_auto_cmd23 = 0x00040000, // AUTO_CMD23 10.188 + 10.189 + // JZ4780/X1600 only. 10.190 + 10.191 + Cdc_sdio_interrupt_2cycle = 0x00020000, // SDIO_PRDT 10.192 + Cdc_auto_cmd12 = 0x00010000, // AUTO_CMD12 10.193 + 10.194 + Cdc_recv_fifo_level_field_mask = 0x3, // RTRG 10.195 + Cdc_fifo_level_16 = 0, 10.196 + Cdc_fifo_level_32 = 1, 10.197 + Cdc_fifo_level_64 = 2, 10.198 + Cdc_fifo_level_96 = 3, 10.199 + Cdc_recv_fifo_level_field_shift = 14, 10.200 + 10.201 + Cdc_trans_fifo_level_field_mask = 0x3, // TTRG 10.202 + Cdc_trans_fifo_level_field_shift = 12, 10.203 + 10.204 + // Common. 10.205 + 10.206 + Cdc_io_abort = 0x0800, // IO_ABORT 10.207 + 10.208 + Cdc_bus_width_field_mask = 0x3, // BUS_WIDTH 10.209 + Cdc_bus_width_field_1bit = 0, // = 0 10.210 + Cdc_bus_width_field_4bit = 2, // = 2 10.211 + Cdc_bus_width_field_shift = 9, 10.212 + 10.213 + // JZ4740 only. 10.214 + 10.215 + Cdc_dma_enable = 0x0100, // DMA_EN 10.216 + Cdc_dma_disable = 0x0000, 10.217 + 10.218 + // Common. 10.219 + 10.220 + Cdc_init_sequence = 0x0080, // INIT 10.221 + 10.222 + Cdc_expect_busy = 0x0040, // BUSY 10.223 + Cdc_do_not_expect_busy = 0x0000, 10.224 + 10.225 + Cdc_stream_block = 0x0020, // STREAM_BLOCK 10.226 + Cdc_not_stream_block = 0x0000, 10.227 + 10.228 + Cdc_write_operation = 0x0010, // WRITE_READ 10.229 + Cdc_read_operation = 0x0000, 10.230 + 10.231 + Cdc_data_with_command = 0x0008, // DATA_EN 10.232 + Cdc_no_data_with_command = 0x0000, 10.233 + 10.234 + Cdc_response_format_field_mask = 0x7, // RESPONSE_FORMAT 10.235 + Cdc_response_format_field_shift = 0, 10.236 +}; 10.237 + 10.238 +enum Response_timeout_bits : unsigned 10.239 +{ 10.240 + // NOTE: 16-bit value in the JZ4780. 10.241 + // NOTE: 32-bit value in the X1600. 10.242 + 10.243 + Response_timeout_mask = 0x000000ff, // RES_TO 10.244 +}; 10.245 + 10.246 +enum Read_timeout_bits : unsigned 10.247 +{ 10.248 + // NOTE: 16-bit value prior to the JZ4780/X1600. 10.249 + 10.250 + Read_timeout_mask = 0xffffffff, // READ_TO 10.251 +}; 10.252 + 10.253 +enum Block_length_bits : unsigned 10.254 +{ 10.255 + // NOTE: 16-bit value in the JZ4780/X1600. 10.256 + 10.257 + Block_length_mask = 0x00000fff, // BLK_LEN 10.258 +}; 10.259 + 10.260 +enum Block_count_bits : unsigned 10.261 +{ 10.262 + Block_count_mask = 0x0000ffff, // NOB/SNOB 10.263 +}; 10.264 + 10.265 +// Interrupt mask/flag bits. 10.266 + 10.267 +enum Interrupt_bits : unsigned 10.268 +{ 10.269 + // X1600 only. 10.270 + 10.271 + Int_dma_data_done = 0x80000000, // DMA_DATA_DONE 10.272 + 10.273 + // JZ4780 only. 10.274 + 10.275 + Int_auto_cmd23_done = 0x40000000, // AUTO_CMD23_DONE 10.276 + Int_signal_voltage_change = 0x20000000, // SVS 10.277 + 10.278 + // JZ4780/X1600 only. 10.279 + 10.280 + Int_pin_level_field_mask = 0x1f, // PIN_LEVEL 10.281 + Int_pin_level_field_shift = 24, 10.282 + 10.283 + // X1600 only. 10.284 + 10.285 + Int_write_request_all_done = 0x00800000, // WR_ALL_DONE 10.286 + 10.287 + // JZ4780/X1600 only. 10.288 + 10.289 + Int_boot_crc_error = 0x00100000, // BCE 10.290 + Int_boot_data_end = 0x00080000, // BDE 10.291 + Int_boot_ack_error = 0x00040000, // BAE 10.292 + Int_boot_ack_received = 0x00020000, // BAR 10.293 + Int_dma_end = 0x00010000, // DMAEND 10.294 + Int_auto_cmd12_done = 0x00008000, // AUTO_CMD12_DONE 10.295 + Int_data_fifo_full = 0x00004000, // DATA_FIFO_FULL 10.296 + Int_data_fifo_empty = 0x00002000, // DATA_FIFO_EMP 10.297 + Int_crc_response_error = 0x00001000, // CRC_RES_ERR 10.298 + Int_crc_read_error = 0x00000800, // CRC_READ_ERR 10.299 + Int_crc_write_error = 0x00000400, // CRC_WRITE_ERR 10.300 + Int_response_timeout = 0x00000200, // TIME_OUT_RES 10.301 + Int_read_timeout = 0x00000100, // TIME_OUT_READ 10.302 + 10.303 + // Common. 10.304 + 10.305 + Int_sdio = 0x80, // SDIO 10.306 + Int_trans_fifo_write_request = 0x40, // TXFIFO_WR_REQ 10.307 + Int_recv_fifo_read_request = 0x20, // RXFIFO_RD_REQ 10.308 + Int_end_command_response = 0x04, // END_CMD_RES 10.309 + Int_programming_done = 0x02, // PRG_DONE 10.310 + Int_data_transfer_done = 0x01, // DATA_TRAN_DONE 10.311 +}; 10.312 + 10.313 +enum Command_index_bits : unsigned 10.314 +{ 10.315 + Command_index_mask = 0x0000003f, // CMD_INDEX 10.316 +}; 10.317 + 10.318 +enum Command_argument_bits : unsigned 10.319 +{ 10.320 + Command_argument_mask = 0xffffffff, // ARG 10.321 +}; 10.322 + 10.323 +enum Response_fifo_bits : unsigned 10.324 +{ 10.325 + Response_fifo_mask = 0x0000ffff, // DATA 10.326 +}; 10.327 + 10.328 +enum Recv_data_fifo_bits : unsigned 10.329 +{ 10.330 + Recv_data_fifo_mask = 0xffffffff, // DATA 10.331 +}; 10.332 + 10.333 +enum Trans_data_fifo_bits : unsigned 10.334 +{ 10.335 + Trans_data_fifo_mask = 0xffffffff, // DATA 10.336 +}; 10.337 + 10.338 +enum Low_power_mode_bits : unsigned 10.339 +{ 10.340 + Low_power_mode_enable = 0x00000001, // LPM 10.341 +}; 10.342 + 10.343 +enum Dma_control_bits : unsigned 10.344 +{ 10.345 + Dma_mode_specify_transfer_length = 0x80, // MODE_SEL 10.346 + 10.347 + Dma_address_offset_field_mask = 0x3, // AOFST 10.348 + Dma_address_offset_field_shift = 5, 10.349 + 10.350 + Dma_align_enable = 0x10, // ALIGNEN 10.351 + 10.352 + Dma_burst_type_field_mask = 0x3, // INCR 10.353 + Dma_burst_type_incr16 = 0, 10.354 + Dma_burst_type_incr32 = 1, 10.355 + Dma_burst_type_incr64 = 2, 10.356 + Dma_burst_type_field_shift = 2, 10.357 + 10.358 + Dma_select_common_dma = 0x02, // DMASEL 10.359 + Dma_select_special_dma = 0x00, 10.360 + 10.361 + Dma_enable = 0x01, // DMAEN 10.362 + Dma_disable = 0x00, 10.363 +}; 10.364 + 10.365 + 10.366 + 10.367 +// Command indexes. 10.368 + 10.369 +enum Command_index : unsigned 10.370 +{ 10.371 + Command_go_idle_state = 0, 10.372 + Command_send_op_cond = 1, 10.373 + Command_all_send_cid = 2, 10.374 + Command_send_relative_addr = 3, // SD 10.375 + Command_set_relative_addr = 3, // MMC 10.376 + Command_set_dsr = 4, 10.377 + Command_io_send_op_cond = 5, // SDIO 10.378 + Command_select_deselect_card = 7, 10.379 + Command_send_if_cond = 8, 10.380 + Command_send_csd = 9, 10.381 + Command_send_cid = 10, 10.382 + Command_read_dat_until_stop = 11, 10.383 + Command_stop_transmission = 12, 10.384 + Command_send_status = 13, 10.385 + Command_go_inactive_state = 15, 10.386 + Command_set_blocklen = 16, 10.387 + Command_read_single_block = 17, 10.388 + Command_read_multiple_block = 18, 10.389 + Command_write_dat_until_stop = 20, 10.390 + Command_set_block_count = 23, 10.391 + Command_write_block = 24, 10.392 + Command_write_multiple_block = 25, 10.393 + Command_program_cid = 26, 10.394 + Command_program_csd = 27, 10.395 + Command_set_write_prot = 28, 10.396 + Command_clr_write_prot = 29, 10.397 + Command_send_write_prot = 30, 10.398 + Command_tag_sector_start = 32, 10.399 + Command_tag_sector_end = 33, 10.400 + Command_untag_sector = 34, 10.401 + Command_tag_erase_group_start = 35, 10.402 + Command_tag_erase_group_end = 36, 10.403 + Command_untag_erase_group = 37, 10.404 + Command_erase = 38, 10.405 + Command_fast_io = 39, 10.406 + Command_go_irq_state = 40, 10.407 + Command_lock_unlock = 42, 10.408 + Command_io_rw_direct = 52, // SDIO 10.409 + Command_app_cmd = 55, 10.410 + Command_gen_cmd = 56, 10.411 +}; 10.412 + 10.413 +// Application-specific command indexes, used by first issuing Command_app_cmd. 10.414 + 10.415 +enum App_command_index : unsigned 10.416 +{ 10.417 + App_command_set_bus_width = 6, 10.418 + App_command_sd_status = 13, 10.419 + App_command_send_num_wr_blocks = 22, 10.420 + App_command_set_wr_block_erase_count = 23, 10.421 + App_command_sd_send_op_cond = 41, 10.422 + App_command_set_clr_card_detect = 42, 10.423 + App_command_send_scr = 51, 10.424 + App_command_read_ocr = 58, 10.425 +}; 10.426 + 10.427 +enum Bus_width_bits : unsigned 10.428 +{ 10.429 + Bus_width_1bit = 0, 10.430 + Bus_width_4bit = 2, 10.431 +}; 10.432 + 10.433 +// Command response sizes in 16-bit units. 10.434 + 10.435 +enum Response_sizes : unsigned 10.436 +{ 10.437 + Response_size_R1 = 3, 10.438 + Response_size_R2 = 8, // omits the CRC and end bit 10.439 + Response_size_R3 = 3, 10.440 + Response_size_R4 = 3, 10.441 + Response_size_R5 = 3, 10.442 + Response_size_R6 = 3, 10.443 + Response_size_R7 = 3, 10.444 +}; 10.445 + 10.446 +// SD_SEND_OP_COND argument flags. 10.447 + 10.448 +enum Ocr_argument_flags : unsigned 10.449 +{ 10.450 + Ocr_high_capacity_storage = 0x40000000, 10.451 +}; 10.452 + 10.453 +// SD_SEND_OP_COND response flags (R3). 10.454 + 10.455 +enum Ocr_response_flags : unsigned 10.456 +{ 10.457 + Ocr_card_powered_up = 0x80000000, 10.458 +}; 10.459 + 10.460 +// R1 status flags. 10.461 + 10.462 +enum R1_status_flags : unsigned 10.463 +{ 10.464 + R1_status_error_mask = 0xffff0000, 10.465 +}; 10.466 + 10.467 + 10.468 + 10.469 +// MMC response structures. 10.470 + 10.471 +struct R1 10.472 +{ 10.473 + uint8_t end_crc; 10.474 + uint32_t status; 10.475 + uint8_t index:6, trans_start:2; 10.476 +} __attribute__((packed)); 10.477 + 10.478 +struct R2 10.479 +{ 10.480 + // uint8_t end_crc; (not retrieved) 10.481 + 10.482 + union 10.483 + { 10.484 + uint8_t raw[15]; 10.485 + struct CID cid; 10.486 + struct CSD csd; 10.487 + } payload; 10.488 + 10.489 + uint8_t reserved_trans_start; 10.490 +} __attribute__((packed)); 10.491 + 10.492 +struct R3 10.493 +{ 10.494 + uint8_t end_reserved; 10.495 + uint32_t ocr; 10.496 + uint8_t reserved_trans_start; 10.497 +} __attribute__((packed)); 10.498 + 10.499 +// SDIO response structures. 10.500 + 10.501 +struct R4 10.502 +{ 10.503 + uint8_t end_reserved; 10.504 + uint32_t ocr:24, stuff:3, memory_present:1, number_io_functions:3, ready:1; 10.505 + uint8_t reserved_trans_start; 10.506 +} __attribute__((packed)); 10.507 + 10.508 +struct R5 10.509 +{ 10.510 + uint8_t end_crc; 10.511 + uint8_t data; 10.512 + uint8_t out_of_range:1, invalid_function_number:1, reserved:1, error:1, 10.513 + io_current_state:2, illegal_command:1, crc_error:1; 10.514 + uint16_t stuff; 10.515 + uint8_t index:6, trans_start:2; 10.516 +} __attribute__((packed)); 10.517 + 10.518 +struct R6 10.519 +{ 10.520 + uint8_t end_crc; 10.521 + uint16_t status; 10.522 + uint16_t rca; 10.523 + uint8_t index:6, trans_start:2; 10.524 +} __attribute__((packed)); 10.525 + 10.526 +struct R7 10.527 +{ 10.528 + uint8_t end_crc; 10.529 + 10.530 + union 10.531 + { 10.532 + uint32_t check:8, voltage:4, reserved:20; 10.533 + uint32_t raw; 10.534 + } check_voltage; 10.535 + 10.536 + uint8_t index:6, trans_start:2; 10.537 +} __attribute__((packed)); 10.538 + 10.539 + 10.540 + 10.541 +// Command frame: 10.542 +// byte: start (1), direction (1), command (6) 10.543 +// 4 bytes: argument 10.544 +// byte: CRC (7), end (1) 10.545 + 10.546 +// IO_RW_DIRECT argument: 10.547 +// Argument MSB to LSB: R/W (1), function number (3), read after write flag (1), 10.548 +// stuff (1), register address (17), stuff (1), 10.549 +// write data or stuff (8) 10.550 +// 0x88000c08: W, function = 0, read after write, register address = 6 (CCCR), 10.551 +// data = 8 (reset) 10.552 + 10.553 +const uint32_t Io_rw_direct_reset = 0x88000c08; 10.554 + 10.555 +// (IO_)SEND_OP_COND argument and default voltage range expected in R3, R4: 10.556 +// Argument MSB to LSB: stuff (8), voltage range (16), reserved (8) 10.557 +// 0x00ff8000: voltage range 2.7 - 3.6V 10.558 + 10.559 +const uint32_t Ocr_default_voltage_range = 0x00ff8000; 10.560 + 10.561 +// SEND_IF_COND argument and default voltage range expected in R7: 10.562 +// Argument MSB to LSB: stuff (20), voltage supplied (4), check (8) 10.563 +// 0x000001aa: voltage range 2.7 - 3.6V, check = 0b10101010 10.564 + 10.565 +const uint32_t If_cond_default_voltage_range = 0x000001aa; 10.566 + 10.567 + 10.568 + 10.569 +// Channel abstraction. 10.570 + 10.571 +Msc_channel::Msc_channel(l4_addr_t msc_start, l4_addr_t addr, l4_cap_idx_t irq) 10.572 +: _msc_start(msc_start), _irq(irq) 10.573 +{ 10.574 + _regs = new Hw::Mmio_register_block<32>(addr); 10.575 +} 10.576 + 10.577 +Msc_channel::~Msc_channel() 10.578 +{ 10.579 +} 10.580 + 10.581 +// Utility methods. 10.582 +// NOTE: Also defined in the CPM abstraction, should be consolidated. 10.583 + 10.584 +uint32_t 10.585 +Msc_channel::get_field(uint32_t reg, uint32_t mask, uint8_t shift) 10.586 +{ 10.587 + return (_regs[reg] & (mask << shift)) >> shift; 10.588 +} 10.589 + 10.590 +void 10.591 +Msc_channel::set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value) 10.592 +{ 10.593 + _regs[reg] = (_regs[reg] & (~(mask << shift))) | ((mask & value) << shift); 10.594 +} 10.595 + 10.596 +bool 10.597 +Msc_channel::command_will_write(uint8_t index) 10.598 +{ 10.599 + // NOTE: Probably incomplete coverage. 10.600 + 10.601 + switch (index) 10.602 + { 10.603 + case Command_write_dat_until_stop: return true; 10.604 + case Command_write_block: return true; 10.605 + case Command_write_multiple_block: return true; 10.606 + case Command_program_cid: return true; 10.607 + case Command_program_csd: return true; 10.608 + case Command_lock_unlock: return true; 10.609 + default: return false; 10.610 + } 10.611 +} 10.612 + 10.613 +bool 10.614 +Msc_channel::command_with_data(uint8_t index) 10.615 +{ 10.616 + // NOTE: Probably incomplete coverage. 10.617 + 10.618 + switch (index) 10.619 + { 10.620 + case Command_read_dat_until_stop: return true; 10.621 + case Command_read_single_block: return true; 10.622 + case Command_read_multiple_block: return true; 10.623 + case Command_write_dat_until_stop: return true; 10.624 + case Command_write_block: return true; 10.625 + case Command_write_multiple_block: return true; 10.626 + case Command_program_cid: return true; 10.627 + case Command_program_csd: return true; 10.628 + case Command_lock_unlock: return true; 10.629 + default: return false; 10.630 + } 10.631 +} 10.632 + 10.633 +bool 10.634 +Msc_channel::command_uses_busy(uint8_t index) 10.635 +{ 10.636 + // NOTE: Probably incomplete coverage. 10.637 + 10.638 + switch (index) 10.639 + { 10.640 + case Command_select_deselect_card: return true; 10.641 + case Command_stop_transmission: return true; 10.642 + default: return false; 10.643 + } 10.644 +} 10.645 + 10.646 +uint8_t 10.647 +Msc_channel::get_response_format(uint8_t index) 10.648 +{ 10.649 + // NOTE: Probably incomplete coverage. 10.650 + 10.651 + switch (index) 10.652 + { 10.653 + // Common commands without response. 10.654 + 10.655 + case Command_go_idle_state: return 0; 10.656 + case Command_set_dsr: return 0; 10.657 + case Command_go_inactive_state: return 0; 10.658 + 10.659 + // Common commands with response. 10.660 + 10.661 + case Command_send_op_cond: return 3; 10.662 + case Command_all_send_cid: return 2; 10.663 + case Command_send_csd: return 2; 10.664 + case Command_send_cid: return 2; 10.665 + 10.666 + // SDIO only. 10.667 + 10.668 + case Command_io_send_op_cond: return 4; 10.669 + case Command_io_rw_direct: return 5; 10.670 + 10.671 + // SDMEM only. 10.672 + 10.673 + case Command_send_relative_addr: return 6; 10.674 + case Command_send_if_cond: return 7; 10.675 + 10.676 + // All other commands. 10.677 + 10.678 + default: return 1; 10.679 + } 10.680 +} 10.681 + 10.682 +uint8_t 10.683 +Msc_channel::get_app_response_format(uint8_t index) 10.684 +{ 10.685 + // NOTE: Probably incomplete coverage. 10.686 + 10.687 + switch (index) 10.688 + { 10.689 + // SDMEM only. 10.690 + 10.691 + case App_command_sd_send_op_cond: return 3; 10.692 + 10.693 + // All other commands. 10.694 + 10.695 + default: return 1; 10.696 + } 10.697 +} 10.698 + 10.699 +// Read a response directly from the FIFO. 10.700 + 10.701 +void 10.702 +Msc_channel::read_response(uint16_t *buffer, uint8_t units) 10.703 +{ 10.704 + uint8_t unit = units; 10.705 + 10.706 + while (unit > 0) 10.707 + { 10.708 + uint32_t data = _regs[Msc_response_fifo]; 10.709 + 10.710 + // Ignore the upper byte of the last unit in small transfers since it is the 10.711 + // lower byte from the previous unit not shifted out of the register. 10.712 + 10.713 + unit--; 10.714 + 10.715 + if ((unit == 0) && (units == 3)) 10.716 + buffer[unit] = (data & 0xff) << 8; 10.717 + else 10.718 + buffer[unit] = data; 10.719 + } 10.720 +} 10.721 + 10.722 +void 10.723 +Msc_channel::ack_irq(uint32_t flags) 10.724 +{ 10.725 + // Clear the flags by setting them. 10.726 + 10.727 + _regs[Msc_interrupt_flag] = _regs[Msc_interrupt_flag] | flags; 10.728 +} 10.729 + 10.730 +void 10.731 +Msc_channel::unmask_irq(uint32_t flags) 10.732 +{ 10.733 + ack_irq(flags); 10.734 + 10.735 + if (_regs[Msc_interrupt_mask] & flags) 10.736 + _regs[Msc_interrupt_mask] = _regs[Msc_interrupt_mask] & ~flags; 10.737 +} 10.738 + 10.739 +void 10.740 +Msc_channel::reset() 10.741 +{ 10.742 + _regs[Msc_control] = _regs[Msc_control] | Control_reset; 10.743 + 10.744 + // NOTE: X1600 and other recent SoCs only. 10.745 + 10.746 + _regs[Msc_control] = _regs[Msc_control] & ~Control_reset; 10.747 + 10.748 + // Sufficient for other SoCs... 10.749 + 10.750 + while (_regs[Msc_status] & Status_resetting); 10.751 +} 10.752 + 10.753 +void 10.754 +Msc_channel::start_clock() 10.755 +{ 10.756 + set_field(Msc_control, Control_clock_control_field_mask, 10.757 + Control_clock_control_field_shift, Control_clock_control_start); 10.758 + 10.759 + while (!(_regs[Msc_status] & Status_clock_enabled)); 10.760 +} 10.761 + 10.762 +void 10.763 +Msc_channel::stop_clock() 10.764 +{ 10.765 + set_field(Msc_control, Control_clock_control_field_mask, 10.766 + Control_clock_control_field_shift, Control_clock_control_stop); 10.767 + 10.768 + while (_regs[Msc_status] & Status_clock_enabled); 10.769 +} 10.770 + 10.771 +uint32_t 10.772 +Msc_channel::get_status() 10.773 +{ 10.774 + return _regs[Msc_status]; 10.775 +} 10.776 + 10.777 +// Send an application-specific command. 10.778 + 10.779 +bool 10.780 +Msc_channel::send_app_command(uint8_t index, uint32_t arg) 10.781 +{ 10.782 + if (!send_command(Command_app_cmd, 0, get_app_response_format(index), 10.783 + false, false, false)) 10.784 + return false; 10.785 + 10.786 + return send_command(index, arg); 10.787 +} 10.788 + 10.789 +// Send a common MMC/SD command. 10.790 + 10.791 +bool 10.792 +Msc_channel::send_command(uint8_t index, uint32_t arg) 10.793 +{ 10.794 + return send_command(index, arg, get_response_format(index), 10.795 + command_with_data(index), command_will_write(index), 10.796 + command_uses_busy(index)); 10.797 +} 10.798 + 10.799 +// Initiate a command having the given index and using the given argument, 10.800 +// employing the specified response format and involving a data transfer if 10.801 +// indicated. 10.802 + 10.803 +bool 10.804 +Msc_channel::send_command(uint8_t index, uint32_t arg, uint8_t response_format, 10.805 + bool data, bool write, bool busy) 10.806 +{ 10.807 + stop_clock(); 10.808 + 10.809 + // Enable DMA for data transfers. 10.810 + // NOTE: Needed for JZ4780 and later SoCs. 10.811 + 10.812 + _regs[Msc_dma_control] = (data ? Dma_select_common_dma | Dma_enable : Dma_disable); 10.813 + 10.814 + // Set the command index and argument. 10.815 + 10.816 + _regs[Msc_command_index] = index; 10.817 + _regs[Msc_command_argument] = arg; 10.818 + 10.819 + // Configure the response format and data bus width. 10.820 + 10.821 + set_field(Msc_command_data_control, Cdc_response_format_field_mask, 10.822 + Cdc_response_format_field_shift, response_format); 10.823 + 10.824 + // NOTE: May need to set the SD bus width. 10.825 + 10.826 + set_field(Msc_command_data_control, Cdc_bus_width_field_mask, 10.827 + Cdc_bus_width_field_shift, Cdc_bus_width_field_1bit); 10.828 + 10.829 + set_field(Msc_command_data_control, Cdc_recv_fifo_level_field_mask, 10.830 + Cdc_recv_fifo_level_field_shift, Cdc_fifo_level_16); 10.831 + 10.832 + set_field(Msc_command_data_control, Cdc_trans_fifo_level_field_mask, 10.833 + Cdc_trans_fifo_level_field_shift, Cdc_fifo_level_16); 10.834 + 10.835 + // Set and clear control bits appropriate to the command. 10.836 + // NOTE: Pre-JZ4780 SoCs enable DMA in this register. 10.837 + 10.838 + _regs[Msc_command_data_control] = _regs[Msc_command_data_control] | 10.839 + // (data ? Cdc_dma_enable : Cdc_dma_disable) | 10.840 + (busy ? Cdc_expect_busy : Cdc_do_not_expect_busy) | 10.841 + (data ? Cdc_data_with_command : Cdc_no_data_with_command) | 10.842 + (write ? Cdc_write_operation : Cdc_read_operation); 10.843 + 10.844 + _regs[Msc_command_data_control] = _regs[Msc_command_data_control] & 10.845 + ~( 10.846 + // (data ? Cdc_dma_disable : Cdc_dma_enable) | 10.847 + (busy ? Cdc_do_not_expect_busy : Cdc_expect_busy) | 10.848 + (data ? Cdc_no_data_with_command : Cdc_data_with_command) | 10.849 + (write ? Cdc_read_operation : Cdc_write_operation) | 10.850 + Cdc_stream_block | Cdc_init_sequence); 10.851 + 10.852 + // Unmask interrupts, start the clock, then initiate the command. 10.853 + 10.854 + uint32_t flags = Int_end_command_response | Int_response_timeout; 10.855 + 10.856 + unmask_irq(flags); 10.857 + start_clock(); 10.858 + 10.859 + _regs[Msc_control] = _regs[Msc_control] | Control_start_operation; 10.860 + 10.861 + // Wait for command completion. 10.862 + 10.863 + if (!wait_for_irq(flags)) 10.864 + return false; 10.865 + 10.866 + // Determine whether a timeout occurred. 10.867 + 10.868 + bool have_response = !(_regs[Msc_interrupt_flag] & Int_response_timeout); 10.869 + 10.870 + // Acknowledge the interrupts and return the status. 10.871 + 10.872 + ack_irq(flags); 10.873 + return have_response; 10.874 +} 10.875 + 10.876 +void 10.877 +Msc_channel::enable() 10.878 +{ 10.879 + // NOTE: X1600 and other recent SoCs only. 10.880 + 10.881 + _regs[Msc_low_power_mode] = _regs[Msc_low_power_mode] & ~Low_power_mode_enable; 10.882 + 10.883 + stop_clock(); 10.884 + reset(); 10.885 + 10.886 + // Slow the clock for initialisation. 10.887 + // NOTE: Should use the CPM module to deduce the appropriate divider value. 10.888 + 10.889 + set_field(Msc_clock_rate, Clock_rate_field_mask, Clock_rate_field_shift, 7); 10.890 + 10.891 + send_command(Command_go_idle_state, 0); 10.892 + 10.893 + if (check_sd()) 10.894 + { 10.895 + init_sdio(); 10.896 + init_sdmem(); 10.897 + } 10.898 + 10.899 + init_mmc(); 10.900 + identify_cards(); 10.901 + query_cards(); 10.902 + 10.903 + // Restore the clock. 10.904 + // NOTE: Should use the CPM module to deduce the appropriate divider value. 10.905 + 10.906 + set_field(Msc_clock_rate, Clock_rate_field_mask, Clock_rate_field_shift, 1); 10.907 + 10.908 + _current_rca = 0; 10.909 +} 10.910 + 10.911 +// Check the voltage range of the SD card, potentially establishing that it is 10.912 +// a high capacity card. Return false if the voltage range is incompatible. 10.913 + 10.914 +bool 10.915 +Msc_channel::check_sd() 10.916 +{ 10.917 + uint16_t buffer[Response_size_R7]; 10.918 + struct R7 *r = (struct R7 *) buffer; 10.919 + 10.920 + // Send an interface condition command. 10.921 + // A card may not respond to this command. 10.922 + 10.923 + if (!send_command(Command_send_if_cond, If_cond_default_voltage_range)) 10.924 + return true; 10.925 + 10.926 + read_response(buffer, Response_size_R7); 10.927 + 10.928 + // Reject any card not supporting the default voltage range. 10.929 + 10.930 + if (r->check_voltage.raw != If_cond_default_voltage_range) 10.931 + return false; 10.932 + 10.933 + return true; 10.934 +} 10.935 + 10.936 +// Check the voltage range of the SDIO card, inactivating it if incompatible. 10.937 + 10.938 +void 10.939 +Msc_channel::init_sdio() 10.940 +{ 10.941 + uint16_t buffer[Response_size_R4]; 10.942 + struct R4 *r = (struct R4 *) buffer; 10.943 + uint32_t ocr = 0; 10.944 + 10.945 + // Reset any SDIO card or IO unit in a combined memory/IO card. 10.946 + // A non-SDIO card may not respond to this command. 10.947 + 10.948 + if (!send_command(Command_io_rw_direct, Io_rw_direct_reset)) 10.949 + return; 10.950 + 10.951 + // Attempt to assert the operating conditions. 10.952 + 10.953 + do 10.954 + { 10.955 + // Obtain OCR (operating conditions register) values for any IO card. 10.956 + // Without a response, the card may have inactivated itself due to voltage 10.957 + // range incompatibility reasons. 10.958 + 10.959 + if (!send_command(Command_io_send_op_cond, ocr)) 10.960 + return; 10.961 + 10.962 + read_response(buffer, Response_size_R4); 10.963 + 10.964 + // Finish if no IO functions provided. 10.965 + // NOTE: Should only need to check this the first time. 10.966 + 10.967 + if (r->number_io_functions == 0) 10.968 + return; 10.969 + 10.970 + if (r->ocr != Ocr_default_voltage_range) 10.971 + { 10.972 + ocr = Ocr_default_voltage_range; 10.973 + continue; 10.974 + } 10.975 + } 10.976 + while (!r->ready); 10.977 +} 10.978 + 10.979 +void 10.980 +Msc_channel::init_sdmem() 10.981 +{ 10.982 + uint16_t buffer[Response_size_R3]; 10.983 + struct R3 *r = (struct R3 *) buffer; 10.984 + 10.985 + // Incorporate the HCS bit into the OCR for SDMEM. 10.986 + 10.987 + uint32_t ocr = Ocr_high_capacity_storage; 10.988 + 10.989 + do 10.990 + { 10.991 + if (!send_app_command(App_command_sd_send_op_cond, ocr)) 10.992 + return; 10.993 + 10.994 + read_response(buffer, Response_size_R3); 10.995 + 10.996 + if (r->ocr != Ocr_default_voltage_range) 10.997 + { 10.998 + ocr = Ocr_default_voltage_range | Ocr_high_capacity_storage; 10.999 + continue; 10.1000 + } 10.1001 + } 10.1002 + while (!(r->ocr & Ocr_card_powered_up)); 10.1003 +} 10.1004 + 10.1005 +void 10.1006 +Msc_channel::init_mmc() 10.1007 +{ 10.1008 + // Obtain OCR (operating conditions register) values for each card using 10.1009 + // send_op_cond command variants without argument, or assert operating 10.1010 + // conditions with argument to avoid handling card responses. Where responses 10.1011 + // are solicited, the host must determine a suitable argument and reissue the 10.1012 + // command. 10.1013 + 10.1014 + uint16_t buffer[Response_size_R3]; 10.1015 + struct R3 *r = (struct R3 *) buffer; 10.1016 + uint32_t ocr = 0; 10.1017 + 10.1018 + do 10.1019 + { 10.1020 + if (!send_command(Command_send_op_cond, ocr)) 10.1021 + return; 10.1022 + 10.1023 + read_response(buffer, Response_size_R3); 10.1024 + 10.1025 + if (r->ocr != Ocr_default_voltage_range) 10.1026 + { 10.1027 + ocr = Ocr_default_voltage_range; 10.1028 + continue; 10.1029 + } 10.1030 + } 10.1031 + while (!(r->ocr & Ocr_card_powered_up)); 10.1032 +} 10.1033 + 10.1034 +void 10.1035 +Msc_channel::identify_cards() 10.1036 +{ 10.1037 + uint16_t buffer[Response_size_R2]; 10.1038 + struct R2 *r = (struct R2 *) buffer; 10.1039 + 10.1040 + _cards = 0; 10.1041 + 10.1042 + while (send_command(Command_all_send_cid, 0)) 10.1043 + { 10.1044 + read_response(buffer, Response_size_R2); 10.1045 + 10.1046 + memcpy(&_cid[_cards], r->payload.raw, sizeof(r->payload.raw)); 10.1047 + 10.1048 + printf("card: %d\n", _cards); 10.1049 + printf("date: %d %d\n", r->payload.cid.month, r->payload.cid.year); 10.1050 + printf("serial: %d\n", r->payload.cid.serial); 10.1051 + printf("revision: %d\n", r->payload.cid.revision); 10.1052 + printf("name: %c%c%c%c%c\n", r->payload.cid.name[4], r->payload.cid.name[3], 10.1053 + r->payload.cid.name[2], r->payload.cid.name[1], 10.1054 + r->payload.cid.name[0]); 10.1055 + printf("oem: %d\n", r->payload.cid.oem); 10.1056 + printf("manufacturer: %d\n", r->payload.cid.manufacturer); 10.1057 + 10.1058 + // Try and obtain a card-issued address. 10.1059 + 10.1060 + if (send_command(Command_send_relative_addr, 0)) 10.1061 + { 10.1062 + uint16_t addr_buffer[Response_size_R6]; 10.1063 + struct R6 *ar = (struct R6 *) addr_buffer; 10.1064 + 10.1065 + read_response(addr_buffer, Response_size_R6); 10.1066 + 10.1067 + memcpy(&_rca[_cards], &ar->rca, sizeof(ar->rca)); 10.1068 + } 10.1069 + 10.1070 + // Try and assign an address. 10.1071 + // Employ 1-based relative addressing. 10.1072 + 10.1073 + else if (send_command(Command_set_relative_addr, _cards + 1)) 10.1074 + _rca[_cards] = _cards + 1; 10.1075 + 10.1076 + // Otherwise, stop identification. 10.1077 + 10.1078 + else 10.1079 + return; 10.1080 + 10.1081 + _cards++; 10.1082 + } 10.1083 +} 10.1084 + 10.1085 +void 10.1086 +Msc_channel::query_cards() 10.1087 +{ 10.1088 + uint16_t buffer[Response_size_R2]; 10.1089 + struct R2 *r = (struct R2 *) buffer; 10.1090 + uint8_t card; 10.1091 + 10.1092 + for (card = 0; card < _cards; card++) 10.1093 + { 10.1094 + // Employ 1-based relative addressing. 10.1095 + 10.1096 + if (!send_command(Command_send_csd, _rca[card] << 16)) 10.1097 + return; 10.1098 + 10.1099 + read_response(buffer, Response_size_R2); 10.1100 + 10.1101 + memcpy(&_csd[card], r->payload.raw, sizeof(r->payload.raw)); 10.1102 + 10.1103 + printf("card: %d\n", card); 10.1104 + printf("csd: %d\n", r->payload.csd.csd); 10.1105 + printf("copy: %s\n", r->payload.csd.copy ? "copied" : "original"); 10.1106 + printf("card command classes: %03x\n", r->payload.csd.card_command_classes); 10.1107 + printf("device (size multiplier): %d %d\n", r->payload.csd.device_size + 1, 10.1108 + 1 << (r->payload.csd.device_size_multiplier + 2)); 10.1109 + printf("device size: %d\n", (1 << r->payload.csd.read_blocklen) * 10.1110 + (r->payload.csd.device_size + 1) * 10.1111 + (1 << (r->payload.csd.device_size_multiplier + 2))); 10.1112 + printf("transfer speed: %d MHz\n", r->payload.csd.tran_speed == 0x32 ? 25 : 50); 10.1113 + printf("format group: %d %d\n", r->payload.csd.format, r->payload.csd.format_group); 10.1114 + printf("write time factor: %d\n", 1 << r->payload.csd.write_time_factor); 10.1115 + printf("write protect (temp perm): %s %s\n", r->payload.csd.temp_write_prot ? "yes" : "no", 10.1116 + r->payload.csd.perm_write_prot ? "yes" : "no"); 10.1117 + printf("write protect group (enable size): %s %d\n", r->payload.csd.write_prot_group_enable ? "yes" : "no", 10.1118 + r->payload.csd.write_prot_group_size + 1); 10.1119 + printf("write block (partial length): %s %d\n", r->payload.csd.write_block_partial ? "yes" : "no", 10.1120 + 1 << r->payload.csd.write_blocklen); 10.1121 + printf("read block (partial length): %s %d\n", r->payload.csd.read_block_partial ? "yes" : "no", 10.1122 + 1 << r->payload.csd.read_blocklen); 10.1123 + printf("erase: sector single: %d %s\n", r->payload.csd.erase_sector_size + 1, 10.1124 + r->payload.csd.erase_single_block_enable ? "yes" : "no"); 10.1125 + printf("misalign: read write: %s %s\n", r->payload.csd.read_block_misalign ? "yes" : "no", 10.1126 + r->payload.csd.write_block_misalign ? "yes" : "no"); 10.1127 + printf("max read current (min max): %d %d\n", r->payload.csd.max_read_current_min, 10.1128 + r->payload.csd.max_read_current_max); 10.1129 + printf("max write current (min max): %d %d\n", r->payload.csd.max_write_current_min, 10.1130 + r->payload.csd.max_write_current_max); 10.1131 + printf("read access time (1 2): %d %d\n", r->payload.csd.data_read_access_time_1, 10.1132 + r->payload.csd.data_read_access_time_2); 10.1133 + printf("DSR: %s\n", r->payload.csd.dsr_implemented ? "yes" : "no"); 10.1134 + } 10.1135 +} 10.1136 + 10.1137 +uint32_t 10.1138 +Msc_channel::recv_data(l4re_dma_space_dma_addr_t paddr, uint32_t count) 10.1139 +{ 10.1140 + return transfer(_msc_start + Msc_recv_data_fifo, paddr, true, count); 10.1141 +} 10.1142 + 10.1143 +uint32_t 10.1144 +Msc_channel::send_data(l4re_dma_space_dma_addr_t paddr, uint32_t count) 10.1145 +{ 10.1146 + return transfer(paddr, _msc_start + Msc_trans_data_fifo, false, count); 10.1147 +} 10.1148 + 10.1149 +uint32_t 10.1150 +Msc_channel::read_block(uint8_t card, l4re_dma_space_dma_addr_t paddr) 10.1151 +{ 10.1152 + uint32_t block_size = 1 << _csd[card].read_blocklen; 10.1153 + uint16_t buffer[Response_size_R1]; 10.1154 + struct R1 *r = (struct R1 *) buffer; 10.1155 + 10.1156 + //printf("read_block: card %d -> %d\n", card, _rca[card]); 10.1157 + 10.1158 + // Select the requested card. 10.1159 + 10.1160 + if (_current_rca != _rca[card]) 10.1161 + { 10.1162 + if (!send_command(Command_select_deselect_card, _rca[card] << 16)) 10.1163 + return 0; 10.1164 + 10.1165 + read_response(buffer, Response_size_R1); 10.1166 + 10.1167 + if (r->status & R1_status_error_mask) 10.1168 + return 0; 10.1169 + 10.1170 + _current_rca = _rca[card]; 10.1171 + } 10.1172 + 10.1173 +#if 0 10.1174 + // NOTE: SMEM cards should allow bus width setting. 10.1175 + // NOTE: SDIO cards have their bus width set in CCCR via CMD52. 10.1176 + 10.1177 + printf("set bus width -> %s\n", 10.1178 + send_app_command(App_command_set_bus_width, Bus_width_4bit) ? "set" : "not set"); 10.1179 +#endif 10.1180 + 10.1181 + if (!send_command(Command_set_blocklen, block_size)) 10.1182 + return 0; 10.1183 + 10.1184 + read_response(buffer, Response_size_R1); 10.1185 + 10.1186 + if (r->status & R1_status_error_mask) 10.1187 + return 0; 10.1188 + 10.1189 + // Apply block count and size properties to the issued command. 10.1190 + 10.1191 + _regs[Msc_block_count] = 1; 10.1192 + _regs[Msc_block_length] = block_size; 10.1193 + 10.1194 + // NOTE: Support an actual address. 10.1195 + // NOTE: Where CCS = 0, byte addressing is used. Otherwise, block addressing is used. 10.1196 + 10.1197 + if (!send_command(Command_read_single_block, 0)) 10.1198 + return 0; 10.1199 + 10.1200 + read_response(buffer, Response_size_R1); 10.1201 + 10.1202 + if (r->status & R1_status_error_mask) 10.1203 + return 0; 10.1204 + 10.1205 + return recv_data(paddr, block_size); 10.1206 +} 10.1207 + 10.1208 +// Wait indefinitely for an interrupt request, returning true if one was delivered. 10.1209 + 10.1210 +bool 10.1211 +Msc_channel::wait_for_irq(uint32_t flags) 10.1212 +{ 10.1213 + return !l4_error(l4_irq_receive(_irq, L4_IPC_NEVER)) && 10.1214 + (_regs[Msc_interrupt_flag] & flags); 10.1215 +} 10.1216 + 10.1217 +// Wait up to the given timeout (in microseconds) for an interrupt request, 10.1218 +// returning true if one was delivered. 10.1219 + 10.1220 +bool 10.1221 +Msc_channel::wait_for_irq(uint32_t flags, unsigned int timeout) 10.1222 +{ 10.1223 + return !l4_error(l4_irq_receive(_irq, l4_timeout(L4_IPC_TIMEOUT_NEVER, 10.1224 + l4util_micros2l4to(timeout)))) && 10.1225 + (_regs[Msc_interrupt_flag] & flags); 10.1226 +} 10.1227 + 10.1228 + 10.1229 + 10.1230 +// Peripheral abstraction. 10.1231 + 10.1232 +Msc_chip::Msc_chip(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end) 10.1233 +: _msc_start(msc_start), _start(start), _end(end) 10.1234 +{ 10.1235 +}
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 11.2 +++ b/pkg/devices/lib/msc/src/jz4780.cc Sun Feb 11 00:39:56 2024 +0100 11.3 @@ -0,0 +1,133 @@ 11.4 +/* 11.5 + * MSC (MMC/SD controller) peripheral support. 11.6 + * 11.7 + * Copyright (C) 2024 Paul Boddie <paul@boddie.org.uk> 11.8 + * 11.9 + * This program is free software; you can redistribute it and/or 11.10 + * modify it under the terms of the GNU General Public License as 11.11 + * published by the Free Software Foundation; either version 2 of 11.12 + * the License, or (at your option) any later version. 11.13 + * 11.14 + * This program is distributed in the hope that it will be useful, 11.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11.17 + * GNU General Public License for more details. 11.18 + * 11.19 + * You should have received a copy of the GNU General Public License 11.20 + * along with this program; if not, write to the Free Software 11.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, 11.22 + * Boston, MA 02110-1301, USA 11.23 + */ 11.24 + 11.25 +#include <l4/sys/err.h> 11.26 + 11.27 +#include "msc-jz4780.h" 11.28 + 11.29 + 11.30 + 11.31 +// Register locations for each channel. 11.32 + 11.33 +enum Regs : unsigned 11.34 +{ 11.35 + // Channel block size/offset. 11.36 + 11.37 + Msc_channel_offset = 0x10000, 11.38 +}; 11.39 + 11.40 + 11.41 + 11.42 +// Channel abstraction. 11.43 + 11.44 +Msc_jz4780_channel::Msc_jz4780_channel(l4_addr_t msc_start, l4_addr_t addr, 11.45 + l4_cap_idx_t irq, Dma_jz4780_channel *dma, 11.46 + enum Dma_jz4780_request_type request_type_in, 11.47 + enum Dma_jz4780_request_type request_type_out) 11.48 +: Msc_channel(msc_start, addr, irq), 11.49 + _dma(dma), 11.50 + _request_type_in(request_type_in), 11.51 + _request_type_out(request_type_out) 11.52 +{ 11.53 +} 11.54 + 11.55 +// Request the transfer of the indicated number of bytes between two physical 11.56 +// addresses in the indicated direction, returning the number of bytes 11.57 +// transferred. 11.58 +// NOTE: To be consolidated into a generic method that uses generic request types. 11.59 + 11.60 +uint32_t 11.61 +Msc_jz4780_channel::transfer(l4re_dma_space_dma_addr_t from_paddr, 11.62 + l4re_dma_space_dma_addr_t to_paddr, 11.63 + bool recv, uint32_t count) 11.64 +{ 11.65 + uint32_t unit_size = 32; 11.66 + uint32_t unit_count = count / unit_size; 11.67 + uint32_t to_transfer; 11.68 + 11.69 + to_transfer = _dma->transfer(from_paddr, to_paddr, 11.70 + unit_count, 11.71 + recv ? false : true, // increment source if sending 11.72 + recv ? true : false, // increment destination if receiving 11.73 + 4, 4, unit_size, 11.74 + recv ? _request_type_in : _request_type_out); 11.75 + 11.76 + return to_transfer - _dma->wait() * unit_size; 11.77 +} 11.78 + 11.79 + 11.80 + 11.81 +// Peripheral abstraction. 11.82 + 11.83 +Msc_jz4780_chip::Msc_jz4780_chip(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end) 11.84 +: Msc_chip(msc_start, start, end) 11.85 +{ 11.86 +} 11.87 + 11.88 +Msc_channel *Msc_jz4780_chip::get_channel(uint8_t channel, l4_cap_idx_t irq, 11.89 + Dma_jz4780_channel *dma) 11.90 +{ 11.91 + const enum Dma_jz4780_request_type in_types[] = 11.92 + {Dma_request_msc0_in, Dma_request_msc1_in, Dma_request_msc2_in}; 11.93 + 11.94 + const enum Dma_jz4780_request_type out_types[] = 11.95 + {Dma_request_msc0_out, Dma_request_msc1_out, Dma_request_msc2_out}; 11.96 + 11.97 + if (channel < num_channels()) 11.98 + return new Msc_jz4780_channel(_msc_start + channel * Msc_channel_offset, 11.99 + _start + channel * Msc_channel_offset, 11.100 + irq, dma, 11.101 + in_types[channel], out_types[channel]); 11.102 + else 11.103 + throw -L4_EINVAL; 11.104 +} 11.105 + 11.106 + 11.107 + 11.108 +// C language interface functions. 11.109 + 11.110 +void *jz4780_msc_init(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end) 11.111 +{ 11.112 + return (void *) new Msc_jz4780_chip(msc_start, start, end); 11.113 +} 11.114 + 11.115 +void *jz4780_msc_get_channel(void *msc, uint8_t channel, l4_cap_idx_t irq, 11.116 + void *dma) 11.117 +{ 11.118 + return static_cast<Msc_jz4780_chip *>(msc)->get_channel(channel, irq, 11.119 + static_cast<Dma_jz4780_channel *>(dma)); 11.120 +} 11.121 + 11.122 +uint32_t jz4780_msc_get_status(void *msc_channel) 11.123 +{ 11.124 + return static_cast<Msc_channel *>(msc_channel)->get_status(); 11.125 +} 11.126 + 11.127 +void jz4780_msc_enable(void *msc_channel) 11.128 +{ 11.129 + static_cast<Msc_channel *>(msc_channel)->enable(); 11.130 +} 11.131 + 11.132 +uint32_t jz4780_msc_read_block(void *msc_channel, uint8_t card, 11.133 + l4re_dma_space_dma_addr_t paddr) 11.134 +{ 11.135 + return static_cast<Msc_channel *>(msc_channel)->read_block(card, paddr); 11.136 +}
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/pkg/devices/lib/msc/src/x1600.cc Sun Feb 11 00:39:56 2024 +0100 12.3 @@ -0,0 +1,133 @@ 12.4 +/* 12.5 + * MSC (MMC/SD controller) peripheral support. 12.6 + * 12.7 + * Copyright (C) 2024 Paul Boddie <paul@boddie.org.uk> 12.8 + * 12.9 + * This program is free software; you can redistribute it and/or 12.10 + * modify it under the terms of the GNU General Public License as 12.11 + * published by the Free Software Foundation; either version 2 of 12.12 + * the License, or (at your option) any later version. 12.13 + * 12.14 + * This program is distributed in the hope that it will be useful, 12.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12.17 + * GNU General Public License for more details. 12.18 + * 12.19 + * You should have received a copy of the GNU General Public License 12.20 + * along with this program; if not, write to the Free Software 12.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, 12.22 + * Boston, MA 02110-1301, USA 12.23 + */ 12.24 + 12.25 +#include <l4/sys/err.h> 12.26 + 12.27 +#include "msc-x1600.h" 12.28 + 12.29 + 12.30 + 12.31 +// Register locations for each channel. 12.32 + 12.33 +enum Regs : unsigned 12.34 +{ 12.35 + // Channel block size/offset. 12.36 + 12.37 + Msc_channel_offset = 0x10000, 12.38 +}; 12.39 + 12.40 + 12.41 + 12.42 +// Channel abstraction. 12.43 + 12.44 +Msc_x1600_channel::Msc_x1600_channel(l4_addr_t msc_start, l4_addr_t addr, 12.45 + l4_cap_idx_t irq, Dma_x1600_channel *dma, 12.46 + enum Dma_x1600_request_type request_type_in, 12.47 + enum Dma_x1600_request_type request_type_out) 12.48 +: Msc_channel(msc_start, addr, irq), 12.49 + _dma(dma), 12.50 + _request_type_in(request_type_in), 12.51 + _request_type_out(request_type_out) 12.52 +{ 12.53 +} 12.54 + 12.55 +// Request the transfer of the indicated number of bytes between two physical 12.56 +// addresses in the indicated direction, returning the number of bytes 12.57 +// transferred. 12.58 +// NOTE: To be consolidated into a generic method that uses generic request types. 12.59 + 12.60 +uint32_t 12.61 +Msc_x1600_channel::transfer(l4re_dma_space_dma_addr_t from_paddr, 12.62 + l4re_dma_space_dma_addr_t to_paddr, 12.63 + bool recv, uint32_t count) 12.64 +{ 12.65 + uint32_t unit_size = 32; 12.66 + uint32_t unit_count = count / unit_size; 12.67 + uint32_t to_transfer; 12.68 + 12.69 + to_transfer = _dma->transfer(from_paddr, to_paddr, 12.70 + unit_count, 12.71 + recv ? false : true, // increment source if sending 12.72 + recv ? true : false, // increment destination if receiving 12.73 + 4, 4, unit_size, 12.74 + recv ? _request_type_in : _request_type_out); 12.75 + 12.76 + return to_transfer - _dma->wait() * unit_size; 12.77 +} 12.78 + 12.79 + 12.80 + 12.81 +// Peripheral abstraction. 12.82 + 12.83 +Msc_x1600_chip::Msc_x1600_chip(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end) 12.84 +: Msc_chip(msc_start, start, end) 12.85 +{ 12.86 +} 12.87 + 12.88 +Msc_channel *Msc_x1600_chip::get_channel(uint8_t channel, l4_cap_idx_t irq, 12.89 + Dma_x1600_channel *dma) 12.90 +{ 12.91 + const enum Dma_x1600_request_type in_types[] = 12.92 + {Dma_request_msc0_in, Dma_request_msc1_in}; 12.93 + 12.94 + const enum Dma_x1600_request_type out_types[] = 12.95 + {Dma_request_msc0_out, Dma_request_msc1_out}; 12.96 + 12.97 + if (channel < num_channels()) 12.98 + return new Msc_x1600_channel(_msc_start + channel * Msc_channel_offset, 12.99 + _start + channel * Msc_channel_offset, 12.100 + irq, dma, 12.101 + in_types[channel], out_types[channel]); 12.102 + else 12.103 + throw -L4_EINVAL; 12.104 +} 12.105 + 12.106 + 12.107 + 12.108 +// C language interface functions. 12.109 + 12.110 +void *x1600_msc_init(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end) 12.111 +{ 12.112 + return (void *) new Msc_x1600_chip(msc_start, start, end); 12.113 +} 12.114 + 12.115 +void *x1600_msc_get_channel(void *msc, uint8_t channel, l4_cap_idx_t irq, 12.116 + void *dma) 12.117 +{ 12.118 + return static_cast<Msc_x1600_chip *>(msc)->get_channel(channel, irq, 12.119 + static_cast<Dma_x1600_channel *>(dma)); 12.120 +} 12.121 + 12.122 +uint32_t x1600_msc_get_status(void *msc_channel) 12.123 +{ 12.124 + return static_cast<Msc_channel *>(msc_channel)->get_status(); 12.125 +} 12.126 + 12.127 +void x1600_msc_enable(void *msc_channel) 12.128 +{ 12.129 + static_cast<Msc_channel *>(msc_channel)->enable(); 12.130 +} 12.131 + 12.132 +uint32_t x1600_msc_read_block(void *msc_channel, uint8_t card, 12.133 + l4re_dma_space_dma_addr_t paddr) 12.134 +{ 12.135 + return static_cast<Msc_channel *>(msc_channel)->read_block(card, paddr); 12.136 +}
13.1 --- a/pkg/landfall-examples/hw_info/Makefile Sun Feb 11 00:36:08 2024 +0100 13.2 +++ b/pkg/landfall-examples/hw_info/Makefile Sun Feb 11 00:39:56 2024 +0100 13.3 @@ -7,7 +7,7 @@ 13.4 REQUIRES_LIBS = \ 13.5 libio l4re_c-util libdrivers-aic libdrivers-cpm \ 13.6 libdrivers-dma libdrivers-gpio libdrivers-i2c \ 13.7 - libdrivers-rtc libdrivers-spi libdrivers-tcu \ 13.8 - libdevice-util 13.9 + libdrivers-msc libdrivers-rtc libdrivers-spi \ 13.10 + libdrivers-tcu libdevice-util 13.11 13.12 include $(L4DIR)/mk/prog.mk
14.1 --- a/pkg/landfall-examples/hw_info/common.h Sun Feb 11 00:36:08 2024 +0100 14.2 +++ b/pkg/landfall-examples/hw_info/common.h Sun Feb 11 00:39:56 2024 +0100 14.3 @@ -166,6 +166,20 @@ 14.4 14.5 14.6 14.7 +/* MSC adapter functions. */ 14.8 + 14.9 +void *msc_init(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end); 14.10 + 14.11 +void *msc_get_channel(void *msc, uint8_t channel, l4_cap_idx_t irq, void *dma); 14.12 + 14.13 +uint32_t msc_get_status(void *msc_channel); 14.14 + 14.15 +void msc_enable(void *msc_channel); 14.16 + 14.17 +uint32_t msc_read_block(void *msc_channel, uint8_t card, l4re_dma_space_dma_addr_t paddr); 14.18 + 14.19 + 14.20 + 14.21 /* RTC adapter functions. */ 14.22 14.23 void *rtc_init(l4_addr_t start, void *cpm); 14.24 @@ -277,7 +291,7 @@ 14.25 14.26 enum memory_regions 14.27 { 14.28 - AIC, CPM, DMA, GPIO, I2C, RTC, SSI, TCU 14.29 + AIC, CPM, DMA, GPIO, I2C, MSC, RTC, SSI, TCU 14.30 }; 14.31 14.32
15.1 --- a/pkg/landfall-examples/hw_info/defs.h Sun Feb 11 00:36:08 2024 +0100 15.2 +++ b/pkg/landfall-examples/hw_info/defs.h Sun Feb 11 00:39:56 2024 +0100 15.3 @@ -81,6 +81,16 @@ 15.4 15.5 15.6 15.7 +/* MSC definitions. */ 15.8 + 15.9 +extern void *msc_channels[]; 15.10 + 15.11 +extern const unsigned int num_msc_channels; 15.12 + 15.13 +extern l4_cap_idx_t msc_irqs[]; 15.14 + 15.15 + 15.16 + 15.17 /* SPI definitions. */ 15.18 15.19 extern void *spi_channels[];
16.1 --- a/pkg/landfall-examples/hw_info/hw_info.c Sun Feb 11 00:36:08 2024 +0100 16.2 +++ b/pkg/landfall-examples/hw_info/hw_info.c Sun Feb 11 00:39:56 2024 +0100 16.3 @@ -1112,6 +1112,92 @@ 16.4 16.5 16.6 16.7 +/* MSC configuration. */ 16.8 + 16.9 +static l4_uint32_t msc_irq_start = 0, msc_irq_end = 0; 16.10 + 16.11 +/* MSC operations. */ 16.12 + 16.13 +static void list_msc_channels(void) 16.14 +{ 16.15 + unsigned int num; 16.16 + void *channel; 16.17 + 16.18 + printf("Channel Status\n"); 16.19 + printf("------- --------\n"); 16.20 + 16.21 + for (num = 0; num < num_msc_channels; num++) 16.22 + { 16.23 + printf("%d ", num); 16.24 + 16.25 + channel = msc_channels[num]; 16.26 + 16.27 + if (channel == NULL) 16.28 + printf("inactive\n"); 16.29 + else 16.30 + printf("%08x\n", msc_get_status(channel)); 16.31 + } 16.32 +} 16.33 + 16.34 +static void new_msc_channel(void *msc) 16.35 +{ 16.36 + l4_cap_idx_t irqcap; 16.37 + int num = get_channel_number(num_msc_channels); 16.38 + void *channel; 16.39 + 16.40 + if (num < 0) 16.41 + return; 16.42 + 16.43 + channel = get_channel(num_dma_channels, dma_channels, NULL); 16.44 + 16.45 + if (channel == NULL) 16.46 + return; 16.47 + 16.48 + irqcap = l4re_util_cap_alloc(); 16.49 + 16.50 + if (init_irq(num, irqcap, msc_irq_start, msc_irq_end)) 16.51 + return; 16.52 + 16.53 + msc_channels[num] = msc_get_channel(msc, num, irqcap, channel); 16.54 + msc_irqs[num] = irqcap; 16.55 +} 16.56 + 16.57 +static void enable_msc_channel(void) 16.58 +{ 16.59 + void *channel = get_channel(num_msc_channels, msc_channels, NULL); 16.60 + 16.61 + if (channel == NULL) 16.62 + return; 16.63 + 16.64 + msc_enable(channel); 16.65 +} 16.66 + 16.67 +static void read_block_from_msc(void) 16.68 +{ 16.69 + void *channel = get_channel(num_msc_channels, msc_channels, NULL); 16.70 + struct dma_region *dma_region = NULL; 16.71 + uint32_t card, transferred; 16.72 + 16.73 + if (channel == NULL) 16.74 + return; 16.75 + 16.76 + dma_region = _get_dma_region(); 16.77 + 16.78 + if (dma_region == NULL) 16.79 + return; 16.80 + 16.81 + if (!read_number("Card", &card)) 16.82 + return; 16.83 + 16.84 + l4_cache_inv_data(dma_region->vaddr, dma_region->vaddr + dma_region->size); 16.85 + 16.86 + transferred = msc_read_block(channel, (uint8_t) card, dma_region->paddr); 16.87 + 16.88 + printf("Transferred: %d\n", transferred); 16.89 +} 16.90 + 16.91 + 16.92 + 16.93 /* RTC operations. */ 16.94 16.95 static void rtc_reset(void *rtc, void *cpm) 16.96 @@ -1375,6 +1461,7 @@ 16.97 16.98 printf(" Clock.. Counter......... Mask..............\n"); 16.99 printf("Channel Status C Pre Cnt Half Full Half Full Int\n"); 16.100 + printf("------- -------- -- ---- ---- ---- ---- -------- -------- ----\n"); 16.101 16.102 for (num = 0; num < num_tcu_channels; num++) 16.103 { 16.104 @@ -1625,6 +1712,27 @@ 16.105 list_memory_regions(); 16.106 } 16.107 16.108 +static void handle_msc(void *msc) 16.109 +{ 16.110 + char *token; 16.111 + 16.112 + if ((token = read_token(NULL)) != NULL) 16.113 + { 16.114 + if (!strcmp(token, "l") || !strcmp(token, "list")) 16.115 + list_msc_channels(); 16.116 + else if (!strcmp(token, "c") || !strcmp(token, "channel")) 16.117 + new_msc_channel(msc); 16.118 + else if (!strcmp(token, "e") || !strcmp(token, "enable")) 16.119 + enable_msc_channel(); 16.120 + else if (!strcmp(token, "r") || !strcmp(token, "read")) 16.121 + read_block_from_msc(); 16.122 + else 16.123 + printf("msc channel | enable | read\n"); 16.124 + } 16.125 + else 16.126 + list_msc_channels(); 16.127 +} 16.128 + 16.129 static void handle_rtc(void *rtc, void *cpm) 16.130 { 16.131 char *token; 16.132 @@ -1736,11 +1844,13 @@ 16.133 l4_addr_t dma_base = 0, dma_base_end = 0; 16.134 l4_addr_t gpio_base = 0, gpio_base_end = 0; 16.135 l4_addr_t i2c_base = 0, i2c_base_end = 0; 16.136 + l4_addr_t msc_base = 0, msc_base_end = 0; 16.137 + l4_addr_t msc_phys_base = 0, msc_phys_base_end = 0; 16.138 l4_addr_t rtc_base = 0, rtc_base_end = 0; 16.139 l4_addr_t ssi_base = 0, ssi_base_end = 0; 16.140 l4_addr_t ssi_phys_base = 0, ssi_phys_base_end = 0; 16.141 l4_addr_t tcu_base = 0, tcu_base_end = 0; 16.142 - void *aic, *cpm, *dma, *gpio[num_gpio_ports], *i2c, *rtc, *spi, *tcu; 16.143 + void *aic, *cpm, *dma, *gpio[num_gpio_ports], *i2c, *msc, *rtc, *spi, *tcu; 16.144 int result = 0; 16.145 unsigned int port; 16.146 16.147 @@ -1811,6 +1921,21 @@ 16.148 16.149 aic = aic_init(aic_phys_base, aic_base, aic_base_end, cpm); 16.150 16.151 + printf("Access MSC...\n"); 16.152 + 16.153 + if ((result = get_memory_complete(io_memory_regions[MSC], &msc_base, &msc_base_end, 16.154 + &msc_phys_base, &msc_phys_base_end)) < 0) 16.155 + return 1; 16.156 + 16.157 + printf("MSC at 0x%lx...0x%lx.\n", msc_base, msc_base_end); 16.158 + 16.159 + msc = msc_init(msc_phys_base, msc_base, msc_base_end); 16.160 + 16.161 + if (get_irq(io_memory_regions[MSC], &msc_irq_start, &msc_irq_end) < 0) 16.162 + return 1; 16.163 + 16.164 + printf("IRQ range at %d...%d.\n", msc_irq_start, msc_irq_end); 16.165 + 16.166 printf("Access RTC...\n"); 16.167 16.168 if ((result = get_memory(io_memory_regions[RTC], &rtc_base, &rtc_base_end)) < 0) 16.169 @@ -1849,7 +1974,7 @@ 16.170 16.171 /* Start the interactive session. */ 16.172 16.173 - printf("aic, cpm, dma, gpio, i2c, rtc, spi, tcu\n"); 16.174 + printf("aic, cpm, dma, gpio, i2c, msc, rtc, spi, tcu\n"); 16.175 16.176 while (1) 16.177 { 16.178 @@ -1890,6 +2015,11 @@ 16.179 else if (!strcmp(token, "i") || !strcmp(token, "i2c")) 16.180 handle_i2c(i2c); 16.181 16.182 + /* MSC commands. */ 16.183 + 16.184 + else if (!strcmp(token, "M") || !strcmp(token, "msc")) 16.185 + handle_msc(msc); 16.186 + 16.187 /* Generic memory commands. */ 16.188 16.189 else if (!strcmp(token, "m") || !strcmp(token, "mem") || !strcmp(token, "memory"))
17.1 --- a/pkg/landfall-examples/hw_info/jz4780.c Sun Feb 11 00:36:08 2024 +0100 17.2 +++ b/pkg/landfall-examples/hw_info/jz4780.c Sun Feb 11 00:39:56 2024 +0100 17.3 @@ -1,7 +1,7 @@ 17.4 /* 17.5 * Access various peripherals on a board using the JZ4780. 17.6 * 17.7 - * Copyright (C) 2023 Paul Boddie <paul@boddie.org.uk> 17.8 + * Copyright (C) 2023, 2024 Paul Boddie <paul@boddie.org.uk> 17.9 * 17.10 * This program is free software; you can redistribute it and/or 17.11 * modify it under the terms of the GNU General Public License as 17.12 @@ -28,6 +28,7 @@ 17.13 #include <l4/devices/dma-jz4780.h> 17.14 #include <l4/devices/gpio-jz4780.h> 17.15 #include <l4/devices/i2c-jz4780.h> 17.16 +#include <l4/devices/msc-jz4780.h> 17.17 17.18 /* The X1600 RTC functionality is a subset of that in the JZ4780. */ 17.19 17.20 @@ -336,6 +337,35 @@ 17.21 17.22 17.23 17.24 +/* MSC adapter functions. */ 17.25 + 17.26 +void *msc_init(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end) 17.27 +{ 17.28 + return jz4780_msc_init(msc_start, start, end); 17.29 +} 17.30 + 17.31 +void *msc_get_channel(void *msc, uint8_t channel, l4_cap_idx_t irq, void *dma) 17.32 +{ 17.33 + return jz4780_msc_get_channel(msc, channel, irq, dma); 17.34 +} 17.35 + 17.36 +uint32_t msc_get_status(void *msc_channel) 17.37 +{ 17.38 + return jz4780_msc_get_status(msc_channel); 17.39 +} 17.40 + 17.41 +void msc_enable(void *msc_channel) 17.42 +{ 17.43 + jz4780_msc_enable(msc_channel); 17.44 +} 17.45 + 17.46 +uint32_t msc_read_block(void *msc_channel, uint8_t card, l4re_dma_space_dma_addr_t paddr) 17.47 +{ 17.48 + return jz4780_msc_read_block(msc_channel, card, paddr); 17.49 +} 17.50 + 17.51 + 17.52 + 17.53 /* RTC adapter functions. */ 17.54 17.55 void *rtc_init(l4_addr_t start, void *cpm) 17.56 @@ -590,6 +620,7 @@ 17.57 [DMA] = "jz4780-dma", 17.58 [GPIO] = "jz4780-gpio", 17.59 [I2C] = "jz4780-i2c", 17.60 + [MSC] = "jz4780-msc", 17.61 [RTC] = "jz4780-rtc", 17.62 [SSI] = "jz4780-ssi", 17.63 [TCU] = "jz4780-tcu", 17.64 @@ -699,6 +730,16 @@ 17.65 17.66 17.67 17.68 +/* MSC definitions. */ 17.69 + 17.70 +void *msc_channels[] = {NULL, NULL, NULL}; 17.71 + 17.72 +const unsigned int num_msc_channels = 3; 17.73 + 17.74 +l4_cap_idx_t msc_irqs[] = {L4_INVALID_CAP, L4_INVALID_CAP, L4_INVALID_CAP}; 17.75 + 17.76 + 17.77 + 17.78 /* SPI definitions. */ 17.79 17.80 void *spi_channels[] = {NULL, NULL};
18.1 --- a/pkg/landfall-examples/hw_info/x1600.c Sun Feb 11 00:36:08 2024 +0100 18.2 +++ b/pkg/landfall-examples/hw_info/x1600.c Sun Feb 11 00:39:56 2024 +0100 18.3 @@ -24,6 +24,7 @@ 18.4 #include <l4/devices/dma-x1600.h> 18.5 #include <l4/devices/gpio-x1600.h> 18.6 #include <l4/devices/i2c-x1600.h> 18.7 +#include <l4/devices/msc-x1600.h> 18.8 #include <l4/devices/rtc-x1600.h> 18.9 #include <l4/devices/spi-gpio.h> 18.10 #include <l4/devices/spi-hybrid.h> 18.11 @@ -325,6 +326,35 @@ 18.12 18.13 18.14 18.15 +/* MSC adapter functions. */ 18.16 + 18.17 +void *msc_init(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end) 18.18 +{ 18.19 + return x1600_msc_init(msc_start, start, end); 18.20 +} 18.21 + 18.22 +void *msc_get_channel(void *msc, uint8_t channel, l4_cap_idx_t irq, void *dma) 18.23 +{ 18.24 + return x1600_msc_get_channel(msc, channel, irq, dma); 18.25 +} 18.26 + 18.27 +uint32_t msc_get_status(void *msc_channel) 18.28 +{ 18.29 + return x1600_msc_get_status(msc_channel); 18.30 +} 18.31 + 18.32 +void msc_enable(void *msc_channel) 18.33 +{ 18.34 + return x1600_msc_enable(msc_channel); 18.35 +} 18.36 + 18.37 +uint32_t msc_read_block(void *msc_channel, uint8_t card, l4re_dma_space_dma_addr_t paddr) 18.38 +{ 18.39 + return x1600_msc_read_block(msc_channel, card, paddr); 18.40 +} 18.41 + 18.42 + 18.43 + 18.44 /* RTC adapter functions. */ 18.45 18.46 void *rtc_init(l4_addr_t start, void *cpm) 18.47 @@ -576,6 +606,7 @@ 18.48 [DMA] = "x1600-dma", 18.49 [GPIO] = "x1600-gpio", 18.50 [I2C] = "x1600-i2c", 18.51 + [MSC] = "x1600-msc", 18.52 [RTC] = "x1600-rtc", 18.53 [SSI] = "x1600-ssi", 18.54 [TCU] = "x1600-tcu", 18.55 @@ -671,6 +702,16 @@ 18.56 18.57 18.58 18.59 +/* MSC definitions. */ 18.60 + 18.61 +void *msc_channels[] = {NULL, NULL}; 18.62 + 18.63 +const unsigned int num_msc_channels = 2; 18.64 + 18.65 +l4_cap_idx_t msc_irqs[] = {L4_INVALID_CAP, L4_INVALID_CAP}; 18.66 + 18.67 + 18.68 + 18.69 /* SPI definitions. */ 18.70 18.71 void *spi_channels[] = {NULL};