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 #include <l4/sys/err.h> 23 24 #include "msc-x1600.h" 25 26 27 28 // Register locations for each channel. 29 30 enum Regs : unsigned 31 { 32 // Channel block size/offset. 33 34 Msc_channel_offset = 0x10000, 35 }; 36 37 38 39 // Channel abstraction. 40 41 Msc_x1600_channel::Msc_x1600_channel(l4_addr_t msc_start, l4_addr_t addr, 42 l4_cap_idx_t irq, Dma_x1600_channel *dma, 43 enum Dma_x1600_request_type request_type_in, 44 enum Dma_x1600_request_type request_type_out) 45 : Msc_channel(msc_start, addr, irq), 46 _dma(dma), 47 _request_type_in(request_type_in), 48 _request_type_out(request_type_out) 49 { 50 } 51 52 // Request the transfer of the indicated number of bytes between two physical 53 // addresses in the indicated direction, returning the number of bytes 54 // transferred. 55 // NOTE: To be consolidated into a generic method that uses generic request types. 56 57 uint32_t 58 Msc_x1600_channel::transfer(l4re_dma_space_dma_addr_t from_paddr, 59 l4re_dma_space_dma_addr_t to_paddr, 60 bool recv, uint32_t count) 61 { 62 uint32_t unit_size = 32; 63 uint32_t unit_count = count / unit_size; 64 uint32_t to_transfer; 65 66 to_transfer = _dma->transfer(from_paddr, to_paddr, 67 unit_count, 68 recv ? false : true, // increment source if sending 69 recv ? true : false, // increment destination if receiving 70 4, 4, unit_size, 71 recv ? _request_type_in : _request_type_out); 72 73 return to_transfer - _dma->wait() * unit_size; 74 } 75 76 77 78 // Peripheral abstraction. 79 80 Msc_x1600_chip::Msc_x1600_chip(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end) 81 : Msc_chip(msc_start, start, end) 82 { 83 } 84 85 Msc_channel *Msc_x1600_chip::get_channel(uint8_t channel, l4_cap_idx_t irq, 86 Dma_x1600_channel *dma) 87 { 88 const enum Dma_x1600_request_type in_types[] = 89 {Dma_request_msc0_in, Dma_request_msc1_in}; 90 91 const enum Dma_x1600_request_type out_types[] = 92 {Dma_request_msc0_out, Dma_request_msc1_out}; 93 94 if (channel < num_channels()) 95 return new Msc_x1600_channel(_msc_start + channel * Msc_channel_offset, 96 _start + channel * Msc_channel_offset, 97 irq, dma, 98 in_types[channel], out_types[channel]); 99 else 100 throw -L4_EINVAL; 101 } 102 103 104 105 // C language interface functions. 106 107 void *x1600_msc_init(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end) 108 { 109 return (void *) new Msc_x1600_chip(msc_start, start, end); 110 } 111 112 void *x1600_msc_get_channel(void *msc, uint8_t channel, l4_cap_idx_t irq, 113 void *dma) 114 { 115 return static_cast<Msc_x1600_chip *>(msc)->get_channel(channel, irq, 116 static_cast<Dma_x1600_channel *>(dma)); 117 } 118 119 uint32_t x1600_msc_get_status(void *msc_channel) 120 { 121 return static_cast<Msc_channel *>(msc_channel)->get_status(); 122 } 123 124 void x1600_msc_enable(void *msc_channel) 125 { 126 static_cast<Msc_channel *>(msc_channel)->enable(); 127 } 128 129 uint32_t x1600_msc_read_block(void *msc_channel, uint8_t card, 130 l4re_dma_space_dma_addr_t paddr) 131 { 132 return static_cast<Msc_channel *>(msc_channel)->read_block(card, paddr); 133 }