313 lines
11 KiB
Diff
313 lines
11 KiB
Diff
|
From 3e4ff8f2195a3dc7b04bb5a1b9fd6b655f78a75e Mon Sep 17 00:00:00 2001
|
||
|
From: Vadim Pasternak <vadimp@nvidia.com>
|
||
|
Date: Mon, 24 Jul 2023 11:10:50 +0000
|
||
|
Subject: [PATH backport v6.1 54/54] platform: mellanox: Introduce support for
|
||
|
switches equipped with new FPGA device
|
||
|
|
||
|
Add support for Nvidia MQM97xx and MSN47xx family switches equipped with
|
||
|
new FPGA device.
|
||
|
|
||
|
These switches are based on previous generation of MQM97xx and MSN47xx
|
||
|
switches, but COMe module uses new FPGA device.
|
||
|
|
||
|
Platform configuration for new switches is based on the new VMOD0016
|
||
|
class. Configuration is extended to support new register map with
|
||
|
callbacks supporting indirect addressing for PCIe-to-LPC bridge.
|
||
|
This bridge provides interface between FPGA at COMe board (directly
|
||
|
connected to CPU PCIe root complex) to CPLDs on switch board (which
|
||
|
cannot be connected directly to PCIe root complex).
|
||
|
|
||
|
Signed-off-by: Vadim Pasternak <vadimp@nvidia.com>
|
||
|
Reviewed-by: Michael Shych <michaelsh@nvidia.com>
|
||
|
---
|
||
|
drivers/platform/x86/mlx-platform.c | 196 ++++++++++++++++++++++++++++
|
||
|
1 file changed, 196 insertions(+)
|
||
|
|
||
|
diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c
|
||
|
index 9021597b5446..46958810e972 100644
|
||
|
--- a/drivers/platform/x86/mlx-platform.c
|
||
|
+++ b/drivers/platform/x86/mlx-platform.c
|
||
|
@@ -183,6 +183,9 @@
|
||
|
#define MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET 0xfb
|
||
|
#define MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET 0xfc
|
||
|
#define MLXPLAT_CPLD_LPC_REG_CONFIG3_OFFSET 0xfd
|
||
|
+#define MLXPLAT_CPLD_LPC_REG_EXT_MIN_OFFSET 0x100
|
||
|
+#define MLXPLAT_CPLD_LPC_REG_EXT_MID_OFFSET 0x195
|
||
|
+#define MLXPLAT_CPLD_LPC_REG_EXT_MAX_OFFSET 0x1ff
|
||
|
#define MLXPLAT_CPLD_LPC_IO_RANGE 0x100
|
||
|
|
||
|
#define MLXPLAT_CPLD_LPC_PIO_OFFSET 0x10000UL
|
||
|
@@ -277,6 +280,7 @@
|
||
|
/* Maximum number of possible physical buses equipped on system */
|
||
|
#define MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM 16
|
||
|
#define MLXPLAT_CPLD_MAX_PHYS_EXT_ADAPTER_NUM 24
|
||
|
+#define MLXPLAT_CPLD_DEFAULT_MUX_HOTPLUG_VECTOR 0
|
||
|
|
||
|
/* Number of channels in group */
|
||
|
#define MLXPLAT_CPLD_GRP_CHNL_NUM 8
|
||
|
@@ -338,6 +342,21 @@
|
||
|
#define PCI_DEVICE_ID_LATTICE_I2C_BRIDGE 0x9c2f
|
||
|
#define PCI_DEVICE_ID_LATTICE_JTAG_BRIDGE 0x9c30
|
||
|
#define PCI_DEVICE_ID_LATTICE_LPC_BRIDGE 0x9c32
|
||
|
+#define MLXPLAT_FPGA_PCI_BAR0_SIZE 0x4000
|
||
|
+#define MLXPLAT_FPGA_PCI_BASE_OFFSET 0x00000000
|
||
|
+#define MLXPLAT_FPGA_PCI_MSB_ADDR 0x25
|
||
|
+#define MLXPLAT_FPGA_PCI_MSB_EXT_ADDR 0x20
|
||
|
+#define MLXPLAT_FPGA_PCI_LSB_ADDR_OFFSET MLXPLAT_FPGA_PCI_BASE_OFFSET
|
||
|
+#define MLXPLAT_FPGA_PCI_MSB_ADDR_OFFSET (MLXPLAT_FPGA_PCI_BASE_OFFSET + 0x01)
|
||
|
+#define MLXPLAT_FPGA_PCI_DATA_OUT_OFFSET (MLXPLAT_FPGA_PCI_BASE_OFFSET + 0x02)
|
||
|
+#define MLXPLAT_FPGA_PCI_DATA_IN_OFFSET (MLXPLAT_FPGA_PCI_BASE_OFFSET + 0x03)
|
||
|
+#define MLXPLAT_FPGA_PCI_CTRL_OFFSET (MLXPLAT_FPGA_PCI_BASE_OFFSET + 0x04)
|
||
|
+#define MLXPLAT_FPGA_PCI_STAT_OFFSET (MLXPLAT_FPGA_PCI_BASE_OFFSET + 0x05)
|
||
|
+
|
||
|
+#define MLXPLAT_FPGA_PCI_CTRL_READ BIT(0)
|
||
|
+#define MLXPLAT_FPGA_PCI_CTRL_WRITE BIT(1)
|
||
|
+#define MLXPLAT_FPGA_PCI_COMPLETED GENMASK(1, 0)
|
||
|
+#define MLXPLAT_FPGA_PCI_TO 50 /* usec */
|
||
|
|
||
|
/* mlxplat_priv - platform private data
|
||
|
* @pdev_i2c - i2c controller platform device
|
||
|
@@ -453,6 +472,28 @@ static struct i2c_mux_reg_platform_data mlxplat_default_mux_data[] = {
|
||
|
|
||
|
};
|
||
|
|
||
|
+/* Default channels vector for regmap mux. */
|
||
|
+static int mlxplat_default_regmap_mux_chan[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
|
||
|
+
|
||
|
+/* Platform regmap mux data */
|
||
|
+static struct i2c_mux_regmap_platform_data mlxplat_default_regmap_mux_data[] = {
|
||
|
+ {
|
||
|
+ .parent = 1,
|
||
|
+ .chan_ids = mlxplat_default_regmap_mux_chan,
|
||
|
+ .num_adaps = ARRAY_SIZE(mlxplat_default_regmap_mux_chan),
|
||
|
+ .sel_reg_addr = MLXPLAT_CPLD_LPC_REG_I2C_CH1_OFFSET,
|
||
|
+ .reg_size = 1,
|
||
|
+ },
|
||
|
+ {
|
||
|
+ .parent = 1,
|
||
|
+ .chan_ids = mlxplat_default_regmap_mux_chan,
|
||
|
+ .num_adaps = ARRAY_SIZE(mlxplat_default_regmap_mux_chan),
|
||
|
+ .sel_reg_addr = MLXPLAT_CPLD_LPC_REG_I2C_CH2_OFFSET,
|
||
|
+ .reg_size = 1,
|
||
|
+ },
|
||
|
+
|
||
|
+};
|
||
|
+
|
||
|
/* Platform mux configuration variables */
|
||
|
static int mlxplat_max_adap_num;
|
||
|
static int mlxplat_mux_num;
|
||
|
@@ -3540,6 +3581,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = {
|
||
|
.mask = GENMASK(7, 0) & ~BIT(2),
|
||
|
.mode = 0200,
|
||
|
},
|
||
|
+ {
|
||
|
+ .label = "kexec_activated",
|
||
|
+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP2_OFFSET,
|
||
|
+ .mask = GENMASK(7, 0) & ~BIT(1),
|
||
|
+ .mode = 0644,
|
||
|
+ },
|
||
|
{
|
||
|
.label = "erot1_reset",
|
||
|
.reg = MLXPLAT_CPLD_LPC_REG_RESET_GP2_OFFSET,
|
||
|
@@ -5065,6 +5112,7 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
|
||
|
case MLXPLAT_CPLD_LPC_REG_PWM3_OFFSET:
|
||
|
case MLXPLAT_CPLD_LPC_REG_PWM4_OFFSET:
|
||
|
case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET:
|
||
|
+ case MLXPLAT_CPLD_LPC_REG_EXT_MIN_OFFSET ... MLXPLAT_CPLD_LPC_REG_EXT_MAX_OFFSET:
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
@@ -5230,6 +5278,7 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
|
||
|
case MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET:
|
||
|
case MLXPLAT_CPLD_LPC_REG_CONFIG3_OFFSET:
|
||
|
case MLXPLAT_CPLD_LPC_REG_UFM_VERSION_OFFSET:
|
||
|
+ case MLXPLAT_CPLD_LPC_REG_EXT_MIN_OFFSET ... MLXPLAT_CPLD_LPC_REG_EXT_MAX_OFFSET:
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
@@ -5387,6 +5436,7 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
|
||
|
case MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET:
|
||
|
case MLXPLAT_CPLD_LPC_REG_CONFIG3_OFFSET:
|
||
|
case MLXPLAT_CPLD_LPC_REG_UFM_VERSION_OFFSET:
|
||
|
+ case MLXPLAT_CPLD_LPC_REG_EXT_MIN_OFFSET ... MLXPLAT_CPLD_LPC_REG_EXT_MAX_OFFSET:
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
@@ -5417,6 +5467,14 @@ static const struct reg_default mlxplat_mlxcpld_regmap_ng400[] = {
|
||
|
{ MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET, 0x00 },
|
||
|
};
|
||
|
|
||
|
+static const struct reg_default mlxplat_mlxcpld_regmap_bf3[] = {
|
||
|
+ { MLXPLAT_CPLD_LPC_REG_GP2_OFFSET, 0xc1 },
|
||
|
+ { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 },
|
||
|
+ { MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET, 0x00 },
|
||
|
+ { MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET, 0x00 },
|
||
|
+ { MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET, 0x00 },
|
||
|
+};
|
||
|
+
|
||
|
static const struct reg_default mlxplat_mlxcpld_regmap_rack_switch[] = {
|
||
|
{ MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, MLXPLAT_REGMAP_NVSWITCH_PWM_DEFAULT },
|
||
|
{ MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET, 0x00 },
|
||
|
@@ -5545,6 +5603,114 @@ static const struct regmap_config mlxplat_mlxcpld_regmap_config_eth_modular = {
|
||
|
.reg_write = mlxplat_mlxcpld_reg_write,
|
||
|
};
|
||
|
|
||
|
+/* Wait completion routine for indirect access for register map */
|
||
|
+static int mlxplat_fpga_completion_wait(struct mlxplat_mlxcpld_regmap_context *ctx)
|
||
|
+{
|
||
|
+ unsigned long end;
|
||
|
+ u8 status;
|
||
|
+
|
||
|
+ end = jiffies + msecs_to_jiffies(MLXPLAT_FPGA_PCI_TO);
|
||
|
+ do {
|
||
|
+ status = ioread8(ctx->base + MLXPLAT_FPGA_PCI_STAT_OFFSET);
|
||
|
+ if (!(status & MLXPLAT_FPGA_PCI_COMPLETED))
|
||
|
+ return 0;
|
||
|
+ cond_resched();
|
||
|
+ } while (time_before(jiffies, end));
|
||
|
+
|
||
|
+ return -EIO;
|
||
|
+}
|
||
|
+
|
||
|
+/* Read callback for indirect register map access */
|
||
|
+static int mlxplat_fpga_reg_read(void *context, unsigned int reg, unsigned int *val)
|
||
|
+{
|
||
|
+ struct mlxplat_mlxcpld_regmap_context *ctx = context;
|
||
|
+ unsigned int msb_off = MLXPLAT_FPGA_PCI_MSB_ADDR;
|
||
|
+ int err;
|
||
|
+
|
||
|
+ if (reg >= MLXPLAT_CPLD_LPC_REG_EXT_MIN_OFFSET) {
|
||
|
+ if (reg <= MLXPLAT_CPLD_LPC_REG_EXT_MID_OFFSET) {
|
||
|
+ /* Access to 2-nd FPGA bank */
|
||
|
+ *val = ioread8(i2c_bridge_addr + reg -
|
||
|
+ MLXPLAT_CPLD_LPC_REG_EXT_MIN_OFFSET);
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+ /* Access to 3-rd FPGA bank */
|
||
|
+ reg -= MLXPLAT_CPLD_LPC_REG_EXT_MIN_OFFSET;
|
||
|
+ msb_off = MLXPLAT_FPGA_PCI_MSB_EXT_ADDR;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Verify there is no pending transactions */
|
||
|
+ err = mlxplat_fpga_completion_wait(ctx);
|
||
|
+ if (err)
|
||
|
+ return err;
|
||
|
+
|
||
|
+ /* Set address in register space */
|
||
|
+ iowrite8(msb_off, ctx->base + MLXPLAT_FPGA_PCI_MSB_ADDR_OFFSET);
|
||
|
+ iowrite8(reg, ctx->base + MLXPLAT_FPGA_PCI_LSB_ADDR_OFFSET);
|
||
|
+ /* Activate read operation */
|
||
|
+ iowrite8(MLXPLAT_FPGA_PCI_CTRL_READ, ctx->base + MLXPLAT_FPGA_PCI_CTRL_OFFSET);
|
||
|
+ /* Verify transaction completion */
|
||
|
+ err = mlxplat_fpga_completion_wait(ctx);
|
||
|
+ if (err)
|
||
|
+ return err;
|
||
|
+
|
||
|
+ /* Read data */
|
||
|
+ *val = ioread8(ctx->base + MLXPLAT_FPGA_PCI_DATA_IN_OFFSET);
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+/* Write callback for indirect register map access */
|
||
|
+static int mlxplat_fpga_reg_write(void *context, unsigned int reg, unsigned int val)
|
||
|
+{
|
||
|
+ struct mlxplat_mlxcpld_regmap_context *ctx = context;
|
||
|
+ unsigned int msb_off = MLXPLAT_FPGA_PCI_MSB_ADDR;
|
||
|
+ int err;
|
||
|
+
|
||
|
+ if (reg >= MLXPLAT_CPLD_LPC_REG_EXT_MIN_OFFSET) {
|
||
|
+ if (reg <= MLXPLAT_CPLD_LPC_REG_EXT_MID_OFFSET) {
|
||
|
+ /* Access to 2-nd FPGA bank */
|
||
|
+ iowrite8(val, i2c_bridge_addr + reg - MLXPLAT_CPLD_LPC_REG_EXT_MIN_OFFSET);
|
||
|
+ /* Flush modification */
|
||
|
+ wmb();
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Access to 3-rd FPGA bank */
|
||
|
+ reg -= MLXPLAT_CPLD_LPC_REG_EXT_MIN_OFFSET;
|
||
|
+ msb_off = MLXPLAT_FPGA_PCI_MSB_EXT_ADDR;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Verify there is no pending transactions */
|
||
|
+ err = mlxplat_fpga_completion_wait(ctx);
|
||
|
+ if (err)
|
||
|
+ return err;
|
||
|
+
|
||
|
+ /* Set address in register space */
|
||
|
+ iowrite8(msb_off, ctx->base + MLXPLAT_FPGA_PCI_MSB_ADDR_OFFSET);
|
||
|
+ iowrite8(reg, ctx->base + MLXPLAT_FPGA_PCI_LSB_ADDR_OFFSET);
|
||
|
+ /* Set data to be written */
|
||
|
+ iowrite8(val, ctx->base + MLXPLAT_FPGA_PCI_DATA_OUT_OFFSET);
|
||
|
+ /* Activate write operation */
|
||
|
+ iowrite8(MLXPLAT_FPGA_PCI_CTRL_WRITE, ctx->base + MLXPLAT_FPGA_PCI_CTRL_OFFSET);
|
||
|
+
|
||
|
+ return mlxplat_fpga_completion_wait(ctx);
|
||
|
+}
|
||
|
+
|
||
|
+static const struct regmap_config mlxplat_fpga_regmap_config_bf3_comex_default = {
|
||
|
+ .reg_bits = 9,
|
||
|
+ .val_bits = 8,
|
||
|
+ .max_register = 511,
|
||
|
+ .cache_type = REGCACHE_FLAT,
|
||
|
+ .writeable_reg = mlxplat_mlxcpld_writeable_reg,
|
||
|
+ .readable_reg = mlxplat_mlxcpld_readable_reg,
|
||
|
+ .volatile_reg = mlxplat_mlxcpld_volatile_reg,
|
||
|
+ .reg_defaults = mlxplat_mlxcpld_regmap_bf3,
|
||
|
+ .num_reg_defaults = ARRAY_SIZE(mlxplat_mlxcpld_regmap_bf3),
|
||
|
+ .reg_read = mlxplat_fpga_reg_read,
|
||
|
+ .reg_write = mlxplat_fpga_reg_write,
|
||
|
+};
|
||
|
+
|
||
|
static struct resource mlxplat_mlxcpld_resources[] = {
|
||
|
[0] = DEFINE_RES_IRQ_NAMED(MLXPLAT_CPLD_LPC_SYSIRQ, "mlxreg-hotplug"),
|
||
|
};
|
||
|
@@ -5927,6 +6093,30 @@ static int __init mlxplat_dmi_l1_switch_matched(const struct dmi_system_id *dmi)
|
||
|
return mlxplat_register_platform_device();
|
||
|
}
|
||
|
|
||
|
+static int __init mlxplat_dmi_bf3_comex_default_matched(const struct dmi_system_id *dmi)
|
||
|
+{
|
||
|
+ int i;
|
||
|
+
|
||
|
+ mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM;
|
||
|
+ mlxplat_mux_hotplug_num = MLXPLAT_CPLD_DEFAULT_MUX_HOTPLUG_VECTOR;
|
||
|
+ mlxplat_mux_num = ARRAY_SIZE(mlxplat_default_regmap_mux_data);
|
||
|
+ mlxplat_mux_regmap_data = mlxplat_default_regmap_mux_data;
|
||
|
+ mlxplat_hotplug = &mlxplat_mlxcpld_ext_data;
|
||
|
+ mlxplat_hotplug->deferred_nr =
|
||
|
+ mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
|
||
|
+ mlxplat_led = &mlxplat_default_ng_led_data;
|
||
|
+ mlxplat_regs_io = &mlxplat_default_ng_regs_io_data;
|
||
|
+ mlxplat_fan = &mlxplat_default_fan_data;
|
||
|
+ for (i = 0; i < ARRAY_SIZE(mlxplat_mlxcpld_wd_set_type2); i++)
|
||
|
+ mlxplat_wd_data[i] = &mlxplat_mlxcpld_wd_set_type2[i];
|
||
|
+ mlxplat_i2c = &mlxplat_mlxcpld_i2c_ng_data;
|
||
|
+ mlxplat_regmap_config = &mlxplat_fpga_regmap_config_bf3_comex_default;
|
||
|
+ mlxplat_reboot_nb = &mlxplat_reboot_default_nb;
|
||
|
+ pm_power_off = mlxplat_poweroff;
|
||
|
+
|
||
|
+ return 1;
|
||
|
+}
|
||
|
+
|
||
|
static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
|
||
|
{
|
||
|
.callback = mlxplat_dmi_default_wc_matched,
|
||
|
@@ -6015,6 +6205,12 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
|
||
|
DMI_MATCH(DMI_BOARD_NAME, "VMOD0015"),
|
||
|
},
|
||
|
},
|
||
|
+ {
|
||
|
+ .callback = mlxplat_dmi_bf3_comex_default_matched,
|
||
|
+ .matches = {
|
||
|
+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0016"),
|
||
|
+ },
|
||
|
+ },
|
||
|
{
|
||
|
.callback = mlxplat_dmi_l1_switch_matched,
|
||
|
.matches = {
|
||
|
--
|
||
|
2.20.1
|
||
|
|