drivers: fpga: simplify load mode selection of iCE40

Replace the enum for load modes for the iCE40 with a boolean flag,
as there are only two options:
- SPI: default, which should be used whenever possible
- GPIO bitbang: workarorund, in case a low-end microcontroller is used

Signed-off-by: Benedikt Schmidt <benedikt.schmidt@embedded-solutions.at>
This commit is contained in:
Benedikt Schmidt 2024-11-04 14:14:04 +01:00 committed by Anas Nashif
commit 5aa835c66b
3 changed files with 10 additions and 30 deletions

View file

@ -42,14 +42,7 @@
* achieve the minimum 1 MHz clock rate for loading the iCE40 bistream. So * achieve the minimum 1 MHz clock rate for loading the iCE40 bistream. So
* in order to bitbang on lower-end microcontrollers, we actually require * in order to bitbang on lower-end microcontrollers, we actually require
* direct register access to the set and clear registers. * direct register access to the set and clear registers.
*
* With that, this driver is left with 2 possible modes of operation which
* are:
* - FPGA_ICE40_LOAD_MODE_SPI (for higher-end microcontrollers)
* - FPGA_ICE40_LOAD_MODE_GPIO (for lower-end microcontrollers)
*/ */
#define FPGA_ICE40_LOAD_MODE_SPI 0
#define FPGA_ICE40_LOAD_MODE_GPIO 1
/* /*
* Values in Hz, intentionally to be comparable with the spi-max-frequency * Values in Hz, intentionally to be comparable with the spi-max-frequency
@ -111,7 +104,7 @@ static void fpga_ice40_crc_to_str(uint32_t crc, char *s)
/* /*
* This is a calibrated delay loop used to achieve a 1 MHz SPI_CLK frequency * This is a calibrated delay loop used to achieve a 1 MHz SPI_CLK frequency
* with FPGA_ICE40_LOAD_MODE_GPIO. It is used both in fpga_ice40_send_clocks() * with the bitbang mode. It is used both in fpga_ice40_send_clocks()
* and fpga_ice40_spi_send_data(). * and fpga_ice40_spi_send_data().
* *
* Calibration is achieved via the mhz_delay_count device tree parameter. See * Calibration is achieved via the mhz_delay_count device tree parameter. See
@ -573,12 +566,8 @@ static int fpga_ice40_init(const struct device *dev)
#define FPGA_ICE40_GPIO_PINS(inst, name) (volatile gpio_port_pins_t *)DT_INST_PROP_OR(inst, name, 0) #define FPGA_ICE40_GPIO_PINS(inst, name) (volatile gpio_port_pins_t *)DT_INST_PROP_OR(inst, name, 0)
#define FPGA_ICE40_LOAD_MODE(inst) DT_INST_PROP(inst, load_mode)
#define FPGA_ICE40_LOAD_FUNC(inst) \ #define FPGA_ICE40_LOAD_FUNC(inst) \
(FPGA_ICE40_LOAD_MODE(inst) == FPGA_ICE40_LOAD_MODE_SPI \ (DT_INST_PROP(inst, load_mode_bitbang) ? fpga_ice40_load_gpio : fpga_ice40_load_spi)
? fpga_ice40_load_spi \
: (FPGA_ICE40_LOAD_MODE(inst) == FPGA_ICE40_LOAD_MODE_GPIO ? fpga_ice40_load_gpio \
: NULL))
#ifdef CONFIG_PINCTRL #ifdef CONFIG_PINCTRL
#define FPGA_ICE40_PINCTRL_CONFIG(inst) .pincfg = PINCTRL_DT_DEV_CONFIG_GET(DT_INST_PARENT(inst)), #define FPGA_ICE40_PINCTRL_CONFIG(inst) .pincfg = PINCTRL_DT_DEV_CONFIG_GET(DT_INST_PARENT(inst)),
@ -589,8 +578,6 @@ static int fpga_ice40_init(const struct device *dev)
#endif #endif
#define FPGA_ICE40_DEFINE(inst) \ #define FPGA_ICE40_DEFINE(inst) \
BUILD_ASSERT(FPGA_ICE40_LOAD_MODE(inst) == FPGA_ICE40_LOAD_MODE_SPI || \
FPGA_ICE40_LOAD_MODE(inst) == FPGA_ICE40_LOAD_MODE_GPIO); \
BUILD_ASSERT(FPGA_ICE40_BUS_FREQ(inst) >= FPGA_ICE40_SPI_HZ_MIN); \ BUILD_ASSERT(FPGA_ICE40_BUS_FREQ(inst) >= FPGA_ICE40_SPI_HZ_MIN); \
BUILD_ASSERT(FPGA_ICE40_BUS_FREQ(inst) <= FPGA_ICE40_SPI_HZ_MAX); \ BUILD_ASSERT(FPGA_ICE40_BUS_FREQ(inst) <= FPGA_ICE40_SPI_HZ_MAX); \
BUILD_ASSERT(FPGA_ICE40_CONFIG_DELAY_US(inst) >= FPGA_ICE40_CONFIG_DELAY_US_MIN); \ BUILD_ASSERT(FPGA_ICE40_CONFIG_DELAY_US(inst) >= FPGA_ICE40_CONFIG_DELAY_US_MIN); \

View file

@ -8,20 +8,14 @@ compatible: "lattice,ice40-fpga"
include: spi-device.yaml include: spi-device.yaml
properties: properties:
load-mode: load-mode-bitbang:
type: int type: boolean
required: true
description: | description: |
Configure the method used to load the bitstream. Select the bitbang mode for loading the bitstream into the FPGA.
The bitstream may be loaded via 2 separate methods: This is a workaround to meet the timing requirements fo the iCE40
0 := load the FPGA via SPI transfer on low-end microcontrollers.
1 := load the FPGA via bit-banged GPIO This option requires clk-gpios, pico-gpios, gpios-set-reg, and
Option 0 may be suitable for some high-end microcontrollers. gpios-clear-reg to be defined.
Option 1 is suitable for low-end microcontrollers. This option
requires clk-gpios, pico-gpios, gpios-set-reg, and gpios-clear-reg
to be defined.
Example usage:
load-mode = <0>;
cdone-gpios: cdone-gpios:
type: phandle-array type: phandle-array
required: true required: true

View file

@ -13,7 +13,7 @@ test_spi_fpga_ice40_gpio: ice40@0 {
reg = <0>; reg = <0>;
spi-max-frequency = <1000000>; spi-max-frequency = <1000000>;
load-mode = <0>; load-mode-bitbang;
cdone-gpios = <&test_gpio 0 0>; cdone-gpios = <&test_gpio 0 0>;
creset-gpios = <&test_gpio 0 0>; creset-gpios = <&test_gpio 0 0>;
config-delay-us = <3900>; config-delay-us = <3900>;
@ -26,7 +26,6 @@ test_spi_fpga_ice40_spi: ice40@1 {
reg = <1>; reg = <1>;
spi-max-frequency = <1000000>; spi-max-frequency = <1000000>;
load-mode = <1>;
cdone-gpios = <&test_gpio 0 0>; cdone-gpios = <&test_gpio 0 0>;
creset-gpios = <&test_gpio 0 0>; creset-gpios = <&test_gpio 0 0>;
clk-gpios = <&test_gpio 0 0>; clk-gpios = <&test_gpio 0 0>;