sonic-buildimage/platform/mellanox/non-upstream-patches/patches/0048-hwmon-pmbus-Add-support-for-MPS-Multi-phase-mp2891-c.patch
Vivek 787dd7221d [Mellanox] Upgrade HW-MGMT to 7.0030.2008 and update platform-api (#17134)
Why I did it
Add platform support for Debian 12 (Bookworm) on Mellanox Platform

How I did it
Update hw-management to v7.0030.2008
Deprecate the sfp_count == module_count approach in favour of asic init completion
Ref: Mellanox/hw-mgmt@bf4f593
Add xxd package to base image which is required by hw-management scripts
Add the non-upstream flag into linux kernel cache options
Update the thermalctl logic based on new sysfs attributes
Fix the integrate-mlnx-hw-mgmt script to not populate the arm64 Kconfig
How to verify it
Build kernel and run platform tests

Signed-off-by: Vivek Reddy <vkarri@nvidia.com>
Co-authored-by: Junchao-Mellanox <junchao@nvidia.com>
Co-authored-by: Junchao-Mellanox <57339448+Junchao-Mellanox@users.noreply.github.com>
2023-11-21 18:53:15 -08:00

564 lines
15 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

From c8a04a4c79a9fb99215e93884ff76b89e9947275 Mon Sep 17 00:00:00 2001
From: Vadim Pasternak <vadimp@nvidia.com>
Date: Thu, 13 Jul 2023 06:16:53 +0000
Subject: [PATCH backport 6.1.42 48/85] hwmon: (pmbus) Add support for MPS
Multi-phase mp2891 controller
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Introduce driver for dual-loop, digital, multi-phase controller MP2891 from
Monolithic Power Systems, Inc. (MPS) vendor.
The MP2891 can work with MPSs Intelli-PhaseTM products to complete the
multi-phase voltage regulator (VR) solution with minimal external
components.
This device supports:
- Two power rails.
- Programmable Multi-Phase up to 16 Phases on rail 1, and a maximum of 8
phases on rail 2.
Signed-off-by: Vadim Pasternak <vadimp@nvidia.com>
---
Documentation/hwmon/mp2891.rst | 128 ++++++++++++
drivers/hwmon/pmbus/Kconfig | 9 +
drivers/hwmon/pmbus/Makefile | 1 +
drivers/hwmon/pmbus/mp2891.c | 357 +++++++++++++++++++++++++++++++++
4 files changed, 495 insertions(+)
create mode 100644 Documentation/hwmon/mp2891.rst
create mode 100644 drivers/hwmon/pmbus/mp2891.c
diff --git a/Documentation/hwmon/mp2891.rst b/Documentation/hwmon/mp2891.rst
new file mode 100644
index 000000000000..c4bda3d7ee8a
--- /dev/null
+++ b/Documentation/hwmon/mp2891.rst
@@ -0,0 +1,128 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Kernel driver mp2891
+====================
+
+Supported chips:
+
+ * MPS MP2891
+
+ Prefix: 'mp2891'
+
+Author:
+
+ Vadim Pasternak <vadimp@nvidia.com>
+
+Description
+-----------
+
+This driver implements support for Monolithic Power Systems, Inc. (MPS)
+vendor dual-loop, digital, multi-phase controller MP2891.
+The MP2891 can work with MPSs Intelli-PhaseTM products to complete the
+multi-phase voltage regulator (VR) solution with minimal external components.
+
+MP2891 is available in a QFN-56 (7mmx7mm) package.
+
+This device supports:
+
+- Two power rails.
+- Programmable Multi-Phase up to 16 Phases on rail 1, and a maximum of 8 phases
+ on rail 2.
+- PWM-VID Interface.
+- Two pages for telemetry.
+- Programmable pins for PMBus Address.
+- Ability to store and restore device configurations.
+- 200kHz to 3MHz Switching Frequency.
+- Automatic Loop Compensation.
+- Couple Inductor Mode.
+- Supports Multi-Configuration for 6 Different Applications.
+- Flexible Pulse-Width Modulation (PWM) Assignment for 2 Rails.
+- Automatic Phase-Shedding (APS) to Improve Overall Efficiency.
+- Phase-to-Phase Active Current Balancing with Configurable Offsets for Thermal
+ Balance.
+- Digital Load-Line Regulation.
+- Overclocking Mode by Adding Offset to VOUT.
+
+Device complaint with:
+
+- PMBus rev 1.3 interface.
+
+Device supports direct format for reading output current, output voltage,
+input and output power and temperature.
+Device supports linear format for reading input voltage and input power.
+
+The driver provides the next attributes for the current:
+
+- for current out input and maximum alarm;
+- for phase current: input and label.
+
+The driver exports the following attributes via the 'sysfs' files, where:
+
+- 'n' is number of configured phases (from 1 to 10);
+- index 1 for "iout";
+- indexes 2 ... 1 + n for phases.
+
+**curr[1-{1+n}]_input**
+
+**curr[1-{1+n}]_label**
+
+**curr1_max**
+
+**curr1_max_alarm**
+
+The driver provides the next attributes for the voltage:
+
+- for voltage in: input, low and high critical thresholds, low and high
+ critical alarms;
+- for voltage out: input and high alarm;
+
+The driver exports the following attributes via the 'sysfs' files, where
+
+**in1_crit**
+
+**in1_crit_alarm**
+
+**in1_input**
+
+**in1_label**
+
+**in1_min**
+
+**in1_min_alarm**
+
+**in2_alarm**
+
+**in2_input**
+
+**in2_label**
+
+The driver provides the next attributes for the power:
+
+- for power in alarm and input.
+- for power out: cap, cap alarm an input.
+
+The driver exports the following attributes via the 'sysfs' files, where
+- indexes 1 for "pin";
+- indexes 2 for "pout";
+
+**power1_alarm**
+
+**power1_input**
+
+**power1_label**
+
+**power2_input**
+
+**power2_label**
+
+**power2_max**
+
+**power2_max_alarm**
+
+The driver provides the next attributes for the temperature:
+
+**temp1_input**
+
+**temp1_max**
+
+**temp1_max_alarm**
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
index 89668af67206..77d67344cee4 100644
--- a/drivers/hwmon/pmbus/Kconfig
+++ b/drivers/hwmon/pmbus/Kconfig
@@ -299,6 +299,15 @@ config SENSORS_MP2888
This driver can also be built as a module. If so, the module will
be called mp2888.
+config SENSORS_MP2891
+ tristate "MPS MP2891"
+ help
+ If you say yes here you get hardware monitoring support for MPS
+ MP2891 Dual Loop Digital Multi-Phase Controller.
+
+ This driver can also be built as a module. If so, the module will
+ be called mp2891.
+
config SENSORS_MP2975
tristate "MPS MP2975"
help
diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile
index 0002dbe22d52..8e767d7b8c5b 100644
--- a/drivers/hwmon/pmbus/Makefile
+++ b/drivers/hwmon/pmbus/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_SENSORS_MAX31785) += max31785.o
obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
obj-$(CONFIG_SENSORS_MAX8688) += max8688.o
obj-$(CONFIG_SENSORS_MP2888) += mp2888.o
+obj-$(CONFIG_SENSORS_MP2891) += mp2891.o
obj-$(CONFIG_SENSORS_MP2975) += mp2975.o
obj-$(CONFIG_SENSORS_MP5023) += mp5023.o
obj-$(CONFIG_SENSORS_PLI1209BC) += pli1209bc.o
diff --git a/drivers/hwmon/pmbus/mp2891.c b/drivers/hwmon/pmbus/mp2891.c
new file mode 100644
index 000000000000..e9e82844ee2a
--- /dev/null
+++ b/drivers/hwmon/pmbus/mp2891.c
@@ -0,0 +1,357 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Hardware monitoring driver for MPS Multi-phase Digital VR Controllers(MP2891)
+ *
+ * Copyright (C) 2023 Nvidia
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include "pmbus.h"
+
+/* Vendor specific registers. */
+/*
+ * MP2891_MFR_SVI3_IOUT_PRT:
+ * bits 15:5 - reserved zeros;
+ * bits 4:3 - set SVI3 Vout digital filter
+ * b00: 5kHz
+ * b01: 2kHz
+ * b10: 1kHz
+ * b11: no filter
+ * bits 2:0 - define output current scaling selection of rail1.
+ * b000: 1 A/LSB
+ * b001: (1/32) A/LSB
+ * b010: (1/16) A/LSB
+ * b011: (1/8) A/LSB
+ * b100: (1/4) A/LSB
+ * b101: (1/2) A/LSB
+ * b110: 1 A/LSB
+ * b111: 2 A/LSB
+ */
+#define MP2891_MFR_SVI3_IOUT_PRT 0x65
+/*
+ * MP2891_MFR_VOUT_LOOP_CTRL:
+ * bits 15:14 define the VID step.
+ * b00: 6.25mV
+ * b01: 5mV
+ * b10: 2mV
+ * b11: 1mV
+ * bit 13 enable bit of 2.5mV resolution.
+ * b0: disable
+ * b1: enable
+ * bits 12:11 reserved zeros
+ * bit 10 defines rail remote sense amplifier gain:
+ * b0: 1
+ * b1: 0.5
+ * bit 9 DC reference_select
+ * b0: Comp EA uses Vfb and Vref
+ * b1: Comp EA uses Vdiff and Vref
+ * bit 8 enables DC loop calibration at DCM.
+ * b0: disable
+ * b1: enable
+ * bit 7 enables DC loop calibration both at DCM and CCM operation.
+ * b0: disable
+ * b1: enable
+ * bit 6 - holds DC loop when the PWM time interval meets PWM switching period condition
+ * set with PMBus command MFR_VR_CONFIG1 (B7h), bit [3:2].
+ * b0: disable hold DC loop when PWM switching period condition meets
+ * b1: hold DC loop when PWM switching period condition meets
+ * bit 5 hold DC loop when phase count is changed.
+ * b0: disable hold DC loop when phase number change
+ * b1: hold the DC loop when phase number change.
+ * bit 4 hold DC loop regulation when a load transient event is detected.
+ * b0: disable hold DC loop when meets VFB+/- window condition
+ * b1: hold DC loop when meets VFB+/- window condition
+ * bits 3:0 set the DC loop minimal holding time in direct format.
+ */
+#define MP2891_MFR_VOUT_LOOP_CTRL 0xbd
+
+#define MP2891_VID_STEP_POS 14
+#define MP2891_VID_STEP_MASK GENMASK(MP2891_VID_STEP_POS + 1, MP2891_VID_STEP_POS)
+#define MP2891_DAC_2P5MV_MASK BIT(13)
+#define MP2891_IOUT_SCALE_MASK GENMASK(2, 0)
+
+#define MP2891_PAGE_NUM 2
+#define MP2891_RAIL1_FUNC (PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | \
+ PMBUS_HAVE_TEMP | PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | \
+ PMBUS_PHASE_VIRTUAL)
+
+#define MP2891_RAIL2_FUNC (PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_TEMP | \
+ PMBUS_HAVE_POUT | PMBUS_PHASE_VIRTUAL)
+
+struct mp2891_data {
+ struct pmbus_driver_info info;
+ int vid_step[MP2891_PAGE_NUM];
+ int iout_scale[MP2891_PAGE_NUM];
+};
+
+#define to_mp2891_data(x) container_of(x, struct mp2891_data, info)
+
+static int mp2891_read_vout(struct i2c_client *client, int page, int phase, int reg)
+{
+ int ret;
+
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct mp2891_data *data = to_mp2891_data(info);
+
+ ret = pmbus_read_word_data(client, page, phase, reg);
+
+ return ret < 0 ? ret : ret * data->vid_step[page] / 100;
+}
+
+static int mp2891_read_iout(struct i2c_client *client, int page, int phase, int reg)
+{
+ int ret;
+
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct mp2891_data *data = to_mp2891_data(info);
+
+ ret = pmbus_read_word_data(client, page, phase, reg);
+
+ return ret < 0 ? ret : ret * data->iout_scale[page];
+}
+
+static int mp2891_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+ int ret;
+
+ switch (reg) {
+ case PMBUS_VOUT_MODE:
+ /*
+ * Enforce VOUT direct format, since device allows to set the
+ * different formats for the different rails. Conversion from
+ * VID to direct provided by driver internally, in case it is
+ * necessary.
+ */
+ ret = PB_VOUT_MODE_DIRECT;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int mp2891_read_word_data(struct i2c_client *client, int page, int phase, int reg)
+{
+ switch (reg) {
+ case PMBUS_READ_VOUT:
+ return mp2891_read_vout(client, page, phase, reg);
+ case PMBUS_READ_IOUT:
+ return mp2891_read_iout(client, page, phase, reg);
+ case PMBUS_OT_WARN_LIMIT:
+ case PMBUS_OT_FAULT_LIMIT:
+ case PMBUS_UT_WARN_LIMIT:
+ case PMBUS_UT_FAULT_LIMIT:
+ case PMBUS_VOUT_OV_WARN_LIMIT:
+ case PMBUS_VIN_OV_WARN_LIMIT:
+ case PMBUS_POUT_MAX:
+ case PMBUS_POUT_OP_FAULT_LIMIT:
+ case PMBUS_MFR_VIN_MIN:
+ case PMBUS_MFR_VOUT_MIN:
+ case PMBUS_MFR_VIN_MAX:
+ case PMBUS_MFR_VOUT_MAX:
+ case PMBUS_MFR_IIN_MAX:
+ case PMBUS_MFR_IOUT_MAX:
+ case PMBUS_MFR_PIN_MAX:
+ case PMBUS_MFR_POUT_MAX:
+ case PMBUS_MFR_MAX_TEMP_1:
+ return -ENXIO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mp2891_identify_vid(struct i2c_client *client, struct mp2891_data *data, u32 reg,
+ int page)
+{
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_read_word_data(client, reg);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Obtain vid_step from MP2891_MFR_VOUT_LOOP_CTRL register:
+ * bit 13 = 1, the vid_step is below 2.5mV/LSB;
+ * bit 13 = 0, the vid_step is defined by bits 15:14:
+ * 00b - 6.25mV/LSB, 01b - 5mV/LSB, 10b - 2mV/LSB, 11b - 1mV
+ */
+ if ((ret & MP2891_DAC_2P5MV_MASK) >> MP2891_VID_STEP_POS) {
+ data->vid_step[page] = 250;
+ return 0;
+ }
+
+ switch ((ret & MP2891_VID_STEP_MASK) >> MP2891_VID_STEP_POS) {
+ case 0:
+ data->vid_step[page] = 625;
+ break;
+ case 1:
+ data->vid_step[page] = 500;
+ break;
+ case 2:
+ data->vid_step[page] = 200;
+ break;
+ default:
+ data->vid_step[page] = 100;
+ break;
+ }
+
+ return 0;
+}
+
+static int mp2891_identify_rails_vid(struct i2c_client *client, struct mp2891_data *data)
+{
+ int ret;
+
+ /* Identify vid_step for rail 1. */
+ ret = mp2891_identify_vid(client, data, MP2891_MFR_VOUT_LOOP_CTRL, 0);
+ if (ret < 0)
+ return ret;
+
+ /* Identify vid_step for rail 2. */
+ return mp2891_identify_vid(client, data, MP2891_MFR_VOUT_LOOP_CTRL, 1);
+}
+
+static int
+mp2891_iout_scale_get(struct i2c_client *client, struct mp2891_data *data, u32 reg, int page)
+{
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_read_word_data(client, reg);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Obtain iout_scale from the register MP2891_MFR_SVI3_IOUT_PRT, bits 2-0.
+ * The value is selected as below:
+ * 000b - 1A/LSB, 001b - (1/32)A/LSB, 010b - (1/16)A/LSB,
+ * 011b - (1/8)A/LSB, 100b - (1/4)A/LSB, 101b - (1/2)A/LSB
+ * 110b - 1A/LSB, 111b - 2A/LSB
+ */
+ switch (ret & MP2891_IOUT_SCALE_MASK) {
+ case 0:
+ case 6:
+ data->iout_scale[page] = 32;
+ return 0;
+ case 1:
+ data->iout_scale[page] = 1;
+ return 0;
+ case 2:
+ data->iout_scale[page] = 2;
+ return 0;
+ case 3:
+ data->iout_scale[page] = 4;
+ return 0;
+ case 4:
+ data->iout_scale[page] = 8;
+ return 0;
+ case 5:
+ data->iout_scale[page] = 16;
+ return 0;
+ default:
+ data->iout_scale[page] = 64;
+ return 0;
+ }
+}
+
+static int mp2891_rails_iout_scale_get(struct i2c_client *client, struct mp2891_data *data)
+{
+ int ret;
+
+ /* Get iout_scale for rail 1. */
+ ret = mp2891_iout_scale_get(client, data, MP2891_MFR_SVI3_IOUT_PRT, 0);
+ /* Get iout_scale for rail 2. */
+ return ret < 0 ? ret : mp2891_iout_scale_get(client, data, MP2891_MFR_SVI3_IOUT_PRT, 1);
+}
+
+static struct pmbus_driver_info mp2891_info = {
+ .pages = MP2891_PAGE_NUM,
+ .format[PSC_VOLTAGE_IN] = direct,
+ .format[PSC_VOLTAGE_OUT] = direct,
+ .format[PSC_CURRENT_OUT] = direct,
+ .format[PSC_TEMPERATURE] = direct,
+ .format[PSC_POWER] = linear,
+ .m[PSC_VOLTAGE_IN] = 1,
+ .m[PSC_VOLTAGE_OUT] = 1,
+ .m[PSC_CURRENT_OUT] = 32,
+ .m[PSC_TEMPERATURE] = 1,
+ .R[PSC_VOLTAGE_IN] = 3,
+ .R[PSC_VOLTAGE_OUT] = 3,
+ .R[PSC_CURRENT_OUT] = 0,
+ .R[PSC_TEMPERATURE] = 0,
+ .b[PSC_VOLTAGE_IN] = 0,
+ .b[PSC_VOLTAGE_OUT] = 0,
+ .b[PSC_CURRENT_OUT] = 0,
+ .b[PSC_TEMPERATURE] = 0,
+ .func[0] = MP2891_RAIL1_FUNC,
+ .func[1] = MP2891_RAIL2_FUNC,
+ .read_word_data = mp2891_read_word_data,
+ .read_byte_data = mp2891_read_byte_data,
+};
+
+static int mp2891_probe(struct i2c_client *client)
+{
+ struct pmbus_driver_info *info;
+ struct mp2891_data *data;
+ int ret;
+
+ data = devm_kzalloc(&client->dev, sizeof(struct mp2891_data), GFP_KERNEL);
+
+ if (!data)
+ return -ENOMEM;
+
+ memcpy(&data->info, &mp2891_info, sizeof(*info));
+ info = &data->info;
+
+ /* Identify VID setting per rail - obtain the vid_step of output voltage. */
+ ret = mp2891_identify_rails_vid(client, data);
+ if (ret < 0)
+ return ret;
+
+ /* Get iout scale per rail - obtain current scale. */
+ ret = mp2891_rails_iout_scale_get(client, data);
+ if (ret < 0)
+ return ret;
+
+ return pmbus_do_probe(client, info);
+}
+
+static const struct i2c_device_id mp2891_id[] = {
+ {"mp2891", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, mp2891_id);
+
+static const struct of_device_id __maybe_unused mp2891_of_match[] = {
+ {.compatible = "mps,mp2891"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, mp2891_of_match);
+
+static struct i2c_driver mp2891_driver = {
+ .driver = {
+ .name = "mp2891",
+ .of_match_table = mp2891_of_match,
+ },
+ .probe_new = mp2891_probe,
+ .id_table = mp2891_id,
+};
+
+module_i2c_driver(mp2891_driver);
+
+MODULE_DESCRIPTION("PMBus driver for MPS MP2891 device");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
--
2.20.1