13d0407baSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 23d0407baSopenharmony_ci/* 33d0407baSopenharmony_ci * Rockchip Generic dmc support. 43d0407baSopenharmony_ci * 53d0407baSopenharmony_ci * Copyright (c) 2021 Rockchip Electronics Co. Ltd. 63d0407baSopenharmony_ci * Author: Finley Xiao <finley.xiao@rock-chips.com> 73d0407baSopenharmony_ci */ 83d0407baSopenharmony_ci 93d0407baSopenharmony_ci#include <dt-bindings/clock/rockchip-ddr.h> 103d0407baSopenharmony_ci#include <dt-bindings/soc/rockchip-system-status.h> 113d0407baSopenharmony_ci#include <drm/drm_modeset_lock.h> 123d0407baSopenharmony_ci#include <linux/arm-smccc.h> 133d0407baSopenharmony_ci#include <linux/clk.h> 143d0407baSopenharmony_ci#include <linux/cpu.h> 153d0407baSopenharmony_ci#include <linux/cpufreq.h> 163d0407baSopenharmony_ci#include <linux/delay.h> 173d0407baSopenharmony_ci#include <linux/devfreq.h> 183d0407baSopenharmony_ci#include <linux/devfreq_cooling.h> 193d0407baSopenharmony_ci#include <linux/devfreq-event.h> 203d0407baSopenharmony_ci#include <linux/input.h> 213d0407baSopenharmony_ci#include <linux/interrupt.h> 223d0407baSopenharmony_ci#include <linux/irq.h> 233d0407baSopenharmony_ci#include <linux/mfd/syscon.h> 243d0407baSopenharmony_ci#include <linux/module.h> 253d0407baSopenharmony_ci#include <linux/of.h> 263d0407baSopenharmony_ci#include <linux/of_irq.h> 273d0407baSopenharmony_ci#include <linux/platform_device.h> 283d0407baSopenharmony_ci#include <linux/pm_opp.h> 293d0407baSopenharmony_ci#include <linux/pm_qos.h> 303d0407baSopenharmony_ci#include <linux/regmap.h> 313d0407baSopenharmony_ci#include <linux/regulator/consumer.h> 323d0407baSopenharmony_ci#include <linux/rockchip/rockchip_sip.h> 333d0407baSopenharmony_ci#include <linux/rwsem.h> 343d0407baSopenharmony_ci#include <linux/slab.h> 353d0407baSopenharmony_ci#include <linux/string.h> 363d0407baSopenharmony_ci#include <linux/suspend.h> 373d0407baSopenharmony_ci#include <linux/thermal.h> 383d0407baSopenharmony_ci 393d0407baSopenharmony_ci#include <soc/rockchip/pm_domains.h> 403d0407baSopenharmony_ci#include <soc/rockchip/rkfb_dmc.h> 413d0407baSopenharmony_ci#include <soc/rockchip/rockchip_dmc.h> 423d0407baSopenharmony_ci#include <soc/rockchip/rockchip_sip.h> 433d0407baSopenharmony_ci#include <soc/rockchip/rockchip_system_monitor.h> 443d0407baSopenharmony_ci#include <soc/rockchip/rockchip-system-status.h> 453d0407baSopenharmony_ci#include <soc/rockchip/rockchip_opp_select.h> 463d0407baSopenharmony_ci#include <soc/rockchip/scpi.h> 473d0407baSopenharmony_ci#include <uapi/drm/drm_mode.h> 483d0407baSopenharmony_ci 493d0407baSopenharmony_ci#include "governor.h" 503d0407baSopenharmony_ci#include "rockchip_dmc_timing.h" 513d0407baSopenharmony_ci#include "../soc/rockchip/clk.h" 523d0407baSopenharmony_ci#include "rockchip_drm_drv.h" 533d0407baSopenharmony_ci 543d0407baSopenharmony_ci#define system_status_to_dmcfreq(nb) container_of(nb, struct rockchip_dmcfreq, \ 553d0407baSopenharmony_ci status_nb) 563d0407baSopenharmony_ci#define reboot_to_dmcfreq(nb) container_of(nb, struct rockchip_dmcfreq, \ 573d0407baSopenharmony_ci reboot_nb) 583d0407baSopenharmony_ci#define boost_to_dmcfreq(work) container_of(work, struct rockchip_dmcfreq, \ 593d0407baSopenharmony_ci boost_work) 603d0407baSopenharmony_ci#define input_hd_to_dmcfreq(hd) container_of(hd, struct rockchip_dmcfreq, \ 613d0407baSopenharmony_ci input_handler) 623d0407baSopenharmony_ci 633d0407baSopenharmony_ci#define VIDEO_1080P_SIZE (1920 * 1080) 643d0407baSopenharmony_ci#define FIQ_INIT_HANDLER (0x1) 653d0407baSopenharmony_ci#define FIQ_CPU_TGT_BOOT (0x0) /* to booting cpu */ 663d0407baSopenharmony_ci#define FIQ_NUM_FOR_DCF (143) /* NA irq map to fiq for dcf */ 673d0407baSopenharmony_ci#define DTS_PAR_OFFSET (4096) 683d0407baSopenharmony_ci 693d0407baSopenharmony_ci#define FALLBACK_STATIC_TEMPERATURE 55000 703d0407baSopenharmony_ci 713d0407baSopenharmony_cistruct dmc_freq_table { 723d0407baSopenharmony_ci unsigned long freq; 733d0407baSopenharmony_ci unsigned long volt; 743d0407baSopenharmony_ci}; 753d0407baSopenharmony_ci 763d0407baSopenharmony_cistruct share_params { 773d0407baSopenharmony_ci u32 hz; 783d0407baSopenharmony_ci u32 lcdc_type; 793d0407baSopenharmony_ci u32 vop; 803d0407baSopenharmony_ci u32 vop_dclk_mode; 813d0407baSopenharmony_ci u32 sr_idle_en; 823d0407baSopenharmony_ci u32 addr_mcu_el3; 833d0407baSopenharmony_ci /* 843d0407baSopenharmony_ci * 1: need to wait flag1 853d0407baSopenharmony_ci * 0: never wait flag1 863d0407baSopenharmony_ci */ 873d0407baSopenharmony_ci u32 wait_flag1; 883d0407baSopenharmony_ci /* 893d0407baSopenharmony_ci * 1: need to wait flag1 903d0407baSopenharmony_ci * 0: never wait flag1 913d0407baSopenharmony_ci */ 923d0407baSopenharmony_ci u32 wait_flag0; 933d0407baSopenharmony_ci u32 complt_hwirq; 943d0407baSopenharmony_ci u32 update_drv_odt_cfg; 953d0407baSopenharmony_ci u32 update_deskew_cfg; 963d0407baSopenharmony_ci 973d0407baSopenharmony_ci u32 freq_count; 983d0407baSopenharmony_ci u32 freq_info_mhz[6]; 993d0407baSopenharmony_ci /* if need, add parameter after */ 1003d0407baSopenharmony_ci}; 1013d0407baSopenharmony_ci 1023d0407baSopenharmony_cistatic struct share_params *ddr_psci_param; 1033d0407baSopenharmony_ci 1043d0407baSopenharmony_cistruct rockchip_dmcfreq_ondemand_data { 1053d0407baSopenharmony_ci unsigned int upthreshold; 1063d0407baSopenharmony_ci unsigned int downdifferential; 1073d0407baSopenharmony_ci}; 1083d0407baSopenharmony_ci 1093d0407baSopenharmony_cistruct rockchip_dmcfreq { 1103d0407baSopenharmony_ci struct device *dev; 1113d0407baSopenharmony_ci struct dmcfreq_common_info info; 1123d0407baSopenharmony_ci struct rockchip_dmcfreq_ondemand_data ondemand_data; 1133d0407baSopenharmony_ci struct clk *dmc_clk; 1143d0407baSopenharmony_ci struct devfreq_event_dev **edev; 1153d0407baSopenharmony_ci struct mutex lock; /* serializes access to video_info_list */ 1163d0407baSopenharmony_ci struct dram_timing *timing; 1173d0407baSopenharmony_ci struct regulator *vdd_center; 1183d0407baSopenharmony_ci struct notifier_block status_nb; 1193d0407baSopenharmony_ci struct list_head video_info_list; 1203d0407baSopenharmony_ci struct freq_map_table *cpu_bw_tbl; 1213d0407baSopenharmony_ci struct work_struct boost_work; 1223d0407baSopenharmony_ci struct input_handler input_handler; 1233d0407baSopenharmony_ci struct monitor_dev_info *mdev_info; 1243d0407baSopenharmony_ci struct share_params *set_rate_params; 1253d0407baSopenharmony_ci 1263d0407baSopenharmony_ci unsigned long *nocp_bw; 1273d0407baSopenharmony_ci unsigned long rate, target_rate; 1283d0407baSopenharmony_ci unsigned long volt, target_volt; 1293d0407baSopenharmony_ci unsigned long auto_min_rate; 1303d0407baSopenharmony_ci unsigned long status_rate; 1313d0407baSopenharmony_ci unsigned long normal_rate; 1323d0407baSopenharmony_ci unsigned long video_1080p_rate; 1333d0407baSopenharmony_ci unsigned long video_4k_rate; 1343d0407baSopenharmony_ci unsigned long video_4k_10b_rate; 1353d0407baSopenharmony_ci unsigned long performance_rate; 1363d0407baSopenharmony_ci unsigned long hdmi_rate; 1373d0407baSopenharmony_ci unsigned long idle_rate; 1383d0407baSopenharmony_ci unsigned long suspend_rate; 1393d0407baSopenharmony_ci unsigned long reboot_rate; 1403d0407baSopenharmony_ci unsigned long boost_rate; 1413d0407baSopenharmony_ci unsigned long fixed_rate; 1423d0407baSopenharmony_ci unsigned long low_power_rate; 1433d0407baSopenharmony_ci 1443d0407baSopenharmony_ci unsigned long freq_count; 1453d0407baSopenharmony_ci unsigned long freq_info_rate[6]; 1463d0407baSopenharmony_ci unsigned long rate_low; 1473d0407baSopenharmony_ci unsigned long rate_mid_low; 1483d0407baSopenharmony_ci unsigned long rate_mid_high; 1493d0407baSopenharmony_ci unsigned long rate_high; 1503d0407baSopenharmony_ci 1513d0407baSopenharmony_ci unsigned int min_cpu_freq; 1523d0407baSopenharmony_ci unsigned int system_status_en; 1533d0407baSopenharmony_ci unsigned int refresh; 1543d0407baSopenharmony_ci int edev_count; 1553d0407baSopenharmony_ci int dfi_id; 1563d0407baSopenharmony_ci int nocp_cpu_id; 1573d0407baSopenharmony_ci 1583d0407baSopenharmony_ci bool is_fixed; 1593d0407baSopenharmony_ci bool is_set_rate_direct; 1603d0407baSopenharmony_ci 1613d0407baSopenharmony_ci struct thermal_cooling_device *devfreq_cooling; 1623d0407baSopenharmony_ci u32 static_coefficient; 1633d0407baSopenharmony_ci s32 ts[4]; 1643d0407baSopenharmony_ci struct thermal_zone_device *ddr_tz; 1653d0407baSopenharmony_ci 1663d0407baSopenharmony_ci unsigned int touchboostpulse_duration_val; 1673d0407baSopenharmony_ci u64 touchboostpulse_endtime; 1683d0407baSopenharmony_ci 1693d0407baSopenharmony_ci int (*set_auto_self_refresh)(u32 en); 1703d0407baSopenharmony_ci}; 1713d0407baSopenharmony_ci 1723d0407baSopenharmony_cistatic struct pm_qos_request pm_qos; 1733d0407baSopenharmony_ci 1743d0407baSopenharmony_cistatic inline unsigned long is_dualview(unsigned long status) 1753d0407baSopenharmony_ci{ 1763d0407baSopenharmony_ci return (status & SYS_STATUS_LCDC0) && (status & SYS_STATUS_LCDC1); 1773d0407baSopenharmony_ci} 1783d0407baSopenharmony_ci 1793d0407baSopenharmony_cistatic inline unsigned long is_isp(unsigned long status) 1803d0407baSopenharmony_ci{ 1813d0407baSopenharmony_ci return (status & SYS_STATUS_ISP) || 1823d0407baSopenharmony_ci (status & SYS_STATUS_CIF0) || 1833d0407baSopenharmony_ci (status & SYS_STATUS_CIF1); 1843d0407baSopenharmony_ci} 1853d0407baSopenharmony_ci 1863d0407baSopenharmony_ci/* 1873d0407baSopenharmony_ci * function: packaging de-skew setting to px30_ddr_dts_config_timing, 1883d0407baSopenharmony_ci * px30_ddr_dts_config_timing will pass to trust firmware, and 1893d0407baSopenharmony_ci * used direct to set register. 1903d0407baSopenharmony_ci * input: de_skew 1913d0407baSopenharmony_ci * output: tim 1923d0407baSopenharmony_ci */ 1933d0407baSopenharmony_cistatic void px30_de_skew_set_2_reg(struct rk3328_ddr_de_skew_setting *de_skew, 1943d0407baSopenharmony_ci struct px30_ddr_dts_config_timing *tim) 1953d0407baSopenharmony_ci{ 1963d0407baSopenharmony_ci u32 n; 1973d0407baSopenharmony_ci u32 offset; 1983d0407baSopenharmony_ci u32 shift; 1993d0407baSopenharmony_ci 2003d0407baSopenharmony_ci memset_io(tim->ca_skew, 0, sizeof(tim->ca_skew)); 2013d0407baSopenharmony_ci memset_io(tim->cs0_skew, 0, sizeof(tim->cs0_skew)); 2023d0407baSopenharmony_ci memset_io(tim->cs1_skew, 0, sizeof(tim->cs1_skew)); 2033d0407baSopenharmony_ci 2043d0407baSopenharmony_ci /* CA de-skew */ 2053d0407baSopenharmony_ci for (n = 0; n < ARRAY_SIZE(de_skew->ca_de_skew); n++) { 2063d0407baSopenharmony_ci offset = n / 2; 2073d0407baSopenharmony_ci shift = n % 2; 2083d0407baSopenharmony_ci /* 0 => 4; 1 => 0 */ 2093d0407baSopenharmony_ci shift = (shift == 0) ? 4 : 0; 2103d0407baSopenharmony_ci tim->ca_skew[offset] &= ~(0xf << shift); 2113d0407baSopenharmony_ci tim->ca_skew[offset] |= (de_skew->ca_de_skew[n] << shift); 2123d0407baSopenharmony_ci } 2133d0407baSopenharmony_ci 2143d0407baSopenharmony_ci /* CS0 data de-skew */ 2153d0407baSopenharmony_ci for (n = 0; n < ARRAY_SIZE(de_skew->cs0_de_skew); n++) { 2163d0407baSopenharmony_ci offset = ((n / 21) * 11) + ((n % 21) / 2); 2173d0407baSopenharmony_ci shift = ((n % 21) % 2); 2183d0407baSopenharmony_ci if ((n % 21) == 20) 2193d0407baSopenharmony_ci shift = 0; 2203d0407baSopenharmony_ci else 2213d0407baSopenharmony_ci /* 0 => 4; 1 => 0 */ 2223d0407baSopenharmony_ci shift = (shift == 0) ? 4 : 0; 2233d0407baSopenharmony_ci tim->cs0_skew[offset] &= ~(0xf << shift); 2243d0407baSopenharmony_ci tim->cs0_skew[offset] |= (de_skew->cs0_de_skew[n] << shift); 2253d0407baSopenharmony_ci } 2263d0407baSopenharmony_ci 2273d0407baSopenharmony_ci /* CS1 data de-skew */ 2283d0407baSopenharmony_ci for (n = 0; n < ARRAY_SIZE(de_skew->cs1_de_skew); n++) { 2293d0407baSopenharmony_ci offset = ((n / 21) * 11) + ((n % 21) / 2); 2303d0407baSopenharmony_ci shift = ((n % 21) % 2); 2313d0407baSopenharmony_ci if ((n % 21) == 20) 2323d0407baSopenharmony_ci shift = 0; 2333d0407baSopenharmony_ci else 2343d0407baSopenharmony_ci /* 0 => 4; 1 => 0 */ 2353d0407baSopenharmony_ci shift = (shift == 0) ? 4 : 0; 2363d0407baSopenharmony_ci tim->cs1_skew[offset] &= ~(0xf << shift); 2373d0407baSopenharmony_ci tim->cs1_skew[offset] |= (de_skew->cs1_de_skew[n] << shift); 2383d0407baSopenharmony_ci } 2393d0407baSopenharmony_ci} 2403d0407baSopenharmony_ci 2413d0407baSopenharmony_ci/* 2423d0407baSopenharmony_ci * function: packaging de-skew setting to rk3328_ddr_dts_config_timing, 2433d0407baSopenharmony_ci * rk3328_ddr_dts_config_timing will pass to trust firmware, and 2443d0407baSopenharmony_ci * used direct to set register. 2453d0407baSopenharmony_ci * input: de_skew 2463d0407baSopenharmony_ci * output: tim 2473d0407baSopenharmony_ci */ 2483d0407baSopenharmony_cistatic void 2493d0407baSopenharmony_cirk3328_de_skew_setting_2_register(struct rk3328_ddr_de_skew_setting *de_skew, 2503d0407baSopenharmony_ci struct rk3328_ddr_dts_config_timing *tim) 2513d0407baSopenharmony_ci{ 2523d0407baSopenharmony_ci u32 n; 2533d0407baSopenharmony_ci u32 offset; 2543d0407baSopenharmony_ci u32 shift; 2553d0407baSopenharmony_ci 2563d0407baSopenharmony_ci memset_io(tim->ca_skew, 0, sizeof(tim->ca_skew)); 2573d0407baSopenharmony_ci memset_io(tim->cs0_skew, 0, sizeof(tim->cs0_skew)); 2583d0407baSopenharmony_ci memset_io(tim->cs1_skew, 0, sizeof(tim->cs1_skew)); 2593d0407baSopenharmony_ci 2603d0407baSopenharmony_ci /* CA de-skew */ 2613d0407baSopenharmony_ci for (n = 0; n < ARRAY_SIZE(de_skew->ca_de_skew); n++) { 2623d0407baSopenharmony_ci offset = n / 2; 2633d0407baSopenharmony_ci shift = n % 2; 2643d0407baSopenharmony_ci /* 0 => 4; 1 => 0 */ 2653d0407baSopenharmony_ci shift = (shift == 0) ? 4 : 0; 2663d0407baSopenharmony_ci tim->ca_skew[offset] &= ~(0xf << shift); 2673d0407baSopenharmony_ci tim->ca_skew[offset] |= (de_skew->ca_de_skew[n] << shift); 2683d0407baSopenharmony_ci } 2693d0407baSopenharmony_ci 2703d0407baSopenharmony_ci /* CS0 data de-skew */ 2713d0407baSopenharmony_ci for (n = 0; n < ARRAY_SIZE(de_skew->cs0_de_skew); n++) { 2723d0407baSopenharmony_ci offset = ((n / 21) * 11) + ((n % 21) / 2); 2733d0407baSopenharmony_ci shift = ((n % 21) % 2); 2743d0407baSopenharmony_ci if ((n % 21) == 20) 2753d0407baSopenharmony_ci shift = 0; 2763d0407baSopenharmony_ci else 2773d0407baSopenharmony_ci /* 0 => 4; 1 => 0 */ 2783d0407baSopenharmony_ci shift = (shift == 0) ? 4 : 0; 2793d0407baSopenharmony_ci tim->cs0_skew[offset] &= ~(0xf << shift); 2803d0407baSopenharmony_ci tim->cs0_skew[offset] |= (de_skew->cs0_de_skew[n] << shift); 2813d0407baSopenharmony_ci } 2823d0407baSopenharmony_ci 2833d0407baSopenharmony_ci /* CS1 data de-skew */ 2843d0407baSopenharmony_ci for (n = 0; n < ARRAY_SIZE(de_skew->cs1_de_skew); n++) { 2853d0407baSopenharmony_ci offset = ((n / 21) * 11) + ((n % 21) / 2); 2863d0407baSopenharmony_ci shift = ((n % 21) % 2); 2873d0407baSopenharmony_ci if ((n % 21) == 20) 2883d0407baSopenharmony_ci shift = 0; 2893d0407baSopenharmony_ci else 2903d0407baSopenharmony_ci /* 0 => 4; 1 => 0 */ 2913d0407baSopenharmony_ci shift = (shift == 0) ? 4 : 0; 2923d0407baSopenharmony_ci tim->cs1_skew[offset] &= ~(0xf << shift); 2933d0407baSopenharmony_ci tim->cs1_skew[offset] |= (de_skew->cs1_de_skew[n] << shift); 2943d0407baSopenharmony_ci } 2953d0407baSopenharmony_ci} 2963d0407baSopenharmony_ci 2973d0407baSopenharmony_cistatic int rk_drm_get_lcdc_type(void) 2983d0407baSopenharmony_ci{ 2993d0407baSopenharmony_ci u32 lcdc_type = rockchip_drm_get_sub_dev_type(); 3003d0407baSopenharmony_ci 3013d0407baSopenharmony_ci switch (lcdc_type) { 3023d0407baSopenharmony_ci case DRM_MODE_CONNECTOR_DPI: 3033d0407baSopenharmony_ci case DRM_MODE_CONNECTOR_LVDS: 3043d0407baSopenharmony_ci lcdc_type = SCREEN_LVDS; 3053d0407baSopenharmony_ci break; 3063d0407baSopenharmony_ci case DRM_MODE_CONNECTOR_DisplayPort: 3073d0407baSopenharmony_ci lcdc_type = SCREEN_DP; 3083d0407baSopenharmony_ci break; 3093d0407baSopenharmony_ci case DRM_MODE_CONNECTOR_HDMIA: 3103d0407baSopenharmony_ci case DRM_MODE_CONNECTOR_HDMIB: 3113d0407baSopenharmony_ci lcdc_type = SCREEN_HDMI; 3123d0407baSopenharmony_ci break; 3133d0407baSopenharmony_ci case DRM_MODE_CONNECTOR_TV: 3143d0407baSopenharmony_ci lcdc_type = SCREEN_TVOUT; 3153d0407baSopenharmony_ci break; 3163d0407baSopenharmony_ci case DRM_MODE_CONNECTOR_eDP: 3173d0407baSopenharmony_ci lcdc_type = SCREEN_EDP; 3183d0407baSopenharmony_ci break; 3193d0407baSopenharmony_ci case DRM_MODE_CONNECTOR_DSI: 3203d0407baSopenharmony_ci lcdc_type = SCREEN_MIPI; 3213d0407baSopenharmony_ci break; 3223d0407baSopenharmony_ci default: 3233d0407baSopenharmony_ci lcdc_type = SCREEN_NULL; 3243d0407baSopenharmony_ci break; 3253d0407baSopenharmony_ci } 3263d0407baSopenharmony_ci 3273d0407baSopenharmony_ci return lcdc_type; 3283d0407baSopenharmony_ci} 3293d0407baSopenharmony_ci 3303d0407baSopenharmony_cistatic int rockchip_ddr_set_rate(unsigned long target_rate) 3313d0407baSopenharmony_ci{ 3323d0407baSopenharmony_ci struct arm_smccc_res res; 3333d0407baSopenharmony_ci 3343d0407baSopenharmony_ci ddr_psci_param->hz = target_rate; 3353d0407baSopenharmony_ci ddr_psci_param->lcdc_type = rk_drm_get_lcdc_type(); 3363d0407baSopenharmony_ci ddr_psci_param->wait_flag1 = 1; 3373d0407baSopenharmony_ci ddr_psci_param->wait_flag0 = 1; 3383d0407baSopenharmony_ci 3393d0407baSopenharmony_ci res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0, 3403d0407baSopenharmony_ci ROCKCHIP_SIP_CONFIG_DRAM_SET_RATE); 3413d0407baSopenharmony_ci 3423d0407baSopenharmony_ci if ((int)res.a1 == SIP_RET_SET_RATE_TIMEOUT) 3433d0407baSopenharmony_ci rockchip_dmcfreq_wait_complete(); 3443d0407baSopenharmony_ci 3453d0407baSopenharmony_ci return res.a0; 3463d0407baSopenharmony_ci} 3473d0407baSopenharmony_ci 3483d0407baSopenharmony_cistatic int rockchip_dmcfreq_target(struct device *dev, unsigned long *freq, 3493d0407baSopenharmony_ci u32 flags) 3503d0407baSopenharmony_ci{ 3513d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq = dev_get_drvdata(dev); 3523d0407baSopenharmony_ci struct dev_pm_opp *opp; 3533d0407baSopenharmony_ci struct cpufreq_policy *policy; 3543d0407baSopenharmony_ci unsigned long old_clk_rate = dmcfreq->rate; 3553d0407baSopenharmony_ci unsigned long target_volt, target_rate; 3563d0407baSopenharmony_ci unsigned int cpu_cur, cpufreq_cur; 3573d0407baSopenharmony_ci bool is_cpufreq_changed = false; 3583d0407baSopenharmony_ci int err = 0; 3593d0407baSopenharmony_ci 3603d0407baSopenharmony_ci opp = devfreq_recommended_opp(dev, freq, flags); 3613d0407baSopenharmony_ci if (IS_ERR(opp)) { 3623d0407baSopenharmony_ci dev_err(dev, "Failed to find opp for %lu Hz\n", *freq); 3633d0407baSopenharmony_ci return PTR_ERR(opp); 3643d0407baSopenharmony_ci } 3653d0407baSopenharmony_ci target_volt = dev_pm_opp_get_voltage(opp); 3663d0407baSopenharmony_ci dev_pm_opp_put(opp); 3673d0407baSopenharmony_ci 3683d0407baSopenharmony_ci if (dmcfreq->is_set_rate_direct) { 3693d0407baSopenharmony_ci target_rate = *freq; 3703d0407baSopenharmony_ci } else { 3713d0407baSopenharmony_ci target_rate = clk_round_rate(dmcfreq->dmc_clk, *freq); 3723d0407baSopenharmony_ci if ((long)target_rate <= 0) 3733d0407baSopenharmony_ci target_rate = *freq; 3743d0407baSopenharmony_ci } 3753d0407baSopenharmony_ci 3763d0407baSopenharmony_ci if (dmcfreq->rate == target_rate) { 3773d0407baSopenharmony_ci if (dmcfreq->volt == target_volt) 3783d0407baSopenharmony_ci return 0; 3793d0407baSopenharmony_ci err = regulator_set_voltage(dmcfreq->vdd_center, target_volt, 3803d0407baSopenharmony_ci INT_MAX); 3813d0407baSopenharmony_ci if (err) { 3823d0407baSopenharmony_ci dev_err(dev, "Cannot set voltage %lu uV\n", 3833d0407baSopenharmony_ci target_volt); 3843d0407baSopenharmony_ci return err; 3853d0407baSopenharmony_ci } 3863d0407baSopenharmony_ci dmcfreq->volt = target_volt; 3873d0407baSopenharmony_ci return 0; 3883d0407baSopenharmony_ci } else if (!dmcfreq->volt) { 3893d0407baSopenharmony_ci dmcfreq->volt = regulator_get_voltage(dmcfreq->vdd_center); 3903d0407baSopenharmony_ci } 3913d0407baSopenharmony_ci 3923d0407baSopenharmony_ci /* 3933d0407baSopenharmony_ci * We need to prevent cpu hotplug from happening while a dmc freq rate 3943d0407baSopenharmony_ci * change is happening. 3953d0407baSopenharmony_ci * 3963d0407baSopenharmony_ci * Do this before taking the policy rwsem to avoid deadlocks between the 3973d0407baSopenharmony_ci * mutex that is locked/unlocked in cpu_hotplug_disable/enable. And it 3983d0407baSopenharmony_ci * can also avoid deadlocks between the mutex that is locked/unlocked 3993d0407baSopenharmony_ci * in get/put_online_cpus (such as store_scaling_max_freq()). 4003d0407baSopenharmony_ci */ 4013d0407baSopenharmony_ci get_online_cpus(); 4023d0407baSopenharmony_ci 4033d0407baSopenharmony_ci /* 4043d0407baSopenharmony_ci * Go to specified cpufreq and block other cpufreq changes since 4053d0407baSopenharmony_ci * set_rate needs to complete during vblank. 4063d0407baSopenharmony_ci */ 4073d0407baSopenharmony_ci cpu_cur = raw_smp_processor_id(); 4083d0407baSopenharmony_ci policy = cpufreq_cpu_get(cpu_cur); 4093d0407baSopenharmony_ci if (!policy) { 4103d0407baSopenharmony_ci dev_err(dev, "cpu%d policy NULL\n", cpu_cur); 4113d0407baSopenharmony_ci goto cpufreq; 4123d0407baSopenharmony_ci } 4133d0407baSopenharmony_ci down_write(&policy->rwsem); 4143d0407baSopenharmony_ci cpufreq_cur = cpufreq_quick_get(cpu_cur); 4153d0407baSopenharmony_ci 4163d0407baSopenharmony_ci /* If we're thermally throttled; don't change; */ 4173d0407baSopenharmony_ci if (dmcfreq->min_cpu_freq && cpufreq_cur < dmcfreq->min_cpu_freq) { 4183d0407baSopenharmony_ci if (policy->max >= dmcfreq->min_cpu_freq) { 4193d0407baSopenharmony_ci __cpufreq_driver_target(policy, dmcfreq->min_cpu_freq, 4203d0407baSopenharmony_ci CPUFREQ_RELATION_L); 4213d0407baSopenharmony_ci is_cpufreq_changed = true; 4223d0407baSopenharmony_ci } else { 4233d0407baSopenharmony_ci dev_dbg(dev, "CPU may too slow for DMC (%d MHz)\n", 4243d0407baSopenharmony_ci policy->max); 4253d0407baSopenharmony_ci } 4263d0407baSopenharmony_ci } 4273d0407baSopenharmony_ci 4283d0407baSopenharmony_ci /* 4293d0407baSopenharmony_ci * If frequency scaling from low to high, adjust voltage first. 4303d0407baSopenharmony_ci * If frequency scaling from high to low, adjust frequency first. 4313d0407baSopenharmony_ci */ 4323d0407baSopenharmony_ci if (old_clk_rate < target_rate) { 4333d0407baSopenharmony_ci err = regulator_set_voltage(dmcfreq->vdd_center, target_volt, 4343d0407baSopenharmony_ci INT_MAX); 4353d0407baSopenharmony_ci if (err) { 4363d0407baSopenharmony_ci dev_err(dev, "Cannot set voltage %lu uV\n", 4373d0407baSopenharmony_ci target_volt); 4383d0407baSopenharmony_ci goto out; 4393d0407baSopenharmony_ci } 4403d0407baSopenharmony_ci } 4413d0407baSopenharmony_ci 4423d0407baSopenharmony_ci /* 4433d0407baSopenharmony_ci * Writer in rwsem may block readers even during its waiting in queue, 4443d0407baSopenharmony_ci * and this may lead to a deadlock when the code path takes read sem 4453d0407baSopenharmony_ci * twice (e.g. one in vop_lock() and another in rockchip_pmu_lock()). 4463d0407baSopenharmony_ci * As a (suboptimal) workaround, let writer to spin until it gets the 4473d0407baSopenharmony_ci * lock. 4483d0407baSopenharmony_ci */ 4493d0407baSopenharmony_ci while (!rockchip_dmcfreq_write_trylock()) 4503d0407baSopenharmony_ci cond_resched(); 4513d0407baSopenharmony_ci dev_dbg(dev, "%lu-->%lu\n", old_clk_rate, target_rate); 4523d0407baSopenharmony_ci 4533d0407baSopenharmony_ci if (dmcfreq->set_rate_params) { 4543d0407baSopenharmony_ci dmcfreq->set_rate_params->lcdc_type = rk_drm_get_lcdc_type(); 4553d0407baSopenharmony_ci dmcfreq->set_rate_params->wait_flag1 = 1; 4563d0407baSopenharmony_ci dmcfreq->set_rate_params->wait_flag0 = 1; 4573d0407baSopenharmony_ci } 4583d0407baSopenharmony_ci 4593d0407baSopenharmony_ci if (dmcfreq->is_set_rate_direct) 4603d0407baSopenharmony_ci err = rockchip_ddr_set_rate(target_rate); 4613d0407baSopenharmony_ci else 4623d0407baSopenharmony_ci err = clk_set_rate(dmcfreq->dmc_clk, target_rate); 4633d0407baSopenharmony_ci 4643d0407baSopenharmony_ci rockchip_dmcfreq_write_unlock(); 4653d0407baSopenharmony_ci if (err) { 4663d0407baSopenharmony_ci dev_err(dev, "Cannot set frequency %lu (%d)\n", 4673d0407baSopenharmony_ci target_rate, err); 4683d0407baSopenharmony_ci regulator_set_voltage(dmcfreq->vdd_center, dmcfreq->volt, 4693d0407baSopenharmony_ci INT_MAX); 4703d0407baSopenharmony_ci goto out; 4713d0407baSopenharmony_ci } 4723d0407baSopenharmony_ci 4733d0407baSopenharmony_ci /* 4743d0407baSopenharmony_ci * Check the dpll rate, 4753d0407baSopenharmony_ci * There only two result we will get, 4763d0407baSopenharmony_ci * 1. Ddr frequency scaling fail, we still get the old rate. 4773d0407baSopenharmony_ci * 2. Ddr frequency scaling sucessful, we get the rate we set. 4783d0407baSopenharmony_ci */ 4793d0407baSopenharmony_ci dmcfreq->rate = clk_get_rate(dmcfreq->dmc_clk); 4803d0407baSopenharmony_ci 4813d0407baSopenharmony_ci /* If get the incorrect rate, set voltage to old value. */ 4823d0407baSopenharmony_ci if (dmcfreq->rate != target_rate) { 4833d0407baSopenharmony_ci dev_err(dev, "Get wrong frequency, Request %lu, Current %lu\n", 4843d0407baSopenharmony_ci target_rate, dmcfreq->rate); 4853d0407baSopenharmony_ci regulator_set_voltage(dmcfreq->vdd_center, dmcfreq->volt, 4863d0407baSopenharmony_ci INT_MAX); 4873d0407baSopenharmony_ci goto out; 4883d0407baSopenharmony_ci } else if (old_clk_rate > target_rate) { 4893d0407baSopenharmony_ci err = regulator_set_voltage(dmcfreq->vdd_center, target_volt, 4903d0407baSopenharmony_ci INT_MAX); 4913d0407baSopenharmony_ci if (err) { 4923d0407baSopenharmony_ci dev_err(dev, "Cannot set vol %lu uV\n", target_volt); 4933d0407baSopenharmony_ci goto out; 4943d0407baSopenharmony_ci } 4953d0407baSopenharmony_ci } 4963d0407baSopenharmony_ci 4973d0407baSopenharmony_ci if (dmcfreq->info.devfreq) { 4983d0407baSopenharmony_ci struct devfreq *devfreq = dmcfreq->info.devfreq; 4993d0407baSopenharmony_ci 5003d0407baSopenharmony_ci devfreq->last_status.current_frequency = *freq; 5013d0407baSopenharmony_ci } 5023d0407baSopenharmony_ci 5033d0407baSopenharmony_ci dmcfreq->volt = target_volt; 5043d0407baSopenharmony_ciout: 5053d0407baSopenharmony_ci if (is_cpufreq_changed) 5063d0407baSopenharmony_ci __cpufreq_driver_target(policy, cpufreq_cur, 5073d0407baSopenharmony_ci CPUFREQ_RELATION_L); 5083d0407baSopenharmony_ci up_write(&policy->rwsem); 5093d0407baSopenharmony_ci cpufreq_cpu_put(policy); 5103d0407baSopenharmony_cicpufreq: 5113d0407baSopenharmony_ci put_online_cpus(); 5123d0407baSopenharmony_ci return err; 5133d0407baSopenharmony_ci} 5143d0407baSopenharmony_ci 5153d0407baSopenharmony_cistatic int rockchip_dmcfreq_get_dev_status(struct device *dev, 5163d0407baSopenharmony_ci struct devfreq_dev_status *stat) 5173d0407baSopenharmony_ci{ 5183d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq = dev_get_drvdata(dev); 5193d0407baSopenharmony_ci struct devfreq_event_data edata; 5203d0407baSopenharmony_ci int i, ret = 0; 5213d0407baSopenharmony_ci 5223d0407baSopenharmony_ci if (!dmcfreq->info.auto_freq_en) 5233d0407baSopenharmony_ci return -EINVAL; 5243d0407baSopenharmony_ci 5253d0407baSopenharmony_ci for (i = 0; i < dmcfreq->edev_count; i++) { 5263d0407baSopenharmony_ci ret = devfreq_event_get_event(dmcfreq->edev[i], &edata); 5273d0407baSopenharmony_ci if (ret < 0) { 5283d0407baSopenharmony_ci dev_err(dev, "failed to get event %s\n", 5293d0407baSopenharmony_ci dmcfreq->edev[i]->desc->name); 5303d0407baSopenharmony_ci return ret; 5313d0407baSopenharmony_ci } 5323d0407baSopenharmony_ci if (i == dmcfreq->dfi_id) { 5333d0407baSopenharmony_ci stat->busy_time = edata.load_count; 5343d0407baSopenharmony_ci stat->total_time = edata.total_count; 5353d0407baSopenharmony_ci } else { 5363d0407baSopenharmony_ci dmcfreq->nocp_bw[i] = edata.load_count; 5373d0407baSopenharmony_ci } 5383d0407baSopenharmony_ci } 5393d0407baSopenharmony_ci 5403d0407baSopenharmony_ci return 0; 5413d0407baSopenharmony_ci} 5423d0407baSopenharmony_ci 5433d0407baSopenharmony_cistatic int rockchip_dmcfreq_get_cur_freq(struct device *dev, 5443d0407baSopenharmony_ci unsigned long *freq) 5453d0407baSopenharmony_ci{ 5463d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq = dev_get_drvdata(dev); 5473d0407baSopenharmony_ci 5483d0407baSopenharmony_ci *freq = dmcfreq->rate; 5493d0407baSopenharmony_ci 5503d0407baSopenharmony_ci return 0; 5513d0407baSopenharmony_ci} 5523d0407baSopenharmony_ci 5533d0407baSopenharmony_cistatic struct devfreq_dev_profile rockchip_devfreq_dmc_profile = { 5543d0407baSopenharmony_ci .polling_ms = 50, 5553d0407baSopenharmony_ci .target = rockchip_dmcfreq_target, 5563d0407baSopenharmony_ci .get_dev_status = rockchip_dmcfreq_get_dev_status, 5573d0407baSopenharmony_ci .get_cur_freq = rockchip_dmcfreq_get_cur_freq, 5583d0407baSopenharmony_ci}; 5593d0407baSopenharmony_ci 5603d0407baSopenharmony_ci 5613d0407baSopenharmony_cistatic inline void reset_last_status(struct devfreq *devfreq) 5623d0407baSopenharmony_ci{ 5633d0407baSopenharmony_ci devfreq->last_status.total_time = 1; 5643d0407baSopenharmony_ci devfreq->last_status.busy_time = 1; 5653d0407baSopenharmony_ci} 5663d0407baSopenharmony_ci 5673d0407baSopenharmony_cistatic void of_get_px30_timings(struct device *dev, 5683d0407baSopenharmony_ci struct device_node *np, uint32_t *timing) 5693d0407baSopenharmony_ci{ 5703d0407baSopenharmony_ci struct device_node *np_tim; 5713d0407baSopenharmony_ci u32 *p; 5723d0407baSopenharmony_ci struct px30_ddr_dts_config_timing *dts_timing; 5733d0407baSopenharmony_ci struct rk3328_ddr_de_skew_setting *de_skew; 5743d0407baSopenharmony_ci int ret = 0; 5753d0407baSopenharmony_ci u32 i; 5763d0407baSopenharmony_ci 5773d0407baSopenharmony_ci dts_timing = 5783d0407baSopenharmony_ci (struct px30_ddr_dts_config_timing *)(timing + 5793d0407baSopenharmony_ci DTS_PAR_OFFSET / 4); 5803d0407baSopenharmony_ci 5813d0407baSopenharmony_ci np_tim = of_parse_phandle(np, "ddr_timing", 0); 5823d0407baSopenharmony_ci if (!np_tim) { 5833d0407baSopenharmony_ci ret = -EINVAL; 5843d0407baSopenharmony_ci goto end; 5853d0407baSopenharmony_ci } 5863d0407baSopenharmony_ci de_skew = kmalloc(sizeof(*de_skew), GFP_KERNEL); 5873d0407baSopenharmony_ci if (!de_skew) { 5883d0407baSopenharmony_ci ret = -ENOMEM; 5893d0407baSopenharmony_ci goto end; 5903d0407baSopenharmony_ci } 5913d0407baSopenharmony_ci p = (u32 *)dts_timing; 5923d0407baSopenharmony_ci for (i = 0; i < ARRAY_SIZE(px30_dts_timing); i++) { 5933d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, px30_dts_timing[i], 5943d0407baSopenharmony_ci p + i); 5953d0407baSopenharmony_ci } 5963d0407baSopenharmony_ci p = (u32 *)de_skew->ca_de_skew; 5973d0407baSopenharmony_ci for (i = 0; i < ARRAY_SIZE(rk3328_dts_ca_timing); i++) { 5983d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, rk3328_dts_ca_timing[i], 5993d0407baSopenharmony_ci p + i); 6003d0407baSopenharmony_ci } 6013d0407baSopenharmony_ci p = (u32 *)de_skew->cs0_de_skew; 6023d0407baSopenharmony_ci for (i = 0; i < ARRAY_SIZE(rk3328_dts_cs0_timing); i++) { 6033d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, rk3328_dts_cs0_timing[i], 6043d0407baSopenharmony_ci p + i); 6053d0407baSopenharmony_ci } 6063d0407baSopenharmony_ci p = (u32 *)de_skew->cs1_de_skew; 6073d0407baSopenharmony_ci for (i = 0; i < ARRAY_SIZE(rk3328_dts_cs1_timing); i++) { 6083d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, rk3328_dts_cs1_timing[i], 6093d0407baSopenharmony_ci p + i); 6103d0407baSopenharmony_ci } 6113d0407baSopenharmony_ci if (!ret) 6123d0407baSopenharmony_ci px30_de_skew_set_2_reg(de_skew, dts_timing); 6133d0407baSopenharmony_ci kfree(de_skew); 6143d0407baSopenharmony_ciend: 6153d0407baSopenharmony_ci if (!ret) { 6163d0407baSopenharmony_ci dts_timing->available = 1; 6173d0407baSopenharmony_ci } else { 6183d0407baSopenharmony_ci dts_timing->available = 0; 6193d0407baSopenharmony_ci dev_err(dev, "of_get_ddr_timings: fail\n"); 6203d0407baSopenharmony_ci } 6213d0407baSopenharmony_ci 6223d0407baSopenharmony_ci of_node_put(np_tim); 6233d0407baSopenharmony_ci} 6243d0407baSopenharmony_ci 6253d0407baSopenharmony_cistatic void of_get_rk1808_timings(struct device *dev, 6263d0407baSopenharmony_ci struct device_node *np, uint32_t *timing) 6273d0407baSopenharmony_ci{ 6283d0407baSopenharmony_ci struct device_node *np_tim; 6293d0407baSopenharmony_ci u32 *p; 6303d0407baSopenharmony_ci struct rk1808_ddr_dts_config_timing *dts_timing; 6313d0407baSopenharmony_ci int ret = 0; 6323d0407baSopenharmony_ci u32 i; 6333d0407baSopenharmony_ci 6343d0407baSopenharmony_ci dts_timing = 6353d0407baSopenharmony_ci (struct rk1808_ddr_dts_config_timing *)(timing + 6363d0407baSopenharmony_ci DTS_PAR_OFFSET / 4); 6373d0407baSopenharmony_ci 6383d0407baSopenharmony_ci np_tim = of_parse_phandle(np, "ddr_timing", 0); 6393d0407baSopenharmony_ci if (!np_tim) { 6403d0407baSopenharmony_ci ret = -EINVAL; 6413d0407baSopenharmony_ci goto end; 6423d0407baSopenharmony_ci } 6433d0407baSopenharmony_ci 6443d0407baSopenharmony_ci p = (u32 *)dts_timing; 6453d0407baSopenharmony_ci for (i = 0; i < ARRAY_SIZE(px30_dts_timing); i++) { 6463d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, px30_dts_timing[i], 6473d0407baSopenharmony_ci p + i); 6483d0407baSopenharmony_ci } 6493d0407baSopenharmony_ci p = (u32 *)dts_timing->ca_de_skew; 6503d0407baSopenharmony_ci for (i = 0; i < ARRAY_SIZE(rk1808_dts_ca_timing); i++) { 6513d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, rk1808_dts_ca_timing[i], 6523d0407baSopenharmony_ci p + i); 6533d0407baSopenharmony_ci } 6543d0407baSopenharmony_ci p = (u32 *)dts_timing->cs0_a_de_skew; 6553d0407baSopenharmony_ci for (i = 0; i < ARRAY_SIZE(rk1808_dts_cs0_a_timing); i++) { 6563d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, rk1808_dts_cs0_a_timing[i], 6573d0407baSopenharmony_ci p + i); 6583d0407baSopenharmony_ci } 6593d0407baSopenharmony_ci p = (u32 *)dts_timing->cs0_b_de_skew; 6603d0407baSopenharmony_ci for (i = 0; i < ARRAY_SIZE(rk1808_dts_cs0_b_timing); i++) { 6613d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, rk1808_dts_cs0_b_timing[i], 6623d0407baSopenharmony_ci p + i); 6633d0407baSopenharmony_ci } 6643d0407baSopenharmony_ci p = (u32 *)dts_timing->cs1_a_de_skew; 6653d0407baSopenharmony_ci for (i = 0; i < ARRAY_SIZE(rk1808_dts_cs1_a_timing); i++) { 6663d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, rk1808_dts_cs1_a_timing[i], 6673d0407baSopenharmony_ci p + i); 6683d0407baSopenharmony_ci } 6693d0407baSopenharmony_ci p = (u32 *)dts_timing->cs1_b_de_skew; 6703d0407baSopenharmony_ci for (i = 0; i < ARRAY_SIZE(rk1808_dts_cs1_b_timing); i++) { 6713d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, rk1808_dts_cs1_b_timing[i], 6723d0407baSopenharmony_ci p + i); 6733d0407baSopenharmony_ci } 6743d0407baSopenharmony_ci 6753d0407baSopenharmony_ciend: 6763d0407baSopenharmony_ci if (!ret) { 6773d0407baSopenharmony_ci dts_timing->available = 1; 6783d0407baSopenharmony_ci } else { 6793d0407baSopenharmony_ci dts_timing->available = 0; 6803d0407baSopenharmony_ci dev_err(dev, "of_get_ddr_timings: fail\n"); 6813d0407baSopenharmony_ci } 6823d0407baSopenharmony_ci 6833d0407baSopenharmony_ci of_node_put(np_tim); 6843d0407baSopenharmony_ci} 6853d0407baSopenharmony_ci 6863d0407baSopenharmony_cistatic void of_get_rk3128_timings(struct device *dev, 6873d0407baSopenharmony_ci struct device_node *np, uint32_t *timing) 6883d0407baSopenharmony_ci{ 6893d0407baSopenharmony_ci struct device_node *np_tim; 6903d0407baSopenharmony_ci u32 *p; 6913d0407baSopenharmony_ci struct rk3128_ddr_dts_config_timing *dts_timing; 6923d0407baSopenharmony_ci struct share_params *init_timing; 6933d0407baSopenharmony_ci int ret = 0; 6943d0407baSopenharmony_ci u32 i; 6953d0407baSopenharmony_ci 6963d0407baSopenharmony_ci init_timing = (struct share_params *)timing; 6973d0407baSopenharmony_ci 6983d0407baSopenharmony_ci if (of_property_read_u32(np, "vop-dclk-mode", 6993d0407baSopenharmony_ci &init_timing->vop_dclk_mode)) 7003d0407baSopenharmony_ci init_timing->vop_dclk_mode = 0; 7013d0407baSopenharmony_ci 7023d0407baSopenharmony_ci p = timing + DTS_PAR_OFFSET / 4; 7033d0407baSopenharmony_ci np_tim = of_parse_phandle(np, "rockchip,ddr_timing", 0); 7043d0407baSopenharmony_ci if (!np_tim) { 7053d0407baSopenharmony_ci ret = -EINVAL; 7063d0407baSopenharmony_ci goto end; 7073d0407baSopenharmony_ci } 7083d0407baSopenharmony_ci for (i = 0; i < ARRAY_SIZE(rk3128_dts_timing); i++) { 7093d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, rk3128_dts_timing[i], 7103d0407baSopenharmony_ci p + i); 7113d0407baSopenharmony_ci } 7123d0407baSopenharmony_ciend: 7133d0407baSopenharmony_ci dts_timing = 7143d0407baSopenharmony_ci (struct rk3128_ddr_dts_config_timing *)(timing + 7153d0407baSopenharmony_ci DTS_PAR_OFFSET / 4); 7163d0407baSopenharmony_ci if (!ret) { 7173d0407baSopenharmony_ci dts_timing->available = 1; 7183d0407baSopenharmony_ci } else { 7193d0407baSopenharmony_ci dts_timing->available = 0; 7203d0407baSopenharmony_ci dev_err(dev, "of_get_ddr_timings: fail\n"); 7213d0407baSopenharmony_ci } 7223d0407baSopenharmony_ci 7233d0407baSopenharmony_ci of_node_put(np_tim); 7243d0407baSopenharmony_ci} 7253d0407baSopenharmony_ci 7263d0407baSopenharmony_cistatic uint32_t of_get_rk3228_timings(struct device *dev, 7273d0407baSopenharmony_ci struct device_node *np, uint32_t *timing) 7283d0407baSopenharmony_ci{ 7293d0407baSopenharmony_ci struct device_node *np_tim; 7303d0407baSopenharmony_ci u32 *p; 7313d0407baSopenharmony_ci int ret = 0; 7323d0407baSopenharmony_ci u32 i; 7333d0407baSopenharmony_ci 7343d0407baSopenharmony_ci p = timing + DTS_PAR_OFFSET / 4; 7353d0407baSopenharmony_ci np_tim = of_parse_phandle(np, "rockchip,dram_timing", 0); 7363d0407baSopenharmony_ci if (!np_tim) { 7373d0407baSopenharmony_ci ret = -EINVAL; 7383d0407baSopenharmony_ci goto end; 7393d0407baSopenharmony_ci } 7403d0407baSopenharmony_ci for (i = 0; i < ARRAY_SIZE(rk3228_dts_timing); i++) { 7413d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, rk3228_dts_timing[i], 7423d0407baSopenharmony_ci p + i); 7433d0407baSopenharmony_ci } 7443d0407baSopenharmony_ciend: 7453d0407baSopenharmony_ci if (ret) 7463d0407baSopenharmony_ci dev_err(dev, "of_get_ddr_timings: fail\n"); 7473d0407baSopenharmony_ci 7483d0407baSopenharmony_ci of_node_put(np_tim); 7493d0407baSopenharmony_ci return ret; 7503d0407baSopenharmony_ci} 7513d0407baSopenharmony_ci 7523d0407baSopenharmony_cistatic void of_get_rk3288_timings(struct device *dev, 7533d0407baSopenharmony_ci struct device_node *np, uint32_t *timing) 7543d0407baSopenharmony_ci{ 7553d0407baSopenharmony_ci struct device_node *np_tim; 7563d0407baSopenharmony_ci u32 *p; 7573d0407baSopenharmony_ci struct rk3288_ddr_dts_config_timing *dts_timing; 7583d0407baSopenharmony_ci struct share_params *init_timing; 7593d0407baSopenharmony_ci int ret = 0; 7603d0407baSopenharmony_ci u32 i; 7613d0407baSopenharmony_ci 7623d0407baSopenharmony_ci init_timing = (struct share_params *)timing; 7633d0407baSopenharmony_ci 7643d0407baSopenharmony_ci if (of_property_read_u32(np, "vop-dclk-mode", 7653d0407baSopenharmony_ci &init_timing->vop_dclk_mode)) 7663d0407baSopenharmony_ci init_timing->vop_dclk_mode = 0; 7673d0407baSopenharmony_ci 7683d0407baSopenharmony_ci p = timing + DTS_PAR_OFFSET / 4; 7693d0407baSopenharmony_ci np_tim = of_parse_phandle(np, "rockchip,ddr_timing", 0); 7703d0407baSopenharmony_ci if (!np_tim) { 7713d0407baSopenharmony_ci ret = -EINVAL; 7723d0407baSopenharmony_ci goto end; 7733d0407baSopenharmony_ci } 7743d0407baSopenharmony_ci for (i = 0; i < ARRAY_SIZE(rk3288_dts_timing); i++) { 7753d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, rk3288_dts_timing[i], 7763d0407baSopenharmony_ci p + i); 7773d0407baSopenharmony_ci } 7783d0407baSopenharmony_ciend: 7793d0407baSopenharmony_ci dts_timing = 7803d0407baSopenharmony_ci (struct rk3288_ddr_dts_config_timing *)(timing + 7813d0407baSopenharmony_ci DTS_PAR_OFFSET / 4); 7823d0407baSopenharmony_ci if (!ret) { 7833d0407baSopenharmony_ci dts_timing->available = 1; 7843d0407baSopenharmony_ci } else { 7853d0407baSopenharmony_ci dts_timing->available = 0; 7863d0407baSopenharmony_ci dev_err(dev, "of_get_ddr_timings: fail\n"); 7873d0407baSopenharmony_ci } 7883d0407baSopenharmony_ci 7893d0407baSopenharmony_ci of_node_put(np_tim); 7903d0407baSopenharmony_ci} 7913d0407baSopenharmony_ci 7923d0407baSopenharmony_cistatic void of_get_rk3328_timings(struct device *dev, 7933d0407baSopenharmony_ci struct device_node *np, uint32_t *timing) 7943d0407baSopenharmony_ci{ 7953d0407baSopenharmony_ci struct device_node *np_tim; 7963d0407baSopenharmony_ci u32 *p; 7973d0407baSopenharmony_ci struct rk3328_ddr_dts_config_timing *dts_timing; 7983d0407baSopenharmony_ci struct rk3328_ddr_de_skew_setting *de_skew; 7993d0407baSopenharmony_ci int ret = 0; 8003d0407baSopenharmony_ci u32 i; 8013d0407baSopenharmony_ci 8023d0407baSopenharmony_ci dts_timing = 8033d0407baSopenharmony_ci (struct rk3328_ddr_dts_config_timing *)(timing + 8043d0407baSopenharmony_ci DTS_PAR_OFFSET / 4); 8053d0407baSopenharmony_ci 8063d0407baSopenharmony_ci np_tim = of_parse_phandle(np, "ddr_timing", 0); 8073d0407baSopenharmony_ci if (!np_tim) { 8083d0407baSopenharmony_ci ret = -EINVAL; 8093d0407baSopenharmony_ci goto end; 8103d0407baSopenharmony_ci } 8113d0407baSopenharmony_ci de_skew = kmalloc(sizeof(*de_skew), GFP_KERNEL); 8123d0407baSopenharmony_ci if (!de_skew) { 8133d0407baSopenharmony_ci ret = -ENOMEM; 8143d0407baSopenharmony_ci goto end; 8153d0407baSopenharmony_ci } 8163d0407baSopenharmony_ci p = (u32 *)dts_timing; 8173d0407baSopenharmony_ci for (i = 0; i < ARRAY_SIZE(rk3328_dts_timing); i++) { 8183d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, rk3328_dts_timing[i], 8193d0407baSopenharmony_ci p + i); 8203d0407baSopenharmony_ci } 8213d0407baSopenharmony_ci p = (u32 *)de_skew->ca_de_skew; 8223d0407baSopenharmony_ci for (i = 0; i < ARRAY_SIZE(rk3328_dts_ca_timing); i++) { 8233d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, rk3328_dts_ca_timing[i], 8243d0407baSopenharmony_ci p + i); 8253d0407baSopenharmony_ci } 8263d0407baSopenharmony_ci p = (u32 *)de_skew->cs0_de_skew; 8273d0407baSopenharmony_ci for (i = 0; i < ARRAY_SIZE(rk3328_dts_cs0_timing); i++) { 8283d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, rk3328_dts_cs0_timing[i], 8293d0407baSopenharmony_ci p + i); 8303d0407baSopenharmony_ci } 8313d0407baSopenharmony_ci p = (u32 *)de_skew->cs1_de_skew; 8323d0407baSopenharmony_ci for (i = 0; i < ARRAY_SIZE(rk3328_dts_cs1_timing); i++) { 8333d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, rk3328_dts_cs1_timing[i], 8343d0407baSopenharmony_ci p + i); 8353d0407baSopenharmony_ci } 8363d0407baSopenharmony_ci if (!ret) 8373d0407baSopenharmony_ci rk3328_de_skew_setting_2_register(de_skew, dts_timing); 8383d0407baSopenharmony_ci kfree(de_skew); 8393d0407baSopenharmony_ciend: 8403d0407baSopenharmony_ci if (!ret) { 8413d0407baSopenharmony_ci dts_timing->available = 1; 8423d0407baSopenharmony_ci } else { 8433d0407baSopenharmony_ci dts_timing->available = 0; 8443d0407baSopenharmony_ci dev_err(dev, "of_get_ddr_timings: fail\n"); 8453d0407baSopenharmony_ci } 8463d0407baSopenharmony_ci 8473d0407baSopenharmony_ci of_node_put(np_tim); 8483d0407baSopenharmony_ci} 8493d0407baSopenharmony_ci 8503d0407baSopenharmony_cistatic void of_get_rv1126_timings(struct device *dev, 8513d0407baSopenharmony_ci struct device_node *np, uint32_t *timing) 8523d0407baSopenharmony_ci{ 8533d0407baSopenharmony_ci struct device_node *np_tim; 8543d0407baSopenharmony_ci u32 *p; 8553d0407baSopenharmony_ci struct rk1808_ddr_dts_config_timing *dts_timing; 8563d0407baSopenharmony_ci int ret = 0; 8573d0407baSopenharmony_ci u32 i; 8583d0407baSopenharmony_ci 8593d0407baSopenharmony_ci dts_timing = 8603d0407baSopenharmony_ci (struct rk1808_ddr_dts_config_timing *)(timing + 8613d0407baSopenharmony_ci DTS_PAR_OFFSET / 4); 8623d0407baSopenharmony_ci 8633d0407baSopenharmony_ci np_tim = of_parse_phandle(np, "ddr_timing", 0); 8643d0407baSopenharmony_ci if (!np_tim) { 8653d0407baSopenharmony_ci ret = -EINVAL; 8663d0407baSopenharmony_ci goto end; 8673d0407baSopenharmony_ci } 8683d0407baSopenharmony_ci 8693d0407baSopenharmony_ci p = (u32 *)dts_timing; 8703d0407baSopenharmony_ci for (i = 0; i < ARRAY_SIZE(px30_dts_timing); i++) { 8713d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, px30_dts_timing[i], 8723d0407baSopenharmony_ci p + i); 8733d0407baSopenharmony_ci } 8743d0407baSopenharmony_ci p = (u32 *)dts_timing->ca_de_skew; 8753d0407baSopenharmony_ci for (i = 0; i < ARRAY_SIZE(rv1126_dts_ca_timing); i++) { 8763d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, rv1126_dts_ca_timing[i], 8773d0407baSopenharmony_ci p + i); 8783d0407baSopenharmony_ci } 8793d0407baSopenharmony_ci p = (u32 *)dts_timing->cs0_a_de_skew; 8803d0407baSopenharmony_ci for (i = 0; i < ARRAY_SIZE(rv1126_dts_cs0_a_timing); i++) { 8813d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, rv1126_dts_cs0_a_timing[i], 8823d0407baSopenharmony_ci p + i); 8833d0407baSopenharmony_ci } 8843d0407baSopenharmony_ci p = (u32 *)dts_timing->cs0_b_de_skew; 8853d0407baSopenharmony_ci for (i = 0; i < ARRAY_SIZE(rv1126_dts_cs0_b_timing); i++) { 8863d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, rv1126_dts_cs0_b_timing[i], 8873d0407baSopenharmony_ci p + i); 8883d0407baSopenharmony_ci } 8893d0407baSopenharmony_ci p = (u32 *)dts_timing->cs1_a_de_skew; 8903d0407baSopenharmony_ci for (i = 0; i < ARRAY_SIZE(rv1126_dts_cs1_a_timing); i++) { 8913d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, rv1126_dts_cs1_a_timing[i], 8923d0407baSopenharmony_ci p + i); 8933d0407baSopenharmony_ci } 8943d0407baSopenharmony_ci p = (u32 *)dts_timing->cs1_b_de_skew; 8953d0407baSopenharmony_ci for (i = 0; i < ARRAY_SIZE(rv1126_dts_cs1_b_timing); i++) { 8963d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, rv1126_dts_cs1_b_timing[i], 8973d0407baSopenharmony_ci p + i); 8983d0407baSopenharmony_ci } 8993d0407baSopenharmony_ci 9003d0407baSopenharmony_ciend: 9013d0407baSopenharmony_ci if (!ret) { 9023d0407baSopenharmony_ci dts_timing->available = 1; 9033d0407baSopenharmony_ci } else { 9043d0407baSopenharmony_ci dts_timing->available = 0; 9053d0407baSopenharmony_ci dev_err(dev, "of_get_ddr_timings: fail\n"); 9063d0407baSopenharmony_ci } 9073d0407baSopenharmony_ci 9083d0407baSopenharmony_ci of_node_put(np_tim); 9093d0407baSopenharmony_ci} 9103d0407baSopenharmony_ci 9113d0407baSopenharmony_cistatic struct rk3368_dram_timing *of_get_rk3368_timings(struct device *dev, 9123d0407baSopenharmony_ci struct device_node *np) 9133d0407baSopenharmony_ci{ 9143d0407baSopenharmony_ci struct rk3368_dram_timing *timing = NULL; 9153d0407baSopenharmony_ci struct device_node *np_tim; 9163d0407baSopenharmony_ci int ret = 0; 9173d0407baSopenharmony_ci 9183d0407baSopenharmony_ci np_tim = of_parse_phandle(np, "ddr_timing", 0); 9193d0407baSopenharmony_ci if (np_tim) { 9203d0407baSopenharmony_ci timing = devm_kzalloc(dev, sizeof(*timing), GFP_KERNEL); 9213d0407baSopenharmony_ci if (!timing) 9223d0407baSopenharmony_ci goto err; 9233d0407baSopenharmony_ci 9243d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "dram_spd_bin", 9253d0407baSopenharmony_ci &timing->dram_spd_bin); 9263d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "sr_idle", 9273d0407baSopenharmony_ci &timing->sr_idle); 9283d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "pd_idle", 9293d0407baSopenharmony_ci &timing->pd_idle); 9303d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "dram_dll_disb_freq", 9313d0407baSopenharmony_ci &timing->dram_dll_dis_freq); 9323d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "phy_dll_disb_freq", 9333d0407baSopenharmony_ci &timing->phy_dll_dis_freq); 9343d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "dram_odt_disb_freq", 9353d0407baSopenharmony_ci &timing->dram_odt_dis_freq); 9363d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "phy_odt_disb_freq", 9373d0407baSopenharmony_ci &timing->phy_odt_dis_freq); 9383d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "ddr3_drv", 9393d0407baSopenharmony_ci &timing->ddr3_drv); 9403d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "ddr3_odt", 9413d0407baSopenharmony_ci &timing->ddr3_odt); 9423d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "lpddr3_drv", 9433d0407baSopenharmony_ci &timing->lpddr3_drv); 9443d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "lpddr3_odt", 9453d0407baSopenharmony_ci &timing->lpddr3_odt); 9463d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "lpddr2_drv", 9473d0407baSopenharmony_ci &timing->lpddr2_drv); 9483d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "phy_clk_drv", 9493d0407baSopenharmony_ci &timing->phy_clk_drv); 9503d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "phy_cmd_drv", 9513d0407baSopenharmony_ci &timing->phy_cmd_drv); 9523d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "phy_dqs_drv", 9533d0407baSopenharmony_ci &timing->phy_dqs_drv); 9543d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "phy_odt", 9553d0407baSopenharmony_ci &timing->phy_odt); 9563d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "ddr_2t", 9573d0407baSopenharmony_ci &timing->ddr_2t); 9583d0407baSopenharmony_ci if (ret) { 9593d0407baSopenharmony_ci devm_kfree(dev, timing); 9603d0407baSopenharmony_ci goto err; 9613d0407baSopenharmony_ci } 9623d0407baSopenharmony_ci of_node_put(np_tim); 9633d0407baSopenharmony_ci return timing; 9643d0407baSopenharmony_ci } 9653d0407baSopenharmony_ci 9663d0407baSopenharmony_cierr: 9673d0407baSopenharmony_ci if (timing) { 9683d0407baSopenharmony_ci devm_kfree(dev, timing); 9693d0407baSopenharmony_ci timing = NULL; 9703d0407baSopenharmony_ci } 9713d0407baSopenharmony_ci of_node_put(np_tim); 9723d0407baSopenharmony_ci return timing; 9733d0407baSopenharmony_ci} 9743d0407baSopenharmony_ci 9753d0407baSopenharmony_cistatic struct rk3399_dram_timing *of_get_rk3399_timings(struct device *dev, 9763d0407baSopenharmony_ci struct device_node *np) 9773d0407baSopenharmony_ci{ 9783d0407baSopenharmony_ci struct rk3399_dram_timing *timing = NULL; 9793d0407baSopenharmony_ci struct device_node *np_tim; 9803d0407baSopenharmony_ci int ret; 9813d0407baSopenharmony_ci 9823d0407baSopenharmony_ci np_tim = of_parse_phandle(np, "ddr_timing", 0); 9833d0407baSopenharmony_ci if (np_tim) { 9843d0407baSopenharmony_ci timing = devm_kzalloc(dev, sizeof(*timing), GFP_KERNEL); 9853d0407baSopenharmony_ci if (!timing) 9863d0407baSopenharmony_ci goto err; 9873d0407baSopenharmony_ci 9883d0407baSopenharmony_ci ret = of_property_read_u32(np_tim, "ddr3_speed_bin", 9893d0407baSopenharmony_ci &timing->ddr3_speed_bin); 9903d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "pd_idle", 9913d0407baSopenharmony_ci &timing->pd_idle); 9923d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "sr_idle", 9933d0407baSopenharmony_ci &timing->sr_idle); 9943d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "sr_mc_gate_idle", 9953d0407baSopenharmony_ci &timing->sr_mc_gate_idle); 9963d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "srpd_lite_idle", 9973d0407baSopenharmony_ci &timing->srpd_lite_idle); 9983d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "standby_idle", 9993d0407baSopenharmony_ci &timing->standby_idle); 10003d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "auto_lp_dis_freq", 10013d0407baSopenharmony_ci &timing->auto_lp_dis_freq); 10023d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "ddr3_dll_dis_freq", 10033d0407baSopenharmony_ci &timing->ddr3_dll_dis_freq); 10043d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "phy_dll_dis_freq", 10053d0407baSopenharmony_ci &timing->phy_dll_dis_freq); 10063d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "ddr3_odt_dis_freq", 10073d0407baSopenharmony_ci &timing->ddr3_odt_dis_freq); 10083d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "ddr3_drv", 10093d0407baSopenharmony_ci &timing->ddr3_drv); 10103d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "ddr3_odt", 10113d0407baSopenharmony_ci &timing->ddr3_odt); 10123d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "phy_ddr3_ca_drv", 10133d0407baSopenharmony_ci &timing->phy_ddr3_ca_drv); 10143d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "phy_ddr3_dq_drv", 10153d0407baSopenharmony_ci &timing->phy_ddr3_dq_drv); 10163d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "phy_ddr3_odt", 10173d0407baSopenharmony_ci &timing->phy_ddr3_odt); 10183d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "lpddr3_odt_dis_freq", 10193d0407baSopenharmony_ci &timing->lpddr3_odt_dis_freq); 10203d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "lpddr3_drv", 10213d0407baSopenharmony_ci &timing->lpddr3_drv); 10223d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "lpddr3_odt", 10233d0407baSopenharmony_ci &timing->lpddr3_odt); 10243d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "phy_lpddr3_ca_drv", 10253d0407baSopenharmony_ci &timing->phy_lpddr3_ca_drv); 10263d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "phy_lpddr3_dq_drv", 10273d0407baSopenharmony_ci &timing->phy_lpddr3_dq_drv); 10283d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "phy_lpddr3_odt", 10293d0407baSopenharmony_ci &timing->phy_lpddr3_odt); 10303d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "lpddr4_odt_dis_freq", 10313d0407baSopenharmony_ci &timing->lpddr4_odt_dis_freq); 10323d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "lpddr4_drv", 10333d0407baSopenharmony_ci &timing->lpddr4_drv); 10343d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "lpddr4_dq_odt", 10353d0407baSopenharmony_ci &timing->lpddr4_dq_odt); 10363d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "lpddr4_ca_odt", 10373d0407baSopenharmony_ci &timing->lpddr4_ca_odt); 10383d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "phy_lpddr4_ca_drv", 10393d0407baSopenharmony_ci &timing->phy_lpddr4_ca_drv); 10403d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "phy_lpddr4_ck_cs_drv", 10413d0407baSopenharmony_ci &timing->phy_lpddr4_ck_cs_drv); 10423d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "phy_lpddr4_dq_drv", 10433d0407baSopenharmony_ci &timing->phy_lpddr4_dq_drv); 10443d0407baSopenharmony_ci ret |= of_property_read_u32(np_tim, "phy_lpddr4_odt", 10453d0407baSopenharmony_ci &timing->phy_lpddr4_odt); 10463d0407baSopenharmony_ci if (ret) { 10473d0407baSopenharmony_ci devm_kfree(dev, timing); 10483d0407baSopenharmony_ci goto err; 10493d0407baSopenharmony_ci } 10503d0407baSopenharmony_ci of_node_put(np_tim); 10513d0407baSopenharmony_ci return timing; 10523d0407baSopenharmony_ci } 10533d0407baSopenharmony_ci 10543d0407baSopenharmony_cierr: 10553d0407baSopenharmony_ci if (timing) { 10563d0407baSopenharmony_ci devm_kfree(dev, timing); 10573d0407baSopenharmony_ci timing = NULL; 10583d0407baSopenharmony_ci } 10593d0407baSopenharmony_ci of_node_put(np_tim); 10603d0407baSopenharmony_ci return timing; 10613d0407baSopenharmony_ci} 10623d0407baSopenharmony_ci 10633d0407baSopenharmony_cistatic int rockchip_ddr_set_auto_self_refresh(uint32_t en) 10643d0407baSopenharmony_ci{ 10653d0407baSopenharmony_ci struct arm_smccc_res res; 10663d0407baSopenharmony_ci 10673d0407baSopenharmony_ci ddr_psci_param->sr_idle_en = en; 10683d0407baSopenharmony_ci res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0, 10693d0407baSopenharmony_ci ROCKCHIP_SIP_CONFIG_DRAM_SET_AT_SR); 10703d0407baSopenharmony_ci 10713d0407baSopenharmony_ci return res.a0; 10723d0407baSopenharmony_ci} 10733d0407baSopenharmony_ci 10743d0407baSopenharmony_cistruct dmcfreq_wait_ctrl_t { 10753d0407baSopenharmony_ci wait_queue_head_t wait_wq; 10763d0407baSopenharmony_ci int complt_irq; 10773d0407baSopenharmony_ci int wait_flag; 10783d0407baSopenharmony_ci int wait_en; 10793d0407baSopenharmony_ci int wait_time_out_ms; 10803d0407baSopenharmony_ci int dcf_en; 10813d0407baSopenharmony_ci struct regmap *regmap_dcf; 10823d0407baSopenharmony_ci}; 10833d0407baSopenharmony_ci 10843d0407baSopenharmony_cistatic struct dmcfreq_wait_ctrl_t wait_ctrl; 10853d0407baSopenharmony_ci 10863d0407baSopenharmony_cistatic irqreturn_t wait_complete_irq(int irqno, void *dev_id) 10873d0407baSopenharmony_ci{ 10883d0407baSopenharmony_ci struct dmcfreq_wait_ctrl_t *ctrl = dev_id; 10893d0407baSopenharmony_ci 10903d0407baSopenharmony_ci ctrl->wait_flag = 0; 10913d0407baSopenharmony_ci wake_up(&ctrl->wait_wq); 10923d0407baSopenharmony_ci return IRQ_HANDLED; 10933d0407baSopenharmony_ci} 10943d0407baSopenharmony_ci 10953d0407baSopenharmony_cistatic irqreturn_t wait_dcf_complete_irq(int irqno, void *dev_id) 10963d0407baSopenharmony_ci{ 10973d0407baSopenharmony_ci struct arm_smccc_res res; 10983d0407baSopenharmony_ci struct dmcfreq_wait_ctrl_t *ctrl = dev_id; 10993d0407baSopenharmony_ci 11003d0407baSopenharmony_ci res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0, 11013d0407baSopenharmony_ci ROCKCHIP_SIP_CONFIG_DRAM_POST_SET_RATE); 11023d0407baSopenharmony_ci if (res.a0) 11033d0407baSopenharmony_ci pr_err("%s: dram post set rate error:%lx\n", __func__, res.a0); 11043d0407baSopenharmony_ci 11053d0407baSopenharmony_ci ctrl->wait_flag = 0; 11063d0407baSopenharmony_ci wake_up(&ctrl->wait_wq); 11073d0407baSopenharmony_ci return IRQ_HANDLED; 11083d0407baSopenharmony_ci} 11093d0407baSopenharmony_ci 11103d0407baSopenharmony_ciint rockchip_dmcfreq_wait_complete(void) 11113d0407baSopenharmony_ci{ 11123d0407baSopenharmony_ci struct arm_smccc_res res; 11133d0407baSopenharmony_ci 11143d0407baSopenharmony_ci if (!wait_ctrl.wait_en) { 11153d0407baSopenharmony_ci pr_err("%s: Do not support time out!\n", __func__); 11163d0407baSopenharmony_ci return 0; 11173d0407baSopenharmony_ci } 11183d0407baSopenharmony_ci wait_ctrl.wait_flag = -1; 11193d0407baSopenharmony_ci 11203d0407baSopenharmony_ci enable_irq(wait_ctrl.complt_irq); 11213d0407baSopenharmony_ci /* 11223d0407baSopenharmony_ci * CPUs only enter WFI when idle to make sure that 11233d0407baSopenharmony_ci * FIQn can quick response. 11243d0407baSopenharmony_ci */ 11253d0407baSopenharmony_ci cpu_latency_qos_update_request(&pm_qos, 0); 11263d0407baSopenharmony_ci 11273d0407baSopenharmony_ci if (wait_ctrl.dcf_en == 1) { 11283d0407baSopenharmony_ci /* start dcf */ 11293d0407baSopenharmony_ci regmap_update_bits(wait_ctrl.regmap_dcf, 0x0, 0x1, 0x1); 11303d0407baSopenharmony_ci } else if (wait_ctrl.dcf_en == 2) { 11313d0407baSopenharmony_ci res = sip_smc_dram(0, 0, ROCKCHIP_SIP_CONFIG_MCU_START); 11323d0407baSopenharmony_ci if (res.a0) { 11333d0407baSopenharmony_ci pr_err("rockchip_sip_config_mcu_start error:%lx\n", res.a0); 11343d0407baSopenharmony_ci return -ENOMEM; 11353d0407baSopenharmony_ci } 11363d0407baSopenharmony_ci } 11373d0407baSopenharmony_ci 11383d0407baSopenharmony_ci wait_event_timeout(wait_ctrl.wait_wq, (wait_ctrl.wait_flag == 0), 11393d0407baSopenharmony_ci msecs_to_jiffies(wait_ctrl.wait_time_out_ms)); 11403d0407baSopenharmony_ci 11413d0407baSopenharmony_ci cpu_latency_qos_update_request(&pm_qos, PM_QOS_DEFAULT_VALUE); 11423d0407baSopenharmony_ci disable_irq(wait_ctrl.complt_irq); 11433d0407baSopenharmony_ci 11443d0407baSopenharmony_ci return 0; 11453d0407baSopenharmony_ci} 11463d0407baSopenharmony_ci 11473d0407baSopenharmony_cistatic __maybe_unused int rockchip_get_freq_info(struct rockchip_dmcfreq *dmcfreq) 11483d0407baSopenharmony_ci{ 11493d0407baSopenharmony_ci struct arm_smccc_res res; 11503d0407baSopenharmony_ci struct dev_pm_opp *opp; 11513d0407baSopenharmony_ci struct dmc_freq_table *freq_table; 11523d0407baSopenharmony_ci unsigned long rate; 11533d0407baSopenharmony_ci int i, j, count, ret = 0; 11543d0407baSopenharmony_ci 11553d0407baSopenharmony_ci res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0, 11563d0407baSopenharmony_ci ROCKCHIP_SIP_CONFIG_DRAM_GET_FREQ_INFO); 11573d0407baSopenharmony_ci if (res.a0) { 11583d0407baSopenharmony_ci dev_err(dmcfreq->dev, "rockchip_sip_config_dram_get_freq_info error:%lx\n", 11593d0407baSopenharmony_ci res.a0); 11603d0407baSopenharmony_ci return -ENOMEM; 11613d0407baSopenharmony_ci } 11623d0407baSopenharmony_ci 11633d0407baSopenharmony_ci if (ddr_psci_param->freq_count == 0 || ddr_psci_param->freq_count > 6) { 11643d0407baSopenharmony_ci dev_err(dmcfreq->dev, "it is no available frequencies!\n"); 11653d0407baSopenharmony_ci return -EPERM; 11663d0407baSopenharmony_ci } 11673d0407baSopenharmony_ci 11683d0407baSopenharmony_ci for (i = 0; i < ddr_psci_param->freq_count; i++) 11693d0407baSopenharmony_ci dmcfreq->freq_info_rate[i] = ddr_psci_param->freq_info_mhz[i] * 1000000; 11703d0407baSopenharmony_ci dmcfreq->freq_count = ddr_psci_param->freq_count; 11713d0407baSopenharmony_ci 11723d0407baSopenharmony_ci /* update dmc_opp_table */ 11733d0407baSopenharmony_ci count = dev_pm_opp_get_opp_count(dmcfreq->dev); 11743d0407baSopenharmony_ci if (count <= 0) { 11753d0407baSopenharmony_ci ret = count ? count : -ENODATA; 11763d0407baSopenharmony_ci return ret; 11773d0407baSopenharmony_ci } 11783d0407baSopenharmony_ci 11793d0407baSopenharmony_ci freq_table = kmalloc(sizeof(struct dmc_freq_table) * count, GFP_KERNEL); 11803d0407baSopenharmony_ci for (i = 0, rate = 0; i < count; i++, rate++) { 11813d0407baSopenharmony_ci /* find next rate */ 11823d0407baSopenharmony_ci opp = dev_pm_opp_find_freq_ceil(dmcfreq->dev, &rate); 11833d0407baSopenharmony_ci if (IS_ERR(opp)) { 11843d0407baSopenharmony_ci ret = PTR_ERR(opp); 11853d0407baSopenharmony_ci dev_err(dmcfreq->dev, "failed to find OPP for freq %lu.\n", rate); 11863d0407baSopenharmony_ci goto out; 11873d0407baSopenharmony_ci } 11883d0407baSopenharmony_ci freq_table[i].freq = rate; 11893d0407baSopenharmony_ci freq_table[i].volt = dev_pm_opp_get_voltage(opp); 11903d0407baSopenharmony_ci dev_pm_opp_put(opp); 11913d0407baSopenharmony_ci 11923d0407baSopenharmony_ci for (j = 0; j < dmcfreq->freq_count; j++) { 11933d0407baSopenharmony_ci if (rate == dmcfreq->freq_info_rate[j]) 11943d0407baSopenharmony_ci break; 11953d0407baSopenharmony_ci } 11963d0407baSopenharmony_ci if (j == dmcfreq->freq_count) 11973d0407baSopenharmony_ci dev_pm_opp_remove(dmcfreq->dev, rate); 11983d0407baSopenharmony_ci } 11993d0407baSopenharmony_ci 12003d0407baSopenharmony_ci for (i = 0; i < dmcfreq->freq_count; i++) { 12013d0407baSopenharmony_ci for (j = 0; j < count; j++) { 12023d0407baSopenharmony_ci if (dmcfreq->freq_info_rate[i] == freq_table[j].freq) { 12033d0407baSopenharmony_ci break; 12043d0407baSopenharmony_ci } else if (dmcfreq->freq_info_rate[i] < freq_table[j].freq) { 12053d0407baSopenharmony_ci dev_pm_opp_add(dmcfreq->dev, dmcfreq->freq_info_rate[i], 12063d0407baSopenharmony_ci freq_table[j].volt); 12073d0407baSopenharmony_ci break; 12083d0407baSopenharmony_ci } 12093d0407baSopenharmony_ci } 12103d0407baSopenharmony_ci if (j == count) { 12113d0407baSopenharmony_ci dev_err(dmcfreq->dev, "failed to match dmc_opp_table for %ld\n", 12123d0407baSopenharmony_ci dmcfreq->freq_info_rate[i]); 12133d0407baSopenharmony_ci if (i == 0) 12143d0407baSopenharmony_ci ret = -EPERM; 12153d0407baSopenharmony_ci else 12163d0407baSopenharmony_ci dmcfreq->freq_count = i; 12173d0407baSopenharmony_ci goto out; 12183d0407baSopenharmony_ci } 12193d0407baSopenharmony_ci } 12203d0407baSopenharmony_ci 12213d0407baSopenharmony_ciout: 12223d0407baSopenharmony_ci kfree(freq_table); 12233d0407baSopenharmony_ci return ret; 12243d0407baSopenharmony_ci} 12253d0407baSopenharmony_ci 12263d0407baSopenharmony_cistatic __maybe_unused int px30_dmc_init(struct platform_device *pdev, 12273d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq) 12283d0407baSopenharmony_ci{ 12293d0407baSopenharmony_ci struct arm_smccc_res res; 12303d0407baSopenharmony_ci u32 size; 12313d0407baSopenharmony_ci int ret; 12323d0407baSopenharmony_ci int complt_irq; 12333d0407baSopenharmony_ci u32 complt_hwirq; 12343d0407baSopenharmony_ci struct irq_data *complt_irq_data; 12353d0407baSopenharmony_ci 12363d0407baSopenharmony_ci res = sip_smc_dram(0, 0, 12373d0407baSopenharmony_ci ROCKCHIP_SIP_CONFIG_DRAM_GET_VERSION); 12383d0407baSopenharmony_ci dev_notice(&pdev->dev, "current ATF version 0x%lx!\n", res.a1); 12393d0407baSopenharmony_ci if (res.a0 || res.a1 < 0x103) { 12403d0407baSopenharmony_ci dev_err(&pdev->dev, 12413d0407baSopenharmony_ci "trusted firmware need to update or is invalid!\n"); 12423d0407baSopenharmony_ci return -ENXIO; 12433d0407baSopenharmony_ci } 12443d0407baSopenharmony_ci 12453d0407baSopenharmony_ci dev_notice(&pdev->dev, "read tf version 0x%lx!\n", res.a1); 12463d0407baSopenharmony_ci 12473d0407baSopenharmony_ci /* 12483d0407baSopenharmony_ci * first 4KB is used for interface parameters 12493d0407baSopenharmony_ci * after 4KB * N is dts parameters 12503d0407baSopenharmony_ci */ 12513d0407baSopenharmony_ci size = sizeof(struct px30_ddr_dts_config_timing); 12523d0407baSopenharmony_ci res = sip_smc_request_share_mem(DIV_ROUND_UP(size, 4096) + 1, 12533d0407baSopenharmony_ci SHARE_PAGE_TYPE_DDR); 12543d0407baSopenharmony_ci if (res.a0 != 0) { 12553d0407baSopenharmony_ci dev_err(&pdev->dev, "no ATF memory for init\n"); 12563d0407baSopenharmony_ci return -ENOMEM; 12573d0407baSopenharmony_ci } 12583d0407baSopenharmony_ci ddr_psci_param = (struct share_params *)res.a1; 12593d0407baSopenharmony_ci of_get_px30_timings(&pdev->dev, pdev->dev.of_node, 12603d0407baSopenharmony_ci (uint32_t *)ddr_psci_param); 12613d0407baSopenharmony_ci 12623d0407baSopenharmony_ci init_waitqueue_head(&wait_ctrl.wait_wq); 12633d0407baSopenharmony_ci wait_ctrl.wait_en = 1; 12643d0407baSopenharmony_ci wait_ctrl.wait_time_out_ms = 17 * 5; 12653d0407baSopenharmony_ci 12663d0407baSopenharmony_ci complt_irq = platform_get_irq_byname(pdev, "complete_irq"); 12673d0407baSopenharmony_ci if (complt_irq < 0) { 12683d0407baSopenharmony_ci dev_err(&pdev->dev, "no IRQ for complete_irq: %d\n", 12693d0407baSopenharmony_ci complt_irq); 12703d0407baSopenharmony_ci return complt_irq; 12713d0407baSopenharmony_ci } 12723d0407baSopenharmony_ci wait_ctrl.complt_irq = complt_irq; 12733d0407baSopenharmony_ci 12743d0407baSopenharmony_ci ret = devm_request_irq(&pdev->dev, complt_irq, wait_complete_irq, 12753d0407baSopenharmony_ci 0, dev_name(&pdev->dev), &wait_ctrl); 12763d0407baSopenharmony_ci if (ret < 0) { 12773d0407baSopenharmony_ci dev_err(&pdev->dev, "cannot request complete_irq\n"); 12783d0407baSopenharmony_ci return ret; 12793d0407baSopenharmony_ci } 12803d0407baSopenharmony_ci disable_irq(complt_irq); 12813d0407baSopenharmony_ci 12823d0407baSopenharmony_ci complt_irq_data = irq_get_irq_data(complt_irq); 12833d0407baSopenharmony_ci complt_hwirq = irqd_to_hwirq(complt_irq_data); 12843d0407baSopenharmony_ci ddr_psci_param->complt_hwirq = complt_hwirq; 12853d0407baSopenharmony_ci 12863d0407baSopenharmony_ci dmcfreq->set_rate_params = ddr_psci_param; 12873d0407baSopenharmony_ci rockchip_set_ddrclk_params(dmcfreq->set_rate_params); 12883d0407baSopenharmony_ci rockchip_set_ddrclk_dmcfreq_wait_complete(rockchip_dmcfreq_wait_complete); 12893d0407baSopenharmony_ci 12903d0407baSopenharmony_ci res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0, 12913d0407baSopenharmony_ci ROCKCHIP_SIP_CONFIG_DRAM_INIT); 12923d0407baSopenharmony_ci if (res.a0) { 12933d0407baSopenharmony_ci dev_err(&pdev->dev, "rockchip_sip_config_dram_init error:%lx\n", 12943d0407baSopenharmony_ci res.a0); 12953d0407baSopenharmony_ci return -ENOMEM; 12963d0407baSopenharmony_ci } 12973d0407baSopenharmony_ci 12983d0407baSopenharmony_ci dmcfreq->set_auto_self_refresh = rockchip_ddr_set_auto_self_refresh; 12993d0407baSopenharmony_ci 13003d0407baSopenharmony_ci return 0; 13013d0407baSopenharmony_ci} 13023d0407baSopenharmony_ci 13033d0407baSopenharmony_cistatic __maybe_unused int rk1808_dmc_init(struct platform_device *pdev, 13043d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq) 13053d0407baSopenharmony_ci{ 13063d0407baSopenharmony_ci struct arm_smccc_res res; 13073d0407baSopenharmony_ci u32 size; 13083d0407baSopenharmony_ci int ret; 13093d0407baSopenharmony_ci int complt_irq; 13103d0407baSopenharmony_ci struct device_node *node; 13113d0407baSopenharmony_ci 13123d0407baSopenharmony_ci res = sip_smc_dram(0, 0, 13133d0407baSopenharmony_ci ROCKCHIP_SIP_CONFIG_DRAM_GET_VERSION); 13143d0407baSopenharmony_ci dev_notice(&pdev->dev, "current ATF version 0x%lx!\n", res.a1); 13153d0407baSopenharmony_ci if (res.a0 || res.a1 < 0x101) { 13163d0407baSopenharmony_ci dev_err(&pdev->dev, 13173d0407baSopenharmony_ci "trusted firmware need to update or is invalid!\n"); 13183d0407baSopenharmony_ci return -ENXIO; 13193d0407baSopenharmony_ci } 13203d0407baSopenharmony_ci 13213d0407baSopenharmony_ci /* 13223d0407baSopenharmony_ci * first 4KB is used for interface parameters 13233d0407baSopenharmony_ci * after 4KB * N is dts parameters 13243d0407baSopenharmony_ci */ 13253d0407baSopenharmony_ci size = sizeof(struct rk1808_ddr_dts_config_timing); 13263d0407baSopenharmony_ci res = sip_smc_request_share_mem(DIV_ROUND_UP(size, 4096) + 1, 13273d0407baSopenharmony_ci SHARE_PAGE_TYPE_DDR); 13283d0407baSopenharmony_ci if (res.a0 != 0) { 13293d0407baSopenharmony_ci dev_err(&pdev->dev, "no ATF memory for init\n"); 13303d0407baSopenharmony_ci return -ENOMEM; 13313d0407baSopenharmony_ci } 13323d0407baSopenharmony_ci ddr_psci_param = (struct share_params *)res.a1; 13333d0407baSopenharmony_ci of_get_rk1808_timings(&pdev->dev, pdev->dev.of_node, 13343d0407baSopenharmony_ci (uint32_t *)ddr_psci_param); 13353d0407baSopenharmony_ci 13363d0407baSopenharmony_ci /* enable start dcf in kernel after dcf ready */ 13373d0407baSopenharmony_ci node = of_parse_phandle(pdev->dev.of_node, "dcf_reg", 0); 13383d0407baSopenharmony_ci wait_ctrl.regmap_dcf = syscon_node_to_regmap(node); 13393d0407baSopenharmony_ci if (IS_ERR(wait_ctrl.regmap_dcf)) 13403d0407baSopenharmony_ci return PTR_ERR(wait_ctrl.regmap_dcf); 13413d0407baSopenharmony_ci wait_ctrl.dcf_en = 1; 13423d0407baSopenharmony_ci 13433d0407baSopenharmony_ci init_waitqueue_head(&wait_ctrl.wait_wq); 13443d0407baSopenharmony_ci wait_ctrl.wait_en = 1; 13453d0407baSopenharmony_ci wait_ctrl.wait_time_out_ms = 17 * 5; 13463d0407baSopenharmony_ci 13473d0407baSopenharmony_ci complt_irq = platform_get_irq_byname(pdev, "complete_irq"); 13483d0407baSopenharmony_ci if (complt_irq < 0) { 13493d0407baSopenharmony_ci dev_err(&pdev->dev, "no IRQ for complete_irq: %d\n", 13503d0407baSopenharmony_ci complt_irq); 13513d0407baSopenharmony_ci return complt_irq; 13523d0407baSopenharmony_ci } 13533d0407baSopenharmony_ci wait_ctrl.complt_irq = complt_irq; 13543d0407baSopenharmony_ci 13553d0407baSopenharmony_ci ret = devm_request_irq(&pdev->dev, complt_irq, wait_dcf_complete_irq, 13563d0407baSopenharmony_ci 0, dev_name(&pdev->dev), &wait_ctrl); 13573d0407baSopenharmony_ci if (ret < 0) { 13583d0407baSopenharmony_ci dev_err(&pdev->dev, "cannot request complete_irq\n"); 13593d0407baSopenharmony_ci return ret; 13603d0407baSopenharmony_ci } 13613d0407baSopenharmony_ci disable_irq(complt_irq); 13623d0407baSopenharmony_ci 13633d0407baSopenharmony_ci dmcfreq->set_rate_params = ddr_psci_param; 13643d0407baSopenharmony_ci rockchip_set_ddrclk_params(dmcfreq->set_rate_params); 13653d0407baSopenharmony_ci rockchip_set_ddrclk_dmcfreq_wait_complete(rockchip_dmcfreq_wait_complete); 13663d0407baSopenharmony_ci 13673d0407baSopenharmony_ci res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0, 13683d0407baSopenharmony_ci ROCKCHIP_SIP_CONFIG_DRAM_INIT); 13693d0407baSopenharmony_ci if (res.a0) { 13703d0407baSopenharmony_ci dev_err(&pdev->dev, "rockchip_sip_config_dram_init error:%lx\n", 13713d0407baSopenharmony_ci res.a0); 13723d0407baSopenharmony_ci return -ENOMEM; 13733d0407baSopenharmony_ci } 13743d0407baSopenharmony_ci 13753d0407baSopenharmony_ci dmcfreq->set_auto_self_refresh = rockchip_ddr_set_auto_self_refresh; 13763d0407baSopenharmony_ci 13773d0407baSopenharmony_ci return 0; 13783d0407baSopenharmony_ci} 13793d0407baSopenharmony_ci 13803d0407baSopenharmony_cistatic __maybe_unused int rk3128_dmc_init(struct platform_device *pdev, 13813d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq) 13823d0407baSopenharmony_ci{ 13833d0407baSopenharmony_ci struct arm_smccc_res res; 13843d0407baSopenharmony_ci 13853d0407baSopenharmony_ci res = sip_smc_request_share_mem(DIV_ROUND_UP(sizeof( 13863d0407baSopenharmony_ci struct rk3128_ddr_dts_config_timing), 13873d0407baSopenharmony_ci 4096) + 1, SHARE_PAGE_TYPE_DDR); 13883d0407baSopenharmony_ci if (res.a0) { 13893d0407baSopenharmony_ci dev_err(&pdev->dev, "no ATF memory for init\n"); 13903d0407baSopenharmony_ci return -ENOMEM; 13913d0407baSopenharmony_ci } 13923d0407baSopenharmony_ci ddr_psci_param = (struct share_params *)res.a1; 13933d0407baSopenharmony_ci of_get_rk3128_timings(&pdev->dev, pdev->dev.of_node, 13943d0407baSopenharmony_ci (uint32_t *)ddr_psci_param); 13953d0407baSopenharmony_ci 13963d0407baSopenharmony_ci ddr_psci_param->hz = 0; 13973d0407baSopenharmony_ci ddr_psci_param->lcdc_type = rk_drm_get_lcdc_type(); 13983d0407baSopenharmony_ci 13993d0407baSopenharmony_ci dmcfreq->set_rate_params = ddr_psci_param; 14003d0407baSopenharmony_ci rockchip_set_ddrclk_params(dmcfreq->set_rate_params); 14013d0407baSopenharmony_ci 14023d0407baSopenharmony_ci res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0, 14033d0407baSopenharmony_ci ROCKCHIP_SIP_CONFIG_DRAM_INIT); 14043d0407baSopenharmony_ci 14053d0407baSopenharmony_ci if (res.a0) { 14063d0407baSopenharmony_ci dev_err(&pdev->dev, "rockchip_sip_config_dram_init error:%lx\n", 14073d0407baSopenharmony_ci res.a0); 14083d0407baSopenharmony_ci return -ENOMEM; 14093d0407baSopenharmony_ci } 14103d0407baSopenharmony_ci 14113d0407baSopenharmony_ci dmcfreq->set_auto_self_refresh = rockchip_ddr_set_auto_self_refresh; 14123d0407baSopenharmony_ci 14133d0407baSopenharmony_ci return 0; 14143d0407baSopenharmony_ci} 14153d0407baSopenharmony_ci 14163d0407baSopenharmony_cistatic __maybe_unused int rk3228_dmc_init(struct platform_device *pdev, 14173d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq) 14183d0407baSopenharmony_ci{ 14193d0407baSopenharmony_ci struct arm_smccc_res res; 14203d0407baSopenharmony_ci 14213d0407baSopenharmony_ci res = sip_smc_request_share_mem(DIV_ROUND_UP(sizeof( 14223d0407baSopenharmony_ci struct rk3228_ddr_dts_config_timing), 14233d0407baSopenharmony_ci 4096) + 1, SHARE_PAGE_TYPE_DDR); 14243d0407baSopenharmony_ci if (res.a0) { 14253d0407baSopenharmony_ci dev_err(&pdev->dev, "no ATF memory for init\n"); 14263d0407baSopenharmony_ci return -ENOMEM; 14273d0407baSopenharmony_ci } 14283d0407baSopenharmony_ci 14293d0407baSopenharmony_ci ddr_psci_param = (struct share_params *)res.a1; 14303d0407baSopenharmony_ci if (of_get_rk3228_timings(&pdev->dev, pdev->dev.of_node, 14313d0407baSopenharmony_ci (uint32_t *)ddr_psci_param)) 14323d0407baSopenharmony_ci return -ENOMEM; 14333d0407baSopenharmony_ci 14343d0407baSopenharmony_ci ddr_psci_param->hz = 0; 14353d0407baSopenharmony_ci 14363d0407baSopenharmony_ci dmcfreq->set_rate_params = ddr_psci_param; 14373d0407baSopenharmony_ci rockchip_set_ddrclk_params(dmcfreq->set_rate_params); 14383d0407baSopenharmony_ci 14393d0407baSopenharmony_ci res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0, 14403d0407baSopenharmony_ci ROCKCHIP_SIP_CONFIG_DRAM_INIT); 14413d0407baSopenharmony_ci 14423d0407baSopenharmony_ci if (res.a0) { 14433d0407baSopenharmony_ci dev_err(&pdev->dev, "rockchip_sip_config_dram_init error:%lx\n", 14443d0407baSopenharmony_ci res.a0); 14453d0407baSopenharmony_ci return -ENOMEM; 14463d0407baSopenharmony_ci } 14473d0407baSopenharmony_ci 14483d0407baSopenharmony_ci dmcfreq->set_auto_self_refresh = rockchip_ddr_set_auto_self_refresh; 14493d0407baSopenharmony_ci 14503d0407baSopenharmony_ci return 0; 14513d0407baSopenharmony_ci} 14523d0407baSopenharmony_ci 14533d0407baSopenharmony_cistatic __maybe_unused int rk3288_dmc_init(struct platform_device *pdev, 14543d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq) 14553d0407baSopenharmony_ci{ 14563d0407baSopenharmony_ci struct device *dev = &pdev->dev; 14573d0407baSopenharmony_ci struct clk *pclk_phy, *pclk_upctl, *dmc_clk; 14583d0407baSopenharmony_ci struct arm_smccc_res res; 14593d0407baSopenharmony_ci int ret; 14603d0407baSopenharmony_ci 14613d0407baSopenharmony_ci dmc_clk = devm_clk_get(dev, "dmc_clk"); 14623d0407baSopenharmony_ci if (IS_ERR(dmc_clk)) { 14633d0407baSopenharmony_ci dev_err(dev, "Cannot get the clk dmc_clk\n"); 14643d0407baSopenharmony_ci return PTR_ERR(dmc_clk); 14653d0407baSopenharmony_ci } 14663d0407baSopenharmony_ci ret = clk_prepare_enable(dmc_clk); 14673d0407baSopenharmony_ci if (ret < 0) { 14683d0407baSopenharmony_ci dev_err(dev, "failed to prepare/enable dmc_clk\n"); 14693d0407baSopenharmony_ci return ret; 14703d0407baSopenharmony_ci } 14713d0407baSopenharmony_ci 14723d0407baSopenharmony_ci pclk_phy = devm_clk_get(dev, "pclk_phy0"); 14733d0407baSopenharmony_ci if (IS_ERR(pclk_phy)) { 14743d0407baSopenharmony_ci dev_err(dev, "Cannot get the clk pclk_phy0\n"); 14753d0407baSopenharmony_ci return PTR_ERR(pclk_phy); 14763d0407baSopenharmony_ci } 14773d0407baSopenharmony_ci ret = clk_prepare_enable(pclk_phy); 14783d0407baSopenharmony_ci if (ret < 0) { 14793d0407baSopenharmony_ci dev_err(dev, "failed to prepare/enable pclk_phy0\n"); 14803d0407baSopenharmony_ci return ret; 14813d0407baSopenharmony_ci } 14823d0407baSopenharmony_ci pclk_upctl = devm_clk_get(dev, "pclk_upctl0"); 14833d0407baSopenharmony_ci if (IS_ERR(pclk_upctl)) { 14843d0407baSopenharmony_ci dev_err(dev, "Cannot get the clk pclk_upctl0\n"); 14853d0407baSopenharmony_ci return PTR_ERR(pclk_upctl); 14863d0407baSopenharmony_ci } 14873d0407baSopenharmony_ci ret = clk_prepare_enable(pclk_upctl); 14883d0407baSopenharmony_ci if (ret < 0) { 14893d0407baSopenharmony_ci dev_err(dev, "failed to prepare/enable pclk_upctl1\n"); 14903d0407baSopenharmony_ci return ret; 14913d0407baSopenharmony_ci } 14923d0407baSopenharmony_ci 14933d0407baSopenharmony_ci pclk_phy = devm_clk_get(dev, "pclk_phy1"); 14943d0407baSopenharmony_ci if (IS_ERR(pclk_phy)) { 14953d0407baSopenharmony_ci dev_err(dev, "Cannot get the clk pclk_phy1\n"); 14963d0407baSopenharmony_ci return PTR_ERR(pclk_phy); 14973d0407baSopenharmony_ci } 14983d0407baSopenharmony_ci ret = clk_prepare_enable(pclk_phy); 14993d0407baSopenharmony_ci if (ret < 0) { 15003d0407baSopenharmony_ci dev_err(dev, "failed to prepare/enable pclk_phy1\n"); 15013d0407baSopenharmony_ci return ret; 15023d0407baSopenharmony_ci } 15033d0407baSopenharmony_ci pclk_upctl = devm_clk_get(dev, "pclk_upctl1"); 15043d0407baSopenharmony_ci if (IS_ERR(pclk_upctl)) { 15053d0407baSopenharmony_ci dev_err(dev, "Cannot get the clk pclk_upctl1\n"); 15063d0407baSopenharmony_ci return PTR_ERR(pclk_upctl); 15073d0407baSopenharmony_ci } 15083d0407baSopenharmony_ci ret = clk_prepare_enable(pclk_upctl); 15093d0407baSopenharmony_ci if (ret < 0) { 15103d0407baSopenharmony_ci dev_err(dev, "failed to prepare/enable pclk_upctl1\n"); 15113d0407baSopenharmony_ci return ret; 15123d0407baSopenharmony_ci } 15133d0407baSopenharmony_ci 15143d0407baSopenharmony_ci res = sip_smc_request_share_mem(DIV_ROUND_UP(sizeof( 15153d0407baSopenharmony_ci struct rk3288_ddr_dts_config_timing), 15163d0407baSopenharmony_ci 4096) + 1, SHARE_PAGE_TYPE_DDR); 15173d0407baSopenharmony_ci if (res.a0) { 15183d0407baSopenharmony_ci dev_err(&pdev->dev, "no ATF memory for init\n"); 15193d0407baSopenharmony_ci return -ENOMEM; 15203d0407baSopenharmony_ci } 15213d0407baSopenharmony_ci 15223d0407baSopenharmony_ci ddr_psci_param = (struct share_params *)res.a1; 15233d0407baSopenharmony_ci of_get_rk3288_timings(&pdev->dev, pdev->dev.of_node, 15243d0407baSopenharmony_ci (uint32_t *)ddr_psci_param); 15253d0407baSopenharmony_ci 15263d0407baSopenharmony_ci ddr_psci_param->hz = 0; 15273d0407baSopenharmony_ci ddr_psci_param->lcdc_type = rk_drm_get_lcdc_type(); 15283d0407baSopenharmony_ci 15293d0407baSopenharmony_ci dmcfreq->set_rate_params = ddr_psci_param; 15303d0407baSopenharmony_ci rockchip_set_ddrclk_params(dmcfreq->set_rate_params); 15313d0407baSopenharmony_ci 15323d0407baSopenharmony_ci res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0, 15333d0407baSopenharmony_ci ROCKCHIP_SIP_CONFIG_DRAM_INIT); 15343d0407baSopenharmony_ci 15353d0407baSopenharmony_ci if (res.a0) { 15363d0407baSopenharmony_ci dev_err(&pdev->dev, "rockchip_sip_config_dram_init error:%lx\n", 15373d0407baSopenharmony_ci res.a0); 15383d0407baSopenharmony_ci return -ENOMEM; 15393d0407baSopenharmony_ci } 15403d0407baSopenharmony_ci 15413d0407baSopenharmony_ci dmcfreq->set_auto_self_refresh = rockchip_ddr_set_auto_self_refresh; 15423d0407baSopenharmony_ci 15433d0407baSopenharmony_ci return 0; 15443d0407baSopenharmony_ci} 15453d0407baSopenharmony_ci 15463d0407baSopenharmony_cistatic __maybe_unused int rk3328_dmc_init(struct platform_device *pdev, 15473d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq) 15483d0407baSopenharmony_ci{ 15493d0407baSopenharmony_ci struct arm_smccc_res res; 15503d0407baSopenharmony_ci u32 size; 15513d0407baSopenharmony_ci 15523d0407baSopenharmony_ci res = sip_smc_dram(0, 0, 15533d0407baSopenharmony_ci ROCKCHIP_SIP_CONFIG_DRAM_GET_VERSION); 15543d0407baSopenharmony_ci dev_notice(&pdev->dev, "current ATF version 0x%lx!\n", res.a1); 15553d0407baSopenharmony_ci if (res.a0 || (res.a1 < 0x101)) { 15563d0407baSopenharmony_ci dev_err(&pdev->dev, 15573d0407baSopenharmony_ci "trusted firmware need to update or is invalid!\n"); 15583d0407baSopenharmony_ci return -ENXIO; 15593d0407baSopenharmony_ci } 15603d0407baSopenharmony_ci 15613d0407baSopenharmony_ci dev_notice(&pdev->dev, "read tf version 0x%lx!\n", res.a1); 15623d0407baSopenharmony_ci 15633d0407baSopenharmony_ci /* 15643d0407baSopenharmony_ci * first 4KB is used for interface parameters 15653d0407baSopenharmony_ci * after 4KB * N is dts parameters 15663d0407baSopenharmony_ci */ 15673d0407baSopenharmony_ci size = sizeof(struct rk3328_ddr_dts_config_timing); 15683d0407baSopenharmony_ci res = sip_smc_request_share_mem(DIV_ROUND_UP(size, 4096) + 1, 15693d0407baSopenharmony_ci SHARE_PAGE_TYPE_DDR); 15703d0407baSopenharmony_ci if (res.a0 != 0) { 15713d0407baSopenharmony_ci dev_err(&pdev->dev, "no ATF memory for init\n"); 15723d0407baSopenharmony_ci return -ENOMEM; 15733d0407baSopenharmony_ci } 15743d0407baSopenharmony_ci ddr_psci_param = (struct share_params *)res.a1; 15753d0407baSopenharmony_ci of_get_rk3328_timings(&pdev->dev, pdev->dev.of_node, 15763d0407baSopenharmony_ci (uint32_t *)ddr_psci_param); 15773d0407baSopenharmony_ci 15783d0407baSopenharmony_ci dmcfreq->set_rate_params = ddr_psci_param; 15793d0407baSopenharmony_ci rockchip_set_ddrclk_params(dmcfreq->set_rate_params); 15803d0407baSopenharmony_ci 15813d0407baSopenharmony_ci res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0, 15823d0407baSopenharmony_ci ROCKCHIP_SIP_CONFIG_DRAM_INIT); 15833d0407baSopenharmony_ci if (res.a0) { 15843d0407baSopenharmony_ci dev_err(&pdev->dev, "rockchip_sip_config_dram_init error:%lx\n", 15853d0407baSopenharmony_ci res.a0); 15863d0407baSopenharmony_ci return -ENOMEM; 15873d0407baSopenharmony_ci } 15883d0407baSopenharmony_ci 15893d0407baSopenharmony_ci dmcfreq->set_auto_self_refresh = rockchip_ddr_set_auto_self_refresh; 15903d0407baSopenharmony_ci 15913d0407baSopenharmony_ci return 0; 15923d0407baSopenharmony_ci} 15933d0407baSopenharmony_ci 15943d0407baSopenharmony_cistatic __maybe_unused int rk3368_dmc_init(struct platform_device *pdev, 15953d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq) 15963d0407baSopenharmony_ci{ 15973d0407baSopenharmony_ci struct device *dev = &pdev->dev; 15983d0407baSopenharmony_ci struct device_node *np = pdev->dev.of_node; 15993d0407baSopenharmony_ci struct arm_smccc_res res; 16003d0407baSopenharmony_ci struct rk3368_dram_timing *dram_timing; 16013d0407baSopenharmony_ci struct clk *pclk_phy, *pclk_upctl; 16023d0407baSopenharmony_ci int ret; 16033d0407baSopenharmony_ci u32 dram_spd_bin; 16043d0407baSopenharmony_ci u32 addr_mcu_el3; 16053d0407baSopenharmony_ci u32 dclk_mode; 16063d0407baSopenharmony_ci u32 lcdc_type; 16073d0407baSopenharmony_ci 16083d0407baSopenharmony_ci pclk_phy = devm_clk_get(dev, "pclk_phy"); 16093d0407baSopenharmony_ci if (IS_ERR(pclk_phy)) { 16103d0407baSopenharmony_ci dev_err(dev, "Cannot get the clk pclk_phy\n"); 16113d0407baSopenharmony_ci return PTR_ERR(pclk_phy); 16123d0407baSopenharmony_ci } 16133d0407baSopenharmony_ci ret = clk_prepare_enable(pclk_phy); 16143d0407baSopenharmony_ci if (ret < 0) { 16153d0407baSopenharmony_ci dev_err(dev, "failed to prepare/enable pclk_phy\n"); 16163d0407baSopenharmony_ci return ret; 16173d0407baSopenharmony_ci } 16183d0407baSopenharmony_ci pclk_upctl = devm_clk_get(dev, "pclk_upctl"); 16193d0407baSopenharmony_ci if (IS_ERR(pclk_upctl)) { 16203d0407baSopenharmony_ci dev_err(dev, "Cannot get the clk pclk_upctl\n"); 16213d0407baSopenharmony_ci return PTR_ERR(pclk_upctl); 16223d0407baSopenharmony_ci } 16233d0407baSopenharmony_ci ret = clk_prepare_enable(pclk_upctl); 16243d0407baSopenharmony_ci if (ret < 0) { 16253d0407baSopenharmony_ci dev_err(dev, "failed to prepare/enable pclk_upctl\n"); 16263d0407baSopenharmony_ci return ret; 16273d0407baSopenharmony_ci } 16283d0407baSopenharmony_ci 16293d0407baSopenharmony_ci /* 16303d0407baSopenharmony_ci * Get dram timing and pass it to arm trust firmware, 16313d0407baSopenharmony_ci * the dram drvier in arm trust firmware will get these 16323d0407baSopenharmony_ci * timing and to do dram initial. 16333d0407baSopenharmony_ci */ 16343d0407baSopenharmony_ci dram_timing = of_get_rk3368_timings(dev, np); 16353d0407baSopenharmony_ci if (dram_timing) { 16363d0407baSopenharmony_ci dram_spd_bin = dram_timing->dram_spd_bin; 16373d0407baSopenharmony_ci if (scpi_ddr_send_timing((u32 *)dram_timing, 16383d0407baSopenharmony_ci sizeof(struct rk3368_dram_timing))) 16393d0407baSopenharmony_ci dev_err(dev, "send ddr timing timeout\n"); 16403d0407baSopenharmony_ci } else { 16413d0407baSopenharmony_ci dev_err(dev, "get ddr timing from dts error\n"); 16423d0407baSopenharmony_ci dram_spd_bin = DDR3_DEFAULT; 16433d0407baSopenharmony_ci } 16443d0407baSopenharmony_ci 16453d0407baSopenharmony_ci res = sip_smc_mcu_el3fiq(FIQ_INIT_HANDLER, 16463d0407baSopenharmony_ci FIQ_NUM_FOR_DCF, 16473d0407baSopenharmony_ci FIQ_CPU_TGT_BOOT); 16483d0407baSopenharmony_ci if ((res.a0) || (res.a1 == 0) || (res.a1 > 0x80000)) 16493d0407baSopenharmony_ci dev_err(dev, "Trust version error, pls check trust version\n"); 16503d0407baSopenharmony_ci addr_mcu_el3 = res.a1; 16513d0407baSopenharmony_ci 16523d0407baSopenharmony_ci if (of_property_read_u32(np, "vop-dclk-mode", &dclk_mode) == 0) 16533d0407baSopenharmony_ci scpi_ddr_dclk_mode(dclk_mode); 16543d0407baSopenharmony_ci 16553d0407baSopenharmony_ci dmcfreq->set_rate_params = 16563d0407baSopenharmony_ci devm_kzalloc(dev, sizeof(struct share_params), GFP_KERNEL); 16573d0407baSopenharmony_ci if (!dmcfreq->set_rate_params) 16583d0407baSopenharmony_ci return -ENOMEM; 16593d0407baSopenharmony_ci rockchip_set_ddrclk_params(dmcfreq->set_rate_params); 16603d0407baSopenharmony_ci 16613d0407baSopenharmony_ci lcdc_type = rk_drm_get_lcdc_type(); 16623d0407baSopenharmony_ci 16633d0407baSopenharmony_ci if (scpi_ddr_init(dram_spd_bin, 0, lcdc_type, 16643d0407baSopenharmony_ci addr_mcu_el3)) 16653d0407baSopenharmony_ci dev_err(dev, "ddr init error\n"); 16663d0407baSopenharmony_ci else 16673d0407baSopenharmony_ci dev_dbg(dev, ("%s out\n"), __func__); 16683d0407baSopenharmony_ci 16693d0407baSopenharmony_ci dmcfreq->set_auto_self_refresh = scpi_ddr_set_auto_self_refresh; 16703d0407baSopenharmony_ci 16713d0407baSopenharmony_ci return 0; 16723d0407baSopenharmony_ci} 16733d0407baSopenharmony_ci 16743d0407baSopenharmony_cistatic int rk3399_set_msch_readlatency(unsigned int readlatency) 16753d0407baSopenharmony_ci{ 16763d0407baSopenharmony_ci struct arm_smccc_res res; 16773d0407baSopenharmony_ci 16783d0407baSopenharmony_ci arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, readlatency, 0, 16793d0407baSopenharmony_ci ROCKCHIP_SIP_CONFIG_DRAM_SET_MSCH_RL, 16803d0407baSopenharmony_ci 0, 0, 0, 0, &res); 16813d0407baSopenharmony_ci 16823d0407baSopenharmony_ci return res.a0; 16833d0407baSopenharmony_ci} 16843d0407baSopenharmony_ci 16853d0407baSopenharmony_cistatic __maybe_unused int rk3399_dmc_init(struct platform_device *pdev, 16863d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq) 16873d0407baSopenharmony_ci{ 16883d0407baSopenharmony_ci struct device *dev = &pdev->dev; 16893d0407baSopenharmony_ci struct device_node *np = pdev->dev.of_node; 16903d0407baSopenharmony_ci struct arm_smccc_res res; 16913d0407baSopenharmony_ci struct rk3399_dram_timing *dram_timing; 16923d0407baSopenharmony_ci int index, size; 16933d0407baSopenharmony_ci u32 *timing; 16943d0407baSopenharmony_ci 16953d0407baSopenharmony_ci /* 16963d0407baSopenharmony_ci * Get dram timing and pass it to arm trust firmware, 16973d0407baSopenharmony_ci * the dram drvier in arm trust firmware will get these 16983d0407baSopenharmony_ci * timing and to do dram initial. 16993d0407baSopenharmony_ci */ 17003d0407baSopenharmony_ci dram_timing = of_get_rk3399_timings(dev, np); 17013d0407baSopenharmony_ci if (dram_timing) { 17023d0407baSopenharmony_ci timing = (u32 *)dram_timing; 17033d0407baSopenharmony_ci size = sizeof(struct rk3399_dram_timing) / 4; 17043d0407baSopenharmony_ci for (index = 0; index < size; index++) { 17053d0407baSopenharmony_ci arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, *timing++, index, 17063d0407baSopenharmony_ci ROCKCHIP_SIP_CONFIG_DRAM_SET_PARAM, 17073d0407baSopenharmony_ci 0, 0, 0, 0, &res); 17083d0407baSopenharmony_ci if (res.a0) { 17093d0407baSopenharmony_ci dev_err(dev, "Failed to set dram param: %ld\n", 17103d0407baSopenharmony_ci res.a0); 17113d0407baSopenharmony_ci return -EINVAL; 17123d0407baSopenharmony_ci } 17133d0407baSopenharmony_ci } 17143d0407baSopenharmony_ci } 17153d0407baSopenharmony_ci 17163d0407baSopenharmony_ci dmcfreq->set_rate_params = 17173d0407baSopenharmony_ci devm_kzalloc(dev, sizeof(struct share_params), GFP_KERNEL); 17183d0407baSopenharmony_ci if (!dmcfreq->set_rate_params) 17193d0407baSopenharmony_ci return -ENOMEM; 17203d0407baSopenharmony_ci rockchip_set_ddrclk_params(dmcfreq->set_rate_params); 17213d0407baSopenharmony_ci 17223d0407baSopenharmony_ci arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, 0, 0, 17233d0407baSopenharmony_ci ROCKCHIP_SIP_CONFIG_DRAM_INIT, 17243d0407baSopenharmony_ci 0, 0, 0, 0, &res); 17253d0407baSopenharmony_ci 17263d0407baSopenharmony_ci dmcfreq->info.set_msch_readlatency = rk3399_set_msch_readlatency; 17273d0407baSopenharmony_ci 17283d0407baSopenharmony_ci return 0; 17293d0407baSopenharmony_ci} 17303d0407baSopenharmony_ci 17313d0407baSopenharmony_cistatic __maybe_unused int rk3568_dmc_init(struct platform_device *pdev, 17323d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq) 17333d0407baSopenharmony_ci{ 17343d0407baSopenharmony_ci struct arm_smccc_res res; 17353d0407baSopenharmony_ci int ret; 17363d0407baSopenharmony_ci int complt_irq; 17373d0407baSopenharmony_ci 17383d0407baSopenharmony_ci res = sip_smc_dram(0, 0, 17393d0407baSopenharmony_ci ROCKCHIP_SIP_CONFIG_DRAM_GET_VERSION); 17403d0407baSopenharmony_ci dev_notice(&pdev->dev, "current ATF version 0x%lx\n", res.a1); 17413d0407baSopenharmony_ci if (res.a0 || res.a1 < 0x101) { 17423d0407baSopenharmony_ci dev_err(&pdev->dev, "trusted firmware need update to V1.01 and above.\n"); 17433d0407baSopenharmony_ci return -ENXIO; 17443d0407baSopenharmony_ci } 17453d0407baSopenharmony_ci 17463d0407baSopenharmony_ci /* 17473d0407baSopenharmony_ci * first 4KB is used for interface parameters 17483d0407baSopenharmony_ci * after 4KB is dts parameters 17493d0407baSopenharmony_ci * request share memory size 4KB * 2 17503d0407baSopenharmony_ci */ 17513d0407baSopenharmony_ci res = sip_smc_request_share_mem(2, SHARE_PAGE_TYPE_DDR); 17523d0407baSopenharmony_ci if (res.a0 != 0) { 17533d0407baSopenharmony_ci dev_err(&pdev->dev, "no ATF memory for init\n"); 17543d0407baSopenharmony_ci return -ENOMEM; 17553d0407baSopenharmony_ci } 17563d0407baSopenharmony_ci ddr_psci_param = (struct share_params *)res.a1; 17573d0407baSopenharmony_ci /* Clear ddr_psci_param, size is 4KB * 2 */ 17583d0407baSopenharmony_ci memset_io(ddr_psci_param, 0x0, 4096 * 2); 17593d0407baSopenharmony_ci 17603d0407baSopenharmony_ci /* start mcu with sip_smc_dram */ 17613d0407baSopenharmony_ci wait_ctrl.dcf_en = 2; 17623d0407baSopenharmony_ci 17633d0407baSopenharmony_ci init_waitqueue_head(&wait_ctrl.wait_wq); 17643d0407baSopenharmony_ci wait_ctrl.wait_en = 1; 17653d0407baSopenharmony_ci wait_ctrl.wait_time_out_ms = 17 * 5; 17663d0407baSopenharmony_ci 17673d0407baSopenharmony_ci complt_irq = platform_get_irq_byname(pdev, "complete"); 17683d0407baSopenharmony_ci if (complt_irq < 0) { 17693d0407baSopenharmony_ci dev_err(&pdev->dev, "no IRQ for complt_irq: %d\n", 17703d0407baSopenharmony_ci complt_irq); 17713d0407baSopenharmony_ci return complt_irq; 17723d0407baSopenharmony_ci } 17733d0407baSopenharmony_ci wait_ctrl.complt_irq = complt_irq; 17743d0407baSopenharmony_ci 17753d0407baSopenharmony_ci ret = devm_request_irq(&pdev->dev, complt_irq, wait_dcf_complete_irq, 17763d0407baSopenharmony_ci 0, dev_name(&pdev->dev), &wait_ctrl); 17773d0407baSopenharmony_ci if (ret < 0) { 17783d0407baSopenharmony_ci dev_err(&pdev->dev, "cannot request complt_irq\n"); 17793d0407baSopenharmony_ci return ret; 17803d0407baSopenharmony_ci } 17813d0407baSopenharmony_ci disable_irq(complt_irq); 17823d0407baSopenharmony_ci 17833d0407baSopenharmony_ci res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0, 17843d0407baSopenharmony_ci ROCKCHIP_SIP_CONFIG_DRAM_INIT); 17853d0407baSopenharmony_ci if (res.a0) { 17863d0407baSopenharmony_ci dev_err(&pdev->dev, "rockchip_sip_config_dram_init error:%lx\n", 17873d0407baSopenharmony_ci res.a0); 17883d0407baSopenharmony_ci return -ENOMEM; 17893d0407baSopenharmony_ci } 17903d0407baSopenharmony_ci 17913d0407baSopenharmony_ci ret = rockchip_get_freq_info(dmcfreq); 17923d0407baSopenharmony_ci if (ret < 0) { 17933d0407baSopenharmony_ci dev_err(&pdev->dev, "cannot get frequency info\n"); 17943d0407baSopenharmony_ci return ret; 17953d0407baSopenharmony_ci } 17963d0407baSopenharmony_ci dmcfreq->is_set_rate_direct = true; 17973d0407baSopenharmony_ci 17983d0407baSopenharmony_ci dmcfreq->set_auto_self_refresh = rockchip_ddr_set_auto_self_refresh; 17993d0407baSopenharmony_ci 18003d0407baSopenharmony_ci return 0; 18013d0407baSopenharmony_ci} 18023d0407baSopenharmony_ci 18033d0407baSopenharmony_cistatic __maybe_unused int rk3588_dmc_init(struct platform_device *pdev, 18043d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq) 18053d0407baSopenharmony_ci{ 18063d0407baSopenharmony_ci struct arm_smccc_res res; 18073d0407baSopenharmony_ci int ret; 18083d0407baSopenharmony_ci int complt_irq; 18093d0407baSopenharmony_ci 18103d0407baSopenharmony_ci res = sip_smc_dram(0, 0, ROCKCHIP_SIP_CONFIG_DRAM_GET_VERSION); 18113d0407baSopenharmony_ci dev_notice(&pdev->dev, "current ATF version 0x%lx\n", res.a1); 18123d0407baSopenharmony_ci if (res.a0) { 18133d0407baSopenharmony_ci dev_err(&pdev->dev, "trusted firmware unsupported, please update.\n"); 18143d0407baSopenharmony_ci return -ENXIO; 18153d0407baSopenharmony_ci } 18163d0407baSopenharmony_ci 18173d0407baSopenharmony_ci /* 18183d0407baSopenharmony_ci * first 4KB is used for interface parameters 18193d0407baSopenharmony_ci * after 4KB is dts parameters 18203d0407baSopenharmony_ci * request share memory size 4KB * 2 18213d0407baSopenharmony_ci */ 18223d0407baSopenharmony_ci res = sip_smc_request_share_mem(2, SHARE_PAGE_TYPE_DDR); 18233d0407baSopenharmony_ci if (res.a0 != 0) { 18243d0407baSopenharmony_ci dev_err(&pdev->dev, "no ATF memory for init\n"); 18253d0407baSopenharmony_ci return -ENOMEM; 18263d0407baSopenharmony_ci } 18273d0407baSopenharmony_ci ddr_psci_param = (struct share_params *)res.a1; 18283d0407baSopenharmony_ci /* Clear ddr_psci_param, size is 4KB * 2 */ 18293d0407baSopenharmony_ci memset_io(ddr_psci_param, 0x0, 4096 * 2); 18303d0407baSopenharmony_ci 18313d0407baSopenharmony_ci /* start mcu with sip_smc_dram */ 18323d0407baSopenharmony_ci wait_ctrl.dcf_en = 2; 18333d0407baSopenharmony_ci 18343d0407baSopenharmony_ci init_waitqueue_head(&wait_ctrl.wait_wq); 18353d0407baSopenharmony_ci wait_ctrl.wait_en = 1; 18363d0407baSopenharmony_ci wait_ctrl.wait_time_out_ms = 17 * 5; 18373d0407baSopenharmony_ci 18383d0407baSopenharmony_ci complt_irq = platform_get_irq_byname(pdev, "complete"); 18393d0407baSopenharmony_ci if (complt_irq < 0) { 18403d0407baSopenharmony_ci dev_err(&pdev->dev, "no IRQ for complt_irq: %d\n", complt_irq); 18413d0407baSopenharmony_ci return complt_irq; 18423d0407baSopenharmony_ci } 18433d0407baSopenharmony_ci wait_ctrl.complt_irq = complt_irq; 18443d0407baSopenharmony_ci 18453d0407baSopenharmony_ci ret = devm_request_irq(&pdev->dev, complt_irq, wait_dcf_complete_irq, 18463d0407baSopenharmony_ci 0, dev_name(&pdev->dev), &wait_ctrl); 18473d0407baSopenharmony_ci if (ret < 0) { 18483d0407baSopenharmony_ci dev_err(&pdev->dev, "cannot request complt_irq\n"); 18493d0407baSopenharmony_ci return ret; 18503d0407baSopenharmony_ci } 18513d0407baSopenharmony_ci disable_irq(complt_irq); 18523d0407baSopenharmony_ci 18533d0407baSopenharmony_ci res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0, ROCKCHIP_SIP_CONFIG_DRAM_INIT); 18543d0407baSopenharmony_ci if (res.a0) { 18553d0407baSopenharmony_ci dev_err(&pdev->dev, "rockchip_sip_config_dram_init error:%lx\n", res.a0); 18563d0407baSopenharmony_ci return -ENOMEM; 18573d0407baSopenharmony_ci } 18583d0407baSopenharmony_ci 18593d0407baSopenharmony_ci ret = rockchip_get_freq_info(dmcfreq); 18603d0407baSopenharmony_ci if (ret < 0) { 18613d0407baSopenharmony_ci dev_err(&pdev->dev, "cannot get frequency info\n"); 18623d0407baSopenharmony_ci return ret; 18633d0407baSopenharmony_ci } 18643d0407baSopenharmony_ci dmcfreq->is_set_rate_direct = true; 18653d0407baSopenharmony_ci 18663d0407baSopenharmony_ci dmcfreq->set_auto_self_refresh = rockchip_ddr_set_auto_self_refresh; 18673d0407baSopenharmony_ci 18683d0407baSopenharmony_ci return 0; 18693d0407baSopenharmony_ci} 18703d0407baSopenharmony_ci 18713d0407baSopenharmony_cistatic __maybe_unused int rv1126_dmc_init(struct platform_device *pdev, 18723d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq) 18733d0407baSopenharmony_ci{ 18743d0407baSopenharmony_ci struct arm_smccc_res res; 18753d0407baSopenharmony_ci u32 size; 18763d0407baSopenharmony_ci int ret; 18773d0407baSopenharmony_ci int complt_irq; 18783d0407baSopenharmony_ci struct device_node *node; 18793d0407baSopenharmony_ci 18803d0407baSopenharmony_ci res = sip_smc_dram(0, 0, 18813d0407baSopenharmony_ci ROCKCHIP_SIP_CONFIG_DRAM_GET_VERSION); 18823d0407baSopenharmony_ci dev_notice(&pdev->dev, "current ATF version 0x%lx\n", res.a1); 18833d0407baSopenharmony_ci if (res.a0 || res.a1 < 0x100) { 18843d0407baSopenharmony_ci dev_err(&pdev->dev, 18853d0407baSopenharmony_ci "trusted firmware need to update or is invalid!\n"); 18863d0407baSopenharmony_ci return -ENXIO; 18873d0407baSopenharmony_ci } 18883d0407baSopenharmony_ci 18893d0407baSopenharmony_ci /* 18903d0407baSopenharmony_ci * first 4KB is used for interface parameters 18913d0407baSopenharmony_ci * after 4KB * N is dts parameters 18923d0407baSopenharmony_ci */ 18933d0407baSopenharmony_ci size = sizeof(struct rk1808_ddr_dts_config_timing); 18943d0407baSopenharmony_ci res = sip_smc_request_share_mem(DIV_ROUND_UP(size, 4096) + 1, 18953d0407baSopenharmony_ci SHARE_PAGE_TYPE_DDR); 18963d0407baSopenharmony_ci if (res.a0 != 0) { 18973d0407baSopenharmony_ci dev_err(&pdev->dev, "no ATF memory for init\n"); 18983d0407baSopenharmony_ci return -ENOMEM; 18993d0407baSopenharmony_ci } 19003d0407baSopenharmony_ci ddr_psci_param = (struct share_params *)res.a1; 19013d0407baSopenharmony_ci of_get_rv1126_timings(&pdev->dev, pdev->dev.of_node, 19023d0407baSopenharmony_ci (uint32_t *)ddr_psci_param); 19033d0407baSopenharmony_ci 19043d0407baSopenharmony_ci /* enable start dcf in kernel after dcf ready */ 19053d0407baSopenharmony_ci node = of_parse_phandle(pdev->dev.of_node, "dcf", 0); 19063d0407baSopenharmony_ci wait_ctrl.regmap_dcf = syscon_node_to_regmap(node); 19073d0407baSopenharmony_ci if (IS_ERR(wait_ctrl.regmap_dcf)) 19083d0407baSopenharmony_ci return PTR_ERR(wait_ctrl.regmap_dcf); 19093d0407baSopenharmony_ci wait_ctrl.dcf_en = 1; 19103d0407baSopenharmony_ci 19113d0407baSopenharmony_ci init_waitqueue_head(&wait_ctrl.wait_wq); 19123d0407baSopenharmony_ci wait_ctrl.wait_en = 1; 19133d0407baSopenharmony_ci wait_ctrl.wait_time_out_ms = 17 * 5; 19143d0407baSopenharmony_ci 19153d0407baSopenharmony_ci complt_irq = platform_get_irq_byname(pdev, "complete"); 19163d0407baSopenharmony_ci if (complt_irq < 0) { 19173d0407baSopenharmony_ci dev_err(&pdev->dev, "no IRQ for complt_irq: %d\n", 19183d0407baSopenharmony_ci complt_irq); 19193d0407baSopenharmony_ci return complt_irq; 19203d0407baSopenharmony_ci } 19213d0407baSopenharmony_ci wait_ctrl.complt_irq = complt_irq; 19223d0407baSopenharmony_ci 19233d0407baSopenharmony_ci ret = devm_request_irq(&pdev->dev, complt_irq, wait_dcf_complete_irq, 19243d0407baSopenharmony_ci 0, dev_name(&pdev->dev), &wait_ctrl); 19253d0407baSopenharmony_ci if (ret < 0) { 19263d0407baSopenharmony_ci dev_err(&pdev->dev, "cannot request complt_irq\n"); 19273d0407baSopenharmony_ci return ret; 19283d0407baSopenharmony_ci } 19293d0407baSopenharmony_ci disable_irq(complt_irq); 19303d0407baSopenharmony_ci 19313d0407baSopenharmony_ci if (of_property_read_u32(pdev->dev.of_node, "update_drv_odt_cfg", 19323d0407baSopenharmony_ci &ddr_psci_param->update_drv_odt_cfg)) 19333d0407baSopenharmony_ci ddr_psci_param->update_drv_odt_cfg = 0; 19343d0407baSopenharmony_ci 19353d0407baSopenharmony_ci if (of_property_read_u32(pdev->dev.of_node, "update_deskew_cfg", 19363d0407baSopenharmony_ci &ddr_psci_param->update_deskew_cfg)) 19373d0407baSopenharmony_ci ddr_psci_param->update_deskew_cfg = 0; 19383d0407baSopenharmony_ci 19393d0407baSopenharmony_ci dmcfreq->set_rate_params = ddr_psci_param; 19403d0407baSopenharmony_ci rockchip_set_ddrclk_params(dmcfreq->set_rate_params); 19413d0407baSopenharmony_ci rockchip_set_ddrclk_dmcfreq_wait_complete(rockchip_dmcfreq_wait_complete); 19423d0407baSopenharmony_ci 19433d0407baSopenharmony_ci res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0, 19443d0407baSopenharmony_ci ROCKCHIP_SIP_CONFIG_DRAM_INIT); 19453d0407baSopenharmony_ci if (res.a0) { 19463d0407baSopenharmony_ci dev_err(&pdev->dev, "rockchip_sip_config_dram_init error:%lx\n", 19473d0407baSopenharmony_ci res.a0); 19483d0407baSopenharmony_ci return -ENOMEM; 19493d0407baSopenharmony_ci } 19503d0407baSopenharmony_ci 19513d0407baSopenharmony_ci dmcfreq->set_auto_self_refresh = rockchip_ddr_set_auto_self_refresh; 19523d0407baSopenharmony_ci 19533d0407baSopenharmony_ci return 0; 19543d0407baSopenharmony_ci} 19553d0407baSopenharmony_ci 19563d0407baSopenharmony_cistatic const struct of_device_id rockchip_dmcfreq_of_match[] = { 19573d0407baSopenharmony_ci#if IS_ENABLED(CONFIG_CPU_PX30) 19583d0407baSopenharmony_ci { .compatible = "rockchip,px30-dmc", .data = px30_dmc_init }, 19593d0407baSopenharmony_ci#endif 19603d0407baSopenharmony_ci#if IS_ENABLED(CONFIG_CPU_RK1808) 19613d0407baSopenharmony_ci { .compatible = "rockchip,rk1808-dmc", .data = rk1808_dmc_init }, 19623d0407baSopenharmony_ci#endif 19633d0407baSopenharmony_ci#if IS_ENABLED(CONFIG_CPU_RK312X) 19643d0407baSopenharmony_ci { .compatible = "rockchip,rk3128-dmc", .data = rk3128_dmc_init }, 19653d0407baSopenharmony_ci#endif 19663d0407baSopenharmony_ci#if IS_ENABLED(CONFIG_CPU_RK322X) 19673d0407baSopenharmony_ci { .compatible = "rockchip,rk3228-dmc", .data = rk3228_dmc_init }, 19683d0407baSopenharmony_ci#endif 19693d0407baSopenharmony_ci#if IS_ENABLED(CONFIG_CPU_RK3288) 19703d0407baSopenharmony_ci { .compatible = "rockchip,rk3288-dmc", .data = rk3288_dmc_init }, 19713d0407baSopenharmony_ci#endif 19723d0407baSopenharmony_ci#if IS_ENABLED(CONFIG_CPU_RK3308) 19733d0407baSopenharmony_ci { .compatible = "rockchip,rk3308-dmc", .data = NULL }, 19743d0407baSopenharmony_ci#endif 19753d0407baSopenharmony_ci#if IS_ENABLED(CONFIG_CPU_RK3328) 19763d0407baSopenharmony_ci { .compatible = "rockchip,rk3328-dmc", .data = rk3328_dmc_init }, 19773d0407baSopenharmony_ci#endif 19783d0407baSopenharmony_ci#if IS_ENABLED(CONFIG_CPU_RK3368) 19793d0407baSopenharmony_ci { .compatible = "rockchip,rk3368-dmc", .data = rk3368_dmc_init }, 19803d0407baSopenharmony_ci#endif 19813d0407baSopenharmony_ci#if IS_ENABLED(CONFIG_CPU_RK3399) 19823d0407baSopenharmony_ci { .compatible = "rockchip,rk3399-dmc", .data = rk3399_dmc_init }, 19833d0407baSopenharmony_ci#endif 19843d0407baSopenharmony_ci#if IS_ENABLED(CONFIG_CPU_RK3568) 19853d0407baSopenharmony_ci { .compatible = "rockchip,rk3568-dmc", .data = rk3568_dmc_init }, 19863d0407baSopenharmony_ci#endif 19873d0407baSopenharmony_ci#if IS_ENABLED(CONFIG_CPU_RK3588) 19883d0407baSopenharmony_ci { .compatible = "rockchip,rk3588-dmc", .data = rk3588_dmc_init }, 19893d0407baSopenharmony_ci#endif 19903d0407baSopenharmony_ci#if IS_ENABLED(CONFIG_CPU_RV1126) 19913d0407baSopenharmony_ci { .compatible = "rockchip,rv1126-dmc", .data = rv1126_dmc_init }, 19923d0407baSopenharmony_ci#endif 19933d0407baSopenharmony_ci { }, 19943d0407baSopenharmony_ci}; 19953d0407baSopenharmony_ciMODULE_DEVICE_TABLE(of, rockchip_dmcfreq_of_match); 19963d0407baSopenharmony_ci 19973d0407baSopenharmony_cistatic int rockchip_get_freq_map_talbe(struct device_node *np, char *porp_name, 19983d0407baSopenharmony_ci struct freq_map_table **table) 19993d0407baSopenharmony_ci{ 20003d0407baSopenharmony_ci struct freq_map_table *tbl; 20013d0407baSopenharmony_ci const struct property *prop; 20023d0407baSopenharmony_ci unsigned int temp_freq = 0; 20033d0407baSopenharmony_ci int count, i; 20043d0407baSopenharmony_ci 20053d0407baSopenharmony_ci prop = of_find_property(np, porp_name, NULL); 20063d0407baSopenharmony_ci if (!prop) 20073d0407baSopenharmony_ci return -EINVAL; 20083d0407baSopenharmony_ci 20093d0407baSopenharmony_ci if (!prop->value) 20103d0407baSopenharmony_ci return -ENODATA; 20113d0407baSopenharmony_ci 20123d0407baSopenharmony_ci count = of_property_count_u32_elems(np, porp_name); 20133d0407baSopenharmony_ci if (count < 0) 20143d0407baSopenharmony_ci return -EINVAL; 20153d0407baSopenharmony_ci 20163d0407baSopenharmony_ci if (count % 3) 20173d0407baSopenharmony_ci return -EINVAL; 20183d0407baSopenharmony_ci 20193d0407baSopenharmony_ci tbl = kzalloc(sizeof(*tbl) * (count / 3 + 1), GFP_KERNEL); 20203d0407baSopenharmony_ci if (!tbl) 20213d0407baSopenharmony_ci return -ENOMEM; 20223d0407baSopenharmony_ci 20233d0407baSopenharmony_ci for (i = 0; i < count / 3; i++) { 20243d0407baSopenharmony_ci of_property_read_u32_index(np, porp_name, 3 * i, &tbl[i].min); 20253d0407baSopenharmony_ci of_property_read_u32_index(np, porp_name, 3 * i + 1, 20263d0407baSopenharmony_ci &tbl[i].max); 20273d0407baSopenharmony_ci of_property_read_u32_index(np, porp_name, 3 * i + 2, 20283d0407baSopenharmony_ci &temp_freq); 20293d0407baSopenharmony_ci tbl[i].freq = temp_freq * 1000; 20303d0407baSopenharmony_ci } 20313d0407baSopenharmony_ci 20323d0407baSopenharmony_ci tbl[i].min = 0; 20333d0407baSopenharmony_ci tbl[i].max = 0; 20343d0407baSopenharmony_ci tbl[i].freq = DMCFREQ_TABLE_END; 20353d0407baSopenharmony_ci 20363d0407baSopenharmony_ci *table = tbl; 20373d0407baSopenharmony_ci 20383d0407baSopenharmony_ci return 0; 20393d0407baSopenharmony_ci} 20403d0407baSopenharmony_ci 20413d0407baSopenharmony_cistatic int rockchip_get_rl_map_talbe(struct device_node *np, char *porp_name, 20423d0407baSopenharmony_ci struct rl_map_table **table) 20433d0407baSopenharmony_ci{ 20443d0407baSopenharmony_ci struct rl_map_table *tbl; 20453d0407baSopenharmony_ci const struct property *prop; 20463d0407baSopenharmony_ci int count, i; 20473d0407baSopenharmony_ci 20483d0407baSopenharmony_ci prop = of_find_property(np, porp_name, NULL); 20493d0407baSopenharmony_ci if (!prop) 20503d0407baSopenharmony_ci return -EINVAL; 20513d0407baSopenharmony_ci 20523d0407baSopenharmony_ci if (!prop->value) 20533d0407baSopenharmony_ci return -ENODATA; 20543d0407baSopenharmony_ci 20553d0407baSopenharmony_ci count = of_property_count_u32_elems(np, porp_name); 20563d0407baSopenharmony_ci if (count < 0) 20573d0407baSopenharmony_ci return -EINVAL; 20583d0407baSopenharmony_ci 20593d0407baSopenharmony_ci if (count % 2) 20603d0407baSopenharmony_ci return -EINVAL; 20613d0407baSopenharmony_ci 20623d0407baSopenharmony_ci tbl = kzalloc(sizeof(*tbl) * (count / 2 + 1), GFP_KERNEL); 20633d0407baSopenharmony_ci if (!tbl) 20643d0407baSopenharmony_ci return -ENOMEM; 20653d0407baSopenharmony_ci 20663d0407baSopenharmony_ci for (i = 0; i < count / 2; i++) { 20673d0407baSopenharmony_ci of_property_read_u32_index(np, porp_name, 2 * i, &tbl[i].pn); 20683d0407baSopenharmony_ci of_property_read_u32_index(np, porp_name, 2 * i + 1, 20693d0407baSopenharmony_ci &tbl[i].rl); 20703d0407baSopenharmony_ci } 20713d0407baSopenharmony_ci 20723d0407baSopenharmony_ci tbl[i].pn = 0; 20733d0407baSopenharmony_ci tbl[i].rl = DMCFREQ_TABLE_END; 20743d0407baSopenharmony_ci 20753d0407baSopenharmony_ci *table = tbl; 20763d0407baSopenharmony_ci 20773d0407baSopenharmony_ci return 0; 20783d0407baSopenharmony_ci} 20793d0407baSopenharmony_ci 20803d0407baSopenharmony_cistatic int rockchip_get_system_status_rate(struct device_node *np, 20813d0407baSopenharmony_ci char *porp_name, 20823d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq) 20833d0407baSopenharmony_ci{ 20843d0407baSopenharmony_ci const struct property *prop; 20853d0407baSopenharmony_ci unsigned int status = 0, freq = 0; 20863d0407baSopenharmony_ci unsigned long temp_rate = 0; 20873d0407baSopenharmony_ci int count, i; 20883d0407baSopenharmony_ci 20893d0407baSopenharmony_ci prop = of_find_property(np, porp_name, NULL); 20903d0407baSopenharmony_ci if (!prop) 20913d0407baSopenharmony_ci return -ENODEV; 20923d0407baSopenharmony_ci 20933d0407baSopenharmony_ci if (!prop->value) 20943d0407baSopenharmony_ci return -ENODATA; 20953d0407baSopenharmony_ci 20963d0407baSopenharmony_ci count = of_property_count_u32_elems(np, porp_name); 20973d0407baSopenharmony_ci if (count < 0) 20983d0407baSopenharmony_ci return -EINVAL; 20993d0407baSopenharmony_ci 21003d0407baSopenharmony_ci if (count % 2) 21013d0407baSopenharmony_ci return -EINVAL; 21023d0407baSopenharmony_ci 21033d0407baSopenharmony_ci for (i = 0; i < count / 2; i++) { 21043d0407baSopenharmony_ci of_property_read_u32_index(np, porp_name, 2 * i, 21053d0407baSopenharmony_ci &status); 21063d0407baSopenharmony_ci of_property_read_u32_index(np, porp_name, 2 * i + 1, 21073d0407baSopenharmony_ci &freq); 21083d0407baSopenharmony_ci switch (status) { 21093d0407baSopenharmony_ci case SYS_STATUS_NORMAL: 21103d0407baSopenharmony_ci dmcfreq->normal_rate = freq * 1000; 21113d0407baSopenharmony_ci break; 21123d0407baSopenharmony_ci case SYS_STATUS_SUSPEND: 21133d0407baSopenharmony_ci dmcfreq->suspend_rate = freq * 1000; 21143d0407baSopenharmony_ci break; 21153d0407baSopenharmony_ci case SYS_STATUS_VIDEO_1080P: 21163d0407baSopenharmony_ci dmcfreq->video_1080p_rate = freq * 1000; 21173d0407baSopenharmony_ci break; 21183d0407baSopenharmony_ci case SYS_STATUS_VIDEO_4K: 21193d0407baSopenharmony_ci dmcfreq->video_4k_rate = freq * 1000; 21203d0407baSopenharmony_ci break; 21213d0407baSopenharmony_ci case SYS_STATUS_VIDEO_4K_10B: 21223d0407baSopenharmony_ci dmcfreq->video_4k_10b_rate = freq * 1000; 21233d0407baSopenharmony_ci break; 21243d0407baSopenharmony_ci case SYS_STATUS_PERFORMANCE: 21253d0407baSopenharmony_ci dmcfreq->performance_rate = freq * 1000; 21263d0407baSopenharmony_ci break; 21273d0407baSopenharmony_ci case SYS_STATUS_HDMI: 21283d0407baSopenharmony_ci dmcfreq->hdmi_rate = freq * 1000; 21293d0407baSopenharmony_ci break; 21303d0407baSopenharmony_ci case SYS_STATUS_IDLE: 21313d0407baSopenharmony_ci dmcfreq->idle_rate = freq * 1000; 21323d0407baSopenharmony_ci break; 21333d0407baSopenharmony_ci case SYS_STATUS_REBOOT: 21343d0407baSopenharmony_ci dmcfreq->reboot_rate = freq * 1000; 21353d0407baSopenharmony_ci break; 21363d0407baSopenharmony_ci case SYS_STATUS_BOOST: 21373d0407baSopenharmony_ci dmcfreq->boost_rate = freq * 1000; 21383d0407baSopenharmony_ci break; 21393d0407baSopenharmony_ci case SYS_STATUS_ISP: 21403d0407baSopenharmony_ci case SYS_STATUS_CIF0: 21413d0407baSopenharmony_ci case SYS_STATUS_CIF1: 21423d0407baSopenharmony_ci case SYS_STATUS_DUALVIEW: 21433d0407baSopenharmony_ci temp_rate = freq * 1000; 21443d0407baSopenharmony_ci if (dmcfreq->fixed_rate < temp_rate) 21453d0407baSopenharmony_ci dmcfreq->fixed_rate = temp_rate; 21463d0407baSopenharmony_ci break; 21473d0407baSopenharmony_ci case SYS_STATUS_LOW_POWER: 21483d0407baSopenharmony_ci dmcfreq->low_power_rate = freq * 1000; 21493d0407baSopenharmony_ci break; 21503d0407baSopenharmony_ci default: 21513d0407baSopenharmony_ci break; 21523d0407baSopenharmony_ci } 21533d0407baSopenharmony_ci } 21543d0407baSopenharmony_ci 21553d0407baSopenharmony_ci return 0; 21563d0407baSopenharmony_ci} 21573d0407baSopenharmony_ci 21583d0407baSopenharmony_cistatic unsigned long rockchip_freq_level_2_rate(struct rockchip_dmcfreq *dmcfreq, 21593d0407baSopenharmony_ci unsigned int level) 21603d0407baSopenharmony_ci{ 21613d0407baSopenharmony_ci unsigned long rate = 0; 21623d0407baSopenharmony_ci 21633d0407baSopenharmony_ci switch (level) { 21643d0407baSopenharmony_ci case DMC_FREQ_LEVEL_LOW: 21653d0407baSopenharmony_ci rate = dmcfreq->rate_low; 21663d0407baSopenharmony_ci break; 21673d0407baSopenharmony_ci case DMC_FREQ_LEVEL_MID_LOW: 21683d0407baSopenharmony_ci rate = dmcfreq->rate_mid_low; 21693d0407baSopenharmony_ci break; 21703d0407baSopenharmony_ci case DMC_FREQ_LEVEL_MID_HIGH: 21713d0407baSopenharmony_ci rate = dmcfreq->rate_mid_high; 21723d0407baSopenharmony_ci break; 21733d0407baSopenharmony_ci case DMC_FREQ_LEVEL_HIGH: 21743d0407baSopenharmony_ci rate = dmcfreq->rate_high; 21753d0407baSopenharmony_ci break; 21763d0407baSopenharmony_ci default: 21773d0407baSopenharmony_ci break; 21783d0407baSopenharmony_ci } 21793d0407baSopenharmony_ci 21803d0407baSopenharmony_ci return rate; 21813d0407baSopenharmony_ci} 21823d0407baSopenharmony_ci 21833d0407baSopenharmony_cistatic int rockchip_get_system_status_level(struct device_node *np, 21843d0407baSopenharmony_ci char *porp_name, 21853d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq) 21863d0407baSopenharmony_ci{ 21873d0407baSopenharmony_ci const struct property *prop; 21883d0407baSopenharmony_ci unsigned int status = 0, level = 0; 21893d0407baSopenharmony_ci unsigned long temp_rate = 0; 21903d0407baSopenharmony_ci int count, i; 21913d0407baSopenharmony_ci 21923d0407baSopenharmony_ci prop = of_find_property(np, porp_name, NULL); 21933d0407baSopenharmony_ci if (!prop) 21943d0407baSopenharmony_ci return -ENODEV; 21953d0407baSopenharmony_ci 21963d0407baSopenharmony_ci if (!prop->value) 21973d0407baSopenharmony_ci return -ENODATA; 21983d0407baSopenharmony_ci 21993d0407baSopenharmony_ci count = of_property_count_u32_elems(np, porp_name); 22003d0407baSopenharmony_ci if (count < 0) 22013d0407baSopenharmony_ci return -EINVAL; 22023d0407baSopenharmony_ci 22033d0407baSopenharmony_ci if (count % 2) 22043d0407baSopenharmony_ci return -EINVAL; 22053d0407baSopenharmony_ci 22063d0407baSopenharmony_ci if (dmcfreq->freq_count == 1) { 22073d0407baSopenharmony_ci dmcfreq->rate_low = dmcfreq->freq_info_rate[0]; 22083d0407baSopenharmony_ci dmcfreq->rate_mid_low = dmcfreq->freq_info_rate[0]; 22093d0407baSopenharmony_ci dmcfreq->rate_mid_high = dmcfreq->freq_info_rate[0]; 22103d0407baSopenharmony_ci dmcfreq->rate_high = dmcfreq->freq_info_rate[0]; 22113d0407baSopenharmony_ci } else if (dmcfreq->freq_count == 2) { 22123d0407baSopenharmony_ci dmcfreq->rate_low = dmcfreq->freq_info_rate[0]; 22133d0407baSopenharmony_ci dmcfreq->rate_mid_low = dmcfreq->freq_info_rate[0]; 22143d0407baSopenharmony_ci dmcfreq->rate_mid_high = dmcfreq->freq_info_rate[1]; 22153d0407baSopenharmony_ci dmcfreq->rate_high = dmcfreq->freq_info_rate[1]; 22163d0407baSopenharmony_ci } else if (dmcfreq->freq_count == 3) { 22173d0407baSopenharmony_ci dmcfreq->rate_low = dmcfreq->freq_info_rate[0]; 22183d0407baSopenharmony_ci dmcfreq->rate_mid_low = dmcfreq->freq_info_rate[1]; 22193d0407baSopenharmony_ci dmcfreq->rate_mid_high = dmcfreq->freq_info_rate[1]; 22203d0407baSopenharmony_ci dmcfreq->rate_high = dmcfreq->freq_info_rate[2]; 22213d0407baSopenharmony_ci } else if (dmcfreq->freq_count == 4) { 22223d0407baSopenharmony_ci dmcfreq->rate_low = dmcfreq->freq_info_rate[0]; 22233d0407baSopenharmony_ci dmcfreq->rate_mid_low = dmcfreq->freq_info_rate[1]; 22243d0407baSopenharmony_ci dmcfreq->rate_mid_high = dmcfreq->freq_info_rate[2]; 22253d0407baSopenharmony_ci dmcfreq->rate_high = dmcfreq->freq_info_rate[3]; 22263d0407baSopenharmony_ci } else if (dmcfreq->freq_count == 5 || dmcfreq->freq_count == 6) { 22273d0407baSopenharmony_ci dmcfreq->rate_low = dmcfreq->freq_info_rate[0]; 22283d0407baSopenharmony_ci dmcfreq->rate_mid_low = dmcfreq->freq_info_rate[1]; 22293d0407baSopenharmony_ci dmcfreq->rate_mid_high = dmcfreq->freq_info_rate[dmcfreq->freq_count - 2]; 22303d0407baSopenharmony_ci dmcfreq->rate_high = dmcfreq->freq_info_rate[dmcfreq->freq_count - 1]; 22313d0407baSopenharmony_ci } else { 22323d0407baSopenharmony_ci return -EINVAL; 22333d0407baSopenharmony_ci } 22343d0407baSopenharmony_ci 22353d0407baSopenharmony_ci dmcfreq->auto_min_rate = dmcfreq->rate_low; 22363d0407baSopenharmony_ci 22373d0407baSopenharmony_ci for (i = 0; i < count / 2; i++) { 22383d0407baSopenharmony_ci of_property_read_u32_index(np, porp_name, 2 * i, 22393d0407baSopenharmony_ci &status); 22403d0407baSopenharmony_ci of_property_read_u32_index(np, porp_name, 2 * i + 1, 22413d0407baSopenharmony_ci &level); 22423d0407baSopenharmony_ci switch (status) { 22433d0407baSopenharmony_ci case SYS_STATUS_NORMAL: 22443d0407baSopenharmony_ci dmcfreq->normal_rate = rockchip_freq_level_2_rate(dmcfreq, level); 22453d0407baSopenharmony_ci dev_info(dmcfreq->dev, "normal_rate = %ld\n", dmcfreq->normal_rate); 22463d0407baSopenharmony_ci break; 22473d0407baSopenharmony_ci case SYS_STATUS_SUSPEND: 22483d0407baSopenharmony_ci dmcfreq->suspend_rate = rockchip_freq_level_2_rate(dmcfreq, level); 22493d0407baSopenharmony_ci dev_info(dmcfreq->dev, "suspend_rate = %ld\n", dmcfreq->suspend_rate); 22503d0407baSopenharmony_ci break; 22513d0407baSopenharmony_ci case SYS_STATUS_VIDEO_1080P: 22523d0407baSopenharmony_ci dmcfreq->video_1080p_rate = rockchip_freq_level_2_rate(dmcfreq, level); 22533d0407baSopenharmony_ci dev_info(dmcfreq->dev, "video_1080p_rate = %ld\n", 22543d0407baSopenharmony_ci dmcfreq->video_1080p_rate); 22553d0407baSopenharmony_ci break; 22563d0407baSopenharmony_ci case SYS_STATUS_VIDEO_4K: 22573d0407baSopenharmony_ci dmcfreq->video_4k_rate = rockchip_freq_level_2_rate(dmcfreq, level); 22583d0407baSopenharmony_ci dev_info(dmcfreq->dev, "video_4k_rate = %ld\n", dmcfreq->video_4k_rate); 22593d0407baSopenharmony_ci break; 22603d0407baSopenharmony_ci case SYS_STATUS_VIDEO_4K_10B: 22613d0407baSopenharmony_ci dmcfreq->video_4k_10b_rate = rockchip_freq_level_2_rate(dmcfreq, level); 22623d0407baSopenharmony_ci dev_info(dmcfreq->dev, "video_4k_10b_rate = %ld\n", 22633d0407baSopenharmony_ci dmcfreq->video_4k_10b_rate); 22643d0407baSopenharmony_ci break; 22653d0407baSopenharmony_ci case SYS_STATUS_PERFORMANCE: 22663d0407baSopenharmony_ci dmcfreq->performance_rate = rockchip_freq_level_2_rate(dmcfreq, level); 22673d0407baSopenharmony_ci dev_info(dmcfreq->dev, "performance_rate = %ld\n", 22683d0407baSopenharmony_ci dmcfreq->performance_rate); 22693d0407baSopenharmony_ci break; 22703d0407baSopenharmony_ci case SYS_STATUS_HDMI: 22713d0407baSopenharmony_ci dmcfreq->hdmi_rate = rockchip_freq_level_2_rate(dmcfreq, level); 22723d0407baSopenharmony_ci dev_info(dmcfreq->dev, "hdmi_rate = %ld\n", dmcfreq->hdmi_rate); 22733d0407baSopenharmony_ci break; 22743d0407baSopenharmony_ci case SYS_STATUS_IDLE: 22753d0407baSopenharmony_ci dmcfreq->idle_rate = rockchip_freq_level_2_rate(dmcfreq, level); 22763d0407baSopenharmony_ci dev_info(dmcfreq->dev, "idle_rate = %ld\n", dmcfreq->idle_rate); 22773d0407baSopenharmony_ci break; 22783d0407baSopenharmony_ci case SYS_STATUS_REBOOT: 22793d0407baSopenharmony_ci dmcfreq->reboot_rate = rockchip_freq_level_2_rate(dmcfreq, level); 22803d0407baSopenharmony_ci dev_info(dmcfreq->dev, "reboot_rate = %ld\n", dmcfreq->reboot_rate); 22813d0407baSopenharmony_ci break; 22823d0407baSopenharmony_ci case SYS_STATUS_BOOST: 22833d0407baSopenharmony_ci dmcfreq->boost_rate = rockchip_freq_level_2_rate(dmcfreq, level); 22843d0407baSopenharmony_ci dev_info(dmcfreq->dev, "boost_rate = %ld\n", dmcfreq->boost_rate); 22853d0407baSopenharmony_ci break; 22863d0407baSopenharmony_ci case SYS_STATUS_ISP: 22873d0407baSopenharmony_ci case SYS_STATUS_CIF0: 22883d0407baSopenharmony_ci case SYS_STATUS_CIF1: 22893d0407baSopenharmony_ci case SYS_STATUS_DUALVIEW: 22903d0407baSopenharmony_ci temp_rate = rockchip_freq_level_2_rate(dmcfreq, level); 22913d0407baSopenharmony_ci if (dmcfreq->fixed_rate < temp_rate) { 22923d0407baSopenharmony_ci dmcfreq->fixed_rate = temp_rate; 22933d0407baSopenharmony_ci dev_info(dmcfreq->dev, 22943d0407baSopenharmony_ci "fixed_rate(isp|cif0|cif1|dualview) = %ld\n", 22953d0407baSopenharmony_ci dmcfreq->fixed_rate); 22963d0407baSopenharmony_ci } 22973d0407baSopenharmony_ci break; 22983d0407baSopenharmony_ci case SYS_STATUS_LOW_POWER: 22993d0407baSopenharmony_ci dmcfreq->low_power_rate = rockchip_freq_level_2_rate(dmcfreq, level); 23003d0407baSopenharmony_ci dev_info(dmcfreq->dev, "low_power_rate = %ld\n", dmcfreq->low_power_rate); 23013d0407baSopenharmony_ci break; 23023d0407baSopenharmony_ci default: 23033d0407baSopenharmony_ci break; 23043d0407baSopenharmony_ci } 23053d0407baSopenharmony_ci } 23063d0407baSopenharmony_ci 23073d0407baSopenharmony_ci return 0; 23083d0407baSopenharmony_ci} 23093d0407baSopenharmony_ci 23103d0407baSopenharmony_cistatic void rockchip_dmcfreq_update_target(struct rockchip_dmcfreq *dmcfreq) 23113d0407baSopenharmony_ci{ 23123d0407baSopenharmony_ci struct devfreq *devfreq = dmcfreq->info.devfreq; 23133d0407baSopenharmony_ci 23143d0407baSopenharmony_ci mutex_lock(&devfreq->lock); 23153d0407baSopenharmony_ci update_devfreq(devfreq); 23163d0407baSopenharmony_ci mutex_unlock(&devfreq->lock); 23173d0407baSopenharmony_ci} 23183d0407baSopenharmony_ci 23193d0407baSopenharmony_cistatic int rockchip_dmcfreq_system_status_notifier(struct notifier_block *nb, 23203d0407baSopenharmony_ci unsigned long status, 23213d0407baSopenharmony_ci void *ptr) 23223d0407baSopenharmony_ci{ 23233d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq = system_status_to_dmcfreq(nb); 23243d0407baSopenharmony_ci unsigned long target_rate = 0; 23253d0407baSopenharmony_ci unsigned int refresh = false; 23263d0407baSopenharmony_ci bool is_fixed = false; 23273d0407baSopenharmony_ci 23283d0407baSopenharmony_ci if (dmcfreq->fixed_rate && (is_dualview(status) || is_isp(status))) { 23293d0407baSopenharmony_ci if (dmcfreq->is_fixed) 23303d0407baSopenharmony_ci return NOTIFY_OK; 23313d0407baSopenharmony_ci is_fixed = true; 23323d0407baSopenharmony_ci target_rate = dmcfreq->fixed_rate; 23333d0407baSopenharmony_ci goto next; 23343d0407baSopenharmony_ci } 23353d0407baSopenharmony_ci 23363d0407baSopenharmony_ci if (dmcfreq->reboot_rate && (status & SYS_STATUS_REBOOT)) { 23373d0407baSopenharmony_ci if (dmcfreq->info.auto_freq_en) 23383d0407baSopenharmony_ci devfreq_monitor_stop(dmcfreq->info.devfreq); 23393d0407baSopenharmony_ci target_rate = dmcfreq->reboot_rate; 23403d0407baSopenharmony_ci goto next; 23413d0407baSopenharmony_ci } 23423d0407baSopenharmony_ci 23433d0407baSopenharmony_ci if (dmcfreq->suspend_rate && (status & SYS_STATUS_SUSPEND)) { 23443d0407baSopenharmony_ci target_rate = dmcfreq->suspend_rate; 23453d0407baSopenharmony_ci refresh = true; 23463d0407baSopenharmony_ci goto next; 23473d0407baSopenharmony_ci } 23483d0407baSopenharmony_ci 23493d0407baSopenharmony_ci if (dmcfreq->low_power_rate && (status & SYS_STATUS_LOW_POWER)) { 23503d0407baSopenharmony_ci target_rate = dmcfreq->low_power_rate; 23513d0407baSopenharmony_ci goto next; 23523d0407baSopenharmony_ci } 23533d0407baSopenharmony_ci 23543d0407baSopenharmony_ci if (dmcfreq->performance_rate && (status & SYS_STATUS_PERFORMANCE)) { 23553d0407baSopenharmony_ci if (dmcfreq->performance_rate > target_rate) 23563d0407baSopenharmony_ci target_rate = dmcfreq->performance_rate; 23573d0407baSopenharmony_ci } 23583d0407baSopenharmony_ci 23593d0407baSopenharmony_ci if (dmcfreq->hdmi_rate && (status & SYS_STATUS_HDMI)) { 23603d0407baSopenharmony_ci if (dmcfreq->hdmi_rate > target_rate) 23613d0407baSopenharmony_ci target_rate = dmcfreq->hdmi_rate; 23623d0407baSopenharmony_ci } 23633d0407baSopenharmony_ci 23643d0407baSopenharmony_ci if (dmcfreq->video_4k_rate && (status & SYS_STATUS_VIDEO_4K)) { 23653d0407baSopenharmony_ci if (dmcfreq->video_4k_rate > target_rate) 23663d0407baSopenharmony_ci target_rate = dmcfreq->video_4k_rate; 23673d0407baSopenharmony_ci } 23683d0407baSopenharmony_ci 23693d0407baSopenharmony_ci if (dmcfreq->video_4k_10b_rate && (status & SYS_STATUS_VIDEO_4K_10B)) { 23703d0407baSopenharmony_ci if (dmcfreq->video_4k_10b_rate > target_rate) 23713d0407baSopenharmony_ci target_rate = dmcfreq->video_4k_10b_rate; 23723d0407baSopenharmony_ci } 23733d0407baSopenharmony_ci 23743d0407baSopenharmony_ci if (dmcfreq->video_1080p_rate && (status & SYS_STATUS_VIDEO_1080P)) { 23753d0407baSopenharmony_ci if (dmcfreq->video_1080p_rate > target_rate) 23763d0407baSopenharmony_ci target_rate = dmcfreq->video_1080p_rate; 23773d0407baSopenharmony_ci } 23783d0407baSopenharmony_ci 23793d0407baSopenharmony_cinext: 23803d0407baSopenharmony_ci 23813d0407baSopenharmony_ci dev_dbg(dmcfreq->dev, "status=0x%x\n", (unsigned int)status); 23823d0407baSopenharmony_ci dmcfreq->is_fixed = is_fixed; 23833d0407baSopenharmony_ci dmcfreq->status_rate = target_rate; 23843d0407baSopenharmony_ci if (dmcfreq->refresh != refresh) { 23853d0407baSopenharmony_ci if (dmcfreq->set_auto_self_refresh) 23863d0407baSopenharmony_ci dmcfreq->set_auto_self_refresh(refresh); 23873d0407baSopenharmony_ci dmcfreq->refresh = refresh; 23883d0407baSopenharmony_ci } 23893d0407baSopenharmony_ci rockchip_dmcfreq_update_target(dmcfreq); 23903d0407baSopenharmony_ci 23913d0407baSopenharmony_ci return NOTIFY_OK; 23923d0407baSopenharmony_ci} 23933d0407baSopenharmony_ci 23943d0407baSopenharmony_cistatic ssize_t rockchip_dmcfreq_status_show(struct device *dev, 23953d0407baSopenharmony_ci struct device_attribute *attr, 23963d0407baSopenharmony_ci char *buf) 23973d0407baSopenharmony_ci{ 23983d0407baSopenharmony_ci unsigned int status = rockchip_get_system_status(); 23993d0407baSopenharmony_ci 24003d0407baSopenharmony_ci return sprintf(buf, "0x%x\n", status); 24013d0407baSopenharmony_ci} 24023d0407baSopenharmony_ci 24033d0407baSopenharmony_cistatic ssize_t rockchip_dmcfreq_status_store(struct device *dev, 24043d0407baSopenharmony_ci struct device_attribute *attr, 24053d0407baSopenharmony_ci const char *buf, 24063d0407baSopenharmony_ci size_t count) 24073d0407baSopenharmony_ci{ 24083d0407baSopenharmony_ci if (!count) 24093d0407baSopenharmony_ci return -EINVAL; 24103d0407baSopenharmony_ci 24113d0407baSopenharmony_ci rockchip_update_system_status(buf); 24123d0407baSopenharmony_ci 24133d0407baSopenharmony_ci return count; 24143d0407baSopenharmony_ci} 24153d0407baSopenharmony_ci 24163d0407baSopenharmony_cistatic DEVICE_ATTR(system_status, 0644, rockchip_dmcfreq_status_show, 24173d0407baSopenharmony_ci rockchip_dmcfreq_status_store); 24183d0407baSopenharmony_ci 24193d0407baSopenharmony_cistatic ssize_t upthreshold_show(struct device *dev, 24203d0407baSopenharmony_ci struct device_attribute *attr, 24213d0407baSopenharmony_ci char *buf) 24223d0407baSopenharmony_ci{ 24233d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq = dev_get_drvdata(dev->parent); 24243d0407baSopenharmony_ci struct rockchip_dmcfreq_ondemand_data *data = &dmcfreq->ondemand_data; 24253d0407baSopenharmony_ci 24263d0407baSopenharmony_ci return sprintf(buf, "%d\n", data->upthreshold); 24273d0407baSopenharmony_ci} 24283d0407baSopenharmony_ci 24293d0407baSopenharmony_cistatic ssize_t upthreshold_store(struct device *dev, 24303d0407baSopenharmony_ci struct device_attribute *attr, 24313d0407baSopenharmony_ci const char *buf, 24323d0407baSopenharmony_ci size_t count) 24333d0407baSopenharmony_ci{ 24343d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq = dev_get_drvdata(dev->parent); 24353d0407baSopenharmony_ci struct rockchip_dmcfreq_ondemand_data *data = &dmcfreq->ondemand_data; 24363d0407baSopenharmony_ci unsigned int value; 24373d0407baSopenharmony_ci 24383d0407baSopenharmony_ci if (kstrtouint(buf, 10, &value)) 24393d0407baSopenharmony_ci return -EINVAL; 24403d0407baSopenharmony_ci 24413d0407baSopenharmony_ci data->upthreshold = value; 24423d0407baSopenharmony_ci 24433d0407baSopenharmony_ci return count; 24443d0407baSopenharmony_ci} 24453d0407baSopenharmony_ci 24463d0407baSopenharmony_cistatic DEVICE_ATTR_RW(upthreshold); 24473d0407baSopenharmony_ci 24483d0407baSopenharmony_cistatic ssize_t downdifferential_show(struct device *dev, 24493d0407baSopenharmony_ci struct device_attribute *attr, 24503d0407baSopenharmony_ci char *buf) 24513d0407baSopenharmony_ci{ 24523d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq = dev_get_drvdata(dev->parent); 24533d0407baSopenharmony_ci struct rockchip_dmcfreq_ondemand_data *data = &dmcfreq->ondemand_data; 24543d0407baSopenharmony_ci 24553d0407baSopenharmony_ci return sprintf(buf, "%d\n", data->downdifferential); 24563d0407baSopenharmony_ci} 24573d0407baSopenharmony_ci 24583d0407baSopenharmony_cistatic ssize_t downdifferential_store(struct device *dev, 24593d0407baSopenharmony_ci struct device_attribute *attr, 24603d0407baSopenharmony_ci const char *buf, 24613d0407baSopenharmony_ci size_t count) 24623d0407baSopenharmony_ci{ 24633d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq = dev_get_drvdata(dev->parent); 24643d0407baSopenharmony_ci struct rockchip_dmcfreq_ondemand_data *data = &dmcfreq->ondemand_data; 24653d0407baSopenharmony_ci unsigned int value; 24663d0407baSopenharmony_ci 24673d0407baSopenharmony_ci if (kstrtouint(buf, 10, &value)) 24683d0407baSopenharmony_ci return -EINVAL; 24693d0407baSopenharmony_ci 24703d0407baSopenharmony_ci data->downdifferential = value; 24713d0407baSopenharmony_ci 24723d0407baSopenharmony_ci return count; 24733d0407baSopenharmony_ci} 24743d0407baSopenharmony_ci 24753d0407baSopenharmony_cistatic DEVICE_ATTR_RW(downdifferential); 24763d0407baSopenharmony_ci 24773d0407baSopenharmony_cistatic unsigned long get_nocp_req_rate(struct rockchip_dmcfreq *dmcfreq) 24783d0407baSopenharmony_ci{ 24793d0407baSopenharmony_ci unsigned long target = 0, cpu_bw = 0; 24803d0407baSopenharmony_ci int i; 24813d0407baSopenharmony_ci 24823d0407baSopenharmony_ci if (!dmcfreq->cpu_bw_tbl || dmcfreq->nocp_cpu_id < 0) 24833d0407baSopenharmony_ci goto out; 24843d0407baSopenharmony_ci 24853d0407baSopenharmony_ci cpu_bw = dmcfreq->nocp_bw[dmcfreq->nocp_cpu_id]; 24863d0407baSopenharmony_ci 24873d0407baSopenharmony_ci for (i = 0; dmcfreq->cpu_bw_tbl[i].freq != CPUFREQ_TABLE_END; i++) { 24883d0407baSopenharmony_ci if (cpu_bw >= dmcfreq->cpu_bw_tbl[i].min) 24893d0407baSopenharmony_ci target = dmcfreq->cpu_bw_tbl[i].freq; 24903d0407baSopenharmony_ci } 24913d0407baSopenharmony_ci 24923d0407baSopenharmony_ciout: 24933d0407baSopenharmony_ci return target; 24943d0407baSopenharmony_ci} 24953d0407baSopenharmony_ci 24963d0407baSopenharmony_cistatic int devfreq_dmc_ondemand_func(struct devfreq *df, 24973d0407baSopenharmony_ci unsigned long *freq) 24983d0407baSopenharmony_ci{ 24993d0407baSopenharmony_ci int err; 25003d0407baSopenharmony_ci struct devfreq_dev_status *stat; 25013d0407baSopenharmony_ci unsigned long long a, b; 25023d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq = dev_get_drvdata(df->dev.parent); 25033d0407baSopenharmony_ci struct rockchip_dmcfreq_ondemand_data *data = &dmcfreq->ondemand_data; 25043d0407baSopenharmony_ci unsigned int upthreshold = data->upthreshold; 25053d0407baSopenharmony_ci unsigned int downdifferential = data->downdifferential; 25063d0407baSopenharmony_ci unsigned long target_freq = 0, nocp_req_rate = 0; 25073d0407baSopenharmony_ci u64 now; 25083d0407baSopenharmony_ci 25093d0407baSopenharmony_ci if (dmcfreq->info.auto_freq_en && !dmcfreq->is_fixed) { 25103d0407baSopenharmony_ci if (dmcfreq->status_rate) 25113d0407baSopenharmony_ci target_freq = dmcfreq->status_rate; 25123d0407baSopenharmony_ci else if (dmcfreq->auto_min_rate) 25133d0407baSopenharmony_ci target_freq = dmcfreq->auto_min_rate; 25143d0407baSopenharmony_ci nocp_req_rate = get_nocp_req_rate(dmcfreq); 25153d0407baSopenharmony_ci target_freq = max3(target_freq, nocp_req_rate, 25163d0407baSopenharmony_ci dmcfreq->info.vop_req_rate); 25173d0407baSopenharmony_ci now = ktime_to_us(ktime_get()); 25183d0407baSopenharmony_ci if (now < dmcfreq->touchboostpulse_endtime) 25193d0407baSopenharmony_ci target_freq = max(target_freq, dmcfreq->boost_rate); 25203d0407baSopenharmony_ci } else { 25213d0407baSopenharmony_ci if (dmcfreq->status_rate) 25223d0407baSopenharmony_ci target_freq = dmcfreq->status_rate; 25233d0407baSopenharmony_ci else if (dmcfreq->normal_rate) 25243d0407baSopenharmony_ci target_freq = dmcfreq->normal_rate; 25253d0407baSopenharmony_ci if (target_freq) 25263d0407baSopenharmony_ci *freq = target_freq; 25273d0407baSopenharmony_ci if (dmcfreq->info.auto_freq_en && !devfreq_update_stats(df)) 25283d0407baSopenharmony_ci return 0; 25293d0407baSopenharmony_ci goto reset_last_status; 25303d0407baSopenharmony_ci } 25313d0407baSopenharmony_ci 25323d0407baSopenharmony_ci if (!upthreshold || !downdifferential) 25333d0407baSopenharmony_ci goto reset_last_status; 25343d0407baSopenharmony_ci 25353d0407baSopenharmony_ci if (upthreshold > 100 || 25363d0407baSopenharmony_ci upthreshold < downdifferential) 25373d0407baSopenharmony_ci goto reset_last_status; 25383d0407baSopenharmony_ci 25393d0407baSopenharmony_ci err = devfreq_update_stats(df); 25403d0407baSopenharmony_ci if (err) 25413d0407baSopenharmony_ci goto reset_last_status; 25423d0407baSopenharmony_ci 25433d0407baSopenharmony_ci stat = &df->last_status; 25443d0407baSopenharmony_ci 25453d0407baSopenharmony_ci /* Assume MAX if it is going to be divided by zero */ 25463d0407baSopenharmony_ci if (stat->total_time == 0) { 25473d0407baSopenharmony_ci *freq = DEVFREQ_MAX_FREQ; 25483d0407baSopenharmony_ci return 0; 25493d0407baSopenharmony_ci } 25503d0407baSopenharmony_ci 25513d0407baSopenharmony_ci /* Prevent overflow */ 25523d0407baSopenharmony_ci if (stat->busy_time >= (1 << 24) || stat->total_time >= (1 << 24)) { 25533d0407baSopenharmony_ci stat->busy_time >>= 7; 25543d0407baSopenharmony_ci stat->total_time >>= 7; 25553d0407baSopenharmony_ci } 25563d0407baSopenharmony_ci 25573d0407baSopenharmony_ci /* Set MAX if it's busy enough */ 25583d0407baSopenharmony_ci if (stat->busy_time * 100 > 25593d0407baSopenharmony_ci stat->total_time * upthreshold) { 25603d0407baSopenharmony_ci *freq = DEVFREQ_MAX_FREQ; 25613d0407baSopenharmony_ci return 0; 25623d0407baSopenharmony_ci } 25633d0407baSopenharmony_ci 25643d0407baSopenharmony_ci /* Set MAX if we do not know the initial frequency */ 25653d0407baSopenharmony_ci if (stat->current_frequency == 0) { 25663d0407baSopenharmony_ci *freq = DEVFREQ_MAX_FREQ; 25673d0407baSopenharmony_ci return 0; 25683d0407baSopenharmony_ci } 25693d0407baSopenharmony_ci 25703d0407baSopenharmony_ci /* Keep the current frequency */ 25713d0407baSopenharmony_ci if (stat->busy_time * 100 > 25723d0407baSopenharmony_ci stat->total_time * (upthreshold - downdifferential)) { 25733d0407baSopenharmony_ci *freq = max(target_freq, stat->current_frequency); 25743d0407baSopenharmony_ci return 0; 25753d0407baSopenharmony_ci } 25763d0407baSopenharmony_ci 25773d0407baSopenharmony_ci /* Set the desired frequency based on the load */ 25783d0407baSopenharmony_ci a = stat->busy_time; 25793d0407baSopenharmony_ci a *= stat->current_frequency; 25803d0407baSopenharmony_ci b = div_u64(a, stat->total_time); 25813d0407baSopenharmony_ci b *= 100; 25823d0407baSopenharmony_ci b = div_u64(b, (upthreshold - downdifferential / 2)); 25833d0407baSopenharmony_ci *freq = max_t(unsigned long, target_freq, b); 25843d0407baSopenharmony_ci 25853d0407baSopenharmony_ci return 0; 25863d0407baSopenharmony_ci 25873d0407baSopenharmony_cireset_last_status: 25883d0407baSopenharmony_ci reset_last_status(df); 25893d0407baSopenharmony_ci 25903d0407baSopenharmony_ci return 0; 25913d0407baSopenharmony_ci} 25923d0407baSopenharmony_ci 25933d0407baSopenharmony_cistatic int devfreq_dmc_ondemand_handler(struct devfreq *devfreq, 25943d0407baSopenharmony_ci unsigned int event, void *data) 25953d0407baSopenharmony_ci{ 25963d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq = dev_get_drvdata(devfreq->dev.parent); 25973d0407baSopenharmony_ci 25983d0407baSopenharmony_ci if (!dmcfreq->info.auto_freq_en) 25993d0407baSopenharmony_ci return 0; 26003d0407baSopenharmony_ci 26013d0407baSopenharmony_ci switch (event) { 26023d0407baSopenharmony_ci case DEVFREQ_GOV_START: 26033d0407baSopenharmony_ci devfreq_monitor_start(devfreq); 26043d0407baSopenharmony_ci break; 26053d0407baSopenharmony_ci 26063d0407baSopenharmony_ci case DEVFREQ_GOV_STOP: 26073d0407baSopenharmony_ci devfreq_monitor_stop(devfreq); 26083d0407baSopenharmony_ci break; 26093d0407baSopenharmony_ci 26103d0407baSopenharmony_ci case DEVFREQ_GOV_UPDATE_INTERVAL: 26113d0407baSopenharmony_ci devfreq_update_interval(devfreq, (unsigned int *)data); 26123d0407baSopenharmony_ci break; 26133d0407baSopenharmony_ci 26143d0407baSopenharmony_ci case DEVFREQ_GOV_SUSPEND: 26153d0407baSopenharmony_ci devfreq_monitor_suspend(devfreq); 26163d0407baSopenharmony_ci break; 26173d0407baSopenharmony_ci 26183d0407baSopenharmony_ci case DEVFREQ_GOV_RESUME: 26193d0407baSopenharmony_ci devfreq_monitor_resume(devfreq); 26203d0407baSopenharmony_ci break; 26213d0407baSopenharmony_ci 26223d0407baSopenharmony_ci default: 26233d0407baSopenharmony_ci break; 26243d0407baSopenharmony_ci } 26253d0407baSopenharmony_ci 26263d0407baSopenharmony_ci return 0; 26273d0407baSopenharmony_ci} 26283d0407baSopenharmony_ci 26293d0407baSopenharmony_cistatic struct devfreq_governor devfreq_dmc_ondemand = { 26303d0407baSopenharmony_ci .name = "dmc_ondemand", 26313d0407baSopenharmony_ci .get_target_freq = devfreq_dmc_ondemand_func, 26323d0407baSopenharmony_ci .event_handler = devfreq_dmc_ondemand_handler, 26333d0407baSopenharmony_ci}; 26343d0407baSopenharmony_ci 26353d0407baSopenharmony_cistatic int rockchip_dmcfreq_enable_event(struct rockchip_dmcfreq *dmcfreq) 26363d0407baSopenharmony_ci{ 26373d0407baSopenharmony_ci int i, ret; 26383d0407baSopenharmony_ci 26393d0407baSopenharmony_ci if (!dmcfreq->info.auto_freq_en) 26403d0407baSopenharmony_ci return 0; 26413d0407baSopenharmony_ci 26423d0407baSopenharmony_ci for (i = 0; i < dmcfreq->edev_count; i++) { 26433d0407baSopenharmony_ci ret = devfreq_event_enable_edev(dmcfreq->edev[i]); 26443d0407baSopenharmony_ci if (ret < 0) { 26453d0407baSopenharmony_ci dev_err(dmcfreq->dev, 26463d0407baSopenharmony_ci "failed to enable devfreq-event\n"); 26473d0407baSopenharmony_ci return ret; 26483d0407baSopenharmony_ci } 26493d0407baSopenharmony_ci } 26503d0407baSopenharmony_ci 26513d0407baSopenharmony_ci return 0; 26523d0407baSopenharmony_ci} 26533d0407baSopenharmony_ci 26543d0407baSopenharmony_cistatic int rockchip_dmcfreq_disable_event(struct rockchip_dmcfreq *dmcfreq) 26553d0407baSopenharmony_ci{ 26563d0407baSopenharmony_ci int i, ret; 26573d0407baSopenharmony_ci 26583d0407baSopenharmony_ci if (!dmcfreq->info.auto_freq_en) 26593d0407baSopenharmony_ci return 0; 26603d0407baSopenharmony_ci 26613d0407baSopenharmony_ci for (i = 0; i < dmcfreq->edev_count; i++) { 26623d0407baSopenharmony_ci ret = devfreq_event_disable_edev(dmcfreq->edev[i]); 26633d0407baSopenharmony_ci if (ret < 0) { 26643d0407baSopenharmony_ci dev_err(dmcfreq->dev, 26653d0407baSopenharmony_ci "failed to disable devfreq-event\n"); 26663d0407baSopenharmony_ci return ret; 26673d0407baSopenharmony_ci } 26683d0407baSopenharmony_ci } 26693d0407baSopenharmony_ci 26703d0407baSopenharmony_ci return 0; 26713d0407baSopenharmony_ci} 26723d0407baSopenharmony_ci 26733d0407baSopenharmony_cistatic int rockchip_get_edev_id(struct rockchip_dmcfreq *dmcfreq, 26743d0407baSopenharmony_ci const char *name) 26753d0407baSopenharmony_ci{ 26763d0407baSopenharmony_ci struct devfreq_event_dev *edev; 26773d0407baSopenharmony_ci int i; 26783d0407baSopenharmony_ci 26793d0407baSopenharmony_ci for (i = 0; i < dmcfreq->edev_count; i++) { 26803d0407baSopenharmony_ci edev = dmcfreq->edev[i]; 26813d0407baSopenharmony_ci if (!strcmp(edev->desc->name, name)) 26823d0407baSopenharmony_ci return i; 26833d0407baSopenharmony_ci } 26843d0407baSopenharmony_ci 26853d0407baSopenharmony_ci return -EINVAL; 26863d0407baSopenharmony_ci} 26873d0407baSopenharmony_ci 26883d0407baSopenharmony_cistatic int rockchip_dmcfreq_get_event(struct rockchip_dmcfreq *dmcfreq) 26893d0407baSopenharmony_ci{ 26903d0407baSopenharmony_ci struct device *dev = dmcfreq->dev; 26913d0407baSopenharmony_ci struct device_node *events_np, *np = dev->of_node; 26923d0407baSopenharmony_ci int i, j, count, available_count = 0; 26933d0407baSopenharmony_ci 26943d0407baSopenharmony_ci count = devfreq_event_get_edev_count(dev, "devfreq-events"); 26953d0407baSopenharmony_ci if (count < 0) { 26963d0407baSopenharmony_ci dev_dbg(dev, "failed to get count of devfreq-event dev\n"); 26973d0407baSopenharmony_ci return 0; 26983d0407baSopenharmony_ci } 26993d0407baSopenharmony_ci for (i = 0; i < count; i++) { 27003d0407baSopenharmony_ci events_np = of_parse_phandle(np, "devfreq-events", i); 27013d0407baSopenharmony_ci if (!events_np) 27023d0407baSopenharmony_ci continue; 27033d0407baSopenharmony_ci if (of_device_is_available(events_np)) 27043d0407baSopenharmony_ci available_count++; 27053d0407baSopenharmony_ci of_node_put(events_np); 27063d0407baSopenharmony_ci } 27073d0407baSopenharmony_ci if (!available_count) { 27083d0407baSopenharmony_ci dev_dbg(dev, "failed to get available devfreq-event\n"); 27093d0407baSopenharmony_ci return 0; 27103d0407baSopenharmony_ci } 27113d0407baSopenharmony_ci dmcfreq->edev_count = available_count; 27123d0407baSopenharmony_ci dmcfreq->edev = devm_kzalloc(dev, 27133d0407baSopenharmony_ci sizeof(*dmcfreq->edev) * available_count, 27143d0407baSopenharmony_ci GFP_KERNEL); 27153d0407baSopenharmony_ci if (!dmcfreq->edev) 27163d0407baSopenharmony_ci return -ENOMEM; 27173d0407baSopenharmony_ci 27183d0407baSopenharmony_ci for (i = 0, j = 0; i < count; i++) { 27193d0407baSopenharmony_ci events_np = of_parse_phandle(np, "devfreq-events", i); 27203d0407baSopenharmony_ci if (!events_np) 27213d0407baSopenharmony_ci continue; 27223d0407baSopenharmony_ci if (of_device_is_available(events_np)) { 27233d0407baSopenharmony_ci of_node_put(events_np); 27243d0407baSopenharmony_ci if (j >= available_count) { 27253d0407baSopenharmony_ci dev_err(dev, "invalid event conut\n"); 27263d0407baSopenharmony_ci return -EINVAL; 27273d0407baSopenharmony_ci } 27283d0407baSopenharmony_ci dmcfreq->edev[j] = 27293d0407baSopenharmony_ci devfreq_event_get_edev_by_phandle(dev, "devfreq-events", i); 27303d0407baSopenharmony_ci if (IS_ERR(dmcfreq->edev[j])) 27313d0407baSopenharmony_ci return -EPROBE_DEFER; 27323d0407baSopenharmony_ci j++; 27333d0407baSopenharmony_ci } else { 27343d0407baSopenharmony_ci of_node_put(events_np); 27353d0407baSopenharmony_ci } 27363d0407baSopenharmony_ci } 27373d0407baSopenharmony_ci dmcfreq->info.auto_freq_en = true; 27383d0407baSopenharmony_ci dmcfreq->dfi_id = rockchip_get_edev_id(dmcfreq, "dfi"); 27393d0407baSopenharmony_ci dmcfreq->nocp_cpu_id = rockchip_get_edev_id(dmcfreq, "nocp-cpu"); 27403d0407baSopenharmony_ci dmcfreq->nocp_bw = 27413d0407baSopenharmony_ci devm_kzalloc(dev, sizeof(*dmcfreq->nocp_bw) * available_count, 27423d0407baSopenharmony_ci GFP_KERNEL); 27433d0407baSopenharmony_ci if (!dmcfreq->nocp_bw) 27443d0407baSopenharmony_ci return -ENOMEM; 27453d0407baSopenharmony_ci 27463d0407baSopenharmony_ci return 0; 27473d0407baSopenharmony_ci} 27483d0407baSopenharmony_ci 27493d0407baSopenharmony_cistatic int rockchip_dmcfreq_power_control(struct rockchip_dmcfreq *dmcfreq) 27503d0407baSopenharmony_ci{ 27513d0407baSopenharmony_ci struct device *dev = dmcfreq->dev; 27523d0407baSopenharmony_ci 27533d0407baSopenharmony_ci dmcfreq->vdd_center = devm_regulator_get_optional(dev, "center"); 27543d0407baSopenharmony_ci if (IS_ERR(dmcfreq->vdd_center)) { 27553d0407baSopenharmony_ci dev_err(dev, "Cannot get the regulator \"center\"\n"); 27563d0407baSopenharmony_ci return PTR_ERR(dmcfreq->vdd_center); 27573d0407baSopenharmony_ci } 27583d0407baSopenharmony_ci 27593d0407baSopenharmony_ci dmcfreq->dmc_clk = devm_clk_get(dev, "dmc_clk"); 27603d0407baSopenharmony_ci if (IS_ERR(dmcfreq->dmc_clk)) { 27613d0407baSopenharmony_ci dev_err(dev, "Cannot get the clk dmc_clk. If using SCMI, trusted firmware need update to V1.01 and above.\n"); 27623d0407baSopenharmony_ci return PTR_ERR(dmcfreq->dmc_clk); 27633d0407baSopenharmony_ci } 27643d0407baSopenharmony_ci dmcfreq->rate = clk_get_rate(dmcfreq->dmc_clk); 27653d0407baSopenharmony_ci 27663d0407baSopenharmony_ci return 0; 27673d0407baSopenharmony_ci} 27683d0407baSopenharmony_ci 27693d0407baSopenharmony_cistatic int rockchip_dmcfreq_dmc_init(struct platform_device *pdev, 27703d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq) 27713d0407baSopenharmony_ci{ 27723d0407baSopenharmony_ci const struct of_device_id *match; 27733d0407baSopenharmony_ci int (*init)(struct platform_device *pdev, 27743d0407baSopenharmony_ci struct rockchip_dmcfreq *data); 27753d0407baSopenharmony_ci int ret; 27763d0407baSopenharmony_ci 27773d0407baSopenharmony_ci match = of_match_node(rockchip_dmcfreq_of_match, pdev->dev.of_node); 27783d0407baSopenharmony_ci if (match) { 27793d0407baSopenharmony_ci init = match->data; 27803d0407baSopenharmony_ci if (init) { 27813d0407baSopenharmony_ci ret = init(pdev, dmcfreq); 27823d0407baSopenharmony_ci if (ret) 27833d0407baSopenharmony_ci return ret; 27843d0407baSopenharmony_ci } 27853d0407baSopenharmony_ci } 27863d0407baSopenharmony_ci 27873d0407baSopenharmony_ci return 0; 27883d0407baSopenharmony_ci} 27893d0407baSopenharmony_ci 27903d0407baSopenharmony_cistatic void rockchip_dmcfreq_parse_dt(struct rockchip_dmcfreq *dmcfreq) 27913d0407baSopenharmony_ci{ 27923d0407baSopenharmony_ci struct device *dev = dmcfreq->dev; 27933d0407baSopenharmony_ci struct device_node *np = dev->of_node; 27943d0407baSopenharmony_ci 27953d0407baSopenharmony_ci if (!rockchip_get_system_status_rate(np, "system-status-freq", dmcfreq)) 27963d0407baSopenharmony_ci dmcfreq->system_status_en = true; 27973d0407baSopenharmony_ci else if (!rockchip_get_system_status_level(np, "system-status-level", dmcfreq)) 27983d0407baSopenharmony_ci dmcfreq->system_status_en = true; 27993d0407baSopenharmony_ci 28003d0407baSopenharmony_ci of_property_read_u32(np, "min-cpu-freq", &dmcfreq->min_cpu_freq); 28013d0407baSopenharmony_ci 28023d0407baSopenharmony_ci of_property_read_u32(np, "upthreshold", 28033d0407baSopenharmony_ci &dmcfreq->ondemand_data.upthreshold); 28043d0407baSopenharmony_ci of_property_read_u32(np, "downdifferential", 28053d0407baSopenharmony_ci &dmcfreq->ondemand_data.downdifferential); 28063d0407baSopenharmony_ci if (dmcfreq->info.auto_freq_en) 28073d0407baSopenharmony_ci of_property_read_u32(np, "auto-freq-en", 28083d0407baSopenharmony_ci &dmcfreq->info.auto_freq_en); 28093d0407baSopenharmony_ci if (!dmcfreq->auto_min_rate) { 28103d0407baSopenharmony_ci of_property_read_u32(np, "auto-min-freq", 28113d0407baSopenharmony_ci (u32 *)&dmcfreq->auto_min_rate); 28123d0407baSopenharmony_ci dmcfreq->auto_min_rate *= 1000; 28133d0407baSopenharmony_ci } 28143d0407baSopenharmony_ci 28153d0407baSopenharmony_ci if (rockchip_get_freq_map_talbe(np, "cpu-bw-dmc-freq", 28163d0407baSopenharmony_ci &dmcfreq->cpu_bw_tbl)) 28173d0407baSopenharmony_ci dev_dbg(dev, "failed to get cpu bandwidth to dmc rate\n"); 28183d0407baSopenharmony_ci if (rockchip_get_freq_map_talbe(np, "vop-frame-bw-dmc-freq", 28193d0407baSopenharmony_ci &dmcfreq->info.vop_frame_bw_tbl)) 28203d0407baSopenharmony_ci dev_dbg(dev, "failed to get vop frame bandwidth to dmc rate\n"); 28213d0407baSopenharmony_ci if (rockchip_get_freq_map_talbe(np, "vop-bw-dmc-freq", 28223d0407baSopenharmony_ci &dmcfreq->info.vop_bw_tbl)) 28233d0407baSopenharmony_ci dev_err(dev, "failed to get vop bandwidth to dmc rate\n"); 28243d0407baSopenharmony_ci if (rockchip_get_rl_map_talbe(np, "vop-pn-msch-readlatency", 28253d0407baSopenharmony_ci &dmcfreq->info.vop_pn_rl_tbl)) 28263d0407baSopenharmony_ci dev_err(dev, "failed to get vop pn to msch rl\n"); 28273d0407baSopenharmony_ci 28283d0407baSopenharmony_ci of_property_read_u32(np, "touchboost_duration", 28293d0407baSopenharmony_ci (u32 *)&dmcfreq->touchboostpulse_duration_val); 28303d0407baSopenharmony_ci if (dmcfreq->touchboostpulse_duration_val) 28313d0407baSopenharmony_ci dmcfreq->touchboostpulse_duration_val *= USEC_PER_MSEC; 28323d0407baSopenharmony_ci else 28333d0407baSopenharmony_ci dmcfreq->touchboostpulse_duration_val = 500 * USEC_PER_MSEC; 28343d0407baSopenharmony_ci} 28353d0407baSopenharmony_ci 28363d0407baSopenharmony_cistatic int rockchip_dmcfreq_set_volt_only(struct rockchip_dmcfreq *dmcfreq) 28373d0407baSopenharmony_ci{ 28383d0407baSopenharmony_ci struct device *dev = dmcfreq->dev; 28393d0407baSopenharmony_ci struct dev_pm_opp *opp; 28403d0407baSopenharmony_ci unsigned long opp_volt, opp_rate = dmcfreq->rate; 28413d0407baSopenharmony_ci int ret; 28423d0407baSopenharmony_ci 28433d0407baSopenharmony_ci opp = devfreq_recommended_opp(dev, &opp_rate, 0); 28443d0407baSopenharmony_ci if (IS_ERR(opp)) { 28453d0407baSopenharmony_ci dev_err(dev, "Failed to find opp for %lu Hz\n", opp_rate); 28463d0407baSopenharmony_ci return PTR_ERR(opp); 28473d0407baSopenharmony_ci } 28483d0407baSopenharmony_ci opp_volt = dev_pm_opp_get_voltage(opp); 28493d0407baSopenharmony_ci dev_pm_opp_put(opp); 28503d0407baSopenharmony_ci 28513d0407baSopenharmony_ci ret = regulator_set_voltage(dmcfreq->vdd_center, opp_volt, INT_MAX); 28523d0407baSopenharmony_ci if (ret) { 28533d0407baSopenharmony_ci dev_err(dev, "Cannot set voltage %lu uV\n", opp_volt); 28543d0407baSopenharmony_ci return ret; 28553d0407baSopenharmony_ci } 28563d0407baSopenharmony_ci 28573d0407baSopenharmony_ci return 0; 28583d0407baSopenharmony_ci} 28593d0407baSopenharmony_ci 28603d0407baSopenharmony_cistatic int rockchip_dmcfreq_add_devfreq(struct rockchip_dmcfreq *dmcfreq) 28613d0407baSopenharmony_ci{ 28623d0407baSopenharmony_ci struct devfreq_dev_profile *devp = &rockchip_devfreq_dmc_profile; 28633d0407baSopenharmony_ci struct device *dev = dmcfreq->dev; 28643d0407baSopenharmony_ci struct dev_pm_opp *opp; 28653d0407baSopenharmony_ci struct devfreq *devfreq; 28663d0407baSopenharmony_ci unsigned long opp_rate = dmcfreq->rate; 28673d0407baSopenharmony_ci 28683d0407baSopenharmony_ci opp = devfreq_recommended_opp(dev, &opp_rate, 0); 28693d0407baSopenharmony_ci if (IS_ERR(opp)) { 28703d0407baSopenharmony_ci dev_err(dev, "Failed to find opp for %lu Hz\n", opp_rate); 28713d0407baSopenharmony_ci return PTR_ERR(opp); 28723d0407baSopenharmony_ci } 28733d0407baSopenharmony_ci dev_pm_opp_put(opp); 28743d0407baSopenharmony_ci 28753d0407baSopenharmony_ci devp->initial_freq = dmcfreq->rate; 28763d0407baSopenharmony_ci devfreq = devm_devfreq_add_device(dev, devp, "dmc_ondemand", 28773d0407baSopenharmony_ci &dmcfreq->ondemand_data); 28783d0407baSopenharmony_ci if (IS_ERR(devfreq)) { 28793d0407baSopenharmony_ci dev_err(dev, "failed to add devfreq\n"); 28803d0407baSopenharmony_ci return PTR_ERR(devfreq); 28813d0407baSopenharmony_ci } 28823d0407baSopenharmony_ci 28833d0407baSopenharmony_ci devm_devfreq_register_opp_notifier(dev, devfreq); 28843d0407baSopenharmony_ci 28853d0407baSopenharmony_ci devfreq->last_status.current_frequency = opp_rate; 28863d0407baSopenharmony_ci 28873d0407baSopenharmony_ci reset_last_status(devfreq); 28883d0407baSopenharmony_ci 28893d0407baSopenharmony_ci dmcfreq->info.devfreq = devfreq; 28903d0407baSopenharmony_ci 28913d0407baSopenharmony_ci return 0; 28923d0407baSopenharmony_ci} 28933d0407baSopenharmony_ci 28943d0407baSopenharmony_cistatic struct monitor_dev_profile dmc_mdevp = { 28953d0407baSopenharmony_ci .type = MONITOR_TPYE_DEV, 28963d0407baSopenharmony_ci .low_temp_adjust = rockchip_monitor_dev_low_temp_adjust, 28973d0407baSopenharmony_ci .high_temp_adjust = rockchip_monitor_dev_high_temp_adjust, 28983d0407baSopenharmony_ci}; 28993d0407baSopenharmony_ci 29003d0407baSopenharmony_cistatic void rockchip_dmcfreq_register_notifier(struct rockchip_dmcfreq *dmcfreq) 29013d0407baSopenharmony_ci{ 29023d0407baSopenharmony_ci int ret; 29033d0407baSopenharmony_ci 29043d0407baSopenharmony_ci if (vop_register_dmc()) 29053d0407baSopenharmony_ci dev_err(dmcfreq->dev, "fail to register notify to vop.\n"); 29063d0407baSopenharmony_ci 29073d0407baSopenharmony_ci dmcfreq->status_nb.notifier_call = 29083d0407baSopenharmony_ci rockchip_dmcfreq_system_status_notifier; 29093d0407baSopenharmony_ci ret = rockchip_register_system_status_notifier(&dmcfreq->status_nb); 29103d0407baSopenharmony_ci if (ret) 29113d0407baSopenharmony_ci dev_err(dmcfreq->dev, "failed to register system_status nb\n"); 29123d0407baSopenharmony_ci 29133d0407baSopenharmony_ci dmc_mdevp.data = dmcfreq->info.devfreq; 29143d0407baSopenharmony_ci dmcfreq->mdev_info = rockchip_system_monitor_register(dmcfreq->dev, 29153d0407baSopenharmony_ci &dmc_mdevp); 29163d0407baSopenharmony_ci if (IS_ERR(dmcfreq->mdev_info)) { 29173d0407baSopenharmony_ci dev_dbg(dmcfreq->dev, "without without system monitor\n"); 29183d0407baSopenharmony_ci dmcfreq->mdev_info = NULL; 29193d0407baSopenharmony_ci } 29203d0407baSopenharmony_ci} 29213d0407baSopenharmony_ci 29223d0407baSopenharmony_cistatic void rockchip_dmcfreq_add_interface(struct rockchip_dmcfreq *dmcfreq) 29233d0407baSopenharmony_ci{ 29243d0407baSopenharmony_ci struct devfreq *devfreq = dmcfreq->info.devfreq; 29253d0407baSopenharmony_ci 29263d0407baSopenharmony_ci if (sysfs_create_file(&devfreq->dev.kobj, &dev_attr_upthreshold.attr)) 29273d0407baSopenharmony_ci dev_err(dmcfreq->dev, 29283d0407baSopenharmony_ci "failed to register upthreshold sysfs file\n"); 29293d0407baSopenharmony_ci if (sysfs_create_file(&devfreq->dev.kobj, 29303d0407baSopenharmony_ci &dev_attr_downdifferential.attr)) 29313d0407baSopenharmony_ci dev_err(dmcfreq->dev, 29323d0407baSopenharmony_ci "failed to register downdifferential sysfs file\n"); 29333d0407baSopenharmony_ci 29343d0407baSopenharmony_ci if (!rockchip_add_system_status_interface(&devfreq->dev)) 29353d0407baSopenharmony_ci return; 29363d0407baSopenharmony_ci if (sysfs_create_file(&devfreq->dev.kobj, 29373d0407baSopenharmony_ci &dev_attr_system_status.attr)) 29383d0407baSopenharmony_ci dev_err(dmcfreq->dev, 29393d0407baSopenharmony_ci "failed to register system_status sysfs file\n"); 29403d0407baSopenharmony_ci} 29413d0407baSopenharmony_ci 29423d0407baSopenharmony_cistatic void rockchip_dmcfreq_boost_work(struct work_struct *work) 29433d0407baSopenharmony_ci{ 29443d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq = boost_to_dmcfreq(work); 29453d0407baSopenharmony_ci 29463d0407baSopenharmony_ci rockchip_dmcfreq_update_target(dmcfreq); 29473d0407baSopenharmony_ci} 29483d0407baSopenharmony_ci 29493d0407baSopenharmony_cistatic void rockchip_dmcfreq_input_event(struct input_handle *handle, 29503d0407baSopenharmony_ci unsigned int type, 29513d0407baSopenharmony_ci unsigned int code, 29523d0407baSopenharmony_ci int value) 29533d0407baSopenharmony_ci{ 29543d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq = handle->private; 29553d0407baSopenharmony_ci u64 now, endtime; 29563d0407baSopenharmony_ci 29573d0407baSopenharmony_ci if (type != EV_ABS && type != EV_KEY) 29583d0407baSopenharmony_ci return; 29593d0407baSopenharmony_ci 29603d0407baSopenharmony_ci now = ktime_to_us(ktime_get()); 29613d0407baSopenharmony_ci endtime = now + dmcfreq->touchboostpulse_duration_val; 29623d0407baSopenharmony_ci if (endtime < (dmcfreq->touchboostpulse_endtime + 10 * USEC_PER_MSEC)) 29633d0407baSopenharmony_ci return; 29643d0407baSopenharmony_ci dmcfreq->touchboostpulse_endtime = endtime; 29653d0407baSopenharmony_ci 29663d0407baSopenharmony_ci schedule_work(&dmcfreq->boost_work); 29673d0407baSopenharmony_ci} 29683d0407baSopenharmony_ci 29693d0407baSopenharmony_cistatic int rockchip_dmcfreq_input_connect(struct input_handler *handler, 29703d0407baSopenharmony_ci struct input_dev *dev, 29713d0407baSopenharmony_ci const struct input_device_id *id) 29723d0407baSopenharmony_ci{ 29733d0407baSopenharmony_ci int error; 29743d0407baSopenharmony_ci struct input_handle *handle; 29753d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq = input_hd_to_dmcfreq(handler); 29763d0407baSopenharmony_ci 29773d0407baSopenharmony_ci handle = kzalloc(sizeof(*handle), GFP_KERNEL); 29783d0407baSopenharmony_ci if (!handle) 29793d0407baSopenharmony_ci return -ENOMEM; 29803d0407baSopenharmony_ci 29813d0407baSopenharmony_ci handle->dev = dev; 29823d0407baSopenharmony_ci handle->handler = handler; 29833d0407baSopenharmony_ci handle->name = "dmcfreq"; 29843d0407baSopenharmony_ci handle->private = dmcfreq; 29853d0407baSopenharmony_ci 29863d0407baSopenharmony_ci error = input_register_handle(handle); 29873d0407baSopenharmony_ci if (error) 29883d0407baSopenharmony_ci goto err2; 29893d0407baSopenharmony_ci 29903d0407baSopenharmony_ci error = input_open_device(handle); 29913d0407baSopenharmony_ci if (error) 29923d0407baSopenharmony_ci goto err1; 29933d0407baSopenharmony_ci 29943d0407baSopenharmony_ci return 0; 29953d0407baSopenharmony_cierr1: 29963d0407baSopenharmony_ci input_unregister_handle(handle); 29973d0407baSopenharmony_cierr2: 29983d0407baSopenharmony_ci kfree(handle); 29993d0407baSopenharmony_ci return error; 30003d0407baSopenharmony_ci} 30013d0407baSopenharmony_ci 30023d0407baSopenharmony_cistatic void rockchip_dmcfreq_input_disconnect(struct input_handle *handle) 30033d0407baSopenharmony_ci{ 30043d0407baSopenharmony_ci input_close_device(handle); 30053d0407baSopenharmony_ci input_unregister_handle(handle); 30063d0407baSopenharmony_ci kfree(handle); 30073d0407baSopenharmony_ci} 30083d0407baSopenharmony_ci 30093d0407baSopenharmony_cistatic const struct input_device_id rockchip_dmcfreq_input_ids[] = { 30103d0407baSopenharmony_ci { 30113d0407baSopenharmony_ci .flags = INPUT_DEVICE_ID_MATCH_EVBIT | 30123d0407baSopenharmony_ci INPUT_DEVICE_ID_MATCH_ABSBIT, 30133d0407baSopenharmony_ci .evbit = { BIT_MASK(EV_ABS) }, 30143d0407baSopenharmony_ci .absbit = { [BIT_WORD(ABS_MT_POSITION_X)] = 30153d0407baSopenharmony_ci BIT_MASK(ABS_MT_POSITION_X) | 30163d0407baSopenharmony_ci BIT_MASK(ABS_MT_POSITION_Y) }, 30173d0407baSopenharmony_ci }, 30183d0407baSopenharmony_ci { 30193d0407baSopenharmony_ci .flags = INPUT_DEVICE_ID_MATCH_KEYBIT | 30203d0407baSopenharmony_ci INPUT_DEVICE_ID_MATCH_ABSBIT, 30213d0407baSopenharmony_ci .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) }, 30223d0407baSopenharmony_ci .absbit = { [BIT_WORD(ABS_X)] = 30233d0407baSopenharmony_ci BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) }, 30243d0407baSopenharmony_ci }, 30253d0407baSopenharmony_ci { 30263d0407baSopenharmony_ci .flags = INPUT_DEVICE_ID_MATCH_EVBIT, 30273d0407baSopenharmony_ci .evbit = { BIT_MASK(EV_KEY) }, 30283d0407baSopenharmony_ci }, 30293d0407baSopenharmony_ci { }, 30303d0407baSopenharmony_ci}; 30313d0407baSopenharmony_ci 30323d0407baSopenharmony_cistatic void rockchip_dmcfreq_boost_init(struct rockchip_dmcfreq *dmcfreq) 30333d0407baSopenharmony_ci{ 30343d0407baSopenharmony_ci if (!dmcfreq->boost_rate) 30353d0407baSopenharmony_ci return; 30363d0407baSopenharmony_ci INIT_WORK(&dmcfreq->boost_work, rockchip_dmcfreq_boost_work); 30373d0407baSopenharmony_ci dmcfreq->input_handler.event = rockchip_dmcfreq_input_event; 30383d0407baSopenharmony_ci dmcfreq->input_handler.connect = rockchip_dmcfreq_input_connect; 30393d0407baSopenharmony_ci dmcfreq->input_handler.disconnect = rockchip_dmcfreq_input_disconnect; 30403d0407baSopenharmony_ci dmcfreq->input_handler.name = "dmcfreq"; 30413d0407baSopenharmony_ci dmcfreq->input_handler.id_table = rockchip_dmcfreq_input_ids; 30423d0407baSopenharmony_ci if (input_register_handler(&dmcfreq->input_handler)) 30433d0407baSopenharmony_ci dev_err(dmcfreq->dev, "failed to register input handler\n"); 30443d0407baSopenharmony_ci} 30453d0407baSopenharmony_ci 30463d0407baSopenharmony_cistatic unsigned long model_static_power(struct devfreq *devfreq, 30473d0407baSopenharmony_ci unsigned long voltage) 30483d0407baSopenharmony_ci{ 30493d0407baSopenharmony_ci struct device *dev = devfreq->dev.parent; 30503d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq = dev_get_drvdata(dev); 30513d0407baSopenharmony_ci 30523d0407baSopenharmony_ci int temperature; 30533d0407baSopenharmony_ci unsigned long temp; 30543d0407baSopenharmony_ci unsigned long temp_squared, temp_cubed, temp_scaling_factor; 30553d0407baSopenharmony_ci const unsigned long voltage_cubed = (voltage * voltage * voltage) >> 10; 30563d0407baSopenharmony_ci 30573d0407baSopenharmony_ci if (!IS_ERR_OR_NULL(dmcfreq->ddr_tz) && dmcfreq->ddr_tz->ops->get_temp) { 30583d0407baSopenharmony_ci int ret; 30593d0407baSopenharmony_ci 30603d0407baSopenharmony_ci ret = 30613d0407baSopenharmony_ci dmcfreq->ddr_tz->ops->get_temp(dmcfreq->ddr_tz, 30623d0407baSopenharmony_ci &temperature); 30633d0407baSopenharmony_ci if (ret) { 30643d0407baSopenharmony_ci dev_warn_ratelimited(dev, 30653d0407baSopenharmony_ci "failed to read temp for ddr thermal zone: %d\n", 30663d0407baSopenharmony_ci ret); 30673d0407baSopenharmony_ci temperature = FALLBACK_STATIC_TEMPERATURE; 30683d0407baSopenharmony_ci } 30693d0407baSopenharmony_ci } else { 30703d0407baSopenharmony_ci temperature = FALLBACK_STATIC_TEMPERATURE; 30713d0407baSopenharmony_ci } 30723d0407baSopenharmony_ci 30733d0407baSopenharmony_ci /* 30743d0407baSopenharmony_ci * Calculate the temperature scaling factor. To be applied to the 30753d0407baSopenharmony_ci * voltage scaled power. 30763d0407baSopenharmony_ci */ 30773d0407baSopenharmony_ci temp = temperature / 1000; 30783d0407baSopenharmony_ci temp_squared = temp * temp; 30793d0407baSopenharmony_ci temp_cubed = temp_squared * temp; 30803d0407baSopenharmony_ci temp_scaling_factor = (dmcfreq->ts[3] * temp_cubed) 30813d0407baSopenharmony_ci + (dmcfreq->ts[2] * temp_squared) 30823d0407baSopenharmony_ci + (dmcfreq->ts[1] * temp) 30833d0407baSopenharmony_ci + dmcfreq->ts[0]; 30843d0407baSopenharmony_ci 30853d0407baSopenharmony_ci return (((dmcfreq->static_coefficient * voltage_cubed) >> 20) 30863d0407baSopenharmony_ci * temp_scaling_factor) / 1000000; 30873d0407baSopenharmony_ci} 30883d0407baSopenharmony_ci 30893d0407baSopenharmony_cistatic struct devfreq_cooling_power ddr_cooling_power_data = { 30903d0407baSopenharmony_ci .get_static_power = model_static_power, 30913d0407baSopenharmony_ci .dyn_power_coeff = 120, 30923d0407baSopenharmony_ci}; 30933d0407baSopenharmony_ci 30943d0407baSopenharmony_cistatic int ddr_power_model_simple_init(struct rockchip_dmcfreq *dmcfreq) 30953d0407baSopenharmony_ci{ 30963d0407baSopenharmony_ci struct device_node *power_model_node; 30973d0407baSopenharmony_ci const char *tz_name; 30983d0407baSopenharmony_ci u32 temp; 30993d0407baSopenharmony_ci 31003d0407baSopenharmony_ci power_model_node = of_get_child_by_name(dmcfreq->dev->of_node, 31013d0407baSopenharmony_ci "ddr_power_model"); 31023d0407baSopenharmony_ci if (!power_model_node) { 31033d0407baSopenharmony_ci dev_err(dmcfreq->dev, "could not find power_model node\n"); 31043d0407baSopenharmony_ci return -ENODEV; 31053d0407baSopenharmony_ci } 31063d0407baSopenharmony_ci 31073d0407baSopenharmony_ci if (of_property_read_string(power_model_node, "thermal-zone", &tz_name)) { 31083d0407baSopenharmony_ci dev_err(dmcfreq->dev, "ts in power_model not available\n"); 31093d0407baSopenharmony_ci return -EINVAL; 31103d0407baSopenharmony_ci } 31113d0407baSopenharmony_ci 31123d0407baSopenharmony_ci dmcfreq->ddr_tz = thermal_zone_get_zone_by_name(tz_name); 31133d0407baSopenharmony_ci if (IS_ERR(dmcfreq->ddr_tz)) { 31143d0407baSopenharmony_ci pr_warn_ratelimited 31153d0407baSopenharmony_ci ("Error getting ddr thermal zone (%ld), not yet ready?\n", 31163d0407baSopenharmony_ci PTR_ERR(dmcfreq->ddr_tz)); 31173d0407baSopenharmony_ci dmcfreq->ddr_tz = NULL; 31183d0407baSopenharmony_ci 31193d0407baSopenharmony_ci return -EPROBE_DEFER; 31203d0407baSopenharmony_ci } 31213d0407baSopenharmony_ci 31223d0407baSopenharmony_ci if (of_property_read_u32(power_model_node, "static-power-coefficient", 31233d0407baSopenharmony_ci &dmcfreq->static_coefficient)) { 31243d0407baSopenharmony_ci dev_err(dmcfreq->dev, 31253d0407baSopenharmony_ci "static-power-coefficient not available\n"); 31263d0407baSopenharmony_ci return -EINVAL; 31273d0407baSopenharmony_ci } 31283d0407baSopenharmony_ci if (of_property_read_u32(power_model_node, "dynamic-power-coefficient", 31293d0407baSopenharmony_ci &temp)) { 31303d0407baSopenharmony_ci dev_err(dmcfreq->dev, 31313d0407baSopenharmony_ci "dynamic-power-coefficient not available\n"); 31323d0407baSopenharmony_ci return -EINVAL; 31333d0407baSopenharmony_ci } 31343d0407baSopenharmony_ci ddr_cooling_power_data.dyn_power_coeff = (unsigned long)temp; 31353d0407baSopenharmony_ci 31363d0407baSopenharmony_ci if (of_property_read_u32_array 31373d0407baSopenharmony_ci (power_model_node, "ts", (u32 *)dmcfreq->ts, 4)) { 31383d0407baSopenharmony_ci dev_err(dmcfreq->dev, "ts in power_model not available\n"); 31393d0407baSopenharmony_ci return -EINVAL; 31403d0407baSopenharmony_ci } 31413d0407baSopenharmony_ci 31423d0407baSopenharmony_ci return 0; 31433d0407baSopenharmony_ci} 31443d0407baSopenharmony_ci 31453d0407baSopenharmony_cistatic void 31463d0407baSopenharmony_cirockchip_dmcfreq_register_cooling_device(struct rockchip_dmcfreq *dmcfreq) 31473d0407baSopenharmony_ci{ 31483d0407baSopenharmony_ci int ret; 31493d0407baSopenharmony_ci 31503d0407baSopenharmony_ci ret = ddr_power_model_simple_init(dmcfreq); 31513d0407baSopenharmony_ci if (ret) 31523d0407baSopenharmony_ci return; 31533d0407baSopenharmony_ci dmcfreq->devfreq_cooling = 31543d0407baSopenharmony_ci of_devfreq_cooling_register_power(dmcfreq->dev->of_node, 31553d0407baSopenharmony_ci dmcfreq->info.devfreq, 31563d0407baSopenharmony_ci &ddr_cooling_power_data); 31573d0407baSopenharmony_ci if (IS_ERR(dmcfreq->devfreq_cooling)) { 31583d0407baSopenharmony_ci ret = PTR_ERR(dmcfreq->devfreq_cooling); 31593d0407baSopenharmony_ci dev_err(dmcfreq->dev, 31603d0407baSopenharmony_ci "Failed to register cooling device (%d)\n", 31613d0407baSopenharmony_ci ret); 31623d0407baSopenharmony_ci } 31633d0407baSopenharmony_ci} 31643d0407baSopenharmony_ci 31653d0407baSopenharmony_cistatic int rockchip_dmcfreq_probe(struct platform_device *pdev) 31663d0407baSopenharmony_ci{ 31673d0407baSopenharmony_ci struct device *dev = &pdev->dev; 31683d0407baSopenharmony_ci struct rockchip_dmcfreq *data; 31693d0407baSopenharmony_ci int ret; 31703d0407baSopenharmony_ci 31713d0407baSopenharmony_ci data = devm_kzalloc(dev, sizeof(struct rockchip_dmcfreq), GFP_KERNEL); 31723d0407baSopenharmony_ci if (!data) 31733d0407baSopenharmony_ci return -ENOMEM; 31743d0407baSopenharmony_ci 31753d0407baSopenharmony_ci data->dev = dev; 31763d0407baSopenharmony_ci data->info.dev = dev; 31773d0407baSopenharmony_ci mutex_init(&data->lock); 31783d0407baSopenharmony_ci INIT_LIST_HEAD(&data->video_info_list); 31793d0407baSopenharmony_ci 31803d0407baSopenharmony_ci ret = rockchip_dmcfreq_get_event(data); 31813d0407baSopenharmony_ci if (ret) 31823d0407baSopenharmony_ci return ret; 31833d0407baSopenharmony_ci 31843d0407baSopenharmony_ci ret = rockchip_dmcfreq_power_control(data); 31853d0407baSopenharmony_ci if (ret) 31863d0407baSopenharmony_ci return ret; 31873d0407baSopenharmony_ci 31883d0407baSopenharmony_ci ret = rockchip_init_opp_table(dev, NULL, "ddr_leakage", "center"); 31893d0407baSopenharmony_ci if (ret) 31903d0407baSopenharmony_ci return ret; 31913d0407baSopenharmony_ci 31923d0407baSopenharmony_ci ret = rockchip_dmcfreq_dmc_init(pdev, data); 31933d0407baSopenharmony_ci if (ret) 31943d0407baSopenharmony_ci return ret; 31953d0407baSopenharmony_ci 31963d0407baSopenharmony_ci rockchip_dmcfreq_parse_dt(data); 31973d0407baSopenharmony_ci if (!data->system_status_en && !data->info.auto_freq_en) { 31983d0407baSopenharmony_ci dev_info(dev, "don't add devfreq feature\n"); 31993d0407baSopenharmony_ci return rockchip_dmcfreq_set_volt_only(data); 32003d0407baSopenharmony_ci } 32013d0407baSopenharmony_ci 32023d0407baSopenharmony_ci cpu_latency_qos_add_request(&pm_qos, PM_QOS_DEFAULT_VALUE); 32033d0407baSopenharmony_ci platform_set_drvdata(pdev, data); 32043d0407baSopenharmony_ci 32053d0407baSopenharmony_ci ret = devfreq_add_governor(&devfreq_dmc_ondemand); 32063d0407baSopenharmony_ci if (ret) 32073d0407baSopenharmony_ci return ret; 32083d0407baSopenharmony_ci ret = rockchip_dmcfreq_enable_event(data); 32093d0407baSopenharmony_ci if (ret) 32103d0407baSopenharmony_ci return ret; 32113d0407baSopenharmony_ci ret = rockchip_dmcfreq_add_devfreq(data); 32123d0407baSopenharmony_ci if (ret) { 32133d0407baSopenharmony_ci rockchip_dmcfreq_disable_event(data); 32143d0407baSopenharmony_ci return ret; 32153d0407baSopenharmony_ci } 32163d0407baSopenharmony_ci 32173d0407baSopenharmony_ci rockchip_dmcfreq_register_notifier(data); 32183d0407baSopenharmony_ci rockchip_dmcfreq_add_interface(data); 32193d0407baSopenharmony_ci rockchip_dmcfreq_boost_init(data); 32203d0407baSopenharmony_ci rockchip_dmcfreq_vop_bandwidth_init(&data->info); 32213d0407baSopenharmony_ci rockchip_dmcfreq_register_cooling_device(data); 32223d0407baSopenharmony_ci 32233d0407baSopenharmony_ci rockchip_set_system_status(SYS_STATUS_NORMAL); 32243d0407baSopenharmony_ci 32253d0407baSopenharmony_ci return 0; 32263d0407baSopenharmony_ci} 32273d0407baSopenharmony_ci 32283d0407baSopenharmony_cistatic __maybe_unused int rockchip_dmcfreq_suspend(struct device *dev) 32293d0407baSopenharmony_ci{ 32303d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq = dev_get_drvdata(dev); 32313d0407baSopenharmony_ci int ret = 0; 32323d0407baSopenharmony_ci 32333d0407baSopenharmony_ci if (!dmcfreq) 32343d0407baSopenharmony_ci return 0; 32353d0407baSopenharmony_ci 32363d0407baSopenharmony_ci ret = rockchip_dmcfreq_disable_event(dmcfreq); 32373d0407baSopenharmony_ci if (ret) 32383d0407baSopenharmony_ci return ret; 32393d0407baSopenharmony_ci 32403d0407baSopenharmony_ci ret = devfreq_suspend_device(dmcfreq->info.devfreq); 32413d0407baSopenharmony_ci if (ret < 0) { 32423d0407baSopenharmony_ci dev_err(dev, "failed to suspend the devfreq devices\n"); 32433d0407baSopenharmony_ci return ret; 32443d0407baSopenharmony_ci } 32453d0407baSopenharmony_ci 32463d0407baSopenharmony_ci return 0; 32473d0407baSopenharmony_ci} 32483d0407baSopenharmony_ci 32493d0407baSopenharmony_cistatic __maybe_unused int rockchip_dmcfreq_resume(struct device *dev) 32503d0407baSopenharmony_ci{ 32513d0407baSopenharmony_ci struct rockchip_dmcfreq *dmcfreq = dev_get_drvdata(dev); 32523d0407baSopenharmony_ci int ret = 0; 32533d0407baSopenharmony_ci 32543d0407baSopenharmony_ci if (!dmcfreq) 32553d0407baSopenharmony_ci return 0; 32563d0407baSopenharmony_ci 32573d0407baSopenharmony_ci ret = rockchip_dmcfreq_enable_event(dmcfreq); 32583d0407baSopenharmony_ci if (ret) 32593d0407baSopenharmony_ci return ret; 32603d0407baSopenharmony_ci 32613d0407baSopenharmony_ci ret = devfreq_resume_device(dmcfreq->info.devfreq); 32623d0407baSopenharmony_ci if (ret < 0) { 32633d0407baSopenharmony_ci dev_err(dev, "failed to resume the devfreq devices\n"); 32643d0407baSopenharmony_ci return ret; 32653d0407baSopenharmony_ci } 32663d0407baSopenharmony_ci return ret; 32673d0407baSopenharmony_ci} 32683d0407baSopenharmony_ci 32693d0407baSopenharmony_cistatic SIMPLE_DEV_PM_OPS(rockchip_dmcfreq_pm, rockchip_dmcfreq_suspend, 32703d0407baSopenharmony_ci rockchip_dmcfreq_resume); 32713d0407baSopenharmony_cistatic struct platform_driver rockchip_dmcfreq_driver = { 32723d0407baSopenharmony_ci .probe = rockchip_dmcfreq_probe, 32733d0407baSopenharmony_ci .driver = { 32743d0407baSopenharmony_ci .name = "rockchip-dmc", 32753d0407baSopenharmony_ci .pm = &rockchip_dmcfreq_pm, 32763d0407baSopenharmony_ci .of_match_table = rockchip_dmcfreq_of_match, 32773d0407baSopenharmony_ci }, 32783d0407baSopenharmony_ci}; 32793d0407baSopenharmony_cimodule_platform_driver(rockchip_dmcfreq_driver); 32803d0407baSopenharmony_ci 32813d0407baSopenharmony_ciMODULE_AUTHOR("Finley Xiao <finley.xiao@rock-chips.com>"); 32823d0407baSopenharmony_ciMODULE_DESCRIPTION("rockchip dmcfreq driver with devfreq framework"); 32833d0407baSopenharmony_ciMODULE_LICENSE("GPL v2"); 3284