1.1 --- a/pkg/devices/lib/spi/include/spi-gpio.h Tue Nov 07 19:20:32 2023 +0100
1.2 +++ b/pkg/devices/lib/spi/include/spi-gpio.h Thu Nov 09 18:40:31 2023 +0100
1.3 @@ -21,32 +21,47 @@
1.4
1.5 #pragma once
1.6
1.7 -#include <l4/devices/gpio.h>
1.8 #include <stdint.h>
1.9
1.10
1.11
1.12 #ifdef __cplusplus
1.13
1.14 -/* SPI peripheral device. */
1.15 +#include <l4/devices/gpio.h>
1.16 +#include <l4/devices/spi.h>
1.17
1.18 -class Spi_gpio
1.19 +/* SPI channel abstraction. */
1.20 +
1.21 +class Spi_gpio : public Spi_channel_base
1.22 {
1.23 + uint64_t _frequency;
1.24 Hw::Gpio_chip *_clock_device;
1.25 int _clock_pin;
1.26 Hw::Gpio_chip *_data_device;
1.27 int _data_pin;
1.28 Hw::Gpio_chip *_enable_device;
1.29 int _enable_pin;
1.30 - uint64_t _frequency;
1.31 + Hw::Gpio_chip *_control_device;
1.32 + int _control_pin;
1.33
1.34 public:
1.35 + explicit Spi_gpio(uint64_t frequency,
1.36 + Hw::Gpio_chip *clock_device, int clock_pin,
1.37 + Hw::Gpio_chip *data_device, int data_pin,
1.38 + Hw::Gpio_chip *enable_device, int enable_pin,
1.39 + Hw::Gpio_chip *control_device = NULL, int control_pin = 0);
1.40 +
1.41 explicit Spi_gpio(Hw::Gpio_chip *clock_device, int clock_pin,
1.42 Hw::Gpio_chip *data_device, int data_pin,
1.43 Hw::Gpio_chip *enable_device, int enable_pin,
1.44 - uint64_t frequency = 0);
1.45 + Hw::Gpio_chip *control_device = NULL, int control_pin = 0);
1.46 +
1.47 + uint32_t send(uint32_t bytes, const uint8_t data[]);
1.48
1.49 - void send(int bytes, const uint8_t data[]);
1.50 + uint32_t send_dc(uint32_t bytes, const uint8_t data[], const int dc[]);
1.51 +
1.52 + uint32_t send_units(uint32_t bytes, const uint8_t data[], uint8_t unit_size,
1.53 + uint8_t char_size);
1.54 };
1.55
1.56 #endif /* __cplusplus */
1.57 @@ -57,11 +72,18 @@
1.58
1.59 EXTERN_C_BEGIN
1.60
1.61 -void *spi_gpio_get_channel(void *clock_chip, int clock_pin,
1.62 +void *spi_gpio_get_channel(uint64_t frequency,
1.63 + void *clock_chip, int clock_pin,
1.64 void *data_chip, int data_pin,
1.65 void *enable_chip, int enable_pin,
1.66 - uint64_t frequency);
1.67 + void *control_chip, int control_pin);
1.68 +
1.69 +uint32_t spi_gpio_send(void *channel, uint32_t bytes, const uint8_t data[]);
1.70
1.71 -void spi_gpio_send(void *channel, int bytes, const uint8_t data[]);
1.72 +uint32_t spi_gpio_send_dc(void *channel, uint32_t bytes, const uint8_t data[],
1.73 + const int dc[]);
1.74 +
1.75 +uint32_t spi_gpio_send_units(void *channel, uint32_t bytes, const uint8_t data[],
1.76 + uint8_t unit_size, uint8_t char_size);
1.77
1.78 EXTERN_C_END
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/pkg/devices/lib/spi/include/spi-hybrid.h Thu Nov 09 18:40:31 2023 +0100
2.3 @@ -0,0 +1,87 @@
2.4 +/*
2.5 + * Perform SPI communication using a suitable abstraction augmented with
2.6 + * explicit manipulation of a control signal.
2.7 + *
2.8 + * Copyright (C) 2023 Paul Boddie <paul@boddie.org.uk>
2.9 + *
2.10 + * This program is free software; you can redistribute it and/or
2.11 + * modify it under the terms of the GNU General Public License as
2.12 + * published by the Free Software Foundation; either version 2 of
2.13 + * the License, or (at your option) any later version.
2.14 + *
2.15 + * This program is distributed in the hope that it will be useful,
2.16 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2.17 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2.18 + * GNU General Public License for more details.
2.19 + *
2.20 + * You should have received a copy of the GNU General Public License
2.21 + * along with this program; if not, write to the Free Software
2.22 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
2.23 + * Boston, MA 02110-1301, USA
2.24 + */
2.25 +
2.26 +#pragma once
2.27 +
2.28 +#include <stdint.h>
2.29 +
2.30 +
2.31 +
2.32 +#ifdef __cplusplus
2.33 +
2.34 +#include <l4/devices/gpio.h>
2.35 +#include <l4/devices/spi.h>
2.36 +
2.37 +/* SPI channel abstraction. */
2.38 +
2.39 +class Spi_hybrid : public Spi_channel_base, public Spi_control_base
2.40 +{
2.41 + Spi_channel_base *_channel;
2.42 + Hw::Gpio_chip *_control_device;
2.43 + int _control_pin;
2.44 + int _control_alt_func;
2.45 +
2.46 +public:
2.47 + explicit Spi_hybrid(Spi_channel_base *channel,
2.48 + Hw::Gpio_chip *control_device, int control_pin,
2.49 + int control_alt_func = -1);
2.50 +
2.51 + Spi_channel_base *get_channel();
2.52 +
2.53 + void acquire_control(bool asserted);
2.54 +
2.55 + void release_control();
2.56 +
2.57 + uint32_t send(uint32_t bytes, const uint8_t data[]);
2.58 +
2.59 + uint32_t send_dc(uint32_t bytes, const uint8_t data[], const int dc[]);
2.60 +
2.61 + uint32_t send_units(uint32_t bytes, const uint8_t data[],
2.62 + uint8_t unit_size, uint8_t char_size);
2.63 +};
2.64 +
2.65 +#endif /* __cplusplus */
2.66 +
2.67 +
2.68 +
2.69 +/* C language interface. */
2.70 +
2.71 +EXTERN_C_BEGIN
2.72 +
2.73 +void *spi_hybrid_get_channel(void *channel, void *control_chip, int control_pin,
2.74 + int control_alt_func);
2.75 +
2.76 +void *spi_hybrid_get_raw_channel(void *channel);
2.77 +
2.78 +void spi_hybrid_acquire_control(void *channel, int asserted);
2.79 +
2.80 +void spi_hybrid_release_control(void *channel);
2.81 +
2.82 +uint32_t spi_hybrid_send(void *channel, uint32_t bytes, const uint8_t data[]);
2.83 +
2.84 +uint32_t spi_hybrid_send_dc(void *channel, uint32_t bytes, const uint8_t data[],
2.85 + const int dc[]);
2.86 +
2.87 +uint32_t spi_hybrid_send_units(void *channel, uint32_t bytes, const uint8_t data[],
2.88 + uint8_t unit_size, uint8_t char_size);
2.89 +
2.90 +EXTERN_C_END
3.1 --- a/pkg/devices/lib/spi/include/spi-jz4780.h Tue Nov 07 19:20:32 2023 +0100
3.2 +++ b/pkg/devices/lib/spi/include/spi-jz4780.h Thu Nov 09 18:40:31 2023 +0100
3.3 @@ -32,10 +32,11 @@
3.4 #include <l4/devices/cpm-jz4780.h>
3.5 #include <l4/devices/dma-jz4780.h>
3.6 #include <l4/devices/hw_mmio_register_block.h>
3.7 +#include <l4/devices/spi.h>
3.8
3.9 /* SPI peripheral channel. */
3.10
3.11 -class Spi_jz4780_channel
3.12 +class Spi_jz4780_channel : public Spi_channel_base
3.13 {
3.14 Hw::Register_block<32> _regs;
3.15
3.16 @@ -48,8 +49,12 @@
3.17 enum Dma_jz4780_request_type _request_type;
3.18 uint64_t _frequency;
3.19
3.20 + /* Common utilities. */
3.21 +
3.22 void configure_transfer(uint8_t char_size);
3.23
3.24 + void wait_busy();
3.25 +
3.26 public:
3.27 explicit Spi_jz4780_channel(l4_addr_t spi_start, l4_addr_t start,
3.28 enum Clock_identifiers clock,
3.29 @@ -58,15 +63,19 @@
3.30 enum Dma_jz4780_request_type request_type,
3.31 uint64_t frequency);
3.32
3.33 + /* Convenience operations. */
3.34 +
3.35 + virtual uint32_t send(uint32_t bytes, const uint8_t data[]);
3.36 +
3.37 + virtual uint32_t send_dc(uint32_t bytes, const uint8_t data[], const int dc[]);
3.38 +
3.39 + uint32_t send_units(uint32_t bytes, const uint8_t data[], uint8_t unit_size,
3.40 + uint8_t char_size);
3.41 +
3.42 /* DMA operations. */
3.43
3.44 uint32_t transfer(l4re_dma_space_dma_addr_t paddr, uint32_t count,
3.45 uint8_t unit_size, uint8_t char_size);
3.46 -
3.47 - /* Convenience operations. */
3.48 -
3.49 - uint32_t send(uint32_t bytes, const uint8_t data[], uint8_t unit_size,
3.50 - uint8_t char_size);
3.51 };
3.52
3.53 /* SPI peripheral. */
3.54 @@ -96,8 +105,13 @@
3.55
3.56 void *jz4780_spi_get_channel(void *spi, uint8_t channel, void *dma, uint64_t frequency);
3.57
3.58 -uint32_t jz4780_spi_send(void *channel, uint32_t bytes, const uint8_t data[],
3.59 - uint8_t unit_size, uint8_t char_size);
3.60 +uint32_t jz4780_spi_send(void *channel, uint32_t bytes, const uint8_t data[]);
3.61 +
3.62 +uint32_t jz4780_spi_send_dc(void *channel, uint32_t bytes, const uint8_t data[],
3.63 + const int dc[]);
3.64 +
3.65 +uint32_t jz4780_spi_send_units(void *channel, uint32_t bytes, const uint8_t data[],
3.66 + uint8_t unit_size, uint8_t char_size);
3.67
3.68 uint32_t jz4780_spi_transfer(void *channel, l4re_dma_space_dma_addr_t paddr,
3.69 uint32_t count, uint8_t unit_size, uint8_t char_size);
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/pkg/devices/lib/spi/include/spi.h Thu Nov 09 18:40:31 2023 +0100
4.3 @@ -0,0 +1,50 @@
4.4 +/*
4.5 + * Common SPI abstractions.
4.6 + *
4.7 + * Copyright (C) 2023 Paul Boddie <paul@boddie.org.uk>
4.8 + *
4.9 + * This program is free software; you can redistribute it and/or
4.10 + * modify it under the terms of the GNU General Public License as
4.11 + * published by the Free Software Foundation; either version 2 of
4.12 + * the License, or (at your option) any later version.
4.13 + *
4.14 + * This program is distributed in the hope that it will be useful,
4.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
4.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4.17 + * GNU General Public License for more details.
4.18 + *
4.19 + * You should have received a copy of the GNU General Public License
4.20 + * along with this program; if not, write to the Free Software
4.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
4.22 + * Boston, MA 02110-1301, USA
4.23 + */
4.24 +
4.25 +#pragma once
4.26 +
4.27 +#ifdef __cplusplus
4.28 +
4.29 +#include <stdint.h>
4.30 +
4.31 +/* SPI channel abstractions. */
4.32 +
4.33 +class Spi_channel_base
4.34 +{
4.35 +public:
4.36 + virtual uint32_t send(uint32_t bytes, const uint8_t data[]) = 0;
4.37 +
4.38 + virtual uint32_t send_dc(uint32_t bytes, const uint8_t data[],
4.39 + const int dc[]) = 0;
4.40 +
4.41 + virtual uint32_t send_units(uint32_t bytes, const uint8_t data[],
4.42 + uint8_t unit_size, uint8_t char_size) = 0;
4.43 +};
4.44 +
4.45 +class Spi_control_base
4.46 +{
4.47 +public:
4.48 + virtual void acquire_control(bool asserted) = 0;
4.49 +
4.50 + virtual void release_control() = 0;
4.51 +};
4.52 +
4.53 +#endif /* __cplusplus */
5.1 --- a/pkg/devices/lib/spi/src/Makefile Tue Nov 07 19:20:32 2023 +0100
5.2 +++ b/pkg/devices/lib/spi/src/Makefile Thu Nov 09 18:40:31 2023 +0100
5.3 @@ -4,7 +4,7 @@
5.4 TARGET = libspi.o.a libspi.o.so
5.5 PC_FILENAME := libdrivers-spi
5.6
5.7 -SRC_CC := gpio.cc jz4780.cc
5.8 +SRC_CC := gpio.cc hybrid.cc jz4780.cc
5.9
5.10 PRIVATE_INCDIR += $(PKGDIR)/lib/spi/include
5.11
6.1 --- a/pkg/devices/lib/spi/src/gpio.cc Tue Nov 07 19:20:32 2023 +0100
6.2 +++ b/pkg/devices/lib/spi/src/gpio.cc Thu Nov 09 18:40:31 2023 +0100
6.3 @@ -27,27 +27,48 @@
6.4 Spi_gpio::Spi_gpio(Hw::Gpio_chip *clock_device, int clock_pin,
6.5 Hw::Gpio_chip *data_device, int data_pin,
6.6 Hw::Gpio_chip *enable_device, int enable_pin,
6.7 - uint64_t frequency)
6.8 + Hw::Gpio_chip *control_device, int control_pin)
6.9 : _clock_device(clock_device),
6.10 _clock_pin(clock_pin),
6.11 _data_device(data_device),
6.12 _data_pin(data_pin),
6.13 _enable_device(enable_device),
6.14 _enable_pin(enable_pin),
6.15 - _frequency(frequency)
6.16 + _control_device(control_device),
6.17 + _control_pin(control_pin)
6.18 {
6.19 _clock_device->setup(_clock_pin, Hw::Gpio_chip::Output, 1);
6.20 _data_device->setup(_data_pin, Hw::Gpio_chip::Output, 0);
6.21 _enable_device->setup(_enable_pin, Hw::Gpio_chip::Output, 1);
6.22 }
6.23
6.24 +Spi_gpio::Spi_gpio(uint64_t frequency,
6.25 + Hw::Gpio_chip *clock_device, int clock_pin,
6.26 + Hw::Gpio_chip *data_device, int data_pin,
6.27 + Hw::Gpio_chip *enable_device, int enable_pin,
6.28 + Hw::Gpio_chip *control_device, int control_pin)
6.29 +: Spi_gpio(clock_device, clock_pin, data_device, data_pin, enable_device,
6.30 + enable_pin, control_device, control_pin)
6.31 +{
6.32 + _frequency = frequency;
6.33 +}
6.34 +
6.35 /* Send a byte sequence. */
6.36
6.37 -void Spi_gpio::send(int bytes, const uint8_t data[])
6.38 +uint32_t Spi_gpio::send(uint32_t bytes, const uint8_t data[])
6.39 +{
6.40 + return send_dc(bytes, data, NULL);
6.41 +}
6.42 +
6.43 +/* Send a byte sequence with accompanying data/command indicators. */
6.44 +
6.45 +uint32_t Spi_gpio::send_dc(uint32_t bytes, const uint8_t data[],
6.46 + const int dc[])
6.47 {
6.48 struct timespec ts;
6.49 uint8_t mask;
6.50 - int bit, byte;
6.51 + int bit;
6.52 + uint32_t byte;
6.53
6.54 if (_frequency)
6.55 {
6.56 @@ -80,6 +101,9 @@
6.57 _clock_device->set(_clock_pin, 0);
6.58 _data_device->set(_data_pin, data[byte] & mask ? 1 : 0);
6.59
6.60 + if ((_control_device != NULL) && (dc != NULL))
6.61 + _control_device->set(_control_pin, dc[byte] ? 1 : 0);
6.62 +
6.63 if (_frequency)
6.64 nanosleep(&ts, NULL);
6.65
6.66 @@ -93,24 +117,77 @@
6.67 }
6.68
6.69 _enable_device->set(_enable_pin, 1);
6.70 +
6.71 + return bytes;
6.72 +}
6.73 +
6.74 +/* Send a number of units, each holding a value in a big endian arrangement
6.75 + limited to the given character size, with any bit immediately above the
6.76 + character portion of the unit indicating the data/command level. */
6.77 +
6.78 +uint32_t Spi_gpio::send_units(uint32_t bytes, const uint8_t data[],
6.79 + uint8_t unit_size, uint8_t char_size)
6.80 +{
6.81 + uint32_t count = bytes / unit_size;
6.82 + int dc[count];
6.83 +
6.84 + /* Traverse the byte sequence, extracting data/command bits for each unit. */
6.85 +
6.86 + for (uint32_t offset = 0, unit = 0; offset < bytes; offset += unit_size, unit++)
6.87 + {
6.88 + /* The unit size must be greater than the character size for data/command
6.89 + bits to be present. */
6.90 +
6.91 + if (unit_size * 8 <= char_size)
6.92 + dc[unit] = 0;
6.93 + else
6.94 + {
6.95 + /* Obtain the unit value. */
6.96 +
6.97 + uint32_t value = 0;
6.98 +
6.99 + for (uint8_t byte = 0; byte < unit_size; byte++)
6.100 + value = (value << 8) | data[offset + byte];
6.101 +
6.102 + /* Extract the data/command level. */
6.103 +
6.104 + dc[unit] = value & (1 << char_size) ? 1 : 0;
6.105 + }
6.106 + }
6.107 +
6.108 + return send_dc(bytes, data, dc);
6.109 }
6.110
6.111
6.112
6.113 /* C language interface. */
6.114
6.115 -void *spi_gpio_get_channel(void *clock_chip, int clock_pin,
6.116 +void *spi_gpio_get_channel(uint64_t frequency,
6.117 + void *clock_chip, int clock_pin,
6.118 void *data_chip, int data_pin,
6.119 void *enable_chip, int enable_pin,
6.120 - uint64_t frequency)
6.121 + void *control_chip, int control_pin)
6.122 {
6.123 - return (void *) new Spi_gpio(reinterpret_cast<Hw::Gpio_chip *>(clock_chip), clock_pin,
6.124 + return (void *) new Spi_gpio(frequency,
6.125 + reinterpret_cast<Hw::Gpio_chip *>(clock_chip), clock_pin,
6.126 reinterpret_cast<Hw::Gpio_chip *>(data_chip), data_pin,
6.127 reinterpret_cast<Hw::Gpio_chip *>(enable_chip), enable_pin,
6.128 - frequency);
6.129 + reinterpret_cast<Hw::Gpio_chip *>(control_chip), control_pin);
6.130 +}
6.131 +
6.132 +uint32_t spi_gpio_send(void *channel, uint32_t bytes, const uint8_t data[])
6.133 +{
6.134 + return static_cast<Spi_gpio *>(channel)->send(bytes, data);
6.135 }
6.136
6.137 -void spi_gpio_send(void *channel, int bytes, const uint8_t data[])
6.138 +uint32_t spi_gpio_send_dc(void *channel, uint32_t bytes, const uint8_t data[],
6.139 + const int dc[])
6.140 {
6.141 - static_cast<Spi_gpio *>(channel)->send(bytes, data);
6.142 + return static_cast<Spi_gpio *>(channel)->send_dc(bytes, data, dc);
6.143 }
6.144 +
6.145 +uint32_t spi_gpio_send_units(void *channel, uint32_t bytes, const uint8_t data[],
6.146 + uint8_t unit_size, uint8_t char_size)
6.147 +{
6.148 + return static_cast<Spi_gpio *>(channel)->send_units(bytes, data, unit_size, char_size);
6.149 +}
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/pkg/devices/lib/spi/src/hybrid.cc Thu Nov 09 18:40:31 2023 +0100
7.3 @@ -0,0 +1,119 @@
7.4 +/*
7.5 + * Perform SPI communication using a suitable abstraction augmented with
7.6 + * explicit manipulation of a control signal.
7.7 + *
7.8 + * Copyright (C) 2023 Paul Boddie <paul@boddie.org.uk>
7.9 + *
7.10 + * This program is free software; you can redistribute it and/or
7.11 + * modify it under the terms of the GNU General Public License as
7.12 + * published by the Free Software Foundation; either version 2 of
7.13 + * the License, or (at your option) any later version.
7.14 + *
7.15 + * This program is distributed in the hope that it will be useful,
7.16 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
7.17 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
7.18 + * GNU General Public License for more details.
7.19 + *
7.20 + * You should have received a copy of the GNU General Public License
7.21 + * along with this program; if not, write to the Free Software
7.22 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
7.23 + * Boston, MA 02110-1301, USA
7.24 + */
7.25 +
7.26 +#include <l4/devices/spi-hybrid.h>
7.27 +
7.28 +
7.29 +
7.30 +Spi_hybrid::Spi_hybrid(Spi_channel_base *channel,
7.31 + Hw::Gpio_chip *control_device, int control_pin,
7.32 + int control_alt_func)
7.33 +: _channel(channel),
7.34 + _control_device(control_device),
7.35 + _control_pin(control_pin),
7.36 + _control_alt_func(control_alt_func)
7.37 +{
7.38 +}
7.39 +
7.40 +Spi_channel_base *Spi_hybrid::get_channel()
7.41 +{
7.42 + return _channel;
7.43 +}
7.44 +
7.45 +void Spi_hybrid::acquire_control(bool asserted)
7.46 +{
7.47 + _control_device->setup(_control_pin, Hw::Gpio_chip::Output, asserted ? 1 : 0);
7.48 +}
7.49 +
7.50 +void Spi_hybrid::release_control()
7.51 +{
7.52 + if (_control_alt_func >= 0)
7.53 + _control_device->config_pad(_control_pin, Hw::Gpio_chip::Function_alt, _control_alt_func);
7.54 + else
7.55 + _control_device->setup(_control_pin, Hw::Gpio_chip::Input, 0);
7.56 +}
7.57 +
7.58 +/* Send a byte sequence. */
7.59 +
7.60 +uint32_t Spi_hybrid::send(uint32_t bytes, const uint8_t data[])
7.61 +{
7.62 + return _channel->send(bytes, data);
7.63 +}
7.64 +
7.65 +/* Send a byte sequence with control information. */
7.66 +
7.67 +uint32_t Spi_hybrid::send_dc(uint32_t bytes, const uint8_t data[], const int dc[])
7.68 +{
7.69 + return _channel->send_dc(bytes, data, dc);
7.70 +}
7.71 +
7.72 +/* Send a sequence of units having the given character size. */
7.73 +
7.74 +uint32_t Spi_hybrid::send_units(uint32_t bytes, const uint8_t data[],
7.75 + uint8_t unit_size, uint8_t char_size)
7.76 +{
7.77 + return _channel->send_units(bytes, data, unit_size, char_size);
7.78 +}
7.79 +
7.80 +
7.81 +
7.82 +/* C language interface. */
7.83 +
7.84 +void *spi_hybrid_get_channel(void *channel, void *control_chip, int control_pin,
7.85 + int control_alt_func)
7.86 +{
7.87 + return (void *) new Spi_hybrid(reinterpret_cast<Spi_channel_base *>(channel),
7.88 + reinterpret_cast<Hw::Gpio_chip *>(control_chip),
7.89 + control_pin, control_alt_func);
7.90 +}
7.91 +
7.92 +void *spi_hybrid_get_raw_channel(void *channel)
7.93 +{
7.94 + return static_cast<Spi_hybrid *>(channel)->get_channel();
7.95 +}
7.96 +
7.97 +void spi_hybrid_acquire_control(void *channel, int level)
7.98 +{
7.99 + static_cast<Spi_hybrid *>(channel)->acquire_control(level);
7.100 +}
7.101 +
7.102 +void spi_hybrid_release_control(void *channel)
7.103 +{
7.104 + static_cast<Spi_hybrid *>(channel)->release_control();
7.105 +}
7.106 +
7.107 +uint32_t spi_hybrid_send(void *channel, uint32_t bytes, const uint8_t data[])
7.108 +{
7.109 + return static_cast<Spi_hybrid *>(channel)->send(bytes, data);
7.110 +}
7.111 +
7.112 +uint32_t spi_hybrid_send_dc(void *channel, uint32_t bytes, const uint8_t data[],
7.113 + const int dc[])
7.114 +{
7.115 + return static_cast<Spi_hybrid *>(channel)->send_dc(bytes, data, dc);
7.116 +}
7.117 +
7.118 +uint32_t spi_hybrid_send_units(void *channel, uint32_t bytes, const uint8_t data[],
7.119 + uint8_t unit_size, uint8_t char_size)
7.120 +{
7.121 + return static_cast<Spi_hybrid *>(channel)->send_units(bytes, data, unit_size, char_size);
7.122 +}
8.1 --- a/pkg/devices/lib/spi/src/jz4780.cc Tue Nov 07 19:20:32 2023 +0100
8.2 +++ b/pkg/devices/lib/spi/src/jz4780.cc Thu Nov 09 18:40:31 2023 +0100
8.3 @@ -269,12 +269,48 @@
8.4 Spi_clock_assert_drive | Spi_clock_idle_high_level;
8.5 }
8.6
8.7 -/* Transfer the given number of bytes from a buffer using the given unit size in
8.8 - bytes and character size in bits. */
8.9 +/* Transfer the given number of bytes from a buffer. */
8.10 +
8.11 +uint32_t
8.12 +Spi_jz4780_channel::send(uint32_t bytes, const uint8_t data[])
8.13 +{
8.14 + return send_units(bytes, data, 1, 8);
8.15 +}
8.16 +
8.17 +/* Transfer the given number of bytes from a buffer together with control values. */
8.18
8.19 uint32_t
8.20 -Spi_jz4780_channel::send(uint32_t bytes, const uint8_t data[], uint8_t unit_size,
8.21 - uint8_t char_size)
8.22 +Spi_jz4780_channel::send_dc(uint32_t bytes, const uint8_t data[],
8.23 + const int dc[])
8.24 +{
8.25 + configure_transfer(8);
8.26 +
8.27 + uint32_t transferred;
8.28 +
8.29 + for (transferred = 0; transferred < bytes; transferred++)
8.30 + {
8.31 + /* Relocate the data/command level to bit 16. */
8.32 +
8.33 + uint32_t command = dc[transferred] ? (1 << 16) : 0;
8.34 + uint32_t value = data[transferred];
8.35 +
8.36 + /* Combine the character with the data/command bit. */
8.37 +
8.38 + _regs[Ssi_data] = value | command;
8.39 + }
8.40 +
8.41 + wait_busy();
8.42 +
8.43 + return transferred;
8.44 +}
8.45 +
8.46 +/* Transfer the given number of bytes from a buffer using the given unit size in
8.47 + bytes and character size in bits. The bytes are stored in a big endian
8.48 + arrangement. */
8.49 +
8.50 +uint32_t
8.51 +Spi_jz4780_channel::send_units(uint32_t bytes, const uint8_t data[],
8.52 + uint8_t unit_size, uint8_t char_size)
8.53 {
8.54 configure_transfer(char_size);
8.55
8.56 @@ -292,15 +328,13 @@
8.57
8.58 uint32_t command = (char_size < 16) && (value & (1 << char_size)) ? (1 << 16) : 0;
8.59
8.60 - /* Combine the significant portion of the character with the command. */
8.61 + /* Combine the character portion of the unit with the command. */
8.62
8.63 value = (value & char_mask) | command;
8.64 _regs[Ssi_data] = value;
8.65 }
8.66
8.67 - /* Wait for the busy condition to clear or for a limited period. */
8.68 -
8.69 - for (unsigned int i = 0; i < (1 << 20) && (_regs[Ssi_status] & Ssi_trans_busy); i++);
8.70 + wait_busy();
8.71
8.72 return transferred;
8.73 }
8.74 @@ -308,9 +342,10 @@
8.75 /* Transfer the given number of bytes from a DMA region using the given
8.76 unit size in bytes and character size in bits. */
8.77
8.78 -uint32_t Spi_jz4780_channel::transfer(l4re_dma_space_dma_addr_t paddr,
8.79 - uint32_t count, uint8_t unit_size,
8.80 - uint8_t char_size)
8.81 +uint32_t
8.82 +Spi_jz4780_channel::transfer(l4re_dma_space_dma_addr_t paddr,
8.83 + uint32_t count, uint8_t unit_size,
8.84 + uint8_t char_size)
8.85 {
8.86 configure_transfer(char_size);
8.87
8.88 @@ -324,13 +359,19 @@
8.89 if (to_transfer)
8.90 transferred = to_transfer ? (unit_count - _dma->wait()) * unit_size : 0;
8.91
8.92 - /* Wait for the busy condition to clear or for a limited period. */
8.93 -
8.94 - for (unsigned int i = 0; i < (1 << 20) && (_regs[Ssi_status] & Ssi_trans_busy); i++);
8.95 + wait_busy();
8.96
8.97 return transferred;
8.98 }
8.99
8.100 +/* Wait for the busy condition to clear or for a limited period. */
8.101 +
8.102 +void
8.103 +Spi_jz4780_channel::wait_busy()
8.104 +{
8.105 + for (unsigned int i = 0; i < (1 << 20) && (_regs[Ssi_status] & Ssi_trans_busy); i++);
8.106 +}
8.107 +
8.108
8.109
8.110 /* Initialise the peripheral abstraction. */
8.111 @@ -374,14 +415,28 @@
8.112 static_cast<Dma_jz4780_channel *>(dma), frequency);
8.113 }
8.114
8.115 -uint32_t jz4780_spi_send(void *channel, uint32_t bytes, const uint8_t data[],
8.116 - uint8_t unit_size, uint8_t char_size)
8.117 +uint32_t jz4780_spi_send(void *channel, uint32_t bytes, const uint8_t data[])
8.118 +{
8.119 + return static_cast<Spi_jz4780_channel *>(channel)->send(bytes, data);
8.120 +}
8.121 +
8.122 +uint32_t jz4780_spi_send_dc(void *channel, uint32_t bytes, const uint8_t data[],
8.123 + const int dc[])
8.124 {
8.125 - return static_cast<Spi_jz4780_channel *>(channel)->send(bytes, data, unit_size, char_size);
8.126 + return static_cast<Spi_jz4780_channel *>(channel)->send_dc(bytes, data, dc);
8.127 +}
8.128 +
8.129 +uint32_t jz4780_spi_send_units(void *channel, uint32_t bytes, const uint8_t data[],
8.130 + uint8_t unit_size, uint8_t char_size)
8.131 +{
8.132 + return static_cast<Spi_jz4780_channel *>(channel)->send_units(bytes, data,
8.133 + unit_size, char_size);
8.134 }
8.135
8.136 uint32_t jz4780_spi_transfer(void *channel, l4re_dma_space_dma_addr_t paddr,
8.137 - uint32_t count, uint8_t unit_size, uint8_t char_size)
8.138 + uint32_t count, uint8_t unit_size,
8.139 + uint8_t char_size)
8.140 {
8.141 - return static_cast<Spi_jz4780_channel *>(channel)->transfer(paddr, count, unit_size, char_size);
8.142 + return static_cast<Spi_jz4780_channel *>(channel)->transfer(paddr, count,
8.143 + unit_size, char_size);
8.144 }
9.1 --- a/pkg/devices/spi/src/jz4740/spi-jz4740.cc Tue Nov 07 19:20:32 2023 +0100
9.2 +++ b/pkg/devices/spi/src/jz4740/spi-jz4740.cc Thu Nov 09 18:40:31 2023 +0100
9.3 @@ -69,7 +69,7 @@
9.4
9.5 long send(int bits, int data)
9.6 {
9.7 - int bytes = (bits + 7) / 8;
9.8 + uint32_t bytes = (bits + 7) / 8;
9.9 uint8_t buffer[bytes];
9.10
9.11 /* Convert the data into a sequence of bytes. */
9.12 @@ -160,7 +160,7 @@
9.13
9.14 gpio_port_enable.setup(enable_pin, Hw::Gpio_chip::Output, 0);
9.15
9.16 - /* Create an object for SPI communication. */
9.17 + /* Create an object for SPI communication omitting any specific frequency. */
9.18
9.19 Spi_gpio spi(&gpio_port_clock, clock_pin, &gpio_port_data, data_pin,
9.20 &gpio_port_enable, enable_pin);
10.1 --- a/pkg/landfall-examples/hw_info/common.h Tue Nov 07 19:20:32 2023 +0100
10.2 +++ b/pkg/landfall-examples/hw_info/common.h Thu Nov 09 18:40:31 2023 +0100
10.3 @@ -169,17 +169,23 @@
10.4
10.5 void *spi_init(l4_addr_t spi_start, l4_addr_t start, l4_addr_t end, void *cpm);
10.6
10.7 -void *spi_get_channel(void *spi, uint8_t num, void *channel, uint64_t frequency);
10.8 +void *spi_get_channel(void *spi, uint8_t num, void *channel, uint64_t frequency,
10.9 + void *control_chip, int control_pin, int control_alt_func);
10.10
10.11 -void *spi_get_channel_gpio(void *clock_chip, int clock_pin,
10.12 +void *spi_get_channel_gpio(uint64_t frequency,
10.13 + void *clock_chip, int clock_pin,
10.14 void *data_chip, int data_pin,
10.15 void *enable_chip, int enable_pin,
10.16 - uint64_t frequency);
10.17 + void *control_chip, int control_pin);
10.18 +
10.19 +void spi_acquire_control(void *channel, int level);
10.20
10.21 -void spi_send(void *channel, int bytes, const uint8_t data[],
10.22 - uint8_t unit_size, uint8_t char_size);
10.23 +void spi_release_control(void *channel);
10.24
10.25 -void spi_send_gpio(void *channel, int bytes, const uint8_t data[]);
10.26 +void spi_send_gpio(void *channel, uint32_t bytes, const uint8_t data[]);
10.27 +
10.28 +void spi_send_units(void *channel, uint32_t bytes, const uint8_t data[],
10.29 + uint8_t unit_size, uint8_t char_size);
10.30
10.31 uint32_t spi_transfer(void *channel, l4re_dma_space_dma_addr_t paddr,
10.32 uint32_t count, uint8_t unit_size, uint8_t char_size);
11.1 --- a/pkg/landfall-examples/hw_info/hw_info.c Tue Nov 07 19:20:32 2023 +0100
11.2 +++ b/pkg/landfall-examples/hw_info/hw_info.c Thu Nov 09 18:40:31 2023 +0100
11.3 @@ -997,8 +997,11 @@
11.4
11.5 /* SPI operations. */
11.6
11.7 -static void new_spi_channel(void *spi)
11.8 +static void new_spi_channel(void *spi, void *gpio[])
11.9 {
11.10 + unsigned int control_port, control_pin, control_alt_func_input;
11.11 + int control_alt_func;
11.12 + void *control_chip;
11.13 int num = get_channel_number(num_spi_channels);
11.14 void *channel;
11.15 uint32_t frequency;
11.16 @@ -1014,18 +1017,35 @@
11.17 if (!read_number("Frequency", &frequency))
11.18 return;
11.19
11.20 - spi_channels[num] = spi_get_channel(spi, num, channel, frequency);
11.21 + if (!get_port_and_pin(&control_port, &control_pin))
11.22 + control_chip = NULL;
11.23 + else
11.24 + control_chip = gpio[control_port];
11.25 +
11.26 + if (!read_number("Function", &control_alt_func_input))
11.27 + control_alt_func = -1;
11.28 + else
11.29 + control_alt_func = control_alt_func_input;
11.30 +
11.31 + spi_channels[num] = spi_get_channel(spi, num, channel, frequency,
11.32 + control_chip, control_pin,
11.33 + control_alt_func);
11.34 }
11.35
11.36 static void new_spi_channel_gpio(void *gpio[])
11.37 {
11.38 - unsigned int clock_port, clock_pin, data_port, data_pin, enable_port, enable_pin;
11.39 + unsigned int clock_port, clock_pin, data_port, data_pin, enable_port,
11.40 + enable_pin, control_port, control_pin;
11.41 + void *control_chip;
11.42 int num = get_channel_number(num_spi_channels);
11.43 uint32_t frequency;
11.44
11.45 if (num < 0)
11.46 return;
11.47
11.48 + if (!read_number("Frequency", &frequency))
11.49 + return;
11.50 +
11.51 if (!get_port_and_pin(&clock_port, &clock_pin))
11.52 return;
11.53
11.54 @@ -1035,13 +1055,32 @@
11.55 if (!get_port_and_pin(&enable_port, &enable_pin))
11.56 return;
11.57
11.58 - if (!read_number("Frequency", &frequency))
11.59 - return;
11.60 + if (!get_port_and_pin(&control_port, &control_pin))
11.61 + control_chip = NULL;
11.62 + else
11.63 + control_chip = gpio[control_port];
11.64
11.65 - spi_channels[num] = spi_get_channel_gpio(gpio[clock_port], clock_pin,
11.66 + spi_channels[num] = spi_get_channel_gpio(frequency,
11.67 + gpio[clock_port], clock_pin,
11.68 gpio[data_port], data_pin,
11.69 gpio[enable_port], enable_pin,
11.70 - frequency);
11.71 + control_chip, control_pin);
11.72 +}
11.73 +
11.74 +static void spi_control(int acquire)
11.75 +{
11.76 + unsigned int level;
11.77 + void *channel = get_channel(num_spi_channels, spi_channels, NULL);
11.78 +
11.79 + if (acquire)
11.80 + {
11.81 + if (!read_number("Level", &level))
11.82 + return;
11.83 +
11.84 + spi_acquire_control(channel, level);
11.85 + }
11.86 + else
11.87 + spi_release_control(channel);
11.88 }
11.89
11.90 static void spi_send_data_gpio(void)
11.91 @@ -1082,7 +1121,7 @@
11.92 while ((byte < 256) && read_encoded_number(NULL, "%2x", &value))
11.93 buffer[byte++] = value;
11.94
11.95 - spi_send(channel, byte, (uint8_t *) buffer, unit_size, char_size);
11.96 + spi_send_units(channel, byte, (uint8_t *) buffer, unit_size, char_size);
11.97 }
11.98
11.99 static void spi_transfer_data(void)
11.100 @@ -1235,8 +1274,12 @@
11.101 {
11.102 if (!strcmp(token, "l") || !strcmp(token, "list"))
11.103 list_channels(num_spi_channels, spi_channels);
11.104 + else if (!strcmp(token, "a") || !strcmp(token, "control-acquire"))
11.105 + spi_control(1);
11.106 + else if (!strcmp(token, "r") || !strcmp(token, "control-release"))
11.107 + spi_control(0);
11.108 else if (!strcmp(token, "c") || !strcmp(token, "channel"))
11.109 - new_spi_channel(spi);
11.110 + new_spi_channel(spi, gpio);
11.111 else if (!strcmp(token, "g") || !strcmp(token, "gpio") || !strcmp(token, "gpio-channel"))
11.112 new_spi_channel_gpio(gpio);
11.113 else if (!strcmp(token, "s") || !strcmp(token, "send"))
11.114 @@ -1246,7 +1289,7 @@
11.115 else if (!strcmp(token, "t") || !strcmp(token, "transfer"))
11.116 spi_transfer_data();
11.117 else
11.118 - printf("spi channel | gpio-channel | list | send | send-units | transfer\n");
11.119 + printf("spi channel | control-acquire | control-release | gpio-channel | list | send | send-units | transfer\n");
11.120 }
11.121 else
11.122 list_channels(num_spi_channels, spi_channels);
12.1 --- a/pkg/landfall-examples/hw_info/jz4780.c Tue Nov 07 19:20:32 2023 +0100
12.2 +++ b/pkg/landfall-examples/hw_info/jz4780.c Thu Nov 09 18:40:31 2023 +0100
12.3 @@ -29,10 +29,11 @@
12.4 #include <l4/devices/gpio-jz4780.h>
12.5 #include <l4/devices/i2c-jz4780.h>
12.6
12.7 -/* GPIO-based SPI can use arbitrary pins, whereas only the secondary header
12.8 - provides pins like GPC. */
12.9 +/* GPIO-based SPI can use arbitrary pins, whereas on the CI20 only the secondary
12.10 + header provides pins like GPC. */
12.11
12.12 #include <l4/devices/spi-gpio.h>
12.13 +#include <l4/devices/spi-hybrid.h>
12.14 #include <l4/devices/spi-jz4780.h>
12.15 #include "common.h"
12.16
12.17 @@ -337,35 +338,54 @@
12.18 return jz4780_spi_init(spi_start, start, end, cpm);
12.19 }
12.20
12.21 -void *spi_get_channel(void *spi, uint8_t num, void *channel, uint64_t frequency)
12.22 +void *spi_get_channel(void *spi, uint8_t num, void *channel, uint64_t frequency,
12.23 + void *control_chip, int control_pin, int control_alt_func)
12.24 {
12.25 - return jz4780_spi_get_channel(spi, num, channel, frequency);
12.26 + void *ch = jz4780_spi_get_channel(spi, num, channel, frequency);
12.27 +
12.28 + return spi_hybrid_get_channel(ch, control_chip, control_pin, control_alt_func);
12.29 }
12.30
12.31 -void *spi_get_channel_gpio(void *clock_chip, int clock_pin,
12.32 +void *spi_get_channel_gpio(uint64_t frequency,
12.33 + void *clock_chip, int clock_pin,
12.34 void *data_chip, int data_pin,
12.35 void *enable_chip, int enable_pin,
12.36 - uint64_t frequency)
12.37 + void *control_chip, int control_pin)
12.38 {
12.39 - return spi_gpio_get_channel(clock_chip, clock_pin, data_chip, data_pin,
12.40 - enable_chip, enable_pin, frequency);
12.41 + return spi_gpio_get_channel(frequency, clock_chip, clock_pin, data_chip,
12.42 + data_pin, enable_chip, enable_pin, control_chip,
12.43 + control_pin);
12.44 +}
12.45 +
12.46 +void spi_acquire_control(void *channel, int level)
12.47 +{
12.48 + spi_hybrid_acquire_control(channel, level);
12.49 }
12.50
12.51 -void spi_send(void *channel, int bytes, const uint8_t data[], uint8_t unit_size,
12.52 - uint8_t char_size)
12.53 +void spi_release_control(void *channel)
12.54 {
12.55 - jz4780_spi_send(channel, bytes, data, unit_size, char_size);
12.56 + spi_hybrid_release_control(channel);
12.57 }
12.58
12.59 -void spi_send_gpio(void *channel, int bytes, const uint8_t data[])
12.60 +void spi_send_gpio(void *channel, uint32_t bytes, const uint8_t data[])
12.61 {
12.62 spi_gpio_send(channel, bytes, data);
12.63 }
12.64
12.65 +void spi_send_units(void *channel, uint32_t bytes, const uint8_t data[],
12.66 + uint8_t unit_size, uint8_t char_size)
12.67 +{
12.68 + jz4780_spi_send_units(channel, bytes, data, unit_size, char_size);
12.69 +}
12.70 +
12.71 uint32_t spi_transfer(void *channel, l4re_dma_space_dma_addr_t paddr,
12.72 uint32_t count, uint8_t unit_size, uint8_t char_size)
12.73 {
12.74 - return jz4780_spi_transfer(channel, paddr, count, unit_size, char_size);
12.75 + /* Transfer is not supported by the common interface. */
12.76 +
12.77 + void *ch = spi_hybrid_get_raw_channel(channel);
12.78 +
12.79 + return jz4780_spi_transfer(ch, paddr, count, unit_size, char_size);
12.80 }
12.81
12.82
13.1 --- a/pkg/landfall-examples/hw_info/x1600.c Tue Nov 07 19:20:32 2023 +0100
13.2 +++ b/pkg/landfall-examples/hw_info/x1600.c Thu Nov 09 18:40:31 2023 +0100
13.3 @@ -25,6 +25,7 @@
13.4 #include <l4/devices/gpio-x1600.h>
13.5 #include <l4/devices/i2c-x1600.h>
13.6 #include <l4/devices/spi-gpio.h>
13.7 +// #include <l4/devices/spi-hybrid.h>
13.8 #include "common.h"
13.9
13.10
13.11 @@ -329,32 +330,55 @@
13.12 return NULL;
13.13 }
13.14
13.15 -void *spi_get_channel(void *spi, uint8_t num, void *channel, uint64_t frequency)
13.16 +void *spi_get_channel(void *spi, uint8_t num, void *channel, uint64_t frequency,
13.17 + void *control_chip, int control_pin, int control_alt_func)
13.18 {
13.19 + /* NOTE: Initialisation of a hybrid channel to be supported. */
13.20 +
13.21 (void) spi; (void) num; (void) channel; (void) frequency;
13.22 + (void) control_chip; (void) control_pin; (void) control_alt_func;
13.23 return NULL;
13.24 }
13.25
13.26 -void *spi_get_channel_gpio(void *clock_chip, int clock_pin,
13.27 +void *spi_get_channel_gpio(uint64_t frequency,
13.28 + void *clock_chip, int clock_pin,
13.29 void *data_chip, int data_pin,
13.30 void *enable_chip, int enable_pin,
13.31 - uint64_t frequency)
13.32 + void *control_chip, int control_pin)
13.33 {
13.34 - return spi_gpio_get_channel(clock_chip, clock_pin, data_chip, data_pin, enable_chip, enable_pin, frequency);
13.35 + return spi_gpio_get_channel(frequency, clock_chip, clock_pin, data_chip,
13.36 + data_pin, enable_chip, enable_pin, control_chip,
13.37 + control_pin);
13.38 +}
13.39 +
13.40 +void spi_acquire_control(void *channel, int level)
13.41 +{
13.42 + /* NOTE: Not yet supported. */
13.43 +
13.44 + (void) channel; (void) level;
13.45 + // spi_hybrid_acquire_control(channel, level);
13.46 }
13.47
13.48 -void spi_send(void *channel, int bytes, const uint8_t data[], uint8_t unit_size,
13.49 - uint8_t char_size)
13.50 +void spi_release_control(void *channel)
13.51 +{
13.52 + /* NOTE: Not yet supported. */
13.53 +
13.54 + (void) channel;
13.55 + // spi_hybrid_release_control(channel);
13.56 +}
13.57 +
13.58 +void spi_send_gpio(void *channel, uint32_t bytes, const uint8_t data[])
13.59 +{
13.60 + spi_gpio_send(channel, bytes, data);
13.61 +}
13.62 +
13.63 +void spi_send_units(void *channel, uint32_t bytes, const uint8_t data[], uint8_t unit_size,
13.64 + uint8_t char_size)
13.65 {
13.66 /* NOTE: Not yet supported. */
13.67
13.68 (void) channel; (void) bytes; (void) data; (void) unit_size; (void) char_size;
13.69 - // x1600_spi_send(channel, bytes, data, unit_size, char_size);
13.70 -}
13.71 -
13.72 -void spi_send_gpio(void *channel, int bytes, const uint8_t data[])
13.73 -{
13.74 - spi_gpio_send(channel, bytes, data);
13.75 + // x1600_spi_send_units(channel, bytes, data, unit_size, char_size);
13.76 }
13.77
13.78 uint32_t spi_transfer(void *channel, l4re_dma_space_dma_addr_t paddr,