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