# HG changeset patch # User Paul Boddie # Date 1699578131 -3600 # Node ID 9dacd9bcc5e8f016131159bf327041f56b1400a0 # Parent 3f9892859cee6792cd2e52690ba60ca5de18b656 Added some support for descriptor-based DMA transfers. diff -r 3f9892859cee -r 9dacd9bcc5e8 pkg/devices/lib/dma/include/dma-jz4780.h --- a/pkg/devices/lib/dma/include/dma-jz4780.h Thu Nov 09 18:40:31 2023 +0100 +++ b/pkg/devices/lib/dma/include/dma-jz4780.h Fri Nov 10 02:02:11 2023 +0100 @@ -21,6 +21,7 @@ #pragma once +#include #include #include @@ -72,6 +73,14 @@ Dma_request_des_in = 47, }; +/* Descriptor structure. */ + +struct jz4780_dma_descriptor +{ + uint32_t command, source, destination, transfer_count, + stride, request_source, reserved0, reserved1; +}; + #ifdef __cplusplus @@ -103,7 +112,9 @@ bool source_increment, bool destination_increment, uint8_t source_width, uint8_t destination_width, uint8_t transfer_unit_size, - enum Dma_jz4780_request_type type=Dma_request_auto); + enum Dma_jz4780_request_type type=Dma_request_auto, + l4_addr_t desc_vaddr = 0, + l4re_dma_space_dma_addr_t desc_paddr = 0); unsigned int wait(); @@ -160,6 +171,10 @@ bool halted(); bool have_interrupt(uint8_t channel); + + // Descriptor operations. + + void commit_descriptor(uint8_t channel); }; #endif /* __cplusplus */ @@ -186,6 +201,16 @@ uint8_t transfer_unit_size, enum Dma_jz4780_request_type type); +unsigned int jz4780_dma_transfer_descriptor(void *dma_channel, + uint32_t source, uint32_t destination, + unsigned int count, + int source_increment, int destination_increment, + uint8_t source_width, uint8_t destination_width, + uint8_t transfer_unit_size, + enum Dma_jz4780_request_type type, + l4_addr_t desc_vaddr, + l4re_dma_space_dma_addr_t desc_paddr); + unsigned int jz4780_dma_wait(void *dma_channel); EXTERN_C_END diff -r 3f9892859cee -r 9dacd9bcc5e8 pkg/devices/lib/dma/src/jz4780.cc --- a/pkg/devices/lib/dma/src/jz4780.cc Thu Nov 09 18:40:31 2023 +0100 +++ b/pkg/devices/lib/dma/src/jz4780.cc Fri Nov 10 02:02:11 2023 +0100 @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -36,6 +37,13 @@ { Dma_control = 0x1000, // DMAC Dma_irq_pending = 0x1004, // DIRQP + Dma_doorbell = 0x1008, // DDB + Dma_doorbell_set = 0x100c, // DDS + Dma_channel_programmable = 0x101c, // DMACP + Dma_soft_irq_pending = 0x1020, // DSIRQP + Dma_soft_irq_mask = 0x1024, // DSIRQM + Dma_mcu_irq_pending = 0x1028, // DCIRQP + Dma_mcu_irq_mask = 0x102c, // DCIRQM }; enum Channel_regs @@ -69,7 +77,10 @@ enum Dma_transfer_count_bits : unsigned { + Dma_descriptor_offset_mask = 0xff000000, // DOA (in DES3) Dma_transfer_count_mask = 0x00ffffff, + + Dma_descriptor_offset_shift = 24, }; enum Dma_request_source_bits : unsigned @@ -81,6 +92,7 @@ { Dma_no_descriptor_transfer = 0x80000000, Dma_8word_descriptor = 0x40000000, + Dma_4word_descriptor = 0x00000000, Dma_copy_offset_mask = 0x0000ff00, Dma_address_error = 0x00000010, Dma_trans_completed = 0x00000008, @@ -253,7 +265,9 @@ bool source_increment, bool destination_increment, uint8_t source_width, uint8_t destination_width, uint8_t transfer_unit_size, - enum Dma_jz4780_request_type type) + enum Dma_jz4780_request_type type, + l4_addr_t desc_vaddr, + l4re_dma_space_dma_addr_t desc_paddr) { printf("transfer:%s%s%s%s\n", error() ? " error" : "", halted() ? " halted" : "", @@ -274,43 +288,65 @@ _regs[Dma_control_status] = _regs[Dma_control_status] & ~Dma_channel_enable; - // Set addresses. - - _regs[Dma_source] = source; - _regs[Dma_destination] = destination; - // Set transfer count to the number of units. unsigned int units = count < Dma_transfer_count_mask ? count : Dma_transfer_count_mask; - _regs[Dma_transfer_count] = units; + // NOTE: Request detection interval length (for autonomous mode) not considered. - // Set auto-request for memory-to-memory transfers. Otherwise, set the - // indicated request type. + uint32_t command = (source_increment ? Dma_source_address_increment : + Dma_source_address_no_increment) | + (destination_increment ? Dma_destination_address_increment : + Dma_destination_address_no_increment) | + encode_source_port_width(source_width) | + encode_destination_port_width(destination_width) | + encode_transfer_unit_size(transfer_unit_size) | + Dma_transfer_irq_enable; - _regs[Dma_request_source] = type; + // Populate the descriptor, largely corresponding to the population of + // registers when descriptors are not being used. - // For a descriptor, the actual fields would be populated instead of the - // command register, descriptor transfer would be indicated in the control/ - // status register along with the appropriate descriptor size indicator. + if (desc_vaddr) + { + struct jz4780_dma_descriptor *desc = (struct jz4780_dma_descriptor *) desc_vaddr; + + // NOTE: Linking to the same descriptor. + + uint32_t descriptor_offset = 0; - /* NOTE: To be considered... - * request detection interval length (for autonomous mode) - */ + desc->command = command | Dma_descriptor_link_enable; + desc->source = source; + desc->destination = destination; + desc->transfer_count = (units & Dma_transfer_count_mask) | + (descriptor_offset << Dma_descriptor_offset_shift); + desc->request_source = type; + + // NOTE: Stride not supported yet. + + l4_cache_clean_data((unsigned long) desc_vaddr, + (unsigned long) desc_vaddr + sizeof(*desc)); + + // Commit the descriptor. - _regs[Dma_command] = (source_increment ? Dma_source_address_increment : Dma_source_address_no_increment) | - (destination_increment ? Dma_destination_address_increment : Dma_destination_address_no_increment) | - encode_source_port_width(source_width) | - encode_destination_port_width(destination_width) | - encode_transfer_unit_size(transfer_unit_size) | - Dma_transfer_irq_enable; + _regs[Dma_descriptor_address] = desc_paddr; + _chip->commit_descriptor(_channel); + } + + // Otherwise, populate the registers for a one-off transfer. - // For a descriptor, the descriptor address would be set and the doorbell - // register field for the channel set. + else + { + _regs[Dma_command] = command; + _regs[Dma_source] = source; + _regs[Dma_destination] = destination; + _regs[Dma_transfer_count] = units & Dma_transfer_count_mask; + _regs[Dma_request_source] = type; + } - // Enable the channel (and peripheral). + // Enable the channel with descriptor transfer configured if appropriate. - _regs[Dma_control_status] = Dma_no_descriptor_transfer | + _regs[Dma_control_status] = (desc_vaddr ? Dma_8word_descriptor : + Dma_no_descriptor_transfer) | Dma_channel_enable; // Return the number of units to transfer. @@ -477,6 +513,12 @@ return _regs[Dma_control] & Dma_control_trans_halted ? true : false; } +void +Dma_jz4780_chip::commit_descriptor(uint8_t channel) +{ + _regs[Dma_doorbell_set] = (1 << channel); +} + // C language interface functions. @@ -502,18 +544,33 @@ } unsigned int jz4780_dma_transfer(void *dma_channel, - uint32_t source, uint32_t destination, - unsigned int count, - int source_increment, int destination_increment, - uint8_t source_width, uint8_t destination_width, - uint8_t transfer_unit_size, - enum Dma_jz4780_request_type type) + uint32_t source, uint32_t destination, + unsigned int count, + int source_increment, int destination_increment, + uint8_t source_width, uint8_t destination_width, + uint8_t transfer_unit_size, + enum Dma_jz4780_request_type type) { return static_cast(dma_channel)->transfer(source, destination, count, source_increment, destination_increment, source_width, destination_width, transfer_unit_size, type); } +unsigned int jz4780_dma_transfer_descriptor(void *dma_channel, + uint32_t source, uint32_t destination, + unsigned int count, + int source_increment, int destination_increment, + uint8_t source_width, uint8_t destination_width, + uint8_t transfer_unit_size, + enum Dma_jz4780_request_type type, + l4_addr_t desc_vaddr, + l4re_dma_space_dma_addr_t desc_paddr) +{ + return static_cast(dma_channel)->transfer(source, + destination, count, source_increment, destination_increment, source_width, + destination_width, transfer_unit_size, type, desc_vaddr, desc_paddr); +} + unsigned int jz4780_dma_wait(void *dma_channel) { return static_cast(dma_channel)->wait(); diff -r 3f9892859cee -r 9dacd9bcc5e8 pkg/devices/lib/spi/include/spi-jz4780.h --- a/pkg/devices/lib/spi/include/spi-jz4780.h Thu Nov 09 18:40:31 2023 +0100 +++ b/pkg/devices/lib/spi/include/spi-jz4780.h Fri Nov 10 02:02:11 2023 +0100 @@ -75,7 +75,9 @@ /* DMA operations. */ uint32_t transfer(l4re_dma_space_dma_addr_t paddr, uint32_t count, - uint8_t unit_size, uint8_t char_size); + uint8_t unit_size, uint8_t char_size, + l4_addr_t desc_vaddr = 0, + l4re_dma_space_dma_addr_t desc_paddr = 0); }; /* SPI peripheral. */ @@ -116,4 +118,9 @@ uint32_t jz4780_spi_transfer(void *channel, l4re_dma_space_dma_addr_t paddr, uint32_t count, uint8_t unit_size, uint8_t char_size); +uint32_t jz4780_spi_transfer_descriptor(void *channel, l4re_dma_space_dma_addr_t paddr, + uint32_t count, uint8_t unit_size, + uint8_t char_size, l4_addr_t desc_vaddr, + l4re_dma_space_dma_addr_t desc_paddr); + EXTERN_C_END diff -r 3f9892859cee -r 9dacd9bcc5e8 pkg/devices/lib/spi/src/jz4780.cc --- a/pkg/devices/lib/spi/src/jz4780.cc Thu Nov 09 18:40:31 2023 +0100 +++ b/pkg/devices/lib/spi/src/jz4780.cc Fri Nov 10 02:02:11 2023 +0100 @@ -345,7 +345,9 @@ uint32_t Spi_jz4780_channel::transfer(l4re_dma_space_dma_addr_t paddr, uint32_t count, uint8_t unit_size, - uint8_t char_size) + uint8_t char_size, + l4_addr_t desc_vaddr, + l4re_dma_space_dma_addr_t desc_paddr) { configure_transfer(char_size); @@ -354,12 +356,18 @@ uint32_t to_transfer = _dma->transfer(paddr, _spi_start + Ssi_data, unit_count, true, false, unit_size, unit_size, unit_size, - _request_type); + _request_type, desc_vaddr, desc_paddr); + + /* Wait if not using a descriptor, which could be causing an endless, + repeating transfer. */ - if (to_transfer) + if (to_transfer && !desc_vaddr) + { transferred = to_transfer ? (unit_count - _dma->wait()) * unit_size : 0; - - wait_busy(); + wait_busy(); + } + else + transferred = to_transfer; return transferred; } @@ -440,3 +448,12 @@ return static_cast(channel)->transfer(paddr, count, unit_size, char_size); } + +uint32_t jz4780_spi_transfer_descriptor(void *channel, l4re_dma_space_dma_addr_t paddr, + uint32_t count, uint8_t unit_size, + uint8_t char_size, l4_addr_t desc_vaddr, + l4re_dma_space_dma_addr_t desc_paddr) +{ + return static_cast(channel)->transfer(paddr, count, + unit_size, char_size, desc_vaddr, desc_paddr); +} diff -r 3f9892859cee -r 9dacd9bcc5e8 pkg/landfall-examples/hw_info/common.h --- a/pkg/landfall-examples/hw_info/common.h Thu Nov 09 18:40:31 2023 +0100 +++ b/pkg/landfall-examples/hw_info/common.h Fri Nov 10 02:02:11 2023 +0100 @@ -188,7 +188,8 @@ uint8_t unit_size, uint8_t char_size); uint32_t spi_transfer(void *channel, l4re_dma_space_dma_addr_t paddr, - uint32_t count, uint8_t unit_size, uint8_t char_size); + uint32_t count, uint8_t unit_size, uint8_t char_size, + l4_addr_t desc_vaddr, l4re_dma_space_dma_addr_t desc_paddr); diff -r 3f9892859cee -r 9dacd9bcc5e8 pkg/landfall-examples/hw_info/hw_info.c --- a/pkg/landfall-examples/hw_info/hw_info.c Thu Nov 09 18:40:31 2023 +0100 +++ b/pkg/landfall-examples/hw_info/hw_info.c Fri Nov 10 02:02:11 2023 +0100 @@ -1127,7 +1127,7 @@ static void spi_transfer_data(void) { void *channel = get_channel(num_spi_channels, spi_channels, NULL); - struct dma_region *region; + struct dma_region *region, *desc_region; unsigned int char_size, unit_size; uint32_t count, transferred; @@ -1148,7 +1148,11 @@ if (!read_number("Character size", &char_size)) return; - transferred = spi_transfer(channel, region->paddr, count, unit_size, char_size); + desc_region = _get_dma_region(); + + transferred = spi_transfer(channel, region->paddr, count, unit_size, char_size, + desc_region != NULL ? desc_region->vaddr : 0, + desc_region != NULL ? desc_region->paddr : 0); printf("Transferred: %d\n", transferred); } diff -r 3f9892859cee -r 9dacd9bcc5e8 pkg/landfall-examples/hw_info/jz4780.c --- a/pkg/landfall-examples/hw_info/jz4780.c Thu Nov 09 18:40:31 2023 +0100 +++ b/pkg/landfall-examples/hw_info/jz4780.c Fri Nov 10 02:02:11 2023 +0100 @@ -379,13 +379,15 @@ } uint32_t spi_transfer(void *channel, l4re_dma_space_dma_addr_t paddr, - uint32_t count, uint8_t unit_size, uint8_t char_size) + uint32_t count, uint8_t unit_size, uint8_t char_size, + l4_addr_t desc_vaddr, l4re_dma_space_dma_addr_t desc_paddr) { /* Transfer is not supported by the common interface. */ void *ch = spi_hybrid_get_raw_channel(channel); - return jz4780_spi_transfer(ch, paddr, count, unit_size, char_size); + return jz4780_spi_transfer_descriptor(ch, paddr, count, unit_size, char_size, + desc_vaddr, desc_paddr); } diff -r 3f9892859cee -r 9dacd9bcc5e8 pkg/landfall-examples/hw_info/x1600.c --- a/pkg/landfall-examples/hw_info/x1600.c Thu Nov 09 18:40:31 2023 +0100 +++ b/pkg/landfall-examples/hw_info/x1600.c Fri Nov 10 02:02:11 2023 +0100 @@ -382,12 +382,15 @@ } uint32_t spi_transfer(void *channel, l4re_dma_space_dma_addr_t paddr, - uint32_t count, uint8_t unit_size, uint8_t char_size) + uint32_t count, uint8_t unit_size, uint8_t char_size, + l4_addr_t desc_vaddr, l4re_dma_space_dma_addr_t desc_paddr) { /* NOTE: Not yet supported. */ (void) channel; (void) paddr; (void) count; (void) unit_size; (void) char_size; - // return x1600_spi_transfer(channel, paddr, count, unit_size, char_size); + (void) desc_vaddr; (void) desc_paddr; + // return x1600_spi_transfer(channel, paddr, count, unit_size, char_size, + // desc_vaddr, desc_paddr); return 0; }