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 // Command properties. 73 74 bool command_will_write(uint8_t index); 75 bool command_with_data(uint8_t index); 76 bool command_uses_busy(uint8_t index); 77 uint8_t get_response_format(uint8_t index); 78 79 bool app_command_will_write(uint8_t index); 80 bool app_command_with_data(uint8_t index); 81 bool app_command_uses_busy(uint8_t index); 82 uint8_t get_app_response_format(uint8_t index); 83 84 // Command initiation. 85 86 bool send_app_command(uint8_t index, uint32_t arg); 87 bool send_command(uint8_t index, uint32_t arg); 88 bool send_command(uint8_t index, uint32_t arg, uint8_t response_format, 89 bool data, bool write, bool busy); 90 91 // Response handling. 92 93 bool have_response(); 94 void read_response(uint16_t *buffer, uint8_t units); 95 bool wait_for_irq(uint32_t flags); 96 bool wait_for_irq(uint32_t flags, unsigned int timeout); 97 98 // Initialisation operations. 99 100 bool check_sd(); 101 void init_sdio(); 102 void init_sdmem(); 103 void init_mmc(); 104 void identify_cards(); 105 void query_cards(); 106 107 // Transfer operations. 108 109 uint32_t recv_data(struct dma_region *region, uint32_t count); 110 uint32_t send_data(struct dma_region *region, uint32_t count); 111 112 virtual uint32_t transfer(l4re_dma_space_dma_addr_t from_paddr, 113 l4re_dma_space_dma_addr_t to_paddr, 114 bool recv, uint32_t count) = 0; 115 116 public: 117 explicit Msc_channel(l4_addr_t msc_start, l4_addr_t start, l4_cap_idx_t irq, 118 Cpm_chip *cpm, enum Clock_identifiers clock); 119 120 virtual ~Msc_channel(); 121 122 void enable(); 123 124 msc_card *get_cards(); 125 126 uint8_t num_cards(); 127 128 uint32_t read_blocks(uint8_t card, struct dma_region *region, 129 uint32_t block_address, uint32_t block_count); 130 }; 131 132 133 134 // MMC/SD controller device control. 135 136 class Msc_chip 137 { 138 protected: 139 l4_addr_t _msc_start, _start, _end; 140 Cpm_chip *_cpm; 141 142 virtual unsigned int num_channels() = 0; 143 144 public: 145 explicit Msc_chip(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end, 146 Cpm_chip *cpm); 147 }; 148 149 #endif /* __cplusplus */