// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2019 MediaTek Inc. */ /* system includes */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mtk_cm_mgr_common.h" #include #ifdef CONFIG_MTK_DVFSRC #include #include #endif /* CONFIG_MTK_DVFSRC */ #if defined(CONFIG_MACH_MT6761) || defined(CONFIG_MACH_MT6765) #undef USE_CM_MGR_AT_SSPM #else #define USE_CM_MGR_AT_SSPM #endif #if defined(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && defined(USE_CM_MGR_AT_SSPM) #include #endif /* CONFIG_MTK_TINYSYS_SSPM_SUPPORT && defined(USE_CM_MGR_AT_SSPM) */ static struct kobject *cm_mgr_kobj; struct platform_device *cm_mgr_pdev; void __iomem *cm_mgr_base; int cm_mgr_num_perf; int *cm_mgr_perfs; int *cm_mgr_cpu_opp_to_dram; int cm_mgr_num_array; int *cm_mgr_buf; int cm_mgr_cpu_opp_size; int cm_mgr_blank_status; int cm_mgr_disable_fb = 1; int cm_mgr_emi_demand_check = 1; int cm_mgr_enable = 1; int cm_mgr_loading_enable; int cm_mgr_loading_level = 1000; int cm_mgr_opp_enable = 1; int cm_mgr_perf_enable = 1; int cm_mgr_perf_force_enable; #if defined(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && defined(USE_CM_MGR_AT_SSPM) int cm_mgr_sspm_enable = 1; #endif /* CONFIG_MTK_TINYSYS_SSPM_SUPPORT && defined(USE_CM_MGR_AT_SSPM) */ unsigned int *cpu_power_ratio_down; unsigned int *cpu_power_ratio_up; unsigned int *vcore_power_ratio_down; unsigned int *vcore_power_ratio_up; unsigned int *debounce_times_down_adb; unsigned int *debounce_times_up_adb; int debounce_times_perf_down = 50; int debounce_times_perf_force_down = 100; int debounce_times_reset_adb; int light_load_cps = 1000; int debounce_times_perf_down_local = -1; int debounce_times_perf_down_force_local = -1; int pm_qos_update_request_status; int cm_mgr_dram_opp_base = -1; int cm_mgr_dram_opp = -1; int cm_mgr_loop_count; static int cm_mgr_dram_level; int total_bw_value; /* setting in DTS */ int cm_mgr_use_bcpu_weight; int cm_mgr_use_cpu_to_dram_map; int cm_mgr_use_cpu_to_dram_map_new; int cpu_power_bcpu_weight_max = 100; int cpu_power_bcpu_weight_min = 100; int cm_mgr_cpu_map_dram_enable = 1; int cm_mgr_cpu_map_emi_opp = 1; int cm_mgr_cpu_map_skip_cpu_opp = 2; static int cm_mgr_fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) { struct fb_event *evdata = data; int blank; if (event != FB_EVENT_BLANK) return 0; blank = *(int *)evdata->data; switch (blank) { case FB_BLANK_UNBLANK: pr_info("#@# %s(%d) SCREEN ON\n", __func__, __LINE__); cm_mgr_blank_status = 0; #if defined(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && defined(USE_CM_MGR_AT_SSPM) cm_mgr_to_sspm_command(IPI_CM_MGR_BLANK, 0); #endif /* CONFIG_MTK_TINYSYS_SSPM_SUPPORT && defined(USE_CM_MGR_AT_SSPM) */ break; case FB_BLANK_POWERDOWN: pr_info("#@# %s(%d) SCREEN OFF\n", __func__, __LINE__); cm_mgr_blank_status = 1; cm_mgr_dram_opp_base = -1; cm_mgr_perf_platform_set_status(0); #if defined(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && defined(USE_CM_MGR_AT_SSPM) cm_mgr_to_sspm_command(IPI_CM_MGR_BLANK, 1); #endif /* CONFIG_MTK_TINYSYS_SSPM_SUPPORT && defined(USE_CM_MGR_AT_SSPM) */ break; default: break; } return 0; } static struct notifier_block cm_mgr_fb_notifier = { .notifier_call = cm_mgr_fb_notifier_callback, }; void cm_mgr_perf_set_status(int enable) { if (cm_mgr_disable_fb == 1 && cm_mgr_blank_status == 1) enable = 0; cm_mgr_perf_platform_set_force_status(enable); if (cm_mgr_perf_force_enable) return; cm_mgr_perf_platform_set_status(enable); } EXPORT_SYMBOL_GPL(cm_mgr_perf_set_status); void cm_mgr_perf_set_force_status(int enable) { if (enable != cm_mgr_perf_force_enable) { cm_mgr_perf_force_enable = enable; if (!enable) cm_mgr_perf_platform_set_force_status(enable); } } EXPORT_SYMBOL_GPL(cm_mgr_perf_set_force_status); void cm_mgr_enable_fn(int enable) { cm_mgr_enable = enable; #if defined(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && defined(USE_CM_MGR_AT_SSPM) cm_mgr_to_sspm_command(IPI_CM_MGR_ENABLE, cm_mgr_enable); #endif /* CONFIG_MTK_TINYSYS_SSPM_SUPPORT && defined(USE_CM_MGR_AT_SSPM) */ } EXPORT_SYMBOL_GPL(cm_mgr_enable_fn); #if defined(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && defined(USE_CM_MGR_AT_SSPM) /* FIXME: */ #if defined(CONFIG_MTK_TINYSYS_SSPM_V2) int cm_mgr_to_sspm_command(u32 cmd, int val) { unsigned int ret = 0; struct cm_mgr_data cm_mgr_d; if (cm_sspm_ready != 1) { pr_info("#@# %s(%d) sspm not ready(%d) to receive cmd(%d)\n", __func__, __LINE__, cm_sspm_ready, cmd); ret = -1; return ret; } cm_ipi_ackdata = 0; switch (cmd) { case IPI_CM_MGR_INIT: case IPI_CM_MGR_ENABLE: case IPI_CM_MGR_OPP_ENABLE: case IPI_CM_MGR_SSPM_ENABLE: case IPI_CM_MGR_BLANK: case IPI_CM_MGR_DISABLE_FB: case IPI_CM_MGR_DRAM_TYPE: case IPI_CM_MGR_CPU_POWER_RATIO_UP: case IPI_CM_MGR_CPU_POWER_RATIO_DOWN: case IPI_CM_MGR_VCORE_POWER_RATIO_UP: case IPI_CM_MGR_VCORE_POWER_RATIO_DOWN: case IPI_CM_MGR_DEBOUNCE_UP: case IPI_CM_MGR_DEBOUNCE_DOWN: case IPI_CM_MGR_DEBOUNCE_TIMES_RESET_ADB: case IPI_CM_MGR_DRAM_LEVEL: case IPI_CM_MGR_LIGHT_LOAD_CPS: case IPI_CM_MGR_LOADING_ENABLE: case IPI_CM_MGR_LOADING_LEVEL: case IPI_CM_MGR_EMI_DEMAND_CHECK: case IPI_CM_MGR_OPP_FREQ_SET: case IPI_CM_MGR_OPP_VOLT_SET: case IPI_CM_MGR_BCPU_WEIGHT_MAX_SET: case IPI_CM_MGR_BCPU_WEIGHT_MIN_SET: cm_mgr_d.cmd = cmd; cm_mgr_d.arg = val; ret = mtk_ipi_send_compl(&sspm_ipidev, IPIS_C_CM, IPI_SEND_POLLING, &cm_mgr_d, CM_MGR_D_LEN, 2000); if (ret != 0) { pr_info("#@# %s(%d) cmd(%d) error, return %d\n", __func__, __LINE__, cmd, ret); } else if (!cm_ipi_ackdata) { ret = cm_ipi_ackdata; pr_info("#@# %s(%d) cmd(%d) ack fail %d\n", __func__, __LINE__, cmd, ret); } break; default: pr_info("#@# %s(%d) wrong cmd(%d)!!!\n", __func__, __LINE__, cmd); break; } return ret; } #else int cm_mgr_to_sspm_command(u32 cmd, int val) { unsigned int ret = 0; struct cm_mgr_data cm_mgr_d; int ack_data; switch (cmd) { case IPI_CM_MGR_INIT: case IPI_CM_MGR_ENABLE: case IPI_CM_MGR_OPP_ENABLE: case IPI_CM_MGR_SSPM_ENABLE: case IPI_CM_MGR_BLANK: case IPI_CM_MGR_DISABLE_FB: case IPI_CM_MGR_DRAM_TYPE: case IPI_CM_MGR_CPU_POWER_RATIO_UP: case IPI_CM_MGR_CPU_POWER_RATIO_DOWN: case IPI_CM_MGR_VCORE_POWER_RATIO_UP: case IPI_CM_MGR_VCORE_POWER_RATIO_DOWN: case IPI_CM_MGR_DEBOUNCE_UP: case IPI_CM_MGR_DEBOUNCE_DOWN: case IPI_CM_MGR_DEBOUNCE_TIMES_RESET_ADB: case IPI_CM_MGR_DRAM_LEVEL: case IPI_CM_MGR_LIGHT_LOAD_CPS: case IPI_CM_MGR_LOADING_ENABLE: case IPI_CM_MGR_LOADING_LEVEL: case IPI_CM_MGR_EMI_DEMAND_CHECK: case IPI_CM_MGR_BCPU_WEIGHT_MAX_SET: case IPI_CM_MGR_BCPU_WEIGHT_MIN_SET: cm_mgr_d.cmd = cmd; cm_mgr_d.arg = val; ret = sspm_ipi_send_sync(IPI_ID_CM, IPI_OPT_POLLING, &cm_mgr_d, CM_MGR_D_LEN, &ack_data, 1); if (ret != 0) { pr_info("#@# %s(%d) cmd(%d) error, return %d\n", __func__, __LINE__, cmd, ret); } else if (ack_data < 0) { ret = ack_data; pr_info("#@# %s(%d) cmd(%d) return %d\n", __func__, __LINE__, cmd, ret); } break; default: pr_info("#@# %s(%d) wrong cmd(%d)!!!\n", __func__, __LINE__, cmd); break; } return ret; } EXPORT_SYMBOL_GPL(cm_mgr_to_sspm_command); #endif /* USE_SSPM_VER_V2 */ #endif /* CONFIG_MTK_TINYSYS_SSPM_SUPPORT && defined(USE_CM_MGR_AT_SSPM) */ void __weak dbg_cm_mgr_platform_show(struct seq_file *m) {} void __weak dbg_cm_mgr_platform_write(int len, char *cmd, u32 val_1, u32 val_2) {} void cm_mgr_cpu_map_update_table(void) { int i; for (i = 0; i < cm_mgr_cpu_opp_size; i++) { if (i < cm_mgr_cpu_map_skip_cpu_opp) cm_mgr_cpu_opp_to_dram[i] = cm_mgr_cpu_map_emi_opp; else cm_mgr_cpu_opp_to_dram[i] = MTK_PM_QOS_DDR_OPP_DEFAULT_VALUE; } } EXPORT_SYMBOL_GPL(cm_mgr_cpu_map_update_table); static ssize_t dbg_cm_mgr_show(struct kobject *kobj, struct kobj_attribute *attr, char *buff) { int i; int len = 0; #define cm_mgr_print(...) \ snprintf(buff + len, (4096 - len) > 0 ? (4096 - len) : 0, __VA_ARGS__) len += cm_mgr_print("cm_mgr_opp_enable %d\n", cm_mgr_opp_enable); len += cm_mgr_print("cm_mgr_enable %d\n", cm_mgr_enable); #if defined(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && defined(USE_CM_MGR_AT_SSPM) len += cm_mgr_print("cm_mgr_sspm_enable %d\n", cm_mgr_sspm_enable); #endif /* CONFIG_MTK_TINYSYS_SSPM_SUPPORT && defined(USE_CM_MGR_AT_SSPM) */ len += cm_mgr_print("cm_mgr_perf_enable %d\n", cm_mgr_perf_enable); len += cm_mgr_print("cm_mgr_perf_force_enable %d\n", cm_mgr_perf_force_enable); if (cm_mgr_use_cpu_to_dram_map) { len += cm_mgr_print("cm_mgr_cpu_map_dram_enable %d\n", cm_mgr_cpu_map_dram_enable); } if (cm_mgr_use_cpu_to_dram_map_new) { len += cm_mgr_print("cm_mgr_cpu_map_emi_opp %d\n", cm_mgr_cpu_map_emi_opp); len += cm_mgr_print("cm_mgr_cpu_map_skip_cpu_opp %d\n", cm_mgr_cpu_map_skip_cpu_opp); len += cm_mgr_print("cm_mgr_cpu_opp_to_dram table"); for (i = 0; i < cm_mgr_cpu_opp_size; i++) len += cm_mgr_print(" %d", cm_mgr_cpu_opp_to_dram[i]); len += cm_mgr_print("\n"); } len += cm_mgr_print("cm_mgr_disable_fb %d\n", cm_mgr_disable_fb); len += cm_mgr_print("light_load_cps %d\n", light_load_cps); len += cm_mgr_print("total_bw_value %d\n", total_bw_value); len += cm_mgr_print("cm_mgr_loop_count %d\n", cm_mgr_loop_count); len += cm_mgr_print("cm_mgr_dram_level %d\n", cm_mgr_dram_level); len += cm_mgr_print("cm_mgr_loading_level %d\n", cm_mgr_loading_level); len += cm_mgr_print("cm_mgr_loading_enable %d\n", cm_mgr_loading_enable); len += cm_mgr_print("cm_mgr_emi_demand_check %d\n", cm_mgr_emi_demand_check); len += cm_mgr_print("cpu_power_ratio_up"); for (i = 0; i < cm_mgr_num_array; i++) len += cm_mgr_print(" %d", cpu_power_ratio_up[i]); len += cm_mgr_print("\n"); len += cm_mgr_print("cpu_power_ratio_down"); for (i = 0; i < cm_mgr_num_array; i++) len += cm_mgr_print(" %d", cpu_power_ratio_down[i]); len += cm_mgr_print("\n"); len += cm_mgr_print("vcore_power_ratio_up"); for (i = 0; i < cm_mgr_num_array; i++) len += cm_mgr_print(" %d", vcore_power_ratio_up[i]); len += cm_mgr_print("\n"); len += cm_mgr_print("vcore_power_ratio_down"); for (i = 0; i < cm_mgr_num_array; i++) len += cm_mgr_print(" %d", vcore_power_ratio_down[i]); len += cm_mgr_print("\n"); if (cm_mgr_use_bcpu_weight) { len += cm_mgr_print("cpu_power_bcpu_weight_max %d\n", cpu_power_bcpu_weight_max); len += cm_mgr_print("cpu_power_bcpu_weight_min %d\n", cpu_power_bcpu_weight_min); } len += cm_mgr_print("debounce_times_up_adb"); for (i = 0; i < cm_mgr_num_array; i++) len += cm_mgr_print(" %d", debounce_times_up_adb[i]); len += cm_mgr_print("\n"); len += cm_mgr_print("debounce_times_down_adb"); for (i = 0; i < cm_mgr_num_array; i++) len += cm_mgr_print(" %d", debounce_times_down_adb[i]); len += cm_mgr_print("\n"); len += cm_mgr_print("debounce_times_reset_adb %d\n", debounce_times_reset_adb); len += cm_mgr_print("debounce_times_perf_down %d\n", debounce_times_perf_down); len += cm_mgr_print("debounce_times_perf_force_down %d\n", debounce_times_perf_force_down); len += cm_mgr_print("\n"); return (len > 4096) ? 4096 : len; } static ssize_t dbg_cm_mgr_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buff, size_t count) { int ret; char cmd[64]; u32 val_1; u32 val_2; ret = sscanf(buff, "%63s %d %d", cmd, &val_1, &val_2); if (ret < 1) { ret = -EPERM; goto out; } if (!strcmp(cmd, "cm_mgr_enable")) { cm_mgr_enable = val_1; #if defined(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && defined(USE_CM_MGR_AT_SSPM) cm_mgr_to_sspm_command(IPI_CM_MGR_ENABLE, cm_mgr_enable); } else if (!strcmp(cmd, "cm_mgr_sspm_enable")) { cm_mgr_sspm_enable = val_1; cm_mgr_to_sspm_command(IPI_CM_MGR_SSPM_ENABLE, cm_mgr_sspm_enable); #endif /* CONFIG_MTK_TINYSYS_SSPM_SUPPORT && defined(USE_CM_MGR_AT_SSPM) */ } else if (!strcmp(cmd, "cm_mgr_perf_enable")) { cm_mgr_perf_enable = val_1; } else if (!strcmp(cmd, "cm_mgr_perf_force_enable")) { cm_mgr_perf_force_enable = val_1; cm_mgr_perf_set_force_status(val_1); } else if (!strcmp(cmd, "cm_mgr_disable_fb")) { cm_mgr_disable_fb = val_1; #if defined(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && defined(USE_CM_MGR_AT_SSPM) cm_mgr_to_sspm_command(IPI_CM_MGR_DISABLE_FB, cm_mgr_disable_fb); #endif /* CONFIG_MTK_TINYSYS_SSPM_SUPPORT && defined(USE_CM_MGR_AT_SSPM) */ } else if (!strcmp(cmd, "light_load_cps")) { light_load_cps = val_1; #if defined(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && defined(USE_CM_MGR_AT_SSPM) cm_mgr_to_sspm_command(IPI_CM_MGR_LIGHT_LOAD_CPS, val_1); #endif /* CONFIG_MTK_TINYSYS_SSPM_SUPPORT && defined(USE_CM_MGR_AT_SSPM) */ } else if (!strcmp(cmd, "total_bw_value")) { total_bw_value = val_1; } else if (!strcmp(cmd, "cm_mgr_loop_count")) { cm_mgr_loop_count = val_1; } else if (!strcmp(cmd, "cm_mgr_dram_level")) { cm_mgr_dram_level = val_1; #if defined(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && defined(USE_CM_MGR_AT_SSPM) cm_mgr_to_sspm_command(IPI_CM_MGR_DRAM_LEVEL, val_1); #endif /* CONFIG_MTK_TINYSYS_SSPM_SUPPORT && defined(USE_CM_MGR_AT_SSPM) */ } else if (!strcmp(cmd, "cm_mgr_loading_level")) { cm_mgr_loading_level = val_1; #if defined(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && defined(USE_CM_MGR_AT_SSPM) cm_mgr_to_sspm_command(IPI_CM_MGR_LOADING_LEVEL, val_1); #endif /* CONFIG_MTK_TINYSYS_SSPM_SUPPORT && defined(USE_CM_MGR_AT_SSPM) */ } else if (!strcmp(cmd, "cm_mgr_loading_enable")) { cm_mgr_loading_enable = val_1; #if defined(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && defined(USE_CM_MGR_AT_SSPM) cm_mgr_to_sspm_command(IPI_CM_MGR_LOADING_ENABLE, val_1); #endif /* CONFIG_MTK_TINYSYS_SSPM_SUPPORT && defined(USE_CM_MGR_AT_SSPM) */ } else if (!strcmp(cmd, "cm_mgr_emi_demand_check")) { cm_mgr_emi_demand_check = val_1; #if defined(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && defined(USE_CM_MGR_AT_SSPM) cm_mgr_to_sspm_command(IPI_CM_MGR_EMI_DEMAND_CHECK, val_1); #endif /* CONFIG_MTK_TINYSYS_SSPM_SUPPORT && defined(USE_CM_MGR_AT_SSPM) */ } else if (!strcmp(cmd, "cpu_power_ratio_up")) { if (ret == 3 && val_1 < cm_mgr_num_array) cpu_power_ratio_up[val_1] = val_2; #if defined(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && defined(USE_CM_MGR_AT_SSPM) cm_mgr_to_sspm_command(IPI_CM_MGR_CPU_POWER_RATIO_UP, val_1 << 16 | val_2); #endif /* CONFIG_MTK_TINYSYS_SSPM_SUPPORT && defined(USE_CM_MGR_AT_SSPM) */ } else if (!strcmp(cmd, "cpu_power_ratio_down")) { if (ret == 3 && val_1 < cm_mgr_num_array) cpu_power_ratio_down[val_1] = val_2; #if defined(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && defined(USE_CM_MGR_AT_SSPM) cm_mgr_to_sspm_command(IPI_CM_MGR_CPU_POWER_RATIO_DOWN, val_1 << 16 | val_2); #endif /* CONFIG_MTK_TINYSYS_SSPM_SUPPORT && defined(USE_CM_MGR_AT_SSPM) */ } else if (!strcmp(cmd, "vcore_power_ratio_up")) { if (ret == 3 && val_1 < cm_mgr_num_array) vcore_power_ratio_up[val_1] = val_2; #if defined(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && defined(USE_CM_MGR_AT_SSPM) cm_mgr_to_sspm_command(IPI_CM_MGR_VCORE_POWER_RATIO_UP, val_1 << 16 | val_2); #endif /* CONFIG_MTK_TINYSYS_SSPM_SUPPORT && defined(USE_CM_MGR_AT_SSPM) */ } else if (!strcmp(cmd, "vcore_power_ratio_down")) { if (ret == 3 && val_1 < cm_mgr_num_array) vcore_power_ratio_down[val_1] = val_2; #if defined(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && defined(USE_CM_MGR_AT_SSPM) cm_mgr_to_sspm_command(IPI_CM_MGR_VCORE_POWER_RATIO_DOWN, val_1 << 16 | val_2); #endif /* CONFIG_MTK_TINYSYS_SSPM_SUPPORT && defined(USE_CM_MGR_AT_SSPM) */ } else if (!strcmp(cmd, "debounce_times_up_adb")) { if (ret == 3 && val_1 < cm_mgr_num_array) debounce_times_up_adb[val_1] = val_2; #if defined(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && defined(USE_CM_MGR_AT_SSPM) cm_mgr_to_sspm_command(IPI_CM_MGR_DEBOUNCE_UP, val_1 << 16 | val_2); #endif /* CONFIG_MTK_TINYSYS_SSPM_SUPPORT && defined(USE_CM_MGR_AT_SSPM) */ } else if (!strcmp(cmd, "debounce_times_down_adb")) { if (ret == 3 && val_1 < cm_mgr_num_array) debounce_times_down_adb[val_1] = val_2; #if defined(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && defined(USE_CM_MGR_AT_SSPM) cm_mgr_to_sspm_command(IPI_CM_MGR_DEBOUNCE_DOWN, val_1 << 16 | val_2); #endif /* CONFIG_MTK_TINYSYS_SSPM_SUPPORT && defined(USE_CM_MGR_AT_SSPM) */ } else if (!strcmp(cmd, "debounce_times_reset_adb")) { debounce_times_reset_adb = val_1; #if defined(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && defined(USE_CM_MGR_AT_SSPM) cm_mgr_to_sspm_command(IPI_CM_MGR_DEBOUNCE_TIMES_RESET_ADB, debounce_times_reset_adb); #endif /* CONFIG_MTK_TINYSYS_SSPM_SUPPORT && defined(USE_CM_MGR_AT_SSPM) */ } else if (!strcmp(cmd, "cpu_power_bcpu_weight_max")) { if (cpu_power_bcpu_weight_max < cpu_power_bcpu_weight_min) { ret = -1; } else { cpu_power_bcpu_weight_max = val_1; #if defined(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && defined(USE_CM_MGR_AT_SSPM) cm_mgr_to_sspm_command(IPI_CM_MGR_BCPU_WEIGHT_MAX_SET, val_1); #endif /* CONFIG_MTK_TINYSYS_SSPM_SUPPORT */ } } else if (!strcmp(cmd, "cpu_power_bcpu_weight_min")) { if (cpu_power_bcpu_weight_max < cpu_power_bcpu_weight_min) { ret = -1; } else { cpu_power_bcpu_weight_min = val_1; #if defined(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && defined(USE_CM_MGR_AT_SSPM) cm_mgr_to_sspm_command(IPI_CM_MGR_BCPU_WEIGHT_MIN_SET, val_1); #endif /* CONFIG_MTK_TINYSYS_SSPM_SUPPORT */ } } else if (!strcmp(cmd, "debounce_times_perf_down")) { debounce_times_perf_down = val_1; } else if (!strcmp(cmd, "debounce_times_perf_force_down")) { debounce_times_perf_force_down = val_1; } else if (!strcmp(cmd, "1")) { /* cm_mgr_perf_force_enable */ cm_mgr_perf_force_enable = 1; cm_mgr_perf_set_force_status(cm_mgr_perf_force_enable); } else if (!strcmp(cmd, "0")) { /* cm_mgr_perf_force_enable */ cm_mgr_perf_force_enable = 0; cm_mgr_perf_set_force_status(cm_mgr_perf_force_enable); } else if (!strcmp(cmd, "cm_mgr_cpu_map_dram_enable")) { cm_mgr_cpu_map_dram_enable = !!val_1; } else if (!strcmp(cmd, "cm_mgr_cpu_map_skip_cpu_opp")) { cm_mgr_cpu_map_skip_cpu_opp = val_1; cm_mgr_cpu_map_update_table(); } else if (!strcmp(cmd, "cm_mgr_cpu_map_emi_opp")) { cm_mgr_cpu_map_emi_opp = val_1; cm_mgr_cpu_map_update_table(); } else { dbg_cm_mgr_platform_write(ret, cmd, val_1, val_2); } out: if (ret < 0) return ret; return count; } static struct kobj_attribute dbg_cm_mgr_attribute = __ATTR(dbg_cm_mgr, 0644, dbg_cm_mgr_show, dbg_cm_mgr_store); static struct attribute *attrs[] = { &dbg_cm_mgr_attribute.attr, NULL, }; static struct attribute_group attr_group = { .attrs = attrs, }; int cm_mgr_check_dts_setting(struct platform_device *pdev) { struct resource *res; struct device *dev = &pdev->dev; struct device_node *node = pdev->dev.of_node; const char *buf; int ret; int opp_count; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cm_mgr_base"); cm_mgr_base = devm_ioremap_resource(dev, res); if (IS_ERR((void const *) cm_mgr_base)) { pr_info("[CM_MGR] Unable to ioremap registers\n"); return -1; } pr_info("[CM_MGR] platform-cm_mgr cm_mgr_base=%p\n", cm_mgr_base); /* cm_mgr_cpu_opp_to_dram */ opp_count = of_count_phandle_with_args(node, "cm_mgr_cpu_opp_to_dram", NULL); pr_info("#@# %s(%d) opp_count %d\n", __func__, __LINE__, opp_count); if (opp_count > 0) cm_mgr_cpu_opp_size = opp_count; else cm_mgr_cpu_opp_size = 16; cm_mgr_cpu_opp_to_dram = devm_kzalloc(dev, sizeof(int) * cm_mgr_cpu_opp_size, GFP_KERNEL); if (!cm_mgr_cpu_opp_to_dram) { ret = -ENOMEM; goto ERROR; } if (opp_count > 0) { ret = of_property_read_u32_array(node, "cm_mgr_cpu_opp_to_dram", cm_mgr_cpu_opp_to_dram, cm_mgr_cpu_opp_size); } ret = of_property_read_string(node, "status", (const char **)&buf); if (!ret) { if (!strcmp(buf, "enable")) cm_mgr_enable = 1; else cm_mgr_enable = 0; } pr_info("#@# %s(%d) cm_mgr_enable %d\n", __func__, __LINE__, cm_mgr_enable); ret = of_property_read_string(node, "use_bcpu_weight", (const char **)&buf); if (!ret) { if (!strcmp(buf, "enable")) cm_mgr_use_bcpu_weight = 1; else cm_mgr_use_bcpu_weight = 0; } pr_info("#@# %s(%d) cm_mgr_use_bcpu_weight %d\n", __func__, __LINE__, cm_mgr_use_bcpu_weight); ret = of_property_read_string(node, "use_cpu_to_dram_map", (const char **)&buf); if (!ret) { if (!strcmp(buf, "enable")) cm_mgr_use_cpu_to_dram_map = 1; else cm_mgr_use_cpu_to_dram_map = 0; } pr_info("#@# %s(%d) cm_mgr_use_cpu_to_dram_map %d\n", __func__, __LINE__, cm_mgr_use_cpu_to_dram_map); ret = of_property_read_string(node, "use_cpu_to_dram_map_new", (const char **)&buf); if (!ret) { if (!strcmp(buf, "enable")) cm_mgr_use_cpu_to_dram_map_new = 1; else cm_mgr_use_cpu_to_dram_map_new = 0; } pr_info("#@# %s(%d) cm_mgr_use_cpu_to_dram_map_new %d\n", __func__, __LINE__, cm_mgr_use_cpu_to_dram_map_new); ret = of_property_read_s32(node, "cpu_power_bcpu_weight_max", &cpu_power_bcpu_weight_max); if (!ret) cpu_power_bcpu_weight_max = 100; pr_info("#@# %s(%d) cpu_power_bcpu_weight_max %d\n", __func__, __LINE__, cpu_power_bcpu_weight_max); ret = of_property_read_s32(node, "cpu_power_bcpu_weight_min", &cpu_power_bcpu_weight_min); if (!ret) cpu_power_bcpu_weight_min = 100; pr_info("#@# %s(%d) cpu_power_bcpu_weight_min %d\n", __func__, __LINE__, cpu_power_bcpu_weight_min); /* cm_mgr args */ cm_mgr_buf = devm_kzalloc(dev, sizeof(int) * 6 * cm_mgr_num_array, GFP_KERNEL); if (!cm_mgr_buf) { ret = -ENOMEM; goto ERROR1; } cpu_power_ratio_down = cm_mgr_buf; cpu_power_ratio_up = cpu_power_ratio_down + cm_mgr_num_array; debounce_times_down_adb = cpu_power_ratio_up + cm_mgr_num_array; debounce_times_up_adb = debounce_times_down_adb + cm_mgr_num_array; vcore_power_ratio_down = debounce_times_up_adb + cm_mgr_num_array; vcore_power_ratio_up = vcore_power_ratio_down + cm_mgr_num_array; ret = of_property_read_u32_array(node, "cm_mgr,cp_down", cpu_power_ratio_down, cm_mgr_num_array); ret = of_property_read_u32_array(node, "cm_mgr,cp_up", cpu_power_ratio_up, cm_mgr_num_array); ret = of_property_read_u32_array(node, "cm_mgr,dt_down", debounce_times_down_adb, cm_mgr_num_array); ret = of_property_read_u32_array(node, "cm_mgr,dt_up", debounce_times_up_adb, cm_mgr_num_array); ret = of_property_read_u32_array(node, "cm_mgr,vp_down", vcore_power_ratio_down, cm_mgr_num_array); ret = of_property_read_u32_array(node, "cm_mgr,vp_up", vcore_power_ratio_up, cm_mgr_num_array); return 0; ERROR1: kfree(cm_mgr_cpu_opp_to_dram); ERROR: return ret; } EXPORT_SYMBOL_GPL(cm_mgr_check_dts_setting); int cm_mgr_common_init(void) { int ret; cm_mgr_kobj = kobject_create_and_add("cm_mgr", kernel_kobj); if (!cm_mgr_kobj) return -ENOMEM; ret = sysfs_create_group(cm_mgr_kobj, &attr_group); if (ret) { pr_info("[CM_MGR] FAILED TO CREATE FILESYSTEM (%d)\n", ret); kobject_put(cm_mgr_kobj); return ret; } ret = fb_register_client(&cm_mgr_fb_notifier); if (ret) { pr_info("[CM_MGR] FAILED TO REGISTER FB CLIENT (%d)\n", ret); return ret; } #if defined(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && defined(USE_CM_MGR_AT_SSPM) cm_mgr_to_sspm_command(IPI_CM_MGR_INIT, 0); cm_mgr_to_sspm_command(IPI_CM_MGR_ENABLE, cm_mgr_enable); cm_mgr_to_sspm_command(IPI_CM_MGR_SSPM_ENABLE, cm_mgr_sspm_enable); cm_mgr_to_sspm_command(IPI_CM_MGR_EMI_DEMAND_CHECK, cm_mgr_emi_demand_check); cm_mgr_to_sspm_command(IPI_CM_MGR_LOADING_LEVEL, cm_mgr_loading_level); cm_mgr_to_sspm_command(IPI_CM_MGR_LOADING_ENABLE, cm_mgr_loading_enable); cm_mgr_to_sspm_command(IPI_CM_MGR_DEBOUNCE_TIMES_RESET_ADB, debounce_times_reset_adb); if (cm_mgr_use_bcpu_weight) { cm_mgr_to_sspm_command(IPI_CM_MGR_BCPU_WEIGHT_MAX_SET, cpu_power_bcpu_weight_max); cm_mgr_to_sspm_command(IPI_CM_MGR_BCPU_WEIGHT_MIN_SET, cpu_power_bcpu_weight_min); } #endif /* CONFIG_MTK_TINYSYS_SSPM_SUPPORT && defined(USE_CM_MGR_AT_SSPM) */ return 0; } EXPORT_SYMBOL_GPL(cm_mgr_common_init); void cm_mgr_common_exit(void) { int ret; kobject_put(cm_mgr_kobj); ret = fb_unregister_client(&cm_mgr_fb_notifier); if (ret) pr_info("[CM_MGR] FAILED TO UNREGISTER FB CLIENT (%d)\n", ret); } EXPORT_SYMBOL_GPL(cm_mgr_common_exit);