On Thu, 16 Jul 2020, Xu Yilun wrote:

> This patch implements the basic functions of the BMC chip for some Intel
> FPGA PCIe Acceleration Cards (PAC). The BMC is implemented using the
> intel max10 CPLD.
> 
> This BMC chip is connected to FPGA by a SPI bus. To provide reliable
> register access from FPGA, an Avalon Memory-Mapped (Avmm) transaction
> protocol over the SPI bus is used between host and slave.
> 
> This driver implements the basic register access using the
> regmap-spi-avmm. The mfd cells array is empty now as a placeholder.
> 
> Signed-off-by: Xu Yilun <[email protected]>
> Signed-off-by: Wu Hao <[email protected]>
> Signed-off-by: Matthew Gerlach <[email protected]>
> Signed-off-by: Russ Weight <[email protected]>
> Signed-off-by: Tom Rix <[email protected]>
> ---
> v2: Split out the regmap-spi-avmm part.
>     Rename the file intel-m10-bmc-main.c to intel-m10-bmc.c, cause
>      there is only one source file left for this module now.
> ---
>  .../ABI/testing/sysfs-driver-intel-m10-bmc         |  15 ++
>  drivers/mfd/Kconfig                                |  13 ++
>  drivers/mfd/Makefile                               |   2 +
>  drivers/mfd/intel-m10-bmc.c                        | 174 
> +++++++++++++++++++++
>  include/linux/mfd/intel-m10-bmc.h                  |  57 +++++++
>  5 files changed, 261 insertions(+)
>  create mode 100644 Documentation/ABI/testing/sysfs-driver-intel-m10-bmc
>  create mode 100644 drivers/mfd/intel-m10-bmc.c
>  create mode 100644 include/linux/mfd/intel-m10-bmc.h
> 
> diff --git a/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc 
> b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc
> new file mode 100644
> index 0000000..54cf5bc
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc
> @@ -0,0 +1,15 @@
> +What:                /sys/bus/spi/devices/.../bmc_version

Why is this in your MFD patch?

Again, this looks like it's documenting a SPI device?

> +Date:                June 2020
> +KernelVersion:       5.9
> +Contact:     Xu Yilun <[email protected]>
> +Description: Read only. Returns the hardware build version of Intel
> +             MAX10 BMC chip.
> +             Format: "0x%x".
> +
> +What:                /sys/bus/spi/devices/.../bmcfw_version
> +Date:                June 2020
> +KernelVersion:       5.9
> +Contact:     Xu Yilun <[email protected]>
> +Description: Read only. Returns the firmware version of Intel MAX10
> +             BMC chip.
> +             Format: "0x%x".

[...]

> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index d13bb0a..42252c8 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -2130,5 +2130,18 @@ config SGI_MFD_IOC3
>         If you have an SGI Origin, Octane, or a PCI IOC3 card,
>         then say Y. Otherwise say N.
>  
> +config MFD_INTEL_M10_BMC
> +     tristate "Intel MAX10 board management controller"

"Board Management Controller"

> +     depends on SPI_MASTER
> +     select REGMAP_SPI_AVMM
> +     select MFD_CORE
> +     help
> +       Support for the Intel MAX10 board management controller using the
> +       SPI interface.
> +
> +       This driver provides common support for accessing the device,
> +       additional drivers must be enabled in order to use the functionality
> +       of the device.
> +
>  endmenu
>  endif
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index 1c8d6be..149d7d1 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -265,3 +265,5 @@ obj-$(CONFIG_MFD_STMFX)   += stmfx.o
>  obj-$(CONFIG_MFD_KHADAS_MCU)         += khadas-mcu.o
>  
>  obj-$(CONFIG_SGI_MFD_IOC3)   += ioc3.o
> +
> +obj-$(CONFIG_MFD_INTEL_M10_BMC)   += intel-m10-bmc.o
> diff --git a/drivers/mfd/intel-m10-bmc.c b/drivers/mfd/intel-m10-bmc.c
> new file mode 100644
> index 0000000..0d5e5d6
> --- /dev/null
> +++ b/drivers/mfd/intel-m10-bmc.c
> @@ -0,0 +1,174 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Intel Max10 Board Management Controller chip Driver

Drop "Driver"

