162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2022 MediaTek Inc. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/bitfield.h> 762306a36Sopenharmony_ci#include <linux/bits.h> 862306a36Sopenharmony_ci#include <linux/clk.h> 962306a36Sopenharmony_ci#include <linux/completion.h> 1062306a36Sopenharmony_ci#include <linux/cpu.h> 1162306a36Sopenharmony_ci#include <linux/cpuidle.h> 1262306a36Sopenharmony_ci#include <linux/debugfs.h> 1362306a36Sopenharmony_ci#include <linux/device.h> 1462306a36Sopenharmony_ci#include <linux/init.h> 1562306a36Sopenharmony_ci#include <linux/interrupt.h> 1662306a36Sopenharmony_ci#include <linux/kernel.h> 1762306a36Sopenharmony_ci#include <linux/kthread.h> 1862306a36Sopenharmony_ci#include <linux/module.h> 1962306a36Sopenharmony_ci#include <linux/mutex.h> 2062306a36Sopenharmony_ci#include <linux/nvmem-consumer.h> 2162306a36Sopenharmony_ci#include <linux/of_address.h> 2262306a36Sopenharmony_ci#include <linux/of_irq.h> 2362306a36Sopenharmony_ci#include <linux/of_platform.h> 2462306a36Sopenharmony_ci#include <linux/platform_device.h> 2562306a36Sopenharmony_ci#include <linux/pm_domain.h> 2662306a36Sopenharmony_ci#include <linux/pm_opp.h> 2762306a36Sopenharmony_ci#include <linux/pm_runtime.h> 2862306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 2962306a36Sopenharmony_ci#include <linux/reset.h> 3062306a36Sopenharmony_ci#include <linux/seq_file.h> 3162306a36Sopenharmony_ci#include <linux/slab.h> 3262306a36Sopenharmony_ci#include <linux/spinlock.h> 3362306a36Sopenharmony_ci#include <linux/thermal.h> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* svs bank 1-line software id */ 3662306a36Sopenharmony_ci#define SVSB_CPU_LITTLE BIT(0) 3762306a36Sopenharmony_ci#define SVSB_CPU_BIG BIT(1) 3862306a36Sopenharmony_ci#define SVSB_CCI BIT(2) 3962306a36Sopenharmony_ci#define SVSB_GPU BIT(3) 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* svs bank 2-line type */ 4262306a36Sopenharmony_ci#define SVSB_LOW BIT(8) 4362306a36Sopenharmony_ci#define SVSB_HIGH BIT(9) 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* svs bank mode support */ 4662306a36Sopenharmony_ci#define SVSB_MODE_ALL_DISABLE 0 4762306a36Sopenharmony_ci#define SVSB_MODE_INIT01 BIT(1) 4862306a36Sopenharmony_ci#define SVSB_MODE_INIT02 BIT(2) 4962306a36Sopenharmony_ci#define SVSB_MODE_MON BIT(3) 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/* svs bank volt flags */ 5262306a36Sopenharmony_ci#define SVSB_INIT01_PD_REQ BIT(0) 5362306a36Sopenharmony_ci#define SVSB_INIT01_VOLT_IGNORE BIT(1) 5462306a36Sopenharmony_ci#define SVSB_INIT01_VOLT_INC_ONLY BIT(2) 5562306a36Sopenharmony_ci#define SVSB_MON_VOLT_IGNORE BIT(16) 5662306a36Sopenharmony_ci#define SVSB_REMOVE_DVTFIXED_VOLT BIT(24) 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/* svs bank register fields and common configuration */ 5962306a36Sopenharmony_ci#define SVSB_PTPCONFIG_DETMAX GENMASK(15, 0) 6062306a36Sopenharmony_ci#define SVSB_DET_MAX FIELD_PREP(SVSB_PTPCONFIG_DETMAX, 0xffff) 6162306a36Sopenharmony_ci#define SVSB_DET_WINDOW 0xa28 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* DESCHAR */ 6462306a36Sopenharmony_ci#define SVSB_DESCHAR_FLD_MDES GENMASK(7, 0) 6562306a36Sopenharmony_ci#define SVSB_DESCHAR_FLD_BDES GENMASK(15, 8) 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/* TEMPCHAR */ 6862306a36Sopenharmony_ci#define SVSB_TEMPCHAR_FLD_DVT_FIXED GENMASK(7, 0) 6962306a36Sopenharmony_ci#define SVSB_TEMPCHAR_FLD_MTDES GENMASK(15, 8) 7062306a36Sopenharmony_ci#define SVSB_TEMPCHAR_FLD_VCO GENMASK(23, 16) 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/* DETCHAR */ 7362306a36Sopenharmony_ci#define SVSB_DETCHAR_FLD_DCMDET GENMASK(7, 0) 7462306a36Sopenharmony_ci#define SVSB_DETCHAR_FLD_DCBDET GENMASK(15, 8) 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/* SVSEN (PTPEN) */ 7762306a36Sopenharmony_ci#define SVSB_PTPEN_INIT01 BIT(0) 7862306a36Sopenharmony_ci#define SVSB_PTPEN_MON BIT(1) 7962306a36Sopenharmony_ci#define SVSB_PTPEN_INIT02 (SVSB_PTPEN_INIT01 | BIT(2)) 8062306a36Sopenharmony_ci#define SVSB_PTPEN_OFF 0x0 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* FREQPCTS */ 8362306a36Sopenharmony_ci#define SVSB_FREQPCTS_FLD_PCT0_4 GENMASK(7, 0) 8462306a36Sopenharmony_ci#define SVSB_FREQPCTS_FLD_PCT1_5 GENMASK(15, 8) 8562306a36Sopenharmony_ci#define SVSB_FREQPCTS_FLD_PCT2_6 GENMASK(23, 16) 8662306a36Sopenharmony_ci#define SVSB_FREQPCTS_FLD_PCT3_7 GENMASK(31, 24) 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci/* INTSTS */ 8962306a36Sopenharmony_ci#define SVSB_INTSTS_VAL_CLEAN 0x00ffffff 9062306a36Sopenharmony_ci#define SVSB_INTSTS_F0_COMPLETE BIT(0) 9162306a36Sopenharmony_ci#define SVSB_INTSTS_FLD_MONVOP GENMASK(23, 16) 9262306a36Sopenharmony_ci#define SVSB_RUNCONFIG_DEFAULT 0x80000000 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci/* LIMITVALS */ 9562306a36Sopenharmony_ci#define SVSB_LIMITVALS_FLD_DTLO GENMASK(7, 0) 9662306a36Sopenharmony_ci#define SVSB_LIMITVALS_FLD_DTHI GENMASK(15, 8) 9762306a36Sopenharmony_ci#define SVSB_LIMITVALS_FLD_VMIN GENMASK(23, 16) 9862306a36Sopenharmony_ci#define SVSB_LIMITVALS_FLD_VMAX GENMASK(31, 24) 9962306a36Sopenharmony_ci#define SVSB_VAL_DTHI 0x1 10062306a36Sopenharmony_ci#define SVSB_VAL_DTLO 0xfe 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci/* INTEN */ 10362306a36Sopenharmony_ci#define SVSB_INTEN_F0EN BIT(0) 10462306a36Sopenharmony_ci#define SVSB_INTEN_DACK0UPEN BIT(8) 10562306a36Sopenharmony_ci#define SVSB_INTEN_DC0EN BIT(9) 10662306a36Sopenharmony_ci#define SVSB_INTEN_DC1EN BIT(10) 10762306a36Sopenharmony_ci#define SVSB_INTEN_DACK0LOEN BIT(11) 10862306a36Sopenharmony_ci#define SVSB_INTEN_INITPROD_OVF_EN BIT(12) 10962306a36Sopenharmony_ci#define SVSB_INTEN_INITSUM_OVF_EN BIT(14) 11062306a36Sopenharmony_ci#define SVSB_INTEN_MONVOPEN GENMASK(23, 16) 11162306a36Sopenharmony_ci#define SVSB_INTEN_INIT0x (SVSB_INTEN_F0EN | SVSB_INTEN_DACK0UPEN | \ 11262306a36Sopenharmony_ci SVSB_INTEN_DC0EN | SVSB_INTEN_DC1EN | \ 11362306a36Sopenharmony_ci SVSB_INTEN_DACK0LOEN | \ 11462306a36Sopenharmony_ci SVSB_INTEN_INITPROD_OVF_EN | \ 11562306a36Sopenharmony_ci SVSB_INTEN_INITSUM_OVF_EN) 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci/* TSCALCS */ 11862306a36Sopenharmony_ci#define SVSB_TSCALCS_FLD_MTS GENMASK(11, 0) 11962306a36Sopenharmony_ci#define SVSB_TSCALCS_FLD_BTS GENMASK(23, 12) 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/* INIT2VALS */ 12262306a36Sopenharmony_ci#define SVSB_INIT2VALS_FLD_DCVOFFSETIN GENMASK(15, 0) 12362306a36Sopenharmony_ci#define SVSB_INIT2VALS_FLD_AGEVOFFSETIN GENMASK(31, 16) 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci/* VOPS */ 12662306a36Sopenharmony_ci#define SVSB_VOPS_FLD_VOP0_4 GENMASK(7, 0) 12762306a36Sopenharmony_ci#define SVSB_VOPS_FLD_VOP1_5 GENMASK(15, 8) 12862306a36Sopenharmony_ci#define SVSB_VOPS_FLD_VOP2_6 GENMASK(23, 16) 12962306a36Sopenharmony_ci#define SVSB_VOPS_FLD_VOP3_7 GENMASK(31, 24) 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci/* svs bank related setting */ 13262306a36Sopenharmony_ci#define BITS8 8 13362306a36Sopenharmony_ci#define MAX_OPP_ENTRIES 16 13462306a36Sopenharmony_ci#define REG_BYTES 4 13562306a36Sopenharmony_ci#define SVSB_DC_SIGNED_BIT BIT(15) 13662306a36Sopenharmony_ci#define SVSB_DET_CLK_EN BIT(31) 13762306a36Sopenharmony_ci#define SVSB_TEMP_LOWER_BOUND 0xb2 13862306a36Sopenharmony_ci#define SVSB_TEMP_UPPER_BOUND 0x64 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic DEFINE_SPINLOCK(svs_lock); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 14362306a36Sopenharmony_ci#define debug_fops_ro(name) \ 14462306a36Sopenharmony_ci static int svs_##name##_debug_open(struct inode *inode, \ 14562306a36Sopenharmony_ci struct file *filp) \ 14662306a36Sopenharmony_ci { \ 14762306a36Sopenharmony_ci return single_open(filp, svs_##name##_debug_show, \ 14862306a36Sopenharmony_ci inode->i_private); \ 14962306a36Sopenharmony_ci } \ 15062306a36Sopenharmony_ci static const struct file_operations svs_##name##_debug_fops = { \ 15162306a36Sopenharmony_ci .owner = THIS_MODULE, \ 15262306a36Sopenharmony_ci .open = svs_##name##_debug_open, \ 15362306a36Sopenharmony_ci .read = seq_read, \ 15462306a36Sopenharmony_ci .llseek = seq_lseek, \ 15562306a36Sopenharmony_ci .release = single_release, \ 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci#define debug_fops_rw(name) \ 15962306a36Sopenharmony_ci static int svs_##name##_debug_open(struct inode *inode, \ 16062306a36Sopenharmony_ci struct file *filp) \ 16162306a36Sopenharmony_ci { \ 16262306a36Sopenharmony_ci return single_open(filp, svs_##name##_debug_show, \ 16362306a36Sopenharmony_ci inode->i_private); \ 16462306a36Sopenharmony_ci } \ 16562306a36Sopenharmony_ci static const struct file_operations svs_##name##_debug_fops = { \ 16662306a36Sopenharmony_ci .owner = THIS_MODULE, \ 16762306a36Sopenharmony_ci .open = svs_##name##_debug_open, \ 16862306a36Sopenharmony_ci .read = seq_read, \ 16962306a36Sopenharmony_ci .write = svs_##name##_debug_write, \ 17062306a36Sopenharmony_ci .llseek = seq_lseek, \ 17162306a36Sopenharmony_ci .release = single_release, \ 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci#define svs_dentry_data(name) {__stringify(name), &svs_##name##_debug_fops} 17562306a36Sopenharmony_ci#endif 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci/** 17862306a36Sopenharmony_ci * enum svsb_phase - svs bank phase enumeration 17962306a36Sopenharmony_ci * @SVSB_PHASE_ERROR: svs bank encounters unexpected condition 18062306a36Sopenharmony_ci * @SVSB_PHASE_INIT01: svs bank basic init for data calibration 18162306a36Sopenharmony_ci * @SVSB_PHASE_INIT02: svs bank can provide voltages to opp table 18262306a36Sopenharmony_ci * @SVSB_PHASE_MON: svs bank can provide voltages with thermal effect 18362306a36Sopenharmony_ci * @SVSB_PHASE_MAX: total number of svs bank phase (debug purpose) 18462306a36Sopenharmony_ci * 18562306a36Sopenharmony_ci * Each svs bank has its own independent phase and we enable each svs bank by 18662306a36Sopenharmony_ci * running their phase orderly. However, when svs bank encounters unexpected 18762306a36Sopenharmony_ci * condition, it will fire an irq (PHASE_ERROR) to inform svs software. 18862306a36Sopenharmony_ci * 18962306a36Sopenharmony_ci * svs bank general phase-enabled order: 19062306a36Sopenharmony_ci * SVSB_PHASE_INIT01 -> SVSB_PHASE_INIT02 -> SVSB_PHASE_MON 19162306a36Sopenharmony_ci */ 19262306a36Sopenharmony_cienum svsb_phase { 19362306a36Sopenharmony_ci SVSB_PHASE_ERROR = 0, 19462306a36Sopenharmony_ci SVSB_PHASE_INIT01, 19562306a36Sopenharmony_ci SVSB_PHASE_INIT02, 19662306a36Sopenharmony_ci SVSB_PHASE_MON, 19762306a36Sopenharmony_ci SVSB_PHASE_MAX, 19862306a36Sopenharmony_ci}; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cienum svs_reg_index { 20162306a36Sopenharmony_ci DESCHAR = 0, 20262306a36Sopenharmony_ci TEMPCHAR, 20362306a36Sopenharmony_ci DETCHAR, 20462306a36Sopenharmony_ci AGECHAR, 20562306a36Sopenharmony_ci DCCONFIG, 20662306a36Sopenharmony_ci AGECONFIG, 20762306a36Sopenharmony_ci FREQPCT30, 20862306a36Sopenharmony_ci FREQPCT74, 20962306a36Sopenharmony_ci LIMITVALS, 21062306a36Sopenharmony_ci VBOOT, 21162306a36Sopenharmony_ci DETWINDOW, 21262306a36Sopenharmony_ci CONFIG, 21362306a36Sopenharmony_ci TSCALCS, 21462306a36Sopenharmony_ci RUNCONFIG, 21562306a36Sopenharmony_ci SVSEN, 21662306a36Sopenharmony_ci INIT2VALS, 21762306a36Sopenharmony_ci DCVALUES, 21862306a36Sopenharmony_ci AGEVALUES, 21962306a36Sopenharmony_ci VOP30, 22062306a36Sopenharmony_ci VOP74, 22162306a36Sopenharmony_ci TEMP, 22262306a36Sopenharmony_ci INTSTS, 22362306a36Sopenharmony_ci INTSTSRAW, 22462306a36Sopenharmony_ci INTEN, 22562306a36Sopenharmony_ci CHKINT, 22662306a36Sopenharmony_ci CHKSHIFT, 22762306a36Sopenharmony_ci STATUS, 22862306a36Sopenharmony_ci VDESIGN30, 22962306a36Sopenharmony_ci VDESIGN74, 23062306a36Sopenharmony_ci DVT30, 23162306a36Sopenharmony_ci DVT74, 23262306a36Sopenharmony_ci AGECOUNT, 23362306a36Sopenharmony_ci SMSTATE0, 23462306a36Sopenharmony_ci SMSTATE1, 23562306a36Sopenharmony_ci CTL0, 23662306a36Sopenharmony_ci DESDETSEC, 23762306a36Sopenharmony_ci TEMPAGESEC, 23862306a36Sopenharmony_ci CTRLSPARE0, 23962306a36Sopenharmony_ci CTRLSPARE1, 24062306a36Sopenharmony_ci CTRLSPARE2, 24162306a36Sopenharmony_ci CTRLSPARE3, 24262306a36Sopenharmony_ci CORESEL, 24362306a36Sopenharmony_ci THERMINTST, 24462306a36Sopenharmony_ci INTST, 24562306a36Sopenharmony_ci THSTAGE0ST, 24662306a36Sopenharmony_ci THSTAGE1ST, 24762306a36Sopenharmony_ci THSTAGE2ST, 24862306a36Sopenharmony_ci THAHBST0, 24962306a36Sopenharmony_ci THAHBST1, 25062306a36Sopenharmony_ci SPARE0, 25162306a36Sopenharmony_ci SPARE1, 25262306a36Sopenharmony_ci SPARE2, 25362306a36Sopenharmony_ci SPARE3, 25462306a36Sopenharmony_ci THSLPEVEB, 25562306a36Sopenharmony_ci SVS_REG_MAX, 25662306a36Sopenharmony_ci}; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic const u32 svs_regs_v2[] = { 25962306a36Sopenharmony_ci [DESCHAR] = 0xc00, 26062306a36Sopenharmony_ci [TEMPCHAR] = 0xc04, 26162306a36Sopenharmony_ci [DETCHAR] = 0xc08, 26262306a36Sopenharmony_ci [AGECHAR] = 0xc0c, 26362306a36Sopenharmony_ci [DCCONFIG] = 0xc10, 26462306a36Sopenharmony_ci [AGECONFIG] = 0xc14, 26562306a36Sopenharmony_ci [FREQPCT30] = 0xc18, 26662306a36Sopenharmony_ci [FREQPCT74] = 0xc1c, 26762306a36Sopenharmony_ci [LIMITVALS] = 0xc20, 26862306a36Sopenharmony_ci [VBOOT] = 0xc24, 26962306a36Sopenharmony_ci [DETWINDOW] = 0xc28, 27062306a36Sopenharmony_ci [CONFIG] = 0xc2c, 27162306a36Sopenharmony_ci [TSCALCS] = 0xc30, 27262306a36Sopenharmony_ci [RUNCONFIG] = 0xc34, 27362306a36Sopenharmony_ci [SVSEN] = 0xc38, 27462306a36Sopenharmony_ci [INIT2VALS] = 0xc3c, 27562306a36Sopenharmony_ci [DCVALUES] = 0xc40, 27662306a36Sopenharmony_ci [AGEVALUES] = 0xc44, 27762306a36Sopenharmony_ci [VOP30] = 0xc48, 27862306a36Sopenharmony_ci [VOP74] = 0xc4c, 27962306a36Sopenharmony_ci [TEMP] = 0xc50, 28062306a36Sopenharmony_ci [INTSTS] = 0xc54, 28162306a36Sopenharmony_ci [INTSTSRAW] = 0xc58, 28262306a36Sopenharmony_ci [INTEN] = 0xc5c, 28362306a36Sopenharmony_ci [CHKINT] = 0xc60, 28462306a36Sopenharmony_ci [CHKSHIFT] = 0xc64, 28562306a36Sopenharmony_ci [STATUS] = 0xc68, 28662306a36Sopenharmony_ci [VDESIGN30] = 0xc6c, 28762306a36Sopenharmony_ci [VDESIGN74] = 0xc70, 28862306a36Sopenharmony_ci [DVT30] = 0xc74, 28962306a36Sopenharmony_ci [DVT74] = 0xc78, 29062306a36Sopenharmony_ci [AGECOUNT] = 0xc7c, 29162306a36Sopenharmony_ci [SMSTATE0] = 0xc80, 29262306a36Sopenharmony_ci [SMSTATE1] = 0xc84, 29362306a36Sopenharmony_ci [CTL0] = 0xc88, 29462306a36Sopenharmony_ci [DESDETSEC] = 0xce0, 29562306a36Sopenharmony_ci [TEMPAGESEC] = 0xce4, 29662306a36Sopenharmony_ci [CTRLSPARE0] = 0xcf0, 29762306a36Sopenharmony_ci [CTRLSPARE1] = 0xcf4, 29862306a36Sopenharmony_ci [CTRLSPARE2] = 0xcf8, 29962306a36Sopenharmony_ci [CTRLSPARE3] = 0xcfc, 30062306a36Sopenharmony_ci [CORESEL] = 0xf00, 30162306a36Sopenharmony_ci [THERMINTST] = 0xf04, 30262306a36Sopenharmony_ci [INTST] = 0xf08, 30362306a36Sopenharmony_ci [THSTAGE0ST] = 0xf0c, 30462306a36Sopenharmony_ci [THSTAGE1ST] = 0xf10, 30562306a36Sopenharmony_ci [THSTAGE2ST] = 0xf14, 30662306a36Sopenharmony_ci [THAHBST0] = 0xf18, 30762306a36Sopenharmony_ci [THAHBST1] = 0xf1c, 30862306a36Sopenharmony_ci [SPARE0] = 0xf20, 30962306a36Sopenharmony_ci [SPARE1] = 0xf24, 31062306a36Sopenharmony_ci [SPARE2] = 0xf28, 31162306a36Sopenharmony_ci [SPARE3] = 0xf2c, 31262306a36Sopenharmony_ci [THSLPEVEB] = 0xf30, 31362306a36Sopenharmony_ci}; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci/** 31662306a36Sopenharmony_ci * struct svs_platform - svs platform control 31762306a36Sopenharmony_ci * @base: svs platform register base 31862306a36Sopenharmony_ci * @dev: svs platform device 31962306a36Sopenharmony_ci * @main_clk: main clock for svs bank 32062306a36Sopenharmony_ci * @pbank: svs bank pointer needing to be protected by spin_lock section 32162306a36Sopenharmony_ci * @banks: svs banks that svs platform supports 32262306a36Sopenharmony_ci * @rst: svs platform reset control 32362306a36Sopenharmony_ci * @efuse_max: total number of svs efuse 32462306a36Sopenharmony_ci * @tefuse_max: total number of thermal efuse 32562306a36Sopenharmony_ci * @regs: svs platform registers map 32662306a36Sopenharmony_ci * @bank_max: total number of svs banks 32762306a36Sopenharmony_ci * @efuse: svs efuse data received from NVMEM framework 32862306a36Sopenharmony_ci * @tefuse: thermal efuse data received from NVMEM framework 32962306a36Sopenharmony_ci */ 33062306a36Sopenharmony_cistruct svs_platform { 33162306a36Sopenharmony_ci void __iomem *base; 33262306a36Sopenharmony_ci struct device *dev; 33362306a36Sopenharmony_ci struct clk *main_clk; 33462306a36Sopenharmony_ci struct svs_bank *pbank; 33562306a36Sopenharmony_ci struct svs_bank *banks; 33662306a36Sopenharmony_ci struct reset_control *rst; 33762306a36Sopenharmony_ci size_t efuse_max; 33862306a36Sopenharmony_ci size_t tefuse_max; 33962306a36Sopenharmony_ci const u32 *regs; 34062306a36Sopenharmony_ci u32 bank_max; 34162306a36Sopenharmony_ci u32 *efuse; 34262306a36Sopenharmony_ci u32 *tefuse; 34362306a36Sopenharmony_ci}; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_cistruct svs_platform_data { 34662306a36Sopenharmony_ci char *name; 34762306a36Sopenharmony_ci struct svs_bank *banks; 34862306a36Sopenharmony_ci bool (*efuse_parsing)(struct svs_platform *svsp); 34962306a36Sopenharmony_ci int (*probe)(struct svs_platform *svsp); 35062306a36Sopenharmony_ci const u32 *regs; 35162306a36Sopenharmony_ci u32 bank_max; 35262306a36Sopenharmony_ci}; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci/** 35562306a36Sopenharmony_ci * struct svs_bank - svs bank representation 35662306a36Sopenharmony_ci * @dev: bank device 35762306a36Sopenharmony_ci * @opp_dev: device for opp table/buck control 35862306a36Sopenharmony_ci * @init_completion: the timeout completion for bank init 35962306a36Sopenharmony_ci * @buck: regulator used by opp_dev 36062306a36Sopenharmony_ci * @tzd: thermal zone device for getting temperature 36162306a36Sopenharmony_ci * @lock: mutex lock to protect voltage update process 36262306a36Sopenharmony_ci * @set_freq_pct: function pointer to set bank frequency percent table 36362306a36Sopenharmony_ci * @get_volts: function pointer to get bank voltages 36462306a36Sopenharmony_ci * @name: bank name 36562306a36Sopenharmony_ci * @buck_name: regulator name 36662306a36Sopenharmony_ci * @tzone_name: thermal zone name 36762306a36Sopenharmony_ci * @phase: bank current phase 36862306a36Sopenharmony_ci * @volt_od: bank voltage overdrive 36962306a36Sopenharmony_ci * @reg_data: bank register data in different phase for debug purpose 37062306a36Sopenharmony_ci * @pm_runtime_enabled_count: bank pm runtime enabled count 37162306a36Sopenharmony_ci * @mode_support: bank mode support. 37262306a36Sopenharmony_ci * @freq_base: reference frequency for bank init 37362306a36Sopenharmony_ci * @turn_freq_base: refenrece frequency for 2-line turn point 37462306a36Sopenharmony_ci * @vboot: voltage request for bank init01 only 37562306a36Sopenharmony_ci * @opp_dfreq: default opp frequency table 37662306a36Sopenharmony_ci * @opp_dvolt: default opp voltage table 37762306a36Sopenharmony_ci * @freq_pct: frequency percent table for bank init 37862306a36Sopenharmony_ci * @volt: bank voltage table 37962306a36Sopenharmony_ci * @volt_step: bank voltage step 38062306a36Sopenharmony_ci * @volt_base: bank voltage base 38162306a36Sopenharmony_ci * @volt_flags: bank voltage flags 38262306a36Sopenharmony_ci * @vmax: bank voltage maximum 38362306a36Sopenharmony_ci * @vmin: bank voltage minimum 38462306a36Sopenharmony_ci * @age_config: bank age configuration 38562306a36Sopenharmony_ci * @age_voffset_in: bank age voltage offset 38662306a36Sopenharmony_ci * @dc_config: bank dc configuration 38762306a36Sopenharmony_ci * @dc_voffset_in: bank dc voltage offset 38862306a36Sopenharmony_ci * @dvt_fixed: bank dvt fixed value 38962306a36Sopenharmony_ci * @vco: bank VCO value 39062306a36Sopenharmony_ci * @chk_shift: bank chicken shift 39162306a36Sopenharmony_ci * @core_sel: bank selection 39262306a36Sopenharmony_ci * @opp_count: bank opp count 39362306a36Sopenharmony_ci * @int_st: bank interrupt identification 39462306a36Sopenharmony_ci * @sw_id: bank software identification 39562306a36Sopenharmony_ci * @cpu_id: cpu core id for SVS CPU bank use only 39662306a36Sopenharmony_ci * @ctl0: TS-x selection 39762306a36Sopenharmony_ci * @temp: bank temperature 39862306a36Sopenharmony_ci * @tzone_htemp: thermal zone high temperature threshold 39962306a36Sopenharmony_ci * @tzone_htemp_voffset: thermal zone high temperature voltage offset 40062306a36Sopenharmony_ci * @tzone_ltemp: thermal zone low temperature threshold 40162306a36Sopenharmony_ci * @tzone_ltemp_voffset: thermal zone low temperature voltage offset 40262306a36Sopenharmony_ci * @bts: svs efuse data 40362306a36Sopenharmony_ci * @mts: svs efuse data 40462306a36Sopenharmony_ci * @bdes: svs efuse data 40562306a36Sopenharmony_ci * @mdes: svs efuse data 40662306a36Sopenharmony_ci * @mtdes: svs efuse data 40762306a36Sopenharmony_ci * @dcbdet: svs efuse data 40862306a36Sopenharmony_ci * @dcmdet: svs efuse data 40962306a36Sopenharmony_ci * @turn_pt: 2-line turn point tells which opp_volt calculated by high/low bank 41062306a36Sopenharmony_ci * @type: bank type to represent it is 2-line (high/low) bank or 1-line bank 41162306a36Sopenharmony_ci * 41262306a36Sopenharmony_ci * Svs bank will generate suitalbe voltages by below general math equation 41362306a36Sopenharmony_ci * and provide these voltages to opp voltage table. 41462306a36Sopenharmony_ci * 41562306a36Sopenharmony_ci * opp_volt[i] = (volt[i] * volt_step) + volt_base; 41662306a36Sopenharmony_ci */ 41762306a36Sopenharmony_cistruct svs_bank { 41862306a36Sopenharmony_ci struct device *dev; 41962306a36Sopenharmony_ci struct device *opp_dev; 42062306a36Sopenharmony_ci struct completion init_completion; 42162306a36Sopenharmony_ci struct regulator *buck; 42262306a36Sopenharmony_ci struct thermal_zone_device *tzd; 42362306a36Sopenharmony_ci struct mutex lock; /* lock to protect voltage update process */ 42462306a36Sopenharmony_ci void (*set_freq_pct)(struct svs_platform *svsp); 42562306a36Sopenharmony_ci void (*get_volts)(struct svs_platform *svsp); 42662306a36Sopenharmony_ci char *name; 42762306a36Sopenharmony_ci char *buck_name; 42862306a36Sopenharmony_ci char *tzone_name; 42962306a36Sopenharmony_ci enum svsb_phase phase; 43062306a36Sopenharmony_ci s32 volt_od; 43162306a36Sopenharmony_ci u32 reg_data[SVSB_PHASE_MAX][SVS_REG_MAX]; 43262306a36Sopenharmony_ci u32 pm_runtime_enabled_count; 43362306a36Sopenharmony_ci u32 mode_support; 43462306a36Sopenharmony_ci u32 freq_base; 43562306a36Sopenharmony_ci u32 turn_freq_base; 43662306a36Sopenharmony_ci u32 vboot; 43762306a36Sopenharmony_ci u32 opp_dfreq[MAX_OPP_ENTRIES]; 43862306a36Sopenharmony_ci u32 opp_dvolt[MAX_OPP_ENTRIES]; 43962306a36Sopenharmony_ci u32 freq_pct[MAX_OPP_ENTRIES]; 44062306a36Sopenharmony_ci u32 volt[MAX_OPP_ENTRIES]; 44162306a36Sopenharmony_ci u32 volt_step; 44262306a36Sopenharmony_ci u32 volt_base; 44362306a36Sopenharmony_ci u32 volt_flags; 44462306a36Sopenharmony_ci u32 vmax; 44562306a36Sopenharmony_ci u32 vmin; 44662306a36Sopenharmony_ci u32 age_config; 44762306a36Sopenharmony_ci u32 age_voffset_in; 44862306a36Sopenharmony_ci u32 dc_config; 44962306a36Sopenharmony_ci u32 dc_voffset_in; 45062306a36Sopenharmony_ci u32 dvt_fixed; 45162306a36Sopenharmony_ci u32 vco; 45262306a36Sopenharmony_ci u32 chk_shift; 45362306a36Sopenharmony_ci u32 core_sel; 45462306a36Sopenharmony_ci u32 opp_count; 45562306a36Sopenharmony_ci u32 int_st; 45662306a36Sopenharmony_ci u32 sw_id; 45762306a36Sopenharmony_ci u32 cpu_id; 45862306a36Sopenharmony_ci u32 ctl0; 45962306a36Sopenharmony_ci u32 temp; 46062306a36Sopenharmony_ci u32 tzone_htemp; 46162306a36Sopenharmony_ci u32 tzone_htemp_voffset; 46262306a36Sopenharmony_ci u32 tzone_ltemp; 46362306a36Sopenharmony_ci u32 tzone_ltemp_voffset; 46462306a36Sopenharmony_ci u32 bts; 46562306a36Sopenharmony_ci u32 mts; 46662306a36Sopenharmony_ci u32 bdes; 46762306a36Sopenharmony_ci u32 mdes; 46862306a36Sopenharmony_ci u32 mtdes; 46962306a36Sopenharmony_ci u32 dcbdet; 47062306a36Sopenharmony_ci u32 dcmdet; 47162306a36Sopenharmony_ci u32 turn_pt; 47262306a36Sopenharmony_ci u32 type; 47362306a36Sopenharmony_ci}; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic u32 percent(u32 numerator, u32 denominator) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci /* If not divide 1000, "numerator * 100" will have data overflow. */ 47862306a36Sopenharmony_ci numerator /= 1000; 47962306a36Sopenharmony_ci denominator /= 1000; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci return DIV_ROUND_UP(numerator * 100, denominator); 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic u32 svs_readl_relaxed(struct svs_platform *svsp, enum svs_reg_index rg_i) 48562306a36Sopenharmony_ci{ 48662306a36Sopenharmony_ci return readl_relaxed(svsp->base + svsp->regs[rg_i]); 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistatic void svs_writel_relaxed(struct svs_platform *svsp, u32 val, 49062306a36Sopenharmony_ci enum svs_reg_index rg_i) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci writel_relaxed(val, svsp->base + svsp->regs[rg_i]); 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_cistatic void svs_switch_bank(struct svs_platform *svsp) 49662306a36Sopenharmony_ci{ 49762306a36Sopenharmony_ci struct svs_bank *svsb = svsp->pbank; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci svs_writel_relaxed(svsp, svsb->core_sel, CORESEL); 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic u32 svs_bank_volt_to_opp_volt(u32 svsb_volt, u32 svsb_volt_step, 50362306a36Sopenharmony_ci u32 svsb_volt_base) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci return (svsb_volt * svsb_volt_step) + svsb_volt_base; 50662306a36Sopenharmony_ci} 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_cistatic u32 svs_opp_volt_to_bank_volt(u32 opp_u_volt, u32 svsb_volt_step, 50962306a36Sopenharmony_ci u32 svsb_volt_base) 51062306a36Sopenharmony_ci{ 51162306a36Sopenharmony_ci return (opp_u_volt - svsb_volt_base) / svsb_volt_step; 51262306a36Sopenharmony_ci} 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_cistatic int svs_sync_bank_volts_from_opp(struct svs_bank *svsb) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci struct dev_pm_opp *opp; 51762306a36Sopenharmony_ci u32 i, opp_u_volt; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci for (i = 0; i < svsb->opp_count; i++) { 52062306a36Sopenharmony_ci opp = dev_pm_opp_find_freq_exact(svsb->opp_dev, 52162306a36Sopenharmony_ci svsb->opp_dfreq[i], 52262306a36Sopenharmony_ci true); 52362306a36Sopenharmony_ci if (IS_ERR(opp)) { 52462306a36Sopenharmony_ci dev_err(svsb->dev, "cannot find freq = %u (%ld)\n", 52562306a36Sopenharmony_ci svsb->opp_dfreq[i], PTR_ERR(opp)); 52662306a36Sopenharmony_ci return PTR_ERR(opp); 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci opp_u_volt = dev_pm_opp_get_voltage(opp); 53062306a36Sopenharmony_ci svsb->volt[i] = svs_opp_volt_to_bank_volt(opp_u_volt, 53162306a36Sopenharmony_ci svsb->volt_step, 53262306a36Sopenharmony_ci svsb->volt_base); 53362306a36Sopenharmony_ci dev_pm_opp_put(opp); 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci return 0; 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic int svs_adjust_pm_opp_volts(struct svs_bank *svsb) 54062306a36Sopenharmony_ci{ 54162306a36Sopenharmony_ci int ret = -EPERM, tzone_temp = 0; 54262306a36Sopenharmony_ci u32 i, svsb_volt, opp_volt, temp_voffset = 0, opp_start, opp_stop; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci mutex_lock(&svsb->lock); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci /* 54762306a36Sopenharmony_ci * 2-line bank updates its corresponding opp volts. 54862306a36Sopenharmony_ci * 1-line bank updates all opp volts. 54962306a36Sopenharmony_ci */ 55062306a36Sopenharmony_ci if (svsb->type == SVSB_HIGH) { 55162306a36Sopenharmony_ci opp_start = 0; 55262306a36Sopenharmony_ci opp_stop = svsb->turn_pt; 55362306a36Sopenharmony_ci } else if (svsb->type == SVSB_LOW) { 55462306a36Sopenharmony_ci opp_start = svsb->turn_pt; 55562306a36Sopenharmony_ci opp_stop = svsb->opp_count; 55662306a36Sopenharmony_ci } else { 55762306a36Sopenharmony_ci opp_start = 0; 55862306a36Sopenharmony_ci opp_stop = svsb->opp_count; 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci /* Get thermal effect */ 56262306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(svsb->tzd)) { 56362306a36Sopenharmony_ci ret = thermal_zone_get_temp(svsb->tzd, &tzone_temp); 56462306a36Sopenharmony_ci if (ret || (svsb->temp > SVSB_TEMP_UPPER_BOUND && 56562306a36Sopenharmony_ci svsb->temp < SVSB_TEMP_LOWER_BOUND)) { 56662306a36Sopenharmony_ci dev_err(svsb->dev, "%s: %d (0x%x), run default volts\n", 56762306a36Sopenharmony_ci svsb->tzone_name, ret, svsb->temp); 56862306a36Sopenharmony_ci svsb->phase = SVSB_PHASE_ERROR; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci if (tzone_temp >= svsb->tzone_htemp) 57262306a36Sopenharmony_ci temp_voffset += svsb->tzone_htemp_voffset; 57362306a36Sopenharmony_ci else if (tzone_temp <= svsb->tzone_ltemp) 57462306a36Sopenharmony_ci temp_voffset += svsb->tzone_ltemp_voffset; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci /* 2-line bank update all opp volts when running mon mode */ 57762306a36Sopenharmony_ci if (svsb->phase == SVSB_PHASE_MON && (svsb->type == SVSB_HIGH || 57862306a36Sopenharmony_ci svsb->type == SVSB_LOW)) { 57962306a36Sopenharmony_ci opp_start = 0; 58062306a36Sopenharmony_ci opp_stop = svsb->opp_count; 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci /* vmin <= svsb_volt (opp_volt) <= default opp voltage */ 58562306a36Sopenharmony_ci for (i = opp_start; i < opp_stop; i++) { 58662306a36Sopenharmony_ci switch (svsb->phase) { 58762306a36Sopenharmony_ci case SVSB_PHASE_ERROR: 58862306a36Sopenharmony_ci opp_volt = svsb->opp_dvolt[i]; 58962306a36Sopenharmony_ci break; 59062306a36Sopenharmony_ci case SVSB_PHASE_INIT01: 59162306a36Sopenharmony_ci /* do nothing */ 59262306a36Sopenharmony_ci goto unlock_mutex; 59362306a36Sopenharmony_ci case SVSB_PHASE_INIT02: 59462306a36Sopenharmony_ci case SVSB_PHASE_MON: 59562306a36Sopenharmony_ci svsb_volt = max(svsb->volt[i] + temp_voffset, svsb->vmin); 59662306a36Sopenharmony_ci opp_volt = svs_bank_volt_to_opp_volt(svsb_volt, 59762306a36Sopenharmony_ci svsb->volt_step, 59862306a36Sopenharmony_ci svsb->volt_base); 59962306a36Sopenharmony_ci break; 60062306a36Sopenharmony_ci default: 60162306a36Sopenharmony_ci dev_err(svsb->dev, "unknown phase: %u\n", svsb->phase); 60262306a36Sopenharmony_ci ret = -EINVAL; 60362306a36Sopenharmony_ci goto unlock_mutex; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci opp_volt = min(opp_volt, svsb->opp_dvolt[i]); 60762306a36Sopenharmony_ci ret = dev_pm_opp_adjust_voltage(svsb->opp_dev, 60862306a36Sopenharmony_ci svsb->opp_dfreq[i], 60962306a36Sopenharmony_ci opp_volt, opp_volt, 61062306a36Sopenharmony_ci svsb->opp_dvolt[i]); 61162306a36Sopenharmony_ci if (ret) { 61262306a36Sopenharmony_ci dev_err(svsb->dev, "set %uuV fail: %d\n", 61362306a36Sopenharmony_ci opp_volt, ret); 61462306a36Sopenharmony_ci goto unlock_mutex; 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ciunlock_mutex: 61962306a36Sopenharmony_ci mutex_unlock(&svsb->lock); 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci return ret; 62262306a36Sopenharmony_ci} 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_cistatic void svs_bank_disable_and_restore_default_volts(struct svs_platform *svsp, 62562306a36Sopenharmony_ci struct svs_bank *svsb) 62662306a36Sopenharmony_ci{ 62762306a36Sopenharmony_ci unsigned long flags; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci if (svsb->mode_support == SVSB_MODE_ALL_DISABLE) 63062306a36Sopenharmony_ci return; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci spin_lock_irqsave(&svs_lock, flags); 63362306a36Sopenharmony_ci svsp->pbank = svsb; 63462306a36Sopenharmony_ci svs_switch_bank(svsp); 63562306a36Sopenharmony_ci svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN); 63662306a36Sopenharmony_ci svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS); 63762306a36Sopenharmony_ci spin_unlock_irqrestore(&svs_lock, flags); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci svsb->phase = SVSB_PHASE_ERROR; 64062306a36Sopenharmony_ci svs_adjust_pm_opp_volts(svsb); 64162306a36Sopenharmony_ci} 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 64462306a36Sopenharmony_cistatic int svs_dump_debug_show(struct seq_file *m, void *p) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci struct svs_platform *svsp = (struct svs_platform *)m->private; 64762306a36Sopenharmony_ci struct svs_bank *svsb; 64862306a36Sopenharmony_ci unsigned long svs_reg_addr; 64962306a36Sopenharmony_ci u32 idx, i, j, bank_id; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci for (i = 0; i < svsp->efuse_max; i++) 65262306a36Sopenharmony_ci if (svsp->efuse && svsp->efuse[i]) 65362306a36Sopenharmony_ci seq_printf(m, "M_HW_RES%d = 0x%08x\n", 65462306a36Sopenharmony_ci i, svsp->efuse[i]); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci for (i = 0; i < svsp->tefuse_max; i++) 65762306a36Sopenharmony_ci if (svsp->tefuse) 65862306a36Sopenharmony_ci seq_printf(m, "THERMAL_EFUSE%d = 0x%08x\n", 65962306a36Sopenharmony_ci i, svsp->tefuse[i]); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci for (bank_id = 0, idx = 0; idx < svsp->bank_max; idx++, bank_id++) { 66262306a36Sopenharmony_ci svsb = &svsp->banks[idx]; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci for (i = SVSB_PHASE_INIT01; i <= SVSB_PHASE_MON; i++) { 66562306a36Sopenharmony_ci seq_printf(m, "Bank_number = %u\n", bank_id); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci if (i == SVSB_PHASE_INIT01 || i == SVSB_PHASE_INIT02) 66862306a36Sopenharmony_ci seq_printf(m, "mode = init%d\n", i); 66962306a36Sopenharmony_ci else if (i == SVSB_PHASE_MON) 67062306a36Sopenharmony_ci seq_puts(m, "mode = mon\n"); 67162306a36Sopenharmony_ci else 67262306a36Sopenharmony_ci seq_puts(m, "mode = error\n"); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci for (j = DESCHAR; j < SVS_REG_MAX; j++) { 67562306a36Sopenharmony_ci svs_reg_addr = (unsigned long)(svsp->base + 67662306a36Sopenharmony_ci svsp->regs[j]); 67762306a36Sopenharmony_ci seq_printf(m, "0x%08lx = 0x%08x\n", 67862306a36Sopenharmony_ci svs_reg_addr, svsb->reg_data[i][j]); 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci return 0; 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_cidebug_fops_ro(dump); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_cistatic int svs_enable_debug_show(struct seq_file *m, void *v) 68962306a36Sopenharmony_ci{ 69062306a36Sopenharmony_ci struct svs_bank *svsb = (struct svs_bank *)m->private; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci switch (svsb->phase) { 69362306a36Sopenharmony_ci case SVSB_PHASE_ERROR: 69462306a36Sopenharmony_ci seq_puts(m, "disabled\n"); 69562306a36Sopenharmony_ci break; 69662306a36Sopenharmony_ci case SVSB_PHASE_INIT01: 69762306a36Sopenharmony_ci seq_puts(m, "init1\n"); 69862306a36Sopenharmony_ci break; 69962306a36Sopenharmony_ci case SVSB_PHASE_INIT02: 70062306a36Sopenharmony_ci seq_puts(m, "init2\n"); 70162306a36Sopenharmony_ci break; 70262306a36Sopenharmony_ci case SVSB_PHASE_MON: 70362306a36Sopenharmony_ci seq_puts(m, "mon mode\n"); 70462306a36Sopenharmony_ci break; 70562306a36Sopenharmony_ci default: 70662306a36Sopenharmony_ci seq_puts(m, "unknown\n"); 70762306a36Sopenharmony_ci break; 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci return 0; 71162306a36Sopenharmony_ci} 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_cistatic ssize_t svs_enable_debug_write(struct file *filp, 71462306a36Sopenharmony_ci const char __user *buffer, 71562306a36Sopenharmony_ci size_t count, loff_t *pos) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci struct svs_bank *svsb = file_inode(filp)->i_private; 71862306a36Sopenharmony_ci struct svs_platform *svsp = dev_get_drvdata(svsb->dev); 71962306a36Sopenharmony_ci int enabled, ret; 72062306a36Sopenharmony_ci char *buf = NULL; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci if (count >= PAGE_SIZE) 72362306a36Sopenharmony_ci return -EINVAL; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci buf = (char *)memdup_user_nul(buffer, count); 72662306a36Sopenharmony_ci if (IS_ERR(buf)) 72762306a36Sopenharmony_ci return PTR_ERR(buf); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci ret = kstrtoint(buf, 10, &enabled); 73062306a36Sopenharmony_ci if (ret) 73162306a36Sopenharmony_ci return ret; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci if (!enabled) { 73462306a36Sopenharmony_ci svs_bank_disable_and_restore_default_volts(svsp, svsb); 73562306a36Sopenharmony_ci svsb->mode_support = SVSB_MODE_ALL_DISABLE; 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci kfree(buf); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci return count; 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_cidebug_fops_rw(enable); 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_cistatic int svs_status_debug_show(struct seq_file *m, void *v) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci struct svs_bank *svsb = (struct svs_bank *)m->private; 74862306a36Sopenharmony_ci struct dev_pm_opp *opp; 74962306a36Sopenharmony_ci int tzone_temp = 0, ret; 75062306a36Sopenharmony_ci u32 i; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci ret = thermal_zone_get_temp(svsb->tzd, &tzone_temp); 75362306a36Sopenharmony_ci if (ret) 75462306a36Sopenharmony_ci seq_printf(m, "%s: temperature ignore, turn_pt = %u\n", 75562306a36Sopenharmony_ci svsb->name, svsb->turn_pt); 75662306a36Sopenharmony_ci else 75762306a36Sopenharmony_ci seq_printf(m, "%s: temperature = %d, turn_pt = %u\n", 75862306a36Sopenharmony_ci svsb->name, tzone_temp, svsb->turn_pt); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci for (i = 0; i < svsb->opp_count; i++) { 76162306a36Sopenharmony_ci opp = dev_pm_opp_find_freq_exact(svsb->opp_dev, 76262306a36Sopenharmony_ci svsb->opp_dfreq[i], true); 76362306a36Sopenharmony_ci if (IS_ERR(opp)) { 76462306a36Sopenharmony_ci seq_printf(m, "%s: cannot find freq = %u (%ld)\n", 76562306a36Sopenharmony_ci svsb->name, svsb->opp_dfreq[i], 76662306a36Sopenharmony_ci PTR_ERR(opp)); 76762306a36Sopenharmony_ci return PTR_ERR(opp); 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci seq_printf(m, "opp_freq[%02u]: %u, opp_volt[%02u]: %lu, ", 77162306a36Sopenharmony_ci i, svsb->opp_dfreq[i], i, 77262306a36Sopenharmony_ci dev_pm_opp_get_voltage(opp)); 77362306a36Sopenharmony_ci seq_printf(m, "svsb_volt[%02u]: 0x%x, freq_pct[%02u]: %u\n", 77462306a36Sopenharmony_ci i, svsb->volt[i], i, svsb->freq_pct[i]); 77562306a36Sopenharmony_ci dev_pm_opp_put(opp); 77662306a36Sopenharmony_ci } 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci return 0; 77962306a36Sopenharmony_ci} 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_cidebug_fops_ro(status); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_cistatic int svs_create_debug_cmds(struct svs_platform *svsp) 78462306a36Sopenharmony_ci{ 78562306a36Sopenharmony_ci struct svs_bank *svsb; 78662306a36Sopenharmony_ci struct dentry *svs_dir, *svsb_dir, *file_entry; 78762306a36Sopenharmony_ci const char *d = "/sys/kernel/debug/svs"; 78862306a36Sopenharmony_ci u32 i, idx; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci struct svs_dentry { 79162306a36Sopenharmony_ci const char *name; 79262306a36Sopenharmony_ci const struct file_operations *fops; 79362306a36Sopenharmony_ci }; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci struct svs_dentry svs_entries[] = { 79662306a36Sopenharmony_ci svs_dentry_data(dump), 79762306a36Sopenharmony_ci }; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci struct svs_dentry svsb_entries[] = { 80062306a36Sopenharmony_ci svs_dentry_data(enable), 80162306a36Sopenharmony_ci svs_dentry_data(status), 80262306a36Sopenharmony_ci }; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci svs_dir = debugfs_create_dir("svs", NULL); 80562306a36Sopenharmony_ci if (IS_ERR(svs_dir)) { 80662306a36Sopenharmony_ci dev_err(svsp->dev, "cannot create %s: %ld\n", 80762306a36Sopenharmony_ci d, PTR_ERR(svs_dir)); 80862306a36Sopenharmony_ci return PTR_ERR(svs_dir); 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(svs_entries); i++) { 81262306a36Sopenharmony_ci file_entry = debugfs_create_file(svs_entries[i].name, 0664, 81362306a36Sopenharmony_ci svs_dir, svsp, 81462306a36Sopenharmony_ci svs_entries[i].fops); 81562306a36Sopenharmony_ci if (IS_ERR(file_entry)) { 81662306a36Sopenharmony_ci dev_err(svsp->dev, "cannot create %s/%s: %ld\n", 81762306a36Sopenharmony_ci d, svs_entries[i].name, PTR_ERR(file_entry)); 81862306a36Sopenharmony_ci return PTR_ERR(file_entry); 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci } 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci for (idx = 0; idx < svsp->bank_max; idx++) { 82362306a36Sopenharmony_ci svsb = &svsp->banks[idx]; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci if (svsb->mode_support == SVSB_MODE_ALL_DISABLE) 82662306a36Sopenharmony_ci continue; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci svsb_dir = debugfs_create_dir(svsb->name, svs_dir); 82962306a36Sopenharmony_ci if (IS_ERR(svsb_dir)) { 83062306a36Sopenharmony_ci dev_err(svsp->dev, "cannot create %s/%s: %ld\n", 83162306a36Sopenharmony_ci d, svsb->name, PTR_ERR(svsb_dir)); 83262306a36Sopenharmony_ci return PTR_ERR(svsb_dir); 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(svsb_entries); i++) { 83662306a36Sopenharmony_ci file_entry = debugfs_create_file(svsb_entries[i].name, 83762306a36Sopenharmony_ci 0664, svsb_dir, svsb, 83862306a36Sopenharmony_ci svsb_entries[i].fops); 83962306a36Sopenharmony_ci if (IS_ERR(file_entry)) { 84062306a36Sopenharmony_ci dev_err(svsp->dev, "no %s/%s/%s?: %ld\n", 84162306a36Sopenharmony_ci d, svsb->name, svsb_entries[i].name, 84262306a36Sopenharmony_ci PTR_ERR(file_entry)); 84362306a36Sopenharmony_ci return PTR_ERR(file_entry); 84462306a36Sopenharmony_ci } 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci return 0; 84962306a36Sopenharmony_ci} 85062306a36Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */ 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_cistatic u32 interpolate(u32 f0, u32 f1, u32 v0, u32 v1, u32 fx) 85362306a36Sopenharmony_ci{ 85462306a36Sopenharmony_ci u32 vx; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci if (v0 == v1 || f0 == f1) 85762306a36Sopenharmony_ci return v0; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci /* *100 to have decimal fraction factor */ 86062306a36Sopenharmony_ci vx = (v0 * 100) - ((((v0 - v1) * 100) / (f0 - f1)) * (f0 - fx)); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci return DIV_ROUND_UP(vx, 100); 86362306a36Sopenharmony_ci} 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_cistatic void svs_get_bank_volts_v3(struct svs_platform *svsp) 86662306a36Sopenharmony_ci{ 86762306a36Sopenharmony_ci struct svs_bank *svsb = svsp->pbank; 86862306a36Sopenharmony_ci u32 i, j, *vop, vop74, vop30, turn_pt = svsb->turn_pt; 86962306a36Sopenharmony_ci u32 b_sft, shift_byte = 0, opp_start = 0, opp_stop = 0; 87062306a36Sopenharmony_ci u32 middle_index = (svsb->opp_count / 2); 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci if (svsb->phase == SVSB_PHASE_MON && 87362306a36Sopenharmony_ci svsb->volt_flags & SVSB_MON_VOLT_IGNORE) 87462306a36Sopenharmony_ci return; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci vop74 = svs_readl_relaxed(svsp, VOP74); 87762306a36Sopenharmony_ci vop30 = svs_readl_relaxed(svsp, VOP30); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci /* Target is to set svsb->volt[] by algorithm */ 88062306a36Sopenharmony_ci if (turn_pt < middle_index) { 88162306a36Sopenharmony_ci if (svsb->type == SVSB_HIGH) { 88262306a36Sopenharmony_ci /* volt[0] ~ volt[turn_pt - 1] */ 88362306a36Sopenharmony_ci for (i = 0; i < turn_pt; i++) { 88462306a36Sopenharmony_ci b_sft = BITS8 * (shift_byte % REG_BYTES); 88562306a36Sopenharmony_ci vop = (shift_byte < REG_BYTES) ? &vop30 : 88662306a36Sopenharmony_ci &vop74; 88762306a36Sopenharmony_ci svsb->volt[i] = (*vop >> b_sft) & GENMASK(7, 0); 88862306a36Sopenharmony_ci shift_byte++; 88962306a36Sopenharmony_ci } 89062306a36Sopenharmony_ci } else if (svsb->type == SVSB_LOW) { 89162306a36Sopenharmony_ci /* volt[turn_pt] + volt[j] ~ volt[opp_count - 1] */ 89262306a36Sopenharmony_ci j = svsb->opp_count - 7; 89362306a36Sopenharmony_ci svsb->volt[turn_pt] = FIELD_GET(SVSB_VOPS_FLD_VOP0_4, vop30); 89462306a36Sopenharmony_ci shift_byte++; 89562306a36Sopenharmony_ci for (i = j; i < svsb->opp_count; i++) { 89662306a36Sopenharmony_ci b_sft = BITS8 * (shift_byte % REG_BYTES); 89762306a36Sopenharmony_ci vop = (shift_byte < REG_BYTES) ? &vop30 : 89862306a36Sopenharmony_ci &vop74; 89962306a36Sopenharmony_ci svsb->volt[i] = (*vop >> b_sft) & GENMASK(7, 0); 90062306a36Sopenharmony_ci shift_byte++; 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci /* volt[turn_pt + 1] ~ volt[j - 1] by interpolate */ 90462306a36Sopenharmony_ci for (i = turn_pt + 1; i < j; i++) 90562306a36Sopenharmony_ci svsb->volt[i] = interpolate(svsb->freq_pct[turn_pt], 90662306a36Sopenharmony_ci svsb->freq_pct[j], 90762306a36Sopenharmony_ci svsb->volt[turn_pt], 90862306a36Sopenharmony_ci svsb->volt[j], 90962306a36Sopenharmony_ci svsb->freq_pct[i]); 91062306a36Sopenharmony_ci } 91162306a36Sopenharmony_ci } else { 91262306a36Sopenharmony_ci if (svsb->type == SVSB_HIGH) { 91362306a36Sopenharmony_ci /* volt[0] + volt[j] ~ volt[turn_pt - 1] */ 91462306a36Sopenharmony_ci j = turn_pt - 7; 91562306a36Sopenharmony_ci svsb->volt[0] = FIELD_GET(SVSB_VOPS_FLD_VOP0_4, vop30); 91662306a36Sopenharmony_ci shift_byte++; 91762306a36Sopenharmony_ci for (i = j; i < turn_pt; i++) { 91862306a36Sopenharmony_ci b_sft = BITS8 * (shift_byte % REG_BYTES); 91962306a36Sopenharmony_ci vop = (shift_byte < REG_BYTES) ? &vop30 : 92062306a36Sopenharmony_ci &vop74; 92162306a36Sopenharmony_ci svsb->volt[i] = (*vop >> b_sft) & GENMASK(7, 0); 92262306a36Sopenharmony_ci shift_byte++; 92362306a36Sopenharmony_ci } 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci /* volt[1] ~ volt[j - 1] by interpolate */ 92662306a36Sopenharmony_ci for (i = 1; i < j; i++) 92762306a36Sopenharmony_ci svsb->volt[i] = interpolate(svsb->freq_pct[0], 92862306a36Sopenharmony_ci svsb->freq_pct[j], 92962306a36Sopenharmony_ci svsb->volt[0], 93062306a36Sopenharmony_ci svsb->volt[j], 93162306a36Sopenharmony_ci svsb->freq_pct[i]); 93262306a36Sopenharmony_ci } else if (svsb->type == SVSB_LOW) { 93362306a36Sopenharmony_ci /* volt[turn_pt] ~ volt[opp_count - 1] */ 93462306a36Sopenharmony_ci for (i = turn_pt; i < svsb->opp_count; i++) { 93562306a36Sopenharmony_ci b_sft = BITS8 * (shift_byte % REG_BYTES); 93662306a36Sopenharmony_ci vop = (shift_byte < REG_BYTES) ? &vop30 : 93762306a36Sopenharmony_ci &vop74; 93862306a36Sopenharmony_ci svsb->volt[i] = (*vop >> b_sft) & GENMASK(7, 0); 93962306a36Sopenharmony_ci shift_byte++; 94062306a36Sopenharmony_ci } 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci if (svsb->type == SVSB_HIGH) { 94562306a36Sopenharmony_ci opp_start = 0; 94662306a36Sopenharmony_ci opp_stop = svsb->turn_pt; 94762306a36Sopenharmony_ci } else if (svsb->type == SVSB_LOW) { 94862306a36Sopenharmony_ci opp_start = svsb->turn_pt; 94962306a36Sopenharmony_ci opp_stop = svsb->opp_count; 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci for (i = opp_start; i < opp_stop; i++) 95362306a36Sopenharmony_ci if (svsb->volt_flags & SVSB_REMOVE_DVTFIXED_VOLT) 95462306a36Sopenharmony_ci svsb->volt[i] -= svsb->dvt_fixed; 95562306a36Sopenharmony_ci} 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_cistatic void svs_set_bank_freq_pct_v3(struct svs_platform *svsp) 95862306a36Sopenharmony_ci{ 95962306a36Sopenharmony_ci struct svs_bank *svsb = svsp->pbank; 96062306a36Sopenharmony_ci u32 i, j, *freq_pct, freq_pct74 = 0, freq_pct30 = 0; 96162306a36Sopenharmony_ci u32 b_sft, shift_byte = 0, turn_pt; 96262306a36Sopenharmony_ci u32 middle_index = (svsb->opp_count / 2); 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci for (i = 0; i < svsb->opp_count; i++) { 96562306a36Sopenharmony_ci if (svsb->opp_dfreq[i] <= svsb->turn_freq_base) { 96662306a36Sopenharmony_ci svsb->turn_pt = i; 96762306a36Sopenharmony_ci break; 96862306a36Sopenharmony_ci } 96962306a36Sopenharmony_ci } 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci turn_pt = svsb->turn_pt; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci /* Target is to fill out freq_pct74 / freq_pct30 by algorithm */ 97462306a36Sopenharmony_ci if (turn_pt < middle_index) { 97562306a36Sopenharmony_ci if (svsb->type == SVSB_HIGH) { 97662306a36Sopenharmony_ci /* 97762306a36Sopenharmony_ci * If we don't handle this situation, 97862306a36Sopenharmony_ci * SVSB_HIGH's FREQPCT74 / FREQPCT30 would keep "0" 97962306a36Sopenharmony_ci * and this leads SVSB_LOW to work abnormally. 98062306a36Sopenharmony_ci */ 98162306a36Sopenharmony_ci if (turn_pt == 0) 98262306a36Sopenharmony_ci freq_pct30 = svsb->freq_pct[0]; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci /* freq_pct[0] ~ freq_pct[turn_pt - 1] */ 98562306a36Sopenharmony_ci for (i = 0; i < turn_pt; i++) { 98662306a36Sopenharmony_ci b_sft = BITS8 * (shift_byte % REG_BYTES); 98762306a36Sopenharmony_ci freq_pct = (shift_byte < REG_BYTES) ? 98862306a36Sopenharmony_ci &freq_pct30 : &freq_pct74; 98962306a36Sopenharmony_ci *freq_pct |= (svsb->freq_pct[i] << b_sft); 99062306a36Sopenharmony_ci shift_byte++; 99162306a36Sopenharmony_ci } 99262306a36Sopenharmony_ci } else if (svsb->type == SVSB_LOW) { 99362306a36Sopenharmony_ci /* 99462306a36Sopenharmony_ci * freq_pct[turn_pt] + 99562306a36Sopenharmony_ci * freq_pct[opp_count - 7] ~ freq_pct[opp_count -1] 99662306a36Sopenharmony_ci */ 99762306a36Sopenharmony_ci freq_pct30 = svsb->freq_pct[turn_pt]; 99862306a36Sopenharmony_ci shift_byte++; 99962306a36Sopenharmony_ci j = svsb->opp_count - 7; 100062306a36Sopenharmony_ci for (i = j; i < svsb->opp_count; i++) { 100162306a36Sopenharmony_ci b_sft = BITS8 * (shift_byte % REG_BYTES); 100262306a36Sopenharmony_ci freq_pct = (shift_byte < REG_BYTES) ? 100362306a36Sopenharmony_ci &freq_pct30 : &freq_pct74; 100462306a36Sopenharmony_ci *freq_pct |= (svsb->freq_pct[i] << b_sft); 100562306a36Sopenharmony_ci shift_byte++; 100662306a36Sopenharmony_ci } 100762306a36Sopenharmony_ci } 100862306a36Sopenharmony_ci } else { 100962306a36Sopenharmony_ci if (svsb->type == SVSB_HIGH) { 101062306a36Sopenharmony_ci /* 101162306a36Sopenharmony_ci * freq_pct[0] + 101262306a36Sopenharmony_ci * freq_pct[turn_pt - 7] ~ freq_pct[turn_pt - 1] 101362306a36Sopenharmony_ci */ 101462306a36Sopenharmony_ci freq_pct30 = svsb->freq_pct[0]; 101562306a36Sopenharmony_ci shift_byte++; 101662306a36Sopenharmony_ci j = turn_pt - 7; 101762306a36Sopenharmony_ci for (i = j; i < turn_pt; i++) { 101862306a36Sopenharmony_ci b_sft = BITS8 * (shift_byte % REG_BYTES); 101962306a36Sopenharmony_ci freq_pct = (shift_byte < REG_BYTES) ? 102062306a36Sopenharmony_ci &freq_pct30 : &freq_pct74; 102162306a36Sopenharmony_ci *freq_pct |= (svsb->freq_pct[i] << b_sft); 102262306a36Sopenharmony_ci shift_byte++; 102362306a36Sopenharmony_ci } 102462306a36Sopenharmony_ci } else if (svsb->type == SVSB_LOW) { 102562306a36Sopenharmony_ci /* freq_pct[turn_pt] ~ freq_pct[opp_count - 1] */ 102662306a36Sopenharmony_ci for (i = turn_pt; i < svsb->opp_count; i++) { 102762306a36Sopenharmony_ci b_sft = BITS8 * (shift_byte % REG_BYTES); 102862306a36Sopenharmony_ci freq_pct = (shift_byte < REG_BYTES) ? 102962306a36Sopenharmony_ci &freq_pct30 : &freq_pct74; 103062306a36Sopenharmony_ci *freq_pct |= (svsb->freq_pct[i] << b_sft); 103162306a36Sopenharmony_ci shift_byte++; 103262306a36Sopenharmony_ci } 103362306a36Sopenharmony_ci } 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci svs_writel_relaxed(svsp, freq_pct74, FREQPCT74); 103762306a36Sopenharmony_ci svs_writel_relaxed(svsp, freq_pct30, FREQPCT30); 103862306a36Sopenharmony_ci} 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_cistatic void svs_get_bank_volts_v2(struct svs_platform *svsp) 104162306a36Sopenharmony_ci{ 104262306a36Sopenharmony_ci struct svs_bank *svsb = svsp->pbank; 104362306a36Sopenharmony_ci u32 temp, i; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci temp = svs_readl_relaxed(svsp, VOP74); 104662306a36Sopenharmony_ci svsb->volt[14] = FIELD_GET(SVSB_VOPS_FLD_VOP3_7, temp); 104762306a36Sopenharmony_ci svsb->volt[12] = FIELD_GET(SVSB_VOPS_FLD_VOP2_6, temp); 104862306a36Sopenharmony_ci svsb->volt[10] = FIELD_GET(SVSB_VOPS_FLD_VOP1_5, temp); 104962306a36Sopenharmony_ci svsb->volt[8] = FIELD_GET(SVSB_VOPS_FLD_VOP0_4, temp); 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci temp = svs_readl_relaxed(svsp, VOP30); 105262306a36Sopenharmony_ci svsb->volt[6] = FIELD_GET(SVSB_VOPS_FLD_VOP3_7, temp); 105362306a36Sopenharmony_ci svsb->volt[4] = FIELD_GET(SVSB_VOPS_FLD_VOP2_6, temp); 105462306a36Sopenharmony_ci svsb->volt[2] = FIELD_GET(SVSB_VOPS_FLD_VOP1_5, temp); 105562306a36Sopenharmony_ci svsb->volt[0] = FIELD_GET(SVSB_VOPS_FLD_VOP0_4, temp); 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci for (i = 0; i <= 12; i += 2) 105862306a36Sopenharmony_ci svsb->volt[i + 1] = interpolate(svsb->freq_pct[i], 105962306a36Sopenharmony_ci svsb->freq_pct[i + 2], 106062306a36Sopenharmony_ci svsb->volt[i], 106162306a36Sopenharmony_ci svsb->volt[i + 2], 106262306a36Sopenharmony_ci svsb->freq_pct[i + 1]); 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci svsb->volt[15] = interpolate(svsb->freq_pct[12], 106562306a36Sopenharmony_ci svsb->freq_pct[14], 106662306a36Sopenharmony_ci svsb->volt[12], 106762306a36Sopenharmony_ci svsb->volt[14], 106862306a36Sopenharmony_ci svsb->freq_pct[15]); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci for (i = 0; i < svsb->opp_count; i++) 107162306a36Sopenharmony_ci svsb->volt[i] += svsb->volt_od; 107262306a36Sopenharmony_ci} 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_cistatic void svs_set_bank_freq_pct_v2(struct svs_platform *svsp) 107562306a36Sopenharmony_ci{ 107662306a36Sopenharmony_ci struct svs_bank *svsb = svsp->pbank; 107762306a36Sopenharmony_ci u32 freqpct74_val, freqpct30_val; 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci freqpct74_val = FIELD_PREP(SVSB_FREQPCTS_FLD_PCT0_4, svsb->freq_pct[8]) | 108062306a36Sopenharmony_ci FIELD_PREP(SVSB_FREQPCTS_FLD_PCT1_5, svsb->freq_pct[10]) | 108162306a36Sopenharmony_ci FIELD_PREP(SVSB_FREQPCTS_FLD_PCT2_6, svsb->freq_pct[12]) | 108262306a36Sopenharmony_ci FIELD_PREP(SVSB_FREQPCTS_FLD_PCT3_7, svsb->freq_pct[14]); 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci freqpct30_val = FIELD_PREP(SVSB_FREQPCTS_FLD_PCT0_4, svsb->freq_pct[0]) | 108562306a36Sopenharmony_ci FIELD_PREP(SVSB_FREQPCTS_FLD_PCT1_5, svsb->freq_pct[2]) | 108662306a36Sopenharmony_ci FIELD_PREP(SVSB_FREQPCTS_FLD_PCT2_6, svsb->freq_pct[4]) | 108762306a36Sopenharmony_ci FIELD_PREP(SVSB_FREQPCTS_FLD_PCT3_7, svsb->freq_pct[6]); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci svs_writel_relaxed(svsp, freqpct74_val, FREQPCT74); 109062306a36Sopenharmony_ci svs_writel_relaxed(svsp, freqpct30_val, FREQPCT30); 109162306a36Sopenharmony_ci} 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_cistatic void svs_set_bank_phase(struct svs_platform *svsp, 109462306a36Sopenharmony_ci enum svsb_phase target_phase) 109562306a36Sopenharmony_ci{ 109662306a36Sopenharmony_ci struct svs_bank *svsb = svsp->pbank; 109762306a36Sopenharmony_ci u32 des_char, temp_char, det_char, limit_vals, init2vals, ts_calcs; 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci svs_switch_bank(svsp); 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci des_char = FIELD_PREP(SVSB_DESCHAR_FLD_BDES, svsb->bdes) | 110262306a36Sopenharmony_ci FIELD_PREP(SVSB_DESCHAR_FLD_MDES, svsb->mdes); 110362306a36Sopenharmony_ci svs_writel_relaxed(svsp, des_char, DESCHAR); 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci temp_char = FIELD_PREP(SVSB_TEMPCHAR_FLD_VCO, svsb->vco) | 110662306a36Sopenharmony_ci FIELD_PREP(SVSB_TEMPCHAR_FLD_MTDES, svsb->mtdes) | 110762306a36Sopenharmony_ci FIELD_PREP(SVSB_TEMPCHAR_FLD_DVT_FIXED, svsb->dvt_fixed); 110862306a36Sopenharmony_ci svs_writel_relaxed(svsp, temp_char, TEMPCHAR); 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci det_char = FIELD_PREP(SVSB_DETCHAR_FLD_DCBDET, svsb->dcbdet) | 111162306a36Sopenharmony_ci FIELD_PREP(SVSB_DETCHAR_FLD_DCMDET, svsb->dcmdet); 111262306a36Sopenharmony_ci svs_writel_relaxed(svsp, det_char, DETCHAR); 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci svs_writel_relaxed(svsp, svsb->dc_config, DCCONFIG); 111562306a36Sopenharmony_ci svs_writel_relaxed(svsp, svsb->age_config, AGECONFIG); 111662306a36Sopenharmony_ci svs_writel_relaxed(svsp, SVSB_RUNCONFIG_DEFAULT, RUNCONFIG); 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci svsb->set_freq_pct(svsp); 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci limit_vals = FIELD_PREP(SVSB_LIMITVALS_FLD_DTLO, SVSB_VAL_DTLO) | 112162306a36Sopenharmony_ci FIELD_PREP(SVSB_LIMITVALS_FLD_DTHI, SVSB_VAL_DTHI) | 112262306a36Sopenharmony_ci FIELD_PREP(SVSB_LIMITVALS_FLD_VMIN, svsb->vmin) | 112362306a36Sopenharmony_ci FIELD_PREP(SVSB_LIMITVALS_FLD_VMAX, svsb->vmax); 112462306a36Sopenharmony_ci svs_writel_relaxed(svsp, limit_vals, LIMITVALS); 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci svs_writel_relaxed(svsp, SVSB_DET_WINDOW, DETWINDOW); 112762306a36Sopenharmony_ci svs_writel_relaxed(svsp, SVSB_DET_MAX, CONFIG); 112862306a36Sopenharmony_ci svs_writel_relaxed(svsp, svsb->chk_shift, CHKSHIFT); 112962306a36Sopenharmony_ci svs_writel_relaxed(svsp, svsb->ctl0, CTL0); 113062306a36Sopenharmony_ci svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS); 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci switch (target_phase) { 113362306a36Sopenharmony_ci case SVSB_PHASE_INIT01: 113462306a36Sopenharmony_ci svs_writel_relaxed(svsp, svsb->vboot, VBOOT); 113562306a36Sopenharmony_ci svs_writel_relaxed(svsp, SVSB_INTEN_INIT0x, INTEN); 113662306a36Sopenharmony_ci svs_writel_relaxed(svsp, SVSB_PTPEN_INIT01, SVSEN); 113762306a36Sopenharmony_ci break; 113862306a36Sopenharmony_ci case SVSB_PHASE_INIT02: 113962306a36Sopenharmony_ci init2vals = FIELD_PREP(SVSB_INIT2VALS_FLD_AGEVOFFSETIN, svsb->age_voffset_in) | 114062306a36Sopenharmony_ci FIELD_PREP(SVSB_INIT2VALS_FLD_DCVOFFSETIN, svsb->dc_voffset_in); 114162306a36Sopenharmony_ci svs_writel_relaxed(svsp, SVSB_INTEN_INIT0x, INTEN); 114262306a36Sopenharmony_ci svs_writel_relaxed(svsp, init2vals, INIT2VALS); 114362306a36Sopenharmony_ci svs_writel_relaxed(svsp, SVSB_PTPEN_INIT02, SVSEN); 114462306a36Sopenharmony_ci break; 114562306a36Sopenharmony_ci case SVSB_PHASE_MON: 114662306a36Sopenharmony_ci ts_calcs = FIELD_PREP(SVSB_TSCALCS_FLD_BTS, svsb->bts) | 114762306a36Sopenharmony_ci FIELD_PREP(SVSB_TSCALCS_FLD_MTS, svsb->mts); 114862306a36Sopenharmony_ci svs_writel_relaxed(svsp, ts_calcs, TSCALCS); 114962306a36Sopenharmony_ci svs_writel_relaxed(svsp, SVSB_INTEN_MONVOPEN, INTEN); 115062306a36Sopenharmony_ci svs_writel_relaxed(svsp, SVSB_PTPEN_MON, SVSEN); 115162306a36Sopenharmony_ci break; 115262306a36Sopenharmony_ci default: 115362306a36Sopenharmony_ci dev_err(svsb->dev, "requested unknown target phase: %u\n", 115462306a36Sopenharmony_ci target_phase); 115562306a36Sopenharmony_ci break; 115662306a36Sopenharmony_ci } 115762306a36Sopenharmony_ci} 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_cistatic inline void svs_save_bank_register_data(struct svs_platform *svsp, 116062306a36Sopenharmony_ci enum svsb_phase phase) 116162306a36Sopenharmony_ci{ 116262306a36Sopenharmony_ci struct svs_bank *svsb = svsp->pbank; 116362306a36Sopenharmony_ci enum svs_reg_index rg_i; 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci for (rg_i = DESCHAR; rg_i < SVS_REG_MAX; rg_i++) 116662306a36Sopenharmony_ci svsb->reg_data[phase][rg_i] = svs_readl_relaxed(svsp, rg_i); 116762306a36Sopenharmony_ci} 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_cistatic inline void svs_error_isr_handler(struct svs_platform *svsp) 117062306a36Sopenharmony_ci{ 117162306a36Sopenharmony_ci struct svs_bank *svsb = svsp->pbank; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci dev_err(svsb->dev, "%s: CORESEL = 0x%08x\n", 117462306a36Sopenharmony_ci __func__, svs_readl_relaxed(svsp, CORESEL)); 117562306a36Sopenharmony_ci dev_err(svsb->dev, "SVSEN = 0x%08x, INTSTS = 0x%08x\n", 117662306a36Sopenharmony_ci svs_readl_relaxed(svsp, SVSEN), 117762306a36Sopenharmony_ci svs_readl_relaxed(svsp, INTSTS)); 117862306a36Sopenharmony_ci dev_err(svsb->dev, "SMSTATE0 = 0x%08x, SMSTATE1 = 0x%08x\n", 117962306a36Sopenharmony_ci svs_readl_relaxed(svsp, SMSTATE0), 118062306a36Sopenharmony_ci svs_readl_relaxed(svsp, SMSTATE1)); 118162306a36Sopenharmony_ci dev_err(svsb->dev, "TEMP = 0x%08x\n", svs_readl_relaxed(svsp, TEMP)); 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci svs_save_bank_register_data(svsp, SVSB_PHASE_ERROR); 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci svsb->phase = SVSB_PHASE_ERROR; 118662306a36Sopenharmony_ci svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN); 118762306a36Sopenharmony_ci svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS); 118862306a36Sopenharmony_ci} 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_cistatic inline void svs_init01_isr_handler(struct svs_platform *svsp) 119162306a36Sopenharmony_ci{ 119262306a36Sopenharmony_ci struct svs_bank *svsb = svsp->pbank; 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci dev_info(svsb->dev, "%s: VDN74~30:0x%08x~0x%08x, DC:0x%08x\n", 119562306a36Sopenharmony_ci __func__, svs_readl_relaxed(svsp, VDESIGN74), 119662306a36Sopenharmony_ci svs_readl_relaxed(svsp, VDESIGN30), 119762306a36Sopenharmony_ci svs_readl_relaxed(svsp, DCVALUES)); 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci svs_save_bank_register_data(svsp, SVSB_PHASE_INIT01); 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci svsb->phase = SVSB_PHASE_INIT01; 120262306a36Sopenharmony_ci svsb->dc_voffset_in = ~(svs_readl_relaxed(svsp, DCVALUES) & 120362306a36Sopenharmony_ci GENMASK(15, 0)) + 1; 120462306a36Sopenharmony_ci if (svsb->volt_flags & SVSB_INIT01_VOLT_IGNORE || 120562306a36Sopenharmony_ci (svsb->dc_voffset_in & SVSB_DC_SIGNED_BIT && 120662306a36Sopenharmony_ci svsb->volt_flags & SVSB_INIT01_VOLT_INC_ONLY)) 120762306a36Sopenharmony_ci svsb->dc_voffset_in = 0; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci svsb->age_voffset_in = svs_readl_relaxed(svsp, AGEVALUES) & 121062306a36Sopenharmony_ci GENMASK(15, 0); 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN); 121362306a36Sopenharmony_ci svs_writel_relaxed(svsp, SVSB_INTSTS_F0_COMPLETE, INTSTS); 121462306a36Sopenharmony_ci svsb->core_sel &= ~SVSB_DET_CLK_EN; 121562306a36Sopenharmony_ci} 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_cistatic inline void svs_init02_isr_handler(struct svs_platform *svsp) 121862306a36Sopenharmony_ci{ 121962306a36Sopenharmony_ci struct svs_bank *svsb = svsp->pbank; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci dev_info(svsb->dev, "%s: VOP74~30:0x%08x~0x%08x, DC:0x%08x\n", 122262306a36Sopenharmony_ci __func__, svs_readl_relaxed(svsp, VOP74), 122362306a36Sopenharmony_ci svs_readl_relaxed(svsp, VOP30), 122462306a36Sopenharmony_ci svs_readl_relaxed(svsp, DCVALUES)); 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci svs_save_bank_register_data(svsp, SVSB_PHASE_INIT02); 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci svsb->phase = SVSB_PHASE_INIT02; 122962306a36Sopenharmony_ci svsb->get_volts(svsp); 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN); 123262306a36Sopenharmony_ci svs_writel_relaxed(svsp, SVSB_INTSTS_F0_COMPLETE, INTSTS); 123362306a36Sopenharmony_ci} 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_cistatic inline void svs_mon_mode_isr_handler(struct svs_platform *svsp) 123662306a36Sopenharmony_ci{ 123762306a36Sopenharmony_ci struct svs_bank *svsb = svsp->pbank; 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci svs_save_bank_register_data(svsp, SVSB_PHASE_MON); 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci svsb->phase = SVSB_PHASE_MON; 124262306a36Sopenharmony_ci svsb->get_volts(svsp); 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci svsb->temp = svs_readl_relaxed(svsp, TEMP) & GENMASK(7, 0); 124562306a36Sopenharmony_ci svs_writel_relaxed(svsp, SVSB_INTSTS_FLD_MONVOP, INTSTS); 124662306a36Sopenharmony_ci} 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_cistatic irqreturn_t svs_isr(int irq, void *data) 124962306a36Sopenharmony_ci{ 125062306a36Sopenharmony_ci struct svs_platform *svsp = data; 125162306a36Sopenharmony_ci struct svs_bank *svsb = NULL; 125262306a36Sopenharmony_ci unsigned long flags; 125362306a36Sopenharmony_ci u32 idx, int_sts, svs_en; 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci for (idx = 0; idx < svsp->bank_max; idx++) { 125662306a36Sopenharmony_ci svsb = &svsp->banks[idx]; 125762306a36Sopenharmony_ci WARN(!svsb, "%s: svsb(%s) is null", __func__, svsb->name); 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci spin_lock_irqsave(&svs_lock, flags); 126062306a36Sopenharmony_ci svsp->pbank = svsb; 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci /* Find out which svs bank fires interrupt */ 126362306a36Sopenharmony_ci if (svsb->int_st & svs_readl_relaxed(svsp, INTST)) { 126462306a36Sopenharmony_ci spin_unlock_irqrestore(&svs_lock, flags); 126562306a36Sopenharmony_ci continue; 126662306a36Sopenharmony_ci } 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci svs_switch_bank(svsp); 126962306a36Sopenharmony_ci int_sts = svs_readl_relaxed(svsp, INTSTS); 127062306a36Sopenharmony_ci svs_en = svs_readl_relaxed(svsp, SVSEN); 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci if (int_sts == SVSB_INTSTS_F0_COMPLETE && 127362306a36Sopenharmony_ci svs_en == SVSB_PTPEN_INIT01) 127462306a36Sopenharmony_ci svs_init01_isr_handler(svsp); 127562306a36Sopenharmony_ci else if (int_sts == SVSB_INTSTS_F0_COMPLETE && 127662306a36Sopenharmony_ci svs_en == SVSB_PTPEN_INIT02) 127762306a36Sopenharmony_ci svs_init02_isr_handler(svsp); 127862306a36Sopenharmony_ci else if (int_sts & SVSB_INTSTS_FLD_MONVOP) 127962306a36Sopenharmony_ci svs_mon_mode_isr_handler(svsp); 128062306a36Sopenharmony_ci else 128162306a36Sopenharmony_ci svs_error_isr_handler(svsp); 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci spin_unlock_irqrestore(&svs_lock, flags); 128462306a36Sopenharmony_ci break; 128562306a36Sopenharmony_ci } 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci svs_adjust_pm_opp_volts(svsb); 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci if (svsb->phase == SVSB_PHASE_INIT01 || 129062306a36Sopenharmony_ci svsb->phase == SVSB_PHASE_INIT02) 129162306a36Sopenharmony_ci complete(&svsb->init_completion); 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci return IRQ_HANDLED; 129462306a36Sopenharmony_ci} 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_cistatic int svs_init01(struct svs_platform *svsp) 129762306a36Sopenharmony_ci{ 129862306a36Sopenharmony_ci struct svs_bank *svsb; 129962306a36Sopenharmony_ci unsigned long flags, time_left; 130062306a36Sopenharmony_ci bool search_done; 130162306a36Sopenharmony_ci int ret = 0, r; 130262306a36Sopenharmony_ci u32 opp_freq, opp_vboot, buck_volt, idx, i; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci /* Keep CPUs' core power on for svs_init01 initialization */ 130562306a36Sopenharmony_ci cpuidle_pause_and_lock(); 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci /* Svs bank init01 preparation - power enable */ 130862306a36Sopenharmony_ci for (idx = 0; idx < svsp->bank_max; idx++) { 130962306a36Sopenharmony_ci svsb = &svsp->banks[idx]; 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci if (!(svsb->mode_support & SVSB_MODE_INIT01)) 131262306a36Sopenharmony_ci continue; 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci ret = regulator_enable(svsb->buck); 131562306a36Sopenharmony_ci if (ret) { 131662306a36Sopenharmony_ci dev_err(svsb->dev, "%s enable fail: %d\n", 131762306a36Sopenharmony_ci svsb->buck_name, ret); 131862306a36Sopenharmony_ci goto svs_init01_resume_cpuidle; 131962306a36Sopenharmony_ci } 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci /* Some buck doesn't support mode change. Show fail msg only */ 132262306a36Sopenharmony_ci ret = regulator_set_mode(svsb->buck, REGULATOR_MODE_FAST); 132362306a36Sopenharmony_ci if (ret) 132462306a36Sopenharmony_ci dev_notice(svsb->dev, "set fast mode fail: %d\n", ret); 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci if (svsb->volt_flags & SVSB_INIT01_PD_REQ) { 132762306a36Sopenharmony_ci if (!pm_runtime_enabled(svsb->opp_dev)) { 132862306a36Sopenharmony_ci pm_runtime_enable(svsb->opp_dev); 132962306a36Sopenharmony_ci svsb->pm_runtime_enabled_count++; 133062306a36Sopenharmony_ci } 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(svsb->opp_dev); 133362306a36Sopenharmony_ci if (ret < 0) { 133462306a36Sopenharmony_ci dev_err(svsb->dev, "mtcmos on fail: %d\n", ret); 133562306a36Sopenharmony_ci goto svs_init01_resume_cpuidle; 133662306a36Sopenharmony_ci } 133762306a36Sopenharmony_ci } 133862306a36Sopenharmony_ci } 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci /* 134162306a36Sopenharmony_ci * Svs bank init01 preparation - vboot voltage adjustment 134262306a36Sopenharmony_ci * Sometimes two svs banks use the same buck. Therefore, 134362306a36Sopenharmony_ci * we have to set each svs bank to target voltage(vboot) first. 134462306a36Sopenharmony_ci */ 134562306a36Sopenharmony_ci for (idx = 0; idx < svsp->bank_max; idx++) { 134662306a36Sopenharmony_ci svsb = &svsp->banks[idx]; 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci if (!(svsb->mode_support & SVSB_MODE_INIT01)) 134962306a36Sopenharmony_ci continue; 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci /* 135262306a36Sopenharmony_ci * Find the fastest freq that can be run at vboot and 135362306a36Sopenharmony_ci * fix to that freq until svs_init01 is done. 135462306a36Sopenharmony_ci */ 135562306a36Sopenharmony_ci search_done = false; 135662306a36Sopenharmony_ci opp_vboot = svs_bank_volt_to_opp_volt(svsb->vboot, 135762306a36Sopenharmony_ci svsb->volt_step, 135862306a36Sopenharmony_ci svsb->volt_base); 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci for (i = 0; i < svsb->opp_count; i++) { 136162306a36Sopenharmony_ci opp_freq = svsb->opp_dfreq[i]; 136262306a36Sopenharmony_ci if (!search_done && svsb->opp_dvolt[i] <= opp_vboot) { 136362306a36Sopenharmony_ci ret = dev_pm_opp_adjust_voltage(svsb->opp_dev, 136462306a36Sopenharmony_ci opp_freq, 136562306a36Sopenharmony_ci opp_vboot, 136662306a36Sopenharmony_ci opp_vboot, 136762306a36Sopenharmony_ci opp_vboot); 136862306a36Sopenharmony_ci if (ret) { 136962306a36Sopenharmony_ci dev_err(svsb->dev, 137062306a36Sopenharmony_ci "set opp %uuV vboot fail: %d\n", 137162306a36Sopenharmony_ci opp_vboot, ret); 137262306a36Sopenharmony_ci goto svs_init01_finish; 137362306a36Sopenharmony_ci } 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci search_done = true; 137662306a36Sopenharmony_ci } else { 137762306a36Sopenharmony_ci ret = dev_pm_opp_disable(svsb->opp_dev, 137862306a36Sopenharmony_ci svsb->opp_dfreq[i]); 137962306a36Sopenharmony_ci if (ret) { 138062306a36Sopenharmony_ci dev_err(svsb->dev, 138162306a36Sopenharmony_ci "opp %uHz disable fail: %d\n", 138262306a36Sopenharmony_ci svsb->opp_dfreq[i], ret); 138362306a36Sopenharmony_ci goto svs_init01_finish; 138462306a36Sopenharmony_ci } 138562306a36Sopenharmony_ci } 138662306a36Sopenharmony_ci } 138762306a36Sopenharmony_ci } 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci /* Svs bank init01 begins */ 139062306a36Sopenharmony_ci for (idx = 0; idx < svsp->bank_max; idx++) { 139162306a36Sopenharmony_ci svsb = &svsp->banks[idx]; 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci if (!(svsb->mode_support & SVSB_MODE_INIT01)) 139462306a36Sopenharmony_ci continue; 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci opp_vboot = svs_bank_volt_to_opp_volt(svsb->vboot, 139762306a36Sopenharmony_ci svsb->volt_step, 139862306a36Sopenharmony_ci svsb->volt_base); 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci buck_volt = regulator_get_voltage(svsb->buck); 140162306a36Sopenharmony_ci if (buck_volt != opp_vboot) { 140262306a36Sopenharmony_ci dev_err(svsb->dev, 140362306a36Sopenharmony_ci "buck voltage: %uuV, expected vboot: %uuV\n", 140462306a36Sopenharmony_ci buck_volt, opp_vboot); 140562306a36Sopenharmony_ci ret = -EPERM; 140662306a36Sopenharmony_ci goto svs_init01_finish; 140762306a36Sopenharmony_ci } 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci spin_lock_irqsave(&svs_lock, flags); 141062306a36Sopenharmony_ci svsp->pbank = svsb; 141162306a36Sopenharmony_ci svs_set_bank_phase(svsp, SVSB_PHASE_INIT01); 141262306a36Sopenharmony_ci spin_unlock_irqrestore(&svs_lock, flags); 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci time_left = wait_for_completion_timeout(&svsb->init_completion, 141562306a36Sopenharmony_ci msecs_to_jiffies(5000)); 141662306a36Sopenharmony_ci if (!time_left) { 141762306a36Sopenharmony_ci dev_err(svsb->dev, "init01 completion timeout\n"); 141862306a36Sopenharmony_ci ret = -EBUSY; 141962306a36Sopenharmony_ci goto svs_init01_finish; 142062306a36Sopenharmony_ci } 142162306a36Sopenharmony_ci } 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_cisvs_init01_finish: 142462306a36Sopenharmony_ci for (idx = 0; idx < svsp->bank_max; idx++) { 142562306a36Sopenharmony_ci svsb = &svsp->banks[idx]; 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci if (!(svsb->mode_support & SVSB_MODE_INIT01)) 142862306a36Sopenharmony_ci continue; 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci for (i = 0; i < svsb->opp_count; i++) { 143162306a36Sopenharmony_ci r = dev_pm_opp_enable(svsb->opp_dev, 143262306a36Sopenharmony_ci svsb->opp_dfreq[i]); 143362306a36Sopenharmony_ci if (r) 143462306a36Sopenharmony_ci dev_err(svsb->dev, "opp %uHz enable fail: %d\n", 143562306a36Sopenharmony_ci svsb->opp_dfreq[i], r); 143662306a36Sopenharmony_ci } 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci if (svsb->volt_flags & SVSB_INIT01_PD_REQ) { 143962306a36Sopenharmony_ci r = pm_runtime_put_sync(svsb->opp_dev); 144062306a36Sopenharmony_ci if (r) 144162306a36Sopenharmony_ci dev_err(svsb->dev, "mtcmos off fail: %d\n", r); 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci if (svsb->pm_runtime_enabled_count > 0) { 144462306a36Sopenharmony_ci pm_runtime_disable(svsb->opp_dev); 144562306a36Sopenharmony_ci svsb->pm_runtime_enabled_count--; 144662306a36Sopenharmony_ci } 144762306a36Sopenharmony_ci } 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci r = regulator_set_mode(svsb->buck, REGULATOR_MODE_NORMAL); 145062306a36Sopenharmony_ci if (r) 145162306a36Sopenharmony_ci dev_notice(svsb->dev, "set normal mode fail: %d\n", r); 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci r = regulator_disable(svsb->buck); 145462306a36Sopenharmony_ci if (r) 145562306a36Sopenharmony_ci dev_err(svsb->dev, "%s disable fail: %d\n", 145662306a36Sopenharmony_ci svsb->buck_name, r); 145762306a36Sopenharmony_ci } 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_cisvs_init01_resume_cpuidle: 146062306a36Sopenharmony_ci cpuidle_resume_and_unlock(); 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci return ret; 146362306a36Sopenharmony_ci} 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_cistatic int svs_init02(struct svs_platform *svsp) 146662306a36Sopenharmony_ci{ 146762306a36Sopenharmony_ci struct svs_bank *svsb; 146862306a36Sopenharmony_ci unsigned long flags, time_left; 146962306a36Sopenharmony_ci int ret; 147062306a36Sopenharmony_ci u32 idx; 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci for (idx = 0; idx < svsp->bank_max; idx++) { 147362306a36Sopenharmony_ci svsb = &svsp->banks[idx]; 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci if (!(svsb->mode_support & SVSB_MODE_INIT02)) 147662306a36Sopenharmony_ci continue; 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci reinit_completion(&svsb->init_completion); 147962306a36Sopenharmony_ci spin_lock_irqsave(&svs_lock, flags); 148062306a36Sopenharmony_ci svsp->pbank = svsb; 148162306a36Sopenharmony_ci svs_set_bank_phase(svsp, SVSB_PHASE_INIT02); 148262306a36Sopenharmony_ci spin_unlock_irqrestore(&svs_lock, flags); 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci time_left = wait_for_completion_timeout(&svsb->init_completion, 148562306a36Sopenharmony_ci msecs_to_jiffies(5000)); 148662306a36Sopenharmony_ci if (!time_left) { 148762306a36Sopenharmony_ci dev_err(svsb->dev, "init02 completion timeout\n"); 148862306a36Sopenharmony_ci ret = -EBUSY; 148962306a36Sopenharmony_ci goto out_of_init02; 149062306a36Sopenharmony_ci } 149162306a36Sopenharmony_ci } 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci /* 149462306a36Sopenharmony_ci * 2-line high/low bank update its corresponding opp voltages only. 149562306a36Sopenharmony_ci * Therefore, we sync voltages from opp for high/low bank voltages 149662306a36Sopenharmony_ci * consistency. 149762306a36Sopenharmony_ci */ 149862306a36Sopenharmony_ci for (idx = 0; idx < svsp->bank_max; idx++) { 149962306a36Sopenharmony_ci svsb = &svsp->banks[idx]; 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci if (!(svsb->mode_support & SVSB_MODE_INIT02)) 150262306a36Sopenharmony_ci continue; 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci if (svsb->type == SVSB_HIGH || svsb->type == SVSB_LOW) { 150562306a36Sopenharmony_ci if (svs_sync_bank_volts_from_opp(svsb)) { 150662306a36Sopenharmony_ci dev_err(svsb->dev, "sync volt fail\n"); 150762306a36Sopenharmony_ci ret = -EPERM; 150862306a36Sopenharmony_ci goto out_of_init02; 150962306a36Sopenharmony_ci } 151062306a36Sopenharmony_ci } 151162306a36Sopenharmony_ci } 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci return 0; 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ciout_of_init02: 151662306a36Sopenharmony_ci for (idx = 0; idx < svsp->bank_max; idx++) { 151762306a36Sopenharmony_ci svsb = &svsp->banks[idx]; 151862306a36Sopenharmony_ci svs_bank_disable_and_restore_default_volts(svsp, svsb); 151962306a36Sopenharmony_ci } 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci return ret; 152262306a36Sopenharmony_ci} 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_cistatic void svs_mon_mode(struct svs_platform *svsp) 152562306a36Sopenharmony_ci{ 152662306a36Sopenharmony_ci struct svs_bank *svsb; 152762306a36Sopenharmony_ci unsigned long flags; 152862306a36Sopenharmony_ci u32 idx; 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci for (idx = 0; idx < svsp->bank_max; idx++) { 153162306a36Sopenharmony_ci svsb = &svsp->banks[idx]; 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci if (!(svsb->mode_support & SVSB_MODE_MON)) 153462306a36Sopenharmony_ci continue; 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci spin_lock_irqsave(&svs_lock, flags); 153762306a36Sopenharmony_ci svsp->pbank = svsb; 153862306a36Sopenharmony_ci svs_set_bank_phase(svsp, SVSB_PHASE_MON); 153962306a36Sopenharmony_ci spin_unlock_irqrestore(&svs_lock, flags); 154062306a36Sopenharmony_ci } 154162306a36Sopenharmony_ci} 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_cistatic int svs_start(struct svs_platform *svsp) 154462306a36Sopenharmony_ci{ 154562306a36Sopenharmony_ci int ret; 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci ret = svs_init01(svsp); 154862306a36Sopenharmony_ci if (ret) 154962306a36Sopenharmony_ci return ret; 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci ret = svs_init02(svsp); 155262306a36Sopenharmony_ci if (ret) 155362306a36Sopenharmony_ci return ret; 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci svs_mon_mode(svsp); 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci return 0; 155862306a36Sopenharmony_ci} 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_cistatic int svs_suspend(struct device *dev) 156162306a36Sopenharmony_ci{ 156262306a36Sopenharmony_ci struct svs_platform *svsp = dev_get_drvdata(dev); 156362306a36Sopenharmony_ci struct svs_bank *svsb; 156462306a36Sopenharmony_ci int ret; 156562306a36Sopenharmony_ci u32 idx; 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci for (idx = 0; idx < svsp->bank_max; idx++) { 156862306a36Sopenharmony_ci svsb = &svsp->banks[idx]; 156962306a36Sopenharmony_ci svs_bank_disable_and_restore_default_volts(svsp, svsb); 157062306a36Sopenharmony_ci } 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci ret = reset_control_assert(svsp->rst); 157362306a36Sopenharmony_ci if (ret) { 157462306a36Sopenharmony_ci dev_err(svsp->dev, "cannot assert reset %d\n", ret); 157562306a36Sopenharmony_ci return ret; 157662306a36Sopenharmony_ci } 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci clk_disable_unprepare(svsp->main_clk); 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci return 0; 158162306a36Sopenharmony_ci} 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_cistatic int svs_resume(struct device *dev) 158462306a36Sopenharmony_ci{ 158562306a36Sopenharmony_ci struct svs_platform *svsp = dev_get_drvdata(dev); 158662306a36Sopenharmony_ci int ret; 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci ret = clk_prepare_enable(svsp->main_clk); 158962306a36Sopenharmony_ci if (ret) { 159062306a36Sopenharmony_ci dev_err(svsp->dev, "cannot enable main_clk, disable svs\n"); 159162306a36Sopenharmony_ci return ret; 159262306a36Sopenharmony_ci } 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci ret = reset_control_deassert(svsp->rst); 159562306a36Sopenharmony_ci if (ret) { 159662306a36Sopenharmony_ci dev_err(svsp->dev, "cannot deassert reset %d\n", ret); 159762306a36Sopenharmony_ci goto out_of_resume; 159862306a36Sopenharmony_ci } 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci ret = svs_init02(svsp); 160162306a36Sopenharmony_ci if (ret) 160262306a36Sopenharmony_ci goto svs_resume_reset_assert; 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci svs_mon_mode(svsp); 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci return 0; 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_cisvs_resume_reset_assert: 160962306a36Sopenharmony_ci dev_err(svsp->dev, "assert reset: %d\n", 161062306a36Sopenharmony_ci reset_control_assert(svsp->rst)); 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ciout_of_resume: 161362306a36Sopenharmony_ci clk_disable_unprepare(svsp->main_clk); 161462306a36Sopenharmony_ci return ret; 161562306a36Sopenharmony_ci} 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_cistatic int svs_bank_resource_setup(struct svs_platform *svsp) 161862306a36Sopenharmony_ci{ 161962306a36Sopenharmony_ci struct svs_bank *svsb; 162062306a36Sopenharmony_ci struct dev_pm_opp *opp; 162162306a36Sopenharmony_ci unsigned long freq; 162262306a36Sopenharmony_ci int count, ret; 162362306a36Sopenharmony_ci u32 idx, i; 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci dev_set_drvdata(svsp->dev, svsp); 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci for (idx = 0; idx < svsp->bank_max; idx++) { 162862306a36Sopenharmony_ci svsb = &svsp->banks[idx]; 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci switch (svsb->sw_id) { 163162306a36Sopenharmony_ci case SVSB_CPU_LITTLE: 163262306a36Sopenharmony_ci svsb->name = "SVSB_CPU_LITTLE"; 163362306a36Sopenharmony_ci break; 163462306a36Sopenharmony_ci case SVSB_CPU_BIG: 163562306a36Sopenharmony_ci svsb->name = "SVSB_CPU_BIG"; 163662306a36Sopenharmony_ci break; 163762306a36Sopenharmony_ci case SVSB_CCI: 163862306a36Sopenharmony_ci svsb->name = "SVSB_CCI"; 163962306a36Sopenharmony_ci break; 164062306a36Sopenharmony_ci case SVSB_GPU: 164162306a36Sopenharmony_ci if (svsb->type == SVSB_HIGH) 164262306a36Sopenharmony_ci svsb->name = "SVSB_GPU_HIGH"; 164362306a36Sopenharmony_ci else if (svsb->type == SVSB_LOW) 164462306a36Sopenharmony_ci svsb->name = "SVSB_GPU_LOW"; 164562306a36Sopenharmony_ci else 164662306a36Sopenharmony_ci svsb->name = "SVSB_GPU"; 164762306a36Sopenharmony_ci break; 164862306a36Sopenharmony_ci default: 164962306a36Sopenharmony_ci dev_err(svsb->dev, "unknown sw_id: %u\n", svsb->sw_id); 165062306a36Sopenharmony_ci return -EINVAL; 165162306a36Sopenharmony_ci } 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci svsb->dev = devm_kzalloc(svsp->dev, sizeof(*svsb->dev), 165462306a36Sopenharmony_ci GFP_KERNEL); 165562306a36Sopenharmony_ci if (!svsb->dev) 165662306a36Sopenharmony_ci return -ENOMEM; 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci ret = dev_set_name(svsb->dev, "%s", svsb->name); 165962306a36Sopenharmony_ci if (ret) 166062306a36Sopenharmony_ci return ret; 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci dev_set_drvdata(svsb->dev, svsp); 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci ret = devm_pm_opp_of_add_table(svsb->opp_dev); 166562306a36Sopenharmony_ci if (ret) { 166662306a36Sopenharmony_ci dev_err(svsb->dev, "add opp table fail: %d\n", ret); 166762306a36Sopenharmony_ci return ret; 166862306a36Sopenharmony_ci } 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci mutex_init(&svsb->lock); 167162306a36Sopenharmony_ci init_completion(&svsb->init_completion); 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci if (svsb->mode_support & SVSB_MODE_INIT01) { 167462306a36Sopenharmony_ci svsb->buck = devm_regulator_get_optional(svsb->opp_dev, 167562306a36Sopenharmony_ci svsb->buck_name); 167662306a36Sopenharmony_ci if (IS_ERR(svsb->buck)) { 167762306a36Sopenharmony_ci dev_err(svsb->dev, "cannot get \"%s-supply\"\n", 167862306a36Sopenharmony_ci svsb->buck_name); 167962306a36Sopenharmony_ci return PTR_ERR(svsb->buck); 168062306a36Sopenharmony_ci } 168162306a36Sopenharmony_ci } 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(svsb->tzone_name)) { 168462306a36Sopenharmony_ci svsb->tzd = thermal_zone_get_zone_by_name(svsb->tzone_name); 168562306a36Sopenharmony_ci if (IS_ERR(svsb->tzd)) { 168662306a36Sopenharmony_ci dev_err(svsb->dev, "cannot get \"%s\" thermal zone\n", 168762306a36Sopenharmony_ci svsb->tzone_name); 168862306a36Sopenharmony_ci return PTR_ERR(svsb->tzd); 168962306a36Sopenharmony_ci } 169062306a36Sopenharmony_ci } 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci count = dev_pm_opp_get_opp_count(svsb->opp_dev); 169362306a36Sopenharmony_ci if (svsb->opp_count != count) { 169462306a36Sopenharmony_ci dev_err(svsb->dev, 169562306a36Sopenharmony_ci "opp_count not \"%u\" but get \"%d\"?\n", 169662306a36Sopenharmony_ci svsb->opp_count, count); 169762306a36Sopenharmony_ci return count; 169862306a36Sopenharmony_ci } 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci for (i = 0, freq = U32_MAX; i < svsb->opp_count; i++, freq--) { 170162306a36Sopenharmony_ci opp = dev_pm_opp_find_freq_floor(svsb->opp_dev, &freq); 170262306a36Sopenharmony_ci if (IS_ERR(opp)) { 170362306a36Sopenharmony_ci dev_err(svsb->dev, "cannot find freq = %ld\n", 170462306a36Sopenharmony_ci PTR_ERR(opp)); 170562306a36Sopenharmony_ci return PTR_ERR(opp); 170662306a36Sopenharmony_ci } 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci svsb->opp_dfreq[i] = freq; 170962306a36Sopenharmony_ci svsb->opp_dvolt[i] = dev_pm_opp_get_voltage(opp); 171062306a36Sopenharmony_ci svsb->freq_pct[i] = percent(svsb->opp_dfreq[i], 171162306a36Sopenharmony_ci svsb->freq_base); 171262306a36Sopenharmony_ci dev_pm_opp_put(opp); 171362306a36Sopenharmony_ci } 171462306a36Sopenharmony_ci } 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci return 0; 171762306a36Sopenharmony_ci} 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_cistatic int svs_get_efuse_data(struct svs_platform *svsp, 172062306a36Sopenharmony_ci const char *nvmem_cell_name, 172162306a36Sopenharmony_ci u32 **svsp_efuse, size_t *svsp_efuse_max) 172262306a36Sopenharmony_ci{ 172362306a36Sopenharmony_ci struct nvmem_cell *cell; 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci cell = nvmem_cell_get(svsp->dev, nvmem_cell_name); 172662306a36Sopenharmony_ci if (IS_ERR(cell)) { 172762306a36Sopenharmony_ci dev_err(svsp->dev, "no \"%s\"? %ld\n", 172862306a36Sopenharmony_ci nvmem_cell_name, PTR_ERR(cell)); 172962306a36Sopenharmony_ci return PTR_ERR(cell); 173062306a36Sopenharmony_ci } 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ci *svsp_efuse = nvmem_cell_read(cell, svsp_efuse_max); 173362306a36Sopenharmony_ci if (IS_ERR(*svsp_efuse)) { 173462306a36Sopenharmony_ci dev_err(svsp->dev, "cannot read \"%s\" efuse: %ld\n", 173562306a36Sopenharmony_ci nvmem_cell_name, PTR_ERR(*svsp_efuse)); 173662306a36Sopenharmony_ci nvmem_cell_put(cell); 173762306a36Sopenharmony_ci return PTR_ERR(*svsp_efuse); 173862306a36Sopenharmony_ci } 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci *svsp_efuse_max /= sizeof(u32); 174162306a36Sopenharmony_ci nvmem_cell_put(cell); 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci return 0; 174462306a36Sopenharmony_ci} 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_cistatic bool svs_mt8192_efuse_parsing(struct svs_platform *svsp) 174762306a36Sopenharmony_ci{ 174862306a36Sopenharmony_ci struct svs_bank *svsb; 174962306a36Sopenharmony_ci u32 idx, i, vmin, golden_temp; 175062306a36Sopenharmony_ci int ret; 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci for (i = 0; i < svsp->efuse_max; i++) 175362306a36Sopenharmony_ci if (svsp->efuse[i]) 175462306a36Sopenharmony_ci dev_info(svsp->dev, "M_HW_RES%d: 0x%08x\n", 175562306a36Sopenharmony_ci i, svsp->efuse[i]); 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci if (!svsp->efuse[9]) { 175862306a36Sopenharmony_ci dev_notice(svsp->dev, "svs_efuse[9] = 0x0?\n"); 175962306a36Sopenharmony_ci return false; 176062306a36Sopenharmony_ci } 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ci /* Svs efuse parsing */ 176362306a36Sopenharmony_ci vmin = (svsp->efuse[19] >> 4) & GENMASK(1, 0); 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci for (idx = 0; idx < svsp->bank_max; idx++) { 176662306a36Sopenharmony_ci svsb = &svsp->banks[idx]; 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_ci if (vmin == 0x1) 176962306a36Sopenharmony_ci svsb->vmin = 0x1e; 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci if (svsb->type == SVSB_LOW) { 177262306a36Sopenharmony_ci svsb->mtdes = svsp->efuse[10] & GENMASK(7, 0); 177362306a36Sopenharmony_ci svsb->bdes = (svsp->efuse[10] >> 16) & GENMASK(7, 0); 177462306a36Sopenharmony_ci svsb->mdes = (svsp->efuse[10] >> 24) & GENMASK(7, 0); 177562306a36Sopenharmony_ci svsb->dcbdet = (svsp->efuse[17]) & GENMASK(7, 0); 177662306a36Sopenharmony_ci svsb->dcmdet = (svsp->efuse[17] >> 8) & GENMASK(7, 0); 177762306a36Sopenharmony_ci } else if (svsb->type == SVSB_HIGH) { 177862306a36Sopenharmony_ci svsb->mtdes = svsp->efuse[9] & GENMASK(7, 0); 177962306a36Sopenharmony_ci svsb->bdes = (svsp->efuse[9] >> 16) & GENMASK(7, 0); 178062306a36Sopenharmony_ci svsb->mdes = (svsp->efuse[9] >> 24) & GENMASK(7, 0); 178162306a36Sopenharmony_ci svsb->dcbdet = (svsp->efuse[17] >> 16) & GENMASK(7, 0); 178262306a36Sopenharmony_ci svsb->dcmdet = (svsp->efuse[17] >> 24) & GENMASK(7, 0); 178362306a36Sopenharmony_ci } 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci svsb->vmax += svsb->dvt_fixed; 178662306a36Sopenharmony_ci } 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci ret = svs_get_efuse_data(svsp, "t-calibration-data", 178962306a36Sopenharmony_ci &svsp->tefuse, &svsp->tefuse_max); 179062306a36Sopenharmony_ci if (ret) 179162306a36Sopenharmony_ci return false; 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci for (i = 0; i < svsp->tefuse_max; i++) 179462306a36Sopenharmony_ci if (svsp->tefuse[i] != 0) 179562306a36Sopenharmony_ci break; 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci if (i == svsp->tefuse_max) 179862306a36Sopenharmony_ci golden_temp = 50; /* All thermal efuse data are 0 */ 179962306a36Sopenharmony_ci else 180062306a36Sopenharmony_ci golden_temp = (svsp->tefuse[0] >> 24) & GENMASK(7, 0); 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ci for (idx = 0; idx < svsp->bank_max; idx++) { 180362306a36Sopenharmony_ci svsb = &svsp->banks[idx]; 180462306a36Sopenharmony_ci svsb->mts = 500; 180562306a36Sopenharmony_ci svsb->bts = (((500 * golden_temp + 250460) / 1000) - 25) * 4; 180662306a36Sopenharmony_ci } 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci return true; 180962306a36Sopenharmony_ci} 181062306a36Sopenharmony_ci 181162306a36Sopenharmony_cistatic bool svs_mt8183_efuse_parsing(struct svs_platform *svsp) 181262306a36Sopenharmony_ci{ 181362306a36Sopenharmony_ci struct svs_bank *svsb; 181462306a36Sopenharmony_ci int format[6], x_roomt[6], o_vtsmcu[5], o_vtsabb, tb_roomt = 0; 181562306a36Sopenharmony_ci int adc_ge_t, adc_oe_t, ge, oe, gain, degc_cali, adc_cali_en_t; 181662306a36Sopenharmony_ci int o_slope, o_slope_sign, ts_id; 181762306a36Sopenharmony_ci u32 idx, i, ft_pgm, mts, temp0, temp1, temp2; 181862306a36Sopenharmony_ci int ret; 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci for (i = 0; i < svsp->efuse_max; i++) 182162306a36Sopenharmony_ci if (svsp->efuse[i]) 182262306a36Sopenharmony_ci dev_info(svsp->dev, "M_HW_RES%d: 0x%08x\n", 182362306a36Sopenharmony_ci i, svsp->efuse[i]); 182462306a36Sopenharmony_ci 182562306a36Sopenharmony_ci if (!svsp->efuse[2]) { 182662306a36Sopenharmony_ci dev_notice(svsp->dev, "svs_efuse[2] = 0x0?\n"); 182762306a36Sopenharmony_ci return false; 182862306a36Sopenharmony_ci } 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci /* Svs efuse parsing */ 183162306a36Sopenharmony_ci ft_pgm = (svsp->efuse[0] >> 4) & GENMASK(3, 0); 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci for (idx = 0; idx < svsp->bank_max; idx++) { 183462306a36Sopenharmony_ci svsb = &svsp->banks[idx]; 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_ci if (ft_pgm <= 1) 183762306a36Sopenharmony_ci svsb->volt_flags |= SVSB_INIT01_VOLT_IGNORE; 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci switch (svsb->sw_id) { 184062306a36Sopenharmony_ci case SVSB_CPU_LITTLE: 184162306a36Sopenharmony_ci svsb->bdes = svsp->efuse[16] & GENMASK(7, 0); 184262306a36Sopenharmony_ci svsb->mdes = (svsp->efuse[16] >> 8) & GENMASK(7, 0); 184362306a36Sopenharmony_ci svsb->dcbdet = (svsp->efuse[16] >> 16) & GENMASK(7, 0); 184462306a36Sopenharmony_ci svsb->dcmdet = (svsp->efuse[16] >> 24) & GENMASK(7, 0); 184562306a36Sopenharmony_ci svsb->mtdes = (svsp->efuse[17] >> 16) & GENMASK(7, 0); 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_ci if (ft_pgm <= 3) 184862306a36Sopenharmony_ci svsb->volt_od += 10; 184962306a36Sopenharmony_ci else 185062306a36Sopenharmony_ci svsb->volt_od += 2; 185162306a36Sopenharmony_ci break; 185262306a36Sopenharmony_ci case SVSB_CPU_BIG: 185362306a36Sopenharmony_ci svsb->bdes = svsp->efuse[18] & GENMASK(7, 0); 185462306a36Sopenharmony_ci svsb->mdes = (svsp->efuse[18] >> 8) & GENMASK(7, 0); 185562306a36Sopenharmony_ci svsb->dcbdet = (svsp->efuse[18] >> 16) & GENMASK(7, 0); 185662306a36Sopenharmony_ci svsb->dcmdet = (svsp->efuse[18] >> 24) & GENMASK(7, 0); 185762306a36Sopenharmony_ci svsb->mtdes = svsp->efuse[17] & GENMASK(7, 0); 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci if (ft_pgm <= 3) 186062306a36Sopenharmony_ci svsb->volt_od += 15; 186162306a36Sopenharmony_ci else 186262306a36Sopenharmony_ci svsb->volt_od += 12; 186362306a36Sopenharmony_ci break; 186462306a36Sopenharmony_ci case SVSB_CCI: 186562306a36Sopenharmony_ci svsb->bdes = svsp->efuse[4] & GENMASK(7, 0); 186662306a36Sopenharmony_ci svsb->mdes = (svsp->efuse[4] >> 8) & GENMASK(7, 0); 186762306a36Sopenharmony_ci svsb->dcbdet = (svsp->efuse[4] >> 16) & GENMASK(7, 0); 186862306a36Sopenharmony_ci svsb->dcmdet = (svsp->efuse[4] >> 24) & GENMASK(7, 0); 186962306a36Sopenharmony_ci svsb->mtdes = (svsp->efuse[5] >> 16) & GENMASK(7, 0); 187062306a36Sopenharmony_ci 187162306a36Sopenharmony_ci if (ft_pgm <= 3) 187262306a36Sopenharmony_ci svsb->volt_od += 10; 187362306a36Sopenharmony_ci else 187462306a36Sopenharmony_ci svsb->volt_od += 2; 187562306a36Sopenharmony_ci break; 187662306a36Sopenharmony_ci case SVSB_GPU: 187762306a36Sopenharmony_ci svsb->bdes = svsp->efuse[6] & GENMASK(7, 0); 187862306a36Sopenharmony_ci svsb->mdes = (svsp->efuse[6] >> 8) & GENMASK(7, 0); 187962306a36Sopenharmony_ci svsb->dcbdet = (svsp->efuse[6] >> 16) & GENMASK(7, 0); 188062306a36Sopenharmony_ci svsb->dcmdet = (svsp->efuse[6] >> 24) & GENMASK(7, 0); 188162306a36Sopenharmony_ci svsb->mtdes = svsp->efuse[5] & GENMASK(7, 0); 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci if (ft_pgm >= 2) { 188462306a36Sopenharmony_ci svsb->freq_base = 800000000; /* 800MHz */ 188562306a36Sopenharmony_ci svsb->dvt_fixed = 2; 188662306a36Sopenharmony_ci } 188762306a36Sopenharmony_ci break; 188862306a36Sopenharmony_ci default: 188962306a36Sopenharmony_ci dev_err(svsb->dev, "unknown sw_id: %u\n", svsb->sw_id); 189062306a36Sopenharmony_ci return false; 189162306a36Sopenharmony_ci } 189262306a36Sopenharmony_ci } 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci ret = svs_get_efuse_data(svsp, "t-calibration-data", 189562306a36Sopenharmony_ci &svsp->tefuse, &svsp->tefuse_max); 189662306a36Sopenharmony_ci if (ret) 189762306a36Sopenharmony_ci return false; 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci /* Thermal efuse parsing */ 190062306a36Sopenharmony_ci adc_ge_t = (svsp->tefuse[1] >> 22) & GENMASK(9, 0); 190162306a36Sopenharmony_ci adc_oe_t = (svsp->tefuse[1] >> 12) & GENMASK(9, 0); 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci o_vtsmcu[0] = (svsp->tefuse[0] >> 17) & GENMASK(8, 0); 190462306a36Sopenharmony_ci o_vtsmcu[1] = (svsp->tefuse[0] >> 8) & GENMASK(8, 0); 190562306a36Sopenharmony_ci o_vtsmcu[2] = svsp->tefuse[1] & GENMASK(8, 0); 190662306a36Sopenharmony_ci o_vtsmcu[3] = (svsp->tefuse[2] >> 23) & GENMASK(8, 0); 190762306a36Sopenharmony_ci o_vtsmcu[4] = (svsp->tefuse[2] >> 5) & GENMASK(8, 0); 190862306a36Sopenharmony_ci o_vtsabb = (svsp->tefuse[2] >> 14) & GENMASK(8, 0); 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_ci degc_cali = (svsp->tefuse[0] >> 1) & GENMASK(5, 0); 191162306a36Sopenharmony_ci adc_cali_en_t = svsp->tefuse[0] & BIT(0); 191262306a36Sopenharmony_ci o_slope_sign = (svsp->tefuse[0] >> 7) & BIT(0); 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ci ts_id = (svsp->tefuse[1] >> 9) & BIT(0); 191562306a36Sopenharmony_ci if (!ts_id) { 191662306a36Sopenharmony_ci o_slope = 1534; 191762306a36Sopenharmony_ci } else { 191862306a36Sopenharmony_ci o_slope = (svsp->tefuse[0] >> 26) & GENMASK(5, 0); 191962306a36Sopenharmony_ci if (!o_slope_sign) 192062306a36Sopenharmony_ci o_slope = 1534 + o_slope * 10; 192162306a36Sopenharmony_ci else 192262306a36Sopenharmony_ci o_slope = 1534 - o_slope * 10; 192362306a36Sopenharmony_ci } 192462306a36Sopenharmony_ci 192562306a36Sopenharmony_ci if (adc_cali_en_t == 0 || 192662306a36Sopenharmony_ci adc_ge_t < 265 || adc_ge_t > 758 || 192762306a36Sopenharmony_ci adc_oe_t < 265 || adc_oe_t > 758 || 192862306a36Sopenharmony_ci o_vtsmcu[0] < -8 || o_vtsmcu[0] > 484 || 192962306a36Sopenharmony_ci o_vtsmcu[1] < -8 || o_vtsmcu[1] > 484 || 193062306a36Sopenharmony_ci o_vtsmcu[2] < -8 || o_vtsmcu[2] > 484 || 193162306a36Sopenharmony_ci o_vtsmcu[3] < -8 || o_vtsmcu[3] > 484 || 193262306a36Sopenharmony_ci o_vtsmcu[4] < -8 || o_vtsmcu[4] > 484 || 193362306a36Sopenharmony_ci o_vtsabb < -8 || o_vtsabb > 484 || 193462306a36Sopenharmony_ci degc_cali < 1 || degc_cali > 63) { 193562306a36Sopenharmony_ci dev_err(svsp->dev, "bad thermal efuse, no mon mode\n"); 193662306a36Sopenharmony_ci goto remove_mt8183_svsb_mon_mode; 193762306a36Sopenharmony_ci } 193862306a36Sopenharmony_ci 193962306a36Sopenharmony_ci ge = ((adc_ge_t - 512) * 10000) / 4096; 194062306a36Sopenharmony_ci oe = (adc_oe_t - 512); 194162306a36Sopenharmony_ci gain = (10000 + ge); 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_ci format[0] = (o_vtsmcu[0] + 3350 - oe); 194462306a36Sopenharmony_ci format[1] = (o_vtsmcu[1] + 3350 - oe); 194562306a36Sopenharmony_ci format[2] = (o_vtsmcu[2] + 3350 - oe); 194662306a36Sopenharmony_ci format[3] = (o_vtsmcu[3] + 3350 - oe); 194762306a36Sopenharmony_ci format[4] = (o_vtsmcu[4] + 3350 - oe); 194862306a36Sopenharmony_ci format[5] = (o_vtsabb + 3350 - oe); 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_ci for (i = 0; i < 6; i++) 195162306a36Sopenharmony_ci x_roomt[i] = (((format[i] * 10000) / 4096) * 10000) / gain; 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci temp0 = (10000 * 100000 / gain) * 15 / 18; 195462306a36Sopenharmony_ci mts = (temp0 * 10) / o_slope; 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_ci for (idx = 0; idx < svsp->bank_max; idx++) { 195762306a36Sopenharmony_ci svsb = &svsp->banks[idx]; 195862306a36Sopenharmony_ci svsb->mts = mts; 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_ci switch (svsb->sw_id) { 196162306a36Sopenharmony_ci case SVSB_CPU_LITTLE: 196262306a36Sopenharmony_ci tb_roomt = x_roomt[3]; 196362306a36Sopenharmony_ci break; 196462306a36Sopenharmony_ci case SVSB_CPU_BIG: 196562306a36Sopenharmony_ci tb_roomt = x_roomt[4]; 196662306a36Sopenharmony_ci break; 196762306a36Sopenharmony_ci case SVSB_CCI: 196862306a36Sopenharmony_ci tb_roomt = x_roomt[3]; 196962306a36Sopenharmony_ci break; 197062306a36Sopenharmony_ci case SVSB_GPU: 197162306a36Sopenharmony_ci tb_roomt = x_roomt[1]; 197262306a36Sopenharmony_ci break; 197362306a36Sopenharmony_ci default: 197462306a36Sopenharmony_ci dev_err(svsb->dev, "unknown sw_id: %u\n", svsb->sw_id); 197562306a36Sopenharmony_ci goto remove_mt8183_svsb_mon_mode; 197662306a36Sopenharmony_ci } 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci temp0 = (degc_cali * 10 / 2); 197962306a36Sopenharmony_ci temp1 = ((10000 * 100000 / 4096 / gain) * 198062306a36Sopenharmony_ci oe + tb_roomt * 10) * 15 / 18; 198162306a36Sopenharmony_ci temp2 = temp1 * 100 / o_slope; 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci svsb->bts = (temp0 + temp2 - 250) * 4 / 10; 198462306a36Sopenharmony_ci } 198562306a36Sopenharmony_ci 198662306a36Sopenharmony_ci return true; 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_ciremove_mt8183_svsb_mon_mode: 198962306a36Sopenharmony_ci for (idx = 0; idx < svsp->bank_max; idx++) { 199062306a36Sopenharmony_ci svsb = &svsp->banks[idx]; 199162306a36Sopenharmony_ci svsb->mode_support &= ~SVSB_MODE_MON; 199262306a36Sopenharmony_ci } 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci return true; 199562306a36Sopenharmony_ci} 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_cistatic struct device *svs_get_subsys_device(struct svs_platform *svsp, 199862306a36Sopenharmony_ci const char *node_name) 199962306a36Sopenharmony_ci{ 200062306a36Sopenharmony_ci struct platform_device *pdev; 200162306a36Sopenharmony_ci struct device_node *np; 200262306a36Sopenharmony_ci 200362306a36Sopenharmony_ci np = of_find_node_by_name(NULL, node_name); 200462306a36Sopenharmony_ci if (!np) { 200562306a36Sopenharmony_ci dev_err(svsp->dev, "cannot find %s node\n", node_name); 200662306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 200762306a36Sopenharmony_ci } 200862306a36Sopenharmony_ci 200962306a36Sopenharmony_ci pdev = of_find_device_by_node(np); 201062306a36Sopenharmony_ci if (!pdev) { 201162306a36Sopenharmony_ci of_node_put(np); 201262306a36Sopenharmony_ci dev_err(svsp->dev, "cannot find pdev by %s\n", node_name); 201362306a36Sopenharmony_ci return ERR_PTR(-ENXIO); 201462306a36Sopenharmony_ci } 201562306a36Sopenharmony_ci 201662306a36Sopenharmony_ci of_node_put(np); 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_ci return &pdev->dev; 201962306a36Sopenharmony_ci} 202062306a36Sopenharmony_ci 202162306a36Sopenharmony_cistatic struct device *svs_add_device_link(struct svs_platform *svsp, 202262306a36Sopenharmony_ci const char *node_name) 202362306a36Sopenharmony_ci{ 202462306a36Sopenharmony_ci struct device *dev; 202562306a36Sopenharmony_ci struct device_link *sup_link; 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci dev = svs_get_subsys_device(svsp, node_name); 202862306a36Sopenharmony_ci if (IS_ERR(dev)) 202962306a36Sopenharmony_ci return dev; 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci sup_link = device_link_add(svsp->dev, dev, 203262306a36Sopenharmony_ci DL_FLAG_AUTOREMOVE_CONSUMER); 203362306a36Sopenharmony_ci if (!sup_link) { 203462306a36Sopenharmony_ci dev_err(svsp->dev, "sup_link is NULL\n"); 203562306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 203662306a36Sopenharmony_ci } 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ci if (sup_link->supplier->links.status != DL_DEV_DRIVER_BOUND) 203962306a36Sopenharmony_ci return ERR_PTR(-EPROBE_DEFER); 204062306a36Sopenharmony_ci 204162306a36Sopenharmony_ci return dev; 204262306a36Sopenharmony_ci} 204362306a36Sopenharmony_ci 204462306a36Sopenharmony_cistatic int svs_mt8192_platform_probe(struct svs_platform *svsp) 204562306a36Sopenharmony_ci{ 204662306a36Sopenharmony_ci struct device *dev; 204762306a36Sopenharmony_ci struct svs_bank *svsb; 204862306a36Sopenharmony_ci u32 idx; 204962306a36Sopenharmony_ci 205062306a36Sopenharmony_ci svsp->rst = devm_reset_control_get_optional(svsp->dev, "svs_rst"); 205162306a36Sopenharmony_ci if (IS_ERR(svsp->rst)) 205262306a36Sopenharmony_ci return dev_err_probe(svsp->dev, PTR_ERR(svsp->rst), 205362306a36Sopenharmony_ci "cannot get svs reset control\n"); 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci dev = svs_add_device_link(svsp, "lvts"); 205662306a36Sopenharmony_ci if (IS_ERR(dev)) 205762306a36Sopenharmony_ci return dev_err_probe(svsp->dev, PTR_ERR(dev), 205862306a36Sopenharmony_ci "failed to get lvts device\n"); 205962306a36Sopenharmony_ci 206062306a36Sopenharmony_ci for (idx = 0; idx < svsp->bank_max; idx++) { 206162306a36Sopenharmony_ci svsb = &svsp->banks[idx]; 206262306a36Sopenharmony_ci 206362306a36Sopenharmony_ci if (svsb->type == SVSB_HIGH) 206462306a36Sopenharmony_ci svsb->opp_dev = svs_add_device_link(svsp, "gpu"); 206562306a36Sopenharmony_ci else if (svsb->type == SVSB_LOW) 206662306a36Sopenharmony_ci svsb->opp_dev = svs_get_subsys_device(svsp, "gpu"); 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci if (IS_ERR(svsb->opp_dev)) 206962306a36Sopenharmony_ci return dev_err_probe(svsp->dev, PTR_ERR(svsb->opp_dev), 207062306a36Sopenharmony_ci "failed to get OPP device for bank %d\n", 207162306a36Sopenharmony_ci idx); 207262306a36Sopenharmony_ci } 207362306a36Sopenharmony_ci 207462306a36Sopenharmony_ci return 0; 207562306a36Sopenharmony_ci} 207662306a36Sopenharmony_ci 207762306a36Sopenharmony_cistatic int svs_mt8183_platform_probe(struct svs_platform *svsp) 207862306a36Sopenharmony_ci{ 207962306a36Sopenharmony_ci struct device *dev; 208062306a36Sopenharmony_ci struct svs_bank *svsb; 208162306a36Sopenharmony_ci u32 idx; 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci dev = svs_add_device_link(svsp, "thermal"); 208462306a36Sopenharmony_ci if (IS_ERR(dev)) 208562306a36Sopenharmony_ci return dev_err_probe(svsp->dev, PTR_ERR(dev), 208662306a36Sopenharmony_ci "failed to get thermal device\n"); 208762306a36Sopenharmony_ci 208862306a36Sopenharmony_ci for (idx = 0; idx < svsp->bank_max; idx++) { 208962306a36Sopenharmony_ci svsb = &svsp->banks[idx]; 209062306a36Sopenharmony_ci 209162306a36Sopenharmony_ci switch (svsb->sw_id) { 209262306a36Sopenharmony_ci case SVSB_CPU_LITTLE: 209362306a36Sopenharmony_ci case SVSB_CPU_BIG: 209462306a36Sopenharmony_ci svsb->opp_dev = get_cpu_device(svsb->cpu_id); 209562306a36Sopenharmony_ci break; 209662306a36Sopenharmony_ci case SVSB_CCI: 209762306a36Sopenharmony_ci svsb->opp_dev = svs_add_device_link(svsp, "cci"); 209862306a36Sopenharmony_ci break; 209962306a36Sopenharmony_ci case SVSB_GPU: 210062306a36Sopenharmony_ci svsb->opp_dev = svs_add_device_link(svsp, "gpu"); 210162306a36Sopenharmony_ci break; 210262306a36Sopenharmony_ci default: 210362306a36Sopenharmony_ci dev_err(svsb->dev, "unknown sw_id: %u\n", svsb->sw_id); 210462306a36Sopenharmony_ci return -EINVAL; 210562306a36Sopenharmony_ci } 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci if (IS_ERR(svsb->opp_dev)) 210862306a36Sopenharmony_ci return dev_err_probe(svsp->dev, PTR_ERR(svsb->opp_dev), 210962306a36Sopenharmony_ci "failed to get OPP device for bank %d\n", 211062306a36Sopenharmony_ci idx); 211162306a36Sopenharmony_ci } 211262306a36Sopenharmony_ci 211362306a36Sopenharmony_ci return 0; 211462306a36Sopenharmony_ci} 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_cistatic struct svs_bank svs_mt8192_banks[] = { 211762306a36Sopenharmony_ci { 211862306a36Sopenharmony_ci .sw_id = SVSB_GPU, 211962306a36Sopenharmony_ci .type = SVSB_LOW, 212062306a36Sopenharmony_ci .set_freq_pct = svs_set_bank_freq_pct_v3, 212162306a36Sopenharmony_ci .get_volts = svs_get_bank_volts_v3, 212262306a36Sopenharmony_ci .tzone_name = "gpu1", 212362306a36Sopenharmony_ci .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT, 212462306a36Sopenharmony_ci .mode_support = SVSB_MODE_INIT02, 212562306a36Sopenharmony_ci .opp_count = MAX_OPP_ENTRIES, 212662306a36Sopenharmony_ci .freq_base = 688000000, 212762306a36Sopenharmony_ci .turn_freq_base = 688000000, 212862306a36Sopenharmony_ci .volt_step = 6250, 212962306a36Sopenharmony_ci .volt_base = 400000, 213062306a36Sopenharmony_ci .vmax = 0x60, 213162306a36Sopenharmony_ci .vmin = 0x1a, 213262306a36Sopenharmony_ci .age_config = 0x555555, 213362306a36Sopenharmony_ci .dc_config = 0x1, 213462306a36Sopenharmony_ci .dvt_fixed = 0x1, 213562306a36Sopenharmony_ci .vco = 0x18, 213662306a36Sopenharmony_ci .chk_shift = 0x87, 213762306a36Sopenharmony_ci .core_sel = 0x0fff0100, 213862306a36Sopenharmony_ci .int_st = BIT(0), 213962306a36Sopenharmony_ci .ctl0 = 0x00540003, 214062306a36Sopenharmony_ci .tzone_htemp = 85000, 214162306a36Sopenharmony_ci .tzone_htemp_voffset = 0, 214262306a36Sopenharmony_ci .tzone_ltemp = 25000, 214362306a36Sopenharmony_ci .tzone_ltemp_voffset = 7, 214462306a36Sopenharmony_ci }, 214562306a36Sopenharmony_ci { 214662306a36Sopenharmony_ci .sw_id = SVSB_GPU, 214762306a36Sopenharmony_ci .type = SVSB_HIGH, 214862306a36Sopenharmony_ci .set_freq_pct = svs_set_bank_freq_pct_v3, 214962306a36Sopenharmony_ci .get_volts = svs_get_bank_volts_v3, 215062306a36Sopenharmony_ci .tzone_name = "gpu1", 215162306a36Sopenharmony_ci .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT | 215262306a36Sopenharmony_ci SVSB_MON_VOLT_IGNORE, 215362306a36Sopenharmony_ci .mode_support = SVSB_MODE_INIT02 | SVSB_MODE_MON, 215462306a36Sopenharmony_ci .opp_count = MAX_OPP_ENTRIES, 215562306a36Sopenharmony_ci .freq_base = 902000000, 215662306a36Sopenharmony_ci .turn_freq_base = 688000000, 215762306a36Sopenharmony_ci .volt_step = 6250, 215862306a36Sopenharmony_ci .volt_base = 400000, 215962306a36Sopenharmony_ci .vmax = 0x60, 216062306a36Sopenharmony_ci .vmin = 0x1a, 216162306a36Sopenharmony_ci .age_config = 0x555555, 216262306a36Sopenharmony_ci .dc_config = 0x1, 216362306a36Sopenharmony_ci .dvt_fixed = 0x6, 216462306a36Sopenharmony_ci .vco = 0x18, 216562306a36Sopenharmony_ci .chk_shift = 0x87, 216662306a36Sopenharmony_ci .core_sel = 0x0fff0101, 216762306a36Sopenharmony_ci .int_st = BIT(1), 216862306a36Sopenharmony_ci .ctl0 = 0x00540003, 216962306a36Sopenharmony_ci .tzone_htemp = 85000, 217062306a36Sopenharmony_ci .tzone_htemp_voffset = 0, 217162306a36Sopenharmony_ci .tzone_ltemp = 25000, 217262306a36Sopenharmony_ci .tzone_ltemp_voffset = 7, 217362306a36Sopenharmony_ci }, 217462306a36Sopenharmony_ci}; 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_cistatic struct svs_bank svs_mt8183_banks[] = { 217762306a36Sopenharmony_ci { 217862306a36Sopenharmony_ci .sw_id = SVSB_CPU_LITTLE, 217962306a36Sopenharmony_ci .set_freq_pct = svs_set_bank_freq_pct_v2, 218062306a36Sopenharmony_ci .get_volts = svs_get_bank_volts_v2, 218162306a36Sopenharmony_ci .cpu_id = 0, 218262306a36Sopenharmony_ci .buck_name = "proc", 218362306a36Sopenharmony_ci .volt_flags = SVSB_INIT01_VOLT_INC_ONLY, 218462306a36Sopenharmony_ci .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02, 218562306a36Sopenharmony_ci .opp_count = MAX_OPP_ENTRIES, 218662306a36Sopenharmony_ci .freq_base = 1989000000, 218762306a36Sopenharmony_ci .vboot = 0x30, 218862306a36Sopenharmony_ci .volt_step = 6250, 218962306a36Sopenharmony_ci .volt_base = 500000, 219062306a36Sopenharmony_ci .vmax = 0x64, 219162306a36Sopenharmony_ci .vmin = 0x18, 219262306a36Sopenharmony_ci .age_config = 0x555555, 219362306a36Sopenharmony_ci .dc_config = 0x555555, 219462306a36Sopenharmony_ci .dvt_fixed = 0x7, 219562306a36Sopenharmony_ci .vco = 0x10, 219662306a36Sopenharmony_ci .chk_shift = 0x77, 219762306a36Sopenharmony_ci .core_sel = 0x8fff0000, 219862306a36Sopenharmony_ci .int_st = BIT(0), 219962306a36Sopenharmony_ci .ctl0 = 0x00010001, 220062306a36Sopenharmony_ci }, 220162306a36Sopenharmony_ci { 220262306a36Sopenharmony_ci .sw_id = SVSB_CPU_BIG, 220362306a36Sopenharmony_ci .set_freq_pct = svs_set_bank_freq_pct_v2, 220462306a36Sopenharmony_ci .get_volts = svs_get_bank_volts_v2, 220562306a36Sopenharmony_ci .cpu_id = 4, 220662306a36Sopenharmony_ci .buck_name = "proc", 220762306a36Sopenharmony_ci .volt_flags = SVSB_INIT01_VOLT_INC_ONLY, 220862306a36Sopenharmony_ci .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02, 220962306a36Sopenharmony_ci .opp_count = MAX_OPP_ENTRIES, 221062306a36Sopenharmony_ci .freq_base = 1989000000, 221162306a36Sopenharmony_ci .vboot = 0x30, 221262306a36Sopenharmony_ci .volt_step = 6250, 221362306a36Sopenharmony_ci .volt_base = 500000, 221462306a36Sopenharmony_ci .vmax = 0x58, 221562306a36Sopenharmony_ci .vmin = 0x10, 221662306a36Sopenharmony_ci .age_config = 0x555555, 221762306a36Sopenharmony_ci .dc_config = 0x555555, 221862306a36Sopenharmony_ci .dvt_fixed = 0x7, 221962306a36Sopenharmony_ci .vco = 0x10, 222062306a36Sopenharmony_ci .chk_shift = 0x77, 222162306a36Sopenharmony_ci .core_sel = 0x8fff0001, 222262306a36Sopenharmony_ci .int_st = BIT(1), 222362306a36Sopenharmony_ci .ctl0 = 0x00000001, 222462306a36Sopenharmony_ci }, 222562306a36Sopenharmony_ci { 222662306a36Sopenharmony_ci .sw_id = SVSB_CCI, 222762306a36Sopenharmony_ci .set_freq_pct = svs_set_bank_freq_pct_v2, 222862306a36Sopenharmony_ci .get_volts = svs_get_bank_volts_v2, 222962306a36Sopenharmony_ci .buck_name = "proc", 223062306a36Sopenharmony_ci .volt_flags = SVSB_INIT01_VOLT_INC_ONLY, 223162306a36Sopenharmony_ci .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02, 223262306a36Sopenharmony_ci .opp_count = MAX_OPP_ENTRIES, 223362306a36Sopenharmony_ci .freq_base = 1196000000, 223462306a36Sopenharmony_ci .vboot = 0x30, 223562306a36Sopenharmony_ci .volt_step = 6250, 223662306a36Sopenharmony_ci .volt_base = 500000, 223762306a36Sopenharmony_ci .vmax = 0x64, 223862306a36Sopenharmony_ci .vmin = 0x18, 223962306a36Sopenharmony_ci .age_config = 0x555555, 224062306a36Sopenharmony_ci .dc_config = 0x555555, 224162306a36Sopenharmony_ci .dvt_fixed = 0x7, 224262306a36Sopenharmony_ci .vco = 0x10, 224362306a36Sopenharmony_ci .chk_shift = 0x77, 224462306a36Sopenharmony_ci .core_sel = 0x8fff0002, 224562306a36Sopenharmony_ci .int_st = BIT(2), 224662306a36Sopenharmony_ci .ctl0 = 0x00100003, 224762306a36Sopenharmony_ci }, 224862306a36Sopenharmony_ci { 224962306a36Sopenharmony_ci .sw_id = SVSB_GPU, 225062306a36Sopenharmony_ci .set_freq_pct = svs_set_bank_freq_pct_v2, 225162306a36Sopenharmony_ci .get_volts = svs_get_bank_volts_v2, 225262306a36Sopenharmony_ci .buck_name = "mali", 225362306a36Sopenharmony_ci .tzone_name = "tzts2", 225462306a36Sopenharmony_ci .volt_flags = SVSB_INIT01_PD_REQ | 225562306a36Sopenharmony_ci SVSB_INIT01_VOLT_INC_ONLY, 225662306a36Sopenharmony_ci .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02 | 225762306a36Sopenharmony_ci SVSB_MODE_MON, 225862306a36Sopenharmony_ci .opp_count = MAX_OPP_ENTRIES, 225962306a36Sopenharmony_ci .freq_base = 900000000, 226062306a36Sopenharmony_ci .vboot = 0x30, 226162306a36Sopenharmony_ci .volt_step = 6250, 226262306a36Sopenharmony_ci .volt_base = 500000, 226362306a36Sopenharmony_ci .vmax = 0x40, 226462306a36Sopenharmony_ci .vmin = 0x14, 226562306a36Sopenharmony_ci .age_config = 0x555555, 226662306a36Sopenharmony_ci .dc_config = 0x555555, 226762306a36Sopenharmony_ci .dvt_fixed = 0x3, 226862306a36Sopenharmony_ci .vco = 0x10, 226962306a36Sopenharmony_ci .chk_shift = 0x77, 227062306a36Sopenharmony_ci .core_sel = 0x8fff0003, 227162306a36Sopenharmony_ci .int_st = BIT(3), 227262306a36Sopenharmony_ci .ctl0 = 0x00050001, 227362306a36Sopenharmony_ci .tzone_htemp = 85000, 227462306a36Sopenharmony_ci .tzone_htemp_voffset = 0, 227562306a36Sopenharmony_ci .tzone_ltemp = 25000, 227662306a36Sopenharmony_ci .tzone_ltemp_voffset = 3, 227762306a36Sopenharmony_ci }, 227862306a36Sopenharmony_ci}; 227962306a36Sopenharmony_ci 228062306a36Sopenharmony_cistatic const struct svs_platform_data svs_mt8192_platform_data = { 228162306a36Sopenharmony_ci .name = "mt8192-svs", 228262306a36Sopenharmony_ci .banks = svs_mt8192_banks, 228362306a36Sopenharmony_ci .efuse_parsing = svs_mt8192_efuse_parsing, 228462306a36Sopenharmony_ci .probe = svs_mt8192_platform_probe, 228562306a36Sopenharmony_ci .regs = svs_regs_v2, 228662306a36Sopenharmony_ci .bank_max = ARRAY_SIZE(svs_mt8192_banks), 228762306a36Sopenharmony_ci}; 228862306a36Sopenharmony_ci 228962306a36Sopenharmony_cistatic const struct svs_platform_data svs_mt8183_platform_data = { 229062306a36Sopenharmony_ci .name = "mt8183-svs", 229162306a36Sopenharmony_ci .banks = svs_mt8183_banks, 229262306a36Sopenharmony_ci .efuse_parsing = svs_mt8183_efuse_parsing, 229362306a36Sopenharmony_ci .probe = svs_mt8183_platform_probe, 229462306a36Sopenharmony_ci .regs = svs_regs_v2, 229562306a36Sopenharmony_ci .bank_max = ARRAY_SIZE(svs_mt8183_banks), 229662306a36Sopenharmony_ci}; 229762306a36Sopenharmony_ci 229862306a36Sopenharmony_cistatic const struct of_device_id svs_of_match[] = { 229962306a36Sopenharmony_ci { 230062306a36Sopenharmony_ci .compatible = "mediatek,mt8192-svs", 230162306a36Sopenharmony_ci .data = &svs_mt8192_platform_data, 230262306a36Sopenharmony_ci }, { 230362306a36Sopenharmony_ci .compatible = "mediatek,mt8183-svs", 230462306a36Sopenharmony_ci .data = &svs_mt8183_platform_data, 230562306a36Sopenharmony_ci }, { 230662306a36Sopenharmony_ci /* Sentinel */ 230762306a36Sopenharmony_ci }, 230862306a36Sopenharmony_ci}; 230962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, svs_of_match); 231062306a36Sopenharmony_ci 231162306a36Sopenharmony_cistatic int svs_probe(struct platform_device *pdev) 231262306a36Sopenharmony_ci{ 231362306a36Sopenharmony_ci struct svs_platform *svsp; 231462306a36Sopenharmony_ci const struct svs_platform_data *svsp_data; 231562306a36Sopenharmony_ci int ret, svsp_irq; 231662306a36Sopenharmony_ci 231762306a36Sopenharmony_ci svsp_data = of_device_get_match_data(&pdev->dev); 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci svsp = devm_kzalloc(&pdev->dev, sizeof(*svsp), GFP_KERNEL); 232062306a36Sopenharmony_ci if (!svsp) 232162306a36Sopenharmony_ci return -ENOMEM; 232262306a36Sopenharmony_ci 232362306a36Sopenharmony_ci svsp->dev = &pdev->dev; 232462306a36Sopenharmony_ci svsp->banks = svsp_data->banks; 232562306a36Sopenharmony_ci svsp->regs = svsp_data->regs; 232662306a36Sopenharmony_ci svsp->bank_max = svsp_data->bank_max; 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci ret = svsp_data->probe(svsp); 232962306a36Sopenharmony_ci if (ret) 233062306a36Sopenharmony_ci return ret; 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci ret = svs_get_efuse_data(svsp, "svs-calibration-data", 233362306a36Sopenharmony_ci &svsp->efuse, &svsp->efuse_max); 233462306a36Sopenharmony_ci if (ret) { 233562306a36Sopenharmony_ci ret = -EPERM; 233662306a36Sopenharmony_ci goto svs_probe_free_efuse; 233762306a36Sopenharmony_ci } 233862306a36Sopenharmony_ci 233962306a36Sopenharmony_ci if (!svsp_data->efuse_parsing(svsp)) { 234062306a36Sopenharmony_ci dev_err(svsp->dev, "efuse data parsing failed\n"); 234162306a36Sopenharmony_ci ret = -EPERM; 234262306a36Sopenharmony_ci goto svs_probe_free_tefuse; 234362306a36Sopenharmony_ci } 234462306a36Sopenharmony_ci 234562306a36Sopenharmony_ci ret = svs_bank_resource_setup(svsp); 234662306a36Sopenharmony_ci if (ret) { 234762306a36Sopenharmony_ci dev_err(svsp->dev, "svs bank resource setup fail: %d\n", ret); 234862306a36Sopenharmony_ci goto svs_probe_free_tefuse; 234962306a36Sopenharmony_ci } 235062306a36Sopenharmony_ci 235162306a36Sopenharmony_ci svsp_irq = platform_get_irq(pdev, 0); 235262306a36Sopenharmony_ci if (svsp_irq < 0) { 235362306a36Sopenharmony_ci ret = svsp_irq; 235462306a36Sopenharmony_ci goto svs_probe_free_tefuse; 235562306a36Sopenharmony_ci } 235662306a36Sopenharmony_ci 235762306a36Sopenharmony_ci svsp->main_clk = devm_clk_get(svsp->dev, "main"); 235862306a36Sopenharmony_ci if (IS_ERR(svsp->main_clk)) { 235962306a36Sopenharmony_ci dev_err(svsp->dev, "failed to get clock: %ld\n", 236062306a36Sopenharmony_ci PTR_ERR(svsp->main_clk)); 236162306a36Sopenharmony_ci ret = PTR_ERR(svsp->main_clk); 236262306a36Sopenharmony_ci goto svs_probe_free_tefuse; 236362306a36Sopenharmony_ci } 236462306a36Sopenharmony_ci 236562306a36Sopenharmony_ci ret = clk_prepare_enable(svsp->main_clk); 236662306a36Sopenharmony_ci if (ret) { 236762306a36Sopenharmony_ci dev_err(svsp->dev, "cannot enable main clk: %d\n", ret); 236862306a36Sopenharmony_ci goto svs_probe_free_tefuse; 236962306a36Sopenharmony_ci } 237062306a36Sopenharmony_ci 237162306a36Sopenharmony_ci svsp->base = of_iomap(svsp->dev->of_node, 0); 237262306a36Sopenharmony_ci if (IS_ERR_OR_NULL(svsp->base)) { 237362306a36Sopenharmony_ci dev_err(svsp->dev, "cannot find svs register base\n"); 237462306a36Sopenharmony_ci ret = -EINVAL; 237562306a36Sopenharmony_ci goto svs_probe_clk_disable; 237662306a36Sopenharmony_ci } 237762306a36Sopenharmony_ci 237862306a36Sopenharmony_ci ret = devm_request_threaded_irq(svsp->dev, svsp_irq, NULL, svs_isr, 237962306a36Sopenharmony_ci IRQF_ONESHOT, svsp_data->name, svsp); 238062306a36Sopenharmony_ci if (ret) { 238162306a36Sopenharmony_ci dev_err(svsp->dev, "register irq(%d) failed: %d\n", 238262306a36Sopenharmony_ci svsp_irq, ret); 238362306a36Sopenharmony_ci goto svs_probe_iounmap; 238462306a36Sopenharmony_ci } 238562306a36Sopenharmony_ci 238662306a36Sopenharmony_ci ret = svs_start(svsp); 238762306a36Sopenharmony_ci if (ret) { 238862306a36Sopenharmony_ci dev_err(svsp->dev, "svs start fail: %d\n", ret); 238962306a36Sopenharmony_ci goto svs_probe_iounmap; 239062306a36Sopenharmony_ci } 239162306a36Sopenharmony_ci 239262306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 239362306a36Sopenharmony_ci ret = svs_create_debug_cmds(svsp); 239462306a36Sopenharmony_ci if (ret) { 239562306a36Sopenharmony_ci dev_err(svsp->dev, "svs create debug cmds fail: %d\n", ret); 239662306a36Sopenharmony_ci goto svs_probe_iounmap; 239762306a36Sopenharmony_ci } 239862306a36Sopenharmony_ci#endif 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_ci return 0; 240162306a36Sopenharmony_ci 240262306a36Sopenharmony_cisvs_probe_iounmap: 240362306a36Sopenharmony_ci iounmap(svsp->base); 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_cisvs_probe_clk_disable: 240662306a36Sopenharmony_ci clk_disable_unprepare(svsp->main_clk); 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_cisvs_probe_free_tefuse: 240962306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(svsp->tefuse)) 241062306a36Sopenharmony_ci kfree(svsp->tefuse); 241162306a36Sopenharmony_ci 241262306a36Sopenharmony_cisvs_probe_free_efuse: 241362306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(svsp->efuse)) 241462306a36Sopenharmony_ci kfree(svsp->efuse); 241562306a36Sopenharmony_ci 241662306a36Sopenharmony_ci return ret; 241762306a36Sopenharmony_ci} 241862306a36Sopenharmony_ci 241962306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(svs_pm_ops, svs_suspend, svs_resume); 242062306a36Sopenharmony_ci 242162306a36Sopenharmony_cistatic struct platform_driver svs_driver = { 242262306a36Sopenharmony_ci .probe = svs_probe, 242362306a36Sopenharmony_ci .driver = { 242462306a36Sopenharmony_ci .name = "mtk-svs", 242562306a36Sopenharmony_ci .pm = &svs_pm_ops, 242662306a36Sopenharmony_ci .of_match_table = svs_of_match, 242762306a36Sopenharmony_ci }, 242862306a36Sopenharmony_ci}; 242962306a36Sopenharmony_ci 243062306a36Sopenharmony_cimodule_platform_driver(svs_driver); 243162306a36Sopenharmony_ci 243262306a36Sopenharmony_ciMODULE_AUTHOR("Roger Lu <roger.lu@mediatek.com>"); 243362306a36Sopenharmony_ciMODULE_DESCRIPTION("MediaTek SVS driver"); 243462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2435