diff options
Diffstat (limited to 'drivers/soc')
-rw-r--r-- | drivers/soc/qcom/Kconfig | 11 | ||||
-rw-r--r-- | drivers/soc/qcom/Makefile | 1 | ||||
-rw-r--r-- | drivers/soc/qcom/mdt_loader.c | 41 | ||||
-rw-r--r-- | drivers/soc/qcom/ocmem.c | 10 | ||||
-rw-r--r-- | drivers/soc/qcom/pmic_glink.c | 8 | ||||
-rw-r--r-- | drivers/soc/qcom/qmi_interface.c | 2 | ||||
-rw-r--r-- | drivers/soc/qcom/ramp_controller.c | 11 | ||||
-rw-r--r-- | drivers/soc/qcom/rpm_master_stats.c | 163 | ||||
-rw-r--r-- | drivers/soc/qcom/rpmpd.c | 4 | ||||
-rw-r--r-- | drivers/soc/qcom/smem.c | 31 | ||||
-rw-r--r-- | drivers/soc/qcom/socinfo.c | 77 | ||||
-rw-r--r-- | drivers/soc/renesas/rcar-rst.c | 15 | ||||
-rw-r--r-- | drivers/soc/renesas/rmobile-sysc.c | 29 | ||||
-rw-r--r-- | drivers/soc/samsung/exynos-pmu.c | 9 | ||||
-rw-r--r-- | drivers/soc/samsung/exynos-pmu.h | 2 | ||||
-rw-r--r-- | drivers/soc/samsung/exynos4-pmu.c | 13 | ||||
-rw-r--r-- | drivers/soc/tegra/fuse/fuse-tegra30.c | 2 | ||||
-rw-r--r-- | drivers/soc/tegra/fuse/tegra-apbmisc.c | 3 | ||||
-rw-r--r-- | drivers/soc/tegra/pmc.c | 31 | ||||
-rw-r--r-- | drivers/soc/xilinx/xlnx_event_manager.c | 6 | ||||
-rw-r--r-- | drivers/soc/xilinx/zynqmp_power.c | 4 |
21 files changed, 334 insertions, 139 deletions
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index a491718f8064..e597799e8121 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -135,6 +135,17 @@ config QCOM_RMTFS_MEM Say y here if you intend to boot the modem remoteproc. +config QCOM_RPM_MASTER_STATS + tristate "Qualcomm RPM Master stats" + depends on ARCH_QCOM || COMPILE_TEST + help + The RPM Master sleep stats driver provides detailed per-subsystem + sleep/wake data, read from the RPM message RAM. It can be used to + assess whether all the low-power modes available are entered as + expected or to check which part of the SoC prevents it from sleeping. + + Say y here if you intend to debug or monitor platform sleep. + config QCOM_RPMH tristate "Qualcomm RPM-Hardened (RPMH) Communication" depends on ARCH_QCOM || COMPILE_TEST diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 0f43a88b4894..7349371fdea1 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o qmi_helpers-y += qmi_encdec.o qmi_interface.o obj-$(CONFIG_QCOM_RAMP_CTRL) += ramp_controller.o obj-$(CONFIG_QCOM_RMTFS_MEM) += rmtfs_mem.o +obj-$(CONFIG_QCOM_RPM_MASTER_STATS) += rpm_master_stats.o obj-$(CONFIG_QCOM_RPMH) += qcom_rpmh.o qcom_rpmh-y += rpmh-rsc.o qcom_rpmh-y += rpmh.o diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index 33dd8c315eb7..9418993a3a92 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -210,6 +210,7 @@ int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, const struct elf32_hdr *ehdr; phys_addr_t min_addr = PHYS_ADDR_MAX; phys_addr_t max_addr = 0; + bool relocate = false; size_t metadata_len; void *metadata; int ret; @@ -224,6 +225,9 @@ int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, if (!mdt_phdr_valid(phdr)) continue; + if (phdr->p_flags & QCOM_MDT_RELOCATABLE) + relocate = true; + if (phdr->p_paddr < min_addr) min_addr = phdr->p_paddr; @@ -246,11 +250,13 @@ int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, goto out; } - ret = qcom_scm_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr); - if (ret) { - /* Unable to set up relocation */ - dev_err(dev, "error %d setting up firmware %s\n", ret, fw_name); - goto out; + if (relocate) { + ret = qcom_scm_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr); + if (ret) { + /* Unable to set up relocation */ + dev_err(dev, "error %d setting up firmware %s\n", ret, fw_name); + goto out; + } } out: @@ -258,6 +264,26 @@ out: } EXPORT_SYMBOL_GPL(qcom_mdt_pas_init); +static bool qcom_mdt_bins_are_split(const struct firmware *fw, const char *fw_name) +{ + const struct elf32_phdr *phdrs; + const struct elf32_hdr *ehdr; + uint64_t seg_start, seg_end; + int i; + + ehdr = (struct elf32_hdr *)fw->data; + phdrs = (struct elf32_phdr *)(ehdr + 1); + + for (i = 0; i < ehdr->e_phnum; i++) { + seg_start = phdrs[i].p_offset; + seg_end = phdrs[i].p_offset + phdrs[i].p_filesz; + if (seg_start > fw->size || seg_end > fw->size) + return true; + } + + return false; +} + static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, void *mem_region, phys_addr_t mem_phys, size_t mem_size, @@ -270,6 +296,7 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, phys_addr_t min_addr = PHYS_ADDR_MAX; ssize_t offset; bool relocate = false; + bool is_split; void *ptr; int ret = 0; int i; @@ -277,6 +304,7 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, if (!fw || !mem_region || !mem_phys || !mem_size) return -EINVAL; + is_split = qcom_mdt_bins_are_split(fw, fw_name); ehdr = (struct elf32_hdr *)fw->data; phdrs = (struct elf32_phdr *)(ehdr + 1); @@ -330,8 +358,7 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, ptr = mem_region + offset; - if (phdr->p_filesz && phdr->p_offset < fw->size && - phdr->p_offset + phdr->p_filesz <= fw->size) { + if (phdr->p_filesz && !is_split) { /* Firmware is large enough to be non-split */ if (phdr->p_offset + phdr->p_filesz > fw->size) { dev_err(dev, "file %s segment %d would be truncated\n", diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c index 199fe9872035..aaddc3cc53b7 100644 --- a/drivers/soc/qcom/ocmem.c +++ b/drivers/soc/qcom/ocmem.c @@ -76,6 +76,10 @@ struct ocmem { #define OCMEM_REG_GFX_MPU_START 0x00001004 #define OCMEM_REG_GFX_MPU_END 0x00001008 +#define OCMEM_HW_VERSION_MAJOR(val) FIELD_GET(GENMASK(31, 28), val) +#define OCMEM_HW_VERSION_MINOR(val) FIELD_GET(GENMASK(27, 16), val) +#define OCMEM_HW_VERSION_STEP(val) FIELD_GET(GENMASK(15, 0), val) + #define OCMEM_HW_PROFILE_NUM_PORTS(val) FIELD_PREP(0x0000000f, (val)) #define OCMEM_HW_PROFILE_NUM_MACROS(val) FIELD_PREP(0x00003f00, (val)) @@ -355,6 +359,12 @@ static int ocmem_dev_probe(struct platform_device *pdev) } } + reg = ocmem_read(ocmem, OCMEM_REG_HW_VERSION); + dev_dbg(dev, "OCMEM hardware version: %lu.%lu.%lu\n", + OCMEM_HW_VERSION_MAJOR(reg), + OCMEM_HW_VERSION_MINOR(reg), + OCMEM_HW_VERSION_STEP(reg)); + reg = ocmem_read(ocmem, OCMEM_REG_HW_PROFILE); ocmem->num_ports = OCMEM_HW_PROFILE_NUM_PORTS(reg); ocmem->num_macros = OCMEM_HW_PROFILE_NUM_MACROS(reg); diff --git a/drivers/soc/qcom/pmic_glink.c b/drivers/soc/qcom/pmic_glink.c index 8bf95df0a56a..c87056769ebd 100644 --- a/drivers/soc/qcom/pmic_glink.c +++ b/drivers/soc/qcom/pmic_glink.c @@ -338,13 +338,17 @@ static int pmic_glink_remove(struct platform_device *pdev) return 0; } -/* Do not handle altmode for now on those platforms */ static const unsigned long pmic_glink_sm8450_client_mask = BIT(PMIC_GLINK_CLIENT_BATT) | + BIT(PMIC_GLINK_CLIENT_ALTMODE) | + BIT(PMIC_GLINK_CLIENT_UCSI); + +/* Do not handle altmode for now on those platforms */ +static const unsigned long pmic_glink_sm8550_client_mask = BIT(PMIC_GLINK_CLIENT_BATT) | BIT(PMIC_GLINK_CLIENT_UCSI); static const struct of_device_id pmic_glink_of_match[] = { { .compatible = "qcom,sm8450-pmic-glink", .data = &pmic_glink_sm8450_client_mask }, - { .compatible = "qcom,sm8550-pmic-glink", .data = &pmic_glink_sm8450_client_mask }, + { .compatible = "qcom,sm8550-pmic-glink", .data = &pmic_glink_sm8550_client_mask }, { .compatible = "qcom,pmic-glink" }, {} }; diff --git a/drivers/soc/qcom/qmi_interface.c b/drivers/soc/qcom/qmi_interface.c index 820bdd9f8e46..78d7361fdcf2 100644 --- a/drivers/soc/qcom/qmi_interface.c +++ b/drivers/soc/qcom/qmi_interface.c @@ -650,7 +650,7 @@ int qmi_handle_init(struct qmi_handle *qmi, size_t recv_buf_size, if (!qmi->recv_buf) return -ENOMEM; - qmi->wq = alloc_workqueue("qmi_msg_handler", WQ_UNBOUND, 1); + qmi->wq = alloc_ordered_workqueue("qmi_msg_handler", 0); if (!qmi->wq) { ret = -ENOMEM; goto err_free_recv_buf; diff --git a/drivers/soc/qcom/ramp_controller.c b/drivers/soc/qcom/ramp_controller.c index dc74d2a19de2..1ff13661bcce 100644 --- a/drivers/soc/qcom/ramp_controller.c +++ b/drivers/soc/qcom/ramp_controller.c @@ -308,12 +308,15 @@ static int qcom_ramp_controller_probe(struct platform_device *pdev) return qcom_ramp_controller_start(qrc); } -static int qcom_ramp_controller_remove(struct platform_device *pdev) +static void qcom_ramp_controller_remove(struct platform_device *pdev) { struct qcom_ramp_controller *qrc = platform_get_drvdata(pdev); + int ret; - return rc_write_cfg(qrc, qrc->desc->cfg_ramp_dis, - RC_DCVS_CFG_SID, qrc->desc->num_ramp_dis); + ret = rc_write_cfg(qrc, qrc->desc->cfg_ramp_dis, + RC_DCVS_CFG_SID, qrc->desc->num_ramp_dis); + if (ret) + dev_err(&pdev->dev, "Failed to send disable sequence\n"); } static const struct of_device_id qcom_ramp_controller_match_table[] = { @@ -329,7 +332,7 @@ static struct platform_driver qcom_ramp_controller_driver = { .suppress_bind_attrs = true, }, .probe = qcom_ramp_controller_probe, - .remove = qcom_ramp_controller_remove, + .remove_new = qcom_ramp_controller_remove, }; static int __init qcom_ramp_controller_init(void) diff --git a/drivers/soc/qcom/rpm_master_stats.c b/drivers/soc/qcom/rpm_master_stats.c new file mode 100644 index 000000000000..6dd98b9f7129 --- /dev/null +++ b/drivers/soc/qcom/rpm_master_stats.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Linaro Limited + * + * This driver supports what is known as "Master Stats v2" in Qualcomm + * downstream kernel terms, which seems to be the only version which has + * ever shipped, all the way from 2013 to 2023. + */ + +#include <linux/debugfs.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> + +struct master_stats_data { + void __iomem *base; + const char *label; +}; + +struct rpm_master_stats { + u32 active_cores; + u32 num_shutdowns; + u64 shutdown_req; + u64 wakeup_idx; + u64 bringup_req; + u64 bringup_ack; + u32 wakeup_reason; /* 0 = "rude wakeup", 1 = scheduled wakeup */ + u32 last_sleep_trans_dur; + u32 last_wake_trans_dur; + + /* Per-subsystem (*not necessarily* SoC-wide) XO shutdown stats */ + u32 xo_count; + u64 xo_last_enter; + u64 last_exit; + u64 xo_total_dur; +} __packed; + +static int master_stats_show(struct seq_file *s, void *unused) +{ + struct master_stats_data *data = s->private; + struct rpm_master_stats stat; + + memcpy_fromio(&stat, data->base, sizeof(stat)); + + seq_printf(s, "%s:\n", data->label); + + seq_printf(s, "\tLast shutdown @ %llu\n", stat.shutdown_req); + seq_printf(s, "\tLast bringup req @ %llu\n", stat.bringup_req); + seq_printf(s, "\tLast bringup ack @ %llu\n", stat.bringup_ack); + seq_printf(s, "\tLast wakeup idx: %llu\n", stat.wakeup_idx); + seq_printf(s, "\tLast XO shutdown enter @ %llu\n", stat.xo_last_enter); + seq_printf(s, "\tLast XO shutdown exit @ %llu\n", stat.last_exit); + seq_printf(s, "\tXO total duration: %llu\n", stat.xo_total_dur); + seq_printf(s, "\tLast sleep transition duration: %u\n", stat.last_sleep_trans_dur); + seq_printf(s, "\tLast wake transition duration: %u\n", stat.last_wake_trans_dur); + seq_printf(s, "\tXO shutdown count: %u\n", stat.xo_count); + seq_printf(s, "\tWakeup reason: 0x%x\n", stat.wakeup_reason); + seq_printf(s, "\tShutdown count: %u\n", stat.num_shutdowns); + seq_printf(s, "\tActive cores bitmask: 0x%x\n", stat.active_cores); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(master_stats); + +static int master_stats_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct master_stats_data *data; + struct device_node *msgram_np; + struct dentry *dent, *root; + struct resource res; + int count, i, ret; + + count = of_property_count_strings(dev->of_node, "qcom,master-names"); + if (count < 0) + return count; + + data = devm_kzalloc(dev, count * sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + root = debugfs_create_dir("qcom_rpm_master_stats", NULL); + platform_set_drvdata(pdev, root); + + for (i = 0; i < count; i++) { + msgram_np = of_parse_phandle(dev->of_node, "qcom,rpm-msg-ram", i); + if (!msgram_np) { + debugfs_remove_recursive(root); + return dev_err_probe(dev, -ENODEV, + "Couldn't parse MSG RAM phandle idx %d", i); + } + + /* + * Purposefully skip devm_platform helpers as we're using a + * shared resource. + */ + ret = of_address_to_resource(msgram_np, 0, &res); + of_node_put(msgram_np); + if (ret < 0) { + debugfs_remove_recursive(root); + return ret; + } + + data[i].base = devm_ioremap(dev, res.start, resource_size(&res)); + if (IS_ERR(data[i].base)) { + debugfs_remove_recursive(root); + return dev_err_probe(dev, -EINVAL, + "Could not map the MSG RAM slice idx %d!\n", i); + } + + ret = of_property_read_string_index(dev->of_node, "qcom,master-names", i, + &data[i].label); + if (ret < 0) { + debugfs_remove_recursive(root); + return dev_err_probe(dev, ret, + "Could not read name idx %d!\n", i); + } + + /* + * Generally it's not advised to fail on debugfs errors, but this + * driver's only job is exposing data therein. + */ + dent = debugfs_create_file(data[i].label, 0444, root, + &data[i], &master_stats_fops); + if (IS_ERR(dent)) { + debugfs_remove_recursive(root); + return dev_err_probe(dev, PTR_ERR(dent), + "Failed to create debugfs file %s!\n", data[i].label); + } + } + + device_set_pm_not_required(dev); + + return 0; +} + +static void master_stats_remove(struct platform_device *pdev) +{ + struct dentry *root = platform_get_drvdata(pdev); + + debugfs_remove_recursive(root); +} + +static const struct of_device_id rpm_master_table[] = { + { .compatible = "qcom,rpm-master-stats" }, + { }, +}; + +static struct platform_driver master_stats_driver = { + .probe = master_stats_probe, + .remove_new = master_stats_remove, + .driver = { + .name = "qcom_rpm_master_stats", + .of_match_table = rpm_master_table, + }, +}; +module_platform_driver(master_stats_driver); + +MODULE_DESCRIPTION("Qualcomm RPM Master Statistics driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/soc/qcom/rpmpd.c b/drivers/soc/qcom/rpmpd.c index f8397dcb146c..99b017fd76b7 100644 --- a/drivers/soc/qcom/rpmpd.c +++ b/drivers/soc/qcom/rpmpd.c @@ -892,8 +892,8 @@ static int rpmpd_set_performance(struct generic_pm_domain *domain, pd->corner = state; /* Always send updates for vfc and vfl */ - if (!pd->enabled && pd->key != KEY_FLOOR_CORNER && - pd->key != KEY_FLOOR_LEVEL) + if (!pd->enabled && pd->key != cpu_to_le32(KEY_FLOOR_CORNER) && + pd->key != cpu_to_le32(KEY_FLOOR_LEVEL)) goto out; ret = rpmpd_aggregate_corner(pd); diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index 6be7ea93c78c..b0d59e815c3b 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -14,6 +14,7 @@ #include <linux/sizes.h> #include <linux/slab.h> #include <linux/soc/qcom/smem.h> +#include <linux/soc/qcom/socinfo.h> /* * The Qualcomm shared memory system is a allocate only heap structure that @@ -500,7 +501,7 @@ int qcom_smem_alloc(unsigned host, unsigned item, size_t size) return ret; } -EXPORT_SYMBOL(qcom_smem_alloc); +EXPORT_SYMBOL_GPL(qcom_smem_alloc); static void *qcom_smem_get_global(struct qcom_smem *smem, unsigned item, @@ -674,7 +675,7 @@ void *qcom_smem_get(unsigned host, unsigned item, size_t *size) return ptr; } -EXPORT_SYMBOL(qcom_smem_get); +EXPORT_SYMBOL_GPL(qcom_smem_get); /** * qcom_smem_get_free_space() - retrieve amount of free space in a partition @@ -719,7 +720,7 @@ int qcom_smem_get_free_space(unsigned host) return ret; } -EXPORT_SYMBOL(qcom_smem_get_free_space); +EXPORT_SYMBOL_GPL(qcom_smem_get_free_space); static bool addr_in_range(void __iomem *base, size_t size, void *addr) { @@ -770,7 +771,29 @@ phys_addr_t qcom_smem_virt_to_phys(void *p) return 0; } -EXPORT_SYMBOL(qcom_smem_virt_to_phys); +EXPORT_SYMBOL_GPL(qcom_smem_virt_to_phys); + +/** + * qcom_smem_get_soc_id() - return the SoC ID + * @id: On success, we return the SoC ID here. + * + * Look up SoC ID from HW/SW build ID and return it. + * + * Return: 0 on success, negative errno on failure. + */ +int qcom_smem_get_soc_id(u32 *id) +{ + struct socinfo *info; + + info = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_HW_SW_BUILD_ID, NULL); + if (IS_ERR(info)) + return PTR_ERR(info); + + *id = __le32_to_cpu(info->id); + + return 0; +} +EXPORT_SYMBOL_GPL(qcom_smem_get_soc_id); static int qcom_smem_get_sbl_version(struct qcom_smem *smem) { diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index c2e4a57dd666..dfd4330daef5 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -11,6 +11,7 @@ #include <linux/random.h> #include <linux/slab.h> #include <linux/soc/qcom/smem.h> +#include <linux/soc/qcom/socinfo.h> #include <linux/string.h> #include <linux/stringify.h> #include <linux/sys_soc.h> @@ -32,15 +33,6 @@ #define qcom_board_id(id) QCOM_ID_ ## id, __stringify(id) #define qcom_board_id_named(id, name) QCOM_ID_ ## id, (name) -#define SMEM_SOCINFO_BUILD_ID_LENGTH 32 -#define SMEM_SOCINFO_CHIP_ID_LENGTH 32 - -/* - * SMEM item id, used to acquire handles to respective - * SMEM region. - */ -#define SMEM_HW_SW_BUILD_ID 137 - #ifdef CONFIG_DEBUG_FS #define SMEM_IMAGE_VERSION_BLOCKS_COUNT 32 #define SMEM_IMAGE_VERSION_SIZE 4096 @@ -126,64 +118,7 @@ static const char *const pmic_models[] = { [58] = "PM8450", [65] = "PM8010", }; -#endif /* CONFIG_DEBUG_FS */ - -/* Socinfo SMEM item structure */ -struct socinfo { - __le32 fmt; - __le32 id; - __le32 ver; - char build_id[SMEM_SOCINFO_BUILD_ID_LENGTH]; - /* Version 2 */ - __le32 raw_id; - __le32 raw_ver; - /* Version 3 */ - __le32 hw_plat; - /* Version 4 */ - __le32 plat_ver; - /* Version 5 */ - __le32 accessory_chip; - /* Version 6 */ - __le32 hw_plat_subtype; - /* Version 7 */ - __le32 pmic_model; - __le32 pmic_die_rev; - /* Version 8 */ - __le32 pmic_model_1; - __le32 pmic_die_rev_1; - __le32 pmic_model_2; - __le32 pmic_die_rev_2; - /* Version 9 */ - __le32 foundry_id; - /* Version 10 */ - __le32 serial_num; - /* Version 11 */ - __le32 num_pmics; - __le32 pmic_array_offset; - /* Version 12 */ - __le32 chip_family; - __le32 raw_device_family; - __le32 raw_device_num; - /* Version 13 */ - __le32 nproduct_id; - char chip_id[SMEM_SOCINFO_CHIP_ID_LENGTH]; - /* Version 14 */ - __le32 num_clusters; - __le32 ncluster_array_offset; - __le32 num_defective_parts; - __le32 ndefective_parts_array_offset; - /* Version 15 */ - __le32 nmodem_supported; - /* Version 16 */ - __le32 feature_code; - __le32 pcode; - __le32 npartnamemap_offset; - __le32 nnum_partname_mapping; - /* Version 17 */ - __le32 oem_variant; -}; -#ifdef CONFIG_DEBUG_FS struct socinfo_params { u32 raw_device_family; u32 hw_plat_subtype; @@ -434,6 +369,9 @@ static const struct soc_id soc_id[] = { { qcom_board_id(SM8350) }, { qcom_board_id(QCM2290) }, { qcom_board_id(SM6115) }, + { qcom_board_id(IPQ5010) }, + { qcom_board_id(IPQ5018) }, + { qcom_board_id(IPQ5028) }, { qcom_board_id(SC8280XP) }, { qcom_board_id(IPQ6005) }, { qcom_board_id(QRB5165) }, @@ -447,6 +385,9 @@ static const struct soc_id soc_id[] = { { qcom_board_id_named(SM8450_3, "SM8450") }, { qcom_board_id(SC7280) }, { qcom_board_id(SC7180P) }, + { qcom_board_id(IPQ5000) }, + { qcom_board_id(IPQ0509) }, + { qcom_board_id(IPQ0518) }, { qcom_board_id(SM6375) }, { qcom_board_id(IPQ9514) }, { qcom_board_id(IPQ9550) }, @@ -454,6 +395,7 @@ static const struct soc_id soc_id[] = { { qcom_board_id(IPQ9570) }, { qcom_board_id(IPQ9574) }, { qcom_board_id(SM8550) }, + { qcom_board_id(IPQ5016) }, { qcom_board_id(IPQ9510) }, { qcom_board_id(QRB4210) }, { qcom_board_id(QRB2210) }, @@ -461,11 +403,14 @@ static const struct soc_id soc_id[] = { { qcom_board_id(QRU1000) }, { qcom_board_id(QDU1000) }, { qcom_board_id(QDU1010) }, + { qcom_board_id(IPQ5019) }, { qcom_board_id(QRU1032) }, { qcom_board_id(QRU1052) }, { qcom_board_id(QRU1062) }, { qcom_board_id(IPQ5332) }, { qcom_board_id(IPQ5322) }, + { qcom_board_id(IPQ5312) }, + { qcom_board_id(IPQ5302) }, }; static const char *socinfo_machine(struct device *dev, unsigned int id) diff --git a/drivers/soc/renesas/rcar-rst.c b/drivers/soc/renesas/rcar-rst.c index e1c7e91f5a86..98fd97da6cd4 100644 --- a/drivers/soc/renesas/rcar-rst.c +++ b/drivers/soc/renesas/rcar-rst.c @@ -12,6 +12,7 @@ #define WDTRSTCR_RESET 0xA55A0002 #define WDTRSTCR 0x0054 +#define GEN4_WDTRSTCR 0x0010 #define CR7BAR 0x0070 #define CR7BAREN BIT(4) @@ -27,6 +28,12 @@ static int rcar_rst_enable_wdt_reset(void __iomem *base) return 0; } +static int rcar_rst_v3u_enable_wdt_reset(void __iomem *base) +{ + iowrite32(WDTRSTCR_RESET, base + GEN4_WDTRSTCR); + return 0; +} + /* * Most of the R-Car Gen3 SoCs have an ARM Realtime Core. * Firmware boot address has to be set in CR7BAR before @@ -66,6 +73,12 @@ static const struct rst_config rcar_rst_gen3 __initconst = { .set_rproc_boot_addr = rcar_rst_set_gen3_rproc_boot_addr, }; +/* V3U firmware doesn't enable WDT reset and there won't be updates anymore */ +static const struct rst_config rcar_rst_v3u __initconst = { + .modemr = 0x00, /* MODEMR0 and it has CPG related bits */ + .configure = rcar_rst_v3u_enable_wdt_reset, +}; + static const struct rst_config rcar_rst_gen4 __initconst = { .modemr = 0x00, /* MODEMR0 and it has CPG related bits */ }; @@ -101,7 +114,7 @@ static const struct of_device_id rcar_rst_matches[] __initconst = { { .compatible = "renesas,r8a77990-rst", .data = &rcar_rst_gen3 }, { .compatible = "renesas,r8a77995-rst", .data = &rcar_rst_gen3 }, /* R-Car Gen4 */ - { .compatible = "renesas,r8a779a0-rst", .data = &rcar_rst_gen4 }, + { .compatible = "renesas,r8a779a0-rst", .data = &rcar_rst_v3u }, { .compatible = "renesas,r8a779f0-rst", .data = &rcar_rst_gen4 }, { .compatible = "renesas,r8a779g0-rst", .data = &rcar_rst_gen4 }, { /* sentinel */ } diff --git a/drivers/soc/renesas/rmobile-sysc.c b/drivers/soc/renesas/rmobile-sysc.c index 728ebac98e14..912daadaa10d 100644 --- a/drivers/soc/renesas/rmobile-sysc.c +++ b/drivers/soc/renesas/rmobile-sysc.c @@ -12,6 +12,8 @@ #include <linux/clk/renesas.h> #include <linux/console.h> #include <linux/delay.h> +#include <linux/io.h> +#include <linux/iopoll.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/pm.h> @@ -19,8 +21,6 @@ #include <linux/pm_domain.h> #include <linux/slab.h> -#include <asm/io.h> - /* SYSC */ #define SPDCR 0x08 /* SYS Power Down Control Register */ #define SWUCR 0x14 /* SYS Wakeup Control Register */ @@ -47,6 +47,7 @@ static int rmobile_pd_power_down(struct generic_pm_domain *genpd) { struct rmobile_pm_domain *rmobile_pd = to_rmobile_pd(genpd); unsigned int mask = BIT(rmobile_pd->bit_shift); + u32 val; if (rmobile_pd->suspend) { int ret = rmobile_pd->suspend(); @@ -56,14 +57,10 @@ static int rmobile_pd_power_down(struct generic_pm_domain *genpd) } if (readl(rmobile_pd->base + PSTR) & mask) { - unsigned int retry_count; writel(mask, rmobile_pd->base + SPDCR); - for (retry_count = PSTR_RETRIES; retry_count; retry_count--) { - if (!(readl(rmobile_pd->base + SPDCR) & mask)) - break; - cpu_relax(); - } + readl_poll_timeout_atomic(rmobile_pd->base + SPDCR, val, + !(val & mask), 0, PSTR_RETRIES); } pr_debug("%s: Power off, 0x%08x -> PSTR = 0x%08x\n", genpd->name, mask, @@ -74,8 +71,7 @@ static int rmobile_pd_power_down(struct generic_pm_domain *genpd) static int __rmobile_pd_power_up(struct rmobile_pm_domain *rmobile_pd) { - unsigned int mask = BIT(rmobile_pd->bit_shift); - unsigned int retry_count; + unsigned int val, mask = BIT(rmobile_pd->bit_shift); int ret = 0; if (readl(rmobile_pd->base + PSTR) & mask) @@ -83,16 +79,9 @@ static int __rmobile_pd_power_up(struct rmobile_pm_domain *rmobile_pd) writel(mask, rmobile_pd->base + SWUCR); - for (retry_count = 2 * PSTR_RETRIES; retry_count; retry_count--) { - if (!(readl(rmobile_pd->base + SWUCR) & mask)) - break; - if (retry_count > PSTR_RETRIES) - udelay(PSTR_DELAY_US); - else - cpu_relax(); - } - if (!retry_count) - ret = -EIO; + ret = readl_poll_timeout_atomic(rmobile_pd->base + SWUCR, val, + (val & mask), PSTR_DELAY_US, + PSTR_RETRIES * PSTR_DELAY_US); pr_debug("%s: Power on, 0x%08x -> PSTR = 0x%08x\n", rmobile_pd->genpd.name, mask, diff --git a/drivers/soc/samsung/exynos-pmu.c b/drivers/soc/samsung/exynos-pmu.c index 732c86ce2be8..5b2664da9853 100644 --- a/drivers/soc/samsung/exynos-pmu.c +++ b/drivers/soc/samsung/exynos-pmu.c @@ -57,6 +57,12 @@ void exynos_sys_powerdown_conf(enum sys_powerdown mode) if (pmu_data->powerdown_conf_extra) pmu_data->powerdown_conf_extra(mode); + + if (pmu_data->pmu_config_extra) { + for (i = 0; pmu_data->pmu_config_extra[i].offset != PMU_TABLE_END; i++) + pmu_raw_writel(pmu_data->pmu_config_extra[i].val[mode], + pmu_data->pmu_config_extra[i].offset); + } } /* @@ -80,6 +86,9 @@ static const struct of_device_id exynos_pmu_of_device_ids[] = { .compatible = "samsung,exynos4210-pmu", .data = exynos_pmu_data_arm_ptr(exynos4210_pmu_data), }, { + .compatible = "samsung,exynos4212-pmu", + .data = exynos_pmu_data_arm_ptr(exynos4212_pmu_data), + }, { .compatible = "samsung,exynos4412-pmu", .data = exynos_pmu_data_arm_ptr(exynos4412_pmu_data), }, { diff --git a/drivers/soc/samsung/exynos-pmu.h b/drivers/soc/samsung/exynos-pmu.h index 5e851f32307e..1c652ffd79b4 100644 --- a/drivers/soc/samsung/exynos-pmu.h +++ b/drivers/soc/samsung/exynos-pmu.h @@ -20,6 +20,7 @@ struct exynos_pmu_conf { struct exynos_pmu_data { const struct exynos_pmu_conf *pmu_config; + const struct exynos_pmu_conf *pmu_config_extra; void (*pmu_init)(void); void (*powerdown_conf)(enum sys_powerdown); @@ -32,6 +33,7 @@ extern void __iomem *pmu_base_addr; /* list of all exported SoC specific data */ extern const struct exynos_pmu_data exynos3250_pmu_data; extern const struct exynos_pmu_data exynos4210_pmu_data; +extern const struct exynos_pmu_data exynos4212_pmu_data; extern const struct exynos_pmu_data exynos4412_pmu_data; extern const struct exynos_pmu_data exynos5250_pmu_data; extern const struct exynos_pmu_data exynos5420_pmu_data; diff --git a/drivers/soc/samsung/exynos4-pmu.c b/drivers/soc/samsung/exynos4-pmu.c index cb35103565a6..f8092190b938 100644 --- a/drivers/soc/samsung/exynos4-pmu.c +++ b/drivers/soc/samsung/exynos4-pmu.c @@ -86,7 +86,7 @@ static const struct exynos_pmu_conf exynos4210_pmu_config[] = { { PMU_TABLE_END,}, }; -static const struct exynos_pmu_conf exynos4412_pmu_config[] = { +static const struct exynos_pmu_conf exynos4x12_pmu_config[] = { { S5P_ARM_CORE0_LOWPWR, { 0x0, 0x0, 0x2 } }, { S5P_DIS_IRQ_CORE0, { 0x0, 0x0, 0x0 } }, { S5P_DIS_IRQ_CENTRAL0, { 0x0, 0x0, 0x0 } }, @@ -191,6 +191,10 @@ static const struct exynos_pmu_conf exynos4412_pmu_config[] = { { S5P_GPS_ALIVE_LOWPWR, { 0x7, 0x0, 0x0 } }, { S5P_CMU_SYSCLK_ISP_LOWPWR, { 0x1, 0x0, 0x0 } }, { S5P_CMU_SYSCLK_GPS_LOWPWR, { 0x1, 0x0, 0x0 } }, + { PMU_TABLE_END,}, +}; + +static const struct exynos_pmu_conf exynos4412_pmu_config[] = { { S5P_ARM_CORE2_LOWPWR, { 0x0, 0x0, 0x2 } }, { S5P_DIS_IRQ_CORE2, { 0x0, 0x0, 0x0 } }, { S5P_DIS_IRQ_CENTRAL2, { 0x0, 0x0, 0x0 } }, @@ -204,6 +208,11 @@ const struct exynos_pmu_data exynos4210_pmu_data = { .pmu_config = exynos4210_pmu_config, }; +const struct exynos_pmu_data exynos4212_pmu_data = { + .pmu_config = exynos4x12_pmu_config, +}; + const struct exynos_pmu_data exynos4412_pmu_data = { - .pmu_config = exynos4412_pmu_config, + .pmu_config = exynos4x12_pmu_config, + .pmu_config_extra = exynos4412_pmu_config, }; diff --git a/drivers/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c index 932a03c64534..c759fb7c8adc 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra30.c +++ b/drivers/soc/tegra/fuse/fuse-tegra30.c @@ -663,7 +663,7 @@ static const struct nvmem_keepout tegra234_fuse_keepouts[] = { static const struct tegra_fuse_info tegra234_fuse_info = { .read = tegra30_fuse_read, - .size = 0x98c, + .size = 0xf90, .spare = 0x280, }; diff --git a/drivers/soc/tegra/fuse/tegra-apbmisc.c b/drivers/soc/tegra/fuse/tegra-apbmisc.c index 4591c5bcb690..eb0a1d924526 100644 --- a/drivers/soc/tegra/fuse/tegra-apbmisc.c +++ b/drivers/soc/tegra/fuse/tegra-apbmisc.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2014-2023, NVIDIA CORPORATION. All rights reserved. */ #include <linux/export.h> @@ -62,6 +62,7 @@ bool tegra_is_silicon(void) switch (tegra_get_chip_id()) { case TEGRA194: case TEGRA234: + case TEGRA264: if (tegra_get_platform() == 0) return true; diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 5d17799524c9..162f52456f65 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -396,7 +396,6 @@ struct tegra_pmc_soc { * @clk: pointer to pclk clock * @soc: pointer to SoC data structure * @tz_only: flag specifying if the PMC can only be accessed via TrustZone - * @debugfs: pointer to debugfs entry * @rate: currently configured rate of pclk * @suspend_mode: lowest suspend mode available * @cpu_good_time: CPU power good time (in microseconds) @@ -431,7 +430,6 @@ struct tegra_pmc { void __iomem *aotag; void __iomem *scratch; struct clk *clk; - struct dentry *debugfs; const struct tegra_pmc_soc *soc; bool tz_only; @@ -1190,16 +1188,6 @@ static int powergate_show(struct seq_file *s, void *data) DEFINE_SHOW_ATTRIBUTE(powergate); -static int tegra_powergate_debugfs_init(void) -{ - pmc->debugfs = debugfs_create_file("powergate", S_IRUGO, NULL, NULL, - &powergate_fops); - if (!pmc->debugfs) - return -ENOMEM; - - return 0; -} - static int tegra_powergate_of_get_clks(struct tegra_powergate *pg, struct device_node *np) { @@ -3004,7 +2992,8 @@ static int tegra_pmc_probe(struct platform_device *pdev) */ if (pmc->clk) { pmc->clk_nb.notifier_call = tegra_pmc_clk_notify_cb; - err = clk_notifier_register(pmc->clk, &pmc->clk_nb); + err = devm_clk_notifier_register(&pdev->dev, pmc->clk, + &pmc->clk_nb); if (err) { dev_err(&pdev->dev, "failed to register clk notifier\n"); @@ -3026,19 +3015,13 @@ static int tegra_pmc_probe(struct platform_device *pdev) tegra_pmc_reset_sysfs_init(pmc); - if (IS_ENABLED(CONFIG_DEBUG_FS)) { - err = tegra_powergate_debugfs_init(); - if (err < 0) - goto cleanup_sysfs; - } - err = tegra_pmc_pinctrl_init(pmc); if (err) - goto cleanup_debugfs; + goto cleanup_sysfs; err = tegra_pmc_regmap_init(pmc); if (err < 0) - goto cleanup_debugfs; + goto cleanup_sysfs; err = tegra_powergate_init(pmc, pdev->dev.of_node); if (err < 0) @@ -3061,16 +3044,15 @@ static int tegra_pmc_probe(struct platform_device *pdev) if (pmc->soc->set_wake_filters) pmc->soc->set_wake_filters(pmc); + debugfs_create_file("powergate", 0444, NULL, NULL, &powergate_fops); + return 0; cleanup_powergates: tegra_powergate_remove_all(pdev->dev.of_node); -cleanup_debugfs: - debugfs_remove(pmc->debugfs); cleanup_sysfs: device_remove_file(&pdev->dev, &dev_attr_reset_reason); device_remove_file(&pdev->dev, &dev_attr_reset_level); - clk_notifier_unregister(pmc->clk, &pmc->clk_nb); return err; } @@ -4250,6 +4232,7 @@ static const struct tegra_wake_event tegra234_wake_events[] = { TEGRA_WAKE_GPIO("power", 29, 1, TEGRA234_AON_GPIO(EE, 4)), TEGRA_WAKE_GPIO("mgbe", 56, 0, TEGRA234_MAIN_GPIO(Y, 3)), TEGRA_WAKE_IRQ("rtc", 73, 10), + TEGRA_WAKE_IRQ("sw-wake", SW_WAKE_ID, 179), }; static const struct tegra_pmc_soc tegra234_pmc_soc = { diff --git a/drivers/soc/xilinx/xlnx_event_manager.c b/drivers/soc/xilinx/xlnx_event_manager.c index c76381899ef4..f9d9b82b562d 100644 --- a/drivers/soc/xilinx/xlnx_event_manager.c +++ b/drivers/soc/xilinx/xlnx_event_manager.c @@ -192,11 +192,12 @@ static int xlnx_remove_cb_for_suspend(event_cb_func_t cb_fun) struct registered_event_data *eve_data; struct agent_cb *cb_pos; struct agent_cb *cb_next; + struct hlist_node *tmp; is_need_to_unregister = false; /* Check for existing entry in hash table for given cb_type */ - hash_for_each_possible(reg_driver_map, eve_data, hentry, PM_INIT_SUSPEND_CB) { + hash_for_each_possible_safe(reg_driver_map, eve_data, tmp, hentry, PM_INIT_SUSPEND_CB) { if (eve_data->cb_type == PM_INIT_SUSPEND_CB) { /* Delete the list of callback */ list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) { @@ -228,11 +229,12 @@ static int xlnx_remove_cb_for_notify_event(const u32 node_id, const u32 event, u64 key = ((u64)node_id << 32U) | (u64)event; struct agent_cb *cb_pos; struct agent_cb *cb_next; + struct hlist_node *tmp; is_need_to_unregister = false; /* Check for existing entry in hash table for given key id */ - hash_for_each_possible(reg_driver_map, eve_data, hentry, key) { + hash_for_each_possible_safe(reg_driver_map, eve_data, tmp, hentry, key) { if (eve_data->key == key) { /* Delete the list of callback */ list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) { diff --git a/drivers/soc/xilinx/zynqmp_power.c b/drivers/soc/xilinx/zynqmp_power.c index 78a8a7545d1e..641dcc958911 100644 --- a/drivers/soc/xilinx/zynqmp_power.c +++ b/drivers/soc/xilinx/zynqmp_power.c @@ -218,7 +218,7 @@ static int zynqmp_pm_probe(struct platform_device *pdev) } else if (ret != -EACCES && ret != -ENODEV) { dev_err(&pdev->dev, "Failed to Register with Xilinx Event manager %d\n", ret); return ret; - } else if (of_find_property(pdev->dev.of_node, "mboxes", NULL)) { + } else if (of_property_present(pdev->dev.of_node, "mboxes")) { zynqmp_pm_init_suspend_work = devm_kzalloc(&pdev->dev, sizeof(struct zynqmp_pm_work_struct), @@ -240,7 +240,7 @@ static int zynqmp_pm_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Failed to request rx channel\n"); return PTR_ERR(rx_chan); } - } else if (of_find_property(pdev->dev.of_node, "interrupts", NULL)) { + } else if (of_property_present(pdev->dev.of_node, "interrupts")) { irq = platform_get_irq(pdev, 0); if (irq <= 0) return -ENXIO; |