diff options
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/bus.c | 3 | ||||
-rw-r--r-- | drivers/acpi/nfit/core.c | 66 | ||||
-rw-r--r-- | drivers/acpi/pmic/intel_pmic.c | 61 | ||||
-rw-r--r-- | drivers/acpi/pmic/intel_pmic.h | 4 | ||||
-rw-r--r-- | drivers/acpi/pmic/intel_pmic_chtwc.c | 19 | ||||
-rw-r--r-- | drivers/acpi/pmic/intel_pmic_xpower.c | 1 |
6 files changed, 135 insertions, 19 deletions
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 5c093ce01bcd..147f6c7ea59c 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -1029,6 +1029,9 @@ void __init acpi_early_init(void) acpi_permanent_mmap = true; + /* Initialize debug output. Linux does not use ACPICA defaults */ + acpi_dbg_level = ACPI_LV_INFO | ACPI_LV_REPAIR; + #ifdef CONFIG_X86 /* * If the machine falls into the DMI check table, diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 5143e11e3b0f..e18ade5d74e9 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -409,6 +409,32 @@ static bool payload_dumpable(struct nvdimm *nvdimm, unsigned int func) return true; } +static int cmd_to_func(struct nfit_mem *nfit_mem, unsigned int cmd, + struct nd_cmd_pkg *call_pkg) +{ + if (call_pkg) { + int i; + + if (nfit_mem->family != call_pkg->nd_family) + return -ENOTTY; + + for (i = 0; i < ARRAY_SIZE(call_pkg->nd_reserved2); i++) + if (call_pkg->nd_reserved2[i]) + return -EINVAL; + return call_pkg->nd_command; + } + + /* Linux ND commands == NVDIMM_FAMILY_INTEL function numbers */ + if (nfit_mem->family == NVDIMM_FAMILY_INTEL) + return cmd; + + /* + * Force function number validation to fail since 0 is never + * published as a valid function in dsm_mask. + */ + return 0; +} + int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, unsigned int cmd, void *buf, unsigned int buf_len, int *cmd_rc) { @@ -422,30 +448,23 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, unsigned long cmd_mask, dsm_mask; u32 offset, fw_status = 0; acpi_handle handle; - unsigned int func; const guid_t *guid; - int rc, i; + int func, rc, i; if (cmd_rc) *cmd_rc = -EINVAL; - func = cmd; - if (cmd == ND_CMD_CALL) { - call_pkg = buf; - func = call_pkg->nd_command; - - for (i = 0; i < ARRAY_SIZE(call_pkg->nd_reserved2); i++) - if (call_pkg->nd_reserved2[i]) - return -EINVAL; - } if (nvdimm) { struct acpi_device *adev = nfit_mem->adev; if (!adev) return -ENOTTY; - if (call_pkg && nfit_mem->family != call_pkg->nd_family) - return -ENOTTY; + if (cmd == ND_CMD_CALL) + call_pkg = buf; + func = cmd_to_func(nfit_mem, cmd, call_pkg); + if (func < 0) + return func; dimm_name = nvdimm_name(nvdimm); cmd_name = nvdimm_cmd_name(cmd); cmd_mask = nvdimm_cmd_mask(nvdimm); @@ -456,6 +475,7 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, } else { struct acpi_device *adev = to_acpi_dev(acpi_desc); + func = cmd; cmd_name = nvdimm_bus_cmd_name(cmd); cmd_mask = nd_desc->cmd_mask; dsm_mask = cmd_mask; @@ -470,7 +490,13 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, if (!desc || (cmd && (desc->out_num + desc->in_num == 0))) return -ENOTTY; - if (!test_bit(cmd, &cmd_mask) || !test_bit(func, &dsm_mask)) + /* + * Check for a valid command. For ND_CMD_CALL, we also have to + * make sure that the DSM function is supported. + */ + if (cmd == ND_CMD_CALL && !test_bit(func, &dsm_mask)) + return -ENOTTY; + else if (!test_bit(cmd, &cmd_mask)) return -ENOTTY; in_obj.type = ACPI_TYPE_PACKAGE; @@ -1867,6 +1893,13 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, return 0; } + /* + * Function 0 is the command interrogation function, don't + * export it to potential userspace use, and enable it to be + * used as an error value in acpi_nfit_ctl(). + */ + dsm_mask &= ~1UL; + guid = to_nfit_uuid(nfit_mem->family); for_each_set_bit(i, &dsm_mask, BITS_PER_LONG) if (acpi_check_dsm(adev_dimm->handle, guid, @@ -2042,11 +2075,6 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc) if (!nvdimm) continue; - rc = nvdimm_security_setup_events(nvdimm); - if (rc < 0) - dev_warn(acpi_desc->dev, - "security event setup failed: %d\n", rc); - nfit_kernfs = sysfs_get_dirent(nvdimm_kobj(nvdimm)->sd, "nfit"); if (nfit_kernfs) nfit_mem->flags_attr = sysfs_get_dirent(nfit_kernfs, diff --git a/drivers/acpi/pmic/intel_pmic.c b/drivers/acpi/pmic/intel_pmic.c index ca18e0d23df9..c14cfaea92e2 100644 --- a/drivers/acpi/pmic/intel_pmic.c +++ b/drivers/acpi/pmic/intel_pmic.c @@ -15,6 +15,7 @@ #include <linux/export.h> #include <linux/acpi.h> +#include <linux/mfd/intel_soc_pmic.h> #include <linux/regmap.h> #include <acpi/acpi_lpat.h> #include "intel_pmic.h" @@ -36,6 +37,8 @@ struct intel_pmic_opregion { struct intel_pmic_regs_handler_ctx ctx; }; +static struct intel_pmic_opregion *intel_pmic_opregion; + static int pmic_get_reg_bit(int address, struct pmic_table *table, int count, int *reg, int *bit) { @@ -304,6 +307,7 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle, } opregion->data = d; + intel_pmic_opregion = opregion; return 0; out_remove_thermal_handler: @@ -319,3 +323,60 @@ out_error: return ret; } EXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler); + +/** + * intel_soc_pmic_exec_mipi_pmic_seq_element - Execute PMIC MIPI sequence + * @i2c_address: I2C client address for the PMIC + * @reg_address: PMIC register address + * @value: New value for the register bits to change + * @mask: Mask indicating which register bits to change + * + * DSI LCD panels describe an initialization sequence in the i915 VBT (Video + * BIOS Tables) using so called MIPI sequences. One possible element in these + * sequences is a PMIC specific element of 15 bytes. + * + * This function executes these PMIC specific elements sending the embedded + * commands to the PMIC. + * + * Return 0 on success, < 0 on failure. + */ +int intel_soc_pmic_exec_mipi_pmic_seq_element(u16 i2c_address, u32 reg_address, + u32 value, u32 mask) +{ + struct intel_pmic_opregion_data *d; + int ret; + + if (!intel_pmic_opregion) { + pr_warn("%s: No PMIC registered\n", __func__); + return -ENXIO; + } + + d = intel_pmic_opregion->data; + + mutex_lock(&intel_pmic_opregion->lock); + + if (d->exec_mipi_pmic_seq_element) { + ret = d->exec_mipi_pmic_seq_element(intel_pmic_opregion->regmap, + i2c_address, reg_address, + value, mask); + } else if (d->pmic_i2c_address) { + if (i2c_address == d->pmic_i2c_address) { + ret = regmap_update_bits(intel_pmic_opregion->regmap, + reg_address, mask, value); + } else { + pr_err("%s: Unexpected i2c-addr: 0x%02x (reg-addr 0x%x value 0x%x mask 0x%x)\n", + __func__, i2c_address, reg_address, value, mask); + ret = -ENXIO; + } + } else { + pr_warn("%s: Not implemented\n", __func__); + pr_warn("%s: i2c-addr: 0x%x reg-addr 0x%x value 0x%x mask 0x%x\n", + __func__, i2c_address, reg_address, value, mask); + ret = -EOPNOTSUPP; + } + + mutex_unlock(&intel_pmic_opregion->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(intel_soc_pmic_exec_mipi_pmic_seq_element); diff --git a/drivers/acpi/pmic/intel_pmic.h b/drivers/acpi/pmic/intel_pmic.h index 095afc96952e..89379476a1df 100644 --- a/drivers/acpi/pmic/intel_pmic.h +++ b/drivers/acpi/pmic/intel_pmic.h @@ -15,10 +15,14 @@ struct intel_pmic_opregion_data { int (*update_aux)(struct regmap *r, int reg, int raw_temp); int (*get_policy)(struct regmap *r, int reg, int bit, u64 *value); int (*update_policy)(struct regmap *r, int reg, int bit, int enable); + int (*exec_mipi_pmic_seq_element)(struct regmap *r, u16 i2c_address, + u32 reg_address, u32 value, u32 mask); struct pmic_table *power_table; int power_table_count; struct pmic_table *thermal_table; int thermal_table_count; + /* For generic exec_mipi_pmic_seq_element handling */ + int pmic_i2c_address; }; int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle, struct regmap *regmap, struct intel_pmic_opregion_data *d); diff --git a/drivers/acpi/pmic/intel_pmic_chtwc.c b/drivers/acpi/pmic/intel_pmic_chtwc.c index 078b0448f30a..7ffd5624b8e1 100644 --- a/drivers/acpi/pmic/intel_pmic_chtwc.c +++ b/drivers/acpi/pmic/intel_pmic_chtwc.c @@ -231,6 +231,24 @@ static int intel_cht_wc_pmic_update_power(struct regmap *regmap, int reg, return regmap_update_bits(regmap, reg, bitmask, on ? 1 : 0); } +static int intel_cht_wc_exec_mipi_pmic_seq_element(struct regmap *regmap, + u16 i2c_client_address, + u32 reg_address, + u32 value, u32 mask) +{ + u32 address; + + if (i2c_client_address > 0xff || reg_address > 0xff) { + pr_warn("%s warning addresses too big client 0x%x reg 0x%x\n", + __func__, i2c_client_address, reg_address); + return -ERANGE; + } + + address = (i2c_client_address << 8) | reg_address; + + return regmap_update_bits(regmap, address, mask, value); +} + /* * The thermal table and ops are empty, we do not support the Thermal opregion * (DPTF) due to lacking documentation. @@ -238,6 +256,7 @@ static int intel_cht_wc_pmic_update_power(struct regmap *regmap, int reg, static struct intel_pmic_opregion_data intel_cht_wc_pmic_opregion_data = { .get_power = intel_cht_wc_pmic_get_power, .update_power = intel_cht_wc_pmic_update_power, + .exec_mipi_pmic_seq_element = intel_cht_wc_exec_mipi_pmic_seq_element, .power_table = power_table, .power_table_count = ARRAY_SIZE(power_table), }; diff --git a/drivers/acpi/pmic/intel_pmic_xpower.c b/drivers/acpi/pmic/intel_pmic_xpower.c index e7c0006e6602..a091d5a8392c 100644 --- a/drivers/acpi/pmic/intel_pmic_xpower.c +++ b/drivers/acpi/pmic/intel_pmic_xpower.c @@ -265,6 +265,7 @@ static struct intel_pmic_opregion_data intel_xpower_pmic_opregion_data = { .power_table_count = ARRAY_SIZE(power_table), .thermal_table = thermal_table, .thermal_table_count = ARRAY_SIZE(thermal_table), + .pmic_i2c_address = 0x34, }; static acpi_status intel_xpower_pmic_gpio_handler(u32 function, |