> + * Copyright (C) 2018-2020 Intel Corporation. All rights reserved.
> + *
> + */
> +#include <linux/bitfield.h>
> +#include <linux/mutex.h>
> +#include <linux/regmap.h>
> +#include <linux/module.h>
> +#include <linux/mfd/core.h>
> +#include <linux/init.h>
> +#include <linux/spi/spi.h>
> +#include <linux/mfd/intel-m10-bmc.h>

Alphabetical.

> +enum m10bmc_type {
> +     M10_N3000,
> +};

Will there be others?

> +static struct mfd_cell m10bmc_pacn3000_subdevs[] = {};
> +
> +static struct regmap_config intel_m10bmc_regmap_config = {
> +     .reg_bits = 32,
> +     .val_bits = 32,
> +     .reg_stride = 4,
> +     .max_register = M10BMC_MEM_END,
> +};
> +
> +static ssize_t bmc_version_show(struct device *dev,
> +                             struct device_attribute *attr, char *buf)
> +{
> +     struct intel_m10bmc *m10bmc = dev_get_drvdata(dev);
> +     unsigned int val;
> +     int ret;
> +
> +     ret = m10bmc_sys_read(m10bmc, M10BMC_BUILD_VER, &val);
> +     if (ret)
> +             return ret;
> +
> +     return sprintf(buf, "0x%x\n", val);
> +}
> +static DEVICE_ATTR_RO(bmc_version);
> +
> +static ssize_t bmcfw_version_show(struct device *dev,
> +                               struct device_attribute *attr, char *buf)
> +{
> +     struct intel_m10bmc *max10 = dev_get_drvdata(dev);
> +     unsigned int val;
> +     int ret;
> +
> +     ret = m10bmc_sys_read(max10, NIOS2_FW_VERSION, &val);
> +     if (ret)
> +             return ret;
> +
> +     return sprintf(buf, "0x%x\n", val);
> +}
> +static DEVICE_ATTR_RO(bmcfw_version);
> +
> +static struct attribute *m10bmc_attrs[] = {
> +     &dev_attr_bmc_version.attr,
> +     &dev_attr_bmcfw_version.attr,
> +     NULL,
> +};
> +
> +static struct attribute_group m10bmc_attr_group = {
> +     .attrs = m10bmc_attrs,
> +};
> +
> +static const struct attribute_group *m10bmc_dev_groups[] = {
> +     &m10bmc_attr_group,
> +     NULL
> +};
> +
> +static int check_m10bmc_version(struct intel_m10bmc *m10bmc)
> +{
> +     unsigned int v;
> +
> +     if (m10bmc_raw_read(m10bmc, M10BMC_LEGACY_SYS_BASE + M10BMC_BUILD_VER,
> +                         &v))
> +             return -ENODEV;
> +
> +     if (v != 0xffffffff) {

So the only supported version number is all 1's?

> +             dev_err(m10bmc->dev, "bad version M10BMC detected\n");
> +             return -ENODEV;
> +     }
> +
> +     return 0;
> +}
> +
> +static int m10bmc_spi_setup(struct spi_device *spi)
> +{
> +     /* try 32 bits bpw first then fall back to 8 bits bpw */
> +     spi->mode = SPI_MODE_1;
> +     spi->bits_per_word = 32;
> +     if (!spi_setup(spi))
> +             return 0;
> +
> +     spi->bits_per_word = 8;
> +     return spi_setup(spi);

Looks odd.  Comments needed.

> +}
> +
> +static int intel_m10_bmc_spi_probe(struct spi_device *spi)
> +{
> +     const struct spi_device_id *id = spi_get_device_id(spi);
> +     struct device *dev = &spi->dev;
> +     struct mfd_cell *cells;
> +     struct intel_m10bmc *m10bmc;
> +     int ret, n_cell;
> +
> +     ret = m10bmc_spi_setup(spi);
> +     if (ret)
> +             return ret;
> +
> +     m10bmc = devm_kzalloc(dev, sizeof(*m10bmc), GFP_KERNEL);
> +     if (!m10bmc)
> +             return -ENOMEM;
> +
> +     m10bmc->dev = dev;
> +
> +     m10bmc->regmap =
> +             devm_regmap_init_spi_avmm(spi, &intel_m10bmc_regmap_config);
> +     if (IS_ERR(m10bmc->regmap)) {
> +             ret = PTR_ERR(m10bmc->regmap);
> +             dev_err(dev, "Failed to allocate regmap: %d\n", ret);
> +             return ret;
> +     }
> +
> +     spi_set_drvdata(spi, m10bmc);
> +
> +     ret = check_m10bmc_version(m10bmc);
> +     if (ret) {
> +             dev_err(dev, "Failed to identify m10bmc hardware\n");
> +             return ret;
> +     }
> +
> +     switch (id->driver_data) {
> +     case M10_N3000:
> +             cells = m10bmc_pacn3000_subdevs;
> +             n_cell = ARRAY_SIZE(m10bmc_pacn3000_subdevs);

This is just an empty cell though, right?

I'm not even sure why this doesn't just crash.

> +             break;
> +     default:
> +             return -ENODEV;
> +     }
> +
> +     ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, cells, n_cell,
> +                                NULL, 0, NULL);

