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/devices/clocks.h> 25 #include <l4/devices/cpm.h> 26 #include <l4/devices/dma.h> 27 #include <l4/devices/msc.h> 28 #include <l4/sys/types.h> 29 #include <stdint.h> 30 31 32 33 #ifdef __cplusplus 34 35 #include <l4/devices/hw_mmio_register_block.h> 36 37 38 39 // MMC/SD controller channel. 40 41 class Msc_channel 42 { 43 protected: 44 l4_addr_t _msc_start; 45 Hw::Register_block<32> _regs; 46 l4_cap_idx_t _irq; 47 Cpm_chip *_cpm; 48 enum Clock_identifiers _clock; 49 50 // Support eight cards. 51 52 struct msc_card _cards[8]; 53 uint8_t _num_cards; 54 int _card; 55 56 // Utility methods. 57 58 uint32_t get_field(uint32_t reg, uint32_t mask, uint8_t shift); 59 void set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value); 60 61 // Low-level operations. 62 63 void ack_irq(uint32_t flags); 64 void unmask_irq(uint32_t flags); 65 66 virtual void reset(); 67 68 bool set_clock_frequency(uint64_t frequency); 69 void start_clock(); 70 void stop_clock(); 71 72 // Hardware properties. 73 74 virtual bool have_dma_enable_in_command(); 75 virtual bool have_dma_selection(); 76 77 // Command properties. 78 79 bool command_will_write(uint8_t index); 80 bool command_with_data(uint8_t index); 81 bool command_uses_busy(uint8_t index); 82 uint8_t get_response_format(uint8_t index); 83 84 bool app_command_will_write(uint8_t index); 85 bool app_command_with_data(uint8_t index); 86 bool app_command_uses_busy(uint8_t index); 87 uint8_t get_app_response_format(uint8_t index); 88 89 // Command initiation. 90 91 bool send_app_command(uint8_t index, uint32_t arg); 92 bool send_command(uint8_t index, uint32_t arg); 93 bool send_command(uint8_t index, uint32_t arg, uint8_t response_format, 94 bool data, bool write, bool busy); 95 96 // Response handling. 97 98 bool have_response(); 99 void read_response(uint16_t *buffer, uint8_t units); 100 bool wait_for_irq(uint32_t flags); 101 bool wait_for_irq(uint32_t flags, unsigned int timeout); 102 103 // Initialisation operations. 104 105 bool check_sd(); 106 void init_sdio(); 107 void init_sdmem(); 108 void init_mmc(); 109 void identify_cards(); 110 void query_cards(); 111 112 // Transfer operations. 113 114 uint32_t recv_data(struct dma_region *region, uint32_t count); 115 uint32_t send_data(struct dma_region *region, uint32_t count); 116 117 virtual uint32_t transfer(l4re_dma_space_dma_addr_t from_paddr, 118 l4re_dma_space_dma_addr_t to_paddr, 119 bool recv, uint32_t count) = 0; 120 121 public: 122 explicit Msc_channel(l4_addr_t msc_start, l4_addr_t start, l4_cap_idx_t irq, 123 Cpm_chip *cpm, enum Clock_identifiers clock); 124 125 virtual ~Msc_channel(); 126 127 void enable(); 128 129 msc_card *get_cards(); 130 131 uint8_t num_cards(); 132 133 uint32_t read(uint8_t card, struct dma_region *region, 134 uint32_t address, uint32_t count); 135 136 uint32_t read_blocks(uint8_t card, struct dma_region *region, 137 uint32_t block_address, uint32_t block_count); 138 }; 139 140 141 142 // MMC/SD controller device control. 143 144 class Msc_chip 145 { 146 protected: 147 l4_addr_t _msc_start, _start, _end; 148 Cpm_chip *_cpm; 149 150 virtual unsigned int num_channels() = 0; 151 152 public: 153 explicit Msc_chip(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end, 154 Cpm_chip *cpm); 155 }; 156 157 #endif /* __cplusplus */