1.1 --- a/pkg/devices/lib/dma/include/dma-jz4730.h Tue Oct 24 17:22:51 2023 +0200
1.2 +++ b/pkg/devices/lib/dma/include/dma-jz4730.h Tue Oct 24 17:32:54 2023 +0200
1.3 @@ -1,7 +1,7 @@
1.4 /*
1.5 * DMA support for the JZ4730.
1.6 *
1.7 - * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
1.8 + * Copyright (C) 2021, 2023 Paul Boddie <paul@boddie.org.uk>
1.9 *
1.10 * This program is free software; you can redistribute it and/or
1.11 * modify it under the terms of the GNU General Public License as
1.12 @@ -28,7 +28,7 @@
1.13
1.14 /* Enumerated types for various transfer parameters. */
1.15
1.16 -enum Dma_jz4730_request_type : unsigned
1.17 +enum Dma_jz4730_request_type
1.18 {
1.19 Dma_request_external = 0,
1.20 Dma_request_pcmcia_out = 4,
1.21 @@ -53,19 +53,19 @@
1.22 Dma_request_ost2_underflow = 28,
1.23 };
1.24
1.25 -enum Dma_jz4730_ext_level : unsigned
1.26 +enum Dma_jz4730_ext_level
1.27 {
1.28 Dma_ext_active_high = 0,
1.29 Dma_ext_active_low = 1,
1.30 };
1.31
1.32 -enum Dma_jz4730_ext_output_mode_cycle : unsigned
1.33 +enum Dma_jz4730_ext_output_mode_cycle
1.34 {
1.35 Dma_ext_output_mode_read_cycle = 0,
1.36 Dma_ext_output_mode_write_cycle = 1,
1.37 };
1.38
1.39 -enum Dma_jz4730_ext_req_detect_mode : unsigned
1.40 +enum Dma_jz4730_ext_req_detect_mode
1.41 {
1.42 Dma_ext_req_detect_mode_low_level = 0,
1.43 Dma_ext_req_detect_mode_falling_edge = 1,
1.44 @@ -73,15 +73,6 @@
1.45 Dma_ext_req_detect_mode_rising_edge = 3,
1.46 };
1.47
1.48 -enum Dma_jz4730_trans_unit_size : unsigned
1.49 -{
1.50 - Dma_trans_unit_size_32_bit = 0,
1.51 - Dma_trans_unit_size_8_bit = 1,
1.52 - Dma_trans_unit_size_16_bit = 2,
1.53 - Dma_trans_unit_size_16_byte = 3,
1.54 - Dma_trans_unit_size_32_byte = 4,
1.55 -};
1.56 -
1.57
1.58
1.59 #ifdef __cplusplus
1.60 @@ -103,7 +94,7 @@
1.61 Hw::Register_block<32> _regs;
1.62 Dma_jz4730_chip *_chip;
1.63 uint8_t _channel;
1.64 - l4_cap_idx_t _irq=L4_INVALID_CAP;
1.65 + l4_cap_idx_t _irq = L4_INVALID_CAP;
1.66
1.67 // External transfer properties with defaults.
1.68
1.69 @@ -117,9 +108,13 @@
1.70
1.71 unsigned int transfer(uint32_t source, uint32_t destination,
1.72 unsigned int count,
1.73 - enum Dma_jz4730_trans_unit_size size,
1.74 + bool source_increment, bool destination_increment,
1.75 + uint8_t source_width, uint8_t destination_width,
1.76 + uint8_t transfer_unit_size,
1.77 enum Dma_jz4730_request_type type=Dma_request_auto);
1.78
1.79 + unsigned int wait();
1.80 +
1.81 // External transfer property configuration.
1.82
1.83 void set_output_polarity(enum Dma_jz4730_ext_level polarity)
1.84 @@ -139,15 +134,13 @@
1.85
1.86 uint32_t encode_external_transfer(enum Dma_jz4730_request_type type);
1.87
1.88 - uint32_t encode_source_address_increment(enum Dma_jz4730_request_type type);
1.89 -
1.90 - uint32_t encode_destination_address_increment(enum Dma_jz4730_request_type type);
1.91 -
1.92 uint32_t encode_req_detect_int_length(uint8_t units);
1.93
1.94 - uint32_t encode_source_port_width(enum Dma_jz4730_request_type type);
1.95 + uint32_t encode_source_port_width(uint8_t width);
1.96
1.97 - uint32_t encode_destination_port_width(enum Dma_jz4730_request_type type);
1.98 + uint32_t encode_destination_port_width(uint8_t width);
1.99 +
1.100 + uint32_t encode_transfer_unit_size(uint8_t size);
1.101
1.102 // Transaction control.
1.103
1.104 @@ -209,9 +202,14 @@
1.105
1.106 void jz4730_dma_set_req_detect_mode(void *dma_channel, enum Dma_jz4730_ext_req_detect_mode mode);
1.107
1.108 -unsigned int jz4730_dma_transfer(void *dma_channel, uint32_t source,
1.109 - uint32_t destination, unsigned int count,
1.110 - enum Dma_jz4730_trans_unit_size size,
1.111 - enum Dma_jz4730_request_type type);
1.112 +unsigned int jz4730_dma_transfer(void *dma_channel,
1.113 + uint32_t source, uint32_t destination,
1.114 + unsigned int count,
1.115 + int source_increment, int destination_increment,
1.116 + uint8_t source_width, uint8_t destination_width,
1.117 + uint8_t transfer_unit_size,
1.118 + enum Dma_jz4730_request_type type);
1.119 +
1.120 +unsigned int jz4730_dma_wait(void *dma_channel);
1.121
1.122 EXTERN_C_END
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/pkg/devices/lib/dma/include/dma-x1600.h Tue Oct 24 17:32:54 2023 +0200
2.3 @@ -0,0 +1,180 @@
2.4 +/*
2.5 + * DMA support for the X1600.
2.6 + *
2.7 + * Copyright (C) 2021, 2023 Paul Boddie <paul@boddie.org.uk>
2.8 + *
2.9 + * This program is free software; you can redistribute it and/or
2.10 + * modify it under the terms of the GNU General Public License as
2.11 + * published by the Free Software Foundation; either version 2 of
2.12 + * the License, or (at your option) any later version.
2.13 + *
2.14 + * This program is distributed in the hope that it will be useful,
2.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2.17 + * GNU General Public License for more details.
2.18 + *
2.19 + * You should have received a copy of the GNU General Public License
2.20 + * along with this program; if not, write to the Free Software
2.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
2.22 + * Boston, MA 02110-1301, USA
2.23 + */
2.24 +
2.25 +#pragma once
2.26 +
2.27 +#include <l4/sys/types.h>
2.28 +#include <stdint.h>
2.29 +
2.30 +
2.31 +
2.32 +/* Enumerated types for various transfer parameters. */
2.33 +
2.34 +enum Dma_x1600_request_type
2.35 +{
2.36 + Dma_request_auto = 8,
2.37 + Dma_request_can0_out = 10,
2.38 + Dma_request_can0_in = 11,
2.39 + Dma_request_can1_out = 10,
2.40 + Dma_request_can1_in = 11,
2.41 + Dma_request_uart3_out = 14,
2.42 + Dma_request_uart3_in = 15,
2.43 + Dma_request_uart2_out = 16,
2.44 + Dma_request_uart2_in = 17,
2.45 + Dma_request_uart1_out = 18,
2.46 + Dma_request_uart1_in = 19,
2.47 + Dma_request_uart0_out = 20,
2.48 + Dma_request_uart0_in = 21,
2.49 + Dma_request_ssi0_send_empty = 22,
2.50 + Dma_request_ssi0_recv_full = 23,
2.51 + Dma_request_i2c0_send_empty = 36,
2.52 + Dma_request_i2c0_recv_full = 37,
2.53 + Dma_request_i2c1_send_empty = 38,
2.54 + Dma_request_i2c1_recv_full = 39,
2.55 + Dma_request_ssi_slv_out = 42,
2.56 + Dma_request_ssi_slv_in = 43,
2.57 + Dma_request_msc0_send_empty = 52,
2.58 + Dma_request_msc0_recv_full = 53,
2.59 + Dma_request_msc1_send_empty = 54,
2.60 + Dma_request_msc1_recv_full = 55,
2.61 + Dma_request_sadc_in = 56,
2.62 + Dma_request_aic_loop_out = 61,
2.63 + Dma_request_aic_out = 62,
2.64 + Dma_request_aic_in = 63,
2.65 +};
2.66 +
2.67 +
2.68 +
2.69 +#ifdef __cplusplus
2.70 +
2.71 +#include <l4/devices/cpm-x1600.h>
2.72 +#include <l4/devices/hw_mmio_register_block.h>
2.73 +
2.74 +// Forward declaration.
2.75 +
2.76 +class Dma_x1600_chip;
2.77 +
2.78 +
2.79 +
2.80 +// DMA channel.
2.81 +
2.82 +class Dma_x1600_channel
2.83 +{
2.84 +private:
2.85 + Hw::Register_block<32> _regs;
2.86 + Dma_x1600_chip *_chip;
2.87 + uint8_t _channel;
2.88 + l4_cap_idx_t _irq = L4_INVALID_CAP;
2.89 +
2.90 +public:
2.91 + Dma_x1600_channel(Dma_x1600_chip *chip, uint8_t channel, l4_addr_t start, l4_cap_idx_t irq);
2.92 +
2.93 + unsigned int transfer(uint32_t source, uint32_t destination,
2.94 + unsigned int count,
2.95 + bool source_increment, bool destination_increment,
2.96 + uint8_t source_width, uint8_t destination_width,
2.97 + uint8_t transfer_unit_size,
2.98 + enum Dma_x1600_request_type type=Dma_request_auto);
2.99 +
2.100 + unsigned int wait();
2.101 +
2.102 +protected:
2.103 + // Transfer property configuration.
2.104 +
2.105 + uint32_t encode_req_detect_int_length(uint8_t units);
2.106 +
2.107 + uint32_t encode_source_port_width(uint8_t width);
2.108 +
2.109 + uint32_t encode_destination_port_width(uint8_t width);
2.110 +
2.111 + uint32_t encode_transfer_unit_size(uint8_t size);
2.112 +
2.113 + // Transaction control.
2.114 +
2.115 + void ack_irq();
2.116 +
2.117 + bool completed();
2.118 +
2.119 + bool error();
2.120 +
2.121 + bool halted();
2.122 +
2.123 + bool wait_for_irq();
2.124 +
2.125 + bool wait_for_irq(unsigned int timeout);
2.126 +};
2.127 +
2.128 +// DMA device control.
2.129 +
2.130 +class Dma_x1600_chip
2.131 +{
2.132 +private:
2.133 + Hw::Register_block<32> _regs;
2.134 + l4_addr_t _start, _end;
2.135 + Cpm_x1600_chip *_cpm;
2.136 +
2.137 +public:
2.138 + Dma_x1600_chip(l4_addr_t start, l4_addr_t end, Cpm_x1600_chip *cpm);
2.139 +
2.140 + void disable();
2.141 +
2.142 + void enable();
2.143 +
2.144 + Dma_x1600_channel *get_channel(uint8_t channel, l4_cap_idx_t irq);
2.145 +
2.146 + // Transaction control.
2.147 +
2.148 + void ack_irq(uint8_t channel);
2.149 +
2.150 + bool error();
2.151 +
2.152 + bool halted();
2.153 +
2.154 + bool have_interrupt(uint8_t channel);
2.155 +};
2.156 +
2.157 +#endif /* __cplusplus */
2.158 +
2.159 +
2.160 +
2.161 +/* C language interface. */
2.162 +
2.163 +EXTERN_C_BEGIN
2.164 +
2.165 +void *x1600_dma_init(l4_addr_t start, l4_addr_t end, void *cpm);
2.166 +
2.167 +void x1600_dma_disable(void *dma_chip);
2.168 +
2.169 +void x1600_dma_enable(void *dma_chip);
2.170 +
2.171 +void *x1600_dma_get_channel(void *dma, uint8_t channel, l4_cap_idx_t irq);
2.172 +
2.173 +unsigned int x1600_dma_transfer(void *dma_channel,
2.174 + uint32_t source, uint32_t destination,
2.175 + unsigned int count,
2.176 + int source_increment, int destination_increment,
2.177 + uint8_t source_width, uint8_t destination_width,
2.178 + uint8_t transfer_unit_size,
2.179 + enum Dma_x1600_request_type type);
2.180 +
2.181 +unsigned int x1600_dma_wait(void *dma_channel);
2.182 +
2.183 +EXTERN_C_END
3.1 --- a/pkg/devices/lib/dma/src/Makefile Tue Oct 24 17:22:51 2023 +0200
3.2 +++ b/pkg/devices/lib/dma/src/Makefile Tue Oct 24 17:32:54 2023 +0200
3.3 @@ -4,7 +4,7 @@
3.4 TARGET = libdma.o.a libdma.o.so
3.5 PC_FILENAME := libdrivers-dma
3.6
3.7 -SRC_CC := jz4730.cc
3.8 +SRC_CC := jz4730.cc x1600.cc
3.9
3.10 PRIVATE_INCDIR += $(PKGDIR)/lib/dma/include
3.11
4.1 --- a/pkg/devices/lib/dma/src/jz4730.cc Tue Oct 24 17:22:51 2023 +0200
4.2 +++ b/pkg/devices/lib/dma/src/jz4730.cc Tue Oct 24 17:32:54 2023 +0200
4.3 @@ -27,7 +27,9 @@
4.4 #include <l4/sys/irq.h>
4.5 #include <l4/util/util.h>
4.6
4.7 -#include <cstdio>
4.8 +#include <stdio.h>
4.9 +
4.10 +
4.11
4.12 enum Global_regs
4.13 {
4.14 @@ -96,7 +98,16 @@
4.15 enum Dma_control_status_bits : unsigned
4.16 {
4.17 Dma_source_address_incr = 0x00800000,
4.18 + Dma_source_address_no_incr = 0x00000000,
4.19 Dma_dest_address_incr = 0x00400000,
4.20 + Dma_dest_address_no_incr = 0x00000000,
4.21 +
4.22 + Dma_trans_unit_size_32_bit = 0x00000000,
4.23 + Dma_trans_unit_size_8_bit = 0x00000100,
4.24 + Dma_trans_unit_size_16_bit = 0x00000200,
4.25 + Dma_trans_unit_size_16_byte = 0x00000300,
4.26 + Dma_trans_unit_size_32_byte = 0x00000400,
4.27 +
4.28 Dma_address_error = 0x00000010,
4.29 Dma_trans_completed = 0x00000008,
4.30 Dma_trans_halted = 0x00000004,
4.31 @@ -142,62 +153,6 @@
4.32 ((external ? (int) _ext_end_of_process_mode : 0) << Dma_ext_end_of_process_mode);
4.33 }
4.34
4.35 -// Encode the appropriate source address increment for the given request type.
4.36 -// Here, memory-to-memory transfers and transfers to peripherals involve an
4.37 -// incrementing source address. Transfers from peripherals involve a static
4.38 -// source address.
4.39 -
4.40 -uint32_t
4.41 -Dma_jz4730_channel::encode_source_address_increment(enum Dma_jz4730_request_type type)
4.42 -{
4.43 - switch (type)
4.44 - {
4.45 - case Dma_request_auto:
4.46 - case Dma_request_pcmcia_out:
4.47 - case Dma_request_des_out:
4.48 - case Dma_request_uart3_out:
4.49 - case Dma_request_uart2_out:
4.50 - case Dma_request_uart1_out:
4.51 - case Dma_request_uart0_out:
4.52 - case Dma_request_ssi_send_empty:
4.53 - case Dma_request_aic_send_empty:
4.54 - case Dma_request_msc_send_empty:
4.55 - case Dma_request_ost2_underflow:
4.56 - return Dma_source_address_incr;
4.57 -
4.58 - default:
4.59 - return 0;
4.60 - }
4.61 -}
4.62 -
4.63 -// Encode the appropriate destination address increment for the given request
4.64 -// type. Here, memory-to-memory transfers and transfers from peripherals involve
4.65 -// an incrementing destination address. Transfers to peripherals involve a static
4.66 -// destination address.
4.67 -
4.68 -uint32_t
4.69 -Dma_jz4730_channel::encode_destination_address_increment(enum Dma_jz4730_request_type type)
4.70 -{
4.71 - switch (type)
4.72 - {
4.73 - case Dma_request_auto:
4.74 - case Dma_request_pcmcia_in:
4.75 - case Dma_request_des_in:
4.76 - case Dma_request_uart3_in:
4.77 - case Dma_request_uart2_in:
4.78 - case Dma_request_uart1_in:
4.79 - case Dma_request_uart0_in:
4.80 - case Dma_request_ssi_recv_full:
4.81 - case Dma_request_aic_recv_full:
4.82 - case Dma_request_msc_recv_full:
4.83 - case Dma_request_ost2_underflow:
4.84 - return Dma_dest_address_incr;
4.85 -
4.86 - default:
4.87 - return 0;
4.88 - }
4.89 -}
4.90 -
4.91 // Return the closest interval length greater than or equal to the number of
4.92 // units given encoded in the request detection interval length field of the
4.93 // control/status register.
4.94 @@ -211,26 +166,23 @@
4.95 if (!units)
4.96 return 0;
4.97
4.98 - for (i = 0; i < 15; i++)
4.99 + for (i = 0; i <= 15; i++)
4.100 {
4.101 - if (lengths[i++] >= units)
4.102 + if (lengths[i] >= units)
4.103 break;
4.104 }
4.105
4.106 - return lengths[i] << Dma_req_detect_int_length;
4.107 + return i << Dma_req_detect_int_length;
4.108 }
4.109
4.110 -// Encode the appropriate source port width for the given request type.
4.111 +// Encode the appropriate source port width.
4.112
4.113 uint32_t
4.114 -Dma_jz4730_channel::encode_source_port_width(enum Dma_jz4730_request_type type)
4.115 +Dma_jz4730_channel::encode_source_port_width(uint8_t width)
4.116 {
4.117 - switch (type)
4.118 + switch (width)
4.119 {
4.120 - case Dma_request_uart3_in:
4.121 - case Dma_request_uart2_in:
4.122 - case Dma_request_uart1_in:
4.123 - case Dma_request_uart0_in:
4.124 + case 1:
4.125 return Dma_port_width_8_bit << Dma_source_port_width;
4.126
4.127 default:
4.128 @@ -241,14 +193,11 @@
4.129 // Encode the appropriate destination port width for the given request type.
4.130
4.131 uint32_t
4.132 -Dma_jz4730_channel::encode_destination_port_width(enum Dma_jz4730_request_type type)
4.133 +Dma_jz4730_channel::encode_destination_port_width(uint8_t width)
4.134 {
4.135 - switch (type)
4.136 + switch (width)
4.137 {
4.138 - case Dma_request_uart3_out:
4.139 - case Dma_request_uart2_out:
4.140 - case Dma_request_uart1_out:
4.141 - case Dma_request_uart0_out:
4.142 + case 1:
4.143 return Dma_port_width_8_bit << Dma_dest_port_width;
4.144
4.145 default:
4.146 @@ -256,12 +205,38 @@
4.147 }
4.148 }
4.149
4.150 +// Encode the transfer unit size.
4.151 +
4.152 +uint32_t
4.153 +Dma_jz4730_channel::encode_transfer_unit_size(uint8_t size)
4.154 +{
4.155 + switch (size)
4.156 + {
4.157 + case 1:
4.158 + return Dma_trans_unit_size_8_bit;
4.159 +
4.160 + case 2:
4.161 + return Dma_trans_unit_size_16_bit;
4.162 +
4.163 + case 16:
4.164 + return Dma_trans_unit_size_16_byte;
4.165 +
4.166 + case 32:
4.167 + return Dma_trans_unit_size_32_byte;
4.168 +
4.169 + default:
4.170 + return Dma_trans_unit_size_32_bit;
4.171 + }
4.172 +}
4.173 +
4.174 // Transfer data between memory locations.
4.175
4.176 unsigned int
4.177 Dma_jz4730_channel::transfer(uint32_t source, uint32_t destination,
4.178 unsigned int count,
4.179 - enum Dma_jz4730_trans_unit_size size,
4.180 + bool source_increment, bool destination_increment,
4.181 + uint8_t source_width, uint8_t destination_width,
4.182 + uint8_t transfer_unit_size,
4.183 enum Dma_jz4730_request_type type)
4.184 {
4.185 // Ensure an absence of address error and halt conditions globally and in this channel.
4.186 @@ -285,7 +260,9 @@
4.187
4.188 // Set transfer count to the number of units.
4.189
4.190 - _regs[Dma_transfer_count] = count;
4.191 + unsigned int units = count < Dma_transfer_count_mask ? count : Dma_transfer_count_mask;
4.192 +
4.193 + _regs[Dma_transfer_count] = units;
4.194
4.195 // Set auto-request for memory-to-memory transfers. Otherwise, set the
4.196 // indicated request type.
4.197 @@ -303,19 +280,27 @@
4.198 */
4.199
4.200 _regs[Dma_control_status] = encode_external_transfer(type) |
4.201 - encode_source_address_increment(type) |
4.202 - encode_destination_address_increment(type) |
4.203 - encode_source_port_width(type) |
4.204 - encode_destination_port_width(type) |
4.205 - (size << Dma_trans_unit_size) |
4.206 + (source_increment ? Dma_source_address_incr : Dma_source_address_no_incr) |
4.207 + (destination_increment ? Dma_dest_address_incr : Dma_dest_address_no_incr) |
4.208 + encode_source_port_width(source_width) |
4.209 + encode_destination_port_width(destination_width) |
4.210 + encode_transfer_unit_size(transfer_unit_size) |
4.211 (Dma_trans_mode_single << Dma_trans_mode) |
4.212 Dma_channel_irq_enable |
4.213 Dma_channel_enable;
4.214
4.215 + // Return the number of units to transfer.
4.216 +
4.217 + return units;
4.218 +}
4.219 +
4.220 +unsigned int
4.221 +Dma_jz4730_channel::wait()
4.222 +{
4.223 // An interrupt will occur upon completion, the completion flag will be set
4.224 // and the transfer count will be zero.
4.225
4.226 - unsigned int remaining = count;
4.227 + unsigned int remaining = 0;
4.228
4.229 do
4.230 {
4.231 @@ -334,9 +319,16 @@
4.232 }
4.233 while (!error() && !halted() && !completed());
4.234
4.235 - // Return the number of transferred units.
4.236 + // Reset the channel status.
4.237
4.238 - return count - remaining;
4.239 + _regs[Dma_control_status] = _regs[Dma_control_status] & ~(Dma_channel_enable |
4.240 + Dma_trans_completed | Dma_address_error |
4.241 + Dma_trans_halted);
4.242 + _regs[Dma_transfer_count] = 0;
4.243 +
4.244 + // Return the number of remaining units.
4.245 +
4.246 + return remaining;
4.247 }
4.248
4.249 // Wait indefinitely for an interrupt request, returning true if one was delivered.
4.250 @@ -424,7 +416,7 @@
4.251 while (_regs[Dma_control] & Dma_control_enable);
4.252 }
4.253
4.254 -// Obtain a channel object. Only one channel is supported.
4.255 +// Obtain a channel object.
4.256
4.257 Dma_jz4730_channel *
4.258 Dma_jz4730_chip::get_channel(uint8_t channel, l4_cap_idx_t irq)
4.259 @@ -487,10 +479,20 @@
4.260 static_cast<Dma_jz4730_channel *>(dma_channel)->set_req_detect_mode(mode);
4.261 }
4.262
4.263 -unsigned int jz4730_dma_transfer(void *dma_channel, uint32_t source,
4.264 - uint32_t destination, unsigned int count,
4.265 - enum Dma_jz4730_trans_unit_size size,
4.266 +unsigned int jz4730_dma_transfer(void *dma_channel,
4.267 + uint32_t source, uint32_t destination,
4.268 + unsigned int count,
4.269 + int source_increment, int destination_increment,
4.270 + uint8_t source_width, uint8_t destination_width,
4.271 + uint8_t transfer_unit_size,
4.272 enum Dma_jz4730_request_type type)
4.273 {
4.274 - return static_cast<Dma_jz4730_channel *>(dma_channel)->transfer(source, destination, count, size, type);
4.275 + return static_cast<Dma_jz4730_channel *>(dma_channel)->transfer(source,
4.276 + destination, count, source_increment, destination_increment, source_width,
4.277 + destination_width, transfer_unit_size, type);
4.278 }
4.279 +
4.280 +unsigned int jz4730_dma_wait(void *dma_channel)
4.281 +{
4.282 + return static_cast<Dma_jz4730_channel *>(dma_channel)->wait();
4.283 +}
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/pkg/devices/lib/dma/src/x1600.cc Tue Oct 24 17:32:54 2023 +0200
5.3 @@ -0,0 +1,509 @@
5.4 +/*
5.5 + * DMA support for the X1600.
5.6 + *
5.7 + * Copyright (C) 2021, 2023 Paul Boddie <paul@boddie.org.uk>
5.8 + *
5.9 + * This program is free software; you can redistribute it and/or
5.10 + * modify it under the terms of the GNU General Public License as
5.11 + * published by the Free Software Foundation; either version 2 of
5.12 + * the License, or (at your option) any later version.
5.13 + *
5.14 + * This program is distributed in the hope that it will be useful,
5.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
5.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5.17 + * GNU General Public License for more details.
5.18 + *
5.19 + * You should have received a copy of the GNU General Public License
5.20 + * along with this program; if not, write to the Free Software
5.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
5.22 + * Boston, MA 02110-1301, USA
5.23 + */
5.24 +
5.25 +#include <l4/devices/dma-x1600.h>
5.26 +#include <l4/devices/hw_mmio_register_block.h>
5.27 +
5.28 +#include <l4/sys/icu.h>
5.29 +#include <l4/sys/ipc.h>
5.30 +#include <l4/sys/irq.h>
5.31 +#include <l4/util/util.h>
5.32 +
5.33 +#include <stdio.h>
5.34 +
5.35 +
5.36 +
5.37 +enum Global_regs
5.38 +{
5.39 + Dma_control = 0x1000, // DMAC
5.40 + Dma_irq_pending = 0x1004, // DIRQP
5.41 +};
5.42 +
5.43 +enum Channel_regs
5.44 +{
5.45 + Dma_source = 0x00, // DSA
5.46 + Dma_destination = 0x04, // DTA
5.47 + Dma_transfer_count = 0x08, // DTC
5.48 + Dma_request_source = 0x0c, // DRT
5.49 + Dma_control_status = 0x10, // DCS
5.50 + Dma_command = 0x14, // DCM
5.51 + Dma_descriptor_address = 0x18, // DDA
5.52 + Dma_stride = 0x1c, // DSD
5.53 +};
5.54 +
5.55 +enum Dma_control_bits : unsigned
5.56 +{
5.57 + Dma_fast_msc_transfer = 0x80000000, // FMSC
5.58 + Dma_fast_ssi_transfer = 0x40000000, // FSSI
5.59 + Dma_fast_tssi_transfer = 0x20000000, // FTSSI
5.60 + Dma_fast_uart_transfer = 0x10000000, // FUART
5.61 + Dma_fast_aic_transfer = 0x08000000, // FAIC
5.62 + Dma_control_trans_halted = 0x00000008, // HLT
5.63 + Dma_control_address_error = 0x00000004, // AR
5.64 + Dma_control_enable = 0x00000001, // DMAE
5.65 +};
5.66 +
5.67 +enum Dma_transfer_count_bits : unsigned
5.68 +{
5.69 + Dma_transfer_count_mask = 0x00ffffff,
5.70 +};
5.71 +
5.72 +enum Dma_request_source_bits : unsigned
5.73 +{
5.74 + Dma_request_type_mask = 0x0000001f,
5.75 +};
5.76 +
5.77 +enum Dma_control_status_bits : unsigned
5.78 +{
5.79 + Dma_no_descriptor_transfer = 0x80000000,
5.80 + Dma_8word_descriptor = 0x40000000,
5.81 + Dma_copy_offset_mask = 0x0000ff00,
5.82 + Dma_address_error = 0x00000010,
5.83 + Dma_trans_completed = 0x00000008,
5.84 + Dma_trans_halted = 0x00000004,
5.85 + Dma_channel_enable = 0x00000001,
5.86 +
5.87 + Dma_copy_offset_shift = 8,
5.88 +};
5.89 +
5.90 +enum Dma_command_bits : unsigned
5.91 +{
5.92 + Dma_source_address_increment = 0x800000,
5.93 + Dma_source_address_no_increment = 0x000000,
5.94 + Dma_destination_address_increment = 0x400000,
5.95 + Dma_destination_address_no_increment = 0x000000,
5.96 +
5.97 + Dma_source_address_increment_wrap = 0x200000,
5.98 + Dma_destination_address_increment_wrap = 0x100000,
5.99 + Dma_recommended_data_unit_size_mask = 0x0f0000,
5.100 + Dma_source_port_width_mask = 0x00c000,
5.101 + Dma_destination_port_width_mask = 0x003000,
5.102 + Dma_transfer_unit_size_mask = 0x000f00,
5.103 +
5.104 + Dma_trans_unit_size_32_bit = 0x000000,
5.105 + Dma_trans_unit_size_8_bit = 0x000100,
5.106 + Dma_trans_unit_size_16_bit = 0x000200,
5.107 + Dma_trans_unit_size_16_byte = 0x000300,
5.108 + Dma_trans_unit_size_32_byte = 0x000400,
5.109 + Dma_trans_unit_size_64_byte = 0x000500,
5.110 + Dma_trans_unit_size_128_byte = 0x000600,
5.111 + Dma_trans_unit_size_autonomous = 0x000700,
5.112 + Dma_trans_unit_size_external = 0x000800,
5.113 +
5.114 + Dma_source_address_compare_index = 0x000080,
5.115 + Dma_destination_address_compare_index = 0x000040,
5.116 + Dma_stride_enable = 0x000004,
5.117 + Dma_transfer_irq_enable = 0x000002,
5.118 + Dma_descriptor_link_enable = 0x000001,
5.119 +
5.120 + Dma_recommended_data_unit_size_shift = 16,
5.121 + Dma_source_port_width_shift = 14,
5.122 + Dma_destination_port_width_shift = 12,
5.123 + Dma_transfer_unit_size_shift = 8,
5.124 +};
5.125 +
5.126 +enum Dma_port_width_values : unsigned
5.127 +{
5.128 + Dma_port_width_32_bit = 0,
5.129 + Dma_port_width_8_bit = 1,
5.130 + Dma_port_width_16_bit = 2,
5.131 +};
5.132 +
5.133 +
5.134 +
5.135 +// Initialise a channel.
5.136 +
5.137 +Dma_x1600_channel::Dma_x1600_channel(Dma_x1600_chip *chip, uint8_t channel,
5.138 + l4_addr_t start, l4_cap_idx_t irq)
5.139 +: _chip(chip), _channel(channel), _irq(irq)
5.140 +{
5.141 + _regs = new Hw::Mmio_register_block<32>(start);
5.142 +
5.143 + // Initialise the transfer count.
5.144 +
5.145 + _regs[Dma_transfer_count] = 0;
5.146 +}
5.147 +
5.148 +// Return the closest interval length greater than or equal to the number of
5.149 +// units given encoded in the request detection interval length field of the
5.150 +// control/status register.
5.151 +
5.152 +uint32_t
5.153 +Dma_x1600_channel::encode_req_detect_int_length(uint8_t units)
5.154 +{
5.155 + static uint8_t lengths[] = {0, 1, 2, 3, 4, 8, 16, 32, 64, 128};
5.156 + int i;
5.157 +
5.158 + if (!units)
5.159 + return 0;
5.160 +
5.161 + for (i = 0; i <= 9; i++)
5.162 + {
5.163 + if (lengths[i] >= units)
5.164 + break;
5.165 + }
5.166 +
5.167 + return i << Dma_recommended_data_unit_size_shift;
5.168 +}
5.169 +
5.170 +// Encode the appropriate source port width for the given request type.
5.171 +
5.172 +uint32_t
5.173 +Dma_x1600_channel::encode_source_port_width(uint8_t width)
5.174 +{
5.175 + switch (width)
5.176 + {
5.177 + case 1:
5.178 + return Dma_port_width_8_bit << Dma_source_port_width_shift;
5.179 +
5.180 + case 2:
5.181 + return Dma_port_width_16_bit << Dma_source_port_width_shift;
5.182 +
5.183 + default:
5.184 + return Dma_port_width_32_bit << Dma_source_port_width_shift;
5.185 + }
5.186 +}
5.187 +
5.188 +// Encode the appropriate destination port width for the given request type.
5.189 +
5.190 +uint32_t
5.191 +Dma_x1600_channel::encode_destination_port_width(uint8_t width)
5.192 +{
5.193 + switch (width)
5.194 + {
5.195 + case 1:
5.196 + return Dma_port_width_8_bit << Dma_destination_port_width_shift;
5.197 +
5.198 + case 2:
5.199 + return Dma_port_width_16_bit << Dma_destination_port_width_shift;
5.200 +
5.201 + default:
5.202 + return Dma_port_width_32_bit << Dma_destination_port_width_shift;
5.203 + }
5.204 +}
5.205 +
5.206 +// Encode the transfer unit size.
5.207 +// NOTE: This does not handle the external case.
5.208 +
5.209 +uint32_t
5.210 +Dma_x1600_channel::encode_transfer_unit_size(uint8_t size)
5.211 +{
5.212 + switch (size)
5.213 + {
5.214 + case 0:
5.215 + return Dma_trans_unit_size_autonomous;
5.216 +
5.217 + case 1:
5.218 + return Dma_trans_unit_size_8_bit;
5.219 +
5.220 + case 2:
5.221 + return Dma_trans_unit_size_16_bit;
5.222 +
5.223 + case 16:
5.224 + return Dma_trans_unit_size_16_byte;
5.225 +
5.226 + case 32:
5.227 + return Dma_trans_unit_size_32_byte;
5.228 +
5.229 + case 64:
5.230 + return Dma_trans_unit_size_64_byte;
5.231 +
5.232 + case 128:
5.233 + return Dma_trans_unit_size_128_byte;
5.234 +
5.235 + default:
5.236 + return Dma_trans_unit_size_32_bit;
5.237 + }
5.238 +}
5.239 +
5.240 +// Transfer data between memory locations.
5.241 +
5.242 +unsigned int
5.243 +Dma_x1600_channel::transfer(uint32_t source, uint32_t destination,
5.244 + unsigned int count,
5.245 + bool source_increment, bool destination_increment,
5.246 + uint8_t source_width, uint8_t destination_width,
5.247 + uint8_t transfer_unit_size,
5.248 + enum Dma_x1600_request_type type)
5.249 +{
5.250 + printf("transfer:%s%s%s%s\n", error() ? " error" : "",
5.251 + halted() ? " halted" : "",
5.252 + completed() ? " completed" : "",
5.253 + _regs[Dma_transfer_count] ? " count" : "");
5.254 +
5.255 + // Ensure an absence of address error and halt conditions globally and in this channel.
5.256 +
5.257 + if (error() || halted())
5.258 + return 0;
5.259 +
5.260 + // Ensure an absence of transaction completed and zero transfer count for this channel.
5.261 +
5.262 + if (completed() || _regs[Dma_transfer_count])
5.263 + return 0;
5.264 +
5.265 + // Disable the channel.
5.266 +
5.267 + _regs[Dma_control_status] = _regs[Dma_control_status] & ~Dma_channel_enable;
5.268 +
5.269 + // Set addresses.
5.270 +
5.271 + _regs[Dma_source] = source;
5.272 + _regs[Dma_destination] = destination;
5.273 +
5.274 + // Set transfer count to the number of units.
5.275 +
5.276 + unsigned int units = count < Dma_transfer_count_mask ? count : Dma_transfer_count_mask;
5.277 +
5.278 + _regs[Dma_transfer_count] = units;
5.279 +
5.280 + // Set auto-request for memory-to-memory transfers. Otherwise, set the
5.281 + // indicated request type.
5.282 +
5.283 + _regs[Dma_request_source] = type;
5.284 +
5.285 + // For a descriptor, the actual fields would be populated instead of the
5.286 + // command register, descriptor transfer would be indicated in the control/
5.287 + // status register along with the appropriate descriptor size indicator.
5.288 +
5.289 + /* NOTE: To be considered...
5.290 + * request detection interval length (for autonomous mode)
5.291 + */
5.292 +
5.293 + _regs[Dma_command] = (source_increment ? Dma_source_address_increment : Dma_source_address_no_increment) |
5.294 + (destination_increment ? Dma_destination_address_increment : Dma_destination_address_no_increment) |
5.295 + encode_source_port_width(source_width) |
5.296 + encode_destination_port_width(destination_width) |
5.297 + encode_transfer_unit_size(transfer_unit_size) |
5.298 + Dma_transfer_irq_enable;
5.299 +
5.300 + // For a descriptor, the descriptor address would be set and the doorbell
5.301 + // register field for the channel set.
5.302 +
5.303 + // Enable the channel (and peripheral).
5.304 +
5.305 + _regs[Dma_control_status] = Dma_no_descriptor_transfer |
5.306 + Dma_channel_enable;
5.307 +
5.308 + // Return the number of units to transfer.
5.309 +
5.310 + return units;
5.311 +}
5.312 +
5.313 +unsigned int
5.314 +Dma_x1600_channel::wait()
5.315 +{
5.316 + // An interrupt will occur upon completion, the completion flag will be set
5.317 + // and the transfer count will be zero.
5.318 +
5.319 + unsigned int remaining = 0;
5.320 +
5.321 + do
5.322 + {
5.323 + if (!wait_for_irq(1000000))
5.324 + printf("status = %x\n", (uint32_t) _regs[Dma_control_status]);
5.325 + else
5.326 + {
5.327 + printf("status = %x\n", (uint32_t) _regs[Dma_control_status]);
5.328 + remaining = _regs[Dma_transfer_count];
5.329 + ack_irq();
5.330 + break;
5.331 + }
5.332 + }
5.333 + while (!error() && !halted() && !completed());
5.334 +
5.335 + // Reset the channel status.
5.336 +
5.337 + _regs[Dma_control_status] = _regs[Dma_control_status] & ~(Dma_channel_enable |
5.338 + Dma_trans_completed | Dma_address_error |
5.339 + Dma_trans_halted);
5.340 + _regs[Dma_transfer_count] = 0;
5.341 +
5.342 + // Return the number of remaining units.
5.343 +
5.344 + return remaining;
5.345 +}
5.346 +
5.347 +// Wait indefinitely for an interrupt request, returning true if one was delivered.
5.348 +
5.349 +bool
5.350 +Dma_x1600_channel::wait_for_irq()
5.351 +{
5.352 + return !l4_error(l4_irq_receive(_irq, L4_IPC_NEVER)) && _chip->have_interrupt(_channel);
5.353 +}
5.354 +
5.355 +// Wait up to the given timeout (in microseconds) for an interrupt request,
5.356 +// returning true if one was delivered.
5.357 +
5.358 +bool
5.359 +Dma_x1600_channel::wait_for_irq(unsigned int timeout)
5.360 +{
5.361 + return !l4_error(l4_irq_receive(_irq, l4_timeout(L4_IPC_TIMEOUT_NEVER, l4util_micros2l4to(timeout)))) && _chip->have_interrupt(_channel);
5.362 +}
5.363 +
5.364 +// Acknowledge an interrupt condition.
5.365 +
5.366 +void
5.367 +Dma_x1600_channel::ack_irq()
5.368 +{
5.369 + _chip->ack_irq(_channel);
5.370 +}
5.371 +
5.372 +// Return whether a transfer has completed.
5.373 +
5.374 +bool
5.375 +Dma_x1600_channel::completed()
5.376 +{
5.377 + return _regs[Dma_control_status] & Dma_trans_completed ? true : false;
5.378 +}
5.379 +
5.380 +// Return whether an address error condition has arisen.
5.381 +
5.382 +bool
5.383 +Dma_x1600_channel::error()
5.384 +{
5.385 + return _chip->error() || (_regs[Dma_control_status] & Dma_address_error ? true : false);
5.386 +}
5.387 +
5.388 +// Return whether a transfer has halted.
5.389 +
5.390 +bool
5.391 +Dma_x1600_channel::halted()
5.392 +{
5.393 + return _chip->halted() || (_regs[Dma_control_status] & Dma_trans_halted ? true : false);
5.394 +}
5.395 +
5.396 +
5.397 +
5.398 +// Initialise the I2C controller.
5.399 +
5.400 +Dma_x1600_chip::Dma_x1600_chip(l4_addr_t start, l4_addr_t end,
5.401 + Cpm_x1600_chip *cpm)
5.402 +: _start(start), _end(end), _cpm(cpm)
5.403 +{
5.404 + _regs = new Hw::Mmio_register_block<32>(start);
5.405 +}
5.406 +
5.407 +// Enable the peripheral.
5.408 +
5.409 +void
5.410 +Dma_x1600_chip::enable()
5.411 +{
5.412 + // Make sure that the DMA clock is available.
5.413 +
5.414 + _cpm->start_clock(Clock_dma);
5.415 +
5.416 + _regs[Dma_control] = Dma_control_enable;
5.417 + while (!(_regs[Dma_control] & Dma_control_enable));
5.418 +}
5.419 +
5.420 +// Disable the channel.
5.421 +
5.422 +void
5.423 +Dma_x1600_chip::disable()
5.424 +{
5.425 + _regs[Dma_control] = 0;
5.426 + while (_regs[Dma_control] & Dma_control_enable);
5.427 +}
5.428 +
5.429 +// Obtain a channel object.
5.430 +
5.431 +Dma_x1600_channel *
5.432 +Dma_x1600_chip::get_channel(uint8_t channel, l4_cap_idx_t irq)
5.433 +{
5.434 + if (channel < 32)
5.435 + return new Dma_x1600_channel(this, channel, _start + 0x20 * channel, irq);
5.436 + else
5.437 + throw -L4_EINVAL;
5.438 +}
5.439 +
5.440 +// Return whether an interrupt is pending on the given channel.
5.441 +
5.442 +bool
5.443 +Dma_x1600_chip::have_interrupt(uint8_t channel)
5.444 +{
5.445 + return _regs[Dma_irq_pending] & (1 << channel) ? true : false;
5.446 +}
5.447 +
5.448 +// Acknowledge an interrupt condition on the given channel.
5.449 +
5.450 +void
5.451 +Dma_x1600_chip::ack_irq(uint8_t channel)
5.452 +{
5.453 + _regs[Dma_irq_pending] = _regs[Dma_irq_pending] & ~(1 << channel);
5.454 +}
5.455 +
5.456 +// Return whether an address error condition has arisen.
5.457 +
5.458 +bool
5.459 +Dma_x1600_chip::error()
5.460 +{
5.461 + return _regs[Dma_control] & Dma_control_address_error ? true : false;
5.462 +}
5.463 +
5.464 +// Return whether a transfer has halted.
5.465 +
5.466 +bool
5.467 +Dma_x1600_chip::halted()
5.468 +{
5.469 + return _regs[Dma_control] & Dma_control_trans_halted ? true : false;
5.470 +}
5.471 +
5.472 +
5.473 +
5.474 +// C language interface functions.
5.475 +
5.476 +void *x1600_dma_init(l4_addr_t start, l4_addr_t end, void *cpm)
5.477 +{
5.478 + return (void *) new Dma_x1600_chip(start, end, static_cast<Cpm_x1600_chip *>(cpm));
5.479 +}
5.480 +
5.481 +void x1600_dma_disable(void *dma_chip)
5.482 +{
5.483 + static_cast<Dma_x1600_chip *>(dma_chip)->disable();
5.484 +}
5.485 +
5.486 +void x1600_dma_enable(void *dma_chip)
5.487 +{
5.488 + static_cast<Dma_x1600_chip *>(dma_chip)->enable();
5.489 +}
5.490 +
5.491 +void *x1600_dma_get_channel(void *dma, uint8_t channel, l4_cap_idx_t irq)
5.492 +{
5.493 + return static_cast<Dma_x1600_chip *>(dma)->get_channel(channel, irq);
5.494 +}
5.495 +
5.496 +unsigned int x1600_dma_transfer(void *dma_channel,
5.497 + uint32_t source, uint32_t destination,
5.498 + unsigned int count,
5.499 + int source_increment, int destination_increment,
5.500 + uint8_t source_width, uint8_t destination_width,
5.501 + uint8_t transfer_unit_size,
5.502 + enum Dma_x1600_request_type type)
5.503 +{
5.504 + return static_cast<Dma_x1600_channel *>(dma_channel)->transfer(source,
5.505 + destination, count, source_increment, destination_increment, source_width,
5.506 + destination_width, transfer_unit_size, type);
5.507 +}
5.508 +
5.509 +unsigned int x1600_dma_wait(void *dma_channel)
5.510 +{
5.511 + return static_cast<Dma_x1600_channel *>(dma_channel)->wait();
5.512 +}