Loading arch/arm64/boot/dts/qcom/sm8150-npu.dtsi +1 −0 Original line number Original line Diff line number Diff line Loading @@ -71,6 +71,7 @@ mbox-names = "aop"; mbox-names = "aop"; #cooling-cells = <2>; #cooling-cells = <2>; qcom,npubw-dev = <&npu_npu_ddr_bw>; qcom,npubw-dev = <&npu_npu_ddr_bw>; qcom,npu-cxlimit-enable; qcom,npu-pwrlevels { qcom,npu-pwrlevels { #address-cells = <1>; #address-cells = <1>; #size-cells = <0>; #size-cells = <0>; Loading drivers/media/platform/msm/npu/npu_common.h +6 −2 Original line number Original line Diff line number Diff line Loading @@ -55,8 +55,8 @@ enum npu_power_level { NPU_PWRLEVEL_LOWSVS, NPU_PWRLEVEL_LOWSVS, NPU_PWRLEVEL_SVS, NPU_PWRLEVEL_SVS, NPU_PWRLEVEL_SVS_L1, NPU_PWRLEVEL_SVS_L1, NPU_PWRLEVEL_NORM, NPU_PWRLEVEL_NOM, NPU_PWRLEVEL_NORM_L1, NPU_PWRLEVEL_NOM_L1, NPU_PWRLEVEL_TURBO, NPU_PWRLEVEL_TURBO, NPU_PWRLEVEL_TURBO_L1, NPU_PWRLEVEL_TURBO_L1, NPU_PWRLEVEL_OFF = 0xFFFFFFFF, NPU_PWRLEVEL_OFF = 0xFFFFFFFF, Loading Loading @@ -148,6 +148,7 @@ struct npu_reg { * @max_pwrlevel - maximum allowable powerlevel per the user * @max_pwrlevel - maximum allowable powerlevel per the user * @min_pwrlevel - minimum allowable powerlevel per the user * @min_pwrlevel - minimum allowable powerlevel per the user * @num_pwrlevels - number of available power levels * @num_pwrlevels - number of available power levels * @cdsprm_pwrlevel - maximum power level from cdsprm * @fmax_pwrlevel - maximum power level from qfprom fmax setting * @fmax_pwrlevel - maximum power level from qfprom fmax setting * @uc_pwrlevel - power level from user driver setting * @uc_pwrlevel - power level from user driver setting * @perf_mode_override - perf mode from sysfs to override perf mode * @perf_mode_override - perf mode from sysfs to override perf mode Loading @@ -167,6 +168,7 @@ struct npu_pwrctrl { struct device *devbw; struct device *devbw; uint32_t bwmon_enabled; uint32_t bwmon_enabled; uint32_t uc_pwrlevel; uint32_t uc_pwrlevel; uint32_t cdsprm_pwrlevel; uint32_t fmax_pwrlevel; uint32_t fmax_pwrlevel; uint32_t perf_mode_override; uint32_t perf_mode_override; }; }; Loading Loading @@ -231,6 +233,7 @@ struct npu_device { struct llcc_slice_desc *sys_cache; struct llcc_slice_desc *sys_cache; uint32_t execute_v2_flag; uint32_t execute_v2_flag; bool cxlimit_registered; }; }; struct npu_kevent { struct npu_kevent { Loading Loading @@ -267,5 +270,6 @@ int npu_set_uc_power_level(struct npu_device *npu_dev, int fw_init(struct npu_device *npu_dev); int fw_init(struct npu_device *npu_dev); void fw_deinit(struct npu_device *npu_dev, bool ssr); void fw_deinit(struct npu_device *npu_dev, bool ssr); int npu_notify_cdsprm_cxlimit_activity(struct npu_device *npu_dev, bool enable); #endif /* _NPU_COMMON_H */ #endif /* _NPU_COMMON_H */ drivers/media/platform/msm/npu/npu_dev.c +222 −18 Original line number Original line Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h> #include <linux/thermal.h> #include <linux/thermal.h> #include <linux/soc/qcom/llcc-qcom.h> #include <linux/soc/qcom/llcc-qcom.h> #include <linux/soc/qcom/cdsprm_cxlimit.h> #include <soc/qcom/devfreq_devbw.h> #include <soc/qcom/devfreq_devbw.h> #include "npu_common.h" #include "npu_common.h" Loading Loading @@ -109,7 +110,9 @@ static int npu_suspend(struct platform_device *dev, pm_message_t state); static int npu_resume(struct platform_device *dev); static int npu_resume(struct platform_device *dev); static int __init npu_init(void); static int __init npu_init(void); static void __exit npu_exit(void); static void __exit npu_exit(void); static int npu_set_power_level(struct npu_device *npu_dev); static int npu_set_power_level(struct npu_device *npu_dev, bool notify_cxlimit); static uint32_t npu_notify_cdsprm_cxlimit_corner(struct npu_device *npu_dev, uint32_t pwr_lvl); /* ------------------------------------------------------------------------- /* ------------------------------------------------------------------------- * File Scope Variables * File Scope Variables Loading Loading @@ -175,6 +178,8 @@ static const struct npu_irq npu_irq_info[NPU_MAX_IRQ] = { {"wdg_bite_irq", 0, IRQF_TRIGGER_RISING | IRQF_ONESHOT}, {"wdg_bite_irq", 0, IRQF_TRIGGER_RISING | IRQF_ONESHOT}, }; }; static struct npu_device *g_npu_dev; /* ------------------------------------------------------------------------- /* ------------------------------------------------------------------------- * Entry Points for Probe * Entry Points for Probe * ------------------------------------------------------------------------- * ------------------------------------------------------------------------- Loading Loading @@ -320,7 +325,7 @@ static ssize_t npu_store_perf_mode_override(struct device *dev, val = min(val, npu_dev->pwrctrl.num_pwrlevels); val = min(val, npu_dev->pwrctrl.num_pwrlevels); npu_dev->pwrctrl.perf_mode_override = val; npu_dev->pwrctrl.perf_mode_override = val; pr_info("setting uc_pwrlevel_override to %d\n", val); pr_info("setting uc_pwrlevel_override to %d\n", val); npu_set_power_level(npu_dev); npu_set_power_level(npu_dev, true); return count; return count; } } Loading @@ -329,6 +334,168 @@ static ssize_t npu_store_perf_mode_override(struct device *dev, * Power Related * Power Related * ------------------------------------------------------------------------- * ------------------------------------------------------------------------- */ */ static enum npu_power_level cdsprm_corner_to_npu_power_level( enum cdsprm_npu_corner corner) { enum npu_power_level pwr_lvl = NPU_PWRLEVEL_TURBO_L1; switch (corner) { case CDSPRM_NPU_CLK_OFF: pwr_lvl = NPU_PWRLEVEL_OFF; break; case CDSPRM_NPU_MIN_SVS: pwr_lvl = NPU_PWRLEVEL_MINSVS; break; case CDSPRM_NPU_LOW_SVS: pwr_lvl = NPU_PWRLEVEL_LOWSVS; break; case CDSPRM_NPU_SVS: pwr_lvl = NPU_PWRLEVEL_SVS; break; case CDSPRM_NPU_SVS_L1: pwr_lvl = NPU_PWRLEVEL_SVS_L1; break; case CDSPRM_NPU_NOM: pwr_lvl = NPU_PWRLEVEL_NOM; break; case CDSPRM_NPU_NOM_L1: pwr_lvl = NPU_PWRLEVEL_NOM_L1; break; case CDSPRM_NPU_TURBO: pwr_lvl = NPU_PWRLEVEL_TURBO; break; case CDSPRM_NPU_TURBO_L1: default: pwr_lvl = NPU_PWRLEVEL_TURBO_L1; break; } return pwr_lvl; } static enum cdsprm_npu_corner npu_power_level_to_cdsprm_corner( enum npu_power_level pwr_lvl) { enum cdsprm_npu_corner corner = CDSPRM_NPU_MIN_SVS; switch (pwr_lvl) { case NPU_PWRLEVEL_OFF: corner = CDSPRM_NPU_CLK_OFF; break; case NPU_PWRLEVEL_MINSVS: corner = CDSPRM_NPU_MIN_SVS; break; case NPU_PWRLEVEL_LOWSVS: corner = CDSPRM_NPU_LOW_SVS; break; case NPU_PWRLEVEL_SVS: corner = CDSPRM_NPU_SVS; break; case NPU_PWRLEVEL_SVS_L1: corner = CDSPRM_NPU_SVS_L1; break; case NPU_PWRLEVEL_NOM: corner = CDSPRM_NPU_NOM; break; case NPU_PWRLEVEL_NOM_L1: corner = CDSPRM_NPU_NOM_L1; break; case NPU_PWRLEVEL_TURBO: corner = CDSPRM_NPU_TURBO; break; case NPU_PWRLEVEL_TURBO_L1: default: corner = CDSPRM_NPU_TURBO_L1; break; } return corner; } static int npu_set_cdsprm_corner_limit(enum cdsprm_npu_corner corner) { struct npu_pwrctrl *pwr; enum npu_power_level pwr_lvl; if (!g_npu_dev) return 0; pwr = &g_npu_dev->pwrctrl; pwr_lvl = cdsprm_corner_to_npu_power_level(corner); pwr->cdsprm_pwrlevel = pwr_lvl; pr_debug("power level from cdsp %d\n", pwr_lvl); return npu_set_power_level(g_npu_dev, false); } const struct cdsprm_npu_limit_cbs cdsprm_npu_limit_cbs = { .set_corner_limit = npu_set_cdsprm_corner_limit, }; int npu_notify_cdsprm_cxlimit_activity(struct npu_device *npu_dev, bool enable) { if (!npu_dev->cxlimit_registered) return 0; pr_debug("notify cxlimit %s activity\n", enable ? "enable" : "disable"); return cdsprm_cxlimit_npu_activity_notify(enable ? 1 : 0); } static uint32_t npu_notify_cdsprm_cxlimit_corner( struct npu_device *npu_dev, uint32_t pwr_lvl) { uint32_t corner, pwr_lvl_to_set; if (!npu_dev->cxlimit_registered) return pwr_lvl; corner = npu_power_level_to_cdsprm_corner(pwr_lvl); corner = cdsprm_cxlimit_npu_corner_notify(corner); pwr_lvl_to_set = cdsprm_corner_to_npu_power_level(corner); pr_debug("Notify cdsprm %d:%d\n", pwr_lvl, pwr_lvl_to_set); return pwr_lvl_to_set; } int npu_cdsprm_cxlimit_init(struct npu_device *npu_dev) { bool enabled; int ret = 0; enabled = of_property_read_bool(npu_dev->pdev->dev.of_node, "qcom,npu-cxlimit-enable"); pr_debug("qcom,npu-xclimit-enable is %s\n", enabled ? "true" : "false"); npu_dev->cxlimit_registered = false; if (enabled) { ret = cdsprm_cxlimit_npu_limit_register(&cdsprm_npu_limit_cbs); if (ret) { pr_err("register cxlimit npu limit failed\n"); } else { pr_debug("register cxlimit npu limit succeeds\n"); npu_dev->cxlimit_registered = true; } } return ret; } int npu_cdsprm_cxlimit_deinit(struct npu_device *npu_dev) { int ret = 0; if (npu_dev->cxlimit_registered) { ret = cdsprm_cxlimit_npu_limit_deregister(); if (ret) pr_err("deregister cxlimit npu limit failed\n"); npu_dev->cxlimit_registered = false; } return ret; } int npu_enable_core_power(struct npu_device *npu_dev) int npu_enable_core_power(struct npu_device *npu_dev) { { struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; Loading Loading @@ -366,6 +533,7 @@ void npu_disable_core_power(struct npu_device *npu_dev) npu_disable_regulators(npu_dev); npu_disable_regulators(npu_dev); pwr->active_pwrlevel = thermalctrl->pwr_level; pwr->active_pwrlevel = thermalctrl->pwr_level; pwr->uc_pwrlevel = pwr->max_pwrlevel; pwr->uc_pwrlevel = pwr->max_pwrlevel; pwr->cdsprm_pwrlevel = pwr->max_pwrlevel; pr_debug("setting back to power level=%d\n", pr_debug("setting back to power level=%d\n", pwr->active_pwrlevel); pwr->active_pwrlevel); } } Loading Loading @@ -432,37 +600,44 @@ static uint32_t npu_calc_power_level(struct npu_device *npu_dev) uc_pwr_level = npu_power_level_from_index(npu_dev, uc_pwr_level = npu_power_level_from_index(npu_dev, npu_dev->pwrctrl.perf_mode_override - 1); npu_dev->pwrctrl.perf_mode_override - 1); /* if thermal power is higher than usecase power /* * leave level at use case. Otherwise go down to * pick the lowese power level between thermal power and usecase power * thermal power level * settings */ */ if (therm_pwr_level > uc_pwr_level) ret_level = min(therm_pwr_level, uc_pwr_level); ret_level = uc_pwr_level; pr_debug("%s therm=%d active=%d uc=%d set level=%d\n", else __func__, therm_pwr_level, active_pwr_level, uc_pwr_level, ret_level = therm_pwr_level; ret_level); pr_debug("%s therm=%d active=%d uc=%d set level=%d\n", __func__, therm_pwr_level, active_pwr_level, uc_pwr_level, ret_level); return ret_level; return ret_level; } } static int npu_set_power_level(struct npu_device *npu_dev) static int npu_set_power_level(struct npu_device *npu_dev, bool notify_cxlimit) { { struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; struct npu_pwrlevel *pwrlevel; struct npu_pwrlevel *pwrlevel; int i, ret = 0; int i, ret = 0; uint32_t pwr_level_to_set, pwr_level_idx; uint32_t pwr_level_to_set, pwr_level_to_cdsprm, pwr_level_idx; /* get power level to set */ /* get power level to set */ pwr_level_to_set = npu_calc_power_level(npu_dev); pwr_level_to_set = npu_calc_power_level(npu_dev); pwr_level_to_cdsprm = pwr_level_to_set; if (!pwr->pwr_vote_num) { if (!pwr->pwr_vote_num) { pr_debug("power is not enabled during set request\n"); pr_debug("power is not enabled during set request\n"); pwr->active_pwrlevel = pwr_level_to_set; pwr->active_pwrlevel = min(pwr_level_to_set, npu_dev->pwrctrl.cdsprm_pwrlevel); return 0; return 0; } } /* notify cxlimit to get allowed power level */ if ((pwr_level_to_set > pwr->active_pwrlevel) && notify_cxlimit) pwr_level_to_set = npu_notify_cdsprm_cxlimit_corner( npu_dev, pwr_level_to_cdsprm); pwr_level_to_set = min(pwr_level_to_set, npu_dev->pwrctrl.cdsprm_pwrlevel); /* if the same as current, dont do anything */ /* if the same as current, dont do anything */ if (pwr_level_to_set == pwr->active_pwrlevel) { if (pwr_level_to_set == pwr->active_pwrlevel) { pr_debug("power level %d doesn't change\n", pwr_level_to_set); pr_debug("power level %d doesn't change\n", pwr_level_to_set); Loading Loading @@ -497,6 +672,12 @@ static int npu_set_power_level(struct npu_device *npu_dev) } } } } if ((pwr_level_to_cdsprm < pwr->active_pwrlevel) && notify_cxlimit) { npu_notify_cdsprm_cxlimit_corner(npu_dev, pwr_level_to_cdsprm); pr_debug("Notify cdsprm(post) %d\n", pwr_level_to_cdsprm); } pwr->active_pwrlevel = pwr_level_to_set; pwr->active_pwrlevel = pwr_level_to_set; return ret; return ret; } } Loading @@ -517,7 +698,7 @@ int npu_set_uc_power_level(struct npu_device *npu_dev, uc_pwrlevel_to_set = pwr->max_pwrlevel; uc_pwrlevel_to_set = pwr->max_pwrlevel; pwr->uc_pwrlevel = uc_pwrlevel_to_set; pwr->uc_pwrlevel = uc_pwrlevel_to_set; return npu_set_power_level(npu_dev); return npu_set_power_level(npu_dev, true); } } /* ------------------------------------------------------------------------- /* ------------------------------------------------------------------------- Loading Loading @@ -619,6 +800,13 @@ static int npu_enable_clocks(struct npu_device *npu_dev, bool post_pil) uint32_t pwrlevel_to_set, pwrlevel_idx; uint32_t pwrlevel_to_set, pwrlevel_idx; pwrlevel_to_set = pwr->active_pwrlevel; pwrlevel_to_set = pwr->active_pwrlevel; if (!post_pil) { pwrlevel_to_set = npu_notify_cdsprm_cxlimit_corner( npu_dev, pwrlevel_to_set); pr_debug("Notify cdsprm %d\n", pwrlevel_to_set); pwr->active_pwrlevel = pwrlevel_to_set; } pwrlevel_idx = npu_power_level_to_index(npu_dev, pwrlevel_to_set); pwrlevel_idx = npu_power_level_to_index(npu_dev, pwrlevel_to_set); pwrlevel = &pwr->pwrlevels[pwrlevel_idx]; pwrlevel = &pwr->pwrlevels[pwrlevel_idx]; for (i = 0; i < ARRAY_SIZE(npu_clock_order); i++) { for (i = 0; i < ARRAY_SIZE(npu_clock_order); i++) { Loading Loading @@ -684,6 +872,11 @@ static void npu_disable_clocks(struct npu_device *npu_dev, bool post_pil) int i = 0; int i = 0; struct npu_clk *core_clks = npu_dev->core_clks; struct npu_clk *core_clks = npu_dev->core_clks; if (!post_pil) { npu_notify_cdsprm_cxlimit_corner(npu_dev, NPU_PWRLEVEL_OFF); pr_debug("Notify cdsprm clock off\n"); } for (i = ARRAY_SIZE(npu_clock_order) - 1; i >= 0 ; i--) { for (i = ARRAY_SIZE(npu_clock_order) - 1; i >= 0 ; i--) { if (!core_clks[i].clk) if (!core_clks[i].clk) continue; continue; Loading Loading @@ -747,7 +940,7 @@ npu_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) thermal->pwr_level = npu_power_level_from_index(npu_dev, thermal->pwr_level = npu_power_level_from_index(npu_dev, thermal->max_state - state); thermal->max_state - state); return npu_set_power_level(npu_dev); return npu_set_power_level(npu_dev, true); } } /* ------------------------------------------------------------------------- /* ------------------------------------------------------------------------- Loading Loading @@ -1534,7 +1727,7 @@ static int npu_of_parse_pwrlevels(struct npu_device *npu_dev, switch (fmax) { switch (fmax) { case 1: case 1: case 2: case 2: fmax_pwrlvl = NPU_PWRLEVEL_NORM; fmax_pwrlvl = NPU_PWRLEVEL_NOM; break; break; case 3: case 3: fmax_pwrlvl = NPU_PWRLEVEL_SVS_L1; fmax_pwrlvl = NPU_PWRLEVEL_SVS_L1; Loading Loading @@ -1566,6 +1759,7 @@ static int npu_of_parse_pwrlevels(struct npu_device *npu_dev, pwr->active_pwrlevel = pwr->default_pwrlevel = init_power_level; pwr->active_pwrlevel = pwr->default_pwrlevel = init_power_level; pwr->uc_pwrlevel = pwr->max_pwrlevel; pwr->uc_pwrlevel = pwr->max_pwrlevel; pwr->perf_mode_override = 0; pwr->perf_mode_override = 0; pwr->cdsprm_pwrlevel = pwr->max_pwrlevel; return 0; return 0; } } Loading Loading @@ -1811,6 +2005,10 @@ static int npu_probe(struct platform_device *pdev) thermal_cdev_update(tcdev); thermal_cdev_update(tcdev); } } rc = npu_cdsprm_cxlimit_init(npu_dev); if (rc) goto error_driver_init; rc = npu_debugfs_init(npu_dev); rc = npu_debugfs_init(npu_dev); if (rc) if (rc) goto error_driver_init; goto error_driver_init; Loading Loading @@ -1840,8 +2038,11 @@ static int npu_probe(struct platform_device *pdev) goto error_driver_init; goto error_driver_init; } } g_npu_dev = npu_dev; return rc; return rc; error_driver_init: error_driver_init: npu_cdsprm_cxlimit_deinit(npu_dev); sysfs_remove_group(&npu_dev->device->kobj, &npu_fs_attr_group); sysfs_remove_group(&npu_dev->device->kobj, &npu_fs_attr_group); arm_iommu_detach_device(&(npu_dev->pdev->dev)); arm_iommu_detach_device(&(npu_dev->pdev->dev)); if (!npu_dev->smmu_ctx.mmu_mapping) if (!npu_dev->smmu_ctx.mmu_mapping) Loading @@ -1867,6 +2068,7 @@ static int npu_remove(struct platform_device *pdev) npu_dev = platform_get_drvdata(pdev); npu_dev = platform_get_drvdata(pdev); thermal_cooling_device_unregister(npu_dev->tcdev); thermal_cooling_device_unregister(npu_dev->tcdev); npu_cdsprm_cxlimit_deinit(npu_dev); npu_debugfs_deinit(npu_dev); npu_debugfs_deinit(npu_dev); npu_host_deinit(npu_dev); npu_host_deinit(npu_dev); arm_iommu_detach_device(&(npu_dev->pdev->dev)); arm_iommu_detach_device(&(npu_dev->pdev->dev)); Loading @@ -1880,6 +2082,8 @@ static int npu_remove(struct platform_device *pdev) if (npu_dev->mbox_aop.chan) if (npu_dev->mbox_aop.chan) mbox_free_channel(npu_dev->mbox_aop.chan); mbox_free_channel(npu_dev->mbox_aop.chan); g_npu_dev = NULL; return 0; return 0; } } Loading drivers/media/platform/msm/npu/npu_mgr.c +12 −0 Original line number Original line Diff line number Diff line Loading @@ -1424,6 +1424,9 @@ int32_t npu_host_exec_network(struct npu_client *client, return -EINVAL; return -EINVAL; } } if (atomic_inc_return(&host_ctx->network_exeute_cnt) == 1) npu_notify_cdsprm_cxlimit_activity(npu_dev, true); if (!network->is_active) { if (!network->is_active) { pr_err("network is not active\n"); pr_err("network is not active\n"); ret = -EINVAL; ret = -EINVAL; Loading Loading @@ -1528,6 +1531,9 @@ int32_t npu_host_exec_network(struct npu_client *client, host_error_hdlr(npu_dev, true); host_error_hdlr(npu_dev, true); } } if (atomic_dec_return(&host_ctx->network_exeute_cnt) == 0) npu_notify_cdsprm_cxlimit_activity(npu_dev, false); return ret; return ret; } } Loading @@ -1553,6 +1559,9 @@ int32_t npu_host_exec_network_v2(struct npu_client *client, return -EINVAL; return -EINVAL; } } if (atomic_inc_return(&host_ctx->network_exeute_cnt) == 1) npu_notify_cdsprm_cxlimit_activity(npu_dev, true); if (!network->is_active) { if (!network->is_active) { pr_err("network is not active\n"); pr_err("network is not active\n"); ret = -EINVAL; ret = -EINVAL; Loading Loading @@ -1679,6 +1688,9 @@ int32_t npu_host_exec_network_v2(struct npu_client *client, host_error_hdlr(npu_dev, true); host_error_hdlr(npu_dev, true); } } if (atomic_dec_return(&host_ctx->network_exeute_cnt) == 0) npu_notify_cdsprm_cxlimit_activity(npu_dev, false); return ret; return ret; } } Loading drivers/media/platform/msm/npu/npu_mgr.h +1 −0 Original line number Original line Diff line number Diff line Loading @@ -87,6 +87,7 @@ struct npu_host_ctx { uint32_t fw_dbg_mode; uint32_t fw_dbg_mode; uint32_t exec_flags_override; uint32_t exec_flags_override; atomic_t ipc_trans_id; atomic_t ipc_trans_id; atomic_t network_exeute_cnt; uint32_t err_irq_sts; uint32_t err_irq_sts; uint32_t wdg_irq_sts; uint32_t wdg_irq_sts; Loading Loading
arch/arm64/boot/dts/qcom/sm8150-npu.dtsi +1 −0 Original line number Original line Diff line number Diff line Loading @@ -71,6 +71,7 @@ mbox-names = "aop"; mbox-names = "aop"; #cooling-cells = <2>; #cooling-cells = <2>; qcom,npubw-dev = <&npu_npu_ddr_bw>; qcom,npubw-dev = <&npu_npu_ddr_bw>; qcom,npu-cxlimit-enable; qcom,npu-pwrlevels { qcom,npu-pwrlevels { #address-cells = <1>; #address-cells = <1>; #size-cells = <0>; #size-cells = <0>; Loading
drivers/media/platform/msm/npu/npu_common.h +6 −2 Original line number Original line Diff line number Diff line Loading @@ -55,8 +55,8 @@ enum npu_power_level { NPU_PWRLEVEL_LOWSVS, NPU_PWRLEVEL_LOWSVS, NPU_PWRLEVEL_SVS, NPU_PWRLEVEL_SVS, NPU_PWRLEVEL_SVS_L1, NPU_PWRLEVEL_SVS_L1, NPU_PWRLEVEL_NORM, NPU_PWRLEVEL_NOM, NPU_PWRLEVEL_NORM_L1, NPU_PWRLEVEL_NOM_L1, NPU_PWRLEVEL_TURBO, NPU_PWRLEVEL_TURBO, NPU_PWRLEVEL_TURBO_L1, NPU_PWRLEVEL_TURBO_L1, NPU_PWRLEVEL_OFF = 0xFFFFFFFF, NPU_PWRLEVEL_OFF = 0xFFFFFFFF, Loading Loading @@ -148,6 +148,7 @@ struct npu_reg { * @max_pwrlevel - maximum allowable powerlevel per the user * @max_pwrlevel - maximum allowable powerlevel per the user * @min_pwrlevel - minimum allowable powerlevel per the user * @min_pwrlevel - minimum allowable powerlevel per the user * @num_pwrlevels - number of available power levels * @num_pwrlevels - number of available power levels * @cdsprm_pwrlevel - maximum power level from cdsprm * @fmax_pwrlevel - maximum power level from qfprom fmax setting * @fmax_pwrlevel - maximum power level from qfprom fmax setting * @uc_pwrlevel - power level from user driver setting * @uc_pwrlevel - power level from user driver setting * @perf_mode_override - perf mode from sysfs to override perf mode * @perf_mode_override - perf mode from sysfs to override perf mode Loading @@ -167,6 +168,7 @@ struct npu_pwrctrl { struct device *devbw; struct device *devbw; uint32_t bwmon_enabled; uint32_t bwmon_enabled; uint32_t uc_pwrlevel; uint32_t uc_pwrlevel; uint32_t cdsprm_pwrlevel; uint32_t fmax_pwrlevel; uint32_t fmax_pwrlevel; uint32_t perf_mode_override; uint32_t perf_mode_override; }; }; Loading Loading @@ -231,6 +233,7 @@ struct npu_device { struct llcc_slice_desc *sys_cache; struct llcc_slice_desc *sys_cache; uint32_t execute_v2_flag; uint32_t execute_v2_flag; bool cxlimit_registered; }; }; struct npu_kevent { struct npu_kevent { Loading Loading @@ -267,5 +270,6 @@ int npu_set_uc_power_level(struct npu_device *npu_dev, int fw_init(struct npu_device *npu_dev); int fw_init(struct npu_device *npu_dev); void fw_deinit(struct npu_device *npu_dev, bool ssr); void fw_deinit(struct npu_device *npu_dev, bool ssr); int npu_notify_cdsprm_cxlimit_activity(struct npu_device *npu_dev, bool enable); #endif /* _NPU_COMMON_H */ #endif /* _NPU_COMMON_H */
drivers/media/platform/msm/npu/npu_dev.c +222 −18 Original line number Original line Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h> #include <linux/thermal.h> #include <linux/thermal.h> #include <linux/soc/qcom/llcc-qcom.h> #include <linux/soc/qcom/llcc-qcom.h> #include <linux/soc/qcom/cdsprm_cxlimit.h> #include <soc/qcom/devfreq_devbw.h> #include <soc/qcom/devfreq_devbw.h> #include "npu_common.h" #include "npu_common.h" Loading Loading @@ -109,7 +110,9 @@ static int npu_suspend(struct platform_device *dev, pm_message_t state); static int npu_resume(struct platform_device *dev); static int npu_resume(struct platform_device *dev); static int __init npu_init(void); static int __init npu_init(void); static void __exit npu_exit(void); static void __exit npu_exit(void); static int npu_set_power_level(struct npu_device *npu_dev); static int npu_set_power_level(struct npu_device *npu_dev, bool notify_cxlimit); static uint32_t npu_notify_cdsprm_cxlimit_corner(struct npu_device *npu_dev, uint32_t pwr_lvl); /* ------------------------------------------------------------------------- /* ------------------------------------------------------------------------- * File Scope Variables * File Scope Variables Loading Loading @@ -175,6 +178,8 @@ static const struct npu_irq npu_irq_info[NPU_MAX_IRQ] = { {"wdg_bite_irq", 0, IRQF_TRIGGER_RISING | IRQF_ONESHOT}, {"wdg_bite_irq", 0, IRQF_TRIGGER_RISING | IRQF_ONESHOT}, }; }; static struct npu_device *g_npu_dev; /* ------------------------------------------------------------------------- /* ------------------------------------------------------------------------- * Entry Points for Probe * Entry Points for Probe * ------------------------------------------------------------------------- * ------------------------------------------------------------------------- Loading Loading @@ -320,7 +325,7 @@ static ssize_t npu_store_perf_mode_override(struct device *dev, val = min(val, npu_dev->pwrctrl.num_pwrlevels); val = min(val, npu_dev->pwrctrl.num_pwrlevels); npu_dev->pwrctrl.perf_mode_override = val; npu_dev->pwrctrl.perf_mode_override = val; pr_info("setting uc_pwrlevel_override to %d\n", val); pr_info("setting uc_pwrlevel_override to %d\n", val); npu_set_power_level(npu_dev); npu_set_power_level(npu_dev, true); return count; return count; } } Loading @@ -329,6 +334,168 @@ static ssize_t npu_store_perf_mode_override(struct device *dev, * Power Related * Power Related * ------------------------------------------------------------------------- * ------------------------------------------------------------------------- */ */ static enum npu_power_level cdsprm_corner_to_npu_power_level( enum cdsprm_npu_corner corner) { enum npu_power_level pwr_lvl = NPU_PWRLEVEL_TURBO_L1; switch (corner) { case CDSPRM_NPU_CLK_OFF: pwr_lvl = NPU_PWRLEVEL_OFF; break; case CDSPRM_NPU_MIN_SVS: pwr_lvl = NPU_PWRLEVEL_MINSVS; break; case CDSPRM_NPU_LOW_SVS: pwr_lvl = NPU_PWRLEVEL_LOWSVS; break; case CDSPRM_NPU_SVS: pwr_lvl = NPU_PWRLEVEL_SVS; break; case CDSPRM_NPU_SVS_L1: pwr_lvl = NPU_PWRLEVEL_SVS_L1; break; case CDSPRM_NPU_NOM: pwr_lvl = NPU_PWRLEVEL_NOM; break; case CDSPRM_NPU_NOM_L1: pwr_lvl = NPU_PWRLEVEL_NOM_L1; break; case CDSPRM_NPU_TURBO: pwr_lvl = NPU_PWRLEVEL_TURBO; break; case CDSPRM_NPU_TURBO_L1: default: pwr_lvl = NPU_PWRLEVEL_TURBO_L1; break; } return pwr_lvl; } static enum cdsprm_npu_corner npu_power_level_to_cdsprm_corner( enum npu_power_level pwr_lvl) { enum cdsprm_npu_corner corner = CDSPRM_NPU_MIN_SVS; switch (pwr_lvl) { case NPU_PWRLEVEL_OFF: corner = CDSPRM_NPU_CLK_OFF; break; case NPU_PWRLEVEL_MINSVS: corner = CDSPRM_NPU_MIN_SVS; break; case NPU_PWRLEVEL_LOWSVS: corner = CDSPRM_NPU_LOW_SVS; break; case NPU_PWRLEVEL_SVS: corner = CDSPRM_NPU_SVS; break; case NPU_PWRLEVEL_SVS_L1: corner = CDSPRM_NPU_SVS_L1; break; case NPU_PWRLEVEL_NOM: corner = CDSPRM_NPU_NOM; break; case NPU_PWRLEVEL_NOM_L1: corner = CDSPRM_NPU_NOM_L1; break; case NPU_PWRLEVEL_TURBO: corner = CDSPRM_NPU_TURBO; break; case NPU_PWRLEVEL_TURBO_L1: default: corner = CDSPRM_NPU_TURBO_L1; break; } return corner; } static int npu_set_cdsprm_corner_limit(enum cdsprm_npu_corner corner) { struct npu_pwrctrl *pwr; enum npu_power_level pwr_lvl; if (!g_npu_dev) return 0; pwr = &g_npu_dev->pwrctrl; pwr_lvl = cdsprm_corner_to_npu_power_level(corner); pwr->cdsprm_pwrlevel = pwr_lvl; pr_debug("power level from cdsp %d\n", pwr_lvl); return npu_set_power_level(g_npu_dev, false); } const struct cdsprm_npu_limit_cbs cdsprm_npu_limit_cbs = { .set_corner_limit = npu_set_cdsprm_corner_limit, }; int npu_notify_cdsprm_cxlimit_activity(struct npu_device *npu_dev, bool enable) { if (!npu_dev->cxlimit_registered) return 0; pr_debug("notify cxlimit %s activity\n", enable ? "enable" : "disable"); return cdsprm_cxlimit_npu_activity_notify(enable ? 1 : 0); } static uint32_t npu_notify_cdsprm_cxlimit_corner( struct npu_device *npu_dev, uint32_t pwr_lvl) { uint32_t corner, pwr_lvl_to_set; if (!npu_dev->cxlimit_registered) return pwr_lvl; corner = npu_power_level_to_cdsprm_corner(pwr_lvl); corner = cdsprm_cxlimit_npu_corner_notify(corner); pwr_lvl_to_set = cdsprm_corner_to_npu_power_level(corner); pr_debug("Notify cdsprm %d:%d\n", pwr_lvl, pwr_lvl_to_set); return pwr_lvl_to_set; } int npu_cdsprm_cxlimit_init(struct npu_device *npu_dev) { bool enabled; int ret = 0; enabled = of_property_read_bool(npu_dev->pdev->dev.of_node, "qcom,npu-cxlimit-enable"); pr_debug("qcom,npu-xclimit-enable is %s\n", enabled ? "true" : "false"); npu_dev->cxlimit_registered = false; if (enabled) { ret = cdsprm_cxlimit_npu_limit_register(&cdsprm_npu_limit_cbs); if (ret) { pr_err("register cxlimit npu limit failed\n"); } else { pr_debug("register cxlimit npu limit succeeds\n"); npu_dev->cxlimit_registered = true; } } return ret; } int npu_cdsprm_cxlimit_deinit(struct npu_device *npu_dev) { int ret = 0; if (npu_dev->cxlimit_registered) { ret = cdsprm_cxlimit_npu_limit_deregister(); if (ret) pr_err("deregister cxlimit npu limit failed\n"); npu_dev->cxlimit_registered = false; } return ret; } int npu_enable_core_power(struct npu_device *npu_dev) int npu_enable_core_power(struct npu_device *npu_dev) { { struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; Loading Loading @@ -366,6 +533,7 @@ void npu_disable_core_power(struct npu_device *npu_dev) npu_disable_regulators(npu_dev); npu_disable_regulators(npu_dev); pwr->active_pwrlevel = thermalctrl->pwr_level; pwr->active_pwrlevel = thermalctrl->pwr_level; pwr->uc_pwrlevel = pwr->max_pwrlevel; pwr->uc_pwrlevel = pwr->max_pwrlevel; pwr->cdsprm_pwrlevel = pwr->max_pwrlevel; pr_debug("setting back to power level=%d\n", pr_debug("setting back to power level=%d\n", pwr->active_pwrlevel); pwr->active_pwrlevel); } } Loading Loading @@ -432,37 +600,44 @@ static uint32_t npu_calc_power_level(struct npu_device *npu_dev) uc_pwr_level = npu_power_level_from_index(npu_dev, uc_pwr_level = npu_power_level_from_index(npu_dev, npu_dev->pwrctrl.perf_mode_override - 1); npu_dev->pwrctrl.perf_mode_override - 1); /* if thermal power is higher than usecase power /* * leave level at use case. Otherwise go down to * pick the lowese power level between thermal power and usecase power * thermal power level * settings */ */ if (therm_pwr_level > uc_pwr_level) ret_level = min(therm_pwr_level, uc_pwr_level); ret_level = uc_pwr_level; pr_debug("%s therm=%d active=%d uc=%d set level=%d\n", else __func__, therm_pwr_level, active_pwr_level, uc_pwr_level, ret_level = therm_pwr_level; ret_level); pr_debug("%s therm=%d active=%d uc=%d set level=%d\n", __func__, therm_pwr_level, active_pwr_level, uc_pwr_level, ret_level); return ret_level; return ret_level; } } static int npu_set_power_level(struct npu_device *npu_dev) static int npu_set_power_level(struct npu_device *npu_dev, bool notify_cxlimit) { { struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; struct npu_pwrlevel *pwrlevel; struct npu_pwrlevel *pwrlevel; int i, ret = 0; int i, ret = 0; uint32_t pwr_level_to_set, pwr_level_idx; uint32_t pwr_level_to_set, pwr_level_to_cdsprm, pwr_level_idx; /* get power level to set */ /* get power level to set */ pwr_level_to_set = npu_calc_power_level(npu_dev); pwr_level_to_set = npu_calc_power_level(npu_dev); pwr_level_to_cdsprm = pwr_level_to_set; if (!pwr->pwr_vote_num) { if (!pwr->pwr_vote_num) { pr_debug("power is not enabled during set request\n"); pr_debug("power is not enabled during set request\n"); pwr->active_pwrlevel = pwr_level_to_set; pwr->active_pwrlevel = min(pwr_level_to_set, npu_dev->pwrctrl.cdsprm_pwrlevel); return 0; return 0; } } /* notify cxlimit to get allowed power level */ if ((pwr_level_to_set > pwr->active_pwrlevel) && notify_cxlimit) pwr_level_to_set = npu_notify_cdsprm_cxlimit_corner( npu_dev, pwr_level_to_cdsprm); pwr_level_to_set = min(pwr_level_to_set, npu_dev->pwrctrl.cdsprm_pwrlevel); /* if the same as current, dont do anything */ /* if the same as current, dont do anything */ if (pwr_level_to_set == pwr->active_pwrlevel) { if (pwr_level_to_set == pwr->active_pwrlevel) { pr_debug("power level %d doesn't change\n", pwr_level_to_set); pr_debug("power level %d doesn't change\n", pwr_level_to_set); Loading Loading @@ -497,6 +672,12 @@ static int npu_set_power_level(struct npu_device *npu_dev) } } } } if ((pwr_level_to_cdsprm < pwr->active_pwrlevel) && notify_cxlimit) { npu_notify_cdsprm_cxlimit_corner(npu_dev, pwr_level_to_cdsprm); pr_debug("Notify cdsprm(post) %d\n", pwr_level_to_cdsprm); } pwr->active_pwrlevel = pwr_level_to_set; pwr->active_pwrlevel = pwr_level_to_set; return ret; return ret; } } Loading @@ -517,7 +698,7 @@ int npu_set_uc_power_level(struct npu_device *npu_dev, uc_pwrlevel_to_set = pwr->max_pwrlevel; uc_pwrlevel_to_set = pwr->max_pwrlevel; pwr->uc_pwrlevel = uc_pwrlevel_to_set; pwr->uc_pwrlevel = uc_pwrlevel_to_set; return npu_set_power_level(npu_dev); return npu_set_power_level(npu_dev, true); } } /* ------------------------------------------------------------------------- /* ------------------------------------------------------------------------- Loading Loading @@ -619,6 +800,13 @@ static int npu_enable_clocks(struct npu_device *npu_dev, bool post_pil) uint32_t pwrlevel_to_set, pwrlevel_idx; uint32_t pwrlevel_to_set, pwrlevel_idx; pwrlevel_to_set = pwr->active_pwrlevel; pwrlevel_to_set = pwr->active_pwrlevel; if (!post_pil) { pwrlevel_to_set = npu_notify_cdsprm_cxlimit_corner( npu_dev, pwrlevel_to_set); pr_debug("Notify cdsprm %d\n", pwrlevel_to_set); pwr->active_pwrlevel = pwrlevel_to_set; } pwrlevel_idx = npu_power_level_to_index(npu_dev, pwrlevel_to_set); pwrlevel_idx = npu_power_level_to_index(npu_dev, pwrlevel_to_set); pwrlevel = &pwr->pwrlevels[pwrlevel_idx]; pwrlevel = &pwr->pwrlevels[pwrlevel_idx]; for (i = 0; i < ARRAY_SIZE(npu_clock_order); i++) { for (i = 0; i < ARRAY_SIZE(npu_clock_order); i++) { Loading Loading @@ -684,6 +872,11 @@ static void npu_disable_clocks(struct npu_device *npu_dev, bool post_pil) int i = 0; int i = 0; struct npu_clk *core_clks = npu_dev->core_clks; struct npu_clk *core_clks = npu_dev->core_clks; if (!post_pil) { npu_notify_cdsprm_cxlimit_corner(npu_dev, NPU_PWRLEVEL_OFF); pr_debug("Notify cdsprm clock off\n"); } for (i = ARRAY_SIZE(npu_clock_order) - 1; i >= 0 ; i--) { for (i = ARRAY_SIZE(npu_clock_order) - 1; i >= 0 ; i--) { if (!core_clks[i].clk) if (!core_clks[i].clk) continue; continue; Loading Loading @@ -747,7 +940,7 @@ npu_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) thermal->pwr_level = npu_power_level_from_index(npu_dev, thermal->pwr_level = npu_power_level_from_index(npu_dev, thermal->max_state - state); thermal->max_state - state); return npu_set_power_level(npu_dev); return npu_set_power_level(npu_dev, true); } } /* ------------------------------------------------------------------------- /* ------------------------------------------------------------------------- Loading Loading @@ -1534,7 +1727,7 @@ static int npu_of_parse_pwrlevels(struct npu_device *npu_dev, switch (fmax) { switch (fmax) { case 1: case 1: case 2: case 2: fmax_pwrlvl = NPU_PWRLEVEL_NORM; fmax_pwrlvl = NPU_PWRLEVEL_NOM; break; break; case 3: case 3: fmax_pwrlvl = NPU_PWRLEVEL_SVS_L1; fmax_pwrlvl = NPU_PWRLEVEL_SVS_L1; Loading Loading @@ -1566,6 +1759,7 @@ static int npu_of_parse_pwrlevels(struct npu_device *npu_dev, pwr->active_pwrlevel = pwr->default_pwrlevel = init_power_level; pwr->active_pwrlevel = pwr->default_pwrlevel = init_power_level; pwr->uc_pwrlevel = pwr->max_pwrlevel; pwr->uc_pwrlevel = pwr->max_pwrlevel; pwr->perf_mode_override = 0; pwr->perf_mode_override = 0; pwr->cdsprm_pwrlevel = pwr->max_pwrlevel; return 0; return 0; } } Loading Loading @@ -1811,6 +2005,10 @@ static int npu_probe(struct platform_device *pdev) thermal_cdev_update(tcdev); thermal_cdev_update(tcdev); } } rc = npu_cdsprm_cxlimit_init(npu_dev); if (rc) goto error_driver_init; rc = npu_debugfs_init(npu_dev); rc = npu_debugfs_init(npu_dev); if (rc) if (rc) goto error_driver_init; goto error_driver_init; Loading Loading @@ -1840,8 +2038,11 @@ static int npu_probe(struct platform_device *pdev) goto error_driver_init; goto error_driver_init; } } g_npu_dev = npu_dev; return rc; return rc; error_driver_init: error_driver_init: npu_cdsprm_cxlimit_deinit(npu_dev); sysfs_remove_group(&npu_dev->device->kobj, &npu_fs_attr_group); sysfs_remove_group(&npu_dev->device->kobj, &npu_fs_attr_group); arm_iommu_detach_device(&(npu_dev->pdev->dev)); arm_iommu_detach_device(&(npu_dev->pdev->dev)); if (!npu_dev->smmu_ctx.mmu_mapping) if (!npu_dev->smmu_ctx.mmu_mapping) Loading @@ -1867,6 +2068,7 @@ static int npu_remove(struct platform_device *pdev) npu_dev = platform_get_drvdata(pdev); npu_dev = platform_get_drvdata(pdev); thermal_cooling_device_unregister(npu_dev->tcdev); thermal_cooling_device_unregister(npu_dev->tcdev); npu_cdsprm_cxlimit_deinit(npu_dev); npu_debugfs_deinit(npu_dev); npu_debugfs_deinit(npu_dev); npu_host_deinit(npu_dev); npu_host_deinit(npu_dev); arm_iommu_detach_device(&(npu_dev->pdev->dev)); arm_iommu_detach_device(&(npu_dev->pdev->dev)); Loading @@ -1880,6 +2082,8 @@ static int npu_remove(struct platform_device *pdev) if (npu_dev->mbox_aop.chan) if (npu_dev->mbox_aop.chan) mbox_free_channel(npu_dev->mbox_aop.chan); mbox_free_channel(npu_dev->mbox_aop.chan); g_npu_dev = NULL; return 0; return 0; } } Loading
drivers/media/platform/msm/npu/npu_mgr.c +12 −0 Original line number Original line Diff line number Diff line Loading @@ -1424,6 +1424,9 @@ int32_t npu_host_exec_network(struct npu_client *client, return -EINVAL; return -EINVAL; } } if (atomic_inc_return(&host_ctx->network_exeute_cnt) == 1) npu_notify_cdsprm_cxlimit_activity(npu_dev, true); if (!network->is_active) { if (!network->is_active) { pr_err("network is not active\n"); pr_err("network is not active\n"); ret = -EINVAL; ret = -EINVAL; Loading Loading @@ -1528,6 +1531,9 @@ int32_t npu_host_exec_network(struct npu_client *client, host_error_hdlr(npu_dev, true); host_error_hdlr(npu_dev, true); } } if (atomic_dec_return(&host_ctx->network_exeute_cnt) == 0) npu_notify_cdsprm_cxlimit_activity(npu_dev, false); return ret; return ret; } } Loading @@ -1553,6 +1559,9 @@ int32_t npu_host_exec_network_v2(struct npu_client *client, return -EINVAL; return -EINVAL; } } if (atomic_inc_return(&host_ctx->network_exeute_cnt) == 1) npu_notify_cdsprm_cxlimit_activity(npu_dev, true); if (!network->is_active) { if (!network->is_active) { pr_err("network is not active\n"); pr_err("network is not active\n"); ret = -EINVAL; ret = -EINVAL; Loading Loading @@ -1679,6 +1688,9 @@ int32_t npu_host_exec_network_v2(struct npu_client *client, host_error_hdlr(npu_dev, true); host_error_hdlr(npu_dev, true); } } if (atomic_dec_return(&host_ctx->network_exeute_cnt) == 0) npu_notify_cdsprm_cxlimit_activity(npu_dev, false); return ret; return ret; } } Loading
drivers/media/platform/msm/npu/npu_mgr.h +1 −0 Original line number Original line Diff line number Diff line Loading @@ -87,6 +87,7 @@ struct npu_host_ctx { uint32_t fw_dbg_mode; uint32_t fw_dbg_mode; uint32_t exec_flags_override; uint32_t exec_flags_override; atomic_t ipc_trans_id; atomic_t ipc_trans_id; atomic_t network_exeute_cnt; uint32_t err_irq_sts; uint32_t err_irq_sts; uint32_t wdg_irq_sts; uint32_t wdg_irq_sts; Loading