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