1 /* 2 * MSC (MMC/SD controller) peripheral support. 3 * 4 * Copyright (C) 2024 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of 9 * the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA 20 */ 21 22 #pragma once 23 24 #include <l4/re/c/dma_space.h> 25 #include <l4/sys/types.h> 26 #include <stdint.h> 27 28 29 30 /* MMC/SD structures. */ 31 32 struct CID 33 { 34 uint16_t month:4, year:8, reserved:4; 35 uint32_t serial; 36 uint8_t revision; 37 char name[5]; 38 uint16_t oem; 39 uint8_t manufacturer; 40 } __attribute__((packed)); 41 42 struct CSD 43 { 44 uint8_t reserved0:2, format:2, temp_write_prot:1, perm_write_prot:1, copy:1, format_group:1; 45 uint16_t reserved1:5, write_block_partial:1, write_blocklen:4, write_time_factor:3, 46 reserved2:2, write_prot_group_enable:1; 47 uint64_t write_prot_group_size:7, erase_sector_size:7, erase_single_block_enable:1, 48 device_size_multiplier:3, max_write_current_max:3, max_write_current_min:3, 49 max_read_current_max:3, max_read_current_min:3, device_size:12, 50 reserved3:2, dsr_implemented:1, read_block_misalign:1, write_block_misalign:1, 51 read_block_partial:1, read_blocklen:4, card_command_classes:12; 52 uint8_t tran_speed, data_read_access_time_2, data_read_access_time_1, 53 reserved4:6, csd:2; 54 } __attribute__((packed)); 55 56 57 58 /* Generic card structure. */ 59 60 struct msc_card 61 { 62 uint16_t rca; 63 uint32_t ocr; 64 uint8_t bus_width; 65 struct CID cid; 66 struct CSD csd; 67 }; 68 69 70 71 #ifdef __cplusplus 72 73 #include <l4/devices/hw_mmio_register_block.h> 74 75 76 77 // MMC/SD controller channel. 78 79 class Msc_channel 80 { 81 protected: 82 l4_addr_t _msc_start; 83 Hw::Register_block<32> _regs; 84 l4_cap_idx_t _irq; 85 86 // Support eight cards. 87 88 struct msc_card _cards[8]; 89 uint8_t _num_cards; 90 int _card; 91 92 // Utility methods. 93 94 uint32_t get_field(uint32_t reg, uint32_t mask, uint8_t shift); 95 void set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value); 96 97 // Low-level operations. 98 99 void ack_irq(uint32_t flags); 100 void unmask_irq(uint32_t flags); 101 void reset(); 102 void start_clock(); 103 void stop_clock(); 104 105 // Command properties. 106 107 bool command_will_write(uint8_t index); 108 bool command_with_data(uint8_t index); 109 bool command_uses_busy(uint8_t index); 110 uint8_t get_response_format(uint8_t index); 111 112 bool app_command_will_write(uint8_t index); 113 bool app_command_with_data(uint8_t index); 114 bool app_command_uses_busy(uint8_t index); 115 uint8_t get_app_response_format(uint8_t index); 116 117 // Command initiation. 118 119 bool send_app_command(uint8_t index, uint32_t arg); 120 bool send_command(uint8_t index, uint32_t arg); 121 bool send_command(uint8_t index, uint32_t arg, uint8_t response_format, 122 bool data, bool write, bool busy); 123 124 // Response handling. 125 126 bool have_response(); 127 void read_response(uint16_t *buffer, uint8_t units); 128 bool wait_for_irq(uint32_t flags); 129 bool wait_for_irq(uint32_t flags, unsigned int timeout); 130 131 // Initialisation operations. 132 133 bool check_sd(); 134 void init_sdio(); 135 void init_sdmem(); 136 void init_mmc(); 137 void identify_cards(); 138 void query_cards(); 139 140 // Transfer operations. 141 142 uint32_t recv_data(l4re_dma_space_dma_addr_t paddr, uint32_t count); 143 uint32_t send_data(l4re_dma_space_dma_addr_t paddr, uint32_t count); 144 145 virtual uint32_t transfer(l4re_dma_space_dma_addr_t from_paddr, 146 l4re_dma_space_dma_addr_t to_paddr, 147 bool recv, uint32_t count) = 0; 148 149 public: 150 explicit Msc_channel(l4_addr_t msc_start, l4_addr_t start, l4_cap_idx_t irq); 151 152 virtual ~Msc_channel(); 153 154 void enable(); 155 156 uint32_t get_status(); 157 158 uint32_t read_blocks(uint8_t card, l4re_dma_space_dma_addr_t paddr, 159 uint32_t block_address, uint32_t block_count); 160 }; 161 162 163 164 // MMC/SD controller device control. 165 166 class Msc_chip 167 { 168 protected: 169 l4_addr_t _msc_start, _start, _end; 170 171 virtual unsigned int num_channels() = 0; 172 173 public: 174 explicit Msc_chip(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end); 175 }; 176 177 #endif /* __cplusplus */