1991 lines
52 KiB
C
1991 lines
52 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
/*
|
|
* Copyright (c) 2019 MediaTek Inc.
|
|
*/
|
|
|
|
#include <linux/device.h>
|
|
#include <linux/err.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/soc/mediatek/mtk-pm-qos.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/mutex.h>
|
|
#include <mt-plat/upmu_common.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of_address.h>
|
|
#include <linux/of_irq.h>
|
|
#include <linux/of_reserved_mem.h>
|
|
#ifdef CONFIG_MTK_DEVINFO
|
|
#include <linux/nvmem-consumer.h>
|
|
#include <linux/slab.h>
|
|
#endif
|
|
#include <mtk_qos_sram.h>
|
|
#include <linux/delay.h>
|
|
#include "vpu_reg.h"
|
|
|
|
|
|
//#include "governor.h"
|
|
|
|
#include <mt-plat/aee.h>
|
|
#include <spm/mtk_spm.h>
|
|
|
|
#include "apu_dvfs.h"
|
|
#include "vpu_cmn.h"
|
|
|
|
#include <linux/regulator/consumer.h>
|
|
|
|
#define CCF_GET_CKGEN_READY (1)
|
|
|
|
static uint32_t g_efuse_ptpod;
|
|
static inline uint32_t get_devinfo_with_index(int idx)
|
|
{
|
|
return g_efuse_ptpod;
|
|
}
|
|
|
|
/*regulator id*/
|
|
static struct regulator *vvpu_reg_id;
|
|
static struct regulator *vmdla_reg_id;
|
|
static struct regulator *vcore_reg_id;
|
|
static struct regulator *vsram_reg_id;
|
|
|
|
|
|
static bool vvpu_DVFS_is_paused_by_ptpod;
|
|
static bool vmdla_DVFS_is_paused_by_ptpod;
|
|
static bool ready_for_ptpod_check;
|
|
static bool ptpod_enabled;
|
|
|
|
|
|
static bool vpu_opp_ready;
|
|
static bool mdla_opp_ready;
|
|
#define VPU_DVFS_OPP_MAX (16)
|
|
#define MDLA_DVFS_OPP_MAX (16)
|
|
|
|
static int apu_power_count;
|
|
static int vvpu_count;
|
|
static int vmdla_count;
|
|
|
|
|
|
#define VPU_DVFS_FREQ0 (700000) /* KHz */
|
|
#define VPU_DVFS_FREQ1 (624000) /* KHz */
|
|
#define VPU_DVFS_FREQ2 (606000) /* KHz */
|
|
#define VPU_DVFS_FREQ3 (594000) /* KHz */
|
|
#define VPU_DVFS_FREQ4 (560000) /* KHz */
|
|
#define VPU_DVFS_FREQ5 (525000) /* KHz */
|
|
#define VPU_DVFS_FREQ6 (450000) /* KHz */
|
|
#define VPU_DVFS_FREQ7 (416000) /* KHz */
|
|
#define VPU_DVFS_FREQ8 (364000) /* KHz */
|
|
#define VPU_DVFS_FREQ9 (312000) /* KHz */
|
|
#define VPU_DVFS_FREQ10 (273000) /* KHz */
|
|
#define VPU_DVFS_FREQ11 (208000) /* KHz */
|
|
#define VPU_DVFS_FREQ12 (137000) /* KHz */
|
|
#define VPU_DVFS_FREQ13 (104000) /* KHz */
|
|
#define VPU_DVFS_FREQ14 (52000) /* KHz */
|
|
#define VPU_DVFS_FREQ15 (26000) /* KHz */
|
|
|
|
|
|
#ifdef AGING_MARGIN
|
|
#define VPU_DVFS_VOLT0 (81250) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT1 (81250) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT2 (81250) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT3 (81250) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT4 (81250) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT5 (71250) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT6 (71250) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT7 (71250) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT8 (71250) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT9 (63750) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT10 (63750) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT11 (63750) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT12 (63750) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT13 (63750) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT14 (63750) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT15 (63750) /* mV x 100 */
|
|
#else
|
|
#define VPU_DVFS_VOLT0 (82500) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT1 (82500) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT2 (82500) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT3 (82500) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT4 (82500) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT5 (72500) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT6 (72500) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT7 (72500) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT8 (72500) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT9 (65000) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT10 (65000) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT11 (65000) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT12 (65000) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT13 (65000) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT14 (65000) /* mV x 100 */
|
|
#define VPU_DVFS_VOLT15 (65000) /* mV x 100 */
|
|
#endif
|
|
|
|
#define MDLA_DVFS_FREQ0 (788000) /* KHz */
|
|
#define MDLA_DVFS_FREQ1 (700000) /* KHz */
|
|
#define MDLA_DVFS_FREQ2 (624000) /* KHz */
|
|
#define MDLA_DVFS_FREQ3 (606000) /* KHz */
|
|
#define MDLA_DVFS_FREQ4 (594000) /* KHz */
|
|
#define MDLA_DVFS_FREQ5 (546000) /* KHz */
|
|
#define MDLA_DVFS_FREQ6 (525000) /* KHz */
|
|
#define MDLA_DVFS_FREQ7 (450000) /* KHz */
|
|
#define MDLA_DVFS_FREQ8 (416000) /* KHz */
|
|
#define MDLA_DVFS_FREQ9 (364000) /* KHz */
|
|
#define MDLA_DVFS_FREQ10 (312000) /* KHz */
|
|
#define MDLA_DVFS_FREQ11 (273000) /* KHz */
|
|
#define MDLA_DVFS_FREQ12 (208000) /* KHz */
|
|
#define MDLA_DVFS_FREQ13 (137000) /* KHz */
|
|
#define MDLA_DVFS_FREQ14 (52000) /* KHz */
|
|
#define MDLA_DVFS_FREQ15 (26000) /* KHz */
|
|
|
|
#ifdef AGING_MARGIN
|
|
#define MDLA_DVFS_VOLT0 (81500) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT1 (81500) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT2 (81500) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT3 (71500) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT4 (71500) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT5 (71500) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT6 (71500) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT7 (71500) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT8 (71500) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT9 (64000) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT10 (64000) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT11 (64000) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT12 (64000) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT13 (64000) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT14 (64000) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT15 (64000) /* mV x 100 */
|
|
#else
|
|
#define MDLA_DVFS_VOLT0 (82500) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT1 (82500) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT2 (82500) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT3 (72500) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT4 (72500) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT5 (72500) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT6 (72500) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT7 (72500) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT8 (72500) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT9 (65000) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT10 (65000) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT11 (65000) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT12 (65000) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT13 (65000) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT14 (65000) /* mV x 100 */
|
|
#define MDLA_DVFS_VOLT15 (65000) /* mV x 100 */
|
|
#endif
|
|
|
|
#define VPUOP(khz, volt, idx) \
|
|
{ \
|
|
.vpufreq_khz = khz, \
|
|
.vpufreq_volt = volt, \
|
|
.vpufreq_idx = idx, \
|
|
}
|
|
#define MDLAOP(khz, volt, idx) \
|
|
{ \
|
|
.mdlafreq_khz = khz, \
|
|
.mdlafreq_volt = volt, \
|
|
.mdlafreq_idx = idx, \
|
|
}
|
|
#define VPU_PTP(ptp_count) \
|
|
{ \
|
|
.vpu_ptp_count = ptp_count, \
|
|
}
|
|
#define MDLA_PTP(ptp_count) \
|
|
{ \
|
|
.mdla_ptp_count = ptp_count, \
|
|
}
|
|
|
|
|
|
static struct vpu_opp_table_info vpu_opp_table_default[] = {
|
|
VPUOP(VPU_DVFS_FREQ0, VPU_DVFS_VOLT0, 0),
|
|
VPUOP(VPU_DVFS_FREQ1, VPU_DVFS_VOLT1, 1),
|
|
VPUOP(VPU_DVFS_FREQ2, VPU_DVFS_VOLT2, 2),
|
|
VPUOP(VPU_DVFS_FREQ3, VPU_DVFS_VOLT3, 3),
|
|
VPUOP(VPU_DVFS_FREQ4, VPU_DVFS_VOLT4, 4),
|
|
VPUOP(VPU_DVFS_FREQ5, VPU_DVFS_VOLT5, 5),
|
|
VPUOP(VPU_DVFS_FREQ6, VPU_DVFS_VOLT6, 6),
|
|
VPUOP(VPU_DVFS_FREQ7, VPU_DVFS_VOLT7, 7),
|
|
VPUOP(VPU_DVFS_FREQ8, VPU_DVFS_VOLT8, 8),
|
|
VPUOP(VPU_DVFS_FREQ9, VPU_DVFS_VOLT9, 9),
|
|
VPUOP(VPU_DVFS_FREQ10, VPU_DVFS_VOLT10, 10),
|
|
VPUOP(VPU_DVFS_FREQ11, VPU_DVFS_VOLT11, 11),
|
|
VPUOP(VPU_DVFS_FREQ12, VPU_DVFS_VOLT12, 12),
|
|
VPUOP(VPU_DVFS_FREQ13, VPU_DVFS_VOLT13, 13),
|
|
VPUOP(VPU_DVFS_FREQ14, VPU_DVFS_VOLT14, 14),
|
|
VPUOP(VPU_DVFS_FREQ15, VPU_DVFS_VOLT15, 15),
|
|
};
|
|
|
|
static struct vpu_opp_table_info vpu_opp_table[] = {
|
|
VPUOP(VPU_DVFS_FREQ0, VPU_DVFS_VOLT0, 0),
|
|
VPUOP(VPU_DVFS_FREQ1, VPU_DVFS_VOLT1, 1),
|
|
VPUOP(VPU_DVFS_FREQ2, VPU_DVFS_VOLT2, 2),
|
|
VPUOP(VPU_DVFS_FREQ3, VPU_DVFS_VOLT3, 3),
|
|
VPUOP(VPU_DVFS_FREQ4, VPU_DVFS_VOLT4, 4),
|
|
VPUOP(VPU_DVFS_FREQ5, VPU_DVFS_VOLT5, 5),
|
|
VPUOP(VPU_DVFS_FREQ6, VPU_DVFS_VOLT6, 6),
|
|
VPUOP(VPU_DVFS_FREQ7, VPU_DVFS_VOLT7, 7),
|
|
VPUOP(VPU_DVFS_FREQ8, VPU_DVFS_VOLT8, 8),
|
|
VPUOP(VPU_DVFS_FREQ9, VPU_DVFS_VOLT9, 9),
|
|
VPUOP(VPU_DVFS_FREQ10, VPU_DVFS_VOLT10, 10),
|
|
VPUOP(VPU_DVFS_FREQ11, VPU_DVFS_VOLT11, 11),
|
|
VPUOP(VPU_DVFS_FREQ12, VPU_DVFS_VOLT12, 12),
|
|
VPUOP(VPU_DVFS_FREQ13, VPU_DVFS_VOLT13, 13),
|
|
VPUOP(VPU_DVFS_FREQ14, VPU_DVFS_VOLT14, 14),
|
|
VPUOP(VPU_DVFS_FREQ15, VPU_DVFS_VOLT15, 15),
|
|
};
|
|
|
|
static struct mdla_opp_table_info mdla_opp_table_default[] = {
|
|
MDLAOP(MDLA_DVFS_FREQ0, MDLA_DVFS_VOLT0, 0),
|
|
MDLAOP(MDLA_DVFS_FREQ1, MDLA_DVFS_VOLT1, 1),
|
|
MDLAOP(MDLA_DVFS_FREQ2, MDLA_DVFS_VOLT2, 2),
|
|
MDLAOP(MDLA_DVFS_FREQ3, MDLA_DVFS_VOLT3, 3),
|
|
MDLAOP(MDLA_DVFS_FREQ4, MDLA_DVFS_VOLT4, 4),
|
|
MDLAOP(MDLA_DVFS_FREQ5, MDLA_DVFS_VOLT5, 5),
|
|
MDLAOP(MDLA_DVFS_FREQ6, MDLA_DVFS_VOLT6, 6),
|
|
MDLAOP(MDLA_DVFS_FREQ7, MDLA_DVFS_VOLT7, 7),
|
|
MDLAOP(MDLA_DVFS_FREQ8, MDLA_DVFS_VOLT8, 8),
|
|
MDLAOP(MDLA_DVFS_FREQ9, MDLA_DVFS_VOLT9, 9),
|
|
MDLAOP(MDLA_DVFS_FREQ10, MDLA_DVFS_VOLT10, 10),
|
|
MDLAOP(MDLA_DVFS_FREQ11, MDLA_DVFS_VOLT11, 11),
|
|
MDLAOP(MDLA_DVFS_FREQ12, MDLA_DVFS_VOLT12, 12),
|
|
MDLAOP(MDLA_DVFS_FREQ13, MDLA_DVFS_VOLT13, 13),
|
|
MDLAOP(MDLA_DVFS_FREQ14, MDLA_DVFS_VOLT14, 14),
|
|
MDLAOP(MDLA_DVFS_FREQ15, MDLA_DVFS_VOLT15, 15),
|
|
};
|
|
|
|
static struct mdla_opp_table_info mdla_opp_table[] = {
|
|
MDLAOP(MDLA_DVFS_FREQ0, MDLA_DVFS_VOLT0, 0),
|
|
MDLAOP(MDLA_DVFS_FREQ1, MDLA_DVFS_VOLT1, 1),
|
|
MDLAOP(MDLA_DVFS_FREQ2, MDLA_DVFS_VOLT2, 2),
|
|
MDLAOP(MDLA_DVFS_FREQ3, MDLA_DVFS_VOLT3, 3),
|
|
MDLAOP(MDLA_DVFS_FREQ4, MDLA_DVFS_VOLT4, 4),
|
|
MDLAOP(MDLA_DVFS_FREQ5, MDLA_DVFS_VOLT5, 5),
|
|
MDLAOP(MDLA_DVFS_FREQ6, MDLA_DVFS_VOLT6, 6),
|
|
MDLAOP(MDLA_DVFS_FREQ7, MDLA_DVFS_VOLT7, 7),
|
|
MDLAOP(MDLA_DVFS_FREQ8, MDLA_DVFS_VOLT8, 8),
|
|
MDLAOP(MDLA_DVFS_FREQ9, MDLA_DVFS_VOLT9, 9),
|
|
MDLAOP(MDLA_DVFS_FREQ10, MDLA_DVFS_VOLT10, 10),
|
|
MDLAOP(MDLA_DVFS_FREQ11, MDLA_DVFS_VOLT11, 11),
|
|
MDLAOP(MDLA_DVFS_FREQ12, MDLA_DVFS_VOLT12, 12),
|
|
MDLAOP(MDLA_DVFS_FREQ13, MDLA_DVFS_VOLT13, 13),
|
|
MDLAOP(MDLA_DVFS_FREQ14, MDLA_DVFS_VOLT14, 14),
|
|
MDLAOP(MDLA_DVFS_FREQ15, MDLA_DVFS_VOLT15, 15),
|
|
};
|
|
static struct vpu_ptp_count_info vpu_ptp_count_table[] = {
|
|
VPU_PTP(0),
|
|
VPU_PTP(0),
|
|
VPU_PTP(0),
|
|
VPU_PTP(0),
|
|
};
|
|
static struct mdla_ptp_count_info mdla_ptp_count_table[] = {
|
|
MDLA_PTP(0),
|
|
MDLA_PTP(0),
|
|
MDLA_PTP(0),
|
|
MDLA_PTP(0),
|
|
};
|
|
|
|
|
|
//#define APU_CONN_BASE (0x19000000)
|
|
|
|
#define APU_CONN_QOS_CTRL0 (0x170)
|
|
#define APU_CONN_QOS_CTRL1 (0x174)
|
|
#define APU_CONN_QOS_CTRL2 (0x178)
|
|
#define APU_CONN_QA_CTRL0 (0x17C)
|
|
#define APU_CONN_QA_CTRL1 (0x180)
|
|
#define APU_CONN_QA_CTRL2 (0x184)
|
|
#define APU_CONN_QA_CTRL3 (0x188)
|
|
#define APU_CONN_QA_CTRL4 (0x18C)
|
|
#define APU_CONN_QA_CTRL5 (0x190)
|
|
#define APU_CONN_QA_CTRL6 (0x194)
|
|
#define APU_CONN_QA_CTRL7 (0x198)
|
|
#define APU_CONN_QA_CTRL8 (0x19C)
|
|
#define APU_CONN_QA_CTRL9 (0x1A0)
|
|
#define APU_CONN_QA_CTRL10 (0x1A4)
|
|
#define APU_CONN_QA_CTRL11 (0x1A8)
|
|
#define APU_CONN_QA_CTRL12 (0x1AC)
|
|
#define APU_CONN_QA_CTRL13 (0x1B0)
|
|
#define APU_CONN_QA_CTRL14 (0x1B4)
|
|
#define APU_CONN_QA_CTRL15 (0x1B8)
|
|
#define APU_CONN_QA_CTRL16 (0x1BC)
|
|
#define APU_CONN_QA_CTRL17 (0x1C0)
|
|
#define APU_CONN_QA_CTRL18 (0x1C4)
|
|
#define APU_CONN_QB_CTRL0 (0x1C8)
|
|
#define APU_CONN_QB_CTRL1 (0x1CC)
|
|
#define APU_CONN_QB_CTRL2 (0x1D0)
|
|
#define APU_CONN_QB_CTRL3 (0x1D4)
|
|
#define APU_CONN_QB_CTRL4 (0x1D8)
|
|
#define APU_CONN_QB_CTRL5 (0x1DC)
|
|
#define APU_CONN_QB_CTRL6 (0x1E0)
|
|
#define APU_CONN_QB_CTRL7 (0x1E4)
|
|
#define APU_CONN_QB_CTRL8 (0x1E8)
|
|
#define APU_CONN_QB_CTRL9 (0x1EC)
|
|
#define APU_CONN_QB_CTRL10 (0x1F0)
|
|
#define APU_CONN_QB_CTRL11 (0x1F4)
|
|
#define APU_CONN_QB_CTRL12 (0x1F8)
|
|
#define APU_CONN_QB_CTRL13 (0x1FC)
|
|
#define APU_CONN_QB_CTRL14 (0x200)
|
|
#define APU_CONN_QB_CTRL15 (0x204)
|
|
#define APU_CONN_QB_CTRL16 (0x208)
|
|
#define APU_CONN_QB_CTRL17 (0x20C)
|
|
#define APU_CONN_QB_CTRL18 (0x210)
|
|
#define APU_CONN_QC_CTRL0 (0x214)
|
|
#define APU_CONN_QC_CTRL1 (0x218)
|
|
#define APU_CONN_QC_CTRL2 (0x21C)
|
|
#define APU_CONN_QC_CTRL3 (0x220)
|
|
#define APU_CONN_QC_CTRL4 (0x224)
|
|
#define APU_CONN_QC_CTRL5 (0x228)
|
|
#define APU_CONN_QC_CTRL6 (0x22C)
|
|
#define APU_CONN_QC_CTRL7 (0x230)
|
|
#define APU_CONN_QC_CTRL8 (0x234)
|
|
#define APU_CONN_QC_CTRL9 (0x238)
|
|
#define APU_CONN_QC_CTRL10 (0x23C)
|
|
#define APU_CONN_QC_CTRL11 (0x240)
|
|
#define APU_CONN_QC_CTRL12 (0x244)
|
|
#define APU_CONN_QC_CTRL13 (0x248)
|
|
#define APU_CONN_QC_CTRL14 (0x24C)
|
|
#define APU_CONN_QC_CTRL15 (0x250)
|
|
#define APU_CONN_QC_CTRL16 (0x254)
|
|
#define APU_CONN_QC_CTRL17 (0x258)
|
|
#define APU_CONN_QC_CTRL18 (0x25C)
|
|
#define APU_CONN_QC1_CTRL0 (0x260)
|
|
#define APU_CONN_QC1_CTRL1 (0x264)
|
|
#define APU_CONN_QC1_CTRL2 (0x268)
|
|
#define APU_CONN_QC1_CTRL3 (0x26C)
|
|
#define APU_CONN_QC1_CTRL4 (0x270)
|
|
#define APU_CONN_QC1_CTRL5 (0x274)
|
|
#define APU_CONN_QC1_CTRL6 (0x278)
|
|
#define APU_CONN_QC1_CTRL7 (0x27C)
|
|
#define APU_CONN_QC1_CTRL8 (0x280)
|
|
#define APU_CONN_QC1_CTRL9 (0x284)
|
|
#define APU_CONN_QC1_CTRL10 (0x288)
|
|
#define APU_CONN_QC1_CTRL11 (0x28C)
|
|
#define APU_CONN_QC1_CTRL12 (0x290)
|
|
#define APU_CONN_QC1_CTRL13 (0x294)
|
|
#define APU_CONN_QC1_CTRL14 (0x298)
|
|
#define APU_CONN_QC1_CTRL15 (0x29C)
|
|
#define APU_CONN_QC1_CTRL16 (0x2A0)
|
|
#define APU_CONN_QC1_CTRL17 (0x2A4)
|
|
#define APU_CONN_QC1_CTRL18 (0x2A8)
|
|
|
|
unsigned long apu_syscfg_base;
|
|
|
|
static struct apu_dvfs *dvfs;
|
|
int vvpu_orig_opp;
|
|
int vmdla_orig_opp;
|
|
int vvpu0_cpe_result;
|
|
int vvpu1_cpe_result;
|
|
int vvpu2_cpe_result;
|
|
int vmdla0_cpe_result;
|
|
int vmdla1_cpe_result;
|
|
int vmdla2_cpe_result;
|
|
|
|
|
|
static DEFINE_MUTEX(vpu_opp_lock);
|
|
static DEFINE_MUTEX(mdla_opp_lock);
|
|
static DEFINE_MUTEX(apu_power_count_lock);
|
|
static DEFINE_MUTEX(power_check_lock);
|
|
|
|
|
|
static void get_vvpu_from_efuse(void);
|
|
static void get_vmdla_from_efuse(void);
|
|
static int vmdla_vbin(int opp);
|
|
static int vvpu_vbin(int opp);
|
|
|
|
|
|
|
|
|
|
static void dvfs_get_timestamp(char *p)
|
|
{
|
|
int ret = 0;
|
|
|
|
u64 sec = local_clock();
|
|
u64 usec = do_div(sec, 1000000000);
|
|
|
|
do_div(usec, 1000000);
|
|
ret = sprintf(p, "%llu.%llu", sec, usec);
|
|
|
|
if (ret < 0)
|
|
LOG_ERR("%s sprintf fail\n", __func__);
|
|
|
|
}
|
|
|
|
void dump_opp_table(void)
|
|
{
|
|
int i;
|
|
|
|
LOG_DBG("%s start\n", __func__);
|
|
for (i = 0; i < VPU_DVFS_OPP_MAX; i++) {
|
|
LOG_INF("vpu opp:%d, vol:%d, freq:%d\n", i
|
|
, vpu_opp_table[i].vpufreq_volt
|
|
, vpu_opp_table[i].vpufreq_khz);
|
|
LOG_INF("mdla opp:%d, vol:%d, freq:%d\n", i
|
|
, mdla_opp_table[i].mdlafreq_volt
|
|
, mdla_opp_table[i].mdlafreq_khz);
|
|
}
|
|
LOG_DBG("%s end\n", __func__);
|
|
}
|
|
void dump_ptp_count(void)
|
|
{
|
|
int i;
|
|
|
|
LOG_DBG("%s start\n", __func__);
|
|
for (i = 0; i < 4; i++) {
|
|
LOG_INF("vvpu id:%d, ptp cnt:%d\n", i
|
|
, vpu_ptp_count_table[i].vpu_ptp_count);
|
|
}
|
|
for (i = 0; i < 4; i++) {
|
|
LOG_INF("vmdla id:%d, ptp cnt:%d\n", i
|
|
, mdla_ptp_count_table[i].mdla_ptp_count);
|
|
}
|
|
LOG_DBG("%s end\n", __func__);
|
|
}
|
|
|
|
void apu_get_power_info(void)
|
|
{
|
|
int vvpu = 0;
|
|
int vmdla = 0;
|
|
int vcore = 0;
|
|
int vsram = 0;
|
|
int dsp_freq = 0;
|
|
int dsp1_freq = 0;
|
|
int dsp2_freq = 0;
|
|
int dsp3_freq = 0;
|
|
int ipuif_freq = 0;
|
|
#if CCF_GET_CKGEN_READY
|
|
int temp_freq = 0;
|
|
#endif
|
|
mutex_lock(&power_check_lock);
|
|
|
|
#if CCF_GET_CKGEN_READY
|
|
dsp_freq = mt_get_ckgen_freq(10);
|
|
if (dsp_freq == 0)
|
|
temp_freq = mt_get_ckgen_freq(1);
|
|
dsp1_freq = mt_get_ckgen_freq(11);
|
|
if (dsp1_freq == 0)
|
|
temp_freq = mt_get_ckgen_freq(1);
|
|
dsp2_freq = mt_get_ckgen_freq(12);
|
|
if (dsp2_freq == 0)
|
|
temp_freq = mt_get_ckgen_freq(1);
|
|
dsp3_freq = mt_get_ckgen_freq(13);
|
|
if (dsp3_freq == 0)
|
|
temp_freq = mt_get_ckgen_freq(1);
|
|
ipuif_freq = mt_get_ckgen_freq(14);
|
|
if (ipuif_freq == 0)
|
|
temp_freq = mt_get_ckgen_freq(1);
|
|
check_vpu_clk_sts();
|
|
#endif
|
|
if (vmdla_reg_id)
|
|
vmdla = regulator_get_voltage(vmdla_reg_id);
|
|
|
|
if (vvpu_reg_id)
|
|
vvpu = regulator_get_voltage(vvpu_reg_id);
|
|
|
|
if (vcore_reg_id)
|
|
vcore = regulator_get_voltage(vcore_reg_id);
|
|
|
|
if (vsram_reg_id)
|
|
vsram = regulator_get_voltage(vsram_reg_id);
|
|
|
|
LOG_ERR("vvpu=%d, vmdla=%d, vcore=%d, vsram=%d\n",
|
|
vvpu, vmdla, vcore, vsram);
|
|
if (vvpu < 700000) {
|
|
if ((dsp_freq >= 364000) || (ipuif_freq >= 364000)) {
|
|
LOG_ERR("freq check fail\n");
|
|
LOG_ERR("dsp_freq = %d\n", dsp_freq);
|
|
LOG_ERR("dsp1_freq = %d\n", dsp1_freq);
|
|
LOG_ERR("dsp2_freq = %d\n", dsp2_freq);
|
|
LOG_ERR("dsp3_freq = %d\n", dsp3_freq);
|
|
LOG_ERR("ipuif_freq = %d\n", ipuif_freq);
|
|
LOG_ERR("vvpu=%d, vmdla=%d, vcore=%d\n", vvpu, vmdla, vcore);
|
|
aee_kernel_warning("freq check", "%s: failed.", __func__);
|
|
}
|
|
}
|
|
mutex_unlock(&power_check_lock);
|
|
}
|
|
EXPORT_SYMBOL(apu_get_power_info);
|
|
|
|
/************************************************
|
|
* return current Vvpu voltage mV*100
|
|
*************************************************/
|
|
bool vvpu_vmdla_vcore_checker(void)
|
|
{
|
|
int ret = 0;
|
|
int vvpu = 0;
|
|
int vmdla = 0;
|
|
int vcore = 0;
|
|
int vvpu_vmdla_diff = 0;
|
|
int vcore_vvpu_diff = 0;
|
|
int vcore_vmdla_diff = 0;
|
|
|
|
mutex_lock(&power_check_lock);
|
|
|
|
vvpu_vmdla_diff = 825000 - 650000;
|
|
vcore_vvpu_diff = 825000 - 650000;
|
|
vcore_vmdla_diff = 825000 - 650000;
|
|
if (vmdla_reg_id)
|
|
vmdla = regulator_get_voltage(vmdla_reg_id);
|
|
|
|
if (vvpu_reg_id)
|
|
vvpu = regulator_get_voltage(vvpu_reg_id);
|
|
|
|
if (vcore_reg_id)
|
|
vcore = regulator_get_voltage(vcore_reg_id);
|
|
|
|
if ((vvpu < vmdla) && ((vmdla - vvpu) >= vvpu_vmdla_diff)
|
|
&& (vvpu != 550000)) {
|
|
ret = 1;
|
|
LOG_ERR("vvpu_vmdla_diff fail\n");
|
|
}
|
|
if ((vvpu > vcore) && ((vvpu - vcore) >= vcore_vvpu_diff)) {
|
|
ret = 1;
|
|
LOG_ERR("vcore_vvpu_diff fail\n");
|
|
}
|
|
if ((vmdla > vcore) && ((vmdla - vcore) >= vcore_vmdla_diff)) {
|
|
ret = 1;
|
|
LOG_ERR("vcore_vmdla_diff fail\n");
|
|
}
|
|
LOG_DVFS("vvpu=%d, vmdla=%d, vcore=%d\n", vvpu, vmdla, vcore);
|
|
LOG_DVFS("get vvpu=%d, vmdla=%d, vcore=%d\n",
|
|
regulator_get_voltage(vvpu_reg_id),
|
|
regulator_get_voltage(vmdla_reg_id),
|
|
regulator_get_voltage(vcore_reg_id));
|
|
if (ret) {
|
|
LOG_INF("vvpuopp:%d, vmdlaopp:%d,\n",
|
|
vvpu_orig_opp, vmdla_orig_opp);
|
|
LOG_INF("vvpu=%d, vmdla=%d, vcore=%d\n", vvpu, vmdla, vcore);
|
|
LOG_INF("get vvpu=%d, vmdla=%d, vcore=%d\n",
|
|
regulator_get_voltage(vvpu_reg_id),
|
|
regulator_get_voltage(vmdla_reg_id),
|
|
regulator_get_voltage(vcore_reg_id));
|
|
aee_kernel_warning("dvfs", "%s: failed.", __func__);
|
|
}
|
|
mutex_unlock(&power_check_lock);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(vvpu_vmdla_vcore_checker);
|
|
|
|
unsigned int vvpu_get_cur_volt(void)
|
|
{
|
|
return (regulator_get_voltage(vvpu_reg_id)/10);
|
|
}
|
|
EXPORT_SYMBOL(vvpu_get_cur_volt);
|
|
|
|
unsigned int vmdla_get_cur_volt(void)
|
|
{
|
|
return (regulator_get_voltage(vmdla_reg_id)/10);
|
|
}
|
|
EXPORT_SYMBOL(vmdla_get_cur_volt);
|
|
|
|
unsigned int vvpu_update_volt(unsigned int pmic_volt[], unsigned int array_size)
|
|
{
|
|
int i; /* , idx; */
|
|
|
|
mutex_lock(&vpu_opp_lock);
|
|
|
|
for (i = 0; i < array_size; i++) {
|
|
vpu_opp_table[i].vpufreq_volt = pmic_volt[i];
|
|
LOG_DBG("%s opp:%d vol:%d", __func__, i, pmic_volt[i]);
|
|
}
|
|
dump_opp_table();
|
|
|
|
vpu_opp_ready = true;
|
|
//
|
|
mutex_unlock(&vpu_opp_lock);
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(vvpu_update_volt);
|
|
|
|
unsigned int vmdla_update_volt(unsigned int pmic_volt[],
|
|
unsigned int array_size)
|
|
{
|
|
int i;
|
|
|
|
mutex_lock(&mdla_opp_lock);
|
|
|
|
for (i = 0; i < array_size; i++) {
|
|
mdla_opp_table[i].mdlafreq_volt = pmic_volt[i];
|
|
LOG_DBG("%s opp:%d vol:%d", __func__, i, pmic_volt[i]);
|
|
}
|
|
dump_opp_table();
|
|
|
|
mdla_opp_ready = true;
|
|
|
|
mutex_unlock(&mdla_opp_lock);
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(vmdla_update_volt);
|
|
unsigned int vvpu_update_ptp_count(unsigned int ptp_count[],
|
|
unsigned int array_size)
|
|
{
|
|
int i; /* , idx; */
|
|
|
|
mutex_lock(&vpu_opp_lock);
|
|
|
|
for (i = 0; i < array_size; i++) {
|
|
vpu_ptp_count_table[i].vpu_ptp_count = ptp_count[i];
|
|
LOG_INF("%s id:%d, ptp cnt:0x%x\n", __func__, i, ptp_count[i]);
|
|
}
|
|
//
|
|
LOG_INF("[CPE]:VPU Det_Count: %d, %d, %d, %d\n",
|
|
vpu_ptp_count_table[0].vpu_ptp_count,
|
|
vpu_ptp_count_table[1].vpu_ptp_count,
|
|
vpu_ptp_count_table[2].vpu_ptp_count,
|
|
vpu_ptp_count_table[3].vpu_ptp_count);
|
|
|
|
get_vvpu_from_efuse();
|
|
|
|
mutex_unlock(&vpu_opp_lock);
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(vvpu_update_ptp_count);
|
|
|
|
unsigned int vmdla_update_ptp_count(unsigned int ptp_count[],
|
|
unsigned int array_size)
|
|
{
|
|
int i; /* , idx; */
|
|
|
|
mutex_lock(&mdla_opp_lock);
|
|
|
|
for (i = 0; i < array_size; i++) {
|
|
mdla_ptp_count_table[i].mdla_ptp_count = ptp_count[i];
|
|
LOG_INF("%s id:%d, ptp cnt:0x%x\n", __func__, i, ptp_count[i]);
|
|
}
|
|
//
|
|
LOG_INF("[CPE]:MDLA Det_Count: %d, %d, %d, %d\n",
|
|
mdla_ptp_count_table[0].mdla_ptp_count,
|
|
mdla_ptp_count_table[1].mdla_ptp_count,
|
|
mdla_ptp_count_table[2].mdla_ptp_count,
|
|
mdla_ptp_count_table[3].mdla_ptp_count);
|
|
|
|
get_vmdla_from_efuse();
|
|
|
|
mutex_unlock(&mdla_opp_lock);
|
|
|
|
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(vmdla_update_ptp_count);
|
|
|
|
|
|
|
|
void vvpu_restore_default_volt(void)
|
|
{
|
|
int i;
|
|
|
|
mutex_lock(&vpu_opp_lock);
|
|
|
|
for (i = 0; i < VPU_DVFS_OPP_MAX; i++) {
|
|
vpu_opp_table[i].vpufreq_volt =
|
|
vpu_opp_table_default[i].vpufreq_volt;
|
|
}
|
|
dump_opp_table();
|
|
|
|
mutex_unlock(&vpu_opp_lock);
|
|
}
|
|
EXPORT_SYMBOL(vvpu_restore_default_volt);
|
|
|
|
void vmdla_restore_default_volt(void)
|
|
{
|
|
int i;
|
|
|
|
mutex_lock(&mdla_opp_lock);
|
|
|
|
for (i = 0; i < MDLA_DVFS_OPP_MAX; i++) {
|
|
mdla_opp_table[i].mdlafreq_volt =
|
|
mdla_opp_table_default[i].mdlafreq_volt;
|
|
}
|
|
dump_opp_table();
|
|
|
|
mutex_unlock(&mdla_opp_lock);
|
|
}
|
|
EXPORT_SYMBOL(vmdla_restore_default_volt);
|
|
|
|
/* API : get frequency via OPP table index */
|
|
unsigned int vpu_get_freq_by_idx(unsigned int idx)
|
|
{
|
|
if (idx < VPU_DVFS_OPP_MAX)
|
|
return vpu_opp_table[idx].vpufreq_khz;
|
|
else
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(vpu_get_freq_by_idx);
|
|
|
|
/* API : get voltage via OPP table index */
|
|
unsigned int vpu_get_volt_by_idx(unsigned int idx)
|
|
{
|
|
if (idx < VPU_DVFS_OPP_MAX)
|
|
return vpu_opp_table[idx].vpufreq_volt;
|
|
else
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(vpu_get_volt_by_idx);
|
|
|
|
/* API : get frequency via OPP table index */
|
|
unsigned int mdla_get_freq_by_idx(unsigned int idx)
|
|
{
|
|
if (idx < MDLA_DVFS_OPP_MAX)
|
|
return mdla_opp_table[idx].mdlafreq_khz;
|
|
else
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(mdla_get_freq_by_idx);
|
|
|
|
/* API : get voltage via OPP table index */
|
|
unsigned int mdla_get_volt_by_idx(unsigned int idx)
|
|
{
|
|
if (idx < MDLA_DVFS_OPP_MAX)
|
|
return mdla_opp_table[idx].mdlafreq_volt;
|
|
else
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(mdla_get_volt_by_idx);
|
|
|
|
/*
|
|
* API : disable DVFS for PTPOD initializing
|
|
*/
|
|
void vpu_disable_by_ptpod(void)
|
|
{
|
|
int ret = 0;
|
|
/* Pause VPU DVFS */
|
|
vvpu_DVFS_is_paused_by_ptpod = true;
|
|
/*fix vvpu to 0.8V*/
|
|
LOG_DBG("%s\n", __func__);
|
|
mutex_lock(&vpu_opp_lock);
|
|
/*--Set voltage--*/
|
|
ret = regulator_set_voltage(vvpu_reg_id,
|
|
10*VVPU_PTPOD_FIX_VOLT,
|
|
10*VVPU_DVFS_VOLT0);
|
|
udelay(20);
|
|
|
|
|
|
regulator_set_mode(vvpu_reg_id, REGULATOR_MODE_FAST);
|
|
|
|
mutex_unlock(&vpu_opp_lock);
|
|
}
|
|
|
|
void ptpod_is_enabled(bool enable)
|
|
{
|
|
/* Freerun VPU DVFS */
|
|
ptpod_enabled = enable;
|
|
}
|
|
EXPORT_SYMBOL(ptpod_is_enabled);
|
|
|
|
/*
|
|
* API : enable DVFS for PTPOD initializing
|
|
*/
|
|
void vpu_enable_by_ptpod(void)
|
|
{
|
|
/* Freerun VPU DVFS */
|
|
vvpu_DVFS_is_paused_by_ptpod = false;
|
|
}
|
|
EXPORT_SYMBOL(vpu_enable_by_ptpod);
|
|
|
|
|
|
bool get_vvpu_DVFS_is_paused_by_ptpod(void)
|
|
{
|
|
/* Freerun VPU DVFS */
|
|
return vvpu_DVFS_is_paused_by_ptpod;
|
|
}
|
|
EXPORT_SYMBOL(get_vvpu_DVFS_is_paused_by_ptpod);
|
|
|
|
/*
|
|
* API : disable DVFS for PTPOD initializing
|
|
*/
|
|
void mdla_disable_by_ptpod(void)
|
|
{
|
|
int ret = 0;
|
|
|
|
/* Pause VPU DVFS */
|
|
vmdla_DVFS_is_paused_by_ptpod = true;
|
|
LOG_DBG("%s\n", __func__);
|
|
mutex_lock(&mdla_opp_lock);
|
|
/*--Set voltage--*/
|
|
ret = regulator_set_voltage(vmdla_reg_id,
|
|
10*VMDLA_PTPOD_FIX_VOLT,
|
|
10*VMDLA_DVFS_VOLT0);
|
|
udelay(500);
|
|
|
|
regulator_set_mode(vmdla_reg_id, REGULATOR_MODE_FAST);
|
|
vvpu_vmdla_vcore_checker();
|
|
mutex_unlock(&mdla_opp_lock);
|
|
}
|
|
|
|
|
|
/*
|
|
* API : enable DVFS for PTPOD initializing
|
|
*/
|
|
void mdla_enable_by_ptpod(void)
|
|
{
|
|
int ret = 0;
|
|
int mode = 0;
|
|
|
|
/* Freerun VPU DVFS */
|
|
vmdla_DVFS_is_paused_by_ptpod = false;
|
|
|
|
mode = regulator_get_mode(vvpu_reg_id);
|
|
if (mode == REGULATOR_MODE_FAST)
|
|
LOG_INF("++vvpu_reg_id pwm mode\n");
|
|
else
|
|
LOG_INF("++vvpu_reg_id auto mode\n");
|
|
|
|
regulator_set_mode(vvpu_reg_id, REGULATOR_MODE_NORMAL);
|
|
udelay(100);
|
|
|
|
mode = regulator_get_mode(vvpu_reg_id);
|
|
if (mode == REGULATOR_MODE_FAST)
|
|
LOG_INF("--vvpu_reg_id pwm mode\n");
|
|
else
|
|
LOG_INF("--vvpu_reg_id auto mode\n");
|
|
|
|
mode = regulator_get_mode(vmdla_reg_id);
|
|
if (mode == REGULATOR_MODE_FAST)
|
|
LOG_INF("++vmdla_reg_id pwm mode\n");
|
|
else
|
|
LOG_INF("++vmdla_reg_id auto mode\n");
|
|
|
|
regulator_set_mode(vmdla_reg_id, REGULATOR_MODE_NORMAL);
|
|
udelay(100);
|
|
|
|
mode = regulator_get_mode(vmdla_reg_id);
|
|
if (mode == REGULATOR_MODE_FAST)
|
|
LOG_INF("--vmdla_reg_id pwm mode\n");
|
|
else
|
|
LOG_INF("--vmdla_reg_id auto mode\n");
|
|
|
|
ret = regulator_set_voltage(vvpu_reg_id,
|
|
10*(vpu_opp_table[9].vpufreq_volt),
|
|
850000);
|
|
|
|
ret = regulator_set_voltage(vmdla_reg_id,
|
|
10*(mdla_opp_table[9].mdlafreq_volt),
|
|
850000);
|
|
|
|
udelay(100);
|
|
ret = vvpu_regulator_set_mode(true);
|
|
udelay(100);
|
|
LOG_DVFS("vvpu set normal mode ret=%d\n", ret);
|
|
ret = vmdla_regulator_set_mode(true);
|
|
udelay(100);
|
|
LOG_DVFS("vmdla set normal mode ret=%d\n", ret);
|
|
ret = vvpu_regulator_set_mode(false);
|
|
udelay(100);
|
|
LOG_DVFS("vvpu set sleep mode ret=%d\n", ret);
|
|
ret = vmdla_regulator_set_mode(false);
|
|
udelay(100);
|
|
LOG_DVFS("vmdla set sleep mode ret=%d\n", ret);
|
|
|
|
vvpu_vmdla_vcore_checker();
|
|
}
|
|
EXPORT_SYMBOL(mdla_enable_by_ptpod);
|
|
|
|
bool get_vmdla_DVFS_is_paused_by_ptpod(void)
|
|
{
|
|
/* Freerun MDLA DVFS */
|
|
return vmdla_DVFS_is_paused_by_ptpod;
|
|
}
|
|
EXPORT_SYMBOL(get_vmdla_DVFS_is_paused_by_ptpod);
|
|
|
|
bool get_ready_for_ptpod_check(void)
|
|
{
|
|
/* Freerun MDLA DVFS */
|
|
return ready_for_ptpod_check;
|
|
}
|
|
EXPORT_SYMBOL(get_ready_for_ptpod_check);
|
|
|
|
|
|
|
|
int vvpu_regulator_set_mode(bool enable)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (!vvpu_reg_id) {
|
|
LOG_INF("vvpu_reg_id not ready\n");
|
|
return ret;
|
|
}
|
|
if (vvpu_DVFS_is_paused_by_ptpod) {
|
|
LOG_INF("vvpu dvfs lock\n");
|
|
return ret;
|
|
}
|
|
mutex_lock(&vpu_opp_lock);
|
|
LOG_DVFS("vvpu_reg enable:%d, count:%d\n", enable, vvpu_count);
|
|
if (enable) {
|
|
if (vvpu_count == 0) {
|
|
ret = regulator_set_mode(vvpu_reg_id,
|
|
REGULATOR_MODE_NORMAL);
|
|
}
|
|
vvpu_count++;
|
|
} else {
|
|
if (vvpu_count == 1) {
|
|
ret = regulator_set_mode(vvpu_reg_id,
|
|
REGULATOR_MODE_IDLE);
|
|
vvpu_count = 0;
|
|
} else if (vvpu_count > 1)
|
|
vvpu_count--;
|
|
}
|
|
mutex_unlock(&vpu_opp_lock);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(vvpu_regulator_set_mode);
|
|
int vmdla_regulator_set_mode(bool enable)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (!vmdla_reg_id) {
|
|
LOG_INF("vmdla_reg_id not ready\n");
|
|
return ret;
|
|
}
|
|
if (vmdla_DVFS_is_paused_by_ptpod) {
|
|
LOG_INF("vmdla dvfs lock\n");
|
|
return ret;
|
|
}
|
|
mutex_lock(&mdla_opp_lock);
|
|
LOG_DVFS("vmdla_reg enable:%d, count:%d\n", enable, vmdla_count);
|
|
if (enable) {
|
|
if (vmdla_count == 0) {
|
|
ret = regulator_set_voltage(vmdla_reg_id,
|
|
10*(mdla_opp_table[9].mdlafreq_volt),
|
|
850000);
|
|
}
|
|
vmdla_count++;
|
|
} else {
|
|
if (vmdla_count == 1) {
|
|
ret = regulator_set_voltage(vmdla_reg_id,
|
|
550000,
|
|
850000);
|
|
vmdla_count = 0;
|
|
} else if (vmdla_count > 1)
|
|
vmdla_count--;
|
|
}
|
|
mutex_unlock(&mdla_opp_lock);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(vmdla_regulator_set_mode);
|
|
|
|
int apu_power_count_enable(bool enable, int user)
|
|
{
|
|
mutex_lock(&apu_power_count_lock);
|
|
if (enable) {
|
|
apu_power_count |= user;
|
|
qos_sram_write(APU_CLK, 1);
|
|
} else {
|
|
apu_power_count &= ~user;
|
|
}
|
|
mutex_unlock(&apu_power_count_lock);
|
|
LOG_DVFS("apu_power_count %d", apu_power_count);
|
|
return apu_power_count;
|
|
}
|
|
EXPORT_SYMBOL(apu_power_count_enable);
|
|
|
|
int apu_shut_down(void)
|
|
{
|
|
int ret = 0;
|
|
int bw_nord = 0;
|
|
|
|
mutex_lock(&apu_power_count_lock);
|
|
if (apu_power_count != 0) {
|
|
mutex_unlock(&apu_power_count_lock);
|
|
return 0;
|
|
}
|
|
qos_sram_write(APU_CLK, 0);
|
|
while (bw_nord == 0) {
|
|
bw_nord = qos_sram_read(APU_BW_NORD);
|
|
udelay(500);
|
|
LOG_DVFS("wait SSPM bw_nord");
|
|
}
|
|
mutex_unlock(&apu_power_count_lock);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(apu_shut_down);
|
|
|
|
int vpu_get_hw_vvpu_opp(int core)
|
|
{
|
|
int opp_value = 0;
|
|
int get_vvpu_value = 0;
|
|
int vvpu_opp_0;
|
|
int vvpu_opp_1;
|
|
int vvpu_opp_2;
|
|
int vvpu_opp_0_vol;
|
|
int vvpu_opp_1_vol;
|
|
int vvpu_opp_2_vol;
|
|
//index63:PTPOD 0x11C105B4
|
|
vvpu_opp_0 = (get_devinfo_with_index(63) & (0x7<<15))>>15;
|
|
vvpu_opp_1 = (get_devinfo_with_index(63) & (0x7<<12))>>12;
|
|
vvpu_opp_2 = (get_devinfo_with_index(63) & (0x7<<9))>>9;
|
|
#ifdef AGING_MARGIN
|
|
if (vvpu0_cpe_result == 1) {
|
|
if ((vvpu_opp_0 <= 7) && (vvpu_opp_0 >= 3))
|
|
vvpu_opp_0_vol = (812500 - 2500);
|
|
else
|
|
vvpu_opp_0_vol = 812500;
|
|
} else
|
|
vvpu_opp_0_vol = 812500;
|
|
|
|
if (vvpu1_cpe_result == 1) {
|
|
if ((vvpu_opp_1 <= 7) && (vvpu_opp_1 >= 3))
|
|
vvpu_opp_1_vol = (712500 - 2500);
|
|
else
|
|
vvpu_opp_1_vol = 712500;
|
|
} else
|
|
vvpu_opp_1_vol = 712500;
|
|
|
|
vvpu_opp_2_vol = 637500;
|
|
#else
|
|
if (vvpu0_cpe_result == 1) {
|
|
if ((vvpu_opp_0 <= 7) && (vvpu_opp_0 >= 3))
|
|
vvpu_opp_0_vol = 800000;
|
|
else
|
|
vvpu_opp_0_vol = 825000;
|
|
} else {
|
|
vvpu_opp_0_vol = 825000;
|
|
}
|
|
if (vvpu1_cpe_result == 1) {
|
|
if ((vvpu_opp_1 <= 7) && (vvpu_opp_1 >= 3))
|
|
vvpu_opp_1_vol = 700000;
|
|
else
|
|
vvpu_opp_1_vol = 725000;
|
|
} else
|
|
vvpu_opp_1_vol = 725000;
|
|
|
|
vvpu_opp_2_vol = 650000;
|
|
#endif
|
|
|
|
get_vvpu_value = (int)regulator_get_voltage(vvpu_reg_id);
|
|
if (get_vvpu_value >= vvpu_opp_0_vol)
|
|
opp_value = 0;
|
|
else if (get_vvpu_value > vvpu_opp_1_vol)
|
|
opp_value = 0;
|
|
else if (get_vvpu_value > vvpu_opp_2_vol)
|
|
opp_value = 1;
|
|
else
|
|
opp_value = 2;
|
|
LOG_DVFS("[vpu_%d] vvpu(%d->%d)\n",
|
|
core, get_vvpu_value, opp_value);
|
|
return opp_value;
|
|
|
|
}
|
|
EXPORT_SYMBOL(vpu_get_hw_vvpu_opp);
|
|
|
|
int mdla_get_hw_vmdla_opp(int core)
|
|
{
|
|
int opp_value = 0;
|
|
int get_vmdla_value = 0;
|
|
int vmdla_opp_0;
|
|
int vmdla_opp_1;
|
|
int vmdla_opp_2;
|
|
int vmdla_opp_0_vol;
|
|
int vmdla_opp_1_vol;
|
|
int vmdla_opp_2_vol;
|
|
//index63:PTPOD 0x11C105B4
|
|
vmdla_opp_0 = (get_devinfo_with_index(63) & (0x7<<24))>>24;
|
|
vmdla_opp_1 = (get_devinfo_with_index(63) & (0x7<<21))>>21;
|
|
vmdla_opp_2 = (get_devinfo_with_index(63) & (0x7<<18))>>18;
|
|
#ifdef AGING_MARGIN
|
|
if (vmdla0_cpe_result == 1) {
|
|
if ((vmdla_opp_0 <= 7) && (vmdla_opp_0 >= 3))
|
|
vmdla_opp_0_vol = (815000 - 25000);
|
|
else
|
|
vmdla_opp_0_vol = 815000;
|
|
} else
|
|
vmdla_opp_0_vol = 815000;
|
|
|
|
if (vmdla1_cpe_result == 1) {
|
|
if ((vmdla_opp_1 <= 7) && (vmdla_opp_1 >= 3))
|
|
vmdla_opp_1_vol = (715000 - 25000);
|
|
else
|
|
vmdla_opp_1_vol = 715000;
|
|
} else
|
|
vmdla_opp_1_vol = 715000;
|
|
|
|
vmdla_opp_2_vol = 640000;
|
|
#else
|
|
if (vmdla0_cpe_result == 1) {
|
|
if ((vmdla_opp_0 <= 7) && (vmdla_opp_0 >= 3))
|
|
vmdla_opp_0_vol = 800000;
|
|
else
|
|
vmdla_opp_0_vol = 825000;
|
|
} else {
|
|
vmdla_opp_0_vol = 825000;
|
|
}
|
|
if (vmdla1_cpe_result == 1) {
|
|
if ((vmdla_opp_1 <= 7) && (vmdla_opp_1 >= 3))
|
|
vmdla_opp_1_vol = 700000;
|
|
else
|
|
vmdla_opp_1_vol = 725000;
|
|
} else
|
|
vmdla_opp_1_vol = 725000;
|
|
|
|
vmdla_opp_2_vol = 650000;
|
|
#endif
|
|
get_vmdla_value = (int)regulator_get_voltage(vmdla_reg_id);
|
|
if (get_vmdla_value >= vmdla_opp_0_vol)
|
|
opp_value = 0;
|
|
else if (get_vmdla_value > vmdla_opp_1_vol)
|
|
opp_value = 0;
|
|
else if (get_vmdla_value > vmdla_opp_2_vol)
|
|
opp_value = 1;
|
|
else
|
|
opp_value = 2;
|
|
|
|
LOG_DVFS("[mdla_%d] vmdla(%d->%d)\n",
|
|
core, get_vmdla_value, opp_value);
|
|
|
|
return opp_value;
|
|
}
|
|
|
|
void init_cycle(unsigned int *reg)
|
|
{
|
|
//2'b00: 0.63ms2'b01: 1.26ms2'b10: 1.89ms2'b11: 2.52ms
|
|
*reg &= ~(1 << 22);//qa_int_cyc[22:21]
|
|
*reg |= (1 << 21);
|
|
}
|
|
void enable_bw(unsigned int *reg)
|
|
{
|
|
//2'b00: 0.63ms2'b01: 1.26ms2'b10: 1.89ms2'b11: 2.52ms
|
|
*reg |= ((1 << 23) | (1 << 7)); //qa_bw_int_en,qa_int_bw
|
|
}
|
|
|
|
void enable_apu_bw(unsigned int core)
|
|
{
|
|
unsigned int reg = 0;
|
|
|
|
if (core == 0) {
|
|
reg = vpu_read_reg32(apu_syscfg_base, APU_CONN_QA_CTRL0);
|
|
init_cycle(®);
|
|
enable_bw(®);
|
|
vpu_write_reg32(apu_syscfg_base, APU_CONN_QA_CTRL0, reg);
|
|
} else if (core == 1) {
|
|
reg = vpu_read_reg32(apu_syscfg_base, APU_CONN_QB_CTRL0);
|
|
init_cycle(®);
|
|
enable_bw(®);
|
|
vpu_write_reg32(apu_syscfg_base, APU_CONN_QB_CTRL0, reg);
|
|
} else {
|
|
reg = vpu_read_reg32(apu_syscfg_base, APU_CONN_QC_CTRL0);
|
|
init_cycle(®);
|
|
enable_bw(®);
|
|
vpu_write_reg32(apu_syscfg_base, APU_CONN_QC_CTRL0, reg);
|
|
reg = vpu_read_reg32(apu_syscfg_base, APU_CONN_QC1_CTRL0);
|
|
init_cycle(®);
|
|
enable_bw(®);
|
|
vpu_write_reg32(apu_syscfg_base, APU_CONN_QC1_CTRL0, reg);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(enable_apu_bw);
|
|
|
|
void enable_apu_latency(unsigned int core)
|
|
{
|
|
unsigned int reg = 0;
|
|
|
|
//qa_avl_timer_prd_shf=2 [11:9]
|
|
//qa_avl_timer_prd=9 [8:1]
|
|
//qa_lt_int_en=1 [0]
|
|
//Unit = 9.884* 2^TIMER_PRD_SHF us
|
|
//(TIMER_PRD<<TIMER_PRD_SHF) * Unit = (9<<2)*9.884*2^2 = 1.422ms
|
|
//APU_CONN_QOS_CTRL1
|
|
//qa_aw_sel [11], qb_aw_sel[8], qc_aw_sel[5], qc1_aw_sel[2]
|
|
if (core == 0) {
|
|
reg = vpu_read_reg32(apu_syscfg_base, APU_CONN_QA_CTRL3);
|
|
reg &= ~((1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) |
|
|
(1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) |
|
|
(1 << 2) | (1 << 1) | 1);
|
|
reg |= ((2 << 9) | (9 << 1) | (1 << 0));
|
|
vpu_write_reg32(apu_syscfg_base, APU_CONN_QA_CTRL3, reg);
|
|
|
|
reg = vpu_read_reg32(apu_syscfg_base, APU_CONN_QOS_CTRL1);
|
|
reg |= (1 << 11);
|
|
vpu_write_reg32(apu_syscfg_base, APU_CONN_QOS_CTRL1, reg);
|
|
|
|
} else if (core == 1) {
|
|
reg = vpu_read_reg32(apu_syscfg_base, APU_CONN_QB_CTRL3);
|
|
reg &= ~((1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) |
|
|
(1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) |
|
|
(1 << 2) | (1 << 1) | 1);
|
|
reg |= ((2 << 9) | (9 << 1) | (1 << 0));
|
|
vpu_write_reg32(apu_syscfg_base, APU_CONN_QB_CTRL3, reg);
|
|
reg = vpu_read_reg32(apu_syscfg_base, APU_CONN_QOS_CTRL1);
|
|
reg |= (1 << 8);
|
|
vpu_write_reg32(apu_syscfg_base, APU_CONN_QOS_CTRL1, reg);
|
|
} else {
|
|
reg = vpu_read_reg32(apu_syscfg_base, APU_CONN_QC_CTRL3);
|
|
reg &= ~((1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) |
|
|
(1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) |
|
|
(1 << 2) | (1 << 1) | 1);
|
|
reg |= ((2 << 9) | (9 << 1) | (1 << 0));
|
|
vpu_write_reg32(apu_syscfg_base, APU_CONN_QC_CTRL3, reg);
|
|
reg = vpu_read_reg32(apu_syscfg_base, APU_CONN_QC1_CTRL3);
|
|
reg &= ~((1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) |
|
|
(1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) |
|
|
(1 << 2) | (1 << 1) | 1);
|
|
reg |= ((2 << 9) | (9 << 1) | (1 << 0));
|
|
vpu_write_reg32(apu_syscfg_base, APU_CONN_QC1_CTRL3, reg);
|
|
reg = vpu_read_reg32(apu_syscfg_base, APU_CONN_QOS_CTRL1);
|
|
reg |= ((1 << 5) | (1 << 2));
|
|
vpu_write_reg32(apu_syscfg_base, APU_CONN_QOS_CTRL1, reg);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(enable_apu_latency);
|
|
|
|
|
|
static int vvpu_vbin(int opp)
|
|
{
|
|
int vbin = 0;
|
|
int result = 0;
|
|
int vvpu_opp = 0;
|
|
int pass_crit = 300000;
|
|
int i = 0;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
if (vpu_ptp_count_table[i].vpu_ptp_count == 0) {
|
|
LOG_INF("vpu ptp count 0\n");
|
|
result = 0;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
//index63:PTPOD 0x11C105B4
|
|
if (opp == 0) {
|
|
vbin = (-1365) * vpu_ptp_count_table[1].vpu_ptp_count +
|
|
(1758) * vpu_ptp_count_table[3].vpu_ptp_count +
|
|
(1443) * vpu_ptp_count_table[0].vpu_ptp_count +
|
|
(2465) * vpu_ptp_count_table[2].vpu_ptp_count
|
|
-2579054;
|
|
vvpu_opp = (get_devinfo_with_index(63) & (0x7<<15))>>15;
|
|
pass_crit = 270000;
|
|
if (vbin < pass_crit)
|
|
result = 0;
|
|
else
|
|
result = 1;
|
|
} else if (opp == 1) {
|
|
vbin = (-1290) * vpu_ptp_count_table[1].vpu_ptp_count +
|
|
(1925) * vpu_ptp_count_table[3].vpu_ptp_count +
|
|
(1346) * vpu_ptp_count_table[0].vpu_ptp_count +
|
|
(1525) * vpu_ptp_count_table[2].vpu_ptp_count
|
|
-2060363;
|
|
|
|
vvpu_opp = (get_devinfo_with_index(63) & (0x7<<12))>>12;
|
|
pass_crit = 290000;
|
|
if (vbin < pass_crit)
|
|
result = 0;
|
|
else
|
|
result = 1;
|
|
|
|
} else if (opp == 2) {
|
|
vbin = (-5328) * vpu_ptp_count_table[1].vpu_ptp_count +
|
|
(2391) * vpu_ptp_count_table[3].vpu_ptp_count +
|
|
(9801) * vpu_ptp_count_table[0].vpu_ptp_count +
|
|
(-2551) * vpu_ptp_count_table[2].vpu_ptp_count
|
|
-1502260;
|
|
|
|
vvpu_opp = (get_devinfo_with_index(63) & (0x7<<9))>>9;
|
|
if (vbin < pass_crit)
|
|
result = 0;
|
|
else
|
|
result = 1;
|
|
}
|
|
LOG_INF("[CPE]:VPU_OPP=%d,VPU_BIN=%d,CPE_VBIN=%d,Criteria=%d,Result=%d\n",
|
|
opp, vvpu_opp, vbin, pass_crit, result);
|
|
return result;
|
|
}
|
|
static int vmdla_vbin(int opp)
|
|
{
|
|
int vbin = 0;
|
|
int result = 0;
|
|
int vmdla_opp = 0;
|
|
int pass_crit = 300000;
|
|
int i = 0;
|
|
|
|
//index63:PTPOD 0x11C105B4
|
|
//vmdla_opp_0 = (get_devinfo_with_index(63) & (0x7<<24))>>24;
|
|
//vmdla_opp_1 = (get_devinfo_with_index(63) & (0x7<<21))>>21;
|
|
//vmdla_opp_2 = (get_devinfo_with_index(63) & (0x7<<18))>>18;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
if (mdla_ptp_count_table[i].mdla_ptp_count == 0) {
|
|
LOG_INF("mdla ptp count 0\n");
|
|
result = 0;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
|
|
if (opp == 0) {
|
|
vbin =
|
|
(-1365) * mdla_ptp_count_table[1].mdla_ptp_count +
|
|
(1758) * mdla_ptp_count_table[3].mdla_ptp_count +
|
|
(1443) * mdla_ptp_count_table[0].mdla_ptp_count +
|
|
(2465) * mdla_ptp_count_table[2].mdla_ptp_count
|
|
-2579054;
|
|
vmdla_opp = (get_devinfo_with_index(63) & (0x7<<24))>>24;
|
|
pass_crit = 270000;
|
|
if (vbin < pass_crit)
|
|
result = 0;
|
|
else
|
|
result = 1;
|
|
} else if (opp == 1) {
|
|
vbin =
|
|
(-1290) * mdla_ptp_count_table[1].mdla_ptp_count +
|
|
(1925) * mdla_ptp_count_table[3].mdla_ptp_count +
|
|
(1346) * mdla_ptp_count_table[0].mdla_ptp_count +
|
|
(1525) * mdla_ptp_count_table[2].mdla_ptp_count
|
|
-2060363;
|
|
|
|
vmdla_opp = (get_devinfo_with_index(63) & (0x7<<21))>>21;
|
|
pass_crit = 290000;
|
|
if (vbin < pass_crit)
|
|
result = 0;
|
|
else
|
|
result = 1;
|
|
|
|
} else if (opp == 2) {
|
|
vbin =
|
|
(-5328) * mdla_ptp_count_table[1].mdla_ptp_count +
|
|
(2391) * mdla_ptp_count_table[3].mdla_ptp_count +
|
|
(9801) * mdla_ptp_count_table[0].mdla_ptp_count +
|
|
(-2551) * mdla_ptp_count_table[2].mdla_ptp_count
|
|
-1502260;
|
|
|
|
vmdla_opp = (get_devinfo_with_index(63) & (0x7<<18))>>18;
|
|
if (vbin < pass_crit)
|
|
result = 0;
|
|
else
|
|
result = 1;
|
|
}
|
|
|
|
LOG_INF("[CPE]:MDLA_OPP=%d,BIN=%d,CPE_VBIN=%d,Criteria=%d,Result=%d\n",
|
|
opp, vmdla_opp, vbin, pass_crit, result);
|
|
return result;
|
|
}
|
|
|
|
|
|
int apu_dvfs_dump_info(void)
|
|
{
|
|
int mode = 0;
|
|
int i = 4;
|
|
|
|
mode = regulator_get_mode(vvpu_reg_id);
|
|
if (mode == REGULATOR_MODE_FAST)
|
|
LOG_INF("++vvpu_reg_id pwm mode\n");
|
|
else
|
|
LOG_INF("++vvpu_reg_id auto mode\n");
|
|
|
|
|
|
mode = regulator_get_mode(vmdla_reg_id);
|
|
if (mode == REGULATOR_MODE_FAST)
|
|
LOG_INF("++vmdla_reg_id pwm mode\n");
|
|
else
|
|
LOG_INF("++vmdla_reg_id auto mode\n");
|
|
|
|
vvpu_vmdla_vcore_checker();
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
LOG_INF("id:%d, vpu ptp cnt:0x%x\n",
|
|
i, vpu_ptp_count_table[i].vpu_ptp_count);
|
|
}
|
|
for (i = 0; i < 4; i++) {
|
|
LOG_INF("id:%d, mdla ptp cnt:0x%x\n",
|
|
i, mdla_ptp_count_table[i].mdla_ptp_count);
|
|
}
|
|
|
|
LOG_INF("vpu dvfs lock:%d, mdla dvfs lock:%d\n",
|
|
vvpu_DVFS_is_paused_by_ptpod, vmdla_DVFS_is_paused_by_ptpod);
|
|
LOG_INF("vpu cpe0:%d, cpe1:%d, cpe2:%d\n",
|
|
vvpu0_cpe_result, vvpu1_cpe_result, vvpu2_cpe_result);
|
|
LOG_INF("mdla cpe0:%d, cpe1:%d, cpe2:%d\n",
|
|
vmdla0_cpe_result, vmdla1_cpe_result, vmdla2_cpe_result);
|
|
vvpu_vbin(0);
|
|
vvpu_vbin(1);
|
|
vvpu_vbin(2);
|
|
vmdla_vbin(0);
|
|
vmdla_vbin(1);
|
|
vmdla_vbin(2);
|
|
dump_opp_table();
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(apu_dvfs_dump_info);
|
|
|
|
static void get_vvpu_from_efuse(void)
|
|
{
|
|
int vvpu_opp_0;
|
|
int vvpu_opp_1;
|
|
int vvpu_opp_2;
|
|
int vvpu_opp_0_vol;
|
|
int vvpu_opp_1_vol;
|
|
int vvpu_opp_2_vol;
|
|
//index63:PTPOD 0x11C105B4
|
|
vvpu_opp_0 = (get_devinfo_with_index(63) & (0x7<<15))>>15;
|
|
vvpu_opp_1 = (get_devinfo_with_index(63) & (0x7<<12))>>12;
|
|
vvpu_opp_2 = (get_devinfo_with_index(63) & (0x7<<9))>>9;
|
|
vvpu0_cpe_result = vvpu_vbin(0);
|
|
vvpu1_cpe_result = vvpu_vbin(1);
|
|
vvpu2_cpe_result = vvpu_vbin(2);
|
|
#ifdef AGING_MARGIN
|
|
if (vvpu0_cpe_result == 1) {
|
|
if ((vvpu_opp_0 <= 7) && (vvpu_opp_0 >= 3))
|
|
vvpu_opp_0_vol = (81250 - 2500);
|
|
else
|
|
vvpu_opp_0_vol = 81250;
|
|
} else
|
|
vvpu_opp_0_vol = 81250;
|
|
|
|
if (vvpu1_cpe_result == 1) {
|
|
if ((vvpu_opp_1 <= 7) && (vvpu_opp_1 >= 3))
|
|
vvpu_opp_1_vol = (71250 - 2500);
|
|
else
|
|
vvpu_opp_1_vol = 71250;
|
|
} else
|
|
vvpu_opp_1_vol = 71250;
|
|
|
|
|
|
vvpu_opp_2_vol = 63750;
|
|
#else
|
|
if (vvpu0_cpe_result == 1) {
|
|
if ((vvpu_opp_0 <= 7) && (vvpu_opp_0 >= 3))
|
|
vvpu_opp_0_vol = 80000;
|
|
else
|
|
vvpu_opp_0_vol = 82500;
|
|
} else
|
|
vvpu_opp_0_vol = 82500;
|
|
|
|
if (vvpu1_cpe_result == 1) {
|
|
if ((vvpu_opp_1 <= 7) && (vvpu_opp_1 >= 3))
|
|
vvpu_opp_1_vol = 70000;
|
|
else
|
|
vvpu_opp_1_vol = 72500;
|
|
} else
|
|
vvpu_opp_1_vol = 72500;
|
|
|
|
|
|
vvpu_opp_2_vol = 65000;
|
|
#endif
|
|
vpu_opp_table[0].vpufreq_volt = vvpu_opp_0_vol;
|
|
vpu_opp_table[1].vpufreq_volt = vvpu_opp_0_vol;
|
|
vpu_opp_table[2].vpufreq_volt = vvpu_opp_0_vol;
|
|
vpu_opp_table[3].vpufreq_volt = vvpu_opp_0_vol;
|
|
vpu_opp_table[4].vpufreq_volt = vvpu_opp_0_vol;
|
|
vpu_opp_table[5].vpufreq_volt = vvpu_opp_1_vol;
|
|
vpu_opp_table[6].vpufreq_volt = vvpu_opp_1_vol;
|
|
vpu_opp_table[7].vpufreq_volt = vvpu_opp_1_vol;
|
|
vpu_opp_table[8].vpufreq_volt = vvpu_opp_1_vol;
|
|
vpu_opp_table[9].vpufreq_volt = vvpu_opp_2_vol;
|
|
vpu_opp_table[10].vpufreq_volt = vvpu_opp_2_vol;
|
|
vpu_opp_table[11].vpufreq_volt = vvpu_opp_2_vol;
|
|
vpu_opp_table[12].vpufreq_volt = vvpu_opp_2_vol;
|
|
vpu_opp_table[13].vpufreq_volt = vvpu_opp_2_vol;
|
|
vpu_opp_table[14].vpufreq_volt = vvpu_opp_2_vol;
|
|
vpu_opp_table[15].vpufreq_volt = vvpu_opp_2_vol;
|
|
|
|
}
|
|
static void get_vvpu_efuse(void)
|
|
{
|
|
int vvpu_opp_0;
|
|
int vvpu_opp_1;
|
|
int vvpu_opp_2;
|
|
//index63:PTPOD 0x11C105B4
|
|
vvpu_opp_0 = (get_devinfo_with_index(63) & (0x7<<15))>>15;
|
|
vvpu_opp_1 = (get_devinfo_with_index(63) & (0x7<<12))>>12;
|
|
vvpu_opp_2 = (get_devinfo_with_index(63) & (0x7<<9))>>9;
|
|
LOG_DVFS("vvpu_opp_0 %d, vvpu_opp_1 %d, vvpu_opp_2 %d\n",
|
|
vvpu_opp_0, vvpu_opp_1, vvpu_opp_2);
|
|
}
|
|
static void get_vmdla_efuse(void)
|
|
{
|
|
int vmdla_opp_0;
|
|
int vmdla_opp_1;
|
|
int vmdla_opp_2;
|
|
//index63:PTPOD 0x11C105B4
|
|
vmdla_opp_0 = (get_devinfo_with_index(63) & (0x7<<24))>>24;
|
|
vmdla_opp_1 = (get_devinfo_with_index(63) & (0x7<<21))>>21;
|
|
vmdla_opp_2 = (get_devinfo_with_index(63) & (0x7<<18))>>18;
|
|
LOG_DVFS("vmdla_opp_0 %d, vmdla_opp_1 %d, vmdla_opp_2 %d\n",
|
|
vmdla_opp_0, vmdla_opp_1, vmdla_opp_2);
|
|
}
|
|
|
|
static void get_vmdla_from_efuse(void)
|
|
{
|
|
int vmdla_opp_0;
|
|
int vmdla_opp_1;
|
|
int vmdla_opp_2;
|
|
int vmdla_opp_0_vol;
|
|
int vmdla_opp_1_vol;
|
|
int vmdla_opp_2_vol;
|
|
|
|
//index63:PTPOD 0x11C105B4
|
|
vmdla_opp_0 = (get_devinfo_with_index(63) & (0x7<<24))>>24;
|
|
vmdla_opp_1 = (get_devinfo_with_index(63) & (0x7<<21))>>21;
|
|
vmdla_opp_2 = (get_devinfo_with_index(63) & (0x7<<18))>>18;
|
|
vmdla0_cpe_result = vmdla_vbin(0);
|
|
vmdla1_cpe_result = vmdla_vbin(1);
|
|
vmdla2_cpe_result = vmdla_vbin(2);
|
|
#ifdef AGING_MARGIN
|
|
if (vmdla0_cpe_result == 1) {
|
|
if ((vmdla_opp_0 <= 7) && (vmdla_opp_0 >= 3))
|
|
vmdla_opp_0_vol = (81500 - 2500);
|
|
else
|
|
vmdla_opp_0_vol = 81500;
|
|
} else
|
|
vmdla_opp_0_vol = 81500;
|
|
|
|
if (vmdla1_cpe_result == 1) {
|
|
if ((vmdla_opp_1 <= 7) && (vmdla_opp_1 >= 3))
|
|
vmdla_opp_1_vol = (71500 - 2500);
|
|
else
|
|
vmdla_opp_1_vol = 71500;
|
|
} else
|
|
vmdla_opp_1_vol = 71500;
|
|
|
|
vmdla_opp_2_vol = 64000;
|
|
#else
|
|
|
|
if (vmdla0_cpe_result == 1) {
|
|
if ((vmdla_opp_0 <= 7) && (vmdla_opp_0 >= 3))
|
|
vmdla_opp_0_vol = 80000;
|
|
else
|
|
vmdla_opp_0_vol = 82500;
|
|
} else
|
|
vmdla_opp_0_vol = 82500;
|
|
|
|
if (vmdla1_cpe_result == 1) {
|
|
if ((vmdla_opp_1 <= 7) && (vmdla_opp_1 >= 3))
|
|
vmdla_opp_1_vol = 70000;
|
|
else
|
|
vmdla_opp_1_vol = 72500;
|
|
} else
|
|
vmdla_opp_1_vol = 72500;
|
|
|
|
vmdla_opp_2_vol = 65000;
|
|
#endif
|
|
mdla_opp_table[0].mdlafreq_volt = vmdla_opp_0_vol;
|
|
mdla_opp_table[1].mdlafreq_volt = vmdla_opp_0_vol;
|
|
mdla_opp_table[2].mdlafreq_volt = vmdla_opp_0_vol;
|
|
mdla_opp_table[3].mdlafreq_volt = vmdla_opp_1_vol;
|
|
mdla_opp_table[4].mdlafreq_volt = vmdla_opp_1_vol;
|
|
mdla_opp_table[5].mdlafreq_volt = vmdla_opp_1_vol;
|
|
mdla_opp_table[6].mdlafreq_volt = vmdla_opp_1_vol;
|
|
mdla_opp_table[7].mdlafreq_volt = vmdla_opp_1_vol;
|
|
mdla_opp_table[8].mdlafreq_volt = vmdla_opp_1_vol;
|
|
mdla_opp_table[9].mdlafreq_volt = vmdla_opp_2_vol;
|
|
mdla_opp_table[10].mdlafreq_volt = vmdla_opp_2_vol;
|
|
mdla_opp_table[11].mdlafreq_volt = vmdla_opp_2_vol;
|
|
mdla_opp_table[12].mdlafreq_volt = vmdla_opp_2_vol;
|
|
mdla_opp_table[13].mdlafreq_volt = vmdla_opp_2_vol;
|
|
mdla_opp_table[14].mdlafreq_volt = vmdla_opp_2_vol;
|
|
mdla_opp_table[15].mdlafreq_volt = vmdla_opp_2_vol;
|
|
}
|
|
|
|
static int commit_data(int type, int data)
|
|
{
|
|
int ret = 0;
|
|
int level = 16, opp = 16;
|
|
int settle_time = 0;
|
|
|
|
switch (type) {
|
|
|
|
case MTK_PM_QOS_VVPU_OPP:
|
|
mutex_lock(&vpu_opp_lock);
|
|
if (get_vvpu_DVFS_is_paused_by_ptpod())
|
|
LOG_INF("PM_QOS_VVPU_OPP paused by ptpod %d\n",
|
|
data);
|
|
else {
|
|
LOG_DVFS("%s PM_QOS_VVPU_OPP %d\n", __func__, data);
|
|
/*settle time*/
|
|
if (data > vvpu_orig_opp) {
|
|
if (data - vvpu_orig_opp == 1)
|
|
settle_time = 14;
|
|
if (data - vvpu_orig_opp == 2)
|
|
settle_time = 24;
|
|
} else if (data < vvpu_orig_opp) {
|
|
if (vvpu_orig_opp - data == 1)
|
|
settle_time = 10;
|
|
if (vvpu_orig_opp - data == 2)
|
|
settle_time = 18;
|
|
} else
|
|
settle_time = 0;
|
|
|
|
vvpu_orig_opp = data;
|
|
|
|
/*--Set voltage--*/
|
|
if (data == 0) {
|
|
LOG_DBG("set_voltage %d\n",
|
|
10*(vpu_opp_table[0].vpufreq_volt));
|
|
ret = regulator_set_voltage(vvpu_reg_id,
|
|
10*(vpu_opp_table[0].vpufreq_volt),
|
|
850000);
|
|
} else if (data == 1) {
|
|
LOG_DBG("set_voltage %d\n",
|
|
10*(vpu_opp_table[5].vpufreq_volt));
|
|
ret = regulator_set_voltage(vvpu_reg_id,
|
|
10*(vpu_opp_table[5].vpufreq_volt),
|
|
850000);
|
|
} else {
|
|
LOG_DBG("set_voltage %d\n",
|
|
10*(vpu_opp_table[9].vpufreq_volt));
|
|
ret = regulator_set_voltage(vvpu_reg_id,
|
|
10*(vpu_opp_table[9].vpufreq_volt),
|
|
850000);
|
|
}
|
|
if (ret)
|
|
LOG_ERR("regulator_set_voltage vvpu_reg_id failed\n");
|
|
}
|
|
udelay(settle_time);
|
|
mutex_unlock(&vpu_opp_lock);
|
|
break;
|
|
case MTK_PM_QOS_VMDLA_OPP:
|
|
mutex_lock(&mdla_opp_lock);
|
|
if (get_vmdla_DVFS_is_paused_by_ptpod())
|
|
LOG_INF("PM_QOS_VMDLA_OPP paused by ptpod %d\n",
|
|
data);
|
|
else {
|
|
LOG_DVFS("%s PM_QOS_VMDLA_OPP %d\n", __func__,
|
|
data);
|
|
/*settle time*/
|
|
if (data > vmdla_orig_opp) {
|
|
if (data - vmdla_orig_opp == 1)
|
|
settle_time = 37;
|
|
if (data - vmdla_orig_opp == 2)
|
|
settle_time = 41;
|
|
} else if (data < vmdla_orig_opp) {
|
|
if (vmdla_orig_opp - data == 1)
|
|
settle_time = 36;
|
|
if (vmdla_orig_opp - data == 2)
|
|
settle_time = 42;
|
|
} else
|
|
settle_time = 0;
|
|
|
|
vmdla_orig_opp = data;
|
|
|
|
/*--Set voltage--*/
|
|
if (data == 0) {
|
|
ret = regulator_set_voltage(vmdla_reg_id,
|
|
10*(mdla_opp_table[0].mdlafreq_volt),
|
|
850000);
|
|
LOG_DBG("set vmdla %d, ret %d\n",
|
|
10*(mdla_opp_table[0].mdlafreq_volt), ret);
|
|
} else if (data == 1) {
|
|
ret = regulator_set_voltage(vmdla_reg_id,
|
|
10*(mdla_opp_table[3].mdlafreq_volt),
|
|
850000);
|
|
LOG_DBG("set vmdla %d, ret %d\n",
|
|
10*(mdla_opp_table[3].mdlafreq_volt), ret);
|
|
} else {
|
|
ret = regulator_set_voltage(vmdla_reg_id,
|
|
10*(mdla_opp_table[9].mdlafreq_volt),
|
|
850000);
|
|
LOG_DBG("set vmdla %d, ret %d\n",
|
|
10*(mdla_opp_table[9].mdlafreq_volt), ret);
|
|
}
|
|
|
|
}
|
|
udelay(settle_time);
|
|
mutex_unlock(&mdla_opp_lock);
|
|
break;
|
|
|
|
default:
|
|
LOG_DBG("unsupported type of commit data\n");
|
|
break;
|
|
}
|
|
vvpu_vmdla_vcore_checker();
|
|
|
|
get_vvpu_efuse();
|
|
get_vmdla_efuse();
|
|
|
|
if (ret < 0) {
|
|
pr_info("%s: type: 0x%x, data: 0x%x, opp: %d, level: %d\n",
|
|
__func__, type, data, opp, level);
|
|
apu_dvfs_dump_reg(NULL);
|
|
aee_kernel_warning("dvfs", "%s: failed.", __func__);
|
|
}
|
|
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void get_pm_qos_info(char *p, size_t n)
|
|
{
|
|
char timestamp[20];
|
|
int start, remain;
|
|
|
|
dvfs_get_timestamp(timestamp);
|
|
// Fix Coverity defect, don't call sprintf
|
|
remain = n;
|
|
start = snprintf(p, remain, "%-24s: 0x%x\n",
|
|
"PM_QOS_VVPU_OPP",
|
|
mtk_pm_qos_request(MTK_PM_QOS_VVPU_OPP));
|
|
if (start >= 0 && start < remain) {
|
|
p += start;
|
|
remain -= start;
|
|
start = snprintf(p, remain, "%-24s: 0x%x\n",
|
|
"PM_QOS_VMDLA_OPP",
|
|
mtk_pm_qos_request(MTK_PM_QOS_VMDLA_OPP));
|
|
}
|
|
if (start >= 0 && start < remain) {
|
|
p += start;
|
|
remain -= start;
|
|
start = snprintf(p, remain, "%-24s: %s\n",
|
|
"Current Timestamp", timestamp);
|
|
}
|
|
if (start >= 0 && start < remain) {
|
|
p += start;
|
|
remain -= start;
|
|
start = snprintf(p, remain, "%-24s: %s\n",
|
|
"Force Start Timestamp", dvfs->force_start);
|
|
}
|
|
if (start >= 0 && start < remain) {
|
|
p += start;
|
|
remain -= start;
|
|
start = snprintf(p, remain, "%-24s: %s\n",
|
|
"Force End Timestamp", dvfs->force_end);
|
|
}
|
|
if (start < 0)
|
|
LOG_ERR("[%s] snprintf failed!\n", __func__);
|
|
}
|
|
|
|
char *apu_dvfs_dump_reg(char *ptr)
|
|
{
|
|
char buf[1024];
|
|
|
|
get_pm_qos_info(buf, 1024);
|
|
// Fix Coverity defect, don't call sprintf
|
|
if (ptr)
|
|
ptr += snprintf(ptr, 1024, "%s\n", buf);
|
|
else
|
|
pr_info("%s\n", buf);
|
|
|
|
return ptr;
|
|
}
|
|
|
|
static int pm_qos_vvpu_opp_notify(struct notifier_block *b,
|
|
unsigned long l, void *v)
|
|
{
|
|
commit_data(MTK_PM_QOS_VVPU_OPP, l);
|
|
|
|
return NOTIFY_OK;
|
|
}
|
|
static int pm_qos_vmdla_opp_notify(struct notifier_block *b,
|
|
unsigned long l, void *v)
|
|
{
|
|
commit_data(MTK_PM_QOS_VMDLA_OPP, l);
|
|
|
|
return NOTIFY_OK;
|
|
}
|
|
|
|
|
|
static void pm_qos_notifier_register(void)
|
|
{
|
|
|
|
dvfs->pm_qos_vvpu_opp_nb.notifier_call =
|
|
pm_qos_vvpu_opp_notify;
|
|
mtk_pm_qos_add_notifier(MTK_PM_QOS_VVPU_OPP,
|
|
&dvfs->pm_qos_vvpu_opp_nb);
|
|
|
|
dvfs->pm_qos_vmdla_opp_nb.notifier_call =
|
|
pm_qos_vmdla_opp_notify;
|
|
mtk_pm_qos_add_notifier(MTK_PM_QOS_VMDLA_OPP,
|
|
&dvfs->pm_qos_vmdla_opp_nb);
|
|
}
|
|
|
|
#ifdef CONFIG_MTK_DEVINFO
|
|
static int get_nvmem_cell_efuse(struct device *dev)
|
|
{
|
|
struct nvmem_cell *cell;
|
|
uint32_t *buf = NULL;
|
|
|
|
cell = nvmem_cell_get(dev, "efuse_ptpod");
|
|
if (IS_ERR(cell)) {
|
|
LOG_ERR("[%s] nvmem_cell_get fail\n", __func__);
|
|
if (PTR_ERR(cell) == -EPROBE_DEFER)
|
|
return PTR_ERR(cell);
|
|
return -1;
|
|
}
|
|
|
|
/* Add null checking for Coverity */
|
|
if (cell != NULL) {
|
|
buf = (uint32_t *)nvmem_cell_read(cell, NULL);
|
|
nvmem_cell_put(cell);
|
|
|
|
if (IS_ERR(buf)) {
|
|
LOG_ERR("[%s] nvmem_cell_read fail\n", __func__);
|
|
return PTR_ERR(buf);
|
|
}
|
|
|
|
if (buf != NULL) {
|
|
g_efuse_ptpod = *buf;
|
|
kfree(buf);
|
|
}
|
|
} else
|
|
LOG_ERR("[%s] cell was null\n", __func__);
|
|
|
|
return 0;
|
|
}
|
|
#endif // CONFIG_MTK_DEVINFO
|
|
|
|
static int apu_dvfs_probe(struct platform_device *pdev)
|
|
{
|
|
int ret;
|
|
struct resource *res;
|
|
struct device_node *ipu_conn_node = NULL;
|
|
struct device_node *ct_node = NULL;
|
|
u32 ct_flag = 0;
|
|
|
|
#ifdef CONFIG_MTK_DEVINFO
|
|
get_nvmem_cell_efuse(&pdev->dev);
|
|
#endif
|
|
dvfs = devm_kzalloc(&pdev->dev, sizeof(*dvfs), GFP_KERNEL);
|
|
if (!dvfs)
|
|
return -ENOMEM;
|
|
|
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
LOG_DBG("%s\n", __func__);
|
|
|
|
dvfs->regs = devm_ioremap_resource(&pdev->dev, res);
|
|
if (IS_ERR(dvfs->regs))
|
|
return PTR_ERR(dvfs->regs);
|
|
platform_set_drvdata(pdev, dvfs);
|
|
|
|
dvfs->dvfs_node = of_find_compatible_node(
|
|
NULL, NULL, "mediatek,apu_dvfs");
|
|
|
|
ipu_conn_node = of_find_compatible_node(NULL, NULL,
|
|
"mediatek,ipu_conn");
|
|
|
|
apu_syscfg_base =
|
|
(unsigned long) of_iomap(ipu_conn_node, 0);
|
|
|
|
|
|
/*enable Vvpu Vmdla*/
|
|
/*--Get regulator handle--*/
|
|
vvpu_reg_id = regulator_get(&pdev->dev, "vpu");
|
|
if (!vvpu_reg_id)
|
|
LOG_ERR("regulator_get vvpu_reg_id failed\n");
|
|
vmdla_reg_id = regulator_get(&pdev->dev, "VMDLA");
|
|
if (!vmdla_reg_id)
|
|
LOG_ERR("regulator_get vmdla_reg_id failed\n");
|
|
vcore_reg_id = regulator_get(&pdev->dev, "vcore");
|
|
if (!vcore_reg_id)
|
|
LOG_ERR("regulator_get vcore_reg_id failed\n");
|
|
vsram_reg_id = regulator_get(&pdev->dev, "vsram_others");
|
|
if (!vsram_reg_id)
|
|
LOG_ERR("regulator_get vsram_reg_id failed\n");
|
|
|
|
ready_for_ptpod_check = false;
|
|
/*--enable regulator--*/
|
|
ret = regulator_enable(vvpu_reg_id);
|
|
udelay(200);//slew rate:rising10mV/us
|
|
if (ret)
|
|
LOG_ERR("regulator_enable vvpu_reg_id failed\n");
|
|
|
|
ret = regulator_enable(vmdla_reg_id);
|
|
udelay(200);
|
|
if (ret)
|
|
LOG_ERR("regulator_enable vmdla_reg_id failed\n");
|
|
|
|
ret = apu_dvfs_add_interface(&pdev->dev);
|
|
|
|
if (ret)
|
|
return ret;
|
|
|
|
pm_qos_notifier_register();
|
|
vvpu_count = 0;
|
|
vmdla_count = 0;
|
|
apu_power_count = 0;
|
|
ct_node = of_find_compatible_node(NULL, NULL, "mediatek,eem_fsm");
|
|
ret = of_property_read_u32(ct_node, "eem-ct", &ct_flag);
|
|
if (ret)
|
|
LOG_ERR("cant find eem-ct node\n");
|
|
if (ct_flag && ptpod_enabled) {
|
|
vpu_disable_by_ptpod();
|
|
mdla_disable_by_ptpod();
|
|
ready_for_ptpod_check = true;
|
|
} else {
|
|
LOG_INF("EEM corner tighten close by DT\n");
|
|
ret = regulator_set_voltage(vvpu_reg_id,
|
|
10*(vpu_opp_table[9].vpufreq_volt),
|
|
850000);
|
|
|
|
ret = regulator_set_voltage(vmdla_reg_id,
|
|
10*(mdla_opp_table[9].mdlafreq_volt),
|
|
850000);
|
|
|
|
udelay(100);
|
|
ret = vvpu_regulator_set_mode(true);
|
|
udelay(100);
|
|
LOG_DVFS("vvpu set normal mode ret=%d\n", ret);
|
|
ret = vmdla_regulator_set_mode(true);
|
|
udelay(100);
|
|
LOG_DVFS("vmdla set normal mode ret=%d\n", ret);
|
|
ret = vvpu_regulator_set_mode(false);
|
|
udelay(100);
|
|
LOG_DVFS("vvpu set sleep mode ret=%d\n", ret);
|
|
ret = vmdla_regulator_set_mode(false);
|
|
udelay(100);
|
|
LOG_DVFS("vmdla set sleep mode ret=%d\n", ret);
|
|
|
|
vvpu_vmdla_vcore_checker();
|
|
}
|
|
|
|
LOG_DVFS("%s: init done\n", __func__);
|
|
|
|
apu_get_power_info();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int apu_dvfs_remove(struct platform_device *pdev)
|
|
{
|
|
apu_dvfs_remove_interface(&pdev->dev);
|
|
return 0;
|
|
}
|
|
|
|
static const struct of_device_id apu_dvfs_of_match[] = {
|
|
{ .compatible = "mediatek,apu_dvfs" },
|
|
{ },
|
|
};
|
|
|
|
MODULE_DEVICE_TABLE(of, apu_dvfs_of_match);
|
|
|
|
static __maybe_unused int apu_dvfs_suspend(struct device *dev)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static __maybe_unused int apu_dvfs_resume(struct device *dev)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static SIMPLE_DEV_PM_OPS(apu_dvfs_pm, apu_dvfs_suspend,
|
|
apu_dvfs_resume);
|
|
|
|
static struct platform_driver apu_dvfs_driver = {
|
|
.probe = apu_dvfs_probe,
|
|
.remove = apu_dvfs_remove,
|
|
.driver = {
|
|
.name = "apu_dvfs",
|
|
.pm = &apu_dvfs_pm,
|
|
.of_match_table = apu_dvfs_of_match,
|
|
},
|
|
};
|
|
|
|
static int __init apu_dvfs_init(void)
|
|
{
|
|
int ret = 0;
|
|
|
|
ret = platform_driver_register(&apu_dvfs_driver);
|
|
return ret;
|
|
}
|
|
late_initcall(apu_dvfs_init)
|
|
|
|
static void __exit apu_dvfs_exit(void)
|
|
{
|
|
//int ret = 0;
|
|
|
|
platform_driver_unregister(&apu_dvfs_driver);
|
|
}
|
|
module_exit(apu_dvfs_exit)
|
|
|
|
MODULE_LICENSE("GPL v2");
|
|
MODULE_DESCRIPTION("apu dvfs driver");
|