Commit 9d18515e authored by Xu Yilun's avatar Xu Yilun

Merge tag 'ib-mfd-fpga-hwmon-v6.3' of...

Merge tag 'ib-mfd-fpga-hwmon-v6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd into for-fpga-v6.3-rc1

Lee writes:

Immutable branch between MFD, FPGA and HWMON due for the v6.3 merge window

* tag 'ib-mfd-fpga-hwmon-v6.3' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/lee/mfd:
  mfd: intel-m10-bmc: Add PMCI driver
  fpga: m10bmc-sec: Make rsu status type specific
  fpga: m10bmc-sec: Create helpers for rsu status/progress checks
  mfd: intel-m10-bmc: Prefix register defines with M10BMC_N3000
  fpga: intel-m10-bmc: Rework flash read/write
  mfd: intel-m10-bmc: Support multiple CSR register layouts
  mfd: intel-m10-bmc: Split into core and spi specific parts
  mfd: intel-m10-bmc: Rename the local variables
  mfd: intel-m10-bmc: Create m10bmc_platform_info for type specific info
  mfd: intel-m10-bmc: Add missing includes to header
parents 48ca6e5f 869b9edd
What: /sys/bus/spi/devices/.../bmc_version
What: /sys/bus/.../drivers/intel-m10-bmc/.../bmc_version
Date: June 2020
KernelVersion: 5.10
Contact: Xu Yilun <yilun.xu@intel.com>
......@@ -6,7 +6,7 @@ Description: Read only. Returns the hardware build version of Intel
MAX10 BMC chip.
Format: "0x%x".
What: /sys/bus/spi/devices/.../bmcfw_version
What: /sys/bus/.../drivers/intel-m10-bmc/.../bmcfw_version
Date: June 2020
KernelVersion: 5.10
Contact: Xu Yilun <yilun.xu@intel.com>
......@@ -14,7 +14,7 @@ Description: Read only. Returns the firmware version of Intel MAX10
BMC chip.
Format: "0x%x".
What: /sys/bus/spi/devices/.../mac_address
What: /sys/bus/.../drivers/intel-m10-bmc/.../mac_address
Date: January 2021
KernelVersion: 5.12
Contact: Russ Weight <russell.h.weight@intel.com>
......@@ -25,7 +25,7 @@ Description: Read only. Returns the first MAC address in a block
space.
Format: "%02x:%02x:%02x:%02x:%02x:%02x".
What: /sys/bus/spi/devices/.../mac_count
What: /sys/bus/.../drivers/intel-m10-bmc/.../mac_count
Date: January 2021
KernelVersion: 5.12
Contact: Russ Weight <russell.h.weight@intel.com>
......
......@@ -10576,7 +10576,7 @@ S: Maintained
F: Documentation/ABI/testing/sysfs-driver-intel-m10-bmc
F: Documentation/hwmon/intel-m10-bmc-hwmon.rst
F: drivers/hwmon/intel-m10-bmc-hwmon.c
F: drivers/mfd/intel-m10-bmc.c
F: drivers/mfd/intel-m10-bmc*
F: include/linux/mfd/intel-m10-bmc.h
INTEL MENLOW THERMAL DRIVER
......
......@@ -246,7 +246,7 @@ config FPGA_MGR_VERSAL_FPGA
config FPGA_M10_BMC_SEC_UPDATE
tristate "Intel MAX10 BMC Secure Update driver"
depends on MFD_INTEL_M10_BMC
depends on MFD_INTEL_M10_BMC_CORE
select FW_LOADER
select FW_UPLOAD
help
......
This diff is collapsed.
......@@ -2341,7 +2341,7 @@ config SENSORS_XGENE
config SENSORS_INTEL_M10_BMC_HWMON
tristate "Intel MAX10 BMC Hardware Monitoring"
depends on MFD_INTEL_M10_BMC
depends on MFD_INTEL_M10_BMC_CORE
help
This driver provides support for the hardware monitoring functionality
on Intel MAX10 BMC chip.
......
......@@ -2224,14 +2224,32 @@ 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 MAX 10 Board Management Controller"
depends on SPI_MASTER
select REGMAP_SPI_AVMM
select MFD_CORE
config MFD_INTEL_M10_BMC_CORE
tristate
select MFD_CORE
select REGMAP
default n
config MFD_INTEL_M10_BMC_SPI
tristate "Intel MAX 10 Board Management Controller with SPI"
depends on SPI_MASTER
select MFD_INTEL_M10_BMC_CORE
select REGMAP_SPI_AVMM
help
Support for the Intel MAX 10 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.
config MFD_INTEL_M10_BMC_PMCI
tristate "Intel MAX 10 Board Management Controller with PMCI"
depends on FPGA_DFL
select MFD_INTEL_M10_BMC_CORE
select REGMAP
help
Support for the Intel MAX 10 board management controller using the
SPI interface.
Support for the Intel MAX 10 board management controller via PMCI.
This driver provides common support for accessing the device,
additional drivers must be enabled in order to use the functionality
......
......@@ -269,7 +269,10 @@ obj-$(CONFIG_MFD_QCOM_PM8008) += qcom-pm8008.o
obj-$(CONFIG_SGI_MFD_IOC3) += ioc3.o
obj-$(CONFIG_MFD_SIMPLE_MFD_I2C) += simple-mfd-i2c.o
obj-$(CONFIG_MFD_SMPRO) += smpro-core.o
obj-$(CONFIG_MFD_INTEL_M10_BMC) += intel-m10-bmc.o
obj-$(CONFIG_MFD_INTEL_M10_BMC_CORE) += intel-m10-bmc-core.o
obj-$(CONFIG_MFD_INTEL_M10_BMC_SPI) += intel-m10-bmc-spi.o
obj-$(CONFIG_MFD_INTEL_M10_BMC_PMCI) += intel-m10-bmc-pmci.o
obj-$(CONFIG_MFD_ATC260X) += atc260x-core.o
obj-$(CONFIG_MFD_ATC260X_I2C) += atc260x-i2c.o
......
// SPDX-License-Identifier: GPL-2.0
/*
* Intel MAX 10 Board Management Controller chip - common code
*
* Copyright (C) 2018-2020 Intel Corporation. All rights reserved.
*/
#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/dev_printk.h>
#include <linux/mfd/core.h>
#include <linux/mfd/intel-m10-bmc.h>
#include <linux/module.h>
static ssize_t bmc_version_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct intel_m10bmc *ddata = dev_get_drvdata(dev);
unsigned int val;
int ret;
ret = m10bmc_sys_read(ddata, ddata->info->csr_map->build_version, &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 *ddata = dev_get_drvdata(dev);
unsigned int val;
int ret;
ret = m10bmc_sys_read(ddata, ddata->info->csr_map->fw_version, &val);
if (ret)
return ret;
return sprintf(buf, "0x%x\n", val);
}
static DEVICE_ATTR_RO(bmcfw_version);
static ssize_t mac_address_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct intel_m10bmc *ddata = dev_get_drvdata(dev);
unsigned int macaddr_low, macaddr_high;
int ret;
ret = m10bmc_sys_read(ddata, ddata->info->csr_map->mac_low, &macaddr_low);
if (ret)
return ret;
ret = m10bmc_sys_read(ddata, ddata->info->csr_map->mac_high, &macaddr_high);
if (ret)
return ret;
return sysfs_emit(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n",
(u8)FIELD_GET(M10BMC_N3000_MAC_BYTE1, macaddr_low),
(u8)FIELD_GET(M10BMC_N3000_MAC_BYTE2, macaddr_low),
(u8)FIELD_GET(M10BMC_N3000_MAC_BYTE3, macaddr_low),
(u8)FIELD_GET(M10BMC_N3000_MAC_BYTE4, macaddr_low),
(u8)FIELD_GET(M10BMC_N3000_MAC_BYTE5, macaddr_high),
(u8)FIELD_GET(M10BMC_N3000_MAC_BYTE6, macaddr_high));
}
static DEVICE_ATTR_RO(mac_address);
static ssize_t mac_count_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct intel_m10bmc *ddata = dev_get_drvdata(dev);
unsigned int macaddr_high;
int ret;
ret = m10bmc_sys_read(ddata, ddata->info->csr_map->mac_high, &macaddr_high);
if (ret)
return ret;
return sysfs_emit(buf, "%u\n", (u8)FIELD_GET(M10BMC_N3000_MAC_COUNT, macaddr_high));
}
static DEVICE_ATTR_RO(mac_count);
static struct attribute *m10bmc_attrs[] = {
&dev_attr_bmc_version.attr,
&dev_attr_bmcfw_version.attr,
&dev_attr_mac_address.attr,
&dev_attr_mac_count.attr,
NULL,
};
static const struct attribute_group m10bmc_group = {
.attrs = m10bmc_attrs,
};
const struct attribute_group *m10bmc_dev_groups[] = {
&m10bmc_group,
NULL,
};
EXPORT_SYMBOL_GPL(m10bmc_dev_groups);
int m10bmc_dev_init(struct intel_m10bmc *m10bmc, const struct intel_m10bmc_platform_info *info)
{
int ret;
m10bmc->info = info;
dev_set_drvdata(m10bmc->dev, m10bmc);
ret = devm_mfd_add_devices(m10bmc->dev, PLATFORM_DEVID_AUTO,
info->cells, info->n_cells,
NULL, 0, NULL);
if (ret)
dev_err(m10bmc->dev, "Failed to register sub-devices: %d\n", ret);
return ret;
}
EXPORT_SYMBOL_GPL(m10bmc_dev_init);
MODULE_DESCRIPTION("Intel MAX 10 BMC core driver");
MODULE_AUTHOR("Intel Corporation");
MODULE_LICENSE("GPL v2");
// SPDX-License-Identifier: GPL-2.0
/*
* MAX10 BMC Platform Management Component Interface (PMCI) based
* interface.
*
* Copyright (C) 2020-2023 Intel Corporation.
*/
#include <linux/device.h>
#include <linux/dfl.h>
#include <linux/mfd/core.h>
#include <linux/mfd/intel-m10-bmc.h>
#include <linux/module.h>
#include <linux/regmap.h>
struct m10bmc_pmci_device {
void __iomem *base;
struct intel_m10bmc m10bmc;
};
/*
* Intel FGPA indirect register access via hardware controller/bridge.
*/
#define INDIRECT_CMD_OFF 0
#define INDIRECT_CMD_CLR 0
#define INDIRECT_CMD_RD BIT(0)
#define INDIRECT_CMD_WR BIT(1)
#define INDIRECT_CMD_ACK BIT(2)
#define INDIRECT_ADDR_OFF 0x4
#define INDIRECT_RD_OFF 0x8
#define INDIRECT_WR_OFF 0xc
#define INDIRECT_INT_US 1
#define INDIRECT_TIMEOUT_US 10000
struct indirect_ctx {
void __iomem *base;
struct device *dev;
};
static int indirect_clear_cmd(struct indirect_ctx *ctx)
{
unsigned int cmd;
int ret;
writel(INDIRECT_CMD_CLR, ctx->base + INDIRECT_CMD_OFF);
ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, cmd,
cmd == INDIRECT_CMD_CLR,
INDIRECT_INT_US, INDIRECT_TIMEOUT_US);
if (ret)
dev_err(ctx->dev, "timed out waiting clear cmd (residual cmd=0x%x)\n", cmd);
return ret;
}
static int indirect_reg_read(void *context, unsigned int reg, unsigned int *val)
{
struct indirect_ctx *ctx = context;
unsigned int cmd, ack, tmpval;
int ret, ret2;
cmd = readl(ctx->base + INDIRECT_CMD_OFF);
if (cmd != INDIRECT_CMD_CLR)
dev_warn(ctx->dev, "residual cmd 0x%x on read entry\n", cmd);
writel(reg, ctx->base + INDIRECT_ADDR_OFF);
writel(INDIRECT_CMD_RD, ctx->base + INDIRECT_CMD_OFF);
ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, ack,
(ack & INDIRECT_CMD_ACK) == INDIRECT_CMD_ACK,
INDIRECT_INT_US, INDIRECT_TIMEOUT_US);
if (ret)
dev_err(ctx->dev, "read timed out on reg 0x%x ack 0x%x\n", reg, ack);
else
tmpval = readl(ctx->base + INDIRECT_RD_OFF);
ret2 = indirect_clear_cmd(ctx);
if (ret)
return ret;
if (ret2)
return ret2;
*val = tmpval;
return 0;
}
static int indirect_reg_write(void *context, unsigned int reg, unsigned int val)
{
struct indirect_ctx *ctx = context;
unsigned int cmd, ack;
int ret, ret2;
cmd = readl(ctx->base + INDIRECT_CMD_OFF);
if (cmd != INDIRECT_CMD_CLR)
dev_warn(ctx->dev, "residual cmd 0x%x on write entry\n", cmd);
writel(val, ctx->base + INDIRECT_WR_OFF);
writel(reg, ctx->base + INDIRECT_ADDR_OFF);
writel(INDIRECT_CMD_WR, ctx->base + INDIRECT_CMD_OFF);
ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, ack,
(ack & INDIRECT_CMD_ACK) == INDIRECT_CMD_ACK,
INDIRECT_INT_US, INDIRECT_TIMEOUT_US);
if (ret)
dev_err(ctx->dev, "write timed out on reg 0x%x ack 0x%x\n", reg, ack);
ret2 = indirect_clear_cmd(ctx);
if (ret)
return ret;
return ret2;
}
static const struct regmap_range m10bmc_pmci_regmap_range[] = {
regmap_reg_range(M10BMC_N6000_SYS_BASE, M10BMC_N6000_SYS_END),
};
static const struct regmap_access_table m10bmc_pmci_access_table = {
.yes_ranges = m10bmc_pmci_regmap_range,
.n_yes_ranges = ARRAY_SIZE(m10bmc_pmci_regmap_range),
};
static struct regmap_config m10bmc_pmci_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.wr_table = &m10bmc_pmci_access_table,
.rd_table = &m10bmc_pmci_access_table,
.reg_read = &indirect_reg_read,
.reg_write = &indirect_reg_write,
.max_register = M10BMC_N6000_SYS_END,
};
static struct mfd_cell m10bmc_pmci_n6000_bmc_subdevs[] = {
{ .name = "n6000bmc-hwmon" },
};
static const struct m10bmc_csr_map m10bmc_n6000_csr_map = {
.base = M10BMC_N6000_SYS_BASE,
.build_version = M10BMC_N6000_BUILD_VER,
.fw_version = NIOS2_N6000_FW_VERSION,
.mac_low = M10BMC_N6000_MAC_LOW,
.mac_high = M10BMC_N6000_MAC_HIGH,
.doorbell = M10BMC_N6000_DOORBELL,
.auth_result = M10BMC_N6000_AUTH_RESULT,
.bmc_prog_addr = M10BMC_N6000_BMC_PROG_ADDR,
.bmc_reh_addr = M10BMC_N6000_BMC_REH_ADDR,
.bmc_magic = M10BMC_N6000_BMC_PROG_MAGIC,
.sr_prog_addr = M10BMC_N6000_SR_PROG_ADDR,
.sr_reh_addr = M10BMC_N6000_SR_REH_ADDR,
.sr_magic = M10BMC_N6000_SR_PROG_MAGIC,
.pr_prog_addr = M10BMC_N6000_PR_PROG_ADDR,
.pr_reh_addr = M10BMC_N6000_PR_REH_ADDR,
.pr_magic = M10BMC_N6000_PR_PROG_MAGIC,
.rsu_update_counter = M10BMC_N6000_STAGING_FLASH_COUNT,
};
static const struct intel_m10bmc_platform_info m10bmc_pmci_n6000 = {
.cells = m10bmc_pmci_n6000_bmc_subdevs,
.n_cells = ARRAY_SIZE(m10bmc_pmci_n6000_bmc_subdevs),
.csr_map = &m10bmc_n6000_csr_map,
};
static int m10bmc_pmci_probe(struct dfl_device *ddev)
{
struct device *dev = &ddev->dev;
struct m10bmc_pmci_device *pmci;
struct indirect_ctx *ctx;
pmci = devm_kzalloc(dev, sizeof(*pmci), GFP_KERNEL);
if (!pmci)
return -ENOMEM;
pmci->m10bmc.dev = dev;
pmci->base = devm_ioremap_resource(dev, &ddev->mmio_res);
if (IS_ERR(pmci->base))
return PTR_ERR(pmci->base);
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
ctx->base = pmci->base + M10BMC_N6000_INDIRECT_BASE;
ctx->dev = dev;
indirect_clear_cmd(ctx);
pmci->m10bmc.regmap = devm_regmap_init(dev, NULL, ctx, &m10bmc_pmci_regmap_config);
if (IS_ERR(pmci->m10bmc.regmap))
return PTR_ERR(pmci->m10bmc.regmap);
return m10bmc_dev_init(&pmci->m10bmc, &m10bmc_pmci_n6000);
}
#define FME_FEATURE_ID_M10BMC_PMCI 0x12
static const struct dfl_device_id m10bmc_pmci_ids[] = {
{ FME_ID, FME_FEATURE_ID_M10BMC_PMCI },
{ }
};
MODULE_DEVICE_TABLE(dfl, m10bmc_pmci_ids);
static struct dfl_driver m10bmc_pmci_driver = {
.drv = {
.name = "intel-m10-bmc",
.dev_groups = m10bmc_dev_groups,
},
.id_table = m10bmc_pmci_ids,
.probe = m10bmc_pmci_probe,
};
module_dfl_driver(m10bmc_pmci_driver);
MODULE_DESCRIPTION("MAX10 BMC PMCI-based interface");
MODULE_AUTHOR("Intel Corporation");
MODULE_LICENSE("GPL");
......@@ -5,39 +5,18 @@
* Copyright (C) 2018-2020 Intel Corporation. All rights reserved.
*/
#include <linux/bitfield.h>
#include <linux/dev_printk.h>
#include <linux/init.h>
#include <linux/mfd/core.h>
#include <linux/mfd/intel-m10-bmc.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
enum m10bmc_type {
M10_N3000,
M10_D5005,
M10_N5010,
};
static struct mfd_cell m10bmc_d5005_subdevs[] = {
{ .name = "d5005bmc-hwmon" },
{ .name = "d5005bmc-sec-update" }
};
static struct mfd_cell m10bmc_pacn3000_subdevs[] = {
{ .name = "n3000bmc-hwmon" },
{ .name = "n3000bmc-retimer" },
{ .name = "n3000bmc-sec-update" },
};
static struct mfd_cell m10bmc_n5010_subdevs[] = {
{ .name = "n5010bmc-hwmon" },
};
static const struct regmap_range m10bmc_regmap_range[] = {
regmap_reg_range(M10BMC_LEGACY_BUILD_VER, M10BMC_LEGACY_BUILD_VER),
regmap_reg_range(M10BMC_SYS_BASE, M10BMC_SYS_END),
regmap_reg_range(M10BMC_FLASH_BASE, M10BMC_FLASH_END),
regmap_reg_range(M10BMC_N3000_LEGACY_BUILD_VER, M10BMC_N3000_LEGACY_BUILD_VER),
regmap_reg_range(M10BMC_N3000_SYS_BASE, M10BMC_N3000_SYS_END),
regmap_reg_range(M10BMC_N3000_FLASH_BASE, M10BMC_N3000_FLASH_END),
};
static const struct regmap_access_table m10bmc_access_table = {
......@@ -51,88 +30,8 @@ static struct regmap_config intel_m10bmc_regmap_config = {
.reg_stride = 4,
.wr_table = &m10bmc_access_table,
.rd_table = &m10bmc_access_table,
.max_register = M10BMC_MEM_END,
};
static ssize_t bmc_version_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct intel_m10bmc *ddata = dev_get_drvdata(dev);
unsigned int val;
int ret;
ret = m10bmc_sys_read(ddata, 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 *ddata = dev_get_drvdata(dev);
unsigned int val;
int ret;
ret = m10bmc_sys_read(ddata, NIOS2_FW_VERSION, &val);
if (ret)
return ret;
return sprintf(buf, "0x%x\n", val);
}
static DEVICE_ATTR_RO(bmcfw_version);
static ssize_t mac_address_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct intel_m10bmc *max10 = dev_get_drvdata(dev);
unsigned int macaddr_low, macaddr_high;
int ret;
ret = m10bmc_sys_read(max10, M10BMC_MAC_LOW, &macaddr_low);
if (ret)
return ret;
ret = m10bmc_sys_read(max10, M10BMC_MAC_HIGH, &macaddr_high);
if (ret)
return ret;
return sysfs_emit(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n",
(u8)FIELD_GET(M10BMC_MAC_BYTE1, macaddr_low),
(u8)FIELD_GET(M10BMC_MAC_BYTE2, macaddr_low),
(u8)FIELD_GET(M10BMC_MAC_BYTE3, macaddr_low),
(u8)FIELD_GET(M10BMC_MAC_BYTE4, macaddr_low),
(u8)FIELD_GET(M10BMC_MAC_BYTE5, macaddr_high),
(u8)FIELD_GET(M10BMC_MAC_BYTE6, macaddr_high));
}
static DEVICE_ATTR_RO(mac_address);
static ssize_t mac_count_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct intel_m10bmc *max10 = dev_get_drvdata(dev);
unsigned int macaddr_high;
int ret;
ret = m10bmc_sys_read(max10, M10BMC_MAC_HIGH, &macaddr_high);
if (ret)
return ret;
return sysfs_emit(buf, "%u\n",
(u8)FIELD_GET(M10BMC_MAC_COUNT, macaddr_high));
}
static DEVICE_ATTR_RO(mac_count);
static struct attribute *m10bmc_attrs[] = {
&dev_attr_bmc_version.attr,
&dev_attr_bmcfw_version.attr,
&dev_attr_mac_address.attr,
&dev_attr_mac_count.attr,
NULL,
.max_register = M10BMC_N3000_MEM_END,
};
ATTRIBUTE_GROUPS(m10bmc);
static int check_m10bmc_version(struct intel_m10bmc *ddata)
{
......@@ -142,16 +41,16 @@ static int check_m10bmc_version(struct intel_m10bmc *ddata)
/*
* This check is to filter out the very old legacy BMC versions. In the
* old BMC chips, the BMC version info is stored in the old version
* register (M10BMC_LEGACY_BUILD_VER), so its read out value would have
* not been M10BMC_VER_LEGACY_INVALID (0xffffffff). But in new BMC
* register (M10BMC_N3000_LEGACY_BUILD_VER), so its read out value would have
* not been M10BMC_N3000_VER_LEGACY_INVALID (0xffffffff). But in new BMC
* chips that the driver supports, the value of this register should be
* M10BMC_VER_LEGACY_INVALID.
* M10BMC_N3000_VER_LEGACY_INVALID.
*/
ret = m10bmc_raw_read(ddata, M10BMC_LEGACY_BUILD_VER, &v);
ret = m10bmc_raw_read(ddata, M10BMC_N3000_LEGACY_BUILD_VER, &v);
if (ret)
return -ENODEV;
if (v != M10BMC_VER_LEGACY_INVALID) {
if (v != M10BMC_N3000_VER_LEGACY_INVALID) {
dev_err(ddata->dev, "bad version M10BMC detected\n");
return -ENODEV;
}
......@@ -162,19 +61,19 @@ static int check_m10bmc_version(struct intel_m10bmc *ddata)
static int intel_m10_bmc_spi_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
const struct intel_m10bmc_platform_info *info;
struct device *dev = &spi->dev;
struct mfd_cell *cells;
struct intel_m10bmc *ddata;
int ret, n_cell;
int ret;
ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata)
return -ENOMEM;
info = (struct intel_m10bmc_platform_info *)id->driver_data;
ddata->dev = dev;
ddata->regmap =
devm_regmap_init_spi_avmm(spi, &intel_m10bmc_regmap_config);
ddata->regmap = devm_regmap_init_spi_avmm(spi, &intel_m10bmc_regmap_config);
if (IS_ERR(ddata->regmap)) {
ret = PTR_ERR(ddata->regmap);
dev_err(dev, "Failed to allocate regmap: %d\n", ret);
......@@ -189,35 +88,66 @@ static int intel_m10_bmc_spi_probe(struct spi_device *spi)
return ret;
}
switch (id->driver_data) {
case M10_N3000:
cells = m10bmc_pacn3000_subdevs;
n_cell = ARRAY_SIZE(m10bmc_pacn3000_subdevs);
break;
case M10_D5005:
cells = m10bmc_d5005_subdevs;
n_cell = ARRAY_SIZE(m10bmc_d5005_subdevs);
break;
case M10_N5010:
cells = m10bmc_n5010_subdevs;
n_cell = ARRAY_SIZE(m10bmc_n5010_subdevs);
break;
default:
return -ENODEV;
}
return m10bmc_dev_init(ddata, info);
}
ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, cells, n_cell,
NULL, 0, NULL);
if (ret)
dev_err(dev, "Failed to register sub-devices: %d\n", ret);
static const struct m10bmc_csr_map m10bmc_n3000_csr_map = {
.base = M10BMC_N3000_SYS_BASE,
.build_version = M10BMC_N3000_BUILD_VER,
.fw_version = NIOS2_N3000_FW_VERSION,
.mac_low = M10BMC_N3000_MAC_LOW,
.mac_high = M10BMC_N3000_MAC_HIGH,
.doorbell = M10BMC_N3000_DOORBELL,
.auth_result = M10BMC_N3000_AUTH_RESULT,
.bmc_prog_addr = M10BMC_N3000_BMC_PROG_ADDR,
.bmc_reh_addr = M10BMC_N3000_BMC_REH_ADDR,
.bmc_magic = M10BMC_N3000_BMC_PROG_MAGIC,
.sr_prog_addr = M10BMC_N3000_SR_PROG_ADDR,
.sr_reh_addr = M10BMC_N3000_SR_REH_ADDR,
.sr_magic = M10BMC_N3000_SR_PROG_MAGIC,
.pr_prog_addr = M10BMC_N3000_PR_PROG_ADDR,
.pr_reh_addr = M10BMC_N3000_PR_REH_ADDR,
.pr_magic = M10BMC_N3000_PR_PROG_MAGIC,
.rsu_update_counter = M10BMC_N3000_STAGING_FLASH_COUNT,
};
return ret;
}
static struct mfd_cell m10bmc_d5005_subdevs[] = {
{ .name = "d5005bmc-hwmon" },
{ .name = "d5005bmc-sec-update" },
};
static struct mfd_cell m10bmc_pacn3000_subdevs[] = {
{ .name = "n3000bmc-hwmon" },
{ .name = "n3000bmc-retimer" },
{ .name = "n3000bmc-sec-update" },
};
static struct mfd_cell m10bmc_n5010_subdevs[] = {
{ .name = "n5010bmc-hwmon" },
};
static const struct intel_m10bmc_platform_info m10bmc_spi_n3000 = {
.cells = m10bmc_pacn3000_subdevs,
.n_cells = ARRAY_SIZE(m10bmc_pacn3000_subdevs),
.csr_map = &m10bmc_n3000_csr_map,
};
static const struct intel_m10bmc_platform_info m10bmc_spi_d5005 = {
.cells = m10bmc_d5005_subdevs,
.n_cells = ARRAY_SIZE(m10bmc_d5005_subdevs),
.csr_map = &m10bmc_n3000_csr_map,
};
static const struct intel_m10bmc_platform_info m10bmc_spi_n5010 = {
.cells = m10bmc_n5010_subdevs,
.n_cells = ARRAY_SIZE(m10bmc_n5010_subdevs),
.csr_map = &m10bmc_n3000_csr_map,
};
static const struct spi_device_id m10bmc_spi_id[] = {
{ "m10-n3000", M10_N3000 },
{ "m10-d5005", M10_D5005 },
{ "m10-n5010", M10_N5010 },
{ "m10-n3000", (kernel_ulong_t)&m10bmc_spi_n3000 },
{ "m10-d5005", (kernel_ulong_t)&m10bmc_spi_d5005 },
{ "m10-n5010", (kernel_ulong_t)&m10bmc_spi_n5010 },
{ }
};
MODULE_DEVICE_TABLE(spi, m10bmc_spi_id);
......@@ -225,14 +155,14 @@ MODULE_DEVICE_TABLE(spi, m10bmc_spi_id);
static struct spi_driver intel_m10bmc_spi_driver = {
.driver = {
.name = "intel-m10-bmc",
.dev_groups = m10bmc_groups,
.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 MAX 10 BMC Device Driver");
MODULE_DESCRIPTION("Intel MAX 10 BMC SPI bus interface");
MODULE_AUTHOR("Intel Corporation");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("spi:intel-m10-bmc");
......@@ -7,40 +7,43 @@
#ifndef __MFD_INTEL_M10_BMC_H
#define __MFD_INTEL_M10_BMC_H
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/dev_printk.h>
#include <linux/regmap.h>
#define M10BMC_LEGACY_BUILD_VER 0x300468
#define M10BMC_SYS_BASE 0x300800
#define M10BMC_SYS_END 0x300fff
#define M10BMC_FLASH_BASE 0x10000000
#define M10BMC_FLASH_END 0x1fffffff
#define M10BMC_MEM_END M10BMC_FLASH_END
#define M10BMC_N3000_LEGACY_BUILD_VER 0x300468
#define M10BMC_N3000_SYS_BASE 0x300800
#define M10BMC_N3000_SYS_END 0x300fff
#define M10BMC_N3000_FLASH_BASE 0x10000000
#define M10BMC_N3000_FLASH_END 0x1fffffff
#define M10BMC_N3000_MEM_END M10BMC_N3000_FLASH_END
#define M10BMC_STAGING_BASE 0x18000000
#define M10BMC_STAGING_SIZE 0x3800000
/* Register offset of system registers */
#define NIOS2_FW_VERSION 0x0
#define M10BMC_MAC_LOW 0x10
#define M10BMC_MAC_BYTE4 GENMASK(7, 0)
#define M10BMC_MAC_BYTE3 GENMASK(15, 8)
#define M10BMC_MAC_BYTE2 GENMASK(23, 16)
#define M10BMC_MAC_BYTE1 GENMASK(31, 24)
#define M10BMC_MAC_HIGH 0x14
#define M10BMC_MAC_BYTE6 GENMASK(7, 0)
#define M10BMC_MAC_BYTE5 GENMASK(15, 8)
#define M10BMC_MAC_COUNT GENMASK(23, 16)
#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)
#define M10BMC_VER_LEGACY_INVALID 0xffffffff
#define NIOS2_N3000_FW_VERSION 0x0
#define M10BMC_N3000_MAC_LOW 0x10
#define M10BMC_N3000_MAC_BYTE4 GENMASK(7, 0)
#define M10BMC_N3000_MAC_BYTE3 GENMASK(15, 8)
#define M10BMC_N3000_MAC_BYTE2 GENMASK(23, 16)
#define M10BMC_N3000_MAC_BYTE1 GENMASK(31, 24)
#define M10BMC_N3000_MAC_HIGH 0x14
#define M10BMC_N3000_MAC_BYTE6 GENMASK(7, 0)
#define M10BMC_N3000_MAC_BYTE5 GENMASK(15, 8)
#define M10BMC_N3000_MAC_COUNT GENMASK(23, 16)
#define M10BMC_N3000_TEST_REG 0x3c
#define M10BMC_N3000_BUILD_VER 0x68
#define M10BMC_N3000_VER_MAJOR_MSK GENMASK(23, 16)
#define M10BMC_N3000_VER_PCB_INFO_MSK GENMASK(31, 24)
#define M10BMC_N3000_VER_LEGACY_INVALID 0xffffffff
/* Secure update doorbell register, in system register region */
#define M10BMC_DOORBELL 0x400
#define M10BMC_N3000_DOORBELL 0x400
/* Authorization Result register, in system register region */
#define M10BMC_AUTH_RESULT 0x404
#define M10BMC_N3000_AUTH_RESULT 0x404
/* Doorbell register fields */
#define DRBL_RSU_REQUEST BIT(0)
......@@ -88,7 +91,6 @@
#define HOST_STATUS_ABORT_RSU 0x2
#define rsu_prog(doorbell) FIELD_GET(DRBL_RSU_PROGRESS, doorbell)
#define rsu_stat(doorbell) FIELD_GET(DRBL_RSU_STATUS, doorbell)
/* interval 100ms and timeout 5s */
#define NIOS_HANDSHAKE_INTERVAL_US (100 * 1000)
......@@ -103,29 +105,94 @@
#define RSU_COMPLETE_TIMEOUT_MS (40 * 60 * 1000)
/* Addresses for security related data in FLASH */
#define BMC_REH_ADDR 0x17ffc004
#define BMC_PROG_ADDR 0x17ffc000
#define BMC_PROG_MAGIC 0x5746
#define M10BMC_N3000_BMC_REH_ADDR 0x17ffc004
#define M10BMC_N3000_BMC_PROG_ADDR 0x17ffc000
#define M10BMC_N3000_BMC_PROG_MAGIC 0x5746
#define SR_REH_ADDR 0x17ffd004
#define SR_PROG_ADDR 0x17ffd000
#define SR_PROG_MAGIC 0x5253
#define M10BMC_N3000_SR_REH_ADDR 0x17ffd004
#define M10BMC_N3000_SR_PROG_ADDR 0x17ffd000
#define M10BMC_N3000_SR_PROG_MAGIC 0x5253
#define PR_REH_ADDR 0x17ffe004
#define PR_PROG_ADDR 0x17ffe000
#define PR_PROG_MAGIC 0x5250
#define M10BMC_N3000_PR_REH_ADDR 0x17ffe004
#define M10BMC_N3000_PR_PROG_ADDR 0x17ffe000
#define M10BMC_N3000_PR_PROG_MAGIC 0x5250
/* Address of 4KB inverted bit vector containing staging area FLASH count */
#define STAGING_FLASH_COUNT 0x17ffb000
#define M10BMC_N3000_STAGING_FLASH_COUNT 0x17ffb000
#define M10BMC_N6000_INDIRECT_BASE 0x400
#define M10BMC_N6000_SYS_BASE 0x0
#define M10BMC_N6000_SYS_END 0xfff
#define M10BMC_N6000_DOORBELL 0x1c0
#define M10BMC_N6000_AUTH_RESULT 0x1c4
#define M10BMC_N6000_BUILD_VER 0x0
#define NIOS2_N6000_FW_VERSION 0x4
#define M10BMC_N6000_MAC_LOW 0x20
#define M10BMC_N6000_MAC_HIGH (M10BMC_N6000_MAC_LOW + 4)
/* Addresses for security related data in FLASH */
#define M10BMC_N6000_BMC_REH_ADDR 0x7ffc004
#define M10BMC_N6000_BMC_PROG_ADDR 0x7ffc000
#define M10BMC_N6000_BMC_PROG_MAGIC 0x5746
#define M10BMC_N6000_SR_REH_ADDR 0x7ffd004
#define M10BMC_N6000_SR_PROG_ADDR 0x7ffd000
#define M10BMC_N6000_SR_PROG_MAGIC 0x5253
#define M10BMC_N6000_PR_REH_ADDR 0x7ffe004
#define M10BMC_N6000_PR_PROG_ADDR 0x7ffe000
#define M10BMC_N6000_PR_PROG_MAGIC 0x5250
#define M10BMC_N6000_STAGING_FLASH_COUNT 0x7ff5000
/**
* struct m10bmc_csr_map - Intel MAX 10 BMC CSR register map
*/
struct m10bmc_csr_map {
unsigned int base;
unsigned int build_version;
unsigned int fw_version;
unsigned int mac_low;
unsigned int mac_high;
unsigned int doorbell;
unsigned int auth_result;
unsigned int bmc_prog_addr;
unsigned int bmc_reh_addr;
unsigned int bmc_magic;
unsigned int sr_prog_addr;
unsigned int sr_reh_addr;
unsigned int sr_magic;
unsigned int pr_prog_addr;
unsigned int pr_reh_addr;
unsigned int pr_magic;
unsigned int rsu_update_counter;
};
/**
* struct intel_m10bmc_platform_info - Intel MAX 10 BMC platform specific information
* @cells: MFD cells
* @n_cells: MFD cells ARRAY_SIZE()
* @csr_map: the mappings for register definition of MAX10 BMC
*/
struct intel_m10bmc_platform_info {
struct mfd_cell *cells;
int n_cells;
const struct m10bmc_csr_map *csr_map;
};
/**
* struct intel_m10bmc - Intel MAX 10 BMC parent driver data structure
* @dev: this device
* @regmap: the regmap used to access registers by m10bmc itself
* @info: the platform information for MAX10 BMC
*/
struct intel_m10bmc {
struct device *dev;
struct regmap *regmap;
const struct intel_m10bmc_platform_info *info;
};
/*
......@@ -152,11 +219,22 @@ m10bmc_raw_read(struct intel_m10bmc *m10bmc, unsigned int addr,
* The base of the system registers could be configured by HW developers, and
* in HW SPEC, the base is not added to the addresses of the system registers.
*
* This macro helps to simplify the accessing of the system registers. And if
* This function helps to simplify the accessing of the system registers. And if
* the base is reconfigured in HW, SW developers could simply change the
* M10BMC_SYS_BASE accordingly.
* csr_map's base accordingly.
*/
static inline int m10bmc_sys_read(struct intel_m10bmc *m10bmc, unsigned int offset,
unsigned int *val)
{
const struct m10bmc_csr_map *csr_map = m10bmc->info->csr_map;
return m10bmc_raw_read(m10bmc, csr_map->base + offset, val);
}
/*
* MAX10 BMC Core support
*/
#define m10bmc_sys_read(m10bmc, offset, val) \
m10bmc_raw_read(m10bmc, M10BMC_SYS_BASE + (offset), val)
int m10bmc_dev_init(struct intel_m10bmc *m10bmc, const struct intel_m10bmc_platform_info *info);
extern const struct attribute_group *m10bmc_dev_groups[];
#endif /* __MFD_INTEL_M10_BMC_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment