diff options
Diffstat (limited to 'drivers/soc/qcom')
-rw-r--r-- | drivers/soc/qcom/apr.c | 15 | ||||
-rw-r--r-- | drivers/soc/qcom/cmd-db.c | 2 | ||||
-rw-r--r-- | drivers/soc/qcom/llcc-qcom.c | 2 | ||||
-rw-r--r-- | drivers/soc/qcom/pdr_internal.h | 20 | ||||
-rw-r--r-- | drivers/soc/qcom/qcom_stats.c | 2 | ||||
-rw-r--r-- | drivers/soc/qcom/rpmh-internal.h | 9 | ||||
-rw-r--r-- | drivers/soc/qcom/rpmh-rsc.c | 146 | ||||
-rw-r--r-- | drivers/soc/qcom/rpmh.c | 4 | ||||
-rw-r--r-- | drivers/soc/qcom/rpmhpd.c | 71 | ||||
-rw-r--r-- | drivers/soc/qcom/smd-rpm.c | 3 | ||||
-rw-r--r-- | drivers/soc/qcom/smp2p.c | 2 | ||||
-rw-r--r-- | drivers/soc/qcom/socinfo.c | 271 | ||||
-rw-r--r-- | drivers/soc/qcom/spm.c | 46 |
13 files changed, 431 insertions, 162 deletions
diff --git a/drivers/soc/qcom/apr.c b/drivers/soc/qcom/apr.c index b4046f393575..cd44f17dad3d 100644 --- a/drivers/soc/qcom/apr.c +++ b/drivers/soc/qcom/apr.c @@ -454,11 +454,19 @@ static int apr_add_device(struct device *dev, struct device_node *np, adev->dev.driver = NULL; spin_lock(&apr->svcs_lock); - idr_alloc(&apr->svcs_idr, svc, svc_id, svc_id + 1, GFP_ATOMIC); + ret = idr_alloc(&apr->svcs_idr, svc, svc_id, svc_id + 1, GFP_ATOMIC); spin_unlock(&apr->svcs_lock); + if (ret < 0) { + dev_err(dev, "idr_alloc failed: %d\n", ret); + goto out; + } - of_property_read_string_index(np, "qcom,protection-domain", - 1, &adev->service_path); + ret = of_property_read_string_index(np, "qcom,protection-domain", + 1, &adev->service_path); + if (ret < 0) { + dev_err(dev, "Failed to read second value of qcom,protection-domain\n"); + goto out; + } dev_info(dev, "Adding APR/GPR dev: %s\n", dev_name(&adev->dev)); @@ -468,6 +476,7 @@ static int apr_add_device(struct device *dev, struct device_node *np, put_device(&adev->dev); } +out: return ret; } diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c index 629a7188b576..33856abd560c 100644 --- a/drivers/soc/qcom/cmd-db.c +++ b/drivers/soc/qcom/cmd-db.c @@ -338,6 +338,8 @@ static int cmd_db_dev_probe(struct platform_device *pdev) debugfs_create_file("cmd-db", 0400, NULL, NULL, &cmd_db_debugfs_ops); + device_set_pm_not_required(&pdev->dev); + return 0; } diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c index 8b7e8118f3ce..82c3cfdcc560 100644 --- a/drivers/soc/qcom/llcc-qcom.c +++ b/drivers/soc/qcom/llcc-qcom.c @@ -849,7 +849,7 @@ static int qcom_llcc_probe(struct platform_device *pdev) if (ret) goto err; - drv_data->ecc_irq = platform_get_irq(pdev, 0); + drv_data->ecc_irq = platform_get_irq_optional(pdev, 0); if (drv_data->ecc_irq >= 0) { llcc_edac = platform_device_register_data(&pdev->dev, "qcom_llcc_edac", -1, drv_data, diff --git a/drivers/soc/qcom/pdr_internal.h b/drivers/soc/qcom/pdr_internal.h index a30422214943..03c282b7f17e 100644 --- a/drivers/soc/qcom/pdr_internal.h +++ b/drivers/soc/qcom/pdr_internal.h @@ -28,7 +28,7 @@ struct servreg_location_entry { u32 instance; }; -static struct qmi_elem_info servreg_location_entry_ei[] = { +static const struct qmi_elem_info servreg_location_entry_ei[] = { { .data_type = QMI_STRING, .elem_len = SERVREG_NAME_LENGTH + 1, @@ -74,7 +74,7 @@ struct servreg_get_domain_list_req { u32 domain_offset; }; -static struct qmi_elem_info servreg_get_domain_list_req_ei[] = { +static const struct qmi_elem_info servreg_get_domain_list_req_ei[] = { { .data_type = QMI_STRING, .elem_len = SERVREG_NAME_LENGTH + 1, @@ -116,7 +116,7 @@ struct servreg_get_domain_list_resp { struct servreg_location_entry domain_list[SERVREG_DOMAIN_LIST_LENGTH]; }; -static struct qmi_elem_info servreg_get_domain_list_resp_ei[] = { +static const struct qmi_elem_info servreg_get_domain_list_resp_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, @@ -199,7 +199,7 @@ struct servreg_register_listener_req { char service_path[SERVREG_NAME_LENGTH + 1]; }; -static struct qmi_elem_info servreg_register_listener_req_ei[] = { +static const struct qmi_elem_info servreg_register_listener_req_ei[] = { { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, @@ -227,7 +227,7 @@ struct servreg_register_listener_resp { enum servreg_service_state curr_state; }; -static struct qmi_elem_info servreg_register_listener_resp_ei[] = { +static const struct qmi_elem_info servreg_register_listener_resp_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, @@ -263,7 +263,7 @@ struct servreg_restart_pd_req { char service_path[SERVREG_NAME_LENGTH + 1]; }; -static struct qmi_elem_info servreg_restart_pd_req_ei[] = { +static const struct qmi_elem_info servreg_restart_pd_req_ei[] = { { .data_type = QMI_STRING, .elem_len = SERVREG_NAME_LENGTH + 1, @@ -280,7 +280,7 @@ struct servreg_restart_pd_resp { struct qmi_response_type_v01 resp; }; -static struct qmi_elem_info servreg_restart_pd_resp_ei[] = { +static const struct qmi_elem_info servreg_restart_pd_resp_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, @@ -300,7 +300,7 @@ struct servreg_state_updated_ind { u16 transaction_id; }; -static struct qmi_elem_info servreg_state_updated_ind_ei[] = { +static const struct qmi_elem_info servreg_state_updated_ind_ei[] = { { .data_type = QMI_SIGNED_4_BYTE_ENUM, .elem_len = 1, @@ -336,7 +336,7 @@ struct servreg_set_ack_req { u16 transaction_id; }; -static struct qmi_elem_info servreg_set_ack_req_ei[] = { +static const struct qmi_elem_info servreg_set_ack_req_ei[] = { { .data_type = QMI_STRING, .elem_len = SERVREG_NAME_LENGTH + 1, @@ -362,7 +362,7 @@ struct servreg_set_ack_resp { struct qmi_response_type_v01 resp; }; -static struct qmi_elem_info servreg_set_ack_resp_ei[] = { +static const struct qmi_elem_info servreg_set_ack_resp_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, diff --git a/drivers/soc/qcom/qcom_stats.c b/drivers/soc/qcom/qcom_stats.c index 121ea409fafc..6228af057120 100644 --- a/drivers/soc/qcom/qcom_stats.c +++ b/drivers/soc/qcom/qcom_stats.c @@ -217,6 +217,8 @@ static int qcom_stats_probe(struct platform_device *pdev) platform_set_drvdata(pdev, root); + device_set_pm_not_required(&pdev->dev); + return 0; } diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h index 344ba687c13b..39f53586f724 100644 --- a/drivers/soc/qcom/rpmh-internal.h +++ b/drivers/soc/qcom/rpmh-internal.h @@ -91,13 +91,15 @@ struct rpmh_ctrlr { * Resource State Coordinator controller (RSC) * * @name: Controller identifier. + * @base: Start address of the DRV registers in this controller. * @tcs_base: Start address of the TCS registers in this controller. * @id: Instance id in the controller (Direct Resource Voter). * @num_tcs: Number of TCSes in this DRV. * @rsc_pm: CPU PM notifier for controller. * Used when solver mode is not present. * @cpus_in_pm: Number of CPUs not in idle power collapse. - * Used when solver mode is not present. + * Used when solver mode and "power-domains" is not present. + * @genpd_nb: PM Domain notifier for cluster genpd notifications. * @tcs: TCS groups. * @tcs_in_use: S/W state of the TCS; only set for ACTIVE_ONLY * transfers, but might show a sleep/wake TCS in use if @@ -110,25 +112,30 @@ struct rpmh_ctrlr { * @tcs_wait: Wait queue used to wait for @tcs_in_use to free up a * slot * @client: Handle to the DRV's client. + * @dev: RSC device. */ struct rsc_drv { const char *name; + void __iomem *base; void __iomem *tcs_base; int id; int num_tcs; struct notifier_block rsc_pm; + struct notifier_block genpd_nb; atomic_t cpus_in_pm; struct tcs_group tcs[TCS_TYPE_NR]; DECLARE_BITMAP(tcs_in_use, MAX_TCS_NR); spinlock_t lock; wait_queue_head_t tcs_wait; struct rpmh_ctrlr client; + struct device *dev; }; int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg); int rpmh_rsc_write_ctrl_data(struct rsc_drv *drv, const struct tcs_request *msg); void rpmh_rsc_invalidate(struct rsc_drv *drv); +void rpmh_rsc_write_next_wakeup(struct rsc_drv *drv); void rpmh_tx_done(const struct tcs_request *msg, int r); int rpmh_flush(struct rpmh_ctrlr *ctrlr); diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index 01c2f50cb97e..c51567b778ef 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -12,16 +12,21 @@ #include <linux/io.h> #include <linux/iopoll.h> #include <linux/kernel.h> +#include <linux/ktime.h> #include <linux/list.h> #include <linux/module.h> +#include <linux/notifier.h> #include <linux/of.h> #include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/platform_device.h> +#include <linux/pm_domain.h> +#include <linux/pm_runtime.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/wait.h> +#include <clocksource/arm_arch_timer.h> #include <soc/qcom/cmd-db.h> #include <soc/qcom/tcs.h> #include <dt-bindings/soc/qcom,rpmh-rsc.h> @@ -46,6 +51,14 @@ #define DRV_NCPT_MASK 0x1F #define DRV_NCPT_SHIFT 27 +/* Offsets for CONTROL TCS Registers */ +#define RSC_DRV_CTL_TCS_DATA_HI 0x38 +#define RSC_DRV_CTL_TCS_DATA_HI_MASK 0xFFFFFF +#define RSC_DRV_CTL_TCS_DATA_HI_VALID BIT(31) +#define RSC_DRV_CTL_TCS_DATA_LO 0x40 +#define RSC_DRV_CTL_TCS_DATA_LO_MASK 0xFFFFFFFF +#define RSC_DRV_CTL_TCS_DATA_SIZE 32 + /* Offsets for common TCS Registers, one bit per TCS */ #define RSC_DRV_IRQ_ENABLE 0x00 #define RSC_DRV_IRQ_STATUS 0x04 @@ -139,6 +152,14 @@ * +---------------------------------------------------+ */ +#define USECS_TO_CYCLES(time_usecs) \ + xloops_to_cycles((time_usecs) * 0x10C7UL) + +static inline unsigned long xloops_to_cycles(u64 xloops) +{ + return (xloops * loops_per_jiffy * HZ) >> 32; +} + static inline void __iomem * tcs_reg_addr(const struct rsc_drv *drv, int reg, int tcs_id) { @@ -754,6 +775,48 @@ static bool rpmh_rsc_ctrlr_is_busy(struct rsc_drv *drv) } /** + * rpmh_rsc_write_next_wakeup() - Write next wakeup in CONTROL_TCS. + * @drv: The controller + * + * Writes maximum wakeup cycles when called from suspend. + * Writes earliest hrtimer wakeup when called from idle. + */ +void rpmh_rsc_write_next_wakeup(struct rsc_drv *drv) +{ + ktime_t now, wakeup; + u64 wakeup_us, wakeup_cycles = ~0; + u32 lo, hi; + + if (!drv->tcs[CONTROL_TCS].num_tcs || !drv->genpd_nb.notifier_call) + return; + + /* Set highest time when system (timekeeping) is suspended */ + if (system_state == SYSTEM_SUSPEND) + goto exit; + + /* Find the earliest hrtimer wakeup from online cpus */ + wakeup = dev_pm_genpd_get_next_hrtimer(drv->dev); + + /* Find the relative wakeup in kernel time scale */ + now = ktime_get(); + wakeup = ktime_sub(wakeup, now); + wakeup_us = ktime_to_us(wakeup); + + /* Convert the wakeup to arch timer scale */ + wakeup_cycles = USECS_TO_CYCLES(wakeup_us); + wakeup_cycles += arch_timer_read_counter(); + +exit: + lo = wakeup_cycles & RSC_DRV_CTL_TCS_DATA_LO_MASK; + hi = wakeup_cycles >> RSC_DRV_CTL_TCS_DATA_SIZE; + hi &= RSC_DRV_CTL_TCS_DATA_HI_MASK; + hi |= RSC_DRV_CTL_TCS_DATA_HI_VALID; + + writel_relaxed(lo, drv->base + RSC_DRV_CTL_TCS_DATA_LO); + writel_relaxed(hi, drv->base + RSC_DRV_CTL_TCS_DATA_HI); +} + +/** * rpmh_rsc_cpu_pm_callback() - Check if any of the AMCs are busy. * @nfb: Pointer to the notifier block in struct rsc_drv. * @action: CPU_PM_ENTER, CPU_PM_ENTER_FAILED, or CPU_PM_EXIT. @@ -834,8 +897,51 @@ static int rpmh_rsc_cpu_pm_callback(struct notifier_block *nfb, return ret; } -static int rpmh_probe_tcs_config(struct platform_device *pdev, - struct rsc_drv *drv, void __iomem *base) +/** + * rpmh_rsc_pd_callback() - Check if any of the AMCs are busy. + * @nfb: Pointer to the genpd notifier block in struct rsc_drv. + * @action: GENPD_NOTIFY_PRE_OFF, GENPD_NOTIFY_OFF, GENPD_NOTIFY_PRE_ON or GENPD_NOTIFY_ON. + * @v: Unused + * + * This function is given to dev_pm_genpd_add_notifier() so we can be informed + * about when cluster-pd is going down. When cluster go down we know no more active + * transfers will be started so we write sleep/wake sets. This function gets + * called from cpuidle code paths and also at system suspend time. + * + * If AMCs are not busy then writes cached sleep and wake messages to TCSes. + * The firmware then takes care of triggering them when entering deepest low power modes. + * + * Return: + * * NOTIFY_OK - success + * * NOTIFY_BAD - failure + */ +static int rpmh_rsc_pd_callback(struct notifier_block *nfb, + unsigned long action, void *v) +{ + struct rsc_drv *drv = container_of(nfb, struct rsc_drv, genpd_nb); + + /* We don't need to lock as genpd on/off are serialized */ + if ((action == GENPD_NOTIFY_PRE_OFF) && + (rpmh_rsc_ctrlr_is_busy(drv) || rpmh_flush(&drv->client))) + return NOTIFY_BAD; + + return NOTIFY_OK; +} + +static int rpmh_rsc_pd_attach(struct rsc_drv *drv, struct device *dev) +{ + int ret; + + pm_runtime_enable(dev); + drv->genpd_nb.notifier_call = rpmh_rsc_pd_callback; + ret = dev_pm_genpd_add_notifier(dev, &drv->genpd_nb); + if (ret) + pm_runtime_disable(dev); + + return ret; +} + +static int rpmh_probe_tcs_config(struct platform_device *pdev, struct rsc_drv *drv) { struct tcs_type_config { u32 type; @@ -849,9 +955,9 @@ static int rpmh_probe_tcs_config(struct platform_device *pdev, ret = of_property_read_u32(dn, "qcom,tcs-offset", &offset); if (ret) return ret; - drv->tcs_base = base + offset; + drv->tcs_base = drv->base + offset; - config = readl_relaxed(base + DRV_PRNT_CHLD_CONFIG); + config = readl_relaxed(drv->base + DRV_PRNT_CHLD_CONFIG); max_tcs = config; max_tcs &= DRV_NUM_TCS_MASK << (DRV_NUM_TCS_SHIFT * drv->id); @@ -913,7 +1019,6 @@ static int rpmh_rsc_probe(struct platform_device *pdev) char drv_id[10] = {0}; int ret, irq; u32 solver_config; - void __iomem *base; /* * Even though RPMh doesn't directly use cmd-db, all of its children @@ -940,11 +1045,11 @@ static int rpmh_rsc_probe(struct platform_device *pdev) drv->name = dev_name(&pdev->dev); snprintf(drv_id, ARRAY_SIZE(drv_id), "drv-%d", drv->id); - base = devm_platform_ioremap_resource_byname(pdev, drv_id); - if (IS_ERR(base)) - return PTR_ERR(base); + drv->base = devm_platform_ioremap_resource_byname(pdev, drv_id); + if (IS_ERR(drv->base)) + return PTR_ERR(drv->base); - ret = rpmh_probe_tcs_config(pdev, drv, base); + ret = rpmh_probe_tcs_config(pdev, drv); if (ret) return ret; @@ -963,16 +1068,22 @@ static int rpmh_rsc_probe(struct platform_device *pdev) return ret; /* - * CPU PM notification are not required for controllers that support + * CPU PM/genpd notification are not required for controllers that support * 'HW solver' mode where they can be in autonomous mode executing low * power mode to power down. */ - solver_config = readl_relaxed(base + DRV_SOLVER_CONFIG); + solver_config = readl_relaxed(drv->base + DRV_SOLVER_CONFIG); solver_config &= DRV_HW_SOLVER_MASK << DRV_HW_SOLVER_SHIFT; solver_config = solver_config >> DRV_HW_SOLVER_SHIFT; if (!solver_config) { - drv->rsc_pm.notifier_call = rpmh_rsc_cpu_pm_callback; - cpu_pm_register_notifier(&drv->rsc_pm); + if (pdev->dev.pm_domain) { + ret = rpmh_rsc_pd_attach(drv, &pdev->dev); + if (ret) + return ret; + } else { + drv->rsc_pm.notifier_call = rpmh_rsc_cpu_pm_callback; + cpu_pm_register_notifier(&drv->rsc_pm); + } } /* Enable the active TCS to send requests immediately */ @@ -984,8 +1095,15 @@ static int rpmh_rsc_probe(struct platform_device *pdev) INIT_LIST_HEAD(&drv->client.batch_cache); dev_set_drvdata(&pdev->dev, drv); + drv->dev = &pdev->dev; - return devm_of_platform_populate(&pdev->dev); + ret = devm_of_platform_populate(&pdev->dev); + if (ret && pdev->dev.pm_domain) { + dev_pm_genpd_remove_notifier(&pdev->dev); + pm_runtime_disable(&pdev->dev); + } + + return ret; } static const struct of_device_id rpmh_drv_match[] = { diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c index 01765ee9cdfb..3a53ed99d03c 100644 --- a/drivers/soc/qcom/rpmh.c +++ b/drivers/soc/qcom/rpmh.c @@ -450,7 +450,7 @@ int rpmh_flush(struct rpmh_ctrlr *ctrlr) if (!ctrlr->dirty) { pr_debug("Skipping flush, TCS has latest data.\n"); - goto exit; + goto write_next_wakeup; } /* Invalidate the TCSes first to avoid stale data */ @@ -479,6 +479,8 @@ int rpmh_flush(struct rpmh_ctrlr *ctrlr) ctrlr->dirty = false; +write_next_wakeup: + rpmh_rsc_write_next_wakeup(ctrlr_to_drv(ctrlr)); exit: spin_unlock(&ctrlr->cache_lock); return ret; diff --git a/drivers/soc/qcom/rpmhpd.c b/drivers/soc/qcom/rpmhpd.c index 092f6ab09acf..7af68cd720f5 100644 --- a/drivers/soc/qcom/rpmhpd.c +++ b/drivers/soc/qcom/rpmhpd.c @@ -39,6 +39,7 @@ * @res_name: Resource name used for cmd-db lookup * @addr: Resource address as looped up using resource name from * cmd-db + * @state_synced: Indicator that sync_state has been invoked for the rpmhpd resource */ struct rpmhpd { struct device *dev; @@ -54,6 +55,7 @@ struct rpmhpd { bool enabled; const char *res_name; u32 addr; + bool state_synced; }; struct rpmhpd_desc { @@ -210,6 +212,23 @@ static const struct rpmhpd_desc sa8540p_desc = { .num_pds = ARRAY_SIZE(sa8540p_rpmhpds), }; +/* SDM670 RPMH powerdomains */ +static struct rpmhpd *sdm670_rpmhpds[] = { + [SDM670_CX] = &cx_w_mx_parent, + [SDM670_CX_AO] = &cx_ao_w_mx_parent, + [SDM670_GFX] = &gfx, + [SDM670_LCX] = &lcx, + [SDM670_LMX] = &lmx, + [SDM670_MSS] = &mss, + [SDM670_MX] = &mx, + [SDM670_MX_AO] = &mx_ao, +}; + +static const struct rpmhpd_desc sdm670_desc = { + .rpmhpds = sdm670_rpmhpds, + .num_pds = ARRAY_SIZE(sdm670_rpmhpds), +}; + /* SDM845 RPMH powerdomains */ static struct rpmhpd *sdm845_rpmhpds[] = { [SDM845_CX] = &cx_w_mx_parent, @@ -353,6 +372,19 @@ static const struct rpmhpd_desc sm8450_desc = { .num_pds = ARRAY_SIZE(sm8450_rpmhpds), }; +/* QDU1000/QRU1000 RPMH powerdomains */ +static struct rpmhpd *qdu1000_rpmhpds[] = { + [QDU1000_CX] = &cx, + [QDU1000_EBI] = &ebi, + [QDU1000_MSS] = &mss, + [QDU1000_MX] = &mx, +}; + +static const struct rpmhpd_desc qdu1000_desc = { + .rpmhpds = qdu1000_rpmhpds, + .num_pds = ARRAY_SIZE(qdu1000_rpmhpds), +}; + /* SC7180 RPMH powerdomains */ static struct rpmhpd *sc7180_rpmhpds[] = { [SC7180_CX] = &cx_w_mx_parent, @@ -430,11 +462,13 @@ static const struct rpmhpd_desc sc8280xp_desc = { }; static const struct of_device_id rpmhpd_match_table[] = { + { .compatible = "qcom,qdu1000-rpmhpd", .data = &qdu1000_desc }, { .compatible = "qcom,sa8540p-rpmhpd", .data = &sa8540p_desc }, { .compatible = "qcom,sc7180-rpmhpd", .data = &sc7180_desc }, { .compatible = "qcom,sc7280-rpmhpd", .data = &sc7280_desc }, { .compatible = "qcom,sc8180x-rpmhpd", .data = &sc8180x_desc }, { .compatible = "qcom,sc8280xp-rpmhpd", .data = &sc8280xp_desc }, + { .compatible = "qcom,sdm670-rpmhpd", .data = &sdm670_desc }, { .compatible = "qcom,sdm845-rpmhpd", .data = &sdm845_desc }, { .compatible = "qcom,sdx55-rpmhpd", .data = &sdx55_desc}, { .compatible = "qcom,sdx65-rpmhpd", .data = &sdx65_desc}, @@ -493,7 +527,13 @@ static int rpmhpd_aggregate_corner(struct rpmhpd *pd, unsigned int corner) unsigned int this_active_corner = 0, this_sleep_corner = 0; unsigned int peer_active_corner = 0, peer_sleep_corner = 0; - to_active_sleep(pd, corner, &this_active_corner, &this_sleep_corner); + if (pd->state_synced) { + to_active_sleep(pd, corner, &this_active_corner, &this_sleep_corner); + } else { + /* Clamp to highest corner if sync_state hasn't happened */ + this_active_corner = pd->level_count - 1; + this_sleep_corner = pd->level_count - 1; + } if (peer && peer->enabled) to_active_sleep(peer, peer->corner, &peer_active_corner, @@ -708,11 +748,40 @@ static int rpmhpd_probe(struct platform_device *pdev) return of_genpd_add_provider_onecell(pdev->dev.of_node, data); } +static void rpmhpd_sync_state(struct device *dev) +{ + const struct rpmhpd_desc *desc = of_device_get_match_data(dev); + struct rpmhpd **rpmhpds = desc->rpmhpds; + unsigned int corner; + struct rpmhpd *pd; + unsigned int i; + int ret; + + mutex_lock(&rpmhpd_lock); + for (i = 0; i < desc->num_pds; i++) { + pd = rpmhpds[i]; + if (!pd) + continue; + + pd->state_synced = true; + if (pd->enabled) + corner = max(pd->corner, pd->enable_corner); + else + corner = 0; + + ret = rpmhpd_aggregate_corner(pd, corner); + if (ret) + dev_err(dev, "failed to sync %s\n", pd->res_name); + } + mutex_unlock(&rpmhpd_lock); +} + static struct platform_driver rpmhpd_driver = { .driver = { .name = "qcom-rpmhpd", .of_match_table = rpmhpd_match_table, .suppress_bind_attrs = true, + .sync_state = rpmhpd_sync_state, }, .probe = rpmhpd_probe, }; diff --git a/drivers/soc/qcom/smd-rpm.c b/drivers/soc/qcom/smd-rpm.c index 413f9f4ae9cd..7e3b6a7ea34c 100644 --- a/drivers/soc/qcom/smd-rpm.c +++ b/drivers/soc/qcom/smd-rpm.c @@ -75,7 +75,7 @@ struct qcom_rpm_message { __le32 length; union { __le32 msg_id; - u8 message[0]; + DECLARE_FLEX_ARRAY(u8, message); }; }; @@ -246,6 +246,7 @@ static const struct of_device_id qcom_smd_rpm_of_match[] = { { .compatible = "qcom,rpm-sdm660" }, { .compatible = "qcom,rpm-sm6115" }, { .compatible = "qcom,rpm-sm6125" }, + { .compatible = "qcom,rpm-sm6375" }, { .compatible = "qcom,rpm-qcm2290" }, { .compatible = "qcom,rpm-qcs404" }, {} diff --git a/drivers/soc/qcom/smp2p.c b/drivers/soc/qcom/smp2p.c index d9c28a8a7cbf..e9c8030d50ee 100644 --- a/drivers/soc/qcom/smp2p.c +++ b/drivers/soc/qcom/smp2p.c @@ -422,7 +422,7 @@ static int qcom_smp2p_outbound_entry(struct qcom_smp2p *smp2p, char buf[SMP2P_MAX_ENTRY_NAME] = {}; /* Allocate an entry from the smem item */ - strlcpy(buf, entry->name, SMP2P_MAX_ENTRY_NAME); + strscpy(buf, entry->name, SMP2P_MAX_ENTRY_NAME); memcpy(out->entries[out->valid_entries].name, buf, SMP2P_MAX_ENTRY_NAME); /* Make the logical entry reference the physical value */ diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index aa37e1bad095..545934aead43 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -12,11 +12,14 @@ #include <linux/slab.h> #include <linux/soc/qcom/smem.h> #include <linux/string.h> +#include <linux/stringify.h> #include <linux/sys_soc.h> #include <linux/types.h> #include <asm/unaligned.h> +#include <dt-bindings/arm/qcom,ids.h> + /* * SoC version type with major number in the upper 16 bits and minor * number in the lower 16 bits. @@ -25,6 +28,10 @@ #define SOCINFO_MINOR(ver) ((ver) & 0xffff) #define SOCINFO_VERSION(maj, min) ((((maj) & 0xffff) << 16)|((min) & 0xffff)) +/* Helper macros to create soc_id table */ +#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 @@ -207,135 +214,141 @@ struct soc_id { }; static const struct soc_id soc_id[] = { - { 87, "MSM8960" }, - { 109, "APQ8064" }, - { 122, "MSM8660A" }, - { 123, "MSM8260A" }, - { 124, "APQ8060A" }, - { 126, "MSM8974" }, - { 130, "MPQ8064" }, - { 138, "MSM8960AB" }, - { 139, "APQ8060AB" }, - { 140, "MSM8260AB" }, - { 141, "MSM8660AB" }, - { 145, "MSM8626" }, - { 147, "MSM8610" }, - { 153, "APQ8064AB" }, - { 158, "MSM8226" }, - { 159, "MSM8526" }, - { 161, "MSM8110" }, - { 162, "MSM8210" }, - { 163, "MSM8810" }, - { 164, "MSM8212" }, - { 165, "MSM8612" }, - { 166, "MSM8112" }, - { 168, "MSM8225Q" }, - { 169, "MSM8625Q" }, - { 170, "MSM8125Q" }, - { 172, "APQ8064AA" }, - { 178, "APQ8084" }, - { 184, "APQ8074" }, - { 185, "MSM8274" }, - { 186, "MSM8674" }, - { 194, "MSM8974PRO-AC" }, - { 198, "MSM8126" }, - { 199, "APQ8026" }, - { 200, "MSM8926" }, - { 205, "MSM8326" }, - { 206, "MSM8916" }, - { 207, "MSM8994" }, - { 208, "APQ8074PRO-AA" }, - { 209, "APQ8074PRO-AB" }, - { 210, "APQ8074PRO-AC" }, - { 211, "MSM8274PRO-AA" }, - { 212, "MSM8274PRO-AB" }, - { 213, "MSM8274PRO-AC" }, - { 214, "MSM8674PRO-AA" }, - { 215, "MSM8674PRO-AB" }, - { 216, "MSM8674PRO-AC" }, - { 217, "MSM8974PRO-AA" }, - { 218, "MSM8974PRO-AB" }, - { 219, "APQ8028" }, - { 220, "MSM8128" }, - { 221, "MSM8228" }, - { 222, "MSM8528" }, - { 223, "MSM8628" }, - { 224, "MSM8928" }, - { 225, "MSM8510" }, - { 226, "MSM8512" }, - { 233, "MSM8936" }, - { 239, "MSM8939" }, - { 240, "APQ8036" }, - { 241, "APQ8039" }, - { 246, "MSM8996" }, - { 247, "APQ8016" }, - { 248, "MSM8216" }, - { 249, "MSM8116" }, - { 250, "MSM8616" }, - { 251, "MSM8992" }, - { 253, "APQ8094" }, - { 290, "MDM9607" }, - { 291, "APQ8096" }, - { 292, "MSM8998" }, - { 293, "MSM8953" }, - { 296, "MDM8207" }, - { 297, "MDM9207" }, - { 298, "MDM9307" }, - { 299, "MDM9628" }, - { 304, "APQ8053" }, - { 305, "MSM8996SG" }, - { 310, "MSM8996AU" }, - { 311, "APQ8096AU" }, - { 312, "APQ8096SG" }, - { 317, "SDM660" }, - { 318, "SDM630" }, - { 319, "APQ8098" }, - { 321, "SDM845" }, - { 322, "MDM9206" }, - { 323, "IPQ8074" }, - { 324, "SDA660" }, - { 325, "SDM658" }, - { 326, "SDA658" }, - { 327, "SDA630" }, - { 338, "SDM450" }, - { 341, "SDA845" }, - { 342, "IPQ8072" }, - { 343, "IPQ8076" }, - { 344, "IPQ8078" }, - { 345, "SDM636" }, - { 346, "SDA636" }, - { 349, "SDM632" }, - { 350, "SDA632" }, - { 351, "SDA450" }, - { 356, "SM8250" }, - { 375, "IPQ8070" }, - { 376, "IPQ8071" }, - { 389, "IPQ8072A" }, - { 390, "IPQ8074A" }, - { 391, "IPQ8076A" }, - { 392, "IPQ8078A" }, - { 394, "SM6125" }, - { 395, "IPQ8070A" }, - { 396, "IPQ8071A" }, - { 402, "IPQ6018" }, - { 403, "IPQ6028" }, - { 421, "IPQ6000" }, - { 422, "IPQ6010" }, - { 425, "SC7180" }, - { 434, "SM6350" }, - { 439, "SM8350" }, - { 449, "SC8280XP" }, - { 453, "IPQ6005" }, - { 455, "QRB5165" }, - { 457, "SM8450" }, - { 459, "SM7225" }, - { 460, "SA8295P" }, - { 461, "SA8540P" }, - { 480, "SM8450" }, - { 482, "SM8450" }, - { 487, "SC7280" }, - { 495, "SC7180P" }, - { 507, "SM6375" }, + { qcom_board_id(MSM8960) }, + { qcom_board_id(APQ8064) }, + { qcom_board_id(MSM8660A) }, + { qcom_board_id(MSM8260A) }, + { qcom_board_id(APQ8060A) }, + { qcom_board_id(MSM8974) }, + { qcom_board_id(MPQ8064) }, + { qcom_board_id(MSM8960AB) }, + { qcom_board_id(APQ8060AB) }, + { qcom_board_id(MSM8260AB) }, + { qcom_board_id(MSM8660AB) }, + { qcom_board_id(MSM8626) }, + { qcom_board_id(MSM8610) }, + { qcom_board_id(APQ8064AB) }, + { qcom_board_id(MSM8226) }, + { qcom_board_id(MSM8526) }, + { qcom_board_id(MSM8110) }, + { qcom_board_id(MSM8210) }, + { qcom_board_id(MSM8810) }, + { qcom_board_id(MSM8212) }, + { qcom_board_id(MSM8612) }, + { qcom_board_id(MSM8112) }, + { qcom_board_id(MSM8225Q) }, + { qcom_board_id(MSM8625Q) }, + { qcom_board_id(MSM8125Q) }, + { qcom_board_id(APQ8064AA) }, + { qcom_board_id(APQ8084) }, + { qcom_board_id(APQ8074) }, + { qcom_board_id(MSM8274) }, + { qcom_board_id(MSM8674) }, + { qcom_board_id_named(MSM8974PRO_AC, "MSM8974PRO-AC") }, + { qcom_board_id(MSM8126) }, + { qcom_board_id(APQ8026) }, + { qcom_board_id(MSM8926) }, + { qcom_board_id(MSM8326) }, + { qcom_board_id(MSM8916) }, + { qcom_board_id(MSM8994) }, + { qcom_board_id_named(APQ8074PRO_AA, "APQ8074PRO-AA") }, + { qcom_board_id_named(APQ8074PRO_AB, "APQ8074PRO-AB") }, + { qcom_board_id_named(APQ8074PRO_AC, "APQ8074PRO-AC") }, + { qcom_board_id_named(MSM8274PRO_AA, "MSM8274PRO-AA") }, + { qcom_board_id_named(MSM8274PRO_AB, "MSM8274PRO-AB") }, + { qcom_board_id_named(MSM8274PRO_AC, "MSM8274PRO-AC") }, + { qcom_board_id_named(MSM8674PRO_AA, "MSM8674PRO-AA") }, + { qcom_board_id_named(MSM8674PRO_AB, "MSM8674PRO-AB") }, + { qcom_board_id_named(MSM8674PRO_AC, "MSM8674PRO-AC") }, + { qcom_board_id_named(MSM8974PRO_AA, "MSM8974PRO-AA") }, + { qcom_board_id_named(MSM8974PRO_AB, "MSM8974PRO-AB") }, + { qcom_board_id(APQ8028) }, + { qcom_board_id(MSM8128) }, + { qcom_board_id(MSM8228) }, + { qcom_board_id(MSM8528) }, + { qcom_board_id(MSM8628) }, + { qcom_board_id(MSM8928) }, + { qcom_board_id(MSM8510) }, + { qcom_board_id(MSM8512) }, + { qcom_board_id(MSM8936) }, + { qcom_board_id(MSM8939) }, + { qcom_board_id(APQ8036) }, + { qcom_board_id(APQ8039) }, + { qcom_board_id(MSM8996) }, + { qcom_board_id(APQ8016) }, + { qcom_board_id(MSM8216) }, + { qcom_board_id(MSM8116) }, + { qcom_board_id(MSM8616) }, + { qcom_board_id(MSM8992) }, + { qcom_board_id(APQ8094) }, + { qcom_board_id(MDM9607) }, + { qcom_board_id(APQ8096) }, + { qcom_board_id(MSM8998) }, + { qcom_board_id(MSM8953) }, + { qcom_board_id(MDM8207) }, + { qcom_board_id(MDM9207) }, + { qcom_board_id(MDM9307) }, + { qcom_board_id(MDM9628) }, + { qcom_board_id(APQ8053) }, + { qcom_board_id(MSM8996SG) }, + { qcom_board_id(MSM8996AU) }, + { qcom_board_id(APQ8096AU) }, + { qcom_board_id(APQ8096SG) }, + { qcom_board_id(SDM660) }, + { qcom_board_id(SDM630) }, + { qcom_board_id(APQ8098) }, + { qcom_board_id(SDM845) }, + { qcom_board_id(MDM9206) }, + { qcom_board_id(IPQ8074) }, + { qcom_board_id(SDA660) }, + { qcom_board_id(SDM658) }, + { qcom_board_id(SDA658) }, + { qcom_board_id(SDA630) }, + { qcom_board_id(SDM450) }, + { qcom_board_id(SDA845) }, + { qcom_board_id(IPQ8072) }, + { qcom_board_id(IPQ8076) }, + { qcom_board_id(IPQ8078) }, + { qcom_board_id(SDM636) }, + { qcom_board_id(SDA636) }, + { qcom_board_id(SDM632) }, + { qcom_board_id(SDA632) }, + { qcom_board_id(SDA450) }, + { qcom_board_id(SM8250) }, + { qcom_board_id(IPQ8070) }, + { qcom_board_id(IPQ8071) }, + { qcom_board_id(IPQ8072A) }, + { qcom_board_id(IPQ8074A) }, + { qcom_board_id(IPQ8076A) }, + { qcom_board_id(IPQ8078A) }, + { qcom_board_id(SM6125) }, + { qcom_board_id(IPQ8070A) }, + { qcom_board_id(IPQ8071A) }, + { qcom_board_id(IPQ6018) }, + { qcom_board_id(IPQ6028) }, + { qcom_board_id(IPQ6000) }, + { qcom_board_id(IPQ6010) }, + { qcom_board_id(SC7180) }, + { qcom_board_id(SM6350) }, + { qcom_board_id(SM8350) }, + { qcom_board_id(SC8280XP) }, + { qcom_board_id(IPQ6005) }, + { qcom_board_id(QRB5165) }, + { qcom_board_id(SM8450) }, + { qcom_board_id(SM7225) }, + { qcom_board_id(SA8295P) }, + { qcom_board_id(SA8540P) }, + { qcom_board_id_named(SM8450_2, "SM8450") }, + { qcom_board_id_named(SM8450_3, "SM8450") }, + { qcom_board_id(SC7280) }, + { qcom_board_id(SC7180P) }, + { qcom_board_id(SM6375) }, + { qcom_board_id(QRU1000) }, + { qcom_board_id(QDU1000) }, + { qcom_board_id(QDU1010) }, + { qcom_board_id(QRU1032) }, + { qcom_board_id(QRU1052) }, + { qcom_board_id(QRU1062) }, }; static const char *socinfo_machine(struct device *dev, unsigned int id) diff --git a/drivers/soc/qcom/spm.c b/drivers/soc/qcom/spm.c index 484b42b7454e..a6cbeb40831b 100644 --- a/drivers/soc/qcom/spm.c +++ b/drivers/soc/qcom/spm.c @@ -98,6 +98,46 @@ static const struct spm_reg_data spm_reg_8916_cpu = { .start_index[PM_SLEEP_MODE_SPC] = 5, }; +static const struct spm_reg_data spm_reg_8939_cpu = { + .reg_offset = spm_reg_offset_v3_0, + .spm_cfg = 0x1, + .spm_dly = 0x3C102800, + .seq = { 0x60, 0x03, 0x60, 0x0B, 0x0F, 0x20, 0x50, 0x1B, 0x10, 0x80, + 0x30, 0x90, 0x5B, 0x60, 0x50, 0x03, 0x60, 0x76, 0x76, 0x0B, + 0x50, 0x1B, 0x94, 0x5B, 0x80, 0x10, 0x26, 0x30, 0x50, 0x0F }, + .start_index[PM_SLEEP_MODE_STBY] = 0, + .start_index[PM_SLEEP_MODE_SPC] = 5, +}; + +static const u16 spm_reg_offset_v2_3[SPM_REG_NR] = { + [SPM_REG_CFG] = 0x08, + [SPM_REG_SPM_CTL] = 0x30, + [SPM_REG_DLY] = 0x34, + [SPM_REG_PMIC_DATA_0] = 0x40, + [SPM_REG_PMIC_DATA_1] = 0x44, +}; + +/* SPM register data for 8976 */ +static const struct spm_reg_data spm_reg_8976_gold_l2 = { + .reg_offset = spm_reg_offset_v2_3, + .spm_cfg = 0x14, + .spm_dly = 0x3c11840a, + .pmic_data[0] = 0x03030080, + .pmic_data[1] = 0x00030000, + .start_index[PM_SLEEP_MODE_STBY] = 0, + .start_index[PM_SLEEP_MODE_SPC] = 3, +}; + +static const struct spm_reg_data spm_reg_8976_silver_l2 = { + .reg_offset = spm_reg_offset_v2_3, + .spm_cfg = 0x14, + .spm_dly = 0x3c102800, + .pmic_data[0] = 0x03030080, + .pmic_data[1] = 0x00030000, + .start_index[PM_SLEEP_MODE_STBY] = 0, + .start_index[PM_SLEEP_MODE_SPC] = 2, +}; + static const u16 spm_reg_offset_v2_1[SPM_REG_NR] = { [SPM_REG_CFG] = 0x08, [SPM_REG_SPM_CTL] = 0x30, @@ -211,8 +251,14 @@ static const struct of_device_id spm_match_table[] = { .data = &spm_reg_8909_cpu }, { .compatible = "qcom,msm8916-saw2-v3.0-cpu", .data = &spm_reg_8916_cpu }, + { .compatible = "qcom,msm8939-saw2-v3.0-cpu", + .data = &spm_reg_8939_cpu }, { .compatible = "qcom,msm8974-saw2-v2.1-cpu", .data = &spm_reg_8974_8084_cpu }, + { .compatible = "qcom,msm8976-gold-saw2-v2.3-l2", + .data = &spm_reg_8976_gold_l2 }, + { .compatible = "qcom,msm8976-silver-saw2-v2.3-l2", + .data = &spm_reg_8976_silver_l2 }, { .compatible = "qcom,msm8998-gold-saw2-v4.1-l2", .data = &spm_reg_8998_gold_l2 }, { .compatible = "qcom,msm8998-silver-saw2-v4.1-l2", |