From c4dba395487a9d674ab8dbb3c87966d8a29f1dc7 Mon Sep 17 00:00:00 2001 From: Elias Speinle Date: Wed, 21 Aug 2024 12:19:55 +0200 Subject: [PATCH] drivers: fpga: add driver for renesas slg471X5 add driver for renesas slg471X5 Signed-off-by: Elias Speinle --- drivers/fpga/CMakeLists.txt | 1 + drivers/fpga/Kconfig | 1 + drivers/fpga/Kconfig.slg471x5 | 10 ++ drivers/fpga/fpga_slg471x5.c | 204 ++++++++++++++++++++++++ dts/bindings/fpga/renesas,slg47105.yaml | 8 + dts/bindings/fpga/renesas,slg47115.yaml | 8 + dts/bindings/fpga/renesas,slg471x5.yaml | 15 ++ 7 files changed, 247 insertions(+) create mode 100644 drivers/fpga/Kconfig.slg471x5 create mode 100644 drivers/fpga/fpga_slg471x5.c create mode 100644 dts/bindings/fpga/renesas,slg47105.yaml create mode 100644 dts/bindings/fpga/renesas,slg47115.yaml create mode 100644 dts/bindings/fpga/renesas,slg471x5.yaml diff --git a/drivers/fpga/CMakeLists.txt b/drivers/fpga/CMakeLists.txt index 8a8f17d1fe9..2b449446ed5 100644 --- a/drivers/fpga/CMakeLists.txt +++ b/drivers/fpga/CMakeLists.txt @@ -9,3 +9,4 @@ zephyr_library_sources_ifdef(CONFIG_EOS_S3_FPGA fpga_eos_s3.c) zephyr_library_sources_ifdef(CONFIG_ICE40_FPGA fpga_ice40.c) zephyr_library_sources_ifdef(CONFIG_MPFS_FPGA fpga_mpfs.c) zephyr_library_sources_ifdef(CONFIG_ZYNQMP_FPGA fpga_zynqmp.c) +zephyr_library_sources_ifdef(CONFIG_SLG471X5_FPGA fpga_slg471x5.c) diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index 2a6a2885c32..2677dd94d12 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -31,5 +31,6 @@ source "drivers/fpga/Kconfig.eos_s3" source "drivers/fpga/Kconfig.ice40" source "drivers/fpga/Kconfig.mpfs" source "drivers/fpga/Kconfig.zynqmp" +source "drivers/fpga/Kconfig.slg471x5" endif # FPGA diff --git a/drivers/fpga/Kconfig.slg471x5 b/drivers/fpga/Kconfig.slg471x5 new file mode 100644 index 00000000000..db770f683e7 --- /dev/null +++ b/drivers/fpga/Kconfig.slg471x5 @@ -0,0 +1,10 @@ +# Copyright 2024 Vogl Electronic GmbH +# SPDX-License-Identifier: Apache-2.0 + +config SLG471X5_FPGA + bool "Renesas SLG47105/SLG47115 GreenPAK Configurable Mixed-Signal IC" + default y + depends on DT_HAS_RENESAS_SLG47105_ENABLED || DT_HAS_RENESAS_SLG47115_ENABLED + select SPI + help + Enable Renesas SLG47105/SLG47115 driver support. diff --git a/drivers/fpga/fpga_slg471x5.c b/drivers/fpga/fpga_slg471x5.c new file mode 100644 index 00000000000..f27128a33df --- /dev/null +++ b/drivers/fpga/fpga_slg471x5.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2024 Vogl Electronic GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include +#include + +LOG_MODULE_REGISTER(fpga_slg471x5); + +#define SLG471X5_NREG 256 + +#define SLG471X5_I2C_RST_REG 0xF5U +#define SLG471X5_I2C_RST_BIT BIT(0) + +#define SLG471X5_ADDR_UNCONFIGURED 0x00U + +/* + * mem_region_t - Memory Region + * + * @addr starting address of memory region + * @len size of memory region + */ +typedef union { + uint16_t mem_region; + struct { + uint8_t addr; + uint8_t len; + } __packed; +} mem_region_t; + +struct fpga_slg471x5_data { + bool loaded; + struct k_spinlock lock; +}; + +struct fpga_slg471x5_config { + struct i2c_dt_spec bus; + mem_region_t *verify_list; + int verify_list_len; + bool try_unconfigured; +}; + +static enum FPGA_status fpga_slg471x5_get_status(const struct device *dev) +{ + enum FPGA_status status; + k_spinlock_key_t key; + struct fpga_slg471x5_data *data = dev->data; + + key = k_spin_lock(&data->lock); + + if (data->loaded) { + status = FPGA_STATUS_ACTIVE; + } else { + status = FPGA_STATUS_INACTIVE; + } + + k_spin_unlock(&data->lock, key); + + return status; +} + +static int fpga_slg471x5_verify(const struct device *dev, uint8_t *img, uint32_t img_size) +{ + const struct fpga_slg471x5_config *config = dev->config; + uint8_t buf[SLG471X5_NREG] = {0}, addr, len; + int i; + + i2c_read_dt(&config->bus, buf, SLG471X5_NREG); + + for (i = 0; i < config->verify_list_len; i++) { + addr = config->verify_list[i].addr; + len = config->verify_list[i].len; + if (memcmp(&img[addr], &buf[addr], len) != 0) { + return -EIO; + } + } + + return 0; +} + +static int fpga_slg471x5_load(const struct device *dev, uint32_t *image_ptr, uint32_t img_size) +{ + const struct fpga_slg471x5_config *config = dev->config; + struct fpga_slg471x5_data *data = dev->data; + uint8_t buf[SLG471X5_NREG + 1]; + int ret; + + if (img_size > SLG471X5_NREG) { + img_size = SLG471X5_NREG; + } + + buf[0] = 0; + memcpy(buf + 1, image_ptr, img_size); + + if (config->try_unconfigured) { + ret = i2c_write(config->bus.bus, buf, img_size + 1, SLG471X5_ADDR_UNCONFIGURED); + if (ret == 0) { + ret = fpga_slg471x5_verify(dev, buf + 1, img_size); + if (ret == 0) { + data->loaded = true; + return 0; + } + } + } + + ret = i2c_write_dt(&config->bus, buf, img_size + 1); + if (ret < 0) { + LOG_ERR("Loading bitstream failed"); + return ret; + } + + ret = fpga_slg471x5_verify(dev, buf + 1, img_size); + if (ret < 0) { + LOG_ERR("Verification failed"); + return ret; + } + + data->loaded = true; + + return 0; +} + +static int fpga_slg471x5_reset(const struct device *dev) +{ + const struct fpga_slg471x5_config *config = dev->config; + struct fpga_slg471x5_data *data = dev->data; + int ret; + + ret = i2c_reg_update_byte_dt(&config->bus, SLG471X5_I2C_RST_REG, SLG471X5_I2C_RST_BIT, + SLG471X5_I2C_RST_BIT); + if (ret < 0) { + return ret; + } + + data->loaded = false; + + return 0; +} + +static const struct fpga_driver_api fpga_slg471x5_api = { + .get_status = fpga_slg471x5_get_status, + .reset = fpga_slg471x5_reset, + .load = fpga_slg471x5_load, +}; + +static int fpga_slg471x5_init(const struct device *dev) +{ + const struct fpga_slg471x5_config *config = dev->config; + + if (!i2c_is_ready_dt(&config->bus)) { + LOG_ERR("I2C bus %s not ready", config->bus.bus->name); + return -ENODEV; + } + + return 0; +} + +#define SLG471X5_INIT(type, inst) \ + static struct fpga_slg471x5_data fpga_slg##type##_data_##inst; \ + \ + static mem_region_t fpga_slg##type##_verify_list[] = FPGA_SLG##type##_VERIFY_LIST; \ + \ + static const struct fpga_slg471x5_config fpga_slg##type##_config_##inst = { \ + .bus = I2C_DT_SPEC_INST_GET(inst), \ + .verify_list = fpga_slg##type##_verify_list, \ + .verify_list_len = sizeof(fpga_slg##type##_verify_list) / sizeof(mem_region_t), \ + .try_unconfigured = DT_INST_NODE_HAS_PROP(inst, try_unconfigured), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, fpga_slg471x5_init, NULL, &fpga_slg##type##_data_##inst, \ + &fpga_slg##type##_config_##inst, POST_KERNEL, \ + CONFIG_FPGA_INIT_PRIORITY, &fpga_slg471x5_api) + +#define FPGA_SLG47105_VERIFY_LIST \ + { \ + {.addr = 0x00, .len = 0x47}, \ + {.addr = 0x4C, .len = 0x01}, \ + {.addr = 0xFD, .len = 0x01}, \ + } + +#define SLG47105_INIT(inst) SLG471X5_INIT(47105, inst) +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT renesas_slg47105 +DT_INST_FOREACH_STATUS_OKAY(SLG47105_INIT) + +#define FPGA_SLG47115_VERIFY_LIST \ + { \ + {.addr = 0x00, .len = 0x47}, \ + {.addr = 0x4C, .len = 0x01}, \ + {.addr = 0xFD, .len = 0x01}, \ + } + +#define SLG47115_INIT(inst) SLG471X5_INIT(47115, inst) +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT renesas_slg47115 +DT_INST_FOREACH_STATUS_OKAY(SLG47115_INIT) diff --git a/dts/bindings/fpga/renesas,slg47105.yaml b/dts/bindings/fpga/renesas,slg47105.yaml new file mode 100644 index 00000000000..4a4f49994ae --- /dev/null +++ b/dts/bindings/fpga/renesas,slg47105.yaml @@ -0,0 +1,8 @@ +# Copyright 2024 Vogl Electronic GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas SLG47105 GreenPAK Configurable Mixed-Signal IC + +compatible: "renesas,slg47105" + +include: renesas,slg471x5.yaml diff --git a/dts/bindings/fpga/renesas,slg47115.yaml b/dts/bindings/fpga/renesas,slg47115.yaml new file mode 100644 index 00000000000..5e58c7e2014 --- /dev/null +++ b/dts/bindings/fpga/renesas,slg47115.yaml @@ -0,0 +1,8 @@ +# Copyright 2024 Vogl Electronic GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas SLG47115 GreenPAK Configurable Mixed-Signal IC + +compatible: "renesas,slg47115" + +include: renesas,slg471x5.yaml diff --git a/dts/bindings/fpga/renesas,slg471x5.yaml b/dts/bindings/fpga/renesas,slg471x5.yaml new file mode 100644 index 00000000000..7b5ffef86ab --- /dev/null +++ b/dts/bindings/fpga/renesas,slg471x5.yaml @@ -0,0 +1,15 @@ +# Copyright 2024 Vogl Electronic GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas SLG47105/SLG47115 GreenPAK Configurable Mixed-Signal IC + +compatible: "renesas,slg471x5" + +include: i2c-device.yaml + +properties: + try-unconfigured: + type: boolean + description: | + If selected driver will test transaction on address 0x0 first, before + trying address defined in devicetree.