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