mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
FPGA Manager changes for 7.2-rc1
- Wentao fixes use-after-free issue in of-fpga-region - Phil adds the of matching for Altera ts73xx fpga driver - Ian adds Efinix FPGA SPI programming driver - Andy fixes several minor issues for Lattice FPGA driver - Manish converts dt-bindings to YAML schema for several Altera devices - Sebastian fixes several minor issues for Intel DFL & Microchip FPGAs All patches have been reviewed on the mailing list, and have been in the last linux-next releases (as part of our for-next branch). Signed-off-by: Xu Yilun <yilun.xu@intel.com> -----BEGIN PGP SIGNATURE----- iIkEABYIADEWIQSgSJpClIeaArXyudb8twOBpKCM2gUCaiD6nRMceWlsdW4ueHVA aW50ZWwuY29tAAoJEPy3A4GkoIzaRK0BAL/tryz4yA9F/7hO5gmTT2ke+LfWn/pH 7NmskFCd76svAQDSGvndrW6rquHdoD7A5ZTwY7MRY1NlFdoZCfUfxtt/Ag== =/REE -----END PGP SIGNATURE----- Merge tag 'fpga-for-7.2-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/fpga/linux-fpga into char-misc-next Xu writes: FPGA Manager changes for 7.2-rc1 - Wentao fixes use-after-free issue in of-fpga-region - Phil adds the of matching for Altera ts73xx fpga driver - Ian adds Efinix FPGA SPI programming driver - Andy fixes several minor issues for Lattice FPGA driver - Manish converts dt-bindings to YAML schema for several Altera devices - Sebastian fixes several minor issues for Intel DFL & Microchip FPGAs All patches have been reviewed on the mailing list, and have been in the last linux-next releases (as part of our for-next branch). Signed-off-by: Xu Yilun <yilun.xu@intel.com> * tag 'fpga-for-7.2-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/fpga/linux-fpga: fpga: microchip-spi: fix zero header_size OOB read in mpf_ops_parse_header() fpga: dfl-afu: validate DMA mapping length in afu_dma_map_region() fpga: dfl: add bounds check in dfh_get_param_size() dt-bindings: fpga: altr,socfpga-fpga-mgr: convert to DT schema dt-bindings: fpga: altr,a10-pr-ip: convert to DT schema fpga: lattice-sysconfig-spi: simplify with spi_get_device_match_data() fpga: lattice-sysconfig-spi: Don't use "proxy" headers fpga: lattice-sysconfig-spi: Drop of_match_ptr() protection fpga: lattice-sysconfig-spi: Fix the terminator entries in ID tables fpga-mgr: Add Efinix SPI programming driver dt-bindings: fpga: Add Efinix SPI programming bindings dt-bindings: vendor-prefix: Add prefix for Efinix, Inc. fpga: ts73xx-fpga: add OF match table for device tree probing dt-bindings: fpga: Add Technologic Systems TS-7300 FPGA Manager fpga: region: fix use-after-free in child_regions_with_firmware()
This commit is contained in:
commit
b23338788b
|
|
@ -1,12 +0,0 @@
|
|||
Altera Arria10 Partial Reconfiguration IP
|
||||
|
||||
Required properties:
|
||||
- compatible : should contain "altr,a10-pr-ip"
|
||||
- reg : base address and size for memory mapped io.
|
||||
|
||||
Example:
|
||||
|
||||
fpga_mgr: fpga-mgr@ff20c000 {
|
||||
compatible = "altr,a10-pr-ip";
|
||||
reg = <0xff20c000 0x10>;
|
||||
};
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
Altera SOCFPGA FPGA Manager
|
||||
|
||||
Required properties:
|
||||
- compatible : should contain "altr,socfpga-fpga-mgr"
|
||||
- reg : base address and size for memory mapped io.
|
||||
- The first index is for FPGA manager register access.
|
||||
- The second index is for writing FPGA configuration data.
|
||||
- interrupts : interrupt for the FPGA Manager device.
|
||||
|
||||
Example:
|
||||
|
||||
hps_0_fpgamgr: fpgamgr@ff706000 {
|
||||
compatible = "altr,socfpga-fpga-mgr";
|
||||
reg = <0xFF706000 0x1000
|
||||
0xFFB90000 0x1000>;
|
||||
interrupts = <0 175 4>;
|
||||
};
|
||||
34
Documentation/devicetree/bindings/fpga/altr,a10-pr-ip.yaml
Normal file
34
Documentation/devicetree/bindings/fpga/altr,a10-pr-ip.yaml
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/fpga/altr,a10-pr-ip.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Altera Arria10 Partial Reconfiguration IP
|
||||
|
||||
maintainers:
|
||||
- Matthew Gerlach <matthew.gerlach@linux.intel.com>
|
||||
|
||||
description:
|
||||
The Altera Arria 10 Partial Reconfiguration IP core allows the host
|
||||
processor to perform partial reconfiguration of the FPGA fabric.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: altr,a10-pr-ip
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
fpga-mgr@ff20c000 {
|
||||
compatible = "altr,a10-pr-ip";
|
||||
reg = <0xff20c000 0x10>;
|
||||
};
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/fpga/altr,socfpga-fpga-mgr.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Altera SOCFPGA FPGA Manager
|
||||
|
||||
maintainers:
|
||||
- Steffen Trumtrar <s.trumtrar@pengutronix.de>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: altr,socfpga-fpga-mgr
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: FPGA manager register access
|
||||
- description: Writing FPGA configuration data
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
fpgamgr@ff706000 {
|
||||
compatible = "altr,socfpga-fpga-mgr";
|
||||
reg = <0xff706000 0x1000>,
|
||||
<0xffb90000 0x1000>;
|
||||
interrupts = <0 175 4>;
|
||||
};
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/fpga/efinix,trion-config.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Efinix SPI FPGA Manager
|
||||
|
||||
maintainers:
|
||||
- Ian Dannapel <iansdannapel@gmail.com>
|
||||
|
||||
description: |
|
||||
Efinix FPGAs (Trion, Topaz, and Titanium families) support loading bitstreams
|
||||
through "SPI Passive Mode".
|
||||
Additional pin hogs for bus width configuration should be set
|
||||
elsewhere, if necessary.
|
||||
|
||||
References:
|
||||
- https://www.efinixinc.com/docs/an006-configuring-trion-fpgas-v6.3.pdf
|
||||
- https://www.efinixinc.com/docs/an033-configuring-titanium-fpgas-v2.8.pdf
|
||||
- https://www.efinixinc.com/docs/an061-configuring-topaz-fpgas-v1.1.pdf
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- efinix,titanium-config
|
||||
- efinix,topaz-config
|
||||
- const: efinix,trion-config
|
||||
- const: efinix,trion-config
|
||||
|
||||
spi-cpha: true
|
||||
|
||||
spi-cpol: true
|
||||
|
||||
spi-max-frequency:
|
||||
maximum: 25000000
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
reset-gpios:
|
||||
description:
|
||||
reset and re-configuration trigger pin (low active)
|
||||
maxItems: 1
|
||||
|
||||
cdone-gpios:
|
||||
description:
|
||||
optional configuration done status pin (high active)
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reset-gpios
|
||||
- spi-cpha
|
||||
- spi-cpol
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
|
||||
fpga-mgr@0 {
|
||||
compatible = "efinix,trion-config";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <25000000>;
|
||||
spi-cpha;
|
||||
spi-cpol;
|
||||
reset-gpios = <&gpio4 17 GPIO_ACTIVE_LOW>;
|
||||
cdone-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
|
||||
fpga-mgr@0 {
|
||||
compatible = "efinix,titanium-config", "efinix,trion-config";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <25000000>;
|
||||
spi-cpha;
|
||||
spi-cpol;
|
||||
reset-gpios = <&gpio4 17 GPIO_ACTIVE_LOW>;
|
||||
cdone-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
||||
...
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/fpga/technologic,ts7300-fpga.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Technologic Systems TS-7300 FPGA Manager
|
||||
|
||||
maintainers:
|
||||
- Florian Fainelli <f.fainelli@gmail.com>
|
||||
|
||||
description:
|
||||
FPGA manager for the Altera Cyclone II FPGA on Technologic Systems
|
||||
TS-7300 board. The FPGA is programmed via the memory-mapped interface
|
||||
implemented in the CPLD.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: technologic,ts7300-fpga
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
fpga-mgr@13c00000 {
|
||||
compatible = "technologic,ts7300-fpga";
|
||||
reg = <0x13c00000 0x2>;
|
||||
};
|
||||
...
|
||||
|
|
@ -489,6 +489,8 @@ patternProperties:
|
|||
description: Emtop Embedded Solutions
|
||||
"^eeti,.*":
|
||||
description: eGalax_eMPIA Technology Inc
|
||||
"^efinix,.*":
|
||||
description: Efinix, Inc.
|
||||
"^egnite,.*":
|
||||
description: egnite GmbH
|
||||
"^einfochips,.*":
|
||||
|
|
|
|||
|
|
@ -288,6 +288,13 @@ config FPGA_MGR_LATTICE_SYSCONFIG_SPI
|
|||
FPGA manager driver support for Lattice FPGAs programming over slave
|
||||
SPI sysCONFIG interface.
|
||||
|
||||
config FPGA_MGR_EFINIX_SPI
|
||||
tristate "Efinix FPGA configuration over SPI"
|
||||
depends on SPI
|
||||
help
|
||||
FPGA manager driver support for Efinix FPGAs configuration over SPI
|
||||
(passive mode only).
|
||||
|
||||
source "drivers/fpga/tests/Kconfig"
|
||||
|
||||
endif # FPGA
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ obj-$(CONFIG_FPGA_MGR_LATTICE_SYSCONFIG) += lattice-sysconfig.o
|
|||
obj-$(CONFIG_FPGA_MGR_LATTICE_SYSCONFIG_SPI) += lattice-sysconfig-spi.o
|
||||
obj-$(CONFIG_ALTERA_PR_IP_CORE) += altera-pr-ip-core.o
|
||||
obj-$(CONFIG_ALTERA_PR_IP_CORE_PLAT) += altera-pr-ip-core-plat.o
|
||||
obj-$(CONFIG_FPGA_MGR_EFINIX_SPI) += efinix-spi.o
|
||||
|
||||
# FPGA Secure Update Drivers
|
||||
obj-$(CONFIG_FPGA_M10_BMC_SEC_UPDATE) += intel-m10-bmc-sec-update.o
|
||||
|
|
|
|||
|
|
@ -723,6 +723,9 @@ afu_ioctl_dma_map(struct dfl_feature_dev_data *fdata, void __user *arg)
|
|||
if (map.argsz < minsz || map.flags)
|
||||
return -EINVAL;
|
||||
|
||||
if (map.length >> PAGE_SHIFT > (u64)INT_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
ret = afu_dma_map_region(fdata, map.user_addr, map.length, &map.iova);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -1132,6 +1132,8 @@ static int dfh_get_param_size(void __iomem *dfh_base, resource_size_t max)
|
|||
return -EINVAL;
|
||||
|
||||
size += next * sizeof(u64);
|
||||
if (size > max)
|
||||
return -EINVAL;
|
||||
|
||||
if (FIELD_GET(DFHv1_PARAM_HDR_NEXT_EOP, v))
|
||||
return size;
|
||||
|
|
|
|||
260
drivers/fpga/efinix-spi.c
Normal file
260
drivers/fpga/efinix-spi.c
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* FPGA Manager Driver for Efinix
|
||||
*
|
||||
* Copyright (C) 2025 iris-GmbH infrared & intelligent sensors
|
||||
*
|
||||
* Ian Dannapel <iansdannapel@gmail.com>
|
||||
*
|
||||
* Load Efinix FPGA firmware over SPI using the serial configuration interface.
|
||||
*
|
||||
* Note: Only passive mode (host initiates transfer) is currently supported.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/fpga/fpga-mgr.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
/*
|
||||
* 13 dummy bytes generate 104 SPI clock cycles (8 bits each).
|
||||
* Used to meet the requirement for >100 clock cycles idle sequence.
|
||||
*/
|
||||
#define EFINIX_SPI_IDLE_CYCLES_BYTES 13
|
||||
|
||||
/*
|
||||
* tDMIN: Minimum time between deassertion of CRESET_N to first
|
||||
* valid configuration data. (32 µs)
|
||||
*/
|
||||
#define EFINIX_TDMIN_US_MIN 35
|
||||
#define EFINIX_TDMIN_US_MAX 40
|
||||
|
||||
/*
|
||||
* tCRESET_N: Minimum CRESET_N low pulse width required to
|
||||
* trigger re-configuration. (320 ns)
|
||||
*/
|
||||
#define EFINIX_TCRESETN_DELAY_MIN_US 1
|
||||
#define EFINIX_TCRESETN_DELAY_MAX_US 2
|
||||
|
||||
/*
|
||||
* tUSER: Minimum configuration duration after CDONE goes high
|
||||
* before entering user mode. (25 µs)
|
||||
*/
|
||||
#define EFINIX_TUSER_US_MIN 30
|
||||
#define EFINIX_TUSER_US_MAX 35
|
||||
|
||||
struct efinix_spi_conf {
|
||||
struct spi_device *spi;
|
||||
struct gpio_desc *cdone;
|
||||
struct gpio_desc *reset;
|
||||
};
|
||||
|
||||
static void efinix_spi_reset(struct efinix_spi_conf *conf)
|
||||
{
|
||||
gpiod_set_value(conf->reset, 1);
|
||||
usleep_range(EFINIX_TCRESETN_DELAY_MIN_US, EFINIX_TCRESETN_DELAY_MAX_US);
|
||||
gpiod_set_value(conf->reset, 0);
|
||||
usleep_range(EFINIX_TDMIN_US_MIN, EFINIX_TDMIN_US_MAX);
|
||||
}
|
||||
|
||||
static enum fpga_mgr_states efinix_spi_state(struct fpga_manager *mgr)
|
||||
{
|
||||
struct efinix_spi_conf *conf = mgr->priv;
|
||||
|
||||
if (conf->cdone && gpiod_get_value(conf->cdone) == 1)
|
||||
return FPGA_MGR_STATE_OPERATING;
|
||||
|
||||
return FPGA_MGR_STATE_UNKNOWN;
|
||||
}
|
||||
|
||||
static int efinix_spi_write_init(struct fpga_manager *mgr,
|
||||
struct fpga_image_info *info,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct efinix_spi_conf *conf = mgr->priv;
|
||||
struct spi_transfer assert_cs = {
|
||||
/* Keep CS asserted across configuration. */
|
||||
.cs_change = 1,
|
||||
};
|
||||
struct spi_message message;
|
||||
int ret;
|
||||
|
||||
if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
|
||||
dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/*
|
||||
* Efinix passive SPI configuration requires chip select to stay
|
||||
* asserted from reset until the bitstream is fully clocked in.
|
||||
* Lock the SPI bus so no other device can toggle CS between the
|
||||
* reset pulse and the write/complete transfers.
|
||||
*/
|
||||
spi_bus_lock(conf->spi->controller);
|
||||
spi_message_init_with_transfers(&message, &assert_cs, 1);
|
||||
ret = spi_sync_locked(conf->spi, &message);
|
||||
if (ret) {
|
||||
spi_bus_unlock(conf->spi->controller);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Reset with CS asserted */
|
||||
efinix_spi_reset(conf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int efinix_spi_write(struct fpga_manager *mgr, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct spi_transfer write_xfer = {
|
||||
.tx_buf = buf,
|
||||
.len = count,
|
||||
.cs_change = 1,
|
||||
};
|
||||
struct efinix_spi_conf *conf = mgr->priv;
|
||||
struct spi_message message;
|
||||
int ret;
|
||||
|
||||
spi_message_init_with_transfers(&message, &write_xfer, 1);
|
||||
ret = spi_sync_locked(conf->spi, &message);
|
||||
if (ret) {
|
||||
dev_err(&mgr->dev, "SPI error in firmware write: %d\n", ret);
|
||||
spi_bus_unlock(conf->spi->controller);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int efinix_spi_write_complete(struct fpga_manager *mgr,
|
||||
struct fpga_image_info *info)
|
||||
{
|
||||
unsigned long timeout =
|
||||
jiffies + usecs_to_jiffies(info->config_complete_timeout_us);
|
||||
struct spi_transfer clk_cycles = {
|
||||
.len = EFINIX_SPI_IDLE_CYCLES_BYTES,
|
||||
/* Release CS after the trailing idle clocks are sent. */
|
||||
.cs_change = 0,
|
||||
};
|
||||
struct efinix_spi_conf *conf = mgr->priv;
|
||||
struct spi_message message;
|
||||
int done, ret;
|
||||
bool expired = false;
|
||||
u8 *dummy_buf;
|
||||
|
||||
dummy_buf = kzalloc(EFINIX_SPI_IDLE_CYCLES_BYTES, GFP_KERNEL);
|
||||
if (!dummy_buf) {
|
||||
ret = -ENOMEM;
|
||||
goto unlock_spi;
|
||||
}
|
||||
|
||||
/*
|
||||
* Keep the bus locked while sending the trailing idle clocks, then
|
||||
* let this final transfer deassert CS to terminate configuration.
|
||||
*/
|
||||
clk_cycles.tx_buf = dummy_buf;
|
||||
spi_message_init_with_transfers(&message, &clk_cycles, 1);
|
||||
ret = spi_sync_locked(conf->spi, &message);
|
||||
if (ret) {
|
||||
dev_err(&mgr->dev, "SPI error in write complete: %d\n", ret);
|
||||
goto free_buf;
|
||||
}
|
||||
|
||||
if (conf->cdone) {
|
||||
while (!expired) {
|
||||
done = gpiod_get_value(conf->cdone);
|
||||
if (done < 0) {
|
||||
ret = done;
|
||||
goto free_buf;
|
||||
}
|
||||
if (done)
|
||||
break;
|
||||
|
||||
usleep_range(10, 20);
|
||||
expired = time_after(jiffies, timeout);
|
||||
}
|
||||
|
||||
if (expired) {
|
||||
dev_err(&mgr->dev, "Timeout waiting for CDONE\n");
|
||||
ret = -ETIMEDOUT;
|
||||
goto free_buf;
|
||||
}
|
||||
}
|
||||
|
||||
usleep_range(EFINIX_TUSER_US_MIN, EFINIX_TUSER_US_MAX);
|
||||
|
||||
free_buf:
|
||||
kfree(dummy_buf);
|
||||
unlock_spi:
|
||||
spi_bus_unlock(conf->spi->controller);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct fpga_manager_ops efinix_spi_ops = {
|
||||
.state = efinix_spi_state,
|
||||
.write_init = efinix_spi_write_init,
|
||||
.write = efinix_spi_write,
|
||||
.write_complete = efinix_spi_write_complete,
|
||||
};
|
||||
|
||||
static int efinix_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct efinix_spi_conf *conf;
|
||||
struct fpga_manager *mgr;
|
||||
|
||||
if (!(spi->mode & SPI_CPHA) || !(spi->mode & SPI_CPOL))
|
||||
return dev_err_probe(&spi->dev, -EINVAL,
|
||||
"Unsupported SPI mode, set CPHA and CPOL\n");
|
||||
|
||||
conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL);
|
||||
if (!conf)
|
||||
return -ENOMEM;
|
||||
|
||||
conf->reset = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(conf->reset))
|
||||
return dev_err_probe(&spi->dev, PTR_ERR(conf->reset),
|
||||
"Failed to get RESET gpio\n");
|
||||
|
||||
conf->cdone = devm_gpiod_get_optional(&spi->dev, "cdone", GPIOD_IN);
|
||||
if (IS_ERR(conf->cdone))
|
||||
return dev_err_probe(&spi->dev, PTR_ERR(conf->cdone),
|
||||
"Failed to get CDONE gpio\n");
|
||||
|
||||
conf->spi = spi;
|
||||
|
||||
mgr = devm_fpga_mgr_register(&spi->dev,
|
||||
"Efinix FPGA Manager",
|
||||
&efinix_spi_ops, conf);
|
||||
|
||||
return PTR_ERR_OR_ZERO(mgr);
|
||||
}
|
||||
|
||||
static const struct of_device_id efinix_spi_of_match[] = {
|
||||
{ .compatible = "efinix,trion-config", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, efinix_spi_of_match);
|
||||
|
||||
static const struct spi_device_id efinix_ids[] = {
|
||||
{ "trion-config", 0 },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, efinix_ids);
|
||||
|
||||
static struct spi_driver efinix_spi_driver = {
|
||||
.driver = {
|
||||
.name = "efinix-spi",
|
||||
.of_match_table = efinix_spi_of_match,
|
||||
},
|
||||
.probe = efinix_spi_probe,
|
||||
.id_table = efinix_ids,
|
||||
};
|
||||
|
||||
module_spi_driver(efinix_spi_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Ian Dannapel <iansdannapel@gmail.com>");
|
||||
MODULE_DESCRIPTION("Efinix FPGA SPI Programming Driver");
|
||||
|
|
@ -3,8 +3,14 @@
|
|||
* Lattice FPGA programming over slave SPI sysCONFIG interface.
|
||||
*/
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/dev_printk.h>
|
||||
#include <linux/device/devres.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "lattice-sysconfig.h"
|
||||
|
||||
|
|
@ -85,7 +91,6 @@ static int sysconfig_spi_bitstream_burst_complete(struct sysconfig_priv *priv)
|
|||
|
||||
static int sysconfig_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct spi_device_id *dev_id;
|
||||
struct device *dev = &spi->dev;
|
||||
struct sysconfig_priv *priv;
|
||||
const u32 *spi_max_speed;
|
||||
|
|
@ -94,15 +99,7 @@ static int sysconfig_spi_probe(struct spi_device *spi)
|
|||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
spi_max_speed = device_get_match_data(dev);
|
||||
if (!spi_max_speed) {
|
||||
dev_id = spi_get_device_id(spi);
|
||||
if (!dev_id)
|
||||
return -ENODEV;
|
||||
|
||||
spi_max_speed = (const u32 *)dev_id->driver_data;
|
||||
}
|
||||
|
||||
spi_max_speed = spi_get_device_match_data(spi);
|
||||
if (!spi_max_speed)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -125,26 +122,26 @@ static const struct spi_device_id sysconfig_spi_ids[] = {
|
|||
{
|
||||
.name = "sysconfig-ecp5",
|
||||
.driver_data = (kernel_ulong_t)&ecp5_spi_max_speed_hz,
|
||||
}, {},
|
||||
},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, sysconfig_spi_ids);
|
||||
|
||||
#if IS_ENABLED(CONFIG_OF)
|
||||
static const struct of_device_id sysconfig_of_ids[] = {
|
||||
{
|
||||
.compatible = "lattice,sysconfig-ecp5",
|
||||
.data = &ecp5_spi_max_speed_hz,
|
||||
}, {},
|
||||
},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sysconfig_of_ids);
|
||||
#endif /* IS_ENABLED(CONFIG_OF) */
|
||||
|
||||
static struct spi_driver lattice_sysconfig_driver = {
|
||||
.probe = sysconfig_spi_probe,
|
||||
.id_table = sysconfig_spi_ids,
|
||||
.driver = {
|
||||
.name = "lattice_sysconfig_spi_fpga_mgr",
|
||||
.of_match_table = of_match_ptr(sysconfig_of_ids),
|
||||
.of_match_table = sysconfig_of_ids,
|
||||
},
|
||||
};
|
||||
module_spi_driver(lattice_sysconfig_driver);
|
||||
|
|
|
|||
|
|
@ -116,6 +116,9 @@ static int mpf_ops_parse_header(struct fpga_manager *mgr,
|
|||
}
|
||||
|
||||
header_size = *(buf + MPF_HEADER_SIZE_OFFSET);
|
||||
if (!header_size)
|
||||
return -EINVAL;
|
||||
|
||||
if (header_size > count) {
|
||||
info->header_size = header_size;
|
||||
return -EAGAIN;
|
||||
|
|
|
|||
|
|
@ -168,11 +168,10 @@ static int child_regions_with_firmware(struct device_node *overlay)
|
|||
fpga_region_of_match);
|
||||
}
|
||||
|
||||
of_node_put(child_region);
|
||||
|
||||
if (ret)
|
||||
pr_err("firmware-name not allowed in child FPGA region: %pOF",
|
||||
child_region);
|
||||
of_node_put(child_region);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/iopoll.h>
|
||||
|
|
@ -119,9 +120,17 @@ static int ts73xx_fpga_probe(struct platform_device *pdev)
|
|||
return PTR_ERR_OR_ZERO(mgr);
|
||||
}
|
||||
|
||||
static const struct of_device_id ts73xx_fpga_of_match[] = {
|
||||
{ .compatible = "technologic,ts7300-fpga" },
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, ts73xx_fpga_of_match);
|
||||
|
||||
static struct platform_driver ts73xx_fpga_driver = {
|
||||
.driver = {
|
||||
.name = "ts73xx-fpga-mgr",
|
||||
.of_match_table = ts73xx_fpga_of_match,
|
||||
},
|
||||
.probe = ts73xx_fpga_probe,
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user