# HG changeset patch # User Paul Boddie # Date 1699916562 -3600 # Node ID 779f8f6a9587a0380c165979702ddd6bf383523f # Parent 438287f28c11c9a91eb86832b4a8cd87150c8b0d Added general support for SPI transfers, employing plain virtual memory regions instead of DMA regions for GPIO-driven transfers. diff -r 438287f28c11 -r 779f8f6a9587 conf/landfall-examples/mips-x1600-info.list --- a/conf/landfall-examples/mips-x1600-info.list Mon Nov 13 01:20:09 2023 +0100 +++ b/conf/landfall-examples/mips-x1600-info.list Tue Nov 14 00:02:42 2023 +0100 @@ -13,3 +13,4 @@ module ned module ex_x1600_info module piano-3.raw +module P8021407-crop-240x240.data diff -r 438287f28c11 -r 779f8f6a9587 pkg/devices/lib/spi/include/spi-gpio.h --- a/pkg/devices/lib/spi/include/spi-gpio.h Mon Nov 13 01:20:09 2023 +0100 +++ b/pkg/devices/lib/spi/include/spi-gpio.h Tue Nov 14 00:02:42 2023 +0100 @@ -21,6 +21,7 @@ #pragma once +#include #include @@ -58,10 +59,16 @@ uint32_t send(uint32_t bytes, const uint8_t data[]); - uint32_t send_dc(uint32_t bytes, const uint8_t data[], const int dc[]); + uint32_t send_dc(uint32_t bytes, const uint8_t data[], const int dc[], + uint8_t char_size, bool big_endian); uint32_t send_units(uint32_t bytes, const uint8_t data[], uint8_t unit_size, - uint8_t char_size); + uint8_t char_size, bool big_endian); + + uint32_t transfer(l4_addr_t vaddr, l4re_dma_space_dma_addr_t paddr, + uint32_t count, uint8_t unit_size, uint8_t char_size, + l4_addr_t desc_vaddr = 0, + l4re_dma_space_dma_addr_t desc_paddr = 0); }; #endif /* __cplusplus */ @@ -81,9 +88,20 @@ uint32_t spi_gpio_send(void *channel, uint32_t bytes, const uint8_t data[]); uint32_t spi_gpio_send_dc(void *channel, uint32_t bytes, const uint8_t data[], - const int dc[]); + const int dc[], uint8_t char_size, int big_endian); uint32_t spi_gpio_send_units(void *channel, uint32_t bytes, const uint8_t data[], - uint8_t unit_size, uint8_t char_size); + uint8_t unit_size, uint8_t char_size, int big_endian); + +uint32_t spi_gpio_transfer(void *channel, l4_addr_t vaddr, + l4re_dma_space_dma_addr_t paddr, + uint32_t count, uint8_t unit_size, + uint8_t char_size); + +uint32_t spi_gpio_transfer_descriptor(void *channel, l4_addr_t vaddr, + 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 438287f28c11 -r 779f8f6a9587 pkg/devices/lib/spi/include/spi-hybrid.h --- a/pkg/devices/lib/spi/include/spi-hybrid.h Mon Nov 13 01:20:09 2023 +0100 +++ b/pkg/devices/lib/spi/include/spi-hybrid.h Tue Nov 14 00:02:42 2023 +0100 @@ -22,6 +22,7 @@ #pragma once +#include #include @@ -53,10 +54,16 @@ uint32_t send(uint32_t bytes, const uint8_t data[]); - uint32_t send_dc(uint32_t bytes, const uint8_t data[], const int dc[]); + uint32_t send_dc(uint32_t bytes, const uint8_t data[], const int dc[], + uint8_t char_size, bool big_endian); uint32_t send_units(uint32_t bytes, const uint8_t data[], - uint8_t unit_size, uint8_t char_size); + uint8_t unit_size, uint8_t char_size, bool big_endian); + + uint32_t transfer(l4_addr_t vaddr, l4re_dma_space_dma_addr_t paddr, + uint32_t count, uint8_t unit_size, uint8_t char_size, + l4_addr_t desc_vaddr = 0, + l4re_dma_space_dma_addr_t desc_paddr = 0); }; #endif /* __cplusplus */ @@ -79,9 +86,19 @@ uint32_t spi_hybrid_send(void *channel, uint32_t bytes, const uint8_t data[]); uint32_t spi_hybrid_send_dc(void *channel, uint32_t bytes, const uint8_t data[], - const int dc[]); + const int dc[], uint8_t char_size, int big_endian); uint32_t spi_hybrid_send_units(void *channel, uint32_t bytes, const uint8_t data[], - uint8_t unit_size, uint8_t char_size); + uint8_t unit_size, uint8_t char_size, int big_endian); + +uint32_t spi_hybrid_transfer(void *channel, l4_addr_t vaddr, + l4re_dma_space_dma_addr_t paddr, uint32_t count, + uint8_t unit_size, uint8_t char_size); + +uint32_t spi_hybrid_transfer_descriptor(void *channel, l4_addr_t vaddr, + 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 438287f28c11 -r 779f8f6a9587 pkg/devices/lib/spi/include/spi-jz4780.h --- a/pkg/devices/lib/spi/include/spi-jz4780.h Mon Nov 13 01:20:09 2023 +0100 +++ b/pkg/devices/lib/spi/include/spi-jz4780.h Tue Nov 14 00:02:42 2023 +0100 @@ -67,15 +67,16 @@ virtual uint32_t send(uint32_t bytes, const uint8_t data[]); - virtual uint32_t send_dc(uint32_t bytes, const uint8_t data[], const int dc[]); + virtual uint32_t send_dc(uint32_t bytes, const uint8_t data[], const int dc[], + uint8_t char_size, bool big_endian); uint32_t send_units(uint32_t bytes, const uint8_t data[], uint8_t unit_size, - uint8_t char_size); + uint8_t char_size, bool big_endian); /* DMA operations. */ - uint32_t transfer(l4re_dma_space_dma_addr_t paddr, uint32_t count, - uint8_t unit_size, uint8_t char_size, + uint32_t transfer(l4_addr_t vaddr, l4re_dma_space_dma_addr_t paddr, + uint32_t count, uint8_t unit_size, uint8_t char_size, l4_addr_t desc_vaddr = 0, l4re_dma_space_dma_addr_t desc_paddr = 0); }; @@ -110,15 +111,17 @@ uint32_t jz4780_spi_send(void *channel, uint32_t bytes, const uint8_t data[]); uint32_t jz4780_spi_send_dc(void *channel, uint32_t bytes, const uint8_t data[], - const int dc[]); + const int dc[], uint8_t char_size, int big_endian); uint32_t jz4780_spi_send_units(void *channel, uint32_t bytes, const uint8_t data[], - uint8_t unit_size, uint8_t char_size); + uint8_t unit_size, uint8_t char_size, int big_endian); -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(void *channel, l4_addr_t vaddr, + 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 jz4780_spi_transfer_descriptor(void *channel, l4_addr_t vaddr, + 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); diff -r 438287f28c11 -r 779f8f6a9587 pkg/devices/lib/spi/include/spi.h --- a/pkg/devices/lib/spi/include/spi.h Mon Nov 13 01:20:09 2023 +0100 +++ b/pkg/devices/lib/spi/include/spi.h Tue Nov 14 00:02:42 2023 +0100 @@ -21,8 +21,11 @@ #pragma once + + #ifdef __cplusplus +#include #include /* SPI channel abstractions. */ @@ -33,10 +36,17 @@ virtual uint32_t send(uint32_t bytes, const uint8_t data[]) = 0; virtual uint32_t send_dc(uint32_t bytes, const uint8_t data[], - const int dc[]) = 0; + const int dc[], uint8_t char_size, + bool big_endian) = 0; virtual uint32_t send_units(uint32_t bytes, const uint8_t data[], - uint8_t unit_size, uint8_t char_size) = 0; + uint8_t unit_size, uint8_t char_size, + bool big_endian) = 0; + + virtual uint32_t transfer(l4_addr_t vaddr, l4re_dma_space_dma_addr_t paddr, + uint32_t count, uint8_t unit_size, uint8_t char_size, + l4_addr_t desc_vaddr = 0, + l4re_dma_space_dma_addr_t desc_paddr = 0) = 0; }; class Spi_control_base diff -r 438287f28c11 -r 779f8f6a9587 pkg/devices/lib/spi/src/gpio.cc --- a/pkg/devices/lib/spi/src/gpio.cc Mon Nov 13 01:20:09 2023 +0100 +++ b/pkg/devices/lib/spi/src/gpio.cc Tue Nov 14 00:02:42 2023 +0100 @@ -19,7 +19,9 @@ * Boston, MA 02110-1301, USA */ +#include #include +#include /* NOTE: required by calloc/free */ #include @@ -58,18 +60,19 @@ uint32_t Spi_gpio::send(uint32_t bytes, const uint8_t data[]) { - return send_dc(bytes, data, NULL); + return send_dc(bytes, data, NULL, 8, false); } -/* Send a byte sequence with accompanying data/command indicators. */ +/* Send a byte sequence with accompanying data/command indicators. Bytes are + grouped into character units, with each unit holding a value with the given + byte ordering. */ uint32_t Spi_gpio::send_dc(uint32_t bytes, const uint8_t data[], - const int dc[]) + const int dc[], uint8_t char_size, bool big_endian) { struct timespec ts; - uint8_t mask; - int bit; - uint32_t byte; + uint32_t offset, char_unit; + uint8_t char_unit_size = ((char_size ? char_size - 1 : 0) / 8) + 1; if (_frequency) { @@ -83,27 +86,34 @@ _clock_device->set(_clock_pin, 1); _data_device->set(_data_pin, 0); + if ((_control_device != NULL) && (_control_pin >= 0) && (dc != NULL)) + _control_device->set(_control_pin, dc[0] ? 1 : 0); + /* Enter the transmission state. */ _enable_device->set(_enable_pin, 0); /* Clock data using the clock and data outputs. */ - for (byte = 0; byte < bytes; byte++) + for (offset = 0, char_unit = 0; offset < bytes; offset += char_unit_size, char_unit++) { - mask = 0x80; + uint32_t mask, value = get_stored_value(&data[offset], char_unit_size, big_endian); + + /* Set the control level, if appropriate. */ - for (bit = 0; bit < 8; bit++) + if ((_control_device != NULL) && (_control_pin >= 0) && (dc != NULL)) + _control_device->set(_control_pin, dc[char_unit] ? 1 : 0); + + mask = 1 << (char_size - 1); + + for (uint8_t bit = 0; bit < char_size; bit++) { /* NOTE: Data presented on falling clock level and sampled on rising clock level. This is SPI mode 3, or 0 given that the enable level is driven low immediately before the first bit is presented. */ _clock_device->set(_clock_pin, 0); - _data_device->set(_data_pin, data[byte] & mask ? 1 : 0); - - if ((_control_device != NULL) && (_control_pin >= 0) && (dc != NULL)) - _control_device->set(_control_pin, dc[byte] ? 1 : 0); + _data_device->set(_data_pin, value & mask ? 1 : 0); if (_frequency) nanosleep(&ts, NULL); @@ -122,45 +132,44 @@ return bytes; } -/* Send a number of units, each holding a value in a big endian arrangement - limited to the given character size, with any bit immediately above the - character portion of the unit indicating the data/command level. */ +/* Send a number of units, each holding a value limited to the given character + size, with any bit immediately above the character portion of the unit + indicating the data/command level. */ uint32_t Spi_gpio::send_units(uint32_t bytes, const uint8_t data[], - uint8_t unit_size, uint8_t char_size) + uint8_t unit_size, uint8_t char_size, + bool big_endian) { - /* Obtain the data/command values for each unit. */ + uint32_t char_units = bytes / unit_size; + uint8_t char_unit_size = ((char_size ? char_size - 1 : 0) / 8) + 1; - uint32_t chars = bytes / unit_size; - int dc[chars]; - + /* Obtain the data/command values for each unit. */ /* Obtain the actual character bytes to be sent. */ - int char_unit_size = ((char_size ? char_size - 1 : 0) / 8) + 1; - uint8_t char_data[char_unit_size * chars]; + /* NOTE: Work around stack allocation limitations in L4Re. We would want to + use a static allocation as follows: + + int dc[char_units]; + uint8_t char_data[char_unit_size * char_units]; + */ + + int *dc = (int *) calloc(char_units, sizeof(int)); + uint8_t *char_data = (uint8_t *) calloc(char_units, char_unit_size); /* Traverse the byte sequence, extracting data/command bits for each unit. */ - for (uint32_t offset = 0, unit = 0, char_offset = 0; unit < chars; - offset += unit_size, unit++, char_offset += char_unit_size) + for (uint32_t offset = 0, char_unit = 0, char_offset = 0; char_unit < char_units; + offset += unit_size, char_unit++, char_offset += char_unit_size) { /* Obtain the unit value. */ - uint32_t value = 0; - - for (uint8_t byte = 0; byte < unit_size; byte++) - value = (value << 8) | data[offset + byte]; + uint32_t value = get_stored_value(&data[offset], unit_size, big_endian); /* The unit size must be greater than the character size for data/command bits to be present. */ - if (unit_size * 8 <= char_size) - dc[unit] = 0; - - /* Extract the data/command level. */ - - else - dc[unit] = value & (1 << char_size) ? 1 : 0; + if (unit_size * 8 > char_size) + dc[char_unit] = value & (1 << char_size) ? 1 : 0; /* Obtain the actual character data from the input data, discarding the most significant bytes beyond the character and masking out any remaining @@ -168,14 +177,38 @@ value = value & ((1 << char_size) - 1); - for (uint8_t byte = char_unit_size; byte != 0; byte--) - { - char_data[char_offset + byte - 1] = value & 0xff; - value >>= 8; - } + set_stored_value(value, &char_data[char_offset], char_unit_size, big_endian); } - return send_dc(chars, char_data, dc); + /* Discard the data/command values if they will not be used. */ + + uint32_t result = send_dc(char_units * char_unit_size, char_data, + (unit_size * 8 <= char_size) ? NULL : dc, + char_size, big_endian); + + /* NOTE: Working around allocation limitations with dc... */ + + free(dc); + free(char_data); + return result; +} + +/* Perform a transfer, ignoring any DMA-specific parameters. */ + +uint32_t Spi_gpio::transfer(l4_addr_t vaddr, + 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) +{ + (void) paddr; (void) desc_vaddr; (void) desc_paddr; + + /* Assume little endian data is being transferred, being the native data + representation. */ + + return send_units(count, (const uint8_t *) vaddr, unit_size, char_size, + false); } @@ -201,13 +234,34 @@ } uint32_t spi_gpio_send_dc(void *channel, uint32_t bytes, const uint8_t data[], - const int dc[]) + const int dc[], uint8_t char_size, int big_endian) { - return static_cast(channel)->send_dc(bytes, data, dc); + return static_cast(channel)->send_dc(bytes, data, dc, char_size, + big_endian); } uint32_t spi_gpio_send_units(void *channel, uint32_t bytes, const uint8_t data[], - uint8_t unit_size, uint8_t char_size) + uint8_t unit_size, uint8_t char_size, int big_endian) { - return static_cast(channel)->send_units(bytes, data, unit_size, char_size); + return static_cast(channel)->send_units(bytes, data, unit_size, + char_size, big_endian); } + +uint32_t spi_gpio_transfer(void *channel, l4_addr_t vaddr, + l4re_dma_space_dma_addr_t paddr, + uint32_t count, uint8_t unit_size, + uint8_t char_size) +{ + return static_cast(channel)->transfer(vaddr, paddr, count, + unit_size, char_size); +} + +uint32_t spi_gpio_transfer_descriptor(void *channel, l4_addr_t vaddr, + 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(vaddr, paddr, count, + unit_size, char_size, desc_vaddr, desc_paddr); +} diff -r 438287f28c11 -r 779f8f6a9587 pkg/devices/lib/spi/src/hybrid.cc --- a/pkg/devices/lib/spi/src/hybrid.cc Mon Nov 13 01:20:09 2023 +0100 +++ b/pkg/devices/lib/spi/src/hybrid.cc Tue Nov 14 00:02:42 2023 +0100 @@ -61,19 +61,34 @@ /* Send a byte sequence with control information. */ -uint32_t Spi_hybrid::send_dc(uint32_t bytes, const uint8_t data[], const int dc[]) +uint32_t Spi_hybrid::send_dc(uint32_t bytes, const uint8_t data[], + const int dc[], uint8_t char_size, bool big_endian) { - return _channel->send_dc(bytes, data, dc); + return _channel->send_dc(bytes, data, dc, char_size, big_endian); } /* Send a sequence of units having the given character size. */ uint32_t Spi_hybrid::send_units(uint32_t bytes, const uint8_t data[], - uint8_t unit_size, uint8_t char_size) + uint8_t unit_size, uint8_t char_size, + bool big_endian) { - return _channel->send_units(bytes, data, unit_size, char_size); + return _channel->send_units(bytes, data, unit_size, char_size, big_endian); } - + +/* Transfer a sequence of units using DMA if available. */ + +uint32_t Spi_hybrid::transfer(l4_addr_t vaddr, + 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 _channel->transfer(vaddr, paddr, count, unit_size, char_size, + desc_vaddr, desc_paddr); +} + /* C language interface. */ @@ -107,13 +122,34 @@ } uint32_t spi_hybrid_send_dc(void *channel, uint32_t bytes, const uint8_t data[], - const int dc[]) + const int dc[], uint8_t char_size, int big_endian) { - return static_cast(channel)->send_dc(bytes, data, dc); + return static_cast(channel)->send_dc(bytes, data, dc, char_size, + big_endian); } uint32_t spi_hybrid_send_units(void *channel, uint32_t bytes, const uint8_t data[], - uint8_t unit_size, uint8_t char_size) + uint8_t unit_size, uint8_t char_size, + int big_endian) +{ + return static_cast(channel)->send_units(bytes, data, unit_size, + char_size, big_endian); +} + +uint32_t spi_hybrid_transfer(void *channel, l4_addr_t vaddr, + l4re_dma_space_dma_addr_t paddr, + uint32_t count, uint8_t unit_size, + uint8_t char_size) { - return static_cast(channel)->send_units(bytes, data, unit_size, char_size); + return static_cast(channel)->transfer(vaddr, paddr, count, unit_size, char_size); } + +uint32_t spi_hybrid_transfer_descriptor(void *channel, l4_addr_t vaddr, + 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(vaddr, paddr, count, + unit_size, char_size, desc_vaddr, desc_paddr); +} diff -r 438287f28c11 -r 779f8f6a9587 pkg/devices/lib/spi/src/jz4780.cc --- a/pkg/devices/lib/spi/src/jz4780.cc Mon Nov 13 01:20:09 2023 +0100 +++ b/pkg/devices/lib/spi/src/jz4780.cc Tue Nov 14 00:02:42 2023 +0100 @@ -19,8 +19,9 @@ * Boston, MA 02110-1301, USA */ +#include +#include #include -#include #include #include @@ -288,29 +289,33 @@ uint32_t Spi_jz4780_channel::send(uint32_t bytes, const uint8_t data[]) { - return send_units(bytes, data, 1, 8); + return send_units(bytes, data, 1, 8, false); } /* Transfer the given number of bytes from a buffer together with control values. */ uint32_t Spi_jz4780_channel::send_dc(uint32_t bytes, const uint8_t data[], - const int dc[]) + const int dc[], uint8_t char_size, bool big_endian) { - configure_transfer(8); + configure_transfer(char_size); - uint32_t transferred; + uint32_t transferred, char_unit; + uint8_t char_unit_size = ((char_size ? char_size - 1 : 0) / 8) + 1; + uint32_t char_mask = (1 << char_size) - 1; - for (transferred = 0; transferred < bytes; transferred++) + for (transferred = 0, char_unit = 0; transferred < bytes; + transferred += char_unit_size, char_unit++) { + uint32_t value = get_stored_value(&data[transferred], char_unit_size, big_endian); + /* Relocate the data/command level to bit 16. */ - uint32_t command = dc[transferred] ? Ssi_data_gpc_set : Ssi_data_gpc_unset; - uint32_t value = data[transferred]; + uint32_t command = dc[char_unit] ? Ssi_data_gpc_set : Ssi_data_gpc_unset; /* Combine the character with the data/command bit. */ - _regs[Ssi_data] = value | command; + _regs[Ssi_data] = (value & char_mask) | command; } wait_busy(); @@ -324,7 +329,8 @@ uint32_t Spi_jz4780_channel::send_units(uint32_t bytes, const uint8_t data[], - uint8_t unit_size, uint8_t char_size) + uint8_t unit_size, uint8_t char_size, + bool big_endian) { configure_transfer(char_size); @@ -333,10 +339,7 @@ for (transferred = 0; transferred < bytes; transferred += unit_size) { - uint32_t value = 0; - - for (uint8_t byte = 0; byte < unit_size; byte++) - value = (value << 8) | data[transferred + byte]; + uint32_t value = get_stored_value(&data[transferred], unit_size, big_endian); /* Relocate any command bit to bit 16 for byte characters. */ @@ -345,8 +348,7 @@ /* Combine the character portion of the unit with the command. */ - value = (value & char_mask) | command; - _regs[Ssi_data] = value; + _regs[Ssi_data] = (value & char_mask) | command; } wait_busy(); @@ -358,12 +360,23 @@ unit size in bytes and character size in bits. */ uint32_t -Spi_jz4780_channel::transfer(l4re_dma_space_dma_addr_t paddr, +Spi_jz4780_channel::transfer(l4_addr_t vaddr, + 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) { + /* Employ a non-DMA transfer if no usable physical address is provided. + Assume little endian byte ordering in line with the native value + representation. */ + + if (!paddr) + return send_units(count, (const uint8_t *) vaddr, unit_size, char_size, + false); + + /* Configure and initiate a DMA transfer with optional descriptor. */ + configure_transfer(char_size); uint32_t transferred = 0; @@ -444,31 +457,34 @@ } uint32_t jz4780_spi_send_dc(void *channel, uint32_t bytes, const uint8_t data[], - const int dc[]) + const int dc[], uint8_t char_size, int big_endian) { - return static_cast(channel)->send_dc(bytes, data, dc); + return static_cast(channel)->send_dc(bytes, data, dc, + char_size, big_endian); } uint32_t jz4780_spi_send_units(void *channel, uint32_t bytes, const uint8_t data[], - uint8_t unit_size, uint8_t char_size) + uint8_t unit_size, uint8_t char_size, int big_endian) { return static_cast(channel)->send_units(bytes, data, - unit_size, char_size); + unit_size, char_size, big_endian); } -uint32_t jz4780_spi_transfer(void *channel, l4re_dma_space_dma_addr_t paddr, +uint32_t jz4780_spi_transfer(void *channel, l4_addr_t vaddr, + l4re_dma_space_dma_addr_t paddr, uint32_t count, uint8_t unit_size, uint8_t char_size) { - return static_cast(channel)->transfer(paddr, count, - unit_size, char_size); + return static_cast(channel)->transfer(vaddr, paddr, + count, unit_size, char_size); } -uint32_t jz4780_spi_transfer_descriptor(void *channel, l4re_dma_space_dma_addr_t paddr, +uint32_t jz4780_spi_transfer_descriptor(void *channel, l4_addr_t vaddr, + 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); + return static_cast(channel)->transfer(vaddr, paddr, + count, unit_size, char_size, desc_vaddr, desc_paddr); } diff -r 438287f28c11 -r 779f8f6a9587 pkg/devices/util/include/byteorder.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/util/include/byteorder.h Tue Nov 14 00:02:42 2023 +0100 @@ -0,0 +1,33 @@ +/* + * Byte ordering utilities. + * + * Copyright (C) 2023 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include + +EXTERN_C_BEGIN + +uint32_t get_stored_value(const uint8_t data[], uint8_t bytes, bool big_endian); + +void set_stored_value(uint32_t value, uint8_t data[], uint8_t bytes, bool big_endian); + +EXTERN_C_END diff -r 438287f28c11 -r 779f8f6a9587 pkg/devices/util/src/Makefile --- a/pkg/devices/util/src/Makefile Mon Nov 13 01:20:09 2023 +0100 +++ b/pkg/devices/util/src/Makefile Tue Nov 14 00:02:42 2023 +0100 @@ -4,7 +4,7 @@ TARGET = libdevice_util.o.a libdevice_util.o.so PC_FILENAME := libdevice-util -SRC_CC := dataspace.cc dl.cc dma.cc event-loop.cc memory.cc +SRC_CC := byteorder.cc dataspace.cc dl.cc dma.cc event-loop.cc memory.cc PRIVATE_INCDIR += $(PKGDIR)/util/include diff -r 438287f28c11 -r 779f8f6a9587 pkg/devices/util/src/byteorder.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/util/src/byteorder.cc Tue Nov 14 00:02:42 2023 +0100 @@ -0,0 +1,62 @@ +/* + * Byte ordering utilities. + * + * Copyright (C) 2023 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include "byteorder.h" + + + +uint32_t get_stored_value(const uint8_t data[], uint8_t bytes, bool big_endian) +{ + uint32_t value = 0; + + if (big_endian) + { + for (uint8_t byte = 0; byte < bytes; byte++) + value = (value << 8) | data[byte]; + } + else + { + for (uint8_t byte = bytes; byte; byte--) + value = (value << 8) | data[byte - 1]; + } + + return value; +} + +void set_stored_value(uint32_t value, uint8_t data[], uint8_t bytes, bool big_endian) +{ + if (big_endian) + { + for (uint8_t byte = bytes; byte; byte--) + { + data[byte - 1] = value & 0xff; + value >>= 8; + } + } + else + { + for (uint8_t byte = 0; byte < bytes; byte++) + { + data[byte] = value & 0xff; + value >>= 8; + } + } +} diff -r 438287f28c11 -r 779f8f6a9587 pkg/landfall-examples/hw_info/common.h --- a/pkg/landfall-examples/hw_info/common.h Mon Nov 13 01:20:09 2023 +0100 +++ b/pkg/landfall-examples/hw_info/common.h Tue Nov 14 00:02:42 2023 +0100 @@ -185,10 +185,11 @@ void spi_send(void *channel, uint32_t bytes, const uint8_t data[]); void spi_send_units(void *channel, uint32_t bytes, const uint8_t data[], - uint8_t unit_size, uint8_t char_size); + uint8_t unit_size, uint8_t char_size, int big_endian); -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 spi_transfer(void *channel, l4_addr_t vaddr, + 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); @@ -232,3 +233,13 @@ { const uint32_t pull_ups, pull_downs; }; + + + +/* Memory definitions. */ + +struct memory_region +{ + unsigned int size; + l4_addr_t addr; +}; diff -r 438287f28c11 -r 779f8f6a9587 pkg/landfall-examples/hw_info/defs.h --- a/pkg/landfall-examples/hw_info/defs.h Mon Nov 13 01:20:09 2023 +0100 +++ b/pkg/landfall-examples/hw_info/defs.h Tue Nov 14 00:02:42 2023 +0100 @@ -27,7 +27,7 @@ /* Memory regions. */ -extern const char *memory_regions[]; +extern const char *io_memory_regions[]; diff -r 438287f28c11 -r 779f8f6a9587 pkg/landfall-examples/hw_info/hw_info.c --- a/pkg/landfall-examples/hw_info/hw_info.c Mon Nov 13 01:20:09 2023 +0100 +++ b/pkg/landfall-examples/hw_info/hw_info.c Tue Nov 14 00:02:42 2023 +0100 @@ -48,6 +48,14 @@ static l4_cap_idx_t icucap; +/* Memory definitions. */ + +static const unsigned int num_memory_regions = 8; + +static struct memory_region memory_regions[] = { + {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + }; + /* Device and resource discovery. */ @@ -118,14 +126,14 @@ return token; } -static int read_increment(const char *message, int *increment) +static int read_flag(const char *message, int *value, const char *flag, size_t n) { char *token = read_token(message); if (token == NULL) return 0; - *increment = !strncmp(token, "i", 1); + *value = !strncmp(token, flag, n); return 1; } @@ -228,6 +236,23 @@ return &dma_regions[num]; } +static struct memory_region *_get_memory_region(void) +{ + int num = get_region_number(num_memory_regions); + + if (num < 0) + return NULL; + + return &memory_regions[num]; +} + +static int get_memory_region(unsigned int size, l4_addr_t *addr) +{ + *addr = (l4_addr_t) calloc(size, sizeof(char)); + + return !(*addr); +} + /* AIC/I2S operations. */ @@ -600,10 +625,10 @@ if (!read_number("Transfer size", &count)) return; - if (!read_increment("Source increment", &source_increment)) + if (!read_flag("Source increment", &source_increment, "i", 1)) return; - if (!read_increment("Destination increment", &destination_increment)) + if (!read_flag("Destination increment", &destination_increment, "i", 1)) return; if (!read_number("Source width", &source_width)) @@ -995,6 +1020,99 @@ +/* Memory operations. */ + +static void list_memory_regions(void) +{ + unsigned int num; + struct memory_region *region; + unsigned int i; + + for (num = 0; num < num_memory_regions; num++) + { + printf("Region %d: ", num); + + region = &memory_regions[num]; + + if (!region->addr) + printf("(inactive)\n"); + else + { + printf("size = %d; virtual = 0x%lx; data =", + region->size, region->addr); + + for (i = 0; (i < region->size) && (i < 16); i++) + printf(" %02x", *((uint8_t *) region->addr + i)); + + printf("\n"); + } + } +} + +static void new_memory_region(void) +{ + struct memory_region *region = _get_memory_region(); + + if (region == NULL) + { + list_memory_regions(); + return; + } + + if (region->addr) + { + printf("Region already defined.\n"); + return; + } + + if (!read_number("Size", ®ion->size)) + return; + + if (get_memory_region(region->size, ®ion->addr)) + printf("Could not allocate region.\n"); +} + +static void set_memory_region(void) +{ + char *token; + struct memory_region *region = _get_memory_region(); + FILE *fp; + + if (region == NULL) + { + list_memory_regions(); + return; + } + + if (!region->addr) + { + printf("Region needs creating.\n"); + return; + } + + memset((void *) region->addr, 0, region->size); + + if ((token = read_token("Filename")) == NULL) + return; + + /* Populate the region from the file. */ + + fp = fopen(token, "r"); + + if (fp == NULL) + { + printf("File not readable.\n"); + return; + } + + fread((char *) region->addr, sizeof(char), region->size, fp); + fclose(fp); + + l4_cache_flush_data(region->addr, region->addr + region->size); +} + + + /* SPI operations. */ static void new_spi_channel(void *spi, void *gpio[]) @@ -1121,22 +1239,32 @@ while ((byte < 256) && read_encoded_number(NULL, "%2x", &value)) buffer[byte++] = value; - spi_send_units(channel, byte, (uint8_t *) buffer, unit_size, char_size); + /* Explicitly indicate big endian data. */ + + spi_send_units(channel, byte, (uint8_t *) buffer, unit_size, char_size, 1); } static void spi_transfer_data(void) { void *channel = get_channel(num_spi_channels, spi_channels, NULL); - struct dma_region *region, *desc_region; + struct dma_region *dma_region = NULL, *desc_region; + struct memory_region *memory_region = NULL; unsigned int char_size, unit_size; uint32_t count, transferred; + int using_dma; if (channel == NULL) return; - region = _get_dma_region(); + if (!read_flag("Using DMA", &using_dma, "d", 1)) + return; - if (region == NULL) + if (using_dma) + dma_region = _get_dma_region(); + else + memory_region = _get_memory_region(); + + if ((dma_region == NULL) && (memory_region == NULL)) return; if (!read_number("Transfer size", &count)) @@ -1148,11 +1276,18 @@ if (!read_number("Character size", &char_size)) return; - desc_region = _get_dma_region(); + if (using_dma) + { + 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); + transferred = spi_transfer(channel, dma_region->vaddr, dma_region->paddr, count, + unit_size, char_size, + desc_region != NULL ? desc_region->vaddr : 0, + desc_region != NULL ? desc_region->paddr : 0); + } + else + transferred = spi_transfer(channel, memory_region->addr, 0, count, + unit_size, char_size, 0, 0); printf("Transferred: %d\n", transferred); } @@ -1174,7 +1309,7 @@ else if (!strcmp(token, "t") || !strcmp(token, "transfer")) aic_transfer_data(); else - printf("aic channel | list | set | transfer\n"); + printf("aic channel | list | transfer\n"); } else list_channels(num_aic_channels, aic_channels); @@ -1270,6 +1405,23 @@ list_i2c_channels(); } +static void handle_memory(void) +{ + char *token; + + if ((token = read_token(NULL)) != NULL) + { + if (!strcmp(token, "r") || !strcmp(token, "region")) + new_memory_region(); + else if (!strcmp(token, "s") || !strcmp(token, "set")) + set_memory_region(); + else + printf("memory region | set\n"); + } + else + list_memory_regions(); +} + static void handle_spi(void *spi, void *gpio[]) { char *token; @@ -1321,7 +1473,7 @@ printf("Access CPM...\n"); - if ((result = get_memory(memory_regions[CPM], &cpm_base, &cpm_base_end)) < 0) + if ((result = get_memory(io_memory_regions[CPM], &cpm_base, &cpm_base_end)) < 0) return 1; printf("CPM at 0x%lx...0x%lx.\n", cpm_base, cpm_base_end); @@ -1330,14 +1482,14 @@ printf("Access DMA...\n"); - if ((result = get_memory(memory_regions[DMA], &dma_base, &dma_base_end)) < 0) + if ((result = get_memory(io_memory_regions[DMA], &dma_base, &dma_base_end)) < 0) return 1; printf("DMA at 0x%lx...0x%lx.\n", dma_base, dma_base_end); dma = dma_init(dma_base, dma_base_end, cpm); - if (get_irq(memory_regions[DMA], &dma_irq_start, &dma_irq_end) < 0) + if (get_irq(io_memory_regions[DMA], &dma_irq_start, &dma_irq_end) < 0) return 1; printf("IRQ range at %d...%d.\n", dma_irq_start, dma_irq_end); @@ -1349,7 +1501,7 @@ printf("Access GPIO...\n"); - if ((result = get_memory(memory_regions[GPIO], &gpio_base, &gpio_base_end)) < 0) + if ((result = get_memory(io_memory_regions[GPIO], &gpio_base, &gpio_base_end)) < 0) return 1; printf("GPIO at 0x%lx...0x%lx.\n", gpio_base, gpio_base_end); @@ -1360,21 +1512,21 @@ printf("Access I2C...\n"); - if ((result = get_memory(memory_regions[I2C], &i2c_base, &i2c_base_end)) < 0) + if ((result = get_memory(io_memory_regions[I2C], &i2c_base, &i2c_base_end)) < 0) return 1; printf("I2C at 0x%lx...0x%lx.\n", i2c_base, i2c_base_end); i2c = i2c_init(i2c_base, i2c_base_end, cpm, 100000); - if (get_irq(memory_regions[I2C], &i2c_irq_start, &i2c_irq_end) < 0) + if (get_irq(io_memory_regions[I2C], &i2c_irq_start, &i2c_irq_end) < 0) return 1; printf("IRQ range at %d...%d.\n", i2c_irq_start, i2c_irq_end); printf("Access AIC...\n"); - if ((result = get_memory_complete(memory_regions[AIC], &aic_base, &aic_base_end, + if ((result = get_memory_complete(io_memory_regions[AIC], &aic_base, &aic_base_end, &aic_phys_base, &aic_phys_base_end)) < 0) return 1; @@ -1384,7 +1536,7 @@ printf("Access SSI...\n"); - if ((result = get_memory_complete(memory_regions[SSI], &ssi_base, &ssi_base_end, + if ((result = get_memory_complete(io_memory_regions[SSI], &ssi_base, &ssi_base_end, &ssi_phys_base, &ssi_phys_base_end)) < 0) return 1; @@ -1435,6 +1587,11 @@ else if (!strcmp(token, "i") || !strcmp(token, "i2c")) handle_i2c(i2c); + /* Generic memory commands. */ + + else if (!strcmp(token, "m") || !strcmp(token, "mem") || !strcmp(token, "memory")) + handle_memory(); + /* SPI commands. */ else if (!strcmp(token, "s") || !strcmp(token, "spi")) diff -r 438287f28c11 -r 779f8f6a9587 pkg/landfall-examples/hw_info/jz4780.c --- a/pkg/landfall-examples/hw_info/jz4780.c Mon Nov 13 01:20:09 2023 +0100 +++ b/pkg/landfall-examples/hw_info/jz4780.c Tue Nov 14 00:02:42 2023 +0100 @@ -375,28 +375,25 @@ } void spi_send_units(void *channel, uint32_t bytes, const uint8_t data[], - uint8_t unit_size, uint8_t char_size) + uint8_t unit_size, uint8_t char_size, int big_endian) { - spi_hybrid_send_units(channel, bytes, data, unit_size, char_size); + spi_hybrid_send_units(channel, bytes, data, unit_size, char_size, big_endian); } -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 spi_transfer(void *channel, l4_addr_t vaddr, + 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) { - /* Transfer is not supported by the common interface. */ - - void *ch = spi_hybrid_get_raw_channel(channel); - - return jz4780_spi_transfer_descriptor(ch, paddr, count, unit_size, char_size, - desc_vaddr, desc_paddr); + return spi_hybrid_transfer_descriptor(channel, vaddr, paddr, count, unit_size, + char_size, desc_vaddr, desc_paddr); } /* Memory regions. */ -const char *memory_regions[] = { +const char *io_memory_regions[] = { [AIC] = "jz4780-aic", [CPM] = "jz4780-cpm", [DMA] = "jz4780-dma", diff -r 438287f28c11 -r 779f8f6a9587 pkg/landfall-examples/hw_info/x1600.c --- a/pkg/landfall-examples/hw_info/x1600.c Mon Nov 13 01:20:09 2023 +0100 +++ b/pkg/landfall-examples/hw_info/x1600.c Tue Nov 14 00:02:42 2023 +0100 @@ -367,28 +367,25 @@ } void spi_send_units(void *channel, uint32_t bytes, const uint8_t data[], uint8_t unit_size, - uint8_t char_size) + uint8_t char_size, int big_endian) { - spi_hybrid_send_units(channel, bytes, data, unit_size, char_size); + spi_hybrid_send_units(channel, bytes, data, unit_size, char_size, big_endian); } -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 spi_transfer(void *channel, l4_addr_t vaddr, + 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) { - /* Transfer is not supported by the common interface. */ - - void *ch = spi_hybrid_get_raw_channel(channel); - - return jz4780_spi_transfer_descriptor(ch, paddr, count, unit_size, char_size, - desc_vaddr, desc_paddr); + return spi_hybrid_transfer_descriptor(channel, vaddr, paddr, count, unit_size, + char_size, desc_vaddr, desc_paddr); } /* Memory regions. */ -const char *memory_regions[] = { +const char *io_memory_regions[] = { [AIC] = "x1600-aic", [CPM] = "x1600-cpm", [DMA] = "x1600-dma",