1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/pkg/devices/lib/msc/src/jz4780.cc Sun Feb 11 00:39:56 2024 +0100
1.3 @@ -0,0 +1,133 @@
1.4 +/*
1.5 + * MSC (MMC/SD controller) peripheral support.
1.6 + *
1.7 + * Copyright (C) 2024 Paul Boddie <paul@boddie.org.uk>
1.8 + *
1.9 + * This program is free software; you can redistribute it and/or
1.10 + * modify it under the terms of the GNU General Public License as
1.11 + * published by the Free Software Foundation; either version 2 of
1.12 + * the License, or (at your option) any later version.
1.13 + *
1.14 + * This program is distributed in the hope that it will be useful,
1.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.17 + * GNU General Public License for more details.
1.18 + *
1.19 + * You should have received a copy of the GNU General Public License
1.20 + * along with this program; if not, write to the Free Software
1.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
1.22 + * Boston, MA 02110-1301, USA
1.23 + */
1.24 +
1.25 +#include <l4/sys/err.h>
1.26 +
1.27 +#include "msc-jz4780.h"
1.28 +
1.29 +
1.30 +
1.31 +// Register locations for each channel.
1.32 +
1.33 +enum Regs : unsigned
1.34 +{
1.35 + // Channel block size/offset.
1.36 +
1.37 + Msc_channel_offset = 0x10000,
1.38 +};
1.39 +
1.40 +
1.41 +
1.42 +// Channel abstraction.
1.43 +
1.44 +Msc_jz4780_channel::Msc_jz4780_channel(l4_addr_t msc_start, l4_addr_t addr,
1.45 + l4_cap_idx_t irq, Dma_jz4780_channel *dma,
1.46 + enum Dma_jz4780_request_type request_type_in,
1.47 + enum Dma_jz4780_request_type request_type_out)
1.48 +: Msc_channel(msc_start, addr, irq),
1.49 + _dma(dma),
1.50 + _request_type_in(request_type_in),
1.51 + _request_type_out(request_type_out)
1.52 +{
1.53 +}
1.54 +
1.55 +// Request the transfer of the indicated number of bytes between two physical
1.56 +// addresses in the indicated direction, returning the number of bytes
1.57 +// transferred.
1.58 +// NOTE: To be consolidated into a generic method that uses generic request types.
1.59 +
1.60 +uint32_t
1.61 +Msc_jz4780_channel::transfer(l4re_dma_space_dma_addr_t from_paddr,
1.62 + l4re_dma_space_dma_addr_t to_paddr,
1.63 + bool recv, uint32_t count)
1.64 +{
1.65 + uint32_t unit_size = 32;
1.66 + uint32_t unit_count = count / unit_size;
1.67 + uint32_t to_transfer;
1.68 +
1.69 + to_transfer = _dma->transfer(from_paddr, to_paddr,
1.70 + unit_count,
1.71 + recv ? false : true, // increment source if sending
1.72 + recv ? true : false, // increment destination if receiving
1.73 + 4, 4, unit_size,
1.74 + recv ? _request_type_in : _request_type_out);
1.75 +
1.76 + return to_transfer - _dma->wait() * unit_size;
1.77 +}
1.78 +
1.79 +
1.80 +
1.81 +// Peripheral abstraction.
1.82 +
1.83 +Msc_jz4780_chip::Msc_jz4780_chip(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end)
1.84 +: Msc_chip(msc_start, start, end)
1.85 +{
1.86 +}
1.87 +
1.88 +Msc_channel *Msc_jz4780_chip::get_channel(uint8_t channel, l4_cap_idx_t irq,
1.89 + Dma_jz4780_channel *dma)
1.90 +{
1.91 + const enum Dma_jz4780_request_type in_types[] =
1.92 + {Dma_request_msc0_in, Dma_request_msc1_in, Dma_request_msc2_in};
1.93 +
1.94 + const enum Dma_jz4780_request_type out_types[] =
1.95 + {Dma_request_msc0_out, Dma_request_msc1_out, Dma_request_msc2_out};
1.96 +
1.97 + if (channel < num_channels())
1.98 + return new Msc_jz4780_channel(_msc_start + channel * Msc_channel_offset,
1.99 + _start + channel * Msc_channel_offset,
1.100 + irq, dma,
1.101 + in_types[channel], out_types[channel]);
1.102 + else
1.103 + throw -L4_EINVAL;
1.104 +}
1.105 +
1.106 +
1.107 +
1.108 +// C language interface functions.
1.109 +
1.110 +void *jz4780_msc_init(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end)
1.111 +{
1.112 + return (void *) new Msc_jz4780_chip(msc_start, start, end);
1.113 +}
1.114 +
1.115 +void *jz4780_msc_get_channel(void *msc, uint8_t channel, l4_cap_idx_t irq,
1.116 + void *dma)
1.117 +{
1.118 + return static_cast<Msc_jz4780_chip *>(msc)->get_channel(channel, irq,
1.119 + static_cast<Dma_jz4780_channel *>(dma));
1.120 +}
1.121 +
1.122 +uint32_t jz4780_msc_get_status(void *msc_channel)
1.123 +{
1.124 + return static_cast<Msc_channel *>(msc_channel)->get_status();
1.125 +}
1.126 +
1.127 +void jz4780_msc_enable(void *msc_channel)
1.128 +{
1.129 + static_cast<Msc_channel *>(msc_channel)->enable();
1.130 +}
1.131 +
1.132 +uint32_t jz4780_msc_read_block(void *msc_channel, uint8_t card,
1.133 + l4re_dma_space_dma_addr_t paddr)
1.134 +{
1.135 + return static_cast<Msc_channel *>(msc_channel)->read_block(card, paddr);
1.136 +}