> Subject: [PATCH v3 4/4] fpga: dfl: add support for N3000 nios private feature > > This patch adds support for the nios handshake private feature on Intel > N3000 FPGA Card. This private feature provides a handshake interface to > FPGA NIOS firmware, which receives retimer configuration command from > host > and executes via an internal SPI master. When nios finished the > configuration, host takes over the ownership of the SPI master to control > an Intel MAX10 BMC Chip on the SPI bus. Maybe you can add some more description on what NIOS is here for people to understand this better. > > For NIOS firmware handshake part, this driver requests the retimer > configuration for NIOS with parameters from module param, and adds some > sysfs nodes for user to query NIOS state. > > For SPI part, this driver adds a spi-altera platform device as well as > the MAX10 BMC spi slave info. A spi-altera driver will be matched to > handle following the SPI work. > > Signed-off-by: Xu Yilun <yilun.xu@xxxxxxxxx> > Signed-off-by: Wu Hao <hao.wu@xxxxxxxxx> > Signed-off-by: Matthew Gerlach <matthew.gerlach@xxxxxxxxxxxxxxx> > Signed-off-by: Russ Weight <russell.h.weight@xxxxxxxxx> > Reviewed-by: Tom Rix <trix@xxxxxxxxxx> > --- > v3: Add the doc for this driver. > Minor fixes for comments from Tom. > --- > .../ABI/testing/sysfs-bus-dfl-devices-n3000-nios | 18 + > Documentation/fpga/dfl-n3000-nios.rst | 39 ++ > Documentation/fpga/index.rst | 1 + > drivers/fpga/Kconfig | 12 + > drivers/fpga/Makefile | 2 + > drivers/fpga/dfl-n3000-nios.c | 518 +++++++++++++++++++++ > 6 files changed, 590 insertions(+) > create mode 100644 Documentation/ABI/testing/sysfs-bus-dfl-devices- > n3000-nios > create mode 100644 Documentation/fpga/dfl-n3000-nios.rst > create mode 100644 drivers/fpga/dfl-n3000-nios.c > > diff --git a/Documentation/ABI/testing/sysfs-bus-dfl-devices-n3000-nios > b/Documentation/ABI/testing/sysfs-bus-dfl-devices-n3000-nios > new file mode 100644 > index 0000000..fcfcdbd > --- /dev/null > +++ b/Documentation/ABI/testing/sysfs-bus-dfl-devices-n3000-nios > @@ -0,0 +1,18 @@ > +What: /sys/bus/dfl/devices/dfl-fme.X.X/fec_mode > +Date: July 2020 > +KernelVersion: 5.9 I don't think we can catch up the 5.9-rc1 at this moment, so 5.10 please. > +Contact: Xu Yilun <yilun.xu@xxxxxxxxx> > +Description: Read-only. It returns the FEC mode of the ethernet retimer > + configured by NIOS firmware. "rs" for RS FEC mode, "kr" for > + KR FEC mode, "no" FOR NO FEC mode. The FEC mode could > be set > + by module parameters, but it could only be set once after the > + board powers up. > + Format: string > + > +What: /sys/bus/dfl/devices/dfl-fme.X.X/nios_fw_version I think you have already modified the device name to dfl-dev.X, right? > +Date: July 2020 > +KernelVersion: 5.9 Ditto. > +Contact: Xu Yilun <yilun.xu@xxxxxxxxx> > +Description: Read-only. It returns the NIOS firmware version in FPGA. Its > + format is "major.minor.patch". > + Format: %x.%x.%x > diff --git a/Documentation/fpga/dfl-n3000-nios.rst > b/Documentation/fpga/dfl-n3000-nios.rst > new file mode 100644 > index 0000000..391528e > --- /dev/null > +++ b/Documentation/fpga/dfl-n3000-nios.rst > @@ -0,0 +1,39 @@ > +.. SPDX-License-Identifier: GPL-2.0 > + > +===================================== > +DFL N3000 Nios Private Feature Driver > +===================================== > + > +The dfl n3000 nios driver supports for the nios handshake private feature > on > +Intel N3000 FPGA Card. > + > +This private feature provides a handshake interface to FPGA NIOS firmware, > +which receives the ethernet retimer configuration command from host and > +do the configuration via an internal SPI master. When nios finished the > +configuration, host takes over the ownership of the SPI master to control an > +Intel MAX10 BMC Chip on the SPI bus. Maybe it's better to unify the naming - Nios > + > +So the driver does 2 major tasks on probe, requires NIOS firmware to > configure > +the ethernet retimer by operating the handshake interfaces, and then > creates a > +spi master platform device with the MAX10 device info in spi_board_info. > + > +Module Parameters > +================= > + > +The dfl n3000 nios driver supports the following module parameters: > + > +* fec_mode: string > + Require the NIOS firmware to set the FEC mode of the ethernet retimer on > + the PAC N3000 FPGA card. The possible values could be: > + > + - "rs": RS FEC mode (default) > + - "kr": KR FEC mode > + - "no": NO FEC mode > + > + The configuration could only be set once after the board powers up, the > + firmware will not accept a second configuration afterward. So the fec > mode > + will not be changed if the module is reloaded with a different param value. > + > + The configured value of the fec mode could be queried from sysfs node: > + > + /sys/bus/dfl/devices/dfl-fme.X.X/fec_mode > diff --git a/Documentation/fpga/index.rst b/Documentation/fpga/index.rst > index f80f956..5fd3c37 100644 > --- a/Documentation/fpga/index.rst > +++ b/Documentation/fpga/index.rst > @@ -8,6 +8,7 @@ fpga > :maxdepth: 1 > > dfl > + dfl-n3000-nios > > .. only:: subproject and html > > diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig > index 7cd5a29..f820142 100644 > --- a/drivers/fpga/Kconfig > +++ b/drivers/fpga/Kconfig > @@ -191,6 +191,18 @@ config FPGA_DFL_AFU > to the FPGA infrastructure via a Port. There may be more than one > Port/AFU per DFL based FPGA device. > > +config FPGA_DFL_N3000_NIOS > + tristate "FPGA DFL N3000 NIOS Driver" > + depends on FPGA_DFL > + select REGMAP > + help > + This is the driver for the nios handshake private feature on Intel > + N3000 FPGA Card. This private feature provides a handshake > interface > + to FPGA NIOS firmware, which receives retimer configuration > command > + from host and executes via an internal SPI master. When nios > finished > + the configuration, host takes over the ownership of the SPI master > to > + control an Intel MAX10 BMC Chip on the SPI bus. > + > config FPGA_DFL_PCI > tristate "FPGA DFL PCIe Device Driver" > depends on PCI && FPGA_DFL > diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile > index d8e21df..27f20f2 100644 > --- a/drivers/fpga/Makefile > +++ b/drivers/fpga/Makefile > @@ -44,5 +44,7 @@ dfl-fme-objs += dfl-fme-perf.o > dfl-afu-objs := dfl-afu-main.o dfl-afu-region.o dfl-afu-dma-region.o > dfl-afu-objs += dfl-afu-error.o > > +obj-$(CONFIG_FPGA_DFL_N3000_NIOS) += dfl-n3000-nios.o > + > # Drivers for FPGAs which implement DFL > obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o > diff --git a/drivers/fpga/dfl-n3000-nios.c b/drivers/fpga/dfl-n3000-nios.c > new file mode 100644 > index 0000000..041d759 > --- /dev/null > +++ b/drivers/fpga/dfl-n3000-nios.c > @@ -0,0 +1,518 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Driver for DFL N3000 NIOS private feature Maybe "DFL device driver for Nios private feature on Intel PAC N3000". It must be described clearly to avoid confusing. > + * > + * Copyright (C) 2019-2020 Intel Corporation, Inc. > + * > + * Authors: > + * Wu Hao <hao.wu@xxxxxxxxx> > + * Xu Yilun <yilun.xu@xxxxxxxxx> > + */ > +#include <linux/bitfield.h> > +#include <linux/errno.h> > +#include <linux/io.h> > +#include <linux/io-64-nonatomic-lo-hi.h> > +#include <linux/kernel.h> > +#include <linux/module.h> > +#include <linux/platform_device.h> > +#include <linux/regmap.h> > +#include <linux/stddef.h> > +#include <linux/spi/altera.h> > +#include <linux/spi/spi.h> > +#include <linux/types.h> > + > +#include "dfl.h" > + > +/** > + * DOC: fec_mode (string) > + * > + * Require the NIOS firmware to set the FEC mode of the ethernet retimer > on > + * PAC N3000 FPGA card. > + * > + * "rs": RS FEC mode (default) > + * > + * "kr": KR FEC mode > + * > + * "no": NO FEC mode > + * > + * The configuration could only be set once after the board powers up, the > + * firmware will not accept a second configuration afterward. So the fec > mode > + * will not be changed if the module is reloaded with a different param > value. > + * > + * The configured value of the fec_mode could be queried from sysfs node: > + * > + * /sys/bus/dfl/devices/dfl-fme.X.X/fec_mode s/dfl-fme.X.X/dfl-dev.X/ > + */ > +static char *fec_mode = "rs"; > +module_param(fec_mode, charp, 0444); > +MODULE_PARM_DESC(child, "FEC mode"); Why it's child here? This description string doesn't help at all I think. : ( You can put the description from code comments into this description. > + > +/* N3000 NIOS private feature registers */ > +#define NIOS_SPI_PARAM 0x8 > +#define PARAM_SHIFT_MODE_MSK BIT_ULL(1) > +#define PARAM_SHIFT_MODE_MSB 0 > +#define PARAM_SHIFT_MODE_LSB 1 > +#define PARAM_DATA_WIDTH GENMASK_ULL(7, 2) > +#define PARAM_NUM_CS GENMASK_ULL(13, 8) > +#define PARAM_CLK_POL BIT_ULL(14) > +#define PARAM_CLK_PHASE BIT_ULL(15) > +#define PARAM_PERIPHERAL_ID GENMASK_ULL(47, 32) > + > +#define NIOS_SPI_CTRL 0x10 > +#define CTRL_WR_DATA GENMASK_ULL(31, 0) > +#define CTRL_ADDR GENMASK_ULL(44, 32) > +#define CTRL_CMD_MSK GENMASK_ULL(63, 62) > +#define CTRL_CMD_NOP 0 > +#define CTRL_CMD_RD 1 > +#define CTRL_CMD_WR 2 > + > +#define NIOS_SPI_STAT 0x18 > +#define STAT_RD_DATA GENMASK_ULL(31, 0) > +#define STAT_RW_VAL BIT_ULL(32) > + > +/* nios handshake registers, indirect access */ Ditto > +#define NIOS_INIT 0x1000 > +#define NIOS_INIT_DONE BIT(0) > +#define NIOS_INIT_START BIT(1) > +/* Mode for PKVL A, link 0, the same below */ > +#define REQ_FEC_MODE_A0_MSK GENMASK(9, 8) > +#define REQ_FEC_MODE_A1_MSK GENMASK(11, 10) > +#define REQ_FEC_MODE_A2_MSK GENMASK(13, 12) > +#define REQ_FEC_MODE_A3_MSK GENMASK(15, 14) > +#define REQ_FEC_MODE_B0_MSK GENMASK(17, 16) > +#define REQ_FEC_MODE_B1_MSK GENMASK(19, 18) > +#define REQ_FEC_MODE_B2_MSK GENMASK(21, 20) > +#define REQ_FEC_MODE_B3_MSK GENMASK(23, 22) > +#define REQ_FEC_MODE_NO 0x0 > +#define REQ_FEC_MODE_KR 0x1 > +#define REQ_FEC_MODE_RS 0x2 What does REQ mean? > + > +#define NIOS_FW_VERSION 0x1004 > +#define NIOS_FW_VERSION_PATCH GENMASK(23, 20) > +#define NIOS_FW_VERSION_MINOR GENMASK(27, 24) > +#define NIOS_FW_VERSION_MAJOR GENMASK(31, 28) > + > +#define PKVL_A_MODE_STS 0x1020 > +#define PKVL_B_MODE_STS 0x1024 > +#define PKVL_MODE_STS_GROUP_MSK GENMASK(15, 8) > +#define PKVL_MODE_STS_GROUP_OK 0x0 > +#define PKVL_MODE_STS_ID_MSK GENMASK(7, 0) > + > +#define NS_REGBUS_WAIT_TIMEOUT 10000 /* loop count */ > +#define NIOS_INIT_TIMEOUT 10000000 /* usec */ > +#define NIOS_INIT_TIME_INTV 100000 /* usec */ > + > +struct dfl_n3000_nios { > + void __iomem *base; > + struct regmap *regmap; > + struct device *dev; > + struct platform_device *altera_spi; > +}; > + > +static int n3000_nios_writel(struct dfl_n3000_nios *ns, unsigned int reg, > + unsigned int val) > +{ > + int ret; > + > + ret = regmap_write(ns->regmap, reg, val); > + if (ret) > + dev_err(ns->dev, "fail to write reg 0x%x val 0x%x: %d\n", > + reg, val, ret); Maybe this log printing should be added in regmap implementation side? Then every user can save some code. > + > + return ret; > +} > + > +static int n3000_nios_readl(struct dfl_n3000_nios *ns, unsigned int reg, > + unsigned int *val) > +{ > + int ret; > + > + ret = regmap_read(ns->regmap, reg, val); > + if (ret) > + dev_err(ns->dev, "fail to read reg 0x%x: %d\n", reg, ret); > + > + return ret; > +} > + > +static ssize_t nios_fw_version_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct dfl_n3000_nios *ns = dev_get_drvdata(dev); > + unsigned int val; > + int ret; > + > + ret = n3000_nios_readl(ns, NIOS_FW_VERSION, &val); > + if (ret) > + return ret; > + > + return sprintf(buf, "%x.%x.%x\n", > + (u8)FIELD_GET(NIOS_FW_VERSION_MAJOR, val), > + (u8)FIELD_GET(NIOS_FW_VERSION_MINOR, val), > + (u8)FIELD_GET(NIOS_FW_VERSION_PATCH, val)); > +} > +static DEVICE_ATTR_RO(nios_fw_version); > + > +static ssize_t fec_mode_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct dfl_n3000_nios *ns = dev_get_drvdata(dev); > + unsigned int val, mode; > + int ret; > + > + ret = n3000_nios_readl(ns, NIOS_INIT, &val); > + if (ret) > + return ret; > + > + /* > + * FEC mode should always be the same for all links, as we set them > + * in this way. > + */ > + mode = FIELD_GET(REQ_FEC_MODE_A0_MSK, val); > + if (mode != FIELD_GET(REQ_FEC_MODE_A1_MSK, val) || > + mode != FIELD_GET(REQ_FEC_MODE_A2_MSK, val) || > + mode != FIELD_GET(REQ_FEC_MODE_A3_MSK, val) || > + mode != FIELD_GET(REQ_FEC_MODE_B0_MSK, val) || > + mode != FIELD_GET(REQ_FEC_MODE_B1_MSK, val) || > + mode != FIELD_GET(REQ_FEC_MODE_B2_MSK, val) || > + mode != FIELD_GET(REQ_FEC_MODE_B3_MSK, val)) > + return -EFAULT; > + > + switch (mode) { > + case REQ_FEC_MODE_NO: > + return sprintf(buf, "no\n"); > + case REQ_FEC_MODE_KR: > + return sprintf(buf, "kr\n"); > + case REQ_FEC_MODE_RS: > + return sprintf(buf, "rs\n"); > + } > + > + return -EFAULT; > +} > +static DEVICE_ATTR_RO(fec_mode); > + > +static struct attribute *n3000_nios_attrs[] = { > + &dev_attr_nios_fw_version.attr, > + &dev_attr_fec_mode.attr, > + NULL, > +}; > +ATTRIBUTE_GROUPS(n3000_nios); > + > +static bool init_error_detected(struct dfl_n3000_nios *ns) > +{ > + unsigned int val; > + > + if (n3000_nios_readl(ns, PKVL_A_MODE_STS, &val)) > + return true; > + > + if (FIELD_GET(PKVL_MODE_STS_GROUP_MSK, val) == > PKVL_MODE_STS_GROUP_OK) > + return true; > + > + if (n3000_nios_readl(ns, PKVL_B_MODE_STS, &val)) > + return true; > + > + if (FIELD_GET(PKVL_MODE_STS_GROUP_MSK, val) == > PKVL_MODE_STS_GROUP_OK) > + return true; > + > + return false; > +} > + > +static void dump_error_stat(struct dfl_n3000_nios *ns) > +{ > + unsigned int val; > + > + if (n3000_nios_readl(ns, PKVL_A_MODE_STS, &val)) { > + dev_err(ns->dev, "Could not read register > PKVL_A_MODE_STS\n"); Why similar error log here again? > + return; > + } > + > + dev_info(ns->dev, "PKVL_A_MODE_STS %x\n", val); > + > + if (n3000_nios_readl(ns, PKVL_B_MODE_STS, &val)) { > + dev_err(ns->dev, "Could not read register > PKVL_B_MODE_STS\n"); > + return; > + } > + > + dev_info(ns->dev, "PKVL_B_MODE_STS %x\n", val); > +} > + > +static int n3000_nios_init_done_check(struct dfl_n3000_nios *ns) > +{ > + struct device *dev = ns->dev; > + unsigned int val, mode; > + int ret; > + > + /* > + * this SPI is shared by NIOS core inside FPGA, NIOS will use this SPI > + * master to do some one time initialization after power up, and then > + * release the control to OS. driver needs to poll on INIT_DONE to > + * see when driver could take the control. > + * > + * Please note that after 3.x.x version, INIT_START is introduced, so > + * driver needs to trigger START firstly and then check INIT_DONE. > + */ > + > + ret = n3000_nios_readl(ns, NIOS_FW_VERSION, &val); > + if (ret) > + return ret; > + > + /* > + * If NIOS version register is totally uninitialized(== 0x0), then the > + * NIOS firmware is missing. So host could take control of SPI master > + * safely, but initialization work for NIOS is not done. This is an > + * issue of FPGA image. We didn't error out because we need SPI > master > + * to reprogram a new image. > + */ > + if (val == 0) { > + dev_warn(dev, "NIOS version reg = 0x%x, skip INIT_DONE > check, but PKVL may be uninitialized\n", > + val); > + return 0; > + } > + > + if (FIELD_GET(NIOS_FW_VERSION_MAJOR, val) >= 3) { > + /* read NIOS_INIT to check if PKVL INIT done or not */ > + ret = n3000_nios_readl(ns, NIOS_INIT, &val); > + if (ret) > + return ret; > + > + /* check if PKVLs are initialized already */ > + if (val & NIOS_INIT_DONE || val & NIOS_INIT_START) > + goto nios_init_done; > + > + /* configure FEC mode per module param */ > + val = NIOS_INIT_START; > + > + /* FEC mode will be ignored by hardware in 10G mode */ > + if (!strcmp(fec_mode, "no")) > + mode = REQ_FEC_MODE_NO; > + else if (!strcmp(fec_mode, "kr")) > + mode = REQ_FEC_MODE_KR; > + else if (!strcmp(fec_mode, "rs")) > + mode = REQ_FEC_MODE_RS; > + else > + return -EINVAL; > + > + /* set the same FEC mode for all links */ > + val |= FIELD_PREP(REQ_FEC_MODE_A0_MSK, mode) | > + FIELD_PREP(REQ_FEC_MODE_A1_MSK, mode) | > + FIELD_PREP(REQ_FEC_MODE_A2_MSK, mode) | > + FIELD_PREP(REQ_FEC_MODE_A3_MSK, mode) | > + FIELD_PREP(REQ_FEC_MODE_B0_MSK, mode) | > + FIELD_PREP(REQ_FEC_MODE_B1_MSK, mode) | > + FIELD_PREP(REQ_FEC_MODE_B2_MSK, mode) | > + FIELD_PREP(REQ_FEC_MODE_B3_MSK, mode); > + > + ret = n3000_nios_writel(ns, NIOS_INIT, val); > + if (ret) > + return ret; > + } > + > +nios_init_done: > + /* polls on NIOS_INIT_DONE */ > + ret = regmap_read_poll_timeout(ns->regmap, NIOS_INIT, val, > + val & NIOS_INIT_DONE, > + NIOS_INIT_TIME_INTV, > + NIOS_INIT_TIMEOUT); > + if (ret) { > + dev_err(dev, "NIOS_INIT_DONE %s\n", > + (ret == -ETIMEDOUT) ? "timed out" : "check error"); > + goto dump_sts; > + } > + > + /* > + * after INIT_DONE is detected, it still needs to check if any ERR > + * detected. > + * We won't error out here even if error detected. Nios will release > + * spi controller when INIT_DONE is set, so driver could continue to > + * initialize spi controller device. > + */ > + if (init_error_detected(ns)) { > + dev_warn(dev, "NIOS_INIT_DONE OK, but err found during > init\n"); > + goto dump_sts; > + } > + return 0; > + > +dump_sts: > + dump_error_stat(ns); > + > + return ret; > +} > + > +struct spi_board_info m10_n3000_info = { > + .modalias = "m10-n3000", > + .max_speed_hz = 12500000, > + .bus_num = 0, > + .chip_select = 0, > +}; > + > +static int create_altera_spi_controller(struct dfl_n3000_nios *ns) > +{ > + struct altera_spi_platform_data pdata = { 0 }; > + struct platform_device_info pdevinfo = { 0 }; > + void __iomem *base = ns->base; > + u64 v; > + > + v = readq(base + NIOS_SPI_PARAM); > + > + pdata.mode_bits = SPI_CS_HIGH; > + if (FIELD_GET(PARAM_CLK_POL, v)) > + pdata.mode_bits |= SPI_CPOL; > + if (FIELD_GET(PARAM_CLK_PHASE, v)) > + pdata.mode_bits |= SPI_CPHA; > + > + pdata.num_chipselect = FIELD_GET(PARAM_NUM_CS, v); > + pdata.bits_per_word_mask = > + SPI_BPW_RANGE_MASK(1, FIELD_GET(PARAM_DATA_WIDTH, > v)); > + > + pdata.num_devices = 1; > + pdata.devices = &m10_n3000_info; > + > + dev_dbg(ns->dev, "%s cs %u bpm 0x%x mode 0x%x\n", __func__, > + pdata.num_chipselect, pdata.bits_per_word_mask, > + pdata.mode_bits); > + > + pdevinfo.name = "subdev_spi_altera"; > + pdevinfo.id = PLATFORM_DEVID_AUTO; > + pdevinfo.parent = ns->dev; > + pdevinfo.data = &pdata; > + pdevinfo.size_data = sizeof(pdata); > + > + ns->altera_spi = platform_device_register_full(&pdevinfo); > + return PTR_ERR_OR_ZERO(ns->altera_spi); > +} > + > +static void destroy_altera_spi_controller(struct dfl_n3000_nios *ns) > +{ > + platform_device_unregister(ns->altera_spi); > +} > + > +/* ns is the abbreviation of nios_spi */ > +static int ns_bus_poll_stat_timeout(void __iomem *base, u64 *v) Why adding "bus" here? I just see it's polling on register bits, right? It's a little confusing on ns_bus. > +{ > + int loops = NS_REGBUS_WAIT_TIMEOUT; > + > + /* > + * We don't use the time based timeout here for performance. > + * > + * The image reprograming engine is on max10 bmc chip, which is the > spi > + * device connected to altera spi controller. So the regbus read/write > + * is on the critical path of PAC N3000 image reprograming. And > usually > + * the state changes in few loops, the time based timeout checking > will > + * add too much overhead on it. > + * > + * Anyway, 10000 times loop is large enough. > + */ > + do { > + *v = readq(base + NIOS_SPI_STAT); > + if (*v & STAT_RW_VAL) > + break; > + cpu_relax(); > + } while (--loops); > + > + return loops ? 0 : -ETIMEDOUT; > +} > + > +static int ns_bus_reg_write(void *context, unsigned int reg, unsigned int val) > +{ > + void __iomem *base = context; > + u64 v = 0; > + > + v |= FIELD_PREP(CTRL_CMD_MSK, CTRL_CMD_WR); > + v |= FIELD_PREP(CTRL_ADDR, reg); > + v |= FIELD_PREP(CTRL_WR_DATA, val); > + writeq(v, base + NIOS_SPI_CTRL); > + > + return ns_bus_poll_stat_timeout(base, &v); > +} > + > +static int ns_bus_reg_read(void *context, unsigned int reg, unsigned int *val) > +{ > + void __iomem *base = context; > + u64 v = 0; > + int ret; > + > + v |= FIELD_PREP(CTRL_CMD_MSK, CTRL_CMD_RD); > + v |= FIELD_PREP(CTRL_ADDR, reg); > + writeq(v, base + NIOS_SPI_CTRL); > + > + ret = ns_bus_poll_stat_timeout(base, &v); > + if (!ret) > + *val = FIELD_GET(STAT_RD_DATA, v); > + > + return ret; > +} > + > +static const struct regmap_config ns_regbus_cfg = { > + .reg_bits = 32, > + .reg_stride = 4, > + .val_bits = 32, > + .fast_io = true, > + > + .reg_write = ns_bus_reg_write, > + .reg_read = ns_bus_reg_read, > +}; > + > +static int dfl_n3000_nios_probe(struct dfl_device *dfl_dev) > +{ > + struct device *dev = &dfl_dev->dev; > + struct dfl_n3000_nios *ns; > + int ret; > + > + ns = devm_kzalloc(dev, sizeof(*ns), GFP_KERNEL); > + if (!ns) > + return -ENOMEM; > + > + dev_set_drvdata(&dfl_dev->dev, ns); > + > + ns->dev = dev; > + > + ns->base = devm_ioremap_resource(&dfl_dev->dev, &dfl_dev- > >mmio_res); > + if (IS_ERR(ns->base)) { > + dev_err(dev, "get mem resource fail!\n"); devm_ioremap_resource should print some error message, will that be enough? > + return PTR_ERR(ns->base); > + } > + > + ns->regmap = devm_regmap_init(dev, NULL, ns->base, > &ns_regbus_cfg); > + if (IS_ERR(ns->regmap)) > + return PTR_ERR(ns->regmap); > + > + ret = n3000_nios_init_done_check(ns); > + if (ret) > + return ret; > + > + ret = create_altera_spi_controller(ns); > + if (ret) > + dev_err(dev, "altera spi controller create failed: %d\n", ret); > + > + return ret; > +} > + > +static void dfl_n3000_nios_remove(struct dfl_device *dfl_dev) > +{ > + struct dfl_n3000_nios *ns = dev_get_drvdata(&dfl_dev->dev); > + > + destroy_altera_spi_controller(ns); > +} > + > +#define FME_FEATURE_ID_N3000_NIOS 0xd > + > +static const struct dfl_device_id dfl_n3000_nios_ids[] = { > + { FME_ID, FME_FEATURE_ID_N3000_NIOS }, > + { } > +}; > + > +static struct dfl_driver dfl_n3000_nios_driver = { > + .drv = { > + .name = "dfl-n3000-nios", > + .dev_groups = n3000_nios_groups, > + }, > + .id_table = dfl_n3000_nios_ids, > + .probe = dfl_n3000_nios_probe, > + .remove = dfl_n3000_nios_remove, > +}; > + > +module_dfl_driver(dfl_n3000_nios_driver); > + > +MODULE_DEVICE_TABLE(dfl, dfl_n3000_nios_ids); > +MODULE_DESCRIPTION("DFL N3000 NIOS driver"); > +MODULE_AUTHOR("Intel Corporation"); > +MODULE_LICENSE("GPL v2"); > -- > 2.7.4