paul@123 | 1 | /* |
paul@123 | 2 | * DMA support for the JZ4730. |
paul@123 | 3 | * |
paul@284 | 4 | * Copyright (C) 2021, 2023, 2024 Paul Boddie <paul@boddie.org.uk> |
paul@123 | 5 | * |
paul@123 | 6 | * This program is free software; you can redistribute it and/or |
paul@123 | 7 | * modify it under the terms of the GNU General Public License as |
paul@123 | 8 | * published by the Free Software Foundation; either version 2 of |
paul@123 | 9 | * the License, or (at your option) any later version. |
paul@123 | 10 | * |
paul@123 | 11 | * This program is distributed in the hope that it will be useful, |
paul@123 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
paul@123 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
paul@123 | 14 | * GNU General Public License for more details. |
paul@123 | 15 | * |
paul@123 | 16 | * You should have received a copy of the GNU General Public License |
paul@123 | 17 | * along with this program; if not, write to the Free Software |
paul@123 | 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, |
paul@123 | 19 | * Boston, MA 02110-1301, USA |
paul@123 | 20 | */ |
paul@123 | 21 | |
paul@123 | 22 | #pragma once |
paul@123 | 23 | |
paul@123 | 24 | #include <l4/sys/types.h> |
paul@123 | 25 | #include <stdint.h> |
paul@123 | 26 | |
paul@123 | 27 | |
paul@123 | 28 | |
paul@123 | 29 | /* Enumerated types for various transfer parameters. */ |
paul@123 | 30 | |
paul@204 | 31 | enum Dma_jz4730_request_type |
paul@123 | 32 | { |
paul@123 | 33 | Dma_request_external = 0, |
paul@123 | 34 | Dma_request_pcmcia_out = 4, |
paul@123 | 35 | Dma_request_pcmcia_in = 5, |
paul@123 | 36 | Dma_request_auto = 8, |
paul@123 | 37 | Dma_request_des_out = 10, |
paul@123 | 38 | Dma_request_des_in = 11, |
paul@123 | 39 | Dma_request_uart3_out = 14, |
paul@123 | 40 | Dma_request_uart3_in = 15, |
paul@123 | 41 | Dma_request_uart2_out = 16, |
paul@123 | 42 | Dma_request_uart2_in = 17, |
paul@123 | 43 | Dma_request_uart1_out = 18, |
paul@123 | 44 | Dma_request_uart1_in = 19, |
paul@123 | 45 | Dma_request_uart0_out = 20, |
paul@123 | 46 | Dma_request_uart0_in = 21, |
paul@214 | 47 | Dma_request_ssi_out = 22, |
paul@214 | 48 | Dma_request_ssi_in = 23, |
paul@214 | 49 | Dma_request_aic_out = 24, |
paul@214 | 50 | Dma_request_aic_in = 25, |
paul@214 | 51 | Dma_request_msc_out = 26, |
paul@214 | 52 | Dma_request_msc_in = 27, |
paul@123 | 53 | Dma_request_ost2_underflow = 28, |
paul@123 | 54 | }; |
paul@123 | 55 | |
paul@204 | 56 | enum Dma_jz4730_ext_level |
paul@123 | 57 | { |
paul@123 | 58 | Dma_ext_active_high = 0, |
paul@123 | 59 | Dma_ext_active_low = 1, |
paul@123 | 60 | }; |
paul@123 | 61 | |
paul@204 | 62 | enum Dma_jz4730_ext_output_mode_cycle |
paul@123 | 63 | { |
paul@123 | 64 | Dma_ext_output_mode_read_cycle = 0, |
paul@123 | 65 | Dma_ext_output_mode_write_cycle = 1, |
paul@123 | 66 | }; |
paul@123 | 67 | |
paul@204 | 68 | enum Dma_jz4730_ext_req_detect_mode |
paul@123 | 69 | { |
paul@123 | 70 | Dma_ext_req_detect_mode_low_level = 0, |
paul@123 | 71 | Dma_ext_req_detect_mode_falling_edge = 1, |
paul@123 | 72 | Dma_ext_req_detect_mode_high_level = 2, |
paul@123 | 73 | Dma_ext_req_detect_mode_rising_edge = 3, |
paul@123 | 74 | }; |
paul@123 | 75 | |
paul@123 | 76 | |
paul@123 | 77 | |
paul@123 | 78 | #ifdef __cplusplus |
paul@123 | 79 | |
paul@284 | 80 | #include <l4/devices/dma-generic.h> |
paul@123 | 81 | #include <l4/devices/hw_mmio_register_block.h> |
paul@123 | 82 | |
paul@123 | 83 | // Forward declaration. |
paul@123 | 84 | |
paul@123 | 85 | class Dma_jz4730_chip; |
paul@123 | 86 | |
paul@123 | 87 | |
paul@123 | 88 | |
paul@123 | 89 | // DMA channel. |
paul@123 | 90 | |
paul@284 | 91 | class Dma_jz4730_channel : public Dma_channel |
paul@123 | 92 | { |
paul@123 | 93 | private: |
paul@123 | 94 | Hw::Register_block<32> _regs; |
paul@284 | 95 | Dma_chip *_chip; |
paul@123 | 96 | uint8_t _channel; |
paul@204 | 97 | l4_cap_idx_t _irq = L4_INVALID_CAP; |
paul@123 | 98 | |
paul@123 | 99 | // External transfer properties with defaults. |
paul@123 | 100 | |
paul@123 | 101 | enum Dma_jz4730_ext_level _ext_output_polarity = Dma_ext_active_high; |
paul@123 | 102 | enum Dma_jz4730_ext_level _ext_end_of_process_mode = Dma_ext_active_high; |
paul@123 | 103 | enum Dma_jz4730_ext_output_mode_cycle _ext_output_mode_cycle = Dma_ext_output_mode_read_cycle; |
paul@123 | 104 | enum Dma_jz4730_ext_req_detect_mode _ext_req_detect_mode = Dma_ext_req_detect_mode_high_level; |
paul@123 | 105 | |
paul@123 | 106 | public: |
paul@284 | 107 | Dma_jz4730_channel(Dma_chip *chip, uint8_t channel, l4_addr_t start, l4_cap_idx_t irq); |
paul@123 | 108 | |
paul@123 | 109 | unsigned int transfer(uint32_t source, uint32_t destination, |
paul@123 | 110 | unsigned int count, |
paul@204 | 111 | bool source_increment, bool destination_increment, |
paul@204 | 112 | uint8_t source_width, uint8_t destination_width, |
paul@204 | 113 | uint8_t transfer_unit_size, |
paul@284 | 114 | int type=Dma_request_auto, |
paul@284 | 115 | l4_addr_t desc_vaddr = 0, |
paul@284 | 116 | l4re_dma_space_dma_addr_t desc_paddr = 0); |
paul@123 | 117 | |
paul@204 | 118 | unsigned int wait(); |
paul@204 | 119 | |
paul@123 | 120 | // External transfer property configuration. |
paul@123 | 121 | |
paul@123 | 122 | void set_output_polarity(enum Dma_jz4730_ext_level polarity) |
paul@123 | 123 | { _ext_output_polarity = polarity; } |
paul@123 | 124 | |
paul@123 | 125 | void set_end_of_process_mode(enum Dma_jz4730_ext_level mode) |
paul@123 | 126 | { _ext_end_of_process_mode = mode; } |
paul@123 | 127 | |
paul@123 | 128 | void set_output_mode_cycle(enum Dma_jz4730_ext_output_mode_cycle cycle) |
paul@123 | 129 | { _ext_output_mode_cycle = cycle; } |
paul@123 | 130 | |
paul@123 | 131 | void set_req_detect_mode(enum Dma_jz4730_ext_req_detect_mode mode) |
paul@123 | 132 | { _ext_req_detect_mode = mode; } |
paul@123 | 133 | |
paul@123 | 134 | protected: |
paul@123 | 135 | // Transfer property configuration. |
paul@123 | 136 | |
paul@123 | 137 | uint32_t encode_external_transfer(enum Dma_jz4730_request_type type); |
paul@123 | 138 | |
paul@123 | 139 | uint32_t encode_req_detect_int_length(uint8_t units); |
paul@123 | 140 | |
paul@204 | 141 | uint32_t encode_source_port_width(uint8_t width); |
paul@123 | 142 | |
paul@204 | 143 | uint32_t encode_destination_port_width(uint8_t width); |
paul@204 | 144 | |
paul@204 | 145 | uint32_t encode_transfer_unit_size(uint8_t size); |
paul@123 | 146 | |
paul@123 | 147 | // Transaction control. |
paul@123 | 148 | |
paul@123 | 149 | void ack_irq(); |
paul@123 | 150 | |
paul@123 | 151 | bool completed(); |
paul@123 | 152 | |
paul@123 | 153 | bool error(); |
paul@123 | 154 | |
paul@123 | 155 | bool halted(); |
paul@123 | 156 | |
paul@123 | 157 | bool wait_for_irq(); |
paul@123 | 158 | |
paul@123 | 159 | bool wait_for_irq(unsigned int timeout); |
paul@123 | 160 | }; |
paul@123 | 161 | |
paul@123 | 162 | // DMA device control. |
paul@123 | 163 | |
paul@284 | 164 | class Dma_jz4730_chip : public Dma_chip |
paul@123 | 165 | { |
paul@123 | 166 | private: |
paul@123 | 167 | Hw::Register_block<32> _regs; |
paul@123 | 168 | l4_addr_t _start, _end; |
paul@284 | 169 | Cpm_chip *_cpm; |
paul@123 | 170 | |
paul@123 | 171 | public: |
paul@284 | 172 | Dma_jz4730_chip(l4_addr_t start, l4_addr_t end, Cpm_chip *cpm); |
paul@123 | 173 | |
paul@123 | 174 | void disable(); |
paul@123 | 175 | |
paul@123 | 176 | void enable(); |
paul@123 | 177 | |
paul@284 | 178 | Dma_channel *get_channel(uint8_t channel, l4_cap_idx_t irq); |
paul@123 | 179 | |
paul@123 | 180 | bool have_interrupt(uint8_t channel); |
paul@123 | 181 | }; |
paul@123 | 182 | |
paul@284 | 183 | Dma_chip *jz4730_dma_chip(l4_addr_t start, l4_addr_t end, Cpm_chip *cpm); |
paul@284 | 184 | |
paul@123 | 185 | #endif /* __cplusplus */ |
paul@123 | 186 | |
paul@123 | 187 | |
paul@123 | 188 | |
paul@123 | 189 | /* C language interface. */ |
paul@123 | 190 | |
paul@123 | 191 | EXTERN_C_BEGIN |
paul@123 | 192 | |
paul@123 | 193 | void *jz4730_dma_init(l4_addr_t start, l4_addr_t end, void *cpm); |
paul@123 | 194 | |
paul@123 | 195 | void jz4730_dma_disable(void *dma_chip); |
paul@123 | 196 | |
paul@123 | 197 | void jz4730_dma_enable(void *dma_chip); |
paul@123 | 198 | |
paul@123 | 199 | void *jz4730_dma_get_channel(void *dma, uint8_t channel, l4_cap_idx_t irq); |
paul@123 | 200 | |
paul@123 | 201 | void jz4730_dma_set_output_polarity(void *dma_channel, enum Dma_jz4730_ext_level polarity); |
paul@123 | 202 | |
paul@123 | 203 | void jz4730_dma_set_end_of_process_mode(void *dma_channel, enum Dma_jz4730_ext_level mode); |
paul@123 | 204 | |
paul@123 | 205 | void jz4730_dma_set_output_mode_cycle(void *dma_channel, enum Dma_jz4730_ext_output_mode_cycle cycle); |
paul@123 | 206 | |
paul@123 | 207 | void jz4730_dma_set_req_detect_mode(void *dma_channel, enum Dma_jz4730_ext_req_detect_mode mode); |
paul@123 | 208 | |
paul@204 | 209 | unsigned int jz4730_dma_transfer(void *dma_channel, |
paul@204 | 210 | uint32_t source, uint32_t destination, |
paul@204 | 211 | unsigned int count, |
paul@204 | 212 | int source_increment, int destination_increment, |
paul@204 | 213 | uint8_t source_width, uint8_t destination_width, |
paul@204 | 214 | uint8_t transfer_unit_size, |
paul@204 | 215 | enum Dma_jz4730_request_type type); |
paul@204 | 216 | |
paul@204 | 217 | unsigned int jz4730_dma_wait(void *dma_channel); |
paul@123 | 218 | |
paul@123 | 219 | EXTERN_C_END |