|
| 1 | +/* KallistiOS ##version## |
| 2 | +
|
| 3 | + dmac.h |
| 4 | + Copyright (C) 2024 Paul Cercueil |
| 5 | +
|
| 6 | +*/ |
| 7 | + |
| 8 | +/** \file arch/dmac.h |
| 9 | + \brief SH4 DMA Controller API |
| 10 | + \ingroup system_dmac |
| 11 | +
|
| 12 | + This header provies an API to use the DMA controller of the SH4. |
| 13 | +
|
| 14 | + \author Paul Cercueil |
| 15 | +*/ |
| 16 | + |
| 17 | +#ifndef __ARCH_DMAC_H |
| 18 | +#define __ARCH_DMAC_H |
| 19 | + |
| 20 | +#include <sys/cdefs.h> |
| 21 | +__BEGIN_DECLS |
| 22 | + |
| 23 | +#include <stdint.h> |
| 24 | + |
| 25 | +/** \defgroup dmac DMA Controller API |
| 26 | + \brief API to use the SH4's DMA Controller |
| 27 | + \ingroup system |
| 28 | +
|
| 29 | + This API can be used to program DMA transfers from memory to memory, |
| 30 | + from hardware to memory or from memory to hardware. |
| 31 | +
|
| 32 | + @{ |
| 33 | +*/ |
| 34 | + |
| 35 | +/** \brief DMA callback type. |
| 36 | + \ingroup dmac |
| 37 | +
|
| 38 | + Function type for DMA callbacks. |
| 39 | + Those registered callbacks will be called when a DMA transfer completes. |
| 40 | + They will be called in an interrupt context, so don't try anything funny. |
| 41 | +*/ |
| 42 | +typedef void (*dma_callback_t)(void *data); |
| 43 | + |
| 44 | +/** \brief DMA channel enum. |
| 45 | + \ingroup dmac |
| 46 | +
|
| 47 | + Represents one of the 4 DMA channels available on the SH4. |
| 48 | +*/ |
| 49 | +typedef enum dma_channel { |
| 50 | + DMA_CHANNEL_0, /**< Channel #0: On Dreamcast, reserved for hardware. */ |
| 51 | + DMA_CHANNEL_1, /**< Channel #1: External, hardware or mem-to-mem requests. */ |
| 52 | + DMA_CHANNEL_2, /**< Channel #2: on Dreamcast, reserved for PVR use. */ |
| 53 | + DMA_CHANNEL_3, /**< Channel #3: mem-to-mem requests only. */ |
| 54 | +} dma_channel_t; |
| 55 | + |
| 56 | +/** \brief DMA request. |
| 57 | + \ingroup dmac |
| 58 | +
|
| 59 | + List of the possible DMA requests. |
| 60 | +
|
| 61 | + "Auto" requests are started as soon as the DMA transfer is programmed to |
| 62 | + the DMA controller. On the other hand, SCI/SCIF/TMU2 requests are only |
| 63 | + started when the given hardware event occurs. |
| 64 | +
|
| 65 | + "External" requests are controlled by external pins of the SH4 CPU. These |
| 66 | + can be wired to other parts of the mother board. |
| 67 | +*/ |
| 68 | +typedef enum dma_request { |
| 69 | + DMA_REQUEST_EXTERNAL_MEM_TO_MEM = 0, |
| 70 | + DMA_REQUEST_EXTERNAL_MEM_TO_DEV = 2, |
| 71 | + DMA_REQUEST_EXTERNAL_DEV_TO_MEM = 3, |
| 72 | + DMA_REQUEST_AUTO_MEM_TO_MEM = 4, |
| 73 | + DMA_REQUEST_AUTO_MEM_TO_DEV = 5, |
| 74 | + DMA_REQUEST_AUTO_DEV_TO_MEM = 6, |
| 75 | + |
| 76 | + DMA_REQUEST_SCI_TRANSMIT = 8, |
| 77 | + DMA_REQUEST_SCI_RECEIVE = 9, |
| 78 | + DMA_REQUEST_SCIF_TRANSMIT = 10, |
| 79 | + DMA_REQUEST_SCIF_RECEIVE = 11, |
| 80 | + DMA_REQUEST_TMU2_MEM_TO_MEM = 12, |
| 81 | + DMA_REQUEST_TMU2_MEM_TO_DEV = 13, |
| 82 | + DMA_REQUEST_TMU2_DEV_TO_MEM = 14, |
| 83 | +} dma_request_t; |
| 84 | + |
| 85 | +/** \brief DMA unit size. |
| 86 | + \ingroup dmac |
| 87 | +
|
| 88 | + The unit size controls the granularity at which the DMA will transfer data. |
| 89 | + For instance, copying data to a 16-bit bus will require a 16-bit unit size. |
| 90 | +
|
| 91 | + For memory-to-memory transfers, it is recommended to use 32-byte transfers |
| 92 | + for the maximum speed. |
| 93 | +*/ |
| 94 | +typedef enum dma_unitsize { |
| 95 | + DMA_UNITSIZE_64BIT, |
| 96 | + DMA_UNITSIZE_8BIT, |
| 97 | + DMA_UNITSIZE_16BIT, |
| 98 | + DMA_UNITSIZE_32BIT, |
| 99 | + DMA_UNITSIZE_32BYTE, |
| 100 | +} dma_unitsize_t; |
| 101 | + |
| 102 | +/** \brief DMA address mode. |
| 103 | + \ingroup dmac |
| 104 | +
|
| 105 | + The "address mode" specifies how the source or destination address of a DMA |
| 106 | + transfer is modified as the transfer goes on. It is only valid when the DMA |
| 107 | + transfer is configured as pointing to memory for that source or destination. |
| 108 | +*/ |
| 109 | +typedef enum dma_addrmode { |
| 110 | + DMA_ADDRMODE_FIXED, /**< The source/destination address is not modified. */ |
| 111 | + DMA_ADDRMODE_INCREMENT, /**< The source/destination address is incremented. */ |
| 112 | + DMA_ADDRMODE_DECREMENT, /**< The source/destination address is decremented. */ |
| 113 | +} dma_addrmode_t; |
| 114 | + |
| 115 | +/** \brief DMA transmit mode. |
| 116 | + \ingroup dmac |
| 117 | +
|
| 118 | + In "Cycle steal" mode, the DMA controller will release the bus at the end of |
| 119 | + each transfer unit (configured by the unit size). This allows the CPU to |
| 120 | + access the bus if it needs to. |
| 121 | +
|
| 122 | + In "Burst" mode, the DMA controller will hold the bus until the DMA transfer |
| 123 | + completes. |
| 124 | +*/ |
| 125 | +typedef enum dma_transmitmode { |
| 126 | + DMA_TRANSMITMODE_CYCLE_STEAL, |
| 127 | + DMA_TRANSMITMODE_BURST, |
| 128 | +} dma_transmitmode_t; |
| 129 | + |
| 130 | +/** \brief DMA transfer configuration. |
| 131 | + \ingroup dmac |
| 132 | +
|
| 133 | + This structure represents the configuration used for a given DMA channel. |
| 134 | +*/ |
| 135 | +typedef struct dma_config { |
| 136 | + dma_channel_t channel; /**< DMA channel used for the transfer. */ |
| 137 | + dma_request_t request; /**< DMA request type. */ |
| 138 | + dma_unitsize_t unit_size; /**< Unit size used for the DMA transfer. */ |
| 139 | + dma_addrmode_t src_mode, dst_mode; /**< Source/destination address mode. */ |
| 140 | + dma_transmitmode_t transmit_mode; /**< DMA Transfer transmit mode. */ |
| 141 | + dma_callback_t callback; /**< Optional callback function for |
| 142 | + end-of-transfer notification. */ |
| 143 | +} dma_config_t; |
| 144 | + |
| 145 | +/** \brief DMA address. |
| 146 | + \ingroup dmac |
| 147 | +
|
| 148 | + This type represents an address that can be used for DMA transfers. |
| 149 | +*/ |
| 150 | +typedef uint32_t dma_addr_t; |
| 151 | + |
| 152 | +/** \brief Convert a hardware address to a DMA address. |
| 153 | + \ingroup dmac |
| 154 | +
|
| 155 | + This function will convert a hardware address (pointing to a device's FIFO, |
| 156 | + or to one of the various mapped memories) to an address suitable for use |
| 157 | + with the DMA controller. |
| 158 | +
|
| 159 | + \param hw_addr The hardware address. |
| 160 | + \return The converted DMA address. |
| 161 | +*/ |
| 162 | +dma_addr_t hw_to_dma_addr(uintptr_t hw_addr); |
| 163 | + |
| 164 | +/** \brief Prepare a source memory buffer for a DMA transfer. |
| 165 | + \ingroup dmac |
| 166 | +
|
| 167 | + This function will flush the data cache for the memory area covered by the |
| 168 | + buffer to ensure memory coherency, and return an address suitable for use |
| 169 | + with the DMA controller. |
| 170 | +
|
| 171 | + \param ptr A pointer to the source buffer. |
| 172 | + \param len The size in bytes of the source buffer. |
| 173 | + \return The converted DMA address. |
| 174 | +
|
| 175 | + \sa dma_map_dst() |
| 176 | +*/ |
| 177 | +dma_addr_t dma_map_src(const void *ptr, size_t len); |
| 178 | + |
| 179 | +/** \brief Prepare a destination memory buffer for a DMA transfer. |
| 180 | + \ingroup dmac |
| 181 | +
|
| 182 | + This function will invalidate the data cache for the memory area covered by |
| 183 | + the buffer to ensure memory coherency, and return an address suitable for |
| 184 | + use with the DMA controller. |
| 185 | +
|
| 186 | + \param ptr A pointer to the destination buffer. |
| 187 | + \param len The size in bytes of the destination buffer. |
| 188 | + \return The converted DMA address. |
| 189 | +
|
| 190 | + \sa dma_map_src() |
| 191 | +*/ |
| 192 | +dma_addr_t dma_map_dst(void *ptr, size_t len); |
| 193 | + |
| 194 | +/** \brief Program a DMA transfer. |
| 195 | + \ingroup dmac |
| 196 | +
|
| 197 | + This function will program a DMA transfer using the specified configuration, |
| 198 | + source/destination addresses and transfer length. |
| 199 | +
|
| 200 | + It will return as soon as the DMA transfer is programmed, which means that |
| 201 | + it will not work for the DMA transfer to complete before returning. |
| 202 | +
|
| 203 | + \param cfg A pointer to the configuration structure. |
| 204 | + \param dst The destination address, if targetting memory; |
| 205 | + can be 0 otherwise. |
| 206 | + \param src The source address, if targetting memory; |
| 207 | + can be 0 otherwise. |
| 208 | + \param len The size in bytes of the DMA transfer. |
| 209 | + \param cb_data The parameter that will be passed to the |
| 210 | + end-of-transfer callback, if a callback has been |
| 211 | + specified in the configuration structure. |
| 212 | + \retval 0 On success. |
| 213 | + \retval -1 On error. |
| 214 | +
|
| 215 | + \sa dma_wait_complete() |
| 216 | +*/ |
| 217 | +int dma_transfer(const dma_config_t *cfg, dma_addr_t dst, dma_addr_t src, |
| 218 | + size_t len, void *cb_data); |
| 219 | + |
| 220 | +/** \brief Wait for a DMA transfer to complete |
| 221 | + \ingroup dmac |
| 222 | +
|
| 223 | + This function will block until any previously programmed DMA transfer for |
| 224 | + the given DMA channel has completed. |
| 225 | +
|
| 226 | + \param channel The DMA channel to wait for. |
| 227 | +*/ |
| 228 | +void dma_wait_complete(dma_channel_t channel); |
| 229 | + |
| 230 | +/** \brief Get the remaining size of a DMA transfer |
| 231 | + \ingroup dmac |
| 232 | +
|
| 233 | + This function will return the number of bytes remaining to transfer, if a |
| 234 | + transfer was previously programmed. |
| 235 | +
|
| 236 | + \param channel The DMA channel to wait for. |
| 237 | + \return The number of bytes remaining to transfer, or zero |
| 238 | + if the previous transfer completed. |
| 239 | +*/ |
| 240 | +size_t dma_transfer_get_remaining(dma_channel_t channel); |
| 241 | + |
| 242 | +/** @} */ |
| 243 | + |
| 244 | +__END_DECLS |
| 245 | + |
| 246 | +#endif /* __ARCH_DMAC_H */ |
0 commit comments