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