Commit 08c49dc1 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'platform-drivers-x86-v5.6-1' of git://git.infradead.org/linux-platform-drivers-x86

Pull x86 platform driver updates from Andy Shevchenko:

 - Enable thermal policy for ASUS TUF FX705DY/FX505DY

 - Support left round button on ASUS N56VB

 - Support new Mellanox platforms of basic class VMOD0009 and VMOD0010

 - Intel Comet Lake, Tiger Lake and Elkhart Lake support in the PMC
   driver

 - Big clean-up to Intel PMC core, PMC IPC and SCU IPC drivers

 - Touchscreen support for the PiPO W11 tablet

* tag 'platform-drivers-x86-v5.6-1' of git://git.infradead.org/linux-platform-drivers-x86: (64 commits)
  platform/x86: intel_pmc_ipc: Switch to use driver->dev_groups
  platform/x86: intel_pmc_ipc: Propagate error from kstrtoul()
  platform/x86: intel_pmc_ipc: Use octal permissions in sysfs attributes
  platform/x86: intel_pmc_ipc: Get rid of unnecessary includes
  platform/x86: intel_pmc_ipc: Drop ipc_data_readb()
  platform/x86: intel_pmc_ipc: Drop intel_pmc_gcr_read() and intel_pmc_gcr_write()
  platform/x86: intel_pmc_ipc: Make intel_pmc_ipc_raw_cmd() static
  platform/x86: intel_pmc_ipc: Make intel_pmc_ipc_simple_command() static
  platform/x86: intel_pmc_ipc: Make intel_pmc_gcr_update() static
  platform/x86: intel_scu_ipc: Reformat kernel-doc comments of exported functions
  platform/x86: intel_scu_ipc: Drop intel_scu_ipc_raw_command()
  platform/x86: intel_scu_ipc: Drop intel_scu_ipc_io[read|write][8|16]()
  platform/x86: intel_scu_ipc: Drop unused macros
  platform/x86: intel_scu_ipc: Drop unused prototype intel_scu_ipc_fw_update()
  platform/x86: intel_scu_ipc: Sleeping is fine when polling
  platform/x86: intel_scu_ipc: Drop intel_scu_ipc_i2c_cntrl()
  platform/x86: intel_scu_ipc: Remove Lincroft support
  platform/x86: intel_scu_ipc: Add constants for register offsets
  platform/x86: intel_scu_ipc: Fix interrupt support
  platform/x86: intel_scu_ipcutil: Remove default y from Kconfig
  ...