What sub-devices does this actually register?

> +     if (ret)
> +             dev_err(dev, "Failed to register sub-devices: %d\n", ret);
> +
> +     return ret;
> +}
> +
> +static const struct spi_device_id m10bmc_spi_id[] = {
> +     { "m10-n3000", M10_N3000 },
> +     { }
> +};
> +MODULE_DEVICE_TABLE(spi, m10bmc_spi_id);
> +
> +static struct spi_driver intel_m10bmc_spi_driver = {
> +     .driver = {
> +             .name = "intel-m10-bmc",
> +             .dev_groups = m10bmc_dev_groups,
> +     },
> +     .probe = intel_m10_bmc_spi_probe,
> +     .id_table = m10bmc_spi_id,
> +};
> +
> +module_spi_driver(intel_m10bmc_spi_driver);
> +
> +MODULE_DESCRIPTION("Intel Max10 BMC Device Driver");
> +MODULE_AUTHOR("Intel Corporation");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("spi:intel-m10-bmc");
> diff --git a/include/linux/mfd/intel-m10-bmc.h 
> b/include/linux/mfd/intel-m10-bmc.h
> new file mode 100644
> index 0000000..4979756
> --- /dev/null
> +++ b/include/linux/mfd/intel-m10-bmc.h
> @@ -0,0 +1,57 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Driver Header File for Intel Max10 Board Management Controller chip.
> + *
> + * Copyright (C) 2018-2020 Intel Corporation, Inc.
> + *
> + */
> +#ifndef __INTEL_M10_BMC_H
> +#define __INTEL_M10_BMC_H
> +
> +#include <linux/regmap.h>
> +
> +#define M10BMC_LEGACY_SYS_BASE       0x300400
> +#define M10BMC_SYS_BASE              0x300800
> +#define M10BMC_MEM_END               0x200000fc
> +
> +/* Register offset of system registers */
> +#define NIOS2_FW_VERSION     0x0
> +#define M10BMC_TEST_REG              0x3c
> +#define M10BMC_BUILD_VER     0x68
> +#define M10BMC_VER_MAJOR_MSK GENMASK(23, 16)
> +#define M10BMC_VER_PCB_INFO_MSK      GENMASK(31, 24)
> +
> +/**
> + * struct intel_m10bmc - Intel Max10 BMC MFD device private data structure
> + * @dev: this device
> + * @regmap: the regmap used to access registers by m10bmc itself
> + */
> +struct intel_m10bmc {
> +     struct device *dev;
> +     struct regmap *regmap;
> +};
> +
> +/*
> + * register access helper functions.
> + *
> + * m10bmc_raw_read - read m10bmc register per addr
> + * m10bmc_sys_read - read m10bmc system register per offset
> + */
> +static inline int
> +m10bmc_raw_read(struct intel_m10bmc *m10bmc, unsigned int addr,
> +             unsigned int *val)
> +{
> +     int ret;
> +
> +     ret = regmap_read(m10bmc->regmap, addr, val);
> +     if (ret)
> +             dev_err(m10bmc->dev, "fail to read raw reg %x: %d\n",
> +                     addr, ret);
> +
> +     return ret;
> +}

Why are you abstracting Regmap?

> +#define m10bmc_sys_read(m10bmc, offset, val) \
> +     m10bmc_raw_read(m10bmc, M10BMC_SYS_BASE + (offset), val)
> +
> +#endif /* __INTEL_M10_BMC_H */

-- 
Lee Jones [李琼斯]
Senior Technical Lead - Developer Services
Linaro.org │ Open source software for Arm SoCs
Follow Linaro: Facebook | Twitter | Blog

Reply via email to