1.1 --- a/pkg/devices/lib/dma/src/x1600.cc Wed Apr 24 00:47:34 2024 +0200
1.2 +++ b/pkg/devices/lib/dma/src/x1600.cc Sat Apr 27 23:46:28 2024 +0200
1.3 @@ -19,9 +19,11 @@
1.4 * Boston, MA 02110-1301, USA
1.5 */
1.6
1.7 +#include <l4/devices/cpm-x1600.h>
1.8 #include <l4/devices/dma-x1600.h>
1.9 #include <l4/devices/hw_mmio_register_block.h>
1.10
1.11 +#include <l4/sys/cache.h>
1.12 #include <l4/sys/ipc.h>
1.13 #include <l4/sys/irq.h>
1.14 #include <l4/sys/rcv_endpoint.h>
1.15 @@ -37,6 +39,8 @@
1.16 {
1.17 Dma_control = 0x1000, // DMAC
1.18 Dma_irq_pending = 0x1004, // DIRQP
1.19 + Dma_doorbell = 0x1008, // DDB
1.20 + Dma_doorbell_set = 0x100c, // DDS
1.21 };
1.22
1.23 enum Channel_regs
1.24 @@ -65,7 +69,10 @@
1.25
1.26 enum Dma_transfer_count_bits : unsigned
1.27 {
1.28 + Dma_descriptor_offset_mask = 0xff000000, // DOA (in DES3)
1.29 +
1.30 Dma_transfer_count_mask = 0x00ffffff,
1.31 + Dma_descriptor_offset_shift = 24,
1.32 };
1.33
1.34 enum Dma_request_source_bits : unsigned
1.35 @@ -133,8 +140,8 @@
1.36
1.37 // Initialise a channel.
1.38
1.39 -Dma_x1600_channel::Dma_x1600_channel(Dma_x1600_chip *chip, uint8_t channel,
1.40 - l4_addr_t start, l4_cap_idx_t irq)
1.41 +Dma_x1600_channel::Dma_x1600_channel(Dma_chip *chip, uint8_t channel,
1.42 + l4_addr_t start, l4_cap_idx_t irq)
1.43 : _chip(chip), _channel(channel), _irq(irq)
1.44 {
1.45 _regs = new Hw::Mmio_register_block<32>(start);
1.46 @@ -245,7 +252,9 @@
1.47 bool source_increment, bool destination_increment,
1.48 uint8_t source_width, uint8_t destination_width,
1.49 uint8_t transfer_unit_size,
1.50 - enum Dma_x1600_request_type type)
1.51 + int type,
1.52 + l4_addr_t desc_vaddr,
1.53 + l4re_dma_space_dma_addr_t desc_paddr)
1.54 {
1.55 // Ensure an absence of address error and halt conditions globally and in this channel.
1.56
1.57 @@ -261,41 +270,71 @@
1.58
1.59 _regs[Dma_control_status] = _regs[Dma_control_status] & ~Dma_channel_enable;
1.60
1.61 - // Set addresses.
1.62 -
1.63 - _regs[Dma_source] = source;
1.64 - _regs[Dma_destination] = destination;
1.65 -
1.66 // Set transfer count to the number of units.
1.67
1.68 unsigned int units = count < Dma_transfer_count_mask ? count : Dma_transfer_count_mask;
1.69
1.70 - _regs[Dma_transfer_count] = units;
1.71 + // NOTE: Request detection interval length (for autonomous mode) not considered.
1.72
1.73 - // Set auto-request for memory-to-memory transfers. Otherwise, set the
1.74 - // indicated request type.
1.75 + uint32_t command = (source_increment ? Dma_source_address_increment
1.76 + : Dma_source_address_no_increment) |
1.77 + (destination_increment ? Dma_destination_address_increment
1.78 + : Dma_destination_address_no_increment) |
1.79 + encode_source_port_width(source_width) |
1.80 + encode_destination_port_width(destination_width) |
1.81 + encode_transfer_unit_size(transfer_unit_size) |
1.82 + Dma_transfer_irq_enable;
1.83 +
1.84 + // Populate the descriptor, largely corresponding to the population of
1.85 + // registers when descriptors are not being used.
1.86
1.87 - _regs[Dma_request_source] = type;
1.88 + if (desc_vaddr)
1.89 + {
1.90 + // For a descriptor, the descriptor address would be set and the doorbell
1.91 + // register field for the channel set.
1.92
1.93 - // For a descriptor, the actual fields would be populated instead of the
1.94 - // command register, descriptor transfer would be indicated in the control/
1.95 - // status register along with the appropriate descriptor size indicator.
1.96 + // For a descriptor, the actual fields would be populated instead of the
1.97 + // command register, descriptor transfer would be indicated in the control/
1.98 + // status register along with the appropriate descriptor size indicator.
1.99 +
1.100 + struct x1600_dma_descriptor *desc = (struct x1600_dma_descriptor *) desc_vaddr;
1.101 +
1.102 + // NOTE: Linking to the same descriptor.
1.103 +
1.104 + uint32_t descriptor_offset = 0;
1.105
1.106 - /* NOTE: To be considered...
1.107 - * request detection interval length (for autonomous mode)
1.108 - */
1.109 + desc->command = command | Dma_descriptor_link_enable;
1.110 + desc->source = source;
1.111 + desc->destination = destination;
1.112 + desc->transfer_count = (units & Dma_transfer_count_mask) |
1.113 + (descriptor_offset << Dma_descriptor_offset_shift);
1.114 + desc->request_source = (enum Dma_x1600_request_type) type;
1.115 +
1.116 + // NOTE: Stride not supported yet.
1.117 +
1.118 + l4_cache_clean_data((unsigned long) desc_vaddr,
1.119 + (unsigned long) desc_vaddr + sizeof(*desc));
1.120 +
1.121 + // Commit the descriptor.
1.122
1.123 - _regs[Dma_command] = (source_increment ? Dma_source_address_increment : Dma_source_address_no_increment) |
1.124 - (destination_increment ? Dma_destination_address_increment : Dma_destination_address_no_increment) |
1.125 - encode_source_port_width(source_width) |
1.126 - encode_destination_port_width(destination_width) |
1.127 - encode_transfer_unit_size(transfer_unit_size) |
1.128 - Dma_transfer_irq_enable;
1.129 + _regs[Dma_descriptor_address] = desc_paddr;
1.130 + _chip->commit_descriptor(_channel);
1.131 + }
1.132 +
1.133 + // Otherwise, populate the registers for a one-off transfer.
1.134
1.135 - // For a descriptor, the descriptor address would be set and the doorbell
1.136 - // register field for the channel set.
1.137 + else
1.138 + {
1.139 + // Set addresses and transfer count.
1.140
1.141 - // Enable the channel (and peripheral).
1.142 + _regs[Dma_source] = source;
1.143 + _regs[Dma_destination] = destination;
1.144 + _regs[Dma_transfer_count] = units;
1.145 + _regs[Dma_request_source] = (enum Dma_x1600_request_type) type;
1.146 + _regs[Dma_command] = command;
1.147 + }
1.148 +
1.149 + // Enable the channel with descriptor transfer configured if appropriate.
1.150
1.151 _regs[Dma_control_status] = Dma_no_descriptor_transfer |
1.152 Dma_channel_enable;
1.153 @@ -398,8 +437,7 @@
1.154
1.155 // Initialise the I2C controller.
1.156
1.157 -Dma_x1600_chip::Dma_x1600_chip(l4_addr_t start, l4_addr_t end,
1.158 - Cpm_x1600_chip *cpm)
1.159 +Dma_x1600_chip::Dma_x1600_chip(l4_addr_t start, l4_addr_t end, Cpm_chip *cpm)
1.160 : _start(start), _end(end), _cpm(cpm)
1.161 {
1.162 _regs = new Hw::Mmio_register_block<32>(start);
1.163 @@ -429,7 +467,7 @@
1.164
1.165 // Obtain a channel object.
1.166
1.167 -Dma_x1600_channel *
1.168 +Dma_channel *
1.169 Dma_x1600_chip::get_channel(uint8_t channel, l4_cap_idx_t irq)
1.170 {
1.171 if (channel < 32)
1.172 @@ -470,28 +508,39 @@
1.173 return _regs[Dma_control] & Dma_control_trans_halted ? true : false;
1.174 }
1.175
1.176 +void
1.177 +Dma_x1600_chip::commit_descriptor(uint8_t channel)
1.178 +{
1.179 + _regs[Dma_doorbell_set] = (1 << channel);
1.180 +}
1.181 +
1.182 +Dma_chip *x1600_dma_chip(l4_addr_t start, l4_addr_t end, Cpm_chip *cpm)
1.183 +{
1.184 + return new Dma_x1600_chip(start, end, cpm);
1.185 +}
1.186 +
1.187
1.188
1.189 // C language interface functions.
1.190
1.191 void *x1600_dma_init(l4_addr_t start, l4_addr_t end, void *cpm)
1.192 {
1.193 - return (void *) new Dma_x1600_chip(start, end, static_cast<Cpm_x1600_chip *>(cpm));
1.194 + return (void *) x1600_dma_chip(start, end, static_cast<Cpm_chip *>(cpm));
1.195 }
1.196
1.197 void x1600_dma_disable(void *dma_chip)
1.198 {
1.199 - static_cast<Dma_x1600_chip *>(dma_chip)->disable();
1.200 + static_cast<Dma_chip *>(dma_chip)->disable();
1.201 }
1.202
1.203 void x1600_dma_enable(void *dma_chip)
1.204 {
1.205 - static_cast<Dma_x1600_chip *>(dma_chip)->enable();
1.206 + static_cast<Dma_chip *>(dma_chip)->enable();
1.207 }
1.208
1.209 void *x1600_dma_get_channel(void *dma, uint8_t channel, l4_cap_idx_t irq)
1.210 {
1.211 - return static_cast<Dma_x1600_chip *>(dma)->get_channel(channel, irq);
1.212 + return static_cast<Dma_chip *>(dma)->get_channel(channel, irq);
1.213 }
1.214
1.215 unsigned int x1600_dma_transfer(void *dma_channel,