# HG changeset patch # User Paul Boddie # Date 1699551631 -3600 # Node ID 3f9892859cee6792cd2e52690ba60ca5de18b656 # Parent 89d597f10dc6399695e27b3e4053bba0e32d7567 Added a "hybrid" SPI driver to allow control signals to be manipulated independently of the normal communication channel. diff -r 89d597f10dc6 -r 3f9892859cee pkg/devices/lib/spi/include/spi-gpio.h --- a/pkg/devices/lib/spi/include/spi-gpio.h Tue Nov 07 19:20:32 2023 +0100 +++ b/pkg/devices/lib/spi/include/spi-gpio.h Thu Nov 09 18:40:31 2023 +0100 @@ -21,32 +21,47 @@ #pragma once -#include #include #ifdef __cplusplus -/* SPI peripheral device. */ +#include +#include -class Spi_gpio +/* SPI channel abstraction. */ + +class Spi_gpio : public Spi_channel_base { + uint64_t _frequency; Hw::Gpio_chip *_clock_device; int _clock_pin; Hw::Gpio_chip *_data_device; int _data_pin; Hw::Gpio_chip *_enable_device; int _enable_pin; - uint64_t _frequency; + Hw::Gpio_chip *_control_device; + int _control_pin; public: + explicit Spi_gpio(uint64_t frequency, + Hw::Gpio_chip *clock_device, int clock_pin, + Hw::Gpio_chip *data_device, int data_pin, + Hw::Gpio_chip *enable_device, int enable_pin, + Hw::Gpio_chip *control_device = NULL, int control_pin = 0); + explicit Spi_gpio(Hw::Gpio_chip *clock_device, int clock_pin, Hw::Gpio_chip *data_device, int data_pin, Hw::Gpio_chip *enable_device, int enable_pin, - uint64_t frequency = 0); + Hw::Gpio_chip *control_device = NULL, int control_pin = 0); + + uint32_t send(uint32_t bytes, const uint8_t data[]); - void send(int bytes, const uint8_t data[]); + uint32_t send_dc(uint32_t bytes, const uint8_t data[], const int dc[]); + + uint32_t send_units(uint32_t bytes, const uint8_t data[], uint8_t unit_size, + uint8_t char_size); }; #endif /* __cplusplus */ @@ -57,11 +72,18 @@ EXTERN_C_BEGIN -void *spi_gpio_get_channel(void *clock_chip, int clock_pin, +void *spi_gpio_get_channel(uint64_t frequency, + void *clock_chip, int clock_pin, void *data_chip, int data_pin, void *enable_chip, int enable_pin, - uint64_t frequency); + void *control_chip, int control_pin); + +uint32_t spi_gpio_send(void *channel, uint32_t bytes, const uint8_t data[]); -void spi_gpio_send(void *channel, int bytes, const uint8_t data[]); +uint32_t spi_gpio_send_dc(void *channel, uint32_t bytes, const uint8_t data[], + const int dc[]); + +uint32_t spi_gpio_send_units(void *channel, uint32_t bytes, const uint8_t data[], + uint8_t unit_size, uint8_t char_size); EXTERN_C_END diff -r 89d597f10dc6 -r 3f9892859cee pkg/devices/lib/spi/include/spi-hybrid.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/spi/include/spi-hybrid.h Thu Nov 09 18:40:31 2023 +0100 @@ -0,0 +1,87 @@ +/* + * Perform SPI communication using a suitable abstraction augmented with + * explicit manipulation of a control signal. + * + * 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 + + + +#ifdef __cplusplus + +#include +#include + +/* SPI channel abstraction. */ + +class Spi_hybrid : public Spi_channel_base, public Spi_control_base +{ + Spi_channel_base *_channel; + Hw::Gpio_chip *_control_device; + int _control_pin; + int _control_alt_func; + +public: + explicit Spi_hybrid(Spi_channel_base *channel, + Hw::Gpio_chip *control_device, int control_pin, + int control_alt_func = -1); + + Spi_channel_base *get_channel(); + + void acquire_control(bool asserted); + + void release_control(); + + 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_units(uint32_t bytes, const uint8_t data[], + uint8_t unit_size, uint8_t char_size); +}; + +#endif /* __cplusplus */ + + + +/* C language interface. */ + +EXTERN_C_BEGIN + +void *spi_hybrid_get_channel(void *channel, void *control_chip, int control_pin, + int control_alt_func); + +void *spi_hybrid_get_raw_channel(void *channel); + +void spi_hybrid_acquire_control(void *channel, int asserted); + +void spi_hybrid_release_control(void *channel); + +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[]); + +uint32_t spi_hybrid_send_units(void *channel, uint32_t bytes, const uint8_t data[], + uint8_t unit_size, uint8_t char_size); + +EXTERN_C_END diff -r 89d597f10dc6 -r 3f9892859cee pkg/devices/lib/spi/include/spi-jz4780.h --- a/pkg/devices/lib/spi/include/spi-jz4780.h Tue Nov 07 19:20:32 2023 +0100 +++ b/pkg/devices/lib/spi/include/spi-jz4780.h Thu Nov 09 18:40:31 2023 +0100 @@ -32,10 +32,11 @@ #include #include #include +#include /* SPI peripheral channel. */ -class Spi_jz4780_channel +class Spi_jz4780_channel : public Spi_channel_base { Hw::Register_block<32> _regs; @@ -48,8 +49,12 @@ enum Dma_jz4780_request_type _request_type; uint64_t _frequency; + /* Common utilities. */ + void configure_transfer(uint8_t char_size); + void wait_busy(); + public: explicit Spi_jz4780_channel(l4_addr_t spi_start, l4_addr_t start, enum Clock_identifiers clock, @@ -58,15 +63,19 @@ enum Dma_jz4780_request_type request_type, uint64_t frequency); + /* Convenience operations. */ + + 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[]); + + uint32_t send_units(uint32_t bytes, const uint8_t data[], uint8_t unit_size, + uint8_t char_size); + /* DMA operations. */ uint32_t transfer(l4re_dma_space_dma_addr_t paddr, uint32_t count, uint8_t unit_size, uint8_t char_size); - - /* Convenience operations. */ - - uint32_t send(uint32_t bytes, const uint8_t data[], uint8_t unit_size, - uint8_t char_size); }; /* SPI peripheral. */ @@ -96,8 +105,13 @@ void *jz4780_spi_get_channel(void *spi, uint8_t channel, void *dma, uint64_t frequency); -uint32_t jz4780_spi_send(void *channel, uint32_t bytes, const uint8_t data[], - uint8_t unit_size, uint8_t char_size); +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[]); + +uint32_t jz4780_spi_send_units(void *channel, uint32_t bytes, const uint8_t data[], + uint8_t unit_size, uint8_t char_size); 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); diff -r 89d597f10dc6 -r 3f9892859cee pkg/devices/lib/spi/include/spi.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/spi/include/spi.h Thu Nov 09 18:40:31 2023 +0100 @@ -0,0 +1,50 @@ +/* + * Common SPI abstractions. + * + * 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 + +#ifdef __cplusplus + +#include + +/* SPI channel abstractions. */ + +class Spi_channel_base +{ +public: + 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; + + virtual uint32_t send_units(uint32_t bytes, const uint8_t data[], + uint8_t unit_size, uint8_t char_size) = 0; +}; + +class Spi_control_base +{ +public: + virtual void acquire_control(bool asserted) = 0; + + virtual void release_control() = 0; +}; + +#endif /* __cplusplus */ diff -r 89d597f10dc6 -r 3f9892859cee pkg/devices/lib/spi/src/Makefile --- a/pkg/devices/lib/spi/src/Makefile Tue Nov 07 19:20:32 2023 +0100 +++ b/pkg/devices/lib/spi/src/Makefile Thu Nov 09 18:40:31 2023 +0100 @@ -4,7 +4,7 @@ TARGET = libspi.o.a libspi.o.so PC_FILENAME := libdrivers-spi -SRC_CC := gpio.cc jz4780.cc +SRC_CC := gpio.cc hybrid.cc jz4780.cc PRIVATE_INCDIR += $(PKGDIR)/lib/spi/include diff -r 89d597f10dc6 -r 3f9892859cee pkg/devices/lib/spi/src/gpio.cc --- a/pkg/devices/lib/spi/src/gpio.cc Tue Nov 07 19:20:32 2023 +0100 +++ b/pkg/devices/lib/spi/src/gpio.cc Thu Nov 09 18:40:31 2023 +0100 @@ -27,27 +27,48 @@ Spi_gpio::Spi_gpio(Hw::Gpio_chip *clock_device, int clock_pin, Hw::Gpio_chip *data_device, int data_pin, Hw::Gpio_chip *enable_device, int enable_pin, - uint64_t frequency) + Hw::Gpio_chip *control_device, int control_pin) : _clock_device(clock_device), _clock_pin(clock_pin), _data_device(data_device), _data_pin(data_pin), _enable_device(enable_device), _enable_pin(enable_pin), - _frequency(frequency) + _control_device(control_device), + _control_pin(control_pin) { _clock_device->setup(_clock_pin, Hw::Gpio_chip::Output, 1); _data_device->setup(_data_pin, Hw::Gpio_chip::Output, 0); _enable_device->setup(_enable_pin, Hw::Gpio_chip::Output, 1); } +Spi_gpio::Spi_gpio(uint64_t frequency, + Hw::Gpio_chip *clock_device, int clock_pin, + Hw::Gpio_chip *data_device, int data_pin, + Hw::Gpio_chip *enable_device, int enable_pin, + Hw::Gpio_chip *control_device, int control_pin) +: Spi_gpio(clock_device, clock_pin, data_device, data_pin, enable_device, + enable_pin, control_device, control_pin) +{ + _frequency = frequency; +} + /* Send a byte sequence. */ -void Spi_gpio::send(int bytes, const uint8_t data[]) +uint32_t Spi_gpio::send(uint32_t bytes, const uint8_t data[]) +{ + return send_dc(bytes, data, NULL); +} + +/* Send a byte sequence with accompanying data/command indicators. */ + +uint32_t Spi_gpio::send_dc(uint32_t bytes, const uint8_t data[], + const int dc[]) { struct timespec ts; uint8_t mask; - int bit, byte; + int bit; + uint32_t byte; if (_frequency) { @@ -80,6 +101,9 @@ _clock_device->set(_clock_pin, 0); _data_device->set(_data_pin, data[byte] & mask ? 1 : 0); + if ((_control_device != NULL) && (dc != NULL)) + _control_device->set(_control_pin, dc[byte] ? 1 : 0); + if (_frequency) nanosleep(&ts, NULL); @@ -93,24 +117,77 @@ } _enable_device->set(_enable_pin, 1); + + 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. */ + +uint32_t Spi_gpio::send_units(uint32_t bytes, const uint8_t data[], + uint8_t unit_size, uint8_t char_size) +{ + uint32_t count = bytes / unit_size; + int dc[count]; + + /* Traverse the byte sequence, extracting data/command bits for each unit. */ + + for (uint32_t offset = 0, unit = 0; offset < bytes; offset += unit_size, unit++) + { + /* 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; + else + { + /* Obtain the unit value. */ + + uint32_t value = 0; + + for (uint8_t byte = 0; byte < unit_size; byte++) + value = (value << 8) | data[offset + byte]; + + /* Extract the data/command level. */ + + dc[unit] = value & (1 << char_size) ? 1 : 0; + } + } + + return send_dc(bytes, data, dc); } /* C language interface. */ -void *spi_gpio_get_channel(void *clock_chip, int clock_pin, +void *spi_gpio_get_channel(uint64_t frequency, + void *clock_chip, int clock_pin, void *data_chip, int data_pin, void *enable_chip, int enable_pin, - uint64_t frequency) + void *control_chip, int control_pin) { - return (void *) new Spi_gpio(reinterpret_cast(clock_chip), clock_pin, + return (void *) new Spi_gpio(frequency, + reinterpret_cast(clock_chip), clock_pin, reinterpret_cast(data_chip), data_pin, reinterpret_cast(enable_chip), enable_pin, - frequency); + reinterpret_cast(control_chip), control_pin); +} + +uint32_t spi_gpio_send(void *channel, uint32_t bytes, const uint8_t data[]) +{ + return static_cast(channel)->send(bytes, data); } -void spi_gpio_send(void *channel, int bytes, const uint8_t data[]) +uint32_t spi_gpio_send_dc(void *channel, uint32_t bytes, const uint8_t data[], + const int dc[]) { - static_cast(channel)->send(bytes, data); + return static_cast(channel)->send_dc(bytes, data, dc); } + +uint32_t spi_gpio_send_units(void *channel, uint32_t bytes, const uint8_t data[], + uint8_t unit_size, uint8_t char_size) +{ + return static_cast(channel)->send_units(bytes, data, unit_size, char_size); +} diff -r 89d597f10dc6 -r 3f9892859cee pkg/devices/lib/spi/src/hybrid.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/spi/src/hybrid.cc Thu Nov 09 18:40:31 2023 +0100 @@ -0,0 +1,119 @@ +/* + * Perform SPI communication using a suitable abstraction augmented with + * explicit manipulation of a control signal. + * + * 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 + + + +Spi_hybrid::Spi_hybrid(Spi_channel_base *channel, + Hw::Gpio_chip *control_device, int control_pin, + int control_alt_func) +: _channel(channel), + _control_device(control_device), + _control_pin(control_pin), + _control_alt_func(control_alt_func) +{ +} + +Spi_channel_base *Spi_hybrid::get_channel() +{ + return _channel; +} + +void Spi_hybrid::acquire_control(bool asserted) +{ + _control_device->setup(_control_pin, Hw::Gpio_chip::Output, asserted ? 1 : 0); +} + +void Spi_hybrid::release_control() +{ + if (_control_alt_func >= 0) + _control_device->config_pad(_control_pin, Hw::Gpio_chip::Function_alt, _control_alt_func); + else + _control_device->setup(_control_pin, Hw::Gpio_chip::Input, 0); +} + +/* Send a byte sequence. */ + +uint32_t Spi_hybrid::send(uint32_t bytes, const uint8_t data[]) +{ + return _channel->send(bytes, data); +} + +/* Send a byte sequence with control information. */ + +uint32_t Spi_hybrid::send_dc(uint32_t bytes, const uint8_t data[], const int dc[]) +{ + return _channel->send_dc(bytes, data, dc); +} + +/* 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) +{ + return _channel->send_units(bytes, data, unit_size, char_size); +} + + + +/* C language interface. */ + +void *spi_hybrid_get_channel(void *channel, void *control_chip, int control_pin, + int control_alt_func) +{ + return (void *) new Spi_hybrid(reinterpret_cast(channel), + reinterpret_cast(control_chip), + control_pin, control_alt_func); +} + +void *spi_hybrid_get_raw_channel(void *channel) +{ + return static_cast(channel)->get_channel(); +} + +void spi_hybrid_acquire_control(void *channel, int level) +{ + static_cast(channel)->acquire_control(level); +} + +void spi_hybrid_release_control(void *channel) +{ + static_cast(channel)->release_control(); +} + +uint32_t spi_hybrid_send(void *channel, uint32_t bytes, const uint8_t data[]) +{ + return static_cast(channel)->send(bytes, data); +} + +uint32_t spi_hybrid_send_dc(void *channel, uint32_t bytes, const uint8_t data[], + const int dc[]) +{ + return static_cast(channel)->send_dc(bytes, data, dc); +} + +uint32_t spi_hybrid_send_units(void *channel, uint32_t bytes, const uint8_t data[], + uint8_t unit_size, uint8_t char_size) +{ + return static_cast(channel)->send_units(bytes, data, unit_size, char_size); +} diff -r 89d597f10dc6 -r 3f9892859cee pkg/devices/lib/spi/src/jz4780.cc --- a/pkg/devices/lib/spi/src/jz4780.cc Tue Nov 07 19:20:32 2023 +0100 +++ b/pkg/devices/lib/spi/src/jz4780.cc Thu Nov 09 18:40:31 2023 +0100 @@ -269,12 +269,48 @@ Spi_clock_assert_drive | Spi_clock_idle_high_level; } -/* Transfer the given number of bytes from a buffer using the given unit size in - bytes and character size in bits. */ +/* Transfer the given number of bytes from a buffer. */ + +uint32_t +Spi_jz4780_channel::send(uint32_t bytes, const uint8_t data[]) +{ + return send_units(bytes, data, 1, 8); +} + +/* Transfer the given number of bytes from a buffer together with control values. */ uint32_t -Spi_jz4780_channel::send(uint32_t bytes, const uint8_t data[], uint8_t unit_size, - uint8_t char_size) +Spi_jz4780_channel::send_dc(uint32_t bytes, const uint8_t data[], + const int dc[]) +{ + configure_transfer(8); + + uint32_t transferred; + + for (transferred = 0; transferred < bytes; transferred++) + { + /* Relocate the data/command level to bit 16. */ + + uint32_t command = dc[transferred] ? (1 << 16) : 0; + uint32_t value = data[transferred]; + + /* Combine the character with the data/command bit. */ + + _regs[Ssi_data] = value | command; + } + + wait_busy(); + + return transferred; +} + +/* Transfer the given number of bytes from a buffer using the given unit size in + bytes and character size in bits. The bytes are stored in a big endian + arrangement. */ + +uint32_t +Spi_jz4780_channel::send_units(uint32_t bytes, const uint8_t data[], + uint8_t unit_size, uint8_t char_size) { configure_transfer(char_size); @@ -292,15 +328,13 @@ uint32_t command = (char_size < 16) && (value & (1 << char_size)) ? (1 << 16) : 0; - /* Combine the significant portion of the character with the command. */ + /* Combine the character portion of the unit with the command. */ value = (value & char_mask) | command; _regs[Ssi_data] = value; } - /* Wait for the busy condition to clear or for a limited period. */ - - for (unsigned int i = 0; i < (1 << 20) && (_regs[Ssi_status] & Ssi_trans_busy); i++); + wait_busy(); return transferred; } @@ -308,9 +342,10 @@ /* Transfer the given number of bytes from a DMA region using the given unit size in bytes and character size in bits. */ -uint32_t Spi_jz4780_channel::transfer(l4re_dma_space_dma_addr_t paddr, - uint32_t count, uint8_t unit_size, - uint8_t char_size) +uint32_t +Spi_jz4780_channel::transfer(l4re_dma_space_dma_addr_t paddr, + uint32_t count, uint8_t unit_size, + uint8_t char_size) { configure_transfer(char_size); @@ -324,13 +359,19 @@ if (to_transfer) transferred = to_transfer ? (unit_count - _dma->wait()) * unit_size : 0; - /* Wait for the busy condition to clear or for a limited period. */ - - for (unsigned int i = 0; i < (1 << 20) && (_regs[Ssi_status] & Ssi_trans_busy); i++); + wait_busy(); return transferred; } +/* Wait for the busy condition to clear or for a limited period. */ + +void +Spi_jz4780_channel::wait_busy() +{ + for (unsigned int i = 0; i < (1 << 20) && (_regs[Ssi_status] & Ssi_trans_busy); i++); +} + /* Initialise the peripheral abstraction. */ @@ -374,14 +415,28 @@ static_cast(dma), frequency); } -uint32_t jz4780_spi_send(void *channel, uint32_t bytes, const uint8_t data[], - uint8_t unit_size, uint8_t char_size) +uint32_t jz4780_spi_send(void *channel, uint32_t bytes, const uint8_t data[]) +{ + return static_cast(channel)->send(bytes, data); +} + +uint32_t jz4780_spi_send_dc(void *channel, uint32_t bytes, const uint8_t data[], + const int dc[]) { - return static_cast(channel)->send(bytes, data, unit_size, char_size); + return static_cast(channel)->send_dc(bytes, data, dc); +} + +uint32_t jz4780_spi_send_units(void *channel, uint32_t bytes, const uint8_t data[], + uint8_t unit_size, uint8_t char_size) +{ + return static_cast(channel)->send_units(bytes, data, + unit_size, char_size); } 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 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(paddr, count, + unit_size, char_size); } diff -r 89d597f10dc6 -r 3f9892859cee pkg/devices/spi/src/jz4740/spi-jz4740.cc --- a/pkg/devices/spi/src/jz4740/spi-jz4740.cc Tue Nov 07 19:20:32 2023 +0100 +++ b/pkg/devices/spi/src/jz4740/spi-jz4740.cc Thu Nov 09 18:40:31 2023 +0100 @@ -69,7 +69,7 @@ long send(int bits, int data) { - int bytes = (bits + 7) / 8; + uint32_t bytes = (bits + 7) / 8; uint8_t buffer[bytes]; /* Convert the data into a sequence of bytes. */ @@ -160,7 +160,7 @@ gpio_port_enable.setup(enable_pin, Hw::Gpio_chip::Output, 0); - /* Create an object for SPI communication. */ + /* Create an object for SPI communication omitting any specific frequency. */ Spi_gpio spi(&gpio_port_clock, clock_pin, &gpio_port_data, data_pin, &gpio_port_enable, enable_pin); diff -r 89d597f10dc6 -r 3f9892859cee pkg/landfall-examples/hw_info/common.h --- a/pkg/landfall-examples/hw_info/common.h Tue Nov 07 19:20:32 2023 +0100 +++ b/pkg/landfall-examples/hw_info/common.h Thu Nov 09 18:40:31 2023 +0100 @@ -169,17 +169,23 @@ void *spi_init(l4_addr_t spi_start, l4_addr_t start, l4_addr_t end, void *cpm); -void *spi_get_channel(void *spi, uint8_t num, void *channel, uint64_t frequency); +void *spi_get_channel(void *spi, uint8_t num, void *channel, uint64_t frequency, + void *control_chip, int control_pin, int control_alt_func); -void *spi_get_channel_gpio(void *clock_chip, int clock_pin, +void *spi_get_channel_gpio(uint64_t frequency, + void *clock_chip, int clock_pin, void *data_chip, int data_pin, void *enable_chip, int enable_pin, - uint64_t frequency); + void *control_chip, int control_pin); + +void spi_acquire_control(void *channel, int level); -void spi_send(void *channel, int bytes, const uint8_t data[], - uint8_t unit_size, uint8_t char_size); +void spi_release_control(void *channel); -void spi_send_gpio(void *channel, int bytes, const uint8_t data[]); +void spi_send_gpio(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); uint32_t spi_transfer(void *channel, l4re_dma_space_dma_addr_t paddr, uint32_t count, uint8_t unit_size, uint8_t char_size); diff -r 89d597f10dc6 -r 3f9892859cee pkg/landfall-examples/hw_info/hw_info.c --- a/pkg/landfall-examples/hw_info/hw_info.c Tue Nov 07 19:20:32 2023 +0100 +++ b/pkg/landfall-examples/hw_info/hw_info.c Thu Nov 09 18:40:31 2023 +0100 @@ -997,8 +997,11 @@ /* SPI operations. */ -static void new_spi_channel(void *spi) +static void new_spi_channel(void *spi, void *gpio[]) { + unsigned int control_port, control_pin, control_alt_func_input; + int control_alt_func; + void *control_chip; int num = get_channel_number(num_spi_channels); void *channel; uint32_t frequency; @@ -1014,18 +1017,35 @@ if (!read_number("Frequency", &frequency)) return; - spi_channels[num] = spi_get_channel(spi, num, channel, frequency); + if (!get_port_and_pin(&control_port, &control_pin)) + control_chip = NULL; + else + control_chip = gpio[control_port]; + + if (!read_number("Function", &control_alt_func_input)) + control_alt_func = -1; + else + control_alt_func = control_alt_func_input; + + spi_channels[num] = spi_get_channel(spi, num, channel, frequency, + control_chip, control_pin, + control_alt_func); } static void new_spi_channel_gpio(void *gpio[]) { - unsigned int clock_port, clock_pin, data_port, data_pin, enable_port, enable_pin; + unsigned int clock_port, clock_pin, data_port, data_pin, enable_port, + enable_pin, control_port, control_pin; + void *control_chip; int num = get_channel_number(num_spi_channels); uint32_t frequency; if (num < 0) return; + if (!read_number("Frequency", &frequency)) + return; + if (!get_port_and_pin(&clock_port, &clock_pin)) return; @@ -1035,13 +1055,32 @@ if (!get_port_and_pin(&enable_port, &enable_pin)) return; - if (!read_number("Frequency", &frequency)) - return; + if (!get_port_and_pin(&control_port, &control_pin)) + control_chip = NULL; + else + control_chip = gpio[control_port]; - spi_channels[num] = spi_get_channel_gpio(gpio[clock_port], clock_pin, + spi_channels[num] = spi_get_channel_gpio(frequency, + gpio[clock_port], clock_pin, gpio[data_port], data_pin, gpio[enable_port], enable_pin, - frequency); + control_chip, control_pin); +} + +static void spi_control(int acquire) +{ + unsigned int level; + void *channel = get_channel(num_spi_channels, spi_channels, NULL); + + if (acquire) + { + if (!read_number("Level", &level)) + return; + + spi_acquire_control(channel, level); + } + else + spi_release_control(channel); } static void spi_send_data_gpio(void) @@ -1082,7 +1121,7 @@ while ((byte < 256) && read_encoded_number(NULL, "%2x", &value)) buffer[byte++] = value; - spi_send(channel, byte, (uint8_t *) buffer, unit_size, char_size); + spi_send_units(channel, byte, (uint8_t *) buffer, unit_size, char_size); } static void spi_transfer_data(void) @@ -1235,8 +1274,12 @@ { if (!strcmp(token, "l") || !strcmp(token, "list")) list_channels(num_spi_channels, spi_channels); + else if (!strcmp(token, "a") || !strcmp(token, "control-acquire")) + spi_control(1); + else if (!strcmp(token, "r") || !strcmp(token, "control-release")) + spi_control(0); else if (!strcmp(token, "c") || !strcmp(token, "channel")) - new_spi_channel(spi); + new_spi_channel(spi, gpio); else if (!strcmp(token, "g") || !strcmp(token, "gpio") || !strcmp(token, "gpio-channel")) new_spi_channel_gpio(gpio); else if (!strcmp(token, "s") || !strcmp(token, "send")) @@ -1246,7 +1289,7 @@ else if (!strcmp(token, "t") || !strcmp(token, "transfer")) spi_transfer_data(); else - printf("spi channel | gpio-channel | list | send | send-units | transfer\n"); + printf("spi channel | control-acquire | control-release | gpio-channel | list | send | send-units | transfer\n"); } else list_channels(num_spi_channels, spi_channels); diff -r 89d597f10dc6 -r 3f9892859cee pkg/landfall-examples/hw_info/jz4780.c --- a/pkg/landfall-examples/hw_info/jz4780.c Tue Nov 07 19:20:32 2023 +0100 +++ b/pkg/landfall-examples/hw_info/jz4780.c Thu Nov 09 18:40:31 2023 +0100 @@ -29,10 +29,11 @@ #include #include -/* GPIO-based SPI can use arbitrary pins, whereas only the secondary header - provides pins like GPC. */ +/* GPIO-based SPI can use arbitrary pins, whereas on the CI20 only the secondary + header provides pins like GPC. */ #include +#include #include #include "common.h" @@ -337,35 +338,54 @@ return jz4780_spi_init(spi_start, start, end, cpm); } -void *spi_get_channel(void *spi, uint8_t num, void *channel, uint64_t frequency) +void *spi_get_channel(void *spi, uint8_t num, void *channel, uint64_t frequency, + void *control_chip, int control_pin, int control_alt_func) { - return jz4780_spi_get_channel(spi, num, channel, frequency); + void *ch = jz4780_spi_get_channel(spi, num, channel, frequency); + + return spi_hybrid_get_channel(ch, control_chip, control_pin, control_alt_func); } -void *spi_get_channel_gpio(void *clock_chip, int clock_pin, +void *spi_get_channel_gpio(uint64_t frequency, + void *clock_chip, int clock_pin, void *data_chip, int data_pin, void *enable_chip, int enable_pin, - uint64_t frequency) + void *control_chip, int control_pin) { - return spi_gpio_get_channel(clock_chip, clock_pin, data_chip, data_pin, - enable_chip, enable_pin, frequency); + return spi_gpio_get_channel(frequency, clock_chip, clock_pin, data_chip, + data_pin, enable_chip, enable_pin, control_chip, + control_pin); +} + +void spi_acquire_control(void *channel, int level) +{ + spi_hybrid_acquire_control(channel, level); } -void spi_send(void *channel, int bytes, const uint8_t data[], uint8_t unit_size, - uint8_t char_size) +void spi_release_control(void *channel) { - jz4780_spi_send(channel, bytes, data, unit_size, char_size); + spi_hybrid_release_control(channel); } -void spi_send_gpio(void *channel, int bytes, const uint8_t data[]) +void spi_send_gpio(void *channel, uint32_t bytes, const uint8_t data[]) { spi_gpio_send(channel, bytes, data); } +void spi_send_units(void *channel, uint32_t bytes, const uint8_t data[], + uint8_t unit_size, uint8_t char_size) +{ + jz4780_spi_send_units(channel, bytes, data, unit_size, 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) { - return jz4780_spi_transfer(channel, paddr, count, unit_size, char_size); + /* 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); } diff -r 89d597f10dc6 -r 3f9892859cee pkg/landfall-examples/hw_info/x1600.c --- a/pkg/landfall-examples/hw_info/x1600.c Tue Nov 07 19:20:32 2023 +0100 +++ b/pkg/landfall-examples/hw_info/x1600.c Thu Nov 09 18:40:31 2023 +0100 @@ -25,6 +25,7 @@ #include #include #include +// #include #include "common.h" @@ -329,32 +330,55 @@ return NULL; } -void *spi_get_channel(void *spi, uint8_t num, void *channel, uint64_t frequency) +void *spi_get_channel(void *spi, uint8_t num, void *channel, uint64_t frequency, + void *control_chip, int control_pin, int control_alt_func) { + /* NOTE: Initialisation of a hybrid channel to be supported. */ + (void) spi; (void) num; (void) channel; (void) frequency; + (void) control_chip; (void) control_pin; (void) control_alt_func; return NULL; } -void *spi_get_channel_gpio(void *clock_chip, int clock_pin, +void *spi_get_channel_gpio(uint64_t frequency, + void *clock_chip, int clock_pin, void *data_chip, int data_pin, void *enable_chip, int enable_pin, - uint64_t frequency) + void *control_chip, int control_pin) { - return spi_gpio_get_channel(clock_chip, clock_pin, data_chip, data_pin, enable_chip, enable_pin, frequency); + return spi_gpio_get_channel(frequency, clock_chip, clock_pin, data_chip, + data_pin, enable_chip, enable_pin, control_chip, + control_pin); +} + +void spi_acquire_control(void *channel, int level) +{ + /* NOTE: Not yet supported. */ + + (void) channel; (void) level; + // spi_hybrid_acquire_control(channel, level); } -void spi_send(void *channel, int bytes, const uint8_t data[], uint8_t unit_size, - uint8_t char_size) +void spi_release_control(void *channel) +{ + /* NOTE: Not yet supported. */ + + (void) channel; + // spi_hybrid_release_control(channel); +} + +void spi_send_gpio(void *channel, uint32_t bytes, const uint8_t data[]) +{ + spi_gpio_send(channel, bytes, data); +} + +void spi_send_units(void *channel, uint32_t bytes, const uint8_t data[], uint8_t unit_size, + uint8_t char_size) { /* NOTE: Not yet supported. */ (void) channel; (void) bytes; (void) data; (void) unit_size; (void) char_size; - // x1600_spi_send(channel, bytes, data, unit_size, char_size); -} - -void spi_send_gpio(void *channel, int bytes, const uint8_t data[]) -{ - spi_gpio_send(channel, bytes, data); + // x1600_spi_send_units(channel, bytes, data, unit_size, char_size); } uint32_t spi_transfer(void *channel, l4re_dma_space_dma_addr_t paddr,