misc: smpro-misc: Add Ampere's Altra SMpro misc driver

Add driver support for accessing various information reported by
Ampere's SMpro co-processor such as Boot Progress and other
miscellaneous data.

Signed-off-by: Quan Nguyen <quan@os.amperecomputing.com>
Link: https://lore.kernel.org/r/20221031024442.2490881-4-quan@os.amperecomputing.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Quan Nguyen 2022-10-31 09:44:42 +07:00 committed by Greg Kroah-Hartman
parent 4a4a4e9eba
commit 763dc90e9a
4 changed files with 204 additions and 0 deletions

View File

@ -262,3 +262,51 @@ Description:
For more details, see section `5.7 GPI Status Registers,
Altra Family Soc BMC Interface Specification`.
What: /sys/bus/platform/devices/smpro-misc.*/boot_progress
KernelVersion: 6.1
Contact: Quan Nguyen <quan@os.amperecomputing.com>
Description:
(RO) Contains the boot stages information in hex as format below::
AABBCCCCCCCC
where:
- ``AA`` : The boot stages
- 00: SMpro firmware booting
- 01: PMpro firmware booting
- 02: ATF BL1 firmware booting
- 03: DDR initialization
- 04: DDR training report status
- 05: ATF BL2 firmware booting
- 06: ATF BL31 firmware booting
- 07: ATF BL32 firmware booting
- 08: UEFI firmware booting
- 09: OS booting
- ``BB`` : Boot status
- 00: Not started
- 01: Started
- 02: Completed without error
- 03: Failed.
- ``CCCCCCCC``: Boot status information defined for each boot stages
For details, see section `5.11 Boot Stage Register Definitions`
and section `6. Processor Boot Progress Codes, Altra Family Soc BMC
Interface Specification`.
What: /sys/bus/platform/devices/smpro-misc*/soc_power_limit
KernelVersion: 6.1
Contact: Quan Nguyen <quan@os.amperecomputing.com>
Description:
(RW) Contains the desired SoC power limit in Watt.
Writes to this sysfs set the desired SoC power limit (W).
Reads from this register return the current SoC power limit (W).
The value ranges:
- Minimum: 120 W
- Maximum: Socket TDP power

View File

@ -188,6 +188,16 @@ config SMPRO_ERRMON
To compile this driver as a module, say M here. The driver will be
called smpro-errmon.
config SMPRO_MISC
tristate "Ampere Computing SMPro miscellaneous driver"
depends on MFD_SMPRO || COMPILE_TEST
help
Say Y here to get support for the SMpro error miscellalenous function
provided by Ampere Computing's Altra and Altra Max SoCs.
To compile this driver as a module, say M here. The driver will be
called smpro-misc.
config CS5535_MFGPT
tristate "CS5535/CS5536 Geode Multi-Function General Purpose Timer (MFGPT) support"
depends on MFD_CS5535

View File

@ -24,6 +24,7 @@ obj-$(CONFIG_KGDB_TESTS) += kgdbts.o
obj-$(CONFIG_SGI_XP) += sgi-xp/
obj-$(CONFIG_SGI_GRU) += sgi-gru/
obj-$(CONFIG_SMPRO_ERRMON) += smpro-errmon.o
obj-$(CONFIG_SMPRO_MISC) += smpro-misc.o
obj-$(CONFIG_CS5535_MFGPT) += cs5535-mfgpt.o
obj-$(CONFIG_GEHC_ACHC) += gehc-achc.o
obj-$(CONFIG_HP_ILO) += hpilo.o

145
drivers/misc/smpro-misc.c Normal file
View File

@ -0,0 +1,145 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Ampere Computing SoC's SMpro Misc Driver
*
* Copyright (c) 2022, Ampere Computing LLC
*/
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
/* Boot Stage/Progress Registers */
#define BOOTSTAGE 0xB0
#define BOOTSTAGE_LO 0xB1
#define CUR_BOOTSTAGE 0xB2
#define BOOTSTAGE_HI 0xB3
/* SOC State Registers */
#define SOC_POWER_LIMIT 0xE5
struct smpro_misc {
struct regmap *regmap;
};
static ssize_t boot_progress_show(struct device *dev, struct device_attribute *da, char *buf)
{
struct smpro_misc *misc = dev_get_drvdata(dev);
u16 boot_progress[3] = { 0 };
u32 bootstage;
u8 boot_stage;
u8 cur_stage;
u32 reg_lo;
u32 reg;
int ret;
/* Read current boot stage */
ret = regmap_read(misc->regmap, CUR_BOOTSTAGE, &reg);
if (ret)
return ret;
cur_stage = reg & 0xff;
ret = regmap_read(misc->regmap, BOOTSTAGE, &bootstage);
if (ret)
return ret;
boot_stage = (bootstage >> 8) & 0xff;
if (boot_stage > cur_stage)
return -EINVAL;
ret = regmap_read(misc->regmap, BOOTSTAGE_LO, &reg_lo);
if (!ret)
ret = regmap_read(misc->regmap, BOOTSTAGE_HI, &reg);
if (ret)
return ret;
/* Firmware to report new boot stage next time */
if (boot_stage < cur_stage) {
ret = regmap_write(misc->regmap, BOOTSTAGE, ((bootstage & 0xff00) | 0x1));
if (ret)
return ret;
}
boot_progress[0] = bootstage;
boot_progress[1] = swab16(reg);
boot_progress[2] = swab16(reg_lo);
return sysfs_emit(buf, "%*phN\n", (int)sizeof(boot_progress), boot_progress);
}
static DEVICE_ATTR_RO(boot_progress);
static ssize_t soc_power_limit_show(struct device *dev, struct device_attribute *da, char *buf)
{
struct smpro_misc *misc = dev_get_drvdata(dev);
unsigned int value;
int ret;
ret = regmap_read(misc->regmap, SOC_POWER_LIMIT, &value);
if (ret)
return ret;
return sysfs_emit(buf, "%d\n", value);
}
static ssize_t soc_power_limit_store(struct device *dev, struct device_attribute *da,
const char *buf, size_t count)
{
struct smpro_misc *misc = dev_get_drvdata(dev);
unsigned long val;
s32 ret;
ret = kstrtoul(buf, 0, &val);
if (ret)
return ret;
ret = regmap_write(misc->regmap, SOC_POWER_LIMIT, (unsigned int)val);
if (ret)
return -EPROTO;
return count;
}
static DEVICE_ATTR_RW(soc_power_limit);
static struct attribute *smpro_misc_attrs[] = {
&dev_attr_boot_progress.attr,
&dev_attr_soc_power_limit.attr,
NULL
};
ATTRIBUTE_GROUPS(smpro_misc);
static int smpro_misc_probe(struct platform_device *pdev)
{
struct smpro_misc *misc;
misc = devm_kzalloc(&pdev->dev, sizeof(struct smpro_misc), GFP_KERNEL);
if (!misc)
return -ENOMEM;
platform_set_drvdata(pdev, misc);
misc->regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!misc->regmap)
return -ENODEV;
return 0;
}
static struct platform_driver smpro_misc_driver = {
.probe = smpro_misc_probe,
.driver = {
.name = "smpro-misc",
.dev_groups = smpro_misc_groups,
},
};
module_platform_driver(smpro_misc_driver);
MODULE_AUTHOR("Tung Nguyen <tungnguyen@os.amperecomputing.com>");
MODULE_AUTHOR("Quan Nguyen <quan@os.amperecomputing.com>");
MODULE_DESCRIPTION("Ampere Altra SMpro Misc driver");
MODULE_LICENSE("GPL");