parents 9e1af756 cf85e7c7
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/asic_health
Date: June 2018
KernelVersion: 4.19
Contact: Vadim Pasternak <vadimpmellanox.com>
......@@ -19,7 +18,6 @@ Description: These files show with which CPLD versions have been burned
The files are read only.
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/fan_dir
Date: December 2018
KernelVersion: 5.0
Contact: Vadim Pasternak <vadimpmellanox.com>
......@@ -30,7 +28,6 @@ Description: This file shows the system fans direction:
The files are read only.
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/cpld3_version
Date: November 2018
KernelVersion: 5.0
Contact: Vadim Pasternak <vadimpmellanox.com>
......@@ -40,7 +37,6 @@ Description: These files show with which CPLD versions have been burned
The files are read only.
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/jtag_enable
Date: November 2018
KernelVersion: 5.0
Contact: Vadim Pasternak <vadimpmellanox.com>
......@@ -108,7 +104,6 @@ What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_comex_pwr_fail
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_from_comex
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_system
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_voltmon_upgrade_fail
Date: November 2018
KernelVersion: 5.0
Contact: Vadim Pasternak <vadimpmellanox.com>
......@@ -130,6 +125,12 @@ Description: These files show with which CPLD versions have been burned
The files are read only.
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_comex_thermal
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_comex_wd
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_from_asic
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_reload_bios
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_sff_wd
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_swb_wd
Date: June 2019
KernelVersion: 5.3
Contact: Vadim Pasternak <vadimpmellanox.com>
......@@ -143,9 +144,65 @@ Description: These files show the system reset cause, as following:
The files are read only.
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_comex_thermal
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_comex_wd
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_from_asic
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_reload_bios
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_sff_wd
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_swb_wd
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/config1
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/config2
Date: January 2020
KernelVersion: 5.6
Contact: Vadim Pasternak <vadimpmellanox.com>
Description: These files show system static topology identification
like system's static I2C topology, number and type of FPGA
devices within the system and so on.
The files are read only.
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_ac_pwr_fail
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_platform
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_soc
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_sw_pwr_off
Date: January 2020
KernelVersion: 5.6
Contact: Vadim Pasternak <vadimpmellanox.com>
Description: These files show the system reset causes, as following: reset
due to AC power failure, reset invoked from software by
assertion reset signal through CPLD. reset caused by signal
asserted by SOC through ACPI register, reset invoked from
software by assertion power off signal through CPLD.
The files are read only.
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/pcie_asic_reset_dis
Date: January 2020
KernelVersion: 5.6
Contact: Vadim Pasternak <vadimpmellanox.com>
Description: This file allows to retain ASIC up during PCIe root complex
reset, when attribute is set 1.
The file is read/write.
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/vpd_wp
Date: January 2020
KernelVersion: 5.6
Contact: Vadim Pasternak <vadimpmellanox.com>
Description: This file allows to overwrite system VPD hardware wrtie
protection when attribute is set 1.
The file is read/write.
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/voltreg_update_status
Date: January 2020
KernelVersion: 5.6
Contact: Vadim Pasternak <vadimpmellanox.com>
Description: This file exposes the configuration update status of burnable
voltage regulator devices. The status values are as following:
0 - OK; 1 - CRC failure; 2 = I2C failure; 3 - in progress.
The file is read only.
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/ufm_version
Date: January 2020
KernelVersion: 5.6
Contact: Vadim Pasternak <vadimpmellanox.com>
Description: This file exposes the firmware version of burnable voltage
regulator devices.
The file is read only.
......@@ -46,3 +46,13 @@ Description:
* 0 - normal,
* 1 - overboost,
* 2 - silent
What: /sys/devices/platform/<platform>/throttle_thermal_policy
Date: Dec 2019
KernelVersion: 5.6
Contact: "Leonid Maksymchuk" <leonmaxx@gmail.com>
Description:
Throttle thermal policy mode:
* 0 - default,
* 1 - overboost,
* 2 - silent
......@@ -8573,6 +8573,12 @@ S: Maintained
F: arch/x86/include/asm/intel_telemetry.h
F: drivers/platform/x86/intel_telemetry*
INTEL UNCORE FREQUENCY CONTROL
M: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/intel-uncore-frequency.c
INTEL VIRTUAL BUTTON DRIVER
M: AceLan Kao <acelan.kao@canonical.com>
L: platform-driver-x86@vger.kernel.org
......
......@@ -31,30 +31,13 @@
#if IS_ENABLED(CONFIG_INTEL_PMC_IPC)
int intel_pmc_ipc_simple_command(int cmd, int sub);
int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen,
u32 *out, u32 outlen, u32 dptr, u32 sptr);
int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen,
u32 *out, u32 outlen);
int intel_pmc_s0ix_counter_read(u64 *data);
int intel_pmc_gcr_read(u32 offset, u32 *data);
int intel_pmc_gcr_read64(u32 offset, u64 *data);
int intel_pmc_gcr_write(u32 offset, u32 data);
int intel_pmc_gcr_update(u32 offset, u32 mask, u32 val);
#else
static inline int intel_pmc_ipc_simple_command(int cmd, int sub)
{
return -EINVAL;
}
static inline int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen,
u32 *out, u32 outlen, u32 dptr, u32 sptr)
{
return -EINVAL;
}
static inline int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen,
u32 *out, u32 outlen)
{
......@@ -66,26 +49,11 @@ static inline int intel_pmc_s0ix_counter_read(u64 *data)
return -EINVAL;
}
static inline int intel_pmc_gcr_read(u32 offset, u32 *data)
{
return -EINVAL;
}
static inline int intel_pmc_gcr_read64(u32 offset, u64 *data)
{
return -EINVAL;
}
static inline int intel_pmc_gcr_write(u32 offset, u32 data)
{
return -EINVAL;
}
static inline int intel_pmc_gcr_update(u32 offset, u32 mask, u32 val)
{
return -EINVAL;
}
#endif /*CONFIG_INTEL_PMC_IPC*/
#endif
......@@ -22,24 +22,12 @@
/* Read single register */
int intel_scu_ipc_ioread8(u16 addr, u8 *data);
/* Read two sequential registers */
int intel_scu_ipc_ioread16(u16 addr, u16 *data);
/* Read four sequential registers */
int intel_scu_ipc_ioread32(u16 addr, u32 *data);
/* Read a vector */
int intel_scu_ipc_readv(u16 *addr, u8 *data, int len);
/* Write single register */
int intel_scu_ipc_iowrite8(u16 addr, u8 data);
/* Write two sequential registers */
int intel_scu_ipc_iowrite16(u16 addr, u16 data);
/* Write four sequential registers */
int intel_scu_ipc_iowrite32(u16 addr, u32 data);
/* Write a vector */
int intel_scu_ipc_writev(u16 *addr, u8 *data, int len);
......@@ -50,14 +38,6 @@ int intel_scu_ipc_update_register(u16 addr, u8 data, u8 mask);
int intel_scu_ipc_simple_command(int cmd, int sub);
int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
u32 *out, int outlen);
int intel_scu_ipc_raw_command(int cmd, int sub, u8 *in, int inlen,
u32 *out, int outlen, u32 dptr, u32 sptr);
/* I2C control api */
int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data);
/* Update FW version */
int intel_scu_ipc_fw_update(u8 *buffer, u32 length);
extern struct blocking_notifier_head intel_scu_notifier;
......
......@@ -40,13 +40,10 @@ struct telemetry_evtmap {
struct telemetry_unit_config {
struct telemetry_evtmap *telem_evts;
void __iomem *regmap;
u32 ssram_base_addr;
u8 ssram_evts_used;
u8 curr_period;
u8 max_period;
u8 min_period;
u32 ssram_size;
};
struct telemetry_plt_config {
......
......@@ -504,6 +504,20 @@ static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv)
item = pdata->items;
for (i = 0; i < pdata->counter; i++, item++) {
if (item->capability) {
/*
* Read group capability register to get actual number
* of interrupt capable components and set group mask
* accordingly.
*/
ret = regmap_read(priv->regmap, item->capability,
&regval);
if (ret)
goto out;
item->mask = GENMASK((regval & item->mask) - 1, 0);
}
/* Clear group presense event. */
ret = regmap_write(priv->regmap, item->reg +
MLXREG_HOTPLUG_EVENT_OFF, 0);
......
......@@ -997,7 +997,6 @@ config INTEL_SCU_IPC
config INTEL_SCU_IPC_UTIL
tristate "Intel SCU IPC utility driver"
depends on INTEL_SCU_IPC
default y
---help---
The IPC Util driver provides an interface with the SCU enabling
low level access for debug work and updating the firmware. Say
......@@ -1299,9 +1298,9 @@ config INTEL_ATOMISP2_PM
depends on PCI && IOSF_MBI && PM
help
Power-management driver for Intel's Image Signal Processor found on
Bay and Cherry Trail devices. This dummy driver's sole purpose is to
turn the ISP off (put it in D3) to save power and to allow entering
of S0ix modes.
Bay Trail and Cherry Trail devices. This dummy driver's sole purpose
is to turn the ISP off (put it in D3) to save power and to allow
entering of S0ix modes.
To compile this driver as a module, choose M here: the module
will be called intel_atomisp2_pm.
......@@ -1337,6 +1336,17 @@ config PCENGINES_APU2
To compile this driver as a module, choose M here: the module
will be called pcengines-apuv2.
config INTEL_UNCORE_FREQ_CONTROL
tristate "Intel Uncore frequency control driver"
depends on X86_64
help
This driver allows control of uncore frequency limits on
supported server platforms.
Uncore frequency controls RING/LLC (last-level cache) clocks.
To compile this driver as a module, choose M here: the module
will be called intel-uncore-frequency.
source "drivers/platform/x86/intel_speed_select_if/Kconfig"
config SYSTEM76_ACPI
......
......@@ -105,3 +105,4 @@ obj-$(CONFIG_INTEL_ATOMISP2_PM) += intel_atomisp2_pm.o
obj-$(CONFIG_PCENGINES_APU2) += pcengines-apuv2.o
obj-$(CONFIG_INTEL_SPEED_SELECT_INTERFACE) += intel_speed_select_if/
obj-$(CONFIG_SYSTEM76_ACPI) += system76_acpi.o
obj-$(CONFIG_INTEL_UNCORE_FREQ_CONTROL) += intel-uncore-frequency.o
......@@ -471,6 +471,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
{ KE_KEY, 0x67, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV */
{ KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } },
{ KE_IGNORE, 0x6E, }, /* Low Battery notification */
{ KE_KEY, 0x71, { KEY_F13 } }, /* General-purpose button */
{ KE_KEY, 0x7a, { KEY_ALS_TOGGLE } }, /* Ambient Light Sensor Toggle */
{ KE_KEY, 0x7c, { KEY_MICMUTE } },
{ KE_KEY, 0x7D, { KEY_BLUETOOTH } }, /* Bluetooth Enable */
......
......@@ -61,6 +61,7 @@ MODULE_LICENSE("GPL");
#define NOTIFY_KBD_BRTDWN 0xc5
#define NOTIFY_KBD_BRTTOGGLE 0xc7
#define NOTIFY_KBD_FBM 0x99
#define NOTIFY_KBD_TTP 0xae
#define ASUS_WMI_FNLOCK_BIOS_DISABLED BIT(0)
......@@ -81,6 +82,10 @@ MODULE_LICENSE("GPL");
#define ASUS_FAN_BOOST_MODE_SILENT_MASK 0x02
#define ASUS_FAN_BOOST_MODES_MASK 0x03
#define ASUS_THROTTLE_THERMAL_POLICY_DEFAULT 0
#define ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST 1
#define ASUS_THROTTLE_THERMAL_POLICY_SILENT 2
#define USB_INTEL_XUSB2PR 0xD0
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31
......@@ -198,6 +203,9 @@ struct asus_wmi {
u8 fan_boost_mode_mask;
u8 fan_boost_mode;
bool throttle_thermal_policy_available;
u8 throttle_thermal_policy_mode;
// The RSOC controls the maximum charging percentage.
bool battery_rsoc_available;
......@@ -1718,6 +1726,107 @@ static ssize_t fan_boost_mode_store(struct device *dev,
// Fan boost mode: 0 - normal, 1 - overboost, 2 - silent
static DEVICE_ATTR_RW(fan_boost_mode);
/* Throttle thermal policy ****************************************************/
static int throttle_thermal_policy_check_present(struct asus_wmi *asus)
{
u32 result;
int err;
asus->throttle_thermal_policy_available = false;
err = asus_wmi_get_devstate(asus,
ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
&result);
if (err) {
if (err == -ENODEV)
return 0;
return err;
}
if (result & ASUS_WMI_DSTS_PRESENCE_BIT)
asus->throttle_thermal_policy_available = true;
return 0;
}
static int throttle_thermal_policy_write(struct asus_wmi *asus)
{
int err;
u8 value;
u32 retval;
value = asus->throttle_thermal_policy_mode;
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
value, &retval);
if (err) {
pr_warn("Failed to set throttle thermal policy: %d\n", err);
return err;
}
if (retval != 1) {
pr_warn("Failed to set throttle thermal policy (retval): 0x%x\n",
retval);
return -EIO;
}
return 0;
}
static int throttle_thermal_policy_set_default(struct asus_wmi *asus)
{
if (!asus->throttle_thermal_policy_available)
return 0;
asus->throttle_thermal_policy_mode = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT;
return throttle_thermal_policy_write(asus);
}
static int throttle_thermal_policy_switch_next(struct asus_wmi *asus)
{
u8 new_mode = asus->throttle_thermal_policy_mode + 1;
if (new_mode > ASUS_THROTTLE_THERMAL_POLICY_SILENT)
new_mode = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT;
asus->throttle_thermal_policy_mode = new_mode;
return throttle_thermal_policy_write(asus);
}
static ssize_t throttle_thermal_policy_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct asus_wmi *asus = dev_get_drvdata(dev);
u8 mode = asus->throttle_thermal_policy_mode;
return scnprintf(buf, PAGE_SIZE, "%d\n", mode);
}
static ssize_t throttle_thermal_policy_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int result;
u8 new_mode;
struct asus_wmi *asus = dev_get_drvdata(dev);
result = kstrtou8(buf, 10, &new_mode);
if (result < 0)
return result;
if (new_mode > ASUS_THROTTLE_THERMAL_POLICY_SILENT)
return -EINVAL;
asus->throttle_thermal_policy_mode = new_mode;
throttle_thermal_policy_write(asus);
return count;
}
// Throttle thermal policy: 0 - default, 1 - overboost, 2 - silent
static DEVICE_ATTR_RW(throttle_thermal_policy);
/* Backlight ******************************************************************/
static int read_backlight_power(struct asus_wmi *asus)
......@@ -1999,6 +2108,11 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
return;
}
if (asus->throttle_thermal_policy_available && code == NOTIFY_KBD_TTP) {
throttle_thermal_policy_switch_next(asus);
return;
}
if (is_display_toggle(code) && asus->driver->quirks->no_display_toggle)
return;
......@@ -2149,6 +2263,7 @@ static struct attribute *platform_attributes[] = {
&dev_attr_lid_resume.attr,
&dev_attr_als_enable.attr,
&dev_attr_fan_boost_mode.attr,
&dev_attr_throttle_thermal_policy.attr,
NULL
};
......@@ -2172,6 +2287,8 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
devid = ASUS_WMI_DEVID_ALS_ENABLE;
else if (attr == &dev_attr_fan_boost_mode.attr)
ok = asus->fan_boost_mode_available;
else if (attr == &dev_attr_throttle_thermal_policy.attr)
ok = asus->throttle_thermal_policy_available;
if (devid != -1)
ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0);
......@@ -2431,6 +2548,12 @@ static int asus_wmi_add(struct platform_device *pdev)
if (err)
goto fail_fan_boost_mode;
err = throttle_thermal_policy_check_present(asus);
if (err)
goto fail_throttle_thermal_policy;
else
throttle_thermal_policy_set_default(asus);
err = asus_wmi_sysfs_init(asus->platform_device);
if (err)
goto fail_sysfs;
......@@ -2515,6 +2638,7 @@ static int asus_wmi_add(struct platform_device *pdev)
fail_input:
asus_wmi_sysfs_exit(asus->platform_device);
fail_sysfs:
fail_throttle_thermal_policy:
fail_fan_boost_mode:
fail_platform:
kfree(asus);
......
// SPDX-License-Identifier: GPL-2.0
/*
* Intel Uncore Frequency Setting
* Copyright (c) 2019, Intel Corporation.
* All rights reserved.
*
* Provide interface to set MSR 620 at a granularity of per die. On CPU online,
* one control CPU is identified per die to read/write limit. This control CPU
* is changed, if the CPU state is changed to offline. When the last CPU is
* offline in a die then remove the sysfs object for that die.
* The majority of actual code is related to sysfs create and read/write
* attributes.
*
* Author: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
*/
#include <linux/cpu.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/suspend.h>
#include <asm/cpu_device_id.h>
#include <asm/intel-family.h>
#define MSR_UNCORE_RATIO_LIMIT 0x620
#define UNCORE_FREQ_KHZ_MULTIPLIER 100000
/**
* struct uncore_data - Encapsulate all uncore data
* @stored_uncore_data: Last user changed MSR 620 value, which will be restored
* on system resume.
* @initial_min_freq_khz: Sampled minimum uncore frequency at driver init
* @initial_max_freq_khz: Sampled maximum uncore frequency at driver init
* @control_cpu: Designated CPU for a die to read/write
* @valid: Mark the data valid/invalid
*
* This structure is used to encapsulate all data related to uncore sysfs
* settings for a die/package.
*/
struct uncore_data {
struct kobject kobj;
u64 stored_uncore_data;
u32 initial_min_freq_khz;
u32 initial_max_freq_khz;
int control_cpu;
bool valid;
};
#define to_uncore_data(a) container_of(a, struct uncore_data, kobj)
/* Max instances for uncore data, one for each die */
static int uncore_max_entries __read_mostly;
/* Storage for uncore data for all instances */
static struct uncore_data *uncore_instances;
/* Root of the all uncore sysfs kobjs */
struct kobject uncore_root_kobj;
/* Stores the CPU mask of the target CPUs to use during uncore read/write */
static cpumask_t uncore_cpu_mask;
/* CPU online callback register instance */
static enum cpuhp_state uncore_hp_state __read_mostly;
/* Mutex to control all mutual exclusions */
static DEFINE_MUTEX(uncore_lock);
struct uncore_attr {
struct attribute attr;
ssize_t (*show)(struct kobject *kobj,
struct attribute *attr, char *buf);
ssize_t (*store)(struct kobject *kobj,
struct attribute *attr, const char *c, ssize_t count);
};
#define define_one_uncore_ro(_name) \
static struct uncore_attr _name = \
__ATTR(_name, 0444, show_##_name, NULL)
#define define_one_uncore_rw(_name) \
static struct uncore_attr _name = \
__ATTR(_name, 0644, show_##_name, store_##_name)
#define show_uncore_data(member_name) \
static ssize_t show_##member_name(struct kobject *kobj, \
struct attribute *attr, \
char *buf) \
{ \
struct uncore_data *data = to_uncore_data(kobj); \
return scnprintf(buf, PAGE_SIZE, "%u\n", \
data->member_name); \
} \
define_one_uncore_ro(member_name)
show_uncore_data(initial_min_freq_khz);
show_uncore_data(initial_max_freq_khz);
/* Common function to read MSR 0x620 and read min/max */
static int uncore_read_ratio(struct uncore_data *data, unsigned int *min,
unsigned int *max)
{
u64 cap;
int ret;
ret = rdmsrl_on_cpu(data->control_cpu, MSR_UNCORE_RATIO_LIMIT, &cap);
if (ret)
return ret;
*max = (cap & 0x7F) * UNCORE_FREQ_KHZ_MULTIPLIER;
*min = ((cap & GENMASK(14, 8)) >> 8) * UNCORE_FREQ_KHZ_MULTIPLIER;
return 0;
}
/* Common function to set min/max ratios to be used by sysfs callbacks */
static int uncore_write_ratio(struct uncore_data *data, unsigned int input,
int set_max)
{
int ret;
u64 cap;
mutex_lock(&uncore_lock);
input /= UNCORE_FREQ_KHZ_MULTIPLIER;
if (!input || input > 0x7F) {
ret = -EINVAL;
goto finish_write;
}
ret = rdmsrl_on_cpu(data->control_cpu, MSR_UNCORE_RATIO_LIMIT, &cap);
if (ret)
goto finish_write;
if (set_max) {
cap &= ~0x7F;
cap |= input;
} else {
cap &= ~GENMASK(14, 8);
cap |= (input << 8);
}
ret = wrmsrl_on_cpu(data->control_cpu, MSR_UNCORE_RATIO_LIMIT, cap);
if (ret)
goto finish_write;
data->stored_uncore_data = cap;
finish_write:
mutex_unlock(&uncore_lock);
return ret;
}
static ssize_t store_min_max_freq_khz(struct kobject *kobj,
struct attribute *attr,
const char *buf, ssize_t count,
int min_max)
{
struct uncore_data *data = to_uncore_data(kobj);
unsigned int input;
if (kstrtouint(buf, 10, &input))
return -EINVAL;
uncore_write_ratio(data, input, min_max);
return count;
}
static ssize_t show_min_max_freq_khz(struct kobject *kobj,
struct attribute *attr,
char *buf, int min_max)
{
struct uncore_data *data = to_uncore_data(kobj);
unsigned int min, max;
int ret;
mutex_lock(&uncore_lock);
ret = uncore_read_ratio(data, &min, &max);
mutex_unlock(&uncore_lock);
if (ret)
return ret;
if (min_max)
return sprintf(buf, "%u\n", max);
return sprintf(buf, "%u\n", min);
}
#define store_uncore_min_max(name, min_max) \
static ssize_t store_##name(struct kobject *kobj, \
struct attribute *attr, \
const char *buf, ssize_t count) \
{ \
\
return store_min_max_freq_khz(kobj, attr, buf, count, \
min_max); \
}
#define show_uncore_min_max(name, min_max) \
static ssize_t show_##name(struct kobject *kobj, \
struct attribute *attr, char *buf) \
{ \
\
return show_min_max_freq_khz(kobj, attr, buf, min_max); \
}
store_uncore_min_max(min_freq_khz, 0);
store_uncore_min_max(max_freq_khz, 1);
show_uncore_min_max(min_freq_khz, 0);
show_uncore_min_max(max_freq_khz, 1);
define_one_uncore_rw(min_freq_khz);
define_one_uncore_rw(max_freq_khz);
static struct attribute *uncore_attrs[] = {
&initial_min_freq_khz.attr,
&initial_max_freq_khz.attr,
&max_freq_khz.attr,
&min_freq_khz.attr,
NULL
};
static struct kobj_type uncore_ktype = {
.sysfs_ops = &kobj_sysfs_ops,
.default_attrs = uncore_attrs,
};
static struct kobj_type uncore_root_ktype = {
.sysfs_ops = &kobj_sysfs_ops,
};
/* Caller provides protection */
static struct uncore_data *uncore_get_instance(unsigned int cpu)
{
int id = topology_logical_die_id(cpu);
if (id >= 0 && id < uncore_max_entries)
return &uncore_instances[id];
return NULL;
}
static void uncore_add_die_entry(int cpu)
{
struct uncore_data *data;
mutex_lock(&uncore_lock);
data = uncore_get_instance(cpu);
if (!data) {
mutex_unlock(&uncore_lock);
return;
}
if (data->valid) {
/* control cpu changed */
data->control_cpu = cpu;
} else {
char str[64];
int ret;
memset(data, 0, sizeof(*data));
sprintf(str, "package_%02d_die_%02d",
topology_physical_package_id(cpu),
topology_die_id(cpu));
uncore_read_ratio(data, &data->initial_min_freq_khz,
&data->initial_max_freq_khz);
ret = kobject_init_and_add(&data->kobj, &uncore_ktype,
&uncore_root_kobj, str);
if (!ret) {
data->control_cpu = cpu;
data->valid = true;
}
}
mutex_unlock(&uncore_lock);
}
/* Last CPU in this die is offline, so remove sysfs entries */
static void uncore_remove_die_entry(int cpu)
{
struct uncore_data *data;
mutex_lock(&uncore_lock);
data = uncore_get_instance(cpu);
if (data) {
kobject_put(&data->kobj);
data->control_cpu = -1;
data->valid = false;
}
mutex_unlock(&uncore_lock);
}
static int uncore_event_cpu_online(unsigned int cpu)
{
int target;
/* Check if there is an online cpu in the package for uncore MSR */
target = cpumask_any_and(&uncore_cpu_mask, topology_die_cpumask(cpu));
if (target < nr_cpu_ids)
return 0;
/* Use this CPU on this die as a control CPU */
cpumask_set_cpu(cpu, &uncore_cpu_mask);
uncore_add_die_entry(cpu);
return 0;
}
static int uncore_event_cpu_offline(unsigned int cpu)
{
int target;
/* Check if existing cpu is used for uncore MSRs */
if (!cpumask_test_and_clear_cpu(cpu, &uncore_cpu_mask))
return 0;
/* Find a new cpu to set uncore MSR */
target = cpumask_any_but(topology_die_cpumask(cpu), cpu);
if (target < nr_cpu_ids) {
cpumask_set_cpu(target, &uncore_cpu_mask);
uncore_add_die_entry(target);
} else {
uncore_remove_die_entry(cpu);
}
return 0;
}
static int uncore_pm_notify(struct notifier_block *nb, unsigned long mode,
void *_unused)
{
int cpu;
switch (mode) {
case PM_POST_HIBERNATION:
case PM_POST_RESTORE:
case PM_POST_SUSPEND:
for_each_cpu(cpu, &uncore_cpu_mask) {
struct uncore_data *data;
int ret;
data = uncore_get_instance(cpu);
if (!data || !data->valid || !data->stored_uncore_data)
continue;
ret = wrmsrl_on_cpu(cpu, MSR_UNCORE_RATIO_LIMIT,
data->stored_uncore_data);
if (ret)
return ret;
}
break;
default:
break;
}
return 0;
}
static struct notifier_block uncore_pm_nb = {
.notifier_call = uncore_pm_notify,
};
#define ICPU(model) { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, }
static const struct x86_cpu_id intel_uncore_cpu_ids[] = {
ICPU(INTEL_FAM6_BROADWELL_G),
ICPU(INTEL_FAM6_BROADWELL_X),
ICPU(INTEL_FAM6_BROADWELL_D),
ICPU(INTEL_FAM6_SKYLAKE_X),
ICPU(INTEL_FAM6_ICELAKE_X),
ICPU(INTEL_FAM6_ICELAKE_D),
{}
};
static int __init intel_uncore_init(void)
{
const struct x86_cpu_id *id;
int ret;
id = x86_match_cpu(intel_uncore_cpu_ids);
if (!id)
return -ENODEV;
uncore_max_entries = topology_max_packages() *
topology_max_die_per_package();
uncore_instances = kcalloc(uncore_max_entries,
sizeof(*uncore_instances), GFP_KERNEL);
if (!uncore_instances)
return -ENOMEM;
ret = kobject_init_and_add(&uncore_root_kobj, &uncore_root_ktype,
&cpu_subsys.dev_root->kobj,
"intel_uncore_frequency");
if (ret)
goto err_free;
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
"platform/x86/uncore-freq:online",
uncore_event_cpu_online,
uncore_event_cpu_offline);
if (ret < 0)
goto err_rem_kobj;
uncore_hp_state = ret;
ret = register_pm_notifier(&uncore_pm_nb);
if (ret)
goto err_rem_state;
return 0;
err_rem_state:
cpuhp_remove_state(uncore_hp_state);
err_rem_kobj:
kobject_put(&uncore_root_kobj);
err_free:
kfree(uncore_instances);
return ret;
}
module_init(intel_uncore_init)
static void __exit intel_uncore_exit(void)
{
int i;
unregister_pm_notifier(&uncore_pm_nb);
cpuhp_remove_state(uncore_hp_state);
for (i = 0; i < uncore_max_entries; ++i) {
if (uncore_instances[i].valid)
kobject_put(&uncore_instances[i].kobj);
}
kobject_put(&uncore_root_kobj);
kfree(uncore_instances);
}
module_exit(intel_uncore_exit)
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Intel Uncore Frequency Limits Driver");
// SPDX-License-Identifier: GPL-2.0
/*
* Dummy driver for Intel's Image Signal Processor found on Bay and Cherry
* Trail devices. The sole purpose of this driver is to allow the ISP to
* be put in D3.
* Dummy driver for Intel's Image Signal Processor found on Bay Trail
* and Cherry Trail devices. The sole purpose of this driver is to allow
* the ISP to be put in D3.
*
* Copyright (C) 2018 Hans de Goede <hdegoede@redhat.com>
*
......@@ -36,8 +36,7 @@
static int isp_set_power(struct pci_dev *dev, bool enable)
{
unsigned long timeout;
u32 val = enable ? ISPSSPM0_IUNIT_POWER_ON :
ISPSSPM0_IUNIT_POWER_OFF;
u32 val = enable ? ISPSSPM0_IUNIT_POWER_ON : ISPSSPM0_IUNIT_POWER_OFF;
/* Write to ISPSSPM0 bit[1:0] to power on/off the IUNIT */
iosf_mbi_modify(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM0,
......@@ -45,29 +44,25 @@ static int isp_set_power(struct pci_dev *dev, bool enable)
/*
* There should be no IUNIT access while power-down is
* in progress HW sighting: 4567865
* in progress. HW sighting: 4567865.
* Wait up to 50 ms for the IUNIT to shut down.
* And we do the same for power on.
*/
timeout = jiffies + msecs_to_jiffies(50);
while (1) {
do {
u32 tmp;
/* Wait until ISPSSPM0 bit[25:24] shows the right value */
iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM0, &tmp);
tmp = (tmp & ISPSSPM0_ISPSSS_MASK) >> ISPSSPM0_ISPSSS_OFFSET;
if (tmp == val)
break;
return 0;
if (time_after(jiffies, timeout)) {
dev_err(&dev->dev, "IUNIT power-%s timeout.\n",
enable ? "on" : "off");
return -EBUSY;
}
usleep_range(1000, 2000);
}
} while (time_before(jiffies, timeout));
return 0;
dev_err(&dev->dev, "IUNIT power-%s timeout.\n", enable ? "on" : "off");
return -EBUSY;
}
static int isp_probe(struct pci_dev *dev, const struct pci_device_id *id)
......
......@@ -146,9 +146,10 @@ static int mid_pb_probe(struct platform_device *pdev)
input_set_capability(input, EV_KEY, KEY_POWER);
ddata = (struct mid_pb_ddata *)id->driver_data;
ddata = devm_kmemdup(&pdev->dev, (void *)id->driver_data,
sizeof(*ddata), GFP_KERNEL);
if (!ddata)
return -ENODATA;
return -ENOMEM;
ddata->dev = &pdev->dev;
ddata->irq = irq;
......
......@@ -49,7 +49,7 @@ static const struct pmc_bit_map spt_pll_map[] = {
{"GEN2 USB2PCIE2 PLL", SPT_PMC_BIT_MPHY_CMN_LANE1},
{"DMIPCIE3 PLL", SPT_PMC_BIT_MPHY_CMN_LANE2},
{"SATA PLL", SPT_PMC_BIT_MPHY_CMN_LANE3},
{},
{}
};
static const struct pmc_bit_map spt_mphy_map[] = {
......@@ -69,7 +69,7 @@ static const struct pmc_bit_map spt_mphy_map[] = {
{"MPHY CORE LANE 13", SPT_PMC_BIT_MPHY_LANE13},
{"MPHY CORE LANE 14", SPT_PMC_BIT_MPHY_LANE14},
{"MPHY CORE LANE 15", SPT_PMC_BIT_MPHY_LANE15},
{},
{}
};
static const struct pmc_bit_map spt_pfear_map[] = {
......@@ -113,7 +113,12 @@ static const struct pmc_bit_map spt_pfear_map[] = {
{"CSME_SMS1", SPT_PMC_BIT_CSME_SMS1},
{"CSME_RTC", SPT_PMC_BIT_CSME_RTC},
{"CSME_PSF", SPT_PMC_BIT_CSME_PSF},
{},
{}
};
static const struct pmc_bit_map *ext_spt_pfear_map[] = {
spt_pfear_map,
NULL
};
static const struct pmc_bit_map spt_ltr_show_map[] = {
......@@ -142,7 +147,7 @@ static const struct pmc_bit_map spt_ltr_show_map[] = {
};
static const struct pmc_reg_map spt_reg_map = {
.pfear_sts = spt_pfear_map,
.pfear_sts = ext_spt_pfear_map,
.mphy_sts = spt_mphy_map,
.pll_sts = spt_pll_map,
.ltr_show_sts = spt_ltr_show_map,
......@@ -186,7 +191,10 @@ static const struct pmc_bit_map cnp_pfear_map[] = {
{"SDX", BIT(4)},
{"SPE", BIT(5)},
{"Fuse", BIT(6)},
/* Reserved for Cannon Lake but valid for Ice Lake and Comet Lake */
/*
* Reserved for Cannon Lake but valid for Ice Lake, Comet Lake,
* Tiger Lake and Elkhart Lake.
*/
{"SBR8", BIT(7)},
{"CSME_FSC", BIT(0)},
......@@ -230,11 +238,22 @@ static const struct pmc_bit_map cnp_pfear_map[] = {
{"HDA_PGD4", BIT(2)},
{"HDA_PGD5", BIT(3)},
{"HDA_PGD6", BIT(4)},
/* Reserved for Cannon Lake but valid for Ice Lake and Comet Lake */
/*
* Reserved for Cannon Lake but valid for Ice Lake, Comet Lake,
* Tiger Lake and ELkhart Lake.
*/
{"PSF6", BIT(5)},
{"PSF7", BIT(6)},
{"PSF8", BIT(7)},
{}
};
static const struct pmc_bit_map *ext_cnp_pfear_map[] = {
cnp_pfear_map,
NULL
};
static const struct pmc_bit_map icl_pfear_map[] = {
/* Ice Lake generation onwards only */
{"RES_65", BIT(0)},
{"RES_66", BIT(1)},
......@@ -247,6 +266,30 @@ static const struct pmc_bit_map cnp_pfear_map[] = {
{}
};
static const struct pmc_bit_map *ext_icl_pfear_map[] = {
cnp_pfear_map,
icl_pfear_map,
NULL
};
static const struct pmc_bit_map tgl_pfear_map[] = {
/* Tiger Lake and Elkhart Lake generation onwards only */
{"PSF9", BIT(0)},
{"RES_66", BIT(1)},
{"RES_67", BIT(2)},
{"RES_68", BIT(3)},
{"RES_69", BIT(4)},
{"RES_70", BIT(5)},
{"TBTLSX", BIT(6)},
{}
};
static const struct pmc_bit_map *ext_tgl_pfear_map[] = {
cnp_pfear_map,
tgl_pfear_map,
NULL
};
static const struct pmc_bit_map cnp_slps0_dbg0_map[] = {
{"AUDIO_D3", BIT(0)},
{"OTG_D3", BIT(1)},
......@@ -300,7 +343,7 @@ static const struct pmc_bit_map *cnp_slps0_dbg_maps[] = {
cnp_slps0_dbg0_map,
cnp_slps0_dbg1_map,
cnp_slps0_dbg2_map,
NULL,
NULL
};
static const struct pmc_bit_map cnp_ltr_show_map[] = {
......@@ -334,7 +377,7 @@ static const struct pmc_bit_map cnp_ltr_show_map[] = {
};
static const struct pmc_reg_map cnp_reg_map = {
.pfear_sts = cnp_pfear_map,
.pfear_sts = ext_cnp_pfear_map,
.slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
.slps0_dbg_maps = cnp_slps0_dbg_maps,
.ltr_show_sts = cnp_ltr_show_map,
......@@ -350,7 +393,7 @@ static const struct pmc_reg_map cnp_reg_map = {
};
static const struct pmc_reg_map icl_reg_map = {
.pfear_sts = cnp_pfear_map,
.pfear_sts = ext_icl_pfear_map,
.slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
.slps0_dbg_maps = cnp_slps0_dbg_maps,
.ltr_show_sts = cnp_ltr_show_map,
......@@ -365,18 +408,29 @@ static const struct pmc_reg_map icl_reg_map = {
.ltr_ignore_max = ICL_NUM_IP_IGN_ALLOWED,
};
static inline u8 pmc_core_reg_read_byte(struct pmc_dev *pmcdev, int offset)
{
return readb(pmcdev->regbase + offset);
}
static const struct pmc_reg_map tgl_reg_map = {
.pfear_sts = ext_tgl_pfear_map,
.slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
.slps0_dbg_maps = cnp_slps0_dbg_maps,
.ltr_show_sts = cnp_ltr_show_map,
.msr_sts = msr_map,
.slps0_dbg_offset = CNP_PMC_SLPS0_DBG_OFFSET,
.ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET,
.regmap_length = CNP_PMC_MMIO_REG_LEN,
.ppfear0_offset = CNP_PMC_HOST_PPFEAR0A,
.ppfear_buckets = ICL_PPFEAR_NUM_ENTRIES,
.pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
.pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
.ltr_ignore_max = TGL_NUM_IP_IGN_ALLOWED,
};
static inline u32 pmc_core_reg_read(struct pmc_dev *pmcdev, int reg_offset)
{
return readl(pmcdev->regbase + reg_offset);
}
static inline void pmc_core_reg_write(struct pmc_dev *pmcdev, int
reg_offset, u32 val)
static inline void pmc_core_reg_write(struct pmc_dev *pmcdev, int reg_offset,
u32 val)
{
writel(val, pmcdev->regbase + reg_offset);
}
......@@ -412,20 +466,25 @@ static int pmc_core_check_read_lock_bit(void)
#if IS_ENABLED(CONFIG_DEBUG_FS)
static bool slps0_dbg_latch;
static void pmc_core_display_map(struct seq_file *s, int index,
u8 pf_reg, const struct pmc_bit_map *pf_map)
static inline u8 pmc_core_reg_read_byte(struct pmc_dev *pmcdev, int offset)
{
return readb(pmcdev->regbase + offset);
}
static void pmc_core_display_map(struct seq_file *s, int index, int idx, int ip,
u8 pf_reg, const struct pmc_bit_map **pf_map)
{
seq_printf(s, "PCH IP: %-2d - %-32s\tState: %s\n",
index, pf_map[index].name,
pf_map[index].bit_mask & pf_reg ? "Off" : "On");
ip, pf_map[idx][index].name,
pf_map[idx][index].bit_mask & pf_reg ? "Off" : "On");
}
static int pmc_core_ppfear_show(struct seq_file *s, void *unused)
{
struct pmc_dev *pmcdev = s->private;
const struct pmc_bit_map *map = pmcdev->map->pfear_sts;
const struct pmc_bit_map **maps = pmcdev->map->pfear_sts;
u8 pf_regs[PPFEAR_MAX_NUM_ENTRIES];
int index, iter;
int index, iter, idx, ip = 0;
iter = pmcdev->map->ppfear0_offset;
......@@ -433,9 +492,12 @@ static int pmc_core_ppfear_show(struct seq_file *s, void *unused)
index < PPFEAR_MAX_NUM_ENTRIES; index++, iter++)
pf_regs[index] = pmc_core_reg_read_byte(pmcdev, iter);
for (index = 0; map[index].name &&
index < pmcdev->map->ppfear_buckets * 8; index++)
pmc_core_display_map(s, index, pf_regs[index / 8], map);
for (idx = 0; maps[idx]; idx++) {
for (index = 0; maps[idx][index].name &&
index < pmcdev->map->ppfear_buckets * 8; ip++, index++)
pmc_core_display_map(s, index, idx, ip,
pf_regs[index / 8], maps);
}
return 0;
}
......@@ -561,21 +623,22 @@ static int pmc_core_pll_show(struct seq_file *s, void *unused)
}
DEFINE_SHOW_ATTRIBUTE(pmc_core_pll);
static ssize_t pmc_core_ltr_ignore_write(struct file *file, const char __user
*userbuf, size_t count, loff_t *ppos)
static ssize_t pmc_core_ltr_ignore_write(struct file *file,
const char __user *userbuf,
size_t count, loff_t *ppos)
{
struct pmc_dev *pmcdev = &pmc;
const struct pmc_reg_map *map = pmcdev->map;
u32 val, buf_size, fd;
int err = 0;
int err;
buf_size = count < 64 ? count : 64;
mutex_lock(&pmcdev->lock);
if (kstrtou32_from_user(userbuf, buf_size, 10, &val)) {
err = -EFAULT;
goto out_unlock;
}
err = kstrtou32_from_user(userbuf, buf_size, 10, &val);
if (err)
return err;
mutex_lock(&pmcdev->lock);
if (val > map->ltr_ignore_max) {
err = -EINVAL;
......@@ -767,8 +830,9 @@ static void pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
debugfs_create_file("slp_s0_residency_usec", 0444, dir, pmcdev,
&pmc_core_dev_state);
debugfs_create_file("pch_ip_power_gating_status", 0444, dir, pmcdev,
&pmc_core_ppfear_fops);
if (pmcdev->map->pfear_sts)
debugfs_create_file("pch_ip_power_gating_status", 0444, dir,
pmcdev, &pmc_core_ppfear_fops);
debugfs_create_file("ltr_ignore", 0644, dir, pmcdev,
&pmc_core_ltr_ignore_ops);
......@@ -816,19 +880,22 @@ static const struct x86_cpu_id intel_pmc_core_ids[] = {
INTEL_CPU_FAM6(ICELAKE_NNPI, icl_reg_map),
INTEL_CPU_FAM6(COMETLAKE, cnp_reg_map),
INTEL_CPU_FAM6(COMETLAKE_L, cnp_reg_map),
INTEL_CPU_FAM6(TIGERLAKE_L, tgl_reg_map),
INTEL_CPU_FAM6(TIGERLAKE, tgl_reg_map),
INTEL_CPU_FAM6(ATOM_TREMONT, tgl_reg_map),
{}
};
MODULE_DEVICE_TABLE(x86cpu, intel_pmc_core_ids);
static const struct pci_device_id pmc_pci_ids[] = {
{ PCI_VDEVICE(INTEL, SPT_PMC_PCI_DEVICE_ID), 0},
{ 0, },
{ PCI_VDEVICE(INTEL, SPT_PMC_PCI_DEVICE_ID) },
{ }
};
/*
* This quirk can be used on those platforms where
* the platform BIOS enforces 24Mhx Crystal to shutdown
* the platform BIOS enforces 24Mhz crystal to shutdown
* before PMC can assert SLP_S0#.
*/
static int quirk_xtal_ignore(const struct dmi_system_id *id)
......
......@@ -186,6 +186,8 @@ enum ppfear_regs {
#define ICL_NUM_IP_IGN_ALLOWED 20
#define ICL_PMC_LTR_WIGIG 0x1BFC
#define TGL_NUM_IP_IGN_ALLOWED 22
struct pmc_bit_map {
const char *name;
u32 bit_mask;
......@@ -213,7 +215,7 @@ struct pmc_bit_map {
* captures them to have a common implementation.
*/
struct pmc_reg_map {
const struct pmc_bit_map *pfear_sts;
const struct pmc_bit_map **pfear_sts;
const struct pmc_bit_map *mphy_sts;
const struct pmc_bit_map *pll_sts;
const struct pmc_bit_map **slps0_dbg_maps;
......
......@@ -12,23 +12,13 @@
*/
#include <linux/acpi.h>
#include <linux/atomic.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/pm_qos.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/suspend.h>
#include <asm/intel_pmc_ipc.h>
......@@ -184,11 +174,6 @@ static inline void ipc_data_writel(u32 data, u32 offset)
writel(data, ipcdev.ipc_base + IPC_WRITE_BUFFER + offset);
}
static inline u8 __maybe_unused ipc_data_readb(u32 offset)
{
return readb(ipcdev.ipc_base + IPC_READ_BUFFER + offset);
}
static inline u32 ipc_data_readl(u32 offset)
{
return readl(ipcdev.ipc_base + IPC_READ_BUFFER + offset);
......@@ -210,35 +195,6 @@ static inline int is_gcr_valid(u32 offset)
return 0;
}
/**
* intel_pmc_gcr_read() - Read a 32-bit PMC GCR register
* @offset: offset of GCR register from GCR address base
* @data: data pointer for storing the register output
*
* Reads the 32-bit PMC GCR register at given offset.
*
* Return: negative value on error or 0 on success.
*/
int intel_pmc_gcr_read(u32 offset, u32 *data)
{
int ret;
spin_lock(&ipcdev.gcr_lock);
ret = is_gcr_valid(offset);
if (ret < 0) {
spin_unlock(&ipcdev.gcr_lock);
return ret;
}
*data = readl(ipcdev.gcr_mem_base + offset);
spin_unlock(&ipcdev.gcr_lock);
return 0;
}
EXPORT_SYMBOL_GPL(intel_pmc_gcr_read);
/**
* intel_pmc_gcr_read64() - Read a 64-bit PMC GCR register
* @offset: offset of GCR register from GCR address base
......@@ -268,36 +224,6 @@ int intel_pmc_gcr_read64(u32 offset, u64 *data)
}
EXPORT_SYMBOL_GPL(intel_pmc_gcr_read64);
/**
* intel_pmc_gcr_write() - Write PMC GCR register
* @offset: offset of GCR register from GCR address base
* @data: register update value
*
* Writes the PMC GCR register of given offset with given
* value.
*
* Return: negative value on error or 0 on success.
*/
int intel_pmc_gcr_write(u32 offset, u32 data)
{
int ret;
spin_lock(&ipcdev.gcr_lock);
ret = is_gcr_valid(offset);
if (ret < 0) {
spin_unlock(&ipcdev.gcr_lock);
return ret;
}
writel(data, ipcdev.gcr_mem_base + offset);
spin_unlock(&ipcdev.gcr_lock);
return 0;
}
EXPORT_SYMBOL_GPL(intel_pmc_gcr_write);
/**
* intel_pmc_gcr_update() - Update PMC GCR register bits
* @offset: offset of GCR register from GCR address base
......@@ -309,7 +235,7 @@ EXPORT_SYMBOL_GPL(intel_pmc_gcr_write);
*
* Return: negative value on error or 0 on success.
*/
int intel_pmc_gcr_update(u32 offset, u32 mask, u32 val)
static int intel_pmc_gcr_update(u32 offset, u32 mask, u32 val)
{
u32 new_val;
int ret = 0;
......@@ -339,7 +265,6 @@ int intel_pmc_gcr_update(u32 offset, u32 mask, u32 val)
spin_unlock(&ipcdev.gcr_lock);
return ret;
}
EXPORT_SYMBOL_GPL(intel_pmc_gcr_update);
static int update_no_reboot_bit(void *priv, bool set)
{
......@@ -405,7 +330,7 @@ static int intel_pmc_ipc_check_status(void)
*
* Return: an IPC error code or 0 on success.
*/
int intel_pmc_ipc_simple_command(int cmd, int sub)
static int intel_pmc_ipc_simple_command(int cmd, int sub)
{
int ret;
......@@ -420,7 +345,6 @@ int intel_pmc_ipc_simple_command(int cmd, int sub)
return ret;
}
EXPORT_SYMBOL_GPL(intel_pmc_ipc_simple_command);
/**
* intel_pmc_ipc_raw_cmd() - IPC command with data and pointers
......@@ -437,8 +361,8 @@ EXPORT_SYMBOL_GPL(intel_pmc_ipc_simple_command);
*
* Return: an IPC error code or 0 on success.
*/
int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen, u32 *out,
u32 outlen, u32 dptr, u32 sptr)
static int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen, u32 *out,
u32 outlen, u32 dptr, u32 sptr)
{
u32 wbuf[4] = { 0 };
int ret;
......@@ -470,7 +394,6 @@ int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen, u32 *out,
return ret;
}
EXPORT_SYMBOL_GPL(intel_pmc_ipc_raw_cmd);
/**
* intel_pmc_ipc_command() - IPC command with input/output data
......@@ -579,6 +502,7 @@ static ssize_t intel_pmc_ipc_simple_cmd_store(struct device *dev,
}
return (ssize_t)count;
}
static DEVICE_ATTR(simplecmd, 0200, NULL, intel_pmc_ipc_simple_cmd_store);
static ssize_t intel_pmc_ipc_northpeak_store(struct device *dev,
struct device_attribute *attr,
......@@ -588,8 +512,9 @@ static ssize_t intel_pmc_ipc_northpeak_store(struct device *dev,
int subcmd;
int ret;
if (kstrtoul(buf, 0, &val))
return -EINVAL;
ret = kstrtoul(buf, 0, &val);
if (ret)
return ret;
if (val)
subcmd = 1;
......@@ -602,11 +527,7 @@ static ssize_t intel_pmc_ipc_northpeak_store(struct device *dev,
}
return (ssize_t)count;
}
static DEVICE_ATTR(simplecmd, S_IWUSR,
NULL, intel_pmc_ipc_simple_cmd_store);
static DEVICE_ATTR(northpeak, S_IWUSR,
NULL, intel_pmc_ipc_northpeak_store);
static DEVICE_ATTR(northpeak, 0200, NULL, intel_pmc_ipc_northpeak_store);
static struct attribute *intel_ipc_attrs[] = {
&dev_attr_northpeak.attr,
......@@ -618,6 +539,11 @@ static const struct attribute_group intel_ipc_group = {
.attrs = intel_ipc_attrs,
};
static const struct attribute_group *intel_ipc_groups[] = {
&intel_ipc_group,
NULL
};
static struct resource punit_res_array[] = {
/* Punit BIOS */
{
......@@ -958,18 +884,10 @@ static int ipc_plat_probe(struct platform_device *pdev)
goto err_irq;
}
ret = sysfs_create_group(&pdev->dev.kobj, &intel_ipc_group);
if (ret) {
dev_err(&pdev->dev, "Failed to create sysfs group %d\n",
ret);
goto err_sys;
}
ipcdev.has_gcr_regs = true;
return 0;
err_sys:
devm_free_irq(&pdev->dev, ipcdev.irq, &ipcdev);
err_irq:
platform_device_unregister(ipcdev.tco_dev);
platform_device_unregister(ipcdev.punit_dev);
......@@ -980,7 +898,6 @@ static int ipc_plat_probe(struct platform_device *pdev)
static int ipc_plat_remove(struct platform_device *pdev)
{
sysfs_remove_group(&pdev->dev.kobj, &intel_ipc_group);
devm_free_irq(&pdev->dev, ipcdev.irq, &ipcdev);
platform_device_unregister(ipcdev.tco_dev);
platform_device_unregister(ipcdev.punit_dev);
......@@ -995,6 +912,7 @@ static struct platform_driver ipc_plat_driver = {
.driver = {
.name = "pmc-ipc-plat",
.acpi_match_table = ACPI_PTR(ipc_acpi_ids),
.dev_groups = intel_ipc_groups,
},
};
......
......@@ -26,11 +26,7 @@
#include <asm/intel_scu_ipc.h>
/* IPC defines the following message types */
#define IPCMSG_WATCHDOG_TIMER 0xF8 /* Set Kernel Watchdog Threshold */
#define IPCMSG_BATTERY 0xEF /* Coulomb Counter Accumulator */
#define IPCMSG_FW_UPDATE 0xFE /* Firmware update */
#define IPCMSG_PCNTRL 0xFF /* Power controller unit read/write */
#define IPCMSG_FW_REVISION 0xF4 /* Get firmware revision */
#define IPCMSG_PCNTRL 0xff /* Power controller unit read/write */
/* Command id associated with message IPCMSG_PCNTRL */
#define IPC_CMD_PCNTRL_W 0 /* Register write */
......@@ -58,56 +54,29 @@
#define IPC_RWBUF_SIZE 20 /* IPC Read buffer Size */
#define IPC_IOC 0x100 /* IPC command register IOC bit */
#define PCI_DEVICE_ID_LINCROFT 0x082a
#define PCI_DEVICE_ID_PENWELL 0x080e
#define PCI_DEVICE_ID_CLOVERVIEW 0x08ea
#define PCI_DEVICE_ID_TANGIER 0x11a0
/* intel scu ipc driver data */
struct intel_scu_ipc_pdata_t {
u32 i2c_base;
u32 i2c_len;
u8 irq_mode;
};
static const struct intel_scu_ipc_pdata_t intel_scu_ipc_lincroft_pdata = {
.i2c_base = 0xff12b000,
.i2c_len = 0x10,
.irq_mode = 0,
};
/* Penwell and Cloverview */
static const struct intel_scu_ipc_pdata_t intel_scu_ipc_penwell_pdata = {
.i2c_base = 0xff12b000,
.i2c_len = 0x10,
.irq_mode = 1,
};
static const struct intel_scu_ipc_pdata_t intel_scu_ipc_tangier_pdata = {
.i2c_base = 0xff00d000,
.i2c_len = 0x10,
.irq_mode = 0,
};
struct intel_scu_ipc_dev {
struct device *dev;
void __iomem *ipc_base;
void __iomem *i2c_base;
struct completion cmd_complete;
u8 irq_mode;
};
static struct intel_scu_ipc_dev ipcdev; /* Only one for now */
#define IPC_STATUS 0x04
#define IPC_STATUS_IRQ BIT(2)
#define IPC_STATUS_ERR BIT(1)
#define IPC_STATUS_BUSY BIT(0)
/*
* IPC Read Buffer (Read Only):
* 16 byte buffer for receiving data from SCU, if IPC command
* processing results in response data
* IPC Write/Read Buffers:
* 16 byte buffer for sending and receiving data to and from SCU.
*/
#define IPC_WRITE_BUFFER 0x80
#define IPC_READ_BUFFER 0x90
#define IPC_I2C_CNTRL_ADDR 0
#define I2C_DATA_ADDR 0x04
/* Timeout in jiffies */
#define IPC_TIMEOUT (3 * HZ)
static DEFINE_MUTEX(ipclock); /* lock used to prevent multiple call to SCU */
......@@ -120,11 +89,8 @@ static DEFINE_MUTEX(ipclock); /* lock used to prevent multiple call to SCU */
*/
static inline void ipc_command(struct intel_scu_ipc_dev *scu, u32 cmd)
{
if (scu->irq_mode) {
reinit_completion(&scu->cmd_complete);
writel(cmd | IPC_IOC, scu->ipc_base);
}
writel(cmd, scu->ipc_base);
reinit_completion(&scu->cmd_complete);
writel(cmd | IPC_IOC, scu->ipc_base);
}
/*
......@@ -135,7 +101,7 @@ static inline void ipc_command(struct intel_scu_ipc_dev *scu, u32 cmd)
*/
static inline void ipc_data_writel(struct intel_scu_ipc_dev *scu, u32 data, u32 offset)
{
writel(data, scu->ipc_base + 0x80 + offset);
writel(data, scu->ipc_base + IPC_WRITE_BUFFER + offset);
}
/*
......@@ -147,7 +113,7 @@ static inline void ipc_data_writel(struct intel_scu_ipc_dev *scu, u32 data, u32
*/
static inline u8 ipc_read_status(struct intel_scu_ipc_dev *scu)
{
return __raw_readl(scu->ipc_base + 0x04);
return __raw_readl(scu->ipc_base + IPC_STATUS);
}
/* Read ipc byte data */
......@@ -165,24 +131,20 @@ static inline u32 ipc_data_readl(struct intel_scu_ipc_dev *scu, u32 offset)
/* Wait till scu status is busy */
static inline int busy_loop(struct intel_scu_ipc_dev *scu)
{
u32 status = ipc_read_status(scu);
u32 loop_count = 100000;
unsigned long end = jiffies + msecs_to_jiffies(IPC_TIMEOUT);
/* break if scu doesn't reset busy bit after huge retry */
while ((status & BIT(0)) && --loop_count) {
udelay(1); /* scu processing time is in few u secods */
status = ipc_read_status(scu);
}
do {
u32 status;
if (status & BIT(0)) {
dev_err(scu->dev, "IPC timed out");
return -ETIMEDOUT;
}
status = ipc_read_status(scu);
if (!(status & IPC_STATUS_BUSY))
return (status & IPC_STATUS_ERR) ? -EIO : 0;
if (status & BIT(1))
return -EIO;
usleep_range(50, 100);
} while (time_before(jiffies, end));
return 0;
dev_err(scu->dev, "IPC timed out");
return -ETIMEDOUT;
}
/* Wait till ipc ioc interrupt is received or timeout in 3 HZ */
......@@ -190,13 +152,13 @@ static inline int ipc_wait_for_interrupt(struct intel_scu_ipc_dev *scu)
{
int status;
if (!wait_for_completion_timeout(&scu->cmd_complete, 3 * HZ)) {
if (!wait_for_completion_timeout(&scu->cmd_complete, IPC_TIMEOUT)) {
dev_err(scu->dev, "IPC timed out\n");
return -ETIMEDOUT;
}
status = ipc_read_status(scu);
if (status & BIT(1))
if (status & IPC_STATUS_ERR)
return -EIO;
return 0;
......@@ -260,14 +222,14 @@ static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id)
}
/**
* intel_scu_ipc_ioread8 - read a word via the SCU
* @addr: register on SCU
* @data: return pointer for read byte
* intel_scu_ipc_ioread8 - read a word via the SCU
* @addr: Register on SCU
* @data: Return pointer for read byte
*
* Read a single register. Returns 0 on success or an error code. All
* locking between SCU accesses is handled for the caller.
* Read a single register. Returns %0 on success or an error code. All
* locking between SCU accesses is handled for the caller.
*
* This function may sleep.
* This function may sleep.
*/
int intel_scu_ipc_ioread8(u16 addr, u8 *data)
{
......@@ -276,48 +238,14 @@ int intel_scu_ipc_ioread8(u16 addr, u8 *data)
EXPORT_SYMBOL(intel_scu_ipc_ioread8);
/**
* intel_scu_ipc_ioread16 - read a word via the SCU
* @addr: register on SCU
* @data: return pointer for read word
*
* Read a register pair. Returns 0 on success or an error code. All
* locking between SCU accesses is handled for the caller.
*
* This function may sleep.
*/
int intel_scu_ipc_ioread16(u16 addr, u16 *data)
{
u16 x[2] = {addr, addr + 1};
return pwr_reg_rdwr(x, (u8 *)data, 2, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_R);
}
EXPORT_SYMBOL(intel_scu_ipc_ioread16);
/**
* intel_scu_ipc_ioread32 - read a dword via the SCU
* @addr: register on SCU
* @data: return pointer for read dword
*
* Read four registers. Returns 0 on success or an error code. All
* locking between SCU accesses is handled for the caller.
*
* This function may sleep.
*/
int intel_scu_ipc_ioread32(u16 addr, u32 *data)
{
u16 x[4] = {addr, addr + 1, addr + 2, addr + 3};
return pwr_reg_rdwr(x, (u8 *)data, 4, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_R);
}
EXPORT_SYMBOL(intel_scu_ipc_ioread32);
/**
* intel_scu_ipc_iowrite8 - write a byte via the SCU
* @addr: register on SCU
* @data: byte to write
* intel_scu_ipc_iowrite8 - write a byte via the SCU
* @addr: Register on SCU
* @data: Byte to write
*
* Write a single register. Returns 0 on success or an error code. All
* locking between SCU accesses is handled for the caller.
* Write a single register. Returns %0 on success or an error code. All
* locking between SCU accesses is handled for the caller.
*
* This function may sleep.
* This function may sleep.
*/
int intel_scu_ipc_iowrite8(u16 addr, u8 data)
{
......@@ -326,51 +254,17 @@ int intel_scu_ipc_iowrite8(u16 addr, u8 data)
EXPORT_SYMBOL(intel_scu_ipc_iowrite8);
/**
* intel_scu_ipc_iowrite16 - write a word via the SCU
* @addr: register on SCU
* @data: word to write
*
* Write two registers. Returns 0 on success or an error code. All
* locking between SCU accesses is handled for the caller.
* intel_scu_ipc_readvv - read a set of registers
* @addr: Register list
* @data: Bytes to return
* @len: Length of array
*
* This function may sleep.
*/
int intel_scu_ipc_iowrite16(u16 addr, u16 data)
{
u16 x[2] = {addr, addr + 1};
return pwr_reg_rdwr(x, (u8 *)&data, 2, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_W);
}
EXPORT_SYMBOL(intel_scu_ipc_iowrite16);
/**
* intel_scu_ipc_iowrite32 - write a dword via the SCU
* @addr: register on SCU
* @data: dword to write
* Read registers. Returns %0 on success or an error code. All locking
* between SCU accesses is handled for the caller.
*
* Write four registers. Returns 0 on success or an error code. All
* locking between SCU accesses is handled for the caller.
* The largest array length permitted by the hardware is 5 items.
*
* This function may sleep.
*/
int intel_scu_ipc_iowrite32(u16 addr, u32 data)
{
u16 x[4] = {addr, addr + 1, addr + 2, addr + 3};
return pwr_reg_rdwr(x, (u8 *)&data, 4, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_W);
}
EXPORT_SYMBOL(intel_scu_ipc_iowrite32);
/**
* intel_scu_ipc_readvv - read a set of registers
* @addr: register list
* @data: bytes to return
* @len: length of array
*
* Read registers. Returns 0 on success or an error code. All
* locking between SCU accesses is handled for the caller.
*
* The largest array length permitted by the hardware is 5 items.
*
* This function may sleep.
* This function may sleep.
*/
int intel_scu_ipc_readv(u16 *addr, u8 *data, int len)
{
......@@ -379,18 +273,17 @@ int intel_scu_ipc_readv(u16 *addr, u8 *data, int len)
EXPORT_SYMBOL(intel_scu_ipc_readv);
/**
* intel_scu_ipc_writev - write a set of registers
* @addr: register list
* @data: bytes to write
* @len: length of array
*
* Write registers. Returns 0 on success or an error code. All
* locking between SCU accesses is handled for the caller.
* intel_scu_ipc_writev - write a set of registers
* @addr: Register list
* @data: Bytes to write
* @len: Length of array
*
* The largest array length permitted by the hardware is 5 items.
* Write registers. Returns %0 on success or an error code. All locking
* between SCU accesses is handled for the caller.
*
* This function may sleep.
* The largest array length permitted by the hardware is 5 items.
*
* This function may sleep.
*/
int intel_scu_ipc_writev(u16 *addr, u8 *data, int len)
{
......@@ -399,19 +292,18 @@ int intel_scu_ipc_writev(u16 *addr, u8 *data, int len)
EXPORT_SYMBOL(intel_scu_ipc_writev);
/**
* intel_scu_ipc_update_register - r/m/w a register
* @addr: register address
* @bits: bits to update
* @mask: mask of bits to update
*
* Read-modify-write power control unit register. The first data argument
* must be register value and second is mask value
* mask is a bitmap that indicates which bits to update.
* 0 = masked. Don't modify this bit, 1 = modify this bit.
* returns 0 on success or an error code.
*
* This function may sleep. Locking between SCU accesses is handled
* for the caller.
* intel_scu_ipc_update_register - r/m/w a register
* @addr: Register address
* @bits: Bits to update
* @mask: Mask of bits to update
*
* Read-modify-write power control unit register. The first data argument
* must be register value and second is mask value mask is a bitmap that
* indicates which bits to update. %0 = masked. Don't modify this bit, %1 =
* modify this bit. returns %0 on success or an error code.
*
* This function may sleep. Locking between SCU accesses is handled
* for the caller.
*/
int intel_scu_ipc_update_register(u16 addr, u8 bits, u8 mask)
{
......@@ -421,16 +313,16 @@ int intel_scu_ipc_update_register(u16 addr, u8 bits, u8 mask)
EXPORT_SYMBOL(intel_scu_ipc_update_register);
/**
* intel_scu_ipc_simple_command - send a simple command
* @cmd: command
* @sub: sub type
* intel_scu_ipc_simple_command - send a simple command
* @cmd: Command
* @sub: Sub type
*
* Issue a simple command to the SCU. Do not use this interface if
* you must then access data as any data values may be overwritten
* by another SCU access by the time this function returns.
* Issue a simple command to the SCU. Do not use this interface if you must
* then access data as any data values may be overwritten by another SCU
* access by the time this function returns.
*
* This function may sleep. Locking for SCU accesses is handled for
* the caller.
* This function may sleep. Locking for SCU accesses is handled for the
* caller.
*/
int intel_scu_ipc_simple_command(int cmd, int sub)
{
......@@ -450,16 +342,16 @@ int intel_scu_ipc_simple_command(int cmd, int sub)
EXPORT_SYMBOL(intel_scu_ipc_simple_command);
/**
* intel_scu_ipc_command - command with data
* @cmd: command
* @sub: sub type
* @in: input data
* @inlen: input length in dwords
* @out: output data
* @outlein: output length in dwords
*
* Issue a command to the SCU which involves data transfers. Do the
* data copies under the lock but leave it for the caller to interpret
* intel_scu_ipc_command - command with data
* @cmd: Command
* @sub: Sub type
* @in: Input data
* @inlen: Input length in dwords
* @out: Output data
* @outlen: Output length in dwords
*
* Issue a command to the SCU which involves data transfers. Do the
* data copies under the lock but leave it for the caller to interpret.
*/
int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
u32 *out, int outlen)
......@@ -489,117 +381,6 @@ int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
}
EXPORT_SYMBOL(intel_scu_ipc_command);
#define IPC_SPTR 0x08
#define IPC_DPTR 0x0C
/**
* intel_scu_ipc_raw_command() - IPC command with data and pointers
* @cmd: IPC command code.
* @sub: IPC command sub type.
* @in: input data of this IPC command.
* @inlen: input data length in dwords.
* @out: output data of this IPC command.
* @outlen: output data length in dwords.
* @sptr: data writing to SPTR register.
* @dptr: data writing to DPTR register.
*
* Send an IPC command to SCU with input/output data and source/dest pointers.
*
* Return: an IPC error code or 0 on success.
*/
int intel_scu_ipc_raw_command(int cmd, int sub, u8 *in, int inlen,
u32 *out, int outlen, u32 dptr, u32 sptr)
{
struct intel_scu_ipc_dev *scu = &ipcdev;
int inbuflen = DIV_ROUND_UP(inlen, 4);
u32 inbuf[4];
int i, err;
/* Up to 16 bytes */
if (inbuflen > 4)
return -EINVAL;
mutex_lock(&ipclock);
if (scu->dev == NULL) {
mutex_unlock(&ipclock);
return -ENODEV;
}
writel(dptr, scu->ipc_base + IPC_DPTR);
writel(sptr, scu->ipc_base + IPC_SPTR);
/*
* SRAM controller doesn't support 8-bit writes, it only
* supports 32-bit writes, so we have to copy input data into
* the temporary buffer, and SCU FW will use the inlen to
* determine the actual input data length in the temporary
* buffer.
*/
memcpy(inbuf, in, inlen);
for (i = 0; i < inbuflen; i++)
ipc_data_writel(scu, inbuf[i], 4 * i);
ipc_command(scu, (inlen << 16) | (sub << 12) | cmd);
err = intel_scu_ipc_check_status(scu);
if (!err) {
for (i = 0; i < outlen; i++)
*out++ = ipc_data_readl(scu, 4 * i);
}
mutex_unlock(&ipclock);
return err;
}
EXPORT_SYMBOL_GPL(intel_scu_ipc_raw_command);
/* I2C commands */
#define IPC_I2C_WRITE 1 /* I2C Write command */
#define IPC_I2C_READ 2 /* I2C Read command */
/**
* intel_scu_ipc_i2c_cntrl - I2C read/write operations
* @addr: I2C address + command bits
* @data: data to read/write
*
* Perform an an I2C read/write operation via the SCU. All locking is
* handled for the caller. This function may sleep.
*
* Returns an error code or 0 on success.
*
* This has to be in the IPC driver for the locking.
*/
int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data)
{
struct intel_scu_ipc_dev *scu = &ipcdev;
u32 cmd = 0;
mutex_lock(&ipclock);
if (scu->dev == NULL) {
mutex_unlock(&ipclock);
return -ENODEV;
}
cmd = (addr >> 24) & 0xFF;
if (cmd == IPC_I2C_READ) {
writel(addr, scu->i2c_base + IPC_I2C_CNTRL_ADDR);
/* Write not getting updated without delay */
usleep_range(1000, 2000);
*data = readl(scu->i2c_base + I2C_DATA_ADDR);
} else if (cmd == IPC_I2C_WRITE) {
writel(*data, scu->i2c_base + I2C_DATA_ADDR);
usleep_range(1000, 2000);
writel(addr, scu->i2c_base + IPC_I2C_CNTRL_ADDR);
} else {
dev_err(scu->dev,
"intel_scu_ipc: I2C INVALID_CMD = 0x%x\n", cmd);
mutex_unlock(&ipclock);
return -EIO;
}
mutex_unlock(&ipclock);
return 0;
}
EXPORT_SYMBOL(intel_scu_ipc_i2c_cntrl);
/*
* Interrupt handler gets called when ioc bit of IPC_COMMAND_REG set to 1
* When ioc bit is set to 1, caller api must wait for interrupt handler called
......@@ -610,9 +391,10 @@ EXPORT_SYMBOL(intel_scu_ipc_i2c_cntrl);
static irqreturn_t ioc(int irq, void *dev_id)
{
struct intel_scu_ipc_dev *scu = dev_id;
int status = ipc_read_status(scu);
if (scu->irq_mode)
complete(&scu->cmd_complete);
writel(status | IPC_STATUS_IRQ, scu->ipc_base + IPC_STATUS);
complete(&scu->cmd_complete);
return IRQ_HANDLED;
}
......@@ -629,17 +411,10 @@ static int ipc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
int err;
struct intel_scu_ipc_dev *scu = &ipcdev;
struct intel_scu_ipc_pdata_t *pdata;
if (scu->dev) /* We support only one SCU */
return -EBUSY;
pdata = (struct intel_scu_ipc_pdata_t *)id->driver_data;
if (!pdata)
return -ENODEV;
scu->irq_mode = pdata->irq_mode;
err = pcim_enable_device(pdev);
if (err)
return err;
......@@ -652,10 +427,6 @@ static int ipc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
scu->ipc_base = pcim_iomap_table(pdev)[0];
scu->i2c_base = ioremap_nocache(pdata->i2c_base, pdata->i2c_len);
if (!scu->i2c_base)
return -ENOMEM;
err = devm_request_irq(&pdev->dev, pdev->irq, ioc, 0, "intel_scu_ipc",
scu);
if (err)
......@@ -670,13 +441,10 @@ static int ipc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return 0;
}
#define SCU_DEVICE(id, pdata) {PCI_VDEVICE(INTEL, id), (kernel_ulong_t)&pdata}
static const struct pci_device_id pci_ids[] = {
SCU_DEVICE(PCI_DEVICE_ID_LINCROFT, intel_scu_ipc_lincroft_pdata),
SCU_DEVICE(PCI_DEVICE_ID_PENWELL, intel_scu_ipc_penwell_pdata),
SCU_DEVICE(PCI_DEVICE_ID_CLOVERVIEW, intel_scu_ipc_penwell_pdata),
SCU_DEVICE(PCI_DEVICE_ID_TANGIER, intel_scu_ipc_tangier_pdata),
{ PCI_VDEVICE(INTEL, 0x080e) },
{ PCI_VDEVICE(INTEL, 0x08ea) },
{ PCI_VDEVICE(INTEL, 0x11a0) },
{}
};
......
......@@ -50,6 +50,8 @@ static const struct isst_valid_cmd_ranges isst_valid_cmds[] = {
{0x7F, 0x00, 0x0B},
{0x7F, 0x10, 0x12},
{0x7F, 0x20, 0x23},
{0x94, 0x03, 0x03},
{0x95, 0x03, 0x03},
};
static const struct isst_cmd_set_req_type isst_cmd_set_reqs[] = {
......@@ -59,6 +61,7 @@ static const struct isst_cmd_set_req_type isst_cmd_set_reqs[] = {
{0xD0, 0x03, 0x08},
{0x7F, 0x02, 0x00},
{0x7F, 0x08, 0x00},
{0x95, 0x03, 0x03},
};
struct isst_cmd {
......
......@@ -686,13 +686,14 @@ static ssize_t telem_pss_trc_verb_write(struct file *file,
u32 verbosity;
int err;
if (kstrtou32_from_user(userbuf, count, 0, &verbosity))
return -EFAULT;
err = kstrtou32_from_user(userbuf, count, 0, &verbosity);
if (err)
return err;
err = telemetry_set_trace_verbosity(TELEM_PSS, verbosity);
if (err) {
pr_err("Changing PSS Trace Verbosity Failed. Error %d\n", err);
count = err;
return err;
}
return count;
......@@ -733,13 +734,14 @@ static ssize_t telem_ioss_trc_verb_write(struct file *file,
u32 verbosity;
int err;
if (kstrtou32_from_user(userbuf, count, 0, &verbosity))
return -EFAULT;
err = kstrtou32_from_user(userbuf, count, 0, &verbosity);
if (err)
return err;
err = telemetry_set_trace_verbosity(TELEM_IOSS, verbosity);
if (err) {
pr_err("Changing IOSS Trace Verbosity Failed. Error %d\n", err);
count = err;
return err;
}
return count;
......
......@@ -1117,9 +1117,9 @@ static const struct telemetry_core_ops telm_pltops = {
static int telemetry_pltdrv_probe(struct platform_device *pdev)
{
struct resource *res0 = NULL, *res1 = NULL;
const struct x86_cpu_id *id;
int size, ret = -ENOMEM;
void __iomem *mem;
int ret;
id = x86_match_cpu(telemetry_cpu_ids);
if (!id)
......@@ -1127,50 +1127,17 @@ static int telemetry_pltdrv_probe(struct platform_device *pdev)
telm_conf = (struct telemetry_plt_config *)id->driver_data;
res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res0) {
ret = -EINVAL;
goto out;
}
size = resource_size(res0);
if (!devm_request_mem_region(&pdev->dev, res0->start, size,
pdev->name)) {
ret = -EBUSY;
goto out;
}
telm_conf->pss_config.ssram_base_addr = res0->start;
telm_conf->pss_config.ssram_size = size;
mem = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(mem))
return PTR_ERR(mem);
res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!res1) {
ret = -EINVAL;
goto out;
}
size = resource_size(res1);
if (!devm_request_mem_region(&pdev->dev, res1->start, size,
pdev->name)) {
ret = -EBUSY;
goto out;
}
telm_conf->pss_config.regmap = mem;
telm_conf->ioss_config.ssram_base_addr = res1->start;
telm_conf->ioss_config.ssram_size = size;
mem = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(mem))
return PTR_ERR(mem);
telm_conf->pss_config.regmap = ioremap_nocache(
telm_conf->pss_config.ssram_base_addr,
telm_conf->pss_config.ssram_size);
if (!telm_conf->pss_config.regmap) {
ret = -ENOMEM;
goto out;
}
telm_conf->ioss_config.regmap = ioremap_nocache(
telm_conf->ioss_config.ssram_base_addr,
telm_conf->ioss_config.ssram_size);
if (!telm_conf->ioss_config.regmap) {
ret = -ENOMEM;
goto out;
}
telm_conf->ioss_config.regmap = mem;
mutex_init(&telm_conf->telem_lock);
mutex_init(&telm_conf->telem_trace_lock);
......@@ -1188,14 +1155,6 @@ static int telemetry_pltdrv_probe(struct platform_device *pdev)
return 0;
out:
if (res0)
release_mem_region(res0->start, resource_size(res0));
if (res1)
release_mem_region(res1->start, resource_size(res1));
if (telm_conf->pss_config.regmap)
iounmap(telm_conf->pss_config.regmap);
if (telm_conf->ioss_config.regmap)
iounmap(telm_conf->ioss_config.regmap);
dev_err(&pdev->dev, "TELEMETRY Setup Failed.\n");
return ret;
......@@ -1204,9 +1163,6 @@ static int telemetry_pltdrv_probe(struct platform_device *pdev)
static int telemetry_pltdrv_remove(struct platform_device *pdev)
{
telemetry_clear_pltdata();
iounmap(telm_conf->pss_config.regmap);
iounmap(telm_conf->ioss_config.regmap);
return 0;
}
......
......@@ -35,6 +35,8 @@
#define MLXPLAT_CPLD_LPC_REG_LED4_OFFSET 0x23
#define MLXPLAT_CPLD_LPC_REG_LED5_OFFSET 0x24
#define MLXPLAT_CPLD_LPC_REG_FAN_DIRECTION 0x2a
#define MLXPLAT_CPLD_LPC_REG_GP0_RO_OFFSET 0x2b
#define MLXPLAT_CPLD_LPC_REG_GP0_OFFSET 0x2e
#define MLXPLAT_CPLD_LPC_REG_GP1_OFFSET 0x30
#define MLXPLAT_CPLD_LPC_REG_WP1_OFFSET 0x31
#define MLXPLAT_CPLD_LPC_REG_GP2_OFFSET 0x32
......@@ -46,6 +48,8 @@
#define MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET 0x41
#define MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET 0x42
#define MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET 0x43
#define MLXPLAT_CPLD_LPC_REG_AGGRCX_OFFSET 0x44
#define MLXPLAT_CPLD_LPC_REG_AGGRCX_MASK_OFFSET 0x45
#define MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET 0x50
#define MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET 0x51
#define MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET 0x52
......@@ -68,6 +72,7 @@
#define MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET 0xd1
#define MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET 0xd2
#define MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET 0xd3
#define MLXPLAT_CPLD_LPC_REG_UFM_VERSION_OFFSET 0xe2
#define MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET 0xe3
#define MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET 0xe4
#define MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET 0xe5
......@@ -85,9 +90,13 @@
#define MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET 0xf6
#define MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET 0xf7
#define MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET 0xf8
#define MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET 0xf9
#define MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET 0xfb
#define MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET 0xfc
#define MLXPLAT_CPLD_LPC_IO_RANGE 0x100
#define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb
#define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda
#define MLXPLAT_CPLD_LPC_I2C_CH3_OFF 0xdc
#define MLXPLAT_CPLD_LPC_PIO_OFFSET 0x10000UL
#define MLXPLAT_CPLD_LPC_REG1 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
......@@ -96,6 +105,9 @@
#define MLXPLAT_CPLD_LPC_REG2 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
MLXPLAT_CPLD_LPC_I2C_CH2_OFF) | \
MLXPLAT_CPLD_LPC_PIO_OFFSET)
#define MLXPLAT_CPLD_LPC_REG3 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
MLXPLAT_CPLD_LPC_I2C_CH3_OFF) | \
MLXPLAT_CPLD_LPC_PIO_OFFSET)
/* Masks for aggregation, psu, pwr and fan event in CPLD related registers. */
#define MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF 0x04
......@@ -112,17 +124,29 @@
#define MLXPLAT_CPLD_LOW_AGGR_MASK_I2C BIT(6)
#define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0)
#define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0)
#define MLXPLAT_CPLD_PSU_EXT_MASK GENMASK(3, 0)
#define MLXPLAT_CPLD_PWR_EXT_MASK GENMASK(3, 0)
#define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0)
#define MLXPLAT_CPLD_ASIC_MASK GENMASK(1, 0)
#define MLXPLAT_CPLD_FAN_NG_MASK GENMASK(5, 0)
#define MLXPLAT_CPLD_LED_LO_NIBBLE_MASK GENMASK(7, 4)
#define MLXPLAT_CPLD_LED_HI_NIBBLE_MASK GENMASK(3, 0)
#define MLXPLAT_CPLD_VOLTREG_UPD_MASK GENMASK(5, 4)
#define MLXPLAT_CPLD_I2C_CAP_BIT 0x04
#define MLXPLAT_CPLD_I2C_CAP_MASK GENMASK(5, MLXPLAT_CPLD_I2C_CAP_BIT)
/* Masks for aggregation for comex carriers */
#define MLXPLAT_CPLD_AGGR_MASK_CARRIER BIT(1)
#define MLXPLAT_CPLD_AGGR_MASK_CARR_DEF (MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF | \
MLXPLAT_CPLD_AGGR_MASK_CARRIER)
#define MLXPLAT_CPLD_LOW_AGGRCX_MASK 0xc1
/* Default I2C parent bus number */
#define MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR 1
/* 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
/* Number of channels in group */
#define MLXPLAT_CPLD_GRP_CHNL_NUM 8
......@@ -130,14 +154,16 @@
/* Start channel numbers */
#define MLXPLAT_CPLD_CH1 2
#define MLXPLAT_CPLD_CH2 10
#define MLXPLAT_CPLD_CH3 18
/* Number of LPC attached MUX platform devices */
#define MLXPLAT_CPLD_LPC_MUX_DEVS 2
#define MLXPLAT_CPLD_LPC_MUX_DEVS 3
/* Hotplug devices adapter numbers */
#define MLXPLAT_CPLD_NR_NONE -1
#define MLXPLAT_CPLD_PSU_DEFAULT_NR 10
#define MLXPLAT_CPLD_PSU_MSNXXXX_NR 4
#define MLXPLAT_CPLD_PSU_MSNXXXX_NR2 3
#define MLXPLAT_CPLD_FAN1_DEFAULT_NR 11
#define MLXPLAT_CPLD_FAN2_DEFAULT_NR 12
#define MLXPLAT_CPLD_FAN3_DEFAULT_NR 13
......@@ -187,8 +213,24 @@ static const struct resource mlxplat_lpc_resources[] = {
IORESOURCE_IO),
};
/* Platform i2c next generation systems data */
static struct mlxreg_core_data mlxplat_mlxcpld_i2c_ng_items_data[] = {
{
.reg = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET,
.mask = MLXPLAT_CPLD_I2C_CAP_MASK,
.bit = MLXPLAT_CPLD_I2C_CAP_BIT,
},
};
static struct mlxreg_core_item mlxplat_mlxcpld_i2c_ng_items[] = {
{
.data = mlxplat_mlxcpld_i2c_ng_items_data,
},
};
/* Platform next generation systems i2c data */
static struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_i2c_ng_data = {
.items = mlxplat_mlxcpld_i2c_ng_items,
.cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
.mask = MLXPLAT_CPLD_AGGR_MASK_COMEX,
.cell_low = MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET,
......@@ -213,7 +255,7 @@ static const int mlxplat_default_channels[][MLXPLAT_CPLD_GRP_CHNL_NUM] = {
static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
/* Platform mux data */
static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
static struct i2c_mux_reg_platform_data mlxplat_default_mux_data[] = {
{
.parent = 1,
.base_nr = MLXPLAT_CPLD_CH1,
......@@ -233,6 +275,40 @@ static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
};
/* Platform mux configuration variables */
static int mlxplat_max_adap_num;
static int mlxplat_mux_num;
static struct i2c_mux_reg_platform_data *mlxplat_mux_data;
/* Platform extended mux data */
static struct i2c_mux_reg_platform_data mlxplat_extended_mux_data[] = {
{
.parent = 1,
.base_nr = MLXPLAT_CPLD_CH1,
.write_only = 1,
.reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1,
.reg_size = 1,
.idle_in_use = 1,
},
{
.parent = 1,
.base_nr = MLXPLAT_CPLD_CH2,
.write_only = 1,
.reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG3,
.reg_size = 1,
.idle_in_use = 1,
},
{
.parent = 1,
.base_nr = MLXPLAT_CPLD_CH3,
.write_only = 1,
.reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2,
.reg_size = 1,
.idle_in_use = 1,
},
};
/* Platform hotplug devices */
static struct i2c_board_info mlxplat_mlxcpld_psu[] = {
{
......@@ -276,6 +352,22 @@ static struct i2c_board_info mlxplat_mlxcpld_fan[] = {
},
};
/* Platform hotplug comex carrier system family data */
static struct mlxreg_core_data mlxplat_mlxcpld_comex_psu_items_data[] = {
{
.label = "psu1",
.reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
.mask = BIT(0),
.hpdev.nr = MLXPLAT_CPLD_NR_NONE,
},
{
.label = "psu2",
.reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
.mask = BIT(1),
.hpdev.nr = MLXPLAT_CPLD_NR_NONE,
},
};
/* Platform hotplug default data */
static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = {
{
......@@ -390,6 +482,45 @@ static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = {
},
};
static struct mlxreg_core_item mlxplat_mlxcpld_comex_items[] = {
{
.data = mlxplat_mlxcpld_comex_psu_items_data,
.aggr_mask = MLXPLAT_CPLD_AGGR_MASK_CARRIER,
.reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
.mask = MLXPLAT_CPLD_PSU_MASK,
.count = ARRAY_SIZE(mlxplat_mlxcpld_psu),
.inversed = 1,
.health = false,
},
{
.data = mlxplat_mlxcpld_default_pwr_items_data,
.aggr_mask = MLXPLAT_CPLD_AGGR_MASK_CARRIER,
.reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
.mask = MLXPLAT_CPLD_PWR_MASK,
.count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
.inversed = 0,
.health = false,
},
{
.data = mlxplat_mlxcpld_default_fan_items_data,
.aggr_mask = MLXPLAT_CPLD_AGGR_MASK_CARRIER,
.reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
.mask = MLXPLAT_CPLD_FAN_MASK,
.count = ARRAY_SIZE(mlxplat_mlxcpld_fan),
.inversed = 1,
.health = false,
},
{
.data = mlxplat_mlxcpld_default_asic_items_data,
.aggr_mask = MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF,
.reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET,
.mask = MLXPLAT_CPLD_ASIC_MASK,
.count = ARRAY_SIZE(mlxplat_mlxcpld_default_asic_items_data),
.inversed = 0,
.health = true,
},
};
static
struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = {
.items = mlxplat_mlxcpld_default_items,
......@@ -400,6 +531,16 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = {
.mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
};
static
struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_comex_data = {
.items = mlxplat_mlxcpld_comex_items,
.counter = ARRAY_SIZE(mlxplat_mlxcpld_comex_items),
.cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
.mask = MLXPLAT_CPLD_AGGR_MASK_CARR_DEF,
.cell_low = MLXPLAT_CPLD_LPC_REG_AGGRCX_OFFSET,
.mask_low = MLXPLAT_CPLD_LOW_AGGRCX_MASK,
};
static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_pwr_items_data[] = {
{
.label = "pwr1",
......@@ -723,6 +864,116 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = {
.mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
};
/* Platform hotplug extended system family data */
static struct mlxreg_core_data mlxplat_mlxcpld_ext_psu_items_data[] = {
{
.label = "psu1",
.reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
.mask = BIT(0),
.hpdev.nr = MLXPLAT_CPLD_NR_NONE,
},
{
.label = "psu2",
.reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
.mask = BIT(1),
.hpdev.nr = MLXPLAT_CPLD_NR_NONE,
},
{
.label = "psu3",
.reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
.mask = BIT(2),
.hpdev.nr = MLXPLAT_CPLD_NR_NONE,
},
{
.label = "psu4",
.reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
.mask = BIT(3),
.hpdev.nr = MLXPLAT_CPLD_NR_NONE,
},
};
static struct mlxreg_core_data mlxplat_mlxcpld_ext_pwr_items_data[] = {
{
.label = "pwr1",
.reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
.mask = BIT(0),
.hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
.hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
},
{
.label = "pwr2",
.reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
.mask = BIT(1),
.hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1],
.hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
},
{
.label = "pwr3",
.reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
.mask = BIT(2),
.hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
.hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR2,
},
{
.label = "pwr4",
.reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
.mask = BIT(3),
.hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1],
.hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR2,
},
};
static struct mlxreg_core_item mlxplat_mlxcpld_ext_items[] = {
{
.data = mlxplat_mlxcpld_ext_psu_items_data,
.aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
.reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
.mask = MLXPLAT_CPLD_PSU_EXT_MASK,
.capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET,
.count = ARRAY_SIZE(mlxplat_mlxcpld_ext_psu_items_data),
.inversed = 1,
.health = false,
},
{
.data = mlxplat_mlxcpld_ext_pwr_items_data,
.aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
.reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
.mask = MLXPLAT_CPLD_PWR_EXT_MASK,
.capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET,
.count = ARRAY_SIZE(mlxplat_mlxcpld_ext_pwr_items_data),
.inversed = 0,
.health = false,
},
{
.data = mlxplat_mlxcpld_default_ng_fan_items_data,
.aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
.reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
.mask = MLXPLAT_CPLD_FAN_NG_MASK,
.count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_fan_items_data),
.inversed = 1,
.health = false,
},
{
.data = mlxplat_mlxcpld_default_asic_items_data,
.aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
.reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET,
.mask = MLXPLAT_CPLD_ASIC_MASK,
.count = ARRAY_SIZE(mlxplat_mlxcpld_default_asic_items_data),
.inversed = 0,
.health = true,
},
};
static
struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_ext_data = {
.items = mlxplat_mlxcpld_ext_items,
.counter = ARRAY_SIZE(mlxplat_mlxcpld_ext_items),
.cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
.mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF | MLXPLAT_CPLD_AGGR_MASK_COMEX,
.cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET,
.mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
};
/* Platform led default data */
static struct mlxreg_core_data mlxplat_mlxcpld_default_led_data[] = {
{
......@@ -964,6 +1215,80 @@ static struct mlxreg_core_platform_data mlxplat_default_ng_led_data = {
.counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_led_data),
};
/* Platform led for Comex based 100GbE systems */
static struct mlxreg_core_data mlxplat_mlxcpld_comex_100G_led_data[] = {
{
.label = "status:green",
.reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
},
{
.label = "status:red",
.reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK
},
{
.label = "psu:green",
.reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
.mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
},
{
.label = "psu:red",
.reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
.mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
},
{
.label = "fan1:green",
.reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
},
{
.label = "fan1:red",
.reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
},
{
.label = "fan2:green",
.reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
.mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
},
{
.label = "fan2:red",
.reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
.mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
},
{
.label = "fan3:green",
.reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
},
{
.label = "fan3:red",
.reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
},
{
.label = "fan4:green",
.reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
.mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
},
{
.label = "fan4:red",
.reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
.mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
},
{
.label = "uid:blue",
.reg = MLXPLAT_CPLD_LPC_REG_LED5_OFFSET,
.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
},
};
static struct mlxreg_core_platform_data mlxplat_comex_100G_led_data = {
.data = mlxplat_mlxcpld_comex_100G_led_data,
.counter = ARRAY_SIZE(mlxplat_mlxcpld_comex_100G_led_data),
};
/* Platform register access default */
static struct mlxreg_core_data mlxplat_mlxcpld_default_regs_io_data[] = {
{
......@@ -1156,6 +1481,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_regs_io_data[] = {
.mask = GENMASK(7, 0) & ~BIT(3),
.mode = 0200,
},
{
.label = "select_iio",
.reg = MLXPLAT_CPLD_LPC_REG_GP2_OFFSET,
.mask = GENMASK(7, 0) & ~BIT(6),
.mode = 0644,
},
{
.label = "asic_health",
.reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET,
......@@ -1244,6 +1575,18 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = {
.mask = GENMASK(7, 0) & ~BIT(3),
.mode = 0444,
},
{
.label = "reset_platform",
.reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET,
.mask = GENMASK(7, 0) & ~BIT(4),
.mode = 0444,
},
{
.label = "reset_soc",
.reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET,
.mask = GENMASK(7, 0) & ~BIT(5),
.mode = 0444,
},
{
.label = "reset_comex_wd",
.reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET,
......@@ -1262,6 +1605,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = {
.mask = GENMASK(7, 0) & ~BIT(1),
.mode = 0444,
},
{
.label = "reset_sw_pwr_off",
.reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET,
.mask = GENMASK(7, 0) & ~BIT(2),
.mode = 0444,
},
{
.label = "reset_comex_thermal",
.reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET,
......@@ -1274,6 +1623,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = {
.mask = GENMASK(7, 0) & ~BIT(5),
.mode = 0444,
},
{
.label = "reset_ac_pwr_fail",
.reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET,
.mask = GENMASK(7, 0) & ~BIT(6),
.mode = 0444,
},
{
.label = "psu1_on",
.reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET,
......@@ -1317,6 +1672,43 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = {
.bit = GENMASK(7, 0),
.mode = 0444,
},
{
.label = "voltreg_update_status",
.reg = MLXPLAT_CPLD_LPC_REG_GP0_RO_OFFSET,
.mask = MLXPLAT_CPLD_VOLTREG_UPD_MASK,
.bit = 5,
.mode = 0444,
},
{
.label = "vpd_wp",
.reg = MLXPLAT_CPLD_LPC_REG_GP0_OFFSET,
.mask = GENMASK(7, 0) & ~BIT(3),
.mode = 0644,
},
{
.label = "pcie_asic_reset_dis",
.reg = MLXPLAT_CPLD_LPC_REG_GP0_OFFSET,
.mask = GENMASK(7, 0) & ~BIT(4),
.mode = 0644,
},
{
.label = "config1",
.reg = MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET,
.bit = GENMASK(7, 0),
.mode = 0444,
},
{
.label = "config2",
.reg = MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET,
.bit = GENMASK(7, 0),
.mode = 0444,
},
{
.label = "ufm_version",
.reg = MLXPLAT_CPLD_LPC_REG_UFM_VERSION_OFFSET,
.bit = GENMASK(7, 0),
.mode = 0444,
},
};
static struct mlxreg_core_platform_data mlxplat_default_ng_regs_io_data = {
......@@ -1575,6 +1967,7 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET:
case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET:
case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET:
case MLXPLAT_CPLD_LPC_REG_GP0_OFFSET:
case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET:
case MLXPLAT_CPLD_LPC_REG_WP1_OFFSET:
case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET:
......@@ -1582,6 +1975,7 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRCX_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
......@@ -1621,6 +2015,8 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET:
case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET:
case MLXPLAT_CPLD_LPC_REG_FAN_DIRECTION:
case MLXPLAT_CPLD_LPC_REG_GP0_RO_OFFSET:
case MLXPLAT_CPLD_LPC_REG_GP0_OFFSET:
case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET:
case MLXPLAT_CPLD_LPC_REG_WP1_OFFSET:
case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET:
......@@ -1631,6 +2027,8 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRCX_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRCX_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET:
case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET:
......@@ -1671,6 +2069,10 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET:
case MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET:
case MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET:
case MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET:
case MLXPLAT_CPLD_LPC_REG_UFM_VERSION_OFFSET:
return true;
}
return false;
......@@ -1692,6 +2094,8 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET:
case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET:
case MLXPLAT_CPLD_LPC_REG_FAN_DIRECTION:
case MLXPLAT_CPLD_LPC_REG_GP0_RO_OFFSET:
case MLXPLAT_CPLD_LPC_REG_GP0_OFFSET:
case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET:
case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
......@@ -1700,6 +2104,8 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRCX_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRCX_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET:
case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET:
......@@ -1734,6 +2140,10 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET:
case MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET:
case MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET:
case MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET:
case MLXPLAT_CPLD_LPC_REG_UFM_VERSION_OFFSET:
return true;
}
return false;
......@@ -1751,6 +2161,19 @@ static const struct reg_default mlxplat_mlxcpld_regmap_ng[] = {
{ MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET, 0x00 },
};
static const struct reg_default mlxplat_mlxcpld_regmap_comex_default[] = {
{ MLXPLAT_CPLD_LPC_REG_AGGRCX_MASK_OFFSET,
MLXPLAT_CPLD_LOW_AGGRCX_MASK },
{ MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 },
};
static const struct reg_default mlxplat_mlxcpld_regmap_ng400[] = {
{ 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 },
};
struct mlxplat_mlxcpld_regmap_context {
void __iomem *base;
};
......@@ -1803,6 +2226,34 @@ static const struct regmap_config mlxplat_mlxcpld_regmap_config_ng = {
.reg_write = mlxplat_mlxcpld_reg_write,
};
static const struct regmap_config mlxplat_mlxcpld_regmap_config_comex = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 255,
.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_comex_default,
.num_reg_defaults = ARRAY_SIZE(mlxplat_mlxcpld_regmap_comex_default),
.reg_read = mlxplat_mlxcpld_reg_read,
.reg_write = mlxplat_mlxcpld_reg_write,
};
static const struct regmap_config mlxplat_mlxcpld_regmap_config_ng400 = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 255,
.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_ng400,
.num_reg_defaults = ARRAY_SIZE(mlxplat_mlxcpld_regmap_ng400),
.reg_read = mlxplat_mlxcpld_reg_read,
.reg_write = mlxplat_mlxcpld_reg_write,
};
static struct resource mlxplat_mlxcpld_resources[] = {
[0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"),
};
......@@ -1821,7 +2272,10 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
{
int i;
for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM;
mlxplat_mux_num = ARRAY_SIZE(mlxplat_default_mux_data);
mlxplat_mux_data = mlxplat_default_mux_data;
for (i = 0; i < mlxplat_mux_num; i++) {
mlxplat_mux_data[i].values = mlxplat_default_channels[i];
mlxplat_mux_data[i].n_values =
ARRAY_SIZE(mlxplat_default_channels[i]);
......@@ -1834,13 +2288,16 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0];
return 1;
};
}
static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
{
int i;
for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM;
mlxplat_mux_num = ARRAY_SIZE(mlxplat_default_mux_data);
mlxplat_mux_data = mlxplat_default_mux_data;
for (i = 0; i < mlxplat_mux_num; i++) {
mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
mlxplat_mux_data[i].n_values =
ARRAY_SIZE(mlxplat_msn21xx_channels);
......@@ -1853,13 +2310,16 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0];
return 1;
};
}
static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi)
{
int i;
for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM;
mlxplat_mux_num = ARRAY_SIZE(mlxplat_default_mux_data);
mlxplat_mux_data = mlxplat_default_mux_data;
for (i = 0; i < mlxplat_mux_num; i++) {
mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
mlxplat_mux_data[i].n_values =
ARRAY_SIZE(mlxplat_msn21xx_channels);
......@@ -1872,13 +2332,16 @@ static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi)
mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0];
return 1;
};
}
static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi)
{
int i;
for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM;
mlxplat_mux_num = ARRAY_SIZE(mlxplat_default_mux_data);
mlxplat_mux_data = mlxplat_default_mux_data;
for (i = 0; i < mlxplat_mux_num; i++) {
mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
mlxplat_mux_data[i].n_values =
ARRAY_SIZE(mlxplat_msn21xx_channels);
......@@ -1891,13 +2354,16 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi)
mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0];
return 1;
};
}
static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi)
{
int i;
for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM;
mlxplat_mux_num = ARRAY_SIZE(mlxplat_default_mux_data);
mlxplat_mux_data = mlxplat_default_mux_data;
for (i = 0; i < mlxplat_mux_num; i++) {
mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
mlxplat_mux_data[i].n_values =
ARRAY_SIZE(mlxplat_msn21xx_channels);
......@@ -1914,7 +2380,57 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi)
mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_ng;
return 1;
};
}
static int __init mlxplat_dmi_comex_matched(const struct dmi_system_id *dmi)
{
int i;
mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_EXT_ADAPTER_NUM;
mlxplat_mux_num = ARRAY_SIZE(mlxplat_extended_mux_data);
mlxplat_mux_data = mlxplat_extended_mux_data;
for (i = 0; i < mlxplat_mux_num; i++) {
mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
mlxplat_mux_data[i].n_values =
ARRAY_SIZE(mlxplat_msn21xx_channels);
}
mlxplat_hotplug = &mlxplat_mlxcpld_comex_data;
mlxplat_hotplug->deferred_nr = MLXPLAT_CPLD_MAX_PHYS_EXT_ADAPTER_NUM;
mlxplat_led = &mlxplat_comex_100G_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_regmap_config = &mlxplat_mlxcpld_regmap_config_comex;
return 1;
}
static int __init mlxplat_dmi_ng400_matched(const struct dmi_system_id *dmi)
{
int i;
mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM;
mlxplat_mux_num = ARRAY_SIZE(mlxplat_default_mux_data);
mlxplat_mux_data = mlxplat_default_mux_data;
for (i = 0; i < mlxplat_mux_num; i++) {
mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
mlxplat_mux_data[i].n_values =
ARRAY_SIZE(mlxplat_msn21xx_channels);
}
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_mlxcpld_regmap_config_ng400;
return 1;
}
static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
{
......@@ -1953,6 +2469,18 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
DMI_MATCH(DMI_BOARD_NAME, "VMOD0007"),
},
},
{
.callback = mlxplat_dmi_comex_matched,
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "VMOD0009"),
},
},
{
.callback = mlxplat_dmi_ng400_matched,
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "VMOD0010"),
},
},
{
.callback = mlxplat_dmi_msn274x_matched,
.matches = {
......@@ -2043,7 +2571,7 @@ static int mlxplat_mlxcpld_verify_bus_topology(int *nr)
/* Scan adapters from expected id to verify it is free. */
*nr = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR;
for (i = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR; i <
MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; i++) {
mlxplat_max_adap_num; i++) {
search_adap = i2c_get_adapter(i);
if (search_adap) {
i2c_put_adapter(search_adap);
......@@ -2057,12 +2585,12 @@ static int mlxplat_mlxcpld_verify_bus_topology(int *nr)
}
/* Return with error if free id for adapter is not found. */
if (i == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM)
if (i == mlxplat_max_adap_num)
return -ENODEV;
/* Shift adapter ids, since expected parent adapter is not free. */
*nr = i;
for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
for (i = 0; i < mlxplat_mux_num; i++) {
shift = *nr - mlxplat_mux_data[i].parent;
mlxplat_mux_data[i].parent = *nr;
mlxplat_mux_data[i].base_nr += shift;
......@@ -2118,7 +2646,7 @@ static int __init mlxplat_init(void)
if (nr < 0)
goto fail_alloc;
nr = (nr == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM) ? -1 : nr;
nr = (nr == mlxplat_max_adap_num) ? -1 : nr;
if (mlxplat_i2c)
mlxplat_i2c->regmap = priv->regmap;
priv->pdev_i2c = platform_device_register_resndata(
......@@ -2131,7 +2659,7 @@ static int __init mlxplat_init(void)
goto fail_alloc;
}
for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
for (i = 0; i < mlxplat_mux_num; i++) {
priv->pdev_mux[i] = platform_device_register_resndata(
&priv->pdev_i2c->dev,
"i2c-mux-reg", i, NULL,
......@@ -2265,7 +2793,7 @@ static void __exit mlxplat_exit(void)
platform_device_unregister(priv->pdev_led);
platform_device_unregister(priv->pdev_hotplug);
for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--)
for (i = mlxplat_mux_num - 1; i >= 0 ; i--)
platform_device_unregister(priv->pdev_mux[i]);
platform_device_unregister(priv->pdev_i2c);
......
......@@ -219,8 +219,7 @@ static const struct property_entry digma_citi_e200_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 1980),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1500),
PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
PROPERTY_ENTRY_STRING("firmware-name",
"gsl1686-digma_citi_e200.fw"),
PROPERTY_ENTRY_STRING("firmware-name", "gsl1686-digma_citi_e200.fw"),
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
PROPERTY_ENTRY_BOOL("silead,home-button"),
{ }
......@@ -236,8 +235,7 @@ static const struct property_entry gp_electronic_t701_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-y", 640),
PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"),
PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
PROPERTY_ENTRY_STRING("firmware-name",
"gsl1680-gp-electronic-t701.fw"),
PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-gp-electronic-t701.fw"),
{ }
};
......@@ -382,8 +380,7 @@ static const struct property_entry onda_v80_plus_v3_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 1698),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
PROPERTY_ENTRY_STRING("firmware-name",
"gsl3676-onda-v80-plus-v3.fw"),
PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-onda-v80-plus-v3.fw"),
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
PROPERTY_ENTRY_BOOL("silead,home-button"),
{ }
......@@ -398,8 +395,7 @@ static const struct property_entry onda_v820w_32g_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 1665),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
PROPERTY_ENTRY_STRING("firmware-name",
"gsl1680-onda-v820w-32g.fw"),
PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-onda-v820w-32g.fw"),
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
PROPERTY_ENTRY_BOOL("silead,home-button"),
{ }
......@@ -415,8 +411,7 @@ static const struct property_entry onda_v891w_v1_props[] = {
PROPERTY_ENTRY_U32("touchscreen-min-y", 8),
PROPERTY_ENTRY_U32("touchscreen-size-x", 1676),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1130),
PROPERTY_ENTRY_STRING("firmware-name",
"gsl3680-onda-v891w-v1.fw"),
PROPERTY_ENTRY_STRING("firmware-name", "gsl3680-onda-v891w-v1.fw"),
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
PROPERTY_ENTRY_BOOL("silead,home-button"),
{ }
......@@ -433,8 +428,7 @@ static const struct property_entry onda_v891w_v3_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 1625),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1135),
PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
PROPERTY_ENTRY_STRING("firmware-name",
"gsl3676-onda-v891w-v3.fw"),
PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-onda-v891w-v3.fw"),
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
PROPERTY_ENTRY_BOOL("silead,home-button"),
{ }
......@@ -450,8 +444,7 @@ static const struct property_entry pipo_w2s_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-y", 880),
PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"),
PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
PROPERTY_ENTRY_STRING("firmware-name",
"gsl1680-pipo-w2s.fw"),
PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-pipo-w2s.fw"),
{ }
};
......@@ -460,14 +453,29 @@ static const struct ts_dmi_data pipo_w2s_data = {
.properties = pipo_w2s_props,
};
static const struct property_entry pipo_w11_props[] = {
PROPERTY_ENTRY_U32("touchscreen-min-x", 1),
PROPERTY_ENTRY_U32("touchscreen-min-y", 15),
PROPERTY_ENTRY_U32("touchscreen-size-x", 1984),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1532),
PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-pipo-w11.fw"),
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
PROPERTY_ENTRY_BOOL("silead,home-button"),
{ }
};
static const struct ts_dmi_data pipo_w11_data = {
.acpi_name = "MSSL1680:00",
.properties = pipo_w11_props,
};
static const struct property_entry pov_mobii_wintab_p800w_v20_props[] = {
PROPERTY_ENTRY_U32("touchscreen-min-x", 32),
PROPERTY_ENTRY_U32("touchscreen-min-y", 16),
PROPERTY_ENTRY_U32("touchscreen-size-x", 1692),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1146),
PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
PROPERTY_ENTRY_STRING("firmware-name",
"gsl3680-pov-mobii-wintab-p800w-v20.fw"),
PROPERTY_ENTRY_STRING("firmware-name", "gsl3680-pov-mobii-wintab-p800w-v20.fw"),
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
PROPERTY_ENTRY_BOOL("silead,home-button"),
{ }
......@@ -484,8 +492,7 @@ static const struct property_entry pov_mobii_wintab_p800w_v21_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 1794),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1148),
PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
PROPERTY_ENTRY_STRING("firmware-name",
"gsl3692-pov-mobii-wintab-p800w.fw"),
PROPERTY_ENTRY_STRING("firmware-name", "gsl3692-pov-mobii-wintab-p800w.fw"),
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
PROPERTY_ENTRY_BOOL("silead,home-button"),
{ }
......@@ -502,8 +509,7 @@ static const struct property_entry pov_mobii_wintab_p1006w_v10_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 1984),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1520),
PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
PROPERTY_ENTRY_STRING("firmware-name",
"gsl3692-pov-mobii-wintab-p1006w-v10.fw"),
PROPERTY_ENTRY_STRING("firmware-name", "gsl3692-pov-mobii-wintab-p1006w-v10.fw"),
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
PROPERTY_ENTRY_BOOL("silead,home-button"),
{ }
......@@ -520,8 +526,7 @@ static const struct property_entry schneider_sct101ctm_props[] = {
PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"),
PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
PROPERTY_ENTRY_STRING("firmware-name",
"gsl1680-schneider-sct101ctm.fw"),
PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-schneider-sct101ctm.fw"),
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
PROPERTY_ENTRY_BOOL("silead,home-button"),
{ }
......@@ -551,8 +556,7 @@ static const struct property_entry teclast_x98plus2_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-y", 1280),
PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"),
PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
PROPERTY_ENTRY_STRING("firmware-name",
"gsl1686-teclast_x98plus2.fw"),
PROPERTY_ENTRY_STRING("firmware-name", "gsl1686-teclast_x98plus2.fw"),
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
{ }
};
......@@ -566,8 +570,7 @@ static const struct property_entry trekstor_primebook_c11_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 1970),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1530),
PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
PROPERTY_ENTRY_STRING("firmware-name",
"gsl1680-trekstor-primebook-c11.fw"),
PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-trekstor-primebook-c11.fw"),
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
PROPERTY_ENTRY_BOOL("silead,home-button"),
{ }
......@@ -581,8 +584,7 @@ static const struct ts_dmi_data trekstor_primebook_c11_data = {
static const struct property_entry trekstor_primebook_c13_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 2624),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1920),
PROPERTY_ENTRY_STRING("firmware-name",
"gsl1680-trekstor-primebook-c13.fw"),
PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-trekstor-primebook-c13.fw"),
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
PROPERTY_ENTRY_BOOL("silead,home-button"),
{ }
......@@ -596,8 +598,7 @@ static const struct ts_dmi_data trekstor_primebook_c13_data = {
static const struct property_entry trekstor_primetab_t13b_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 2500),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1900),
PROPERTY_ENTRY_STRING("firmware-name",
"gsl1680-trekstor-primetab-t13b.fw"),
PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-trekstor-primetab-t13b.fw"),
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
PROPERTY_ENTRY_BOOL("silead,home-button"),
PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
......@@ -613,8 +614,7 @@ static const struct property_entry trekstor_surftab_twin_10_1_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 1900),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1280),
PROPERTY_ENTRY_U32("touchscreen-inverted-y", 1),
PROPERTY_ENTRY_STRING("firmware-name",
"gsl3670-surftab-twin-10-1-st10432-8.fw"),
PROPERTY_ENTRY_STRING("firmware-name", "gsl3670-surftab-twin-10-1-st10432-8.fw"),
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
{ }
};
......@@ -629,8 +629,7 @@ static const struct property_entry trekstor_surftab_wintron70_props[] = {
PROPERTY_ENTRY_U32("touchscreen-min-y", 8),
PROPERTY_ENTRY_U32("touchscreen-size-x", 884),
PROPERTY_ENTRY_U32("touchscreen-size-y", 632),
PROPERTY_ENTRY_STRING("firmware-name",
"gsl1686-surftab-wintron70-st70416-6.fw"),
PROPERTY_ENTRY_STRING("firmware-name", "gsl1686-surftab-wintron70-st70416-6.fw"),
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
PROPERTY_ENTRY_BOOL("silead,home-button"),
{ }
......@@ -909,6 +908,16 @@ static const struct dmi_system_id touchscreen_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "W2S"),
},
},
{
/* Pipo W11 */
.driver_data = (void *)&pipo_w11_data,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "PIPO"),
DMI_MATCH(DMI_PRODUCT_NAME, "To be filled by O.E.M."),
/* Above matches are too generic, add bios-ver match */
DMI_MATCH(DMI_BIOS_VERSION, "JS-BI-10.6-SF133GR300-GA55B-024-F"),
},
},
{
/* Ployer Momo7w (same hardware as the Trekstor ST70416-6) */
.driver_data = (void *)&trekstor_surftab_wintron70_data,
......@@ -1032,8 +1041,7 @@ static const struct dmi_system_id touchscreen_dmi_table[] = {
.driver_data = (void *)&trekstor_surftab_wintron70_data,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TrekStor"),
DMI_MATCH(DMI_PRODUCT_NAME,
"SurfTab wintron 7.0 ST70416-6"),
DMI_MATCH(DMI_PRODUCT_NAME, "SurfTab wintron 7.0 ST70416-6"),
/* Exact match, different versions need different fw */
DMI_MATCH(DMI_BIOS_VERSION, "TREK.G.WI71C.JGBMRBA05"),
},
......@@ -1065,7 +1073,7 @@ static void ts_dmi_add_props(struct i2c_client *client)
}
static int ts_dmi_notifier_call(struct notifier_block *nb,
unsigned long action, void *data)
unsigned long action, void *data)
{
struct device *dev = data;
struct i2c_client *client;
......
......@@ -101,6 +101,7 @@ struct mlxreg_core_data {
* @aggr_mask: group aggregation mask;
* @reg: group interrupt status register;
* @mask: group interrupt mask;
* @capability: group capability register;
* @cache: last status value for elements fro the same group;
* @count: number of available elements in the group;
* @ind: element's index inside the group;
......@@ -112,6 +113,7 @@ struct mlxreg_core_item {
u32 aggr_mask;
u32 reg;
u32 mask;
u32 capability;
u32 cache;
u8 count;
u8 ind;
......
......@@ -58,6 +58,7 @@
#define ASUS_WMI_DEVID_LIGHT_SENSOR 0x00050022 /* ?? */
#define ASUS_WMI_DEVID_LIGHTBAR 0x00050025
#define ASUS_WMI_DEVID_FAN_BOOST_MODE 0x00110018
#define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY 0x00120075
/* Misc */
#define ASUS_WMI_DEVID_CAMERA 0x00060013
......
......@@ -15,7 +15,7 @@ struct process_cmd_struct {
int arg;
};
static const char *version_str = "v1.1";
static const char *version_str = "v1.2";
static const int supported_api_ver = 1;
static struct isst_if_platform_info isst_platform_info;
static char *progname;
......@@ -1384,14 +1384,10 @@ static void set_pbf_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
goto disp_result;
}
if (auto_mode) {
if (status) {
ret = set_pbf_core_power(cpu);
if (ret)
goto disp_result;
} else {
isst_pm_qos_config(cpu, 0, 0);
}
if (auto_mode && status) {
ret = set_pbf_core_power(cpu);
if (ret)
goto disp_result;
}
ret = isst_set_pbf_fact_status(cpu, 1, status);
......@@ -1408,6 +1404,9 @@ static void set_pbf_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
}
}
if (auto_mode && !status)
isst_pm_qos_config(cpu, 0, 0);
disp_result:
if (status)
isst_display_result(cpu, outf, "base-freq", "enable",
......@@ -1496,14 +1495,10 @@ static void set_fact_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
int ret;
int status = *(int *)arg4;
if (auto_mode) {
if (status) {
ret = isst_pm_qos_config(cpu, 1, 1);
if (ret)
goto disp_results;
} else {
isst_pm_qos_config(cpu, 0, 0);
}
if (auto_mode && status) {
ret = isst_pm_qos_config(cpu, 1, 1);
if (ret)
goto disp_results;
}
ret = isst_set_pbf_fact_status(cpu, 0, status);
......@@ -1524,6 +1519,9 @@ static void set_fact_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
ret = isst_set_trl(cpu, fact_trl);
if (ret && auto_mode)
isst_pm_qos_config(cpu, 0, 0);
} else {
if (auto_mode)
isst_pm_qos_config(cpu, 0, 0);
}
disp_results:
......@@ -1638,7 +1636,7 @@ static void set_fact_enable(int arg)
if (ret)
goto error_disp;
}
isst_display_result(i, outf, "turbo-freq --auto", "enable", 0);
isst_display_result(-1, outf, "turbo-freq --auto", "enable", 0);
}
return;
......
......@@ -6,6 +6,44 @@
#include "isst.h"
int isst_write_pm_config(int cpu, int cp_state)
{
unsigned int req, resp;
int ret;
if (cp_state)
req = BIT(16);
else
req = 0;
ret = isst_send_mbox_command(cpu, WRITE_PM_CONFIG, PM_FEATURE, 0, req,
&resp);
if (ret)
return ret;
debug_printf("cpu:%d WRITE_PM_CONFIG resp:%x\n", cpu, resp);
return 0;
}
int isst_read_pm_config(int cpu, int *cp_state, int *cp_cap)
{
unsigned int resp;
int ret;
ret = isst_send_mbox_command(cpu, READ_PM_CONFIG, PM_FEATURE, 0, 0,
&resp);
if (ret)
return ret;
debug_printf("cpu:%d READ_PM_CONFIG resp:%x\n", cpu, resp);
*cp_state = resp & BIT(16);
*cp_cap = resp & BIT(0) ? 1 : 0;
return 0;
}
int isst_get_ctdp_levels(int cpu, struct isst_pkg_ctdp *pkg_dev)
{
unsigned int resp;
......@@ -36,6 +74,7 @@ int isst_get_ctdp_levels(int cpu, struct isst_pkg_ctdp *pkg_dev)
int isst_get_ctdp_control(int cpu, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level)
{
int cp_state, cp_cap;
unsigned int resp;
int ret;
......@@ -50,6 +89,15 @@ int isst_get_ctdp_control(int cpu, int config_index,
ctdp_level->fact_enabled = !!(resp & BIT(16));
ctdp_level->pbf_enabled = !!(resp & BIT(17));
ret = isst_read_pm_config(cpu, &cp_state, &cp_cap);
if (ret) {
debug_printf("cpu:%d pm_config is not supported \n", cpu);
} else {
debug_printf("cpu:%d pm_config SST-CP state:%d cap:%d \n", cpu, cp_state, cp_cap);
ctdp_level->sst_cp_support = cp_cap;
ctdp_level->sst_cp_enabled = cp_state;
}
debug_printf(
"cpu:%d CONFIG_TDP_GET_TDP_CONTROL resp:%x fact_support:%d pbf_support: %d fact_enabled:%d pbf_enabled:%d\n",
cpu, resp, ctdp_level->fact_support, ctdp_level->pbf_support,
......@@ -779,6 +827,13 @@ int isst_pm_qos_config(int cpu, int enable_clos, int priority_type)
debug_printf("Turbo-freq feature must be disabled first\n");
return -EINVAL;
}
ret = isst_write_pm_config(cpu, 0);
if (ret)
perror("isst_write_pm_config\n");
} else {
ret = isst_write_pm_config(cpu, 1);
if (ret)
perror("isst_write_pm_config\n");
}
ret = isst_send_mbox_command(cpu, CONFIG_CLOS, CLOS_PM_QOS_CONFIG, 0, 0,
......
......@@ -418,6 +418,17 @@ void isst_ctdp_display_information(int cpu, FILE *outf, int tdp_level,
snprintf(value, sizeof(value), "unsupported");
format_and_print(outf, base_level + 4, header, value);
snprintf(header, sizeof(header),
"speed-select-core-power");
if (ctdp_level->sst_cp_support) {
if (ctdp_level->sst_cp_enabled)
snprintf(value, sizeof(value), "enabled");
else
snprintf(value, sizeof(value), "disabled");
} else
snprintf(value, sizeof(value), "unsupported");
format_and_print(outf, base_level + 4, header, value);
if (is_clx_n_platform()) {
if (ctdp_level->pbf_support)
_isst_pbf_display_information(cpu, outf,
......@@ -634,13 +645,15 @@ void isst_display_result(int cpu, FILE *outf, char *feature, char *cmd,
char header[256];
char value[256];
snprintf(header, sizeof(header), "package-%d",
get_physical_package_id(cpu));
format_and_print(outf, 1, header, NULL);
snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu));
format_and_print(outf, 2, header, NULL);
snprintf(header, sizeof(header), "cpu-%d", cpu);
format_and_print(outf, 3, header, NULL);
if (cpu >= 0) {
snprintf(header, sizeof(header), "package-%d",
get_physical_package_id(cpu));
format_and_print(outf, 1, header, NULL);
snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu));
format_and_print(outf, 2, header, NULL);
snprintf(header, sizeof(header), "cpu-%d", cpu);
format_and_print(outf, 3, header, NULL);
}
snprintf(header, sizeof(header), "%s", feature);
format_and_print(outf, 4, header, NULL);
snprintf(header, sizeof(header), "%s", cmd);
......
......@@ -69,6 +69,10 @@
#define PM_CLOS_OFFSET 0x08
#define PQR_ASSOC_OFFSET 0x20
#define READ_PM_CONFIG 0x94
#define WRITE_PM_CONFIG 0x95
#define PM_FEATURE 0x03
#define DISP_FREQ_MULTIPLIER 100
struct isst_clos_config {
......@@ -119,6 +123,8 @@ struct isst_pkg_ctdp_level_info {
int pbf_support;
int fact_enabled;
int pbf_enabled;
int sst_cp_support;
int sst_cp_enabled;
int tdp_ratio;
int active;
int tdp_control;
......
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