diff options
Diffstat (limited to 'drivers/soc/mediatek/mtk-svs.c')
| -rw-r--r-- | drivers/soc/mediatek/mtk-svs.c | 1901 |
1 files changed, 1200 insertions, 701 deletions
diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c index 0469c9dfeb04..f45537546553 100644 --- a/drivers/soc/mediatek/mtk-svs.c +++ b/drivers/soc/mediatek/mtk-svs.c @@ -1,12 +1,15 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2022 MediaTek Inc. + * Copyright (C) 2022 Collabora Ltd. + * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> */ #include <linux/bitfield.h> #include <linux/bits.h> #include <linux/clk.h> #include <linux/completion.h> +#include <linux/cpu.h> #include <linux/cpuidle.h> #include <linux/debugfs.h> #include <linux/device.h> @@ -31,16 +34,6 @@ #include <linux/spinlock.h> #include <linux/thermal.h> -/* svs bank 1-line software id */ -#define SVSB_CPU_LITTLE BIT(0) -#define SVSB_CPU_BIG BIT(1) -#define SVSB_CCI BIT(2) -#define SVSB_GPU BIT(3) - -/* svs bank 2-line type */ -#define SVSB_LOW BIT(8) -#define SVSB_HIGH BIT(9) - /* svs bank mode support */ #define SVSB_MODE_ALL_DISABLE 0 #define SVSB_MODE_INIT01 BIT(1) @@ -127,6 +120,13 @@ #define SVSB_VOPS_FLD_VOP2_6 GENMASK(23, 16) #define SVSB_VOPS_FLD_VOP3_7 GENMASK(31, 24) +/* SVS Thermal Coefficients */ +#define SVSB_TS_COEFF_MT8195 250460 +#define SVSB_TS_COEFF_MT8186 204650 + +/* Algo helpers */ +#define FUSE_DATA_NOT_VALID U32_MAX + /* svs bank related setting */ #define BITS8 8 #define MAX_OPP_ENTRIES 16 @@ -138,6 +138,7 @@ static DEFINE_SPINLOCK(svs_lock); +#ifdef CONFIG_DEBUG_FS #define debug_fops_ro(name) \ static int svs_##name##_debug_open(struct inode *inode, \ struct file *filp) \ @@ -170,6 +171,37 @@ static DEFINE_SPINLOCK(svs_lock); } #define svs_dentry_data(name) {__stringify(name), &svs_##name##_debug_fops} +#endif + +/** + * enum svsb_sw_id - SVS Bank Software ID + * @SVSB_SWID_CPU_LITTLE: CPU little cluster Bank + * @SVSB_SWID_CPU_BIG: CPU big cluster Bank + * @SVSB_SWID_CCI: Cache Coherent Interconnect Bank + * @SVSB_SWID_GPU: GPU Bank + * @SVSB_SWID_MAX: Total number of Banks + */ +enum svsb_sw_id { + SVSB_SWID_CPU_LITTLE, + SVSB_SWID_CPU_BIG, + SVSB_SWID_CCI, + SVSB_SWID_GPU, + SVSB_SWID_MAX +}; + +/** + * enum svsb_type - SVS Bank 2-line: Type and Role + * @SVSB_TYPE_NONE: One-line type Bank - Global role + * @SVSB_TYPE_LOW: Two-line type Bank - Low bank role + * @SVSB_TYPE_HIGH: Two-line type Bank - High bank role + * @SVSB_TYPE_MAX: Total number of bank types + */ +enum svsb_type { + SVSB_TYPE_NONE, + SVSB_TYPE_LOW, + SVSB_TYPE_HIGH, + SVSB_TYPE_MAX +}; /** * enum svsb_phase - svs bank phase enumeration @@ -253,155 +285,213 @@ enum svs_reg_index { }; static const u32 svs_regs_v2[] = { - [DESCHAR] = 0xc00, - [TEMPCHAR] = 0xc04, - [DETCHAR] = 0xc08, - [AGECHAR] = 0xc0c, - [DCCONFIG] = 0xc10, - [AGECONFIG] = 0xc14, - [FREQPCT30] = 0xc18, - [FREQPCT74] = 0xc1c, - [LIMITVALS] = 0xc20, - [VBOOT] = 0xc24, - [DETWINDOW] = 0xc28, - [CONFIG] = 0xc2c, - [TSCALCS] = 0xc30, - [RUNCONFIG] = 0xc34, - [SVSEN] = 0xc38, - [INIT2VALS] = 0xc3c, - [DCVALUES] = 0xc40, - [AGEVALUES] = 0xc44, - [VOP30] = 0xc48, - [VOP74] = 0xc4c, - [TEMP] = 0xc50, - [INTSTS] = 0xc54, - [INTSTSRAW] = 0xc58, - [INTEN] = 0xc5c, - [CHKINT] = 0xc60, - [CHKSHIFT] = 0xc64, - [STATUS] = 0xc68, - [VDESIGN30] = 0xc6c, - [VDESIGN74] = 0xc70, - [DVT30] = 0xc74, - [DVT74] = 0xc78, - [AGECOUNT] = 0xc7c, - [SMSTATE0] = 0xc80, - [SMSTATE1] = 0xc84, - [CTL0] = 0xc88, - [DESDETSEC] = 0xce0, - [TEMPAGESEC] = 0xce4, - [CTRLSPARE0] = 0xcf0, - [CTRLSPARE1] = 0xcf4, - [CTRLSPARE2] = 0xcf8, - [CTRLSPARE3] = 0xcfc, - [CORESEL] = 0xf00, - [THERMINTST] = 0xf04, - [INTST] = 0xf08, - [THSTAGE0ST] = 0xf0c, - [THSTAGE1ST] = 0xf10, - [THSTAGE2ST] = 0xf14, - [THAHBST0] = 0xf18, - [THAHBST1] = 0xf1c, - [SPARE0] = 0xf20, - [SPARE1] = 0xf24, - [SPARE2] = 0xf28, - [SPARE3] = 0xf2c, - [THSLPEVEB] = 0xf30, + [DESCHAR] = 0x00, + [TEMPCHAR] = 0x04, + [DETCHAR] = 0x08, + [AGECHAR] = 0x0c, + [DCCONFIG] = 0x10, + [AGECONFIG] = 0x14, + [FREQPCT30] = 0x18, + [FREQPCT74] = 0x1c, + [LIMITVALS] = 0x20, + [VBOOT] = 0x24, + [DETWINDOW] = 0x28, + [CONFIG] = 0x2c, + [TSCALCS] = 0x30, + [RUNCONFIG] = 0x34, + [SVSEN] = 0x38, + [INIT2VALS] = 0x3c, + [DCVALUES] = 0x40, + [AGEVALUES] = 0x44, + [VOP30] = 0x48, + [VOP74] = 0x4c, + [TEMP] = 0x50, + [INTSTS] = 0x54, + [INTSTSRAW] = 0x58, + [INTEN] = 0x5c, + [CHKINT] = 0x60, + [CHKSHIFT] = 0x64, + [STATUS] = 0x68, + [VDESIGN30] = 0x6c, + [VDESIGN74] = 0x70, + [DVT30] = 0x74, + [DVT74] = 0x78, + [AGECOUNT] = 0x7c, + [SMSTATE0] = 0x80, + [SMSTATE1] = 0x84, + [CTL0] = 0x88, + [DESDETSEC] = 0xe0, + [TEMPAGESEC] = 0xe4, + [CTRLSPARE0] = 0xf0, + [CTRLSPARE1] = 0xf4, + [CTRLSPARE2] = 0xf8, + [CTRLSPARE3] = 0xfc, + [CORESEL] = 0x300, + [THERMINTST] = 0x304, + [INTST] = 0x308, + [THSTAGE0ST] = 0x30c, + [THSTAGE1ST] = 0x310, + [THSTAGE2ST] = 0x314, + [THAHBST0] = 0x318, + [THAHBST1] = 0x31c, + [SPARE0] = 0x320, + [SPARE1] = 0x324, + [SPARE2] = 0x328, + [SPARE3] = 0x32c, + [THSLPEVEB] = 0x330, +}; + +static const char * const svs_swid_names[SVSB_SWID_MAX] = { + "SVSB_CPU_LITTLE", "SVSB_CPU_BIG", "SVSB_CCI", "SVSB_GPU" +}; + +static const char * const svs_type_names[SVSB_TYPE_MAX] = { + "", "_LOW", "_HIGH" +}; + +enum svs_fusemap_dev { + BDEV_BDES, + BDEV_MDES, + BDEV_MTDES, + BDEV_DCBDET, + BDEV_DCMDET, + BDEV_MAX +}; + +enum svs_fusemap_glb { + GLB_FT_PGM, + GLB_VMIN, + GLB_MAX +}; + +struct svs_fusemap { + s8 index; + u8 ofst; }; /** * struct svs_platform - svs platform control - * @name: svs platform name * @base: svs platform register base * @dev: svs platform device * @main_clk: main clock for svs bank - * @pbank: svs bank pointer needing to be protected by spin_lock section * @banks: svs banks that svs platform supports * @rst: svs platform reset control - * @efuse_parsing: svs platform efuse parsing function pointer - * @probe: svs platform probe function pointer * @efuse_max: total number of svs efuse * @tefuse_max: total number of thermal efuse * @regs: svs platform registers map - * @bank_max: total number of svs banks * @efuse: svs efuse data received from NVMEM framework * @tefuse: thermal efuse data received from NVMEM framework + * @ts_coeff: thermal sensors coefficient + * @bank_max: total number of svs banks */ struct svs_platform { - char *name; void __iomem *base; struct device *dev; struct clk *main_clk; - struct svs_bank *pbank; struct svs_bank *banks; struct reset_control *rst; - bool (*efuse_parsing)(struct svs_platform *svsp); - int (*probe)(struct svs_platform *svsp); size_t efuse_max; size_t tefuse_max; const u32 *regs; - u32 bank_max; u32 *efuse; u32 *tefuse; + u32 ts_coeff; + u16 bank_max; }; struct svs_platform_data { char *name; struct svs_bank *banks; - bool (*efuse_parsing)(struct svs_platform *svsp); + bool (*efuse_parsing)(struct svs_platform *svsp, const struct svs_platform_data *pdata); int (*probe)(struct svs_platform *svsp); + const struct svs_fusemap *glb_fuse_map; const u32 *regs; - u32 bank_max; + u32 ts_coeff; + u16 bank_max; +}; + +/** + * struct svs_bank_pdata - SVS Bank immutable config parameters + * @dev_fuse_map: Bank fuse map data + * @buck_name: Regulator name + * @tzone_name: Thermal zone name + * @age_config: Bank age configuration + * @ctl0: TS-x selection + * @dc_config: Bank dc configuration + * @int_st: Bank interrupt identification + * @turn_freq_base: Reference frequency for 2-line turn point + * @tzone_htemp: Thermal zone high temperature threshold + * @tzone_ltemp: Thermal zone low temperature threshold + * @volt_step: Bank voltage step + * @volt_base: Bank voltage base + * @tzone_htemp_voffset: Thermal zone high temperature voltage offset + * @tzone_ltemp_voffset: Thermal zone low temperature voltage offset + * @chk_shift: Bank chicken shift + * @cpu_id: CPU core ID for SVS CPU bank use only + * @opp_count: Bank opp count + * @vboot: Voltage request for bank init01 only + * @vco: Bank VCO value + * @sw_id: Bank software identification + * @type: SVS Bank Type (1 or 2-line) and Role (high/low) + * @set_freq_pct: function pointer to set bank frequency percent table + * @get_volts: function pointer to get bank voltages + */ +struct svs_bank_pdata { + const struct svs_fusemap *dev_fuse_map; + char *buck_name; + char *tzone_name; + u32 age_config; + u32 ctl0; + u32 dc_config; + u32 int_st; + u32 turn_freq_base; + u32 tzone_htemp; + u32 tzone_ltemp; + u32 volt_step; + u32 volt_base; + u16 tzone_htemp_voffset; + u16 tzone_ltemp_voffset; + u8 chk_shift; + u8 cpu_id; + u8 opp_count; + u8 vboot; + u8 vco; + u8 sw_id; + u8 type; + + /* Callbacks */ + void (*set_freq_pct)(struct svs_platform *svsp, struct svs_bank *svsb); + void (*get_volts)(struct svs_platform *svsp, struct svs_bank *svsb); }; /** * struct svs_bank - svs bank representation + * @pdata: SVS Bank immutable config parameters * @dev: bank device * @opp_dev: device for opp table/buck control * @init_completion: the timeout completion for bank init * @buck: regulator used by opp_dev * @tzd: thermal zone device for getting temperature * @lock: mutex lock to protect voltage update process - * @set_freq_pct: function pointer to set bank frequency percent table - * @get_volts: function pointer to get bank voltages * @name: bank name - * @buck_name: regulator name - * @tzone_name: thermal zone name * @phase: bank current phase * @volt_od: bank voltage overdrive * @reg_data: bank register data in different phase for debug purpose * @pm_runtime_enabled_count: bank pm runtime enabled count - * @mode_support: bank mode support. + * @mode_support: bank mode support * @freq_base: reference frequency for bank init - * @turn_freq_base: refenrece frequency for 2-line turn point - * @vboot: voltage request for bank init01 only * @opp_dfreq: default opp frequency table * @opp_dvolt: default opp voltage table * @freq_pct: frequency percent table for bank init * @volt: bank voltage table - * @volt_step: bank voltage step - * @volt_base: bank voltage base * @volt_flags: bank voltage flags * @vmax: bank voltage maximum * @vmin: bank voltage minimum - * @age_config: bank age configuration * @age_voffset_in: bank age voltage offset - * @dc_config: bank dc configuration * @dc_voffset_in: bank dc voltage offset * @dvt_fixed: bank dvt fixed value - * @vco: bank VCO value - * @chk_shift: bank chicken shift * @core_sel: bank selection - * @opp_count: bank opp count - * @int_st: bank interrupt identification - * @sw_id: bank software identification - * @cpu_id: cpu core id for SVS CPU bank use only - * @ctl0: TS-x selection * @temp: bank temperature - * @tzone_htemp: thermal zone high temperature threshold - * @tzone_htemp_voffset: thermal zone high temperature voltage offset - * @tzone_ltemp: thermal zone low temperature threshold - * @tzone_ltemp_voffset: thermal zone low temperature voltage offset * @bts: svs efuse data * @mts: svs efuse data * @bdes: svs efuse data @@ -410,69 +500,49 @@ struct svs_platform_data { * @dcbdet: svs efuse data * @dcmdet: svs efuse data * @turn_pt: 2-line turn point tells which opp_volt calculated by high/low bank - * @type: bank type to represent it is 2-line (high/low) bank or 1-line bank + * @vbin_turn_pt: voltage bin turn point helps know which svsb_volt should be overridden * - * Svs bank will generate suitalbe voltages by below general math equation + * Svs bank will generate suitable voltages by below general math equation * and provide these voltages to opp voltage table. * * opp_volt[i] = (volt[i] * volt_step) + volt_base; */ struct svs_bank { + const struct svs_bank_pdata pdata; struct device *dev; struct device *opp_dev; struct completion init_completion; struct regulator *buck; struct thermal_zone_device *tzd; - struct mutex lock; /* lock to protect voltage update process */ - void (*set_freq_pct)(struct svs_platform *svsp); - void (*get_volts)(struct svs_platform *svsp); + struct mutex lock; + int pm_runtime_enabled_count; + short int volt_od; char *name; - char *buck_name; - char *tzone_name; enum svsb_phase phase; - s32 volt_od; u32 reg_data[SVSB_PHASE_MAX][SVS_REG_MAX]; - u32 pm_runtime_enabled_count; - u32 mode_support; - u32 freq_base; - u32 turn_freq_base; - u32 vboot; + u8 mode_support; u32 opp_dfreq[MAX_OPP_ENTRIES]; u32 opp_dvolt[MAX_OPP_ENTRIES]; u32 freq_pct[MAX_OPP_ENTRIES]; u32 volt[MAX_OPP_ENTRIES]; - u32 volt_step; - u32 volt_base; u32 volt_flags; - u32 vmax; - u32 vmin; - u32 age_config; - u32 age_voffset_in; - u32 dc_config; - u32 dc_voffset_in; - u32 dvt_fixed; - u32 vco; - u32 chk_shift; + u32 freq_base; + u32 turn_pt; + u32 vbin_turn_pt; u32 core_sel; - u32 opp_count; - u32 int_st; - u32 sw_id; - u32 cpu_id; - u32 ctl0; u32 temp; - u32 tzone_htemp; - u32 tzone_htemp_voffset; - u32 tzone_ltemp; - u32 tzone_ltemp_voffset; - u32 bts; - u32 mts; - u32 bdes; - u32 mdes; - u32 mtdes; - u32 dcbdet; - u32 dcmdet; - u32 turn_pt; - u32 type; + u16 age_voffset_in; + u16 dc_voffset_in; + u8 dvt_fixed; + u8 vmax; + u8 vmin; + u16 bts; + u16 mts; + u16 bdes; + u16 mdes; + u8 mtdes; + u8 dcbdet; + u8 dcmdet; }; static u32 percent(u32 numerator, u32 denominator) @@ -495,10 +565,8 @@ static void svs_writel_relaxed(struct svs_platform *svsp, u32 val, writel_relaxed(val, svsp->base + svsp->regs[rg_i]); } -static void svs_switch_bank(struct svs_platform *svsp) +static void svs_switch_bank(struct svs_platform *svsp, struct svs_bank *svsb) { - struct svs_bank *svsb = svsp->pbank; - svs_writel_relaxed(svsp, svsb->core_sel, CORESEL); } @@ -516,10 +584,11 @@ static u32 svs_opp_volt_to_bank_volt(u32 opp_u_volt, u32 svsb_volt_step, static int svs_sync_bank_volts_from_opp(struct svs_bank *svsb) { + const struct svs_bank_pdata *bdata = &svsb->pdata; struct dev_pm_opp *opp; u32 i, opp_u_volt; - for (i = 0; i < svsb->opp_count; i++) { + for (i = 0; i < bdata->opp_count; i++) { opp = dev_pm_opp_find_freq_exact(svsb->opp_dev, svsb->opp_dfreq[i], true); @@ -531,8 +600,8 @@ static int svs_sync_bank_volts_from_opp(struct svs_bank *svsb) opp_u_volt = dev_pm_opp_get_voltage(opp); svsb->volt[i] = svs_opp_volt_to_bank_volt(opp_u_volt, - svsb->volt_step, - svsb->volt_base); + bdata->volt_step, + bdata->volt_base); dev_pm_opp_put(opp); } @@ -542,6 +611,7 @@ static int svs_sync_bank_volts_from_opp(struct svs_bank *svsb) static int svs_adjust_pm_opp_volts(struct svs_bank *svsb) { int ret = -EPERM, tzone_temp = 0; + const struct svs_bank_pdata *bdata = &svsb->pdata; u32 i, svsb_volt, opp_volt, temp_voffset = 0, opp_start, opp_stop; mutex_lock(&svsb->lock); @@ -550,36 +620,37 @@ static int svs_adjust_pm_opp_volts(struct svs_bank *svsb) * 2-line bank updates its corresponding opp volts. * 1-line bank updates all opp volts. */ - if (svsb->type == SVSB_HIGH) { + if (bdata->type == SVSB_TYPE_HIGH) { opp_start = 0; opp_stop = svsb->turn_pt; - } else if (svsb->type == SVSB_LOW) { + } else if (bdata->type == SVSB_TYPE_LOW) { opp_start = svsb->turn_pt; - opp_stop = svsb->opp_count; + opp_stop = bdata->opp_count; } else { opp_start = 0; - opp_stop = svsb->opp_count; + opp_stop = bdata->opp_count; } /* Get thermal effect */ - if (svsb->phase == SVSB_PHASE_MON) { + if (!IS_ERR_OR_NULL(svsb->tzd)) { ret = thermal_zone_get_temp(svsb->tzd, &tzone_temp); if (ret || (svsb->temp > SVSB_TEMP_UPPER_BOUND && svsb->temp < SVSB_TEMP_LOWER_BOUND)) { dev_err(svsb->dev, "%s: %d (0x%x), run default volts\n", - svsb->tzone_name, ret, svsb->temp); + bdata->tzone_name, ret, svsb->temp); svsb->phase = SVSB_PHASE_ERROR; } - if (tzone_temp >= svsb->tzone_htemp) - temp_voffset += svsb->tzone_htemp_voffset; - else if (tzone_temp <= svsb->tzone_ltemp) - temp_voffset += svsb->tzone_ltemp_voffset; + if (tzone_temp >= bdata->tzone_htemp) + temp_voffset += bdata->tzone_htemp_voffset; + else if (tzone_temp <= bdata->tzone_ltemp) + temp_voffset += bdata->tzone_ltemp_voffset; /* 2-line bank update all opp volts when running mon mode */ - if (svsb->type == SVSB_HIGH || svsb->type == SVSB_LOW) { + if (svsb->phase == SVSB_PHASE_MON && (bdata->type == SVSB_TYPE_HIGH || + bdata->type == SVSB_TYPE_LOW)) { opp_start = 0; - opp_stop = svsb->opp_count; + opp_stop = bdata->opp_count; } } @@ -593,16 +664,11 @@ static int svs_adjust_pm_opp_volts(struct svs_bank *svsb) /* do nothing */ goto unlock_mutex; case SVSB_PHASE_INIT02: - svsb_volt = max(svsb->volt[i], svsb->vmin); - opp_volt = svs_bank_volt_to_opp_volt(svsb_volt, - svsb->volt_step, - svsb->volt_base); - break; case SVSB_PHASE_MON: svsb_volt = max(svsb->volt[i] + temp_voffset, svsb->vmin); opp_volt = svs_bank_volt_to_opp_volt(svsb_volt, - svsb->volt_step, - svsb->volt_base); + bdata->volt_step, + bdata->volt_base); break; default: dev_err(svsb->dev, "unknown phase: %u\n", svsb->phase); @@ -628,6 +694,25 @@ unlock_mutex: return ret; } +static void svs_bank_disable_and_restore_default_volts(struct svs_platform *svsp, + struct svs_bank *svsb) +{ + unsigned long flags; + + if (svsb->mode_support == SVSB_MODE_ALL_DISABLE) + return; + + spin_lock_irqsave(&svs_lock, flags); + svs_switch_bank(svsp, svsb); + svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN); + svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS); + spin_unlock_irqrestore(&svs_lock, flags); + + svsb->phase = SVSB_PHASE_ERROR; + svs_adjust_pm_opp_volts(svsb); +} + +#ifdef CONFIG_DEBUG_FS static int svs_dump_debug_show(struct seq_file *m, void *p) { struct svs_platform *svsp = (struct svs_platform *)m->private; @@ -703,7 +788,6 @@ static ssize_t svs_enable_debug_write(struct file *filp, { struct svs_bank *svsb = file_inode(filp)->i_private; struct svs_platform *svsp = dev_get_drvdata(svsb->dev); - unsigned long flags; int enabled, ret; char *buf = NULL; @@ -719,16 +803,8 @@ static ssize_t svs_enable_debug_write(struct file *filp, return ret; if (!enabled) { - spin_lock_irqsave(&svs_lock, flags); - svsp->pbank = svsb; + svs_bank_disable_and_restore_default_volts(svsp, svsb); svsb->mode_support = SVSB_MODE_ALL_DISABLE; - svs_switch_bank(svsp); - svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN); - svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS); - spin_unlock_irqrestore(&svs_lock, flags); - - svsb->phase = SVSB_PHASE_ERROR; - svs_adjust_pm_opp_volts(svsb); } kfree(buf); @@ -747,13 +823,14 @@ static int svs_status_debug_show(struct seq_file *m, void *v) ret = thermal_zone_get_temp(svsb->tzd, &tzone_temp); if (ret) - seq_printf(m, "%s: temperature ignore, turn_pt = %u\n", - svsb->name, svsb->turn_pt); + seq_printf(m, "%s: temperature ignore, vbin_turn_pt = %u, turn_pt = %u\n", + svsb->name, svsb->vbin_turn_pt, svsb->turn_pt); else - seq_printf(m, "%s: temperature = %d, turn_pt = %u\n", - svsb->name, tzone_temp, svsb->turn_pt); + seq_printf(m, "%s: temperature = %d, vbin_turn_pt = %u, turn_pt = %u\n", + svsb->name, tzone_temp, svsb->vbin_turn_pt, + svsb->turn_pt); - for (i = 0; i < svsb->opp_count; i++) { + for (i = 0; i < svsb->pdata.opp_count; i++) { opp = dev_pm_opp_find_freq_exact(svsb->opp_dev, svsb->opp_dfreq[i], true); if (IS_ERR(opp)) { @@ -843,6 +920,7 @@ static int svs_create_debug_cmds(struct svs_platform *svsp) return 0; } +#endif /* CONFIG_DEBUG_FS */ static u32 interpolate(u32 f0, u32 f1, u32 v0, u32 v1, u32 fx) { @@ -857,12 +935,12 @@ static u32 interpolate(u32 f0, u32 f1, u32 v0, u32 v1, u32 fx) return DIV_ROUND_UP(vx, 100); } -static void svs_get_bank_volts_v3(struct svs_platform *svsp) +static void svs_get_bank_volts_v3(struct svs_platform *svsp, struct svs_bank *svsb) { - struct svs_bank *svsb = svsp->pbank; + const struct svs_bank_pdata *bdata = &svsb->pdata; u32 i, j, *vop, vop74, vop30, turn_pt = svsb->turn_pt; u32 b_sft, shift_byte = 0, opp_start = 0, opp_stop = 0; - u32 middle_index = (svsb->opp_count / 2); + u32 middle_index = (bdata->opp_count / 2); if (svsb->phase == SVSB_PHASE_MON && svsb->volt_flags & SVSB_MON_VOLT_IGNORE) @@ -873,7 +951,7 @@ static void svs_get_bank_volts_v3(struct svs_platform *svsp) /* Target is to set svsb->volt[] by algorithm */ if (turn_pt < middle_index) { - if (svsb->type == SVSB_HIGH) { + if (bdata->type == SVSB_TYPE_HIGH) { /* volt[0] ~ volt[turn_pt - 1] */ for (i = 0; i < turn_pt; i++) { b_sft = BITS8 * (shift_byte % REG_BYTES); @@ -882,12 +960,12 @@ static void svs_get_bank_volts_v3(struct svs_platform *svsp) svsb->volt[i] = (*vop >> b_sft) & GENMASK(7, 0); shift_byte++; } - } else if (svsb->type == SVSB_LOW) { + } else if (bdata->type == SVSB_TYPE_LOW) { /* volt[turn_pt] + volt[j] ~ volt[opp_count - 1] */ - j = svsb->opp_count - 7; + j = bdata->opp_count - 7; svsb->volt[turn_pt] = FIELD_GET(SVSB_VOPS_FLD_VOP0_4, vop30); shift_byte++; - for (i = j; i < svsb->opp_count; i++) { + for (i = j; i < bdata->opp_count; i++) { b_sft = BITS8 * (shift_byte % REG_BYTES); vop = (shift_byte < REG_BYTES) ? &vop30 : &vop74; @@ -904,7 +982,7 @@ static void svs_get_bank_volts_v3(struct svs_platform *svsp) svsb->freq_pct[i]); } } else { - if (svsb->type == SVSB_HIGH) { + if (bdata->type == SVSB_TYPE_HIGH) { /* volt[0] + volt[j] ~ volt[turn_pt - 1] */ j = turn_pt - 7; svsb->volt[0] = FIELD_GET(SVSB_VOPS_FLD_VOP0_4, vop30); @@ -924,9 +1002,9 @@ static void svs_get_bank_volts_v3(struct svs_platform *svsp) svsb->volt[0], svsb->volt[j], svsb->freq_pct[i]); - } else if (svsb->type == SVSB_LOW) { + } else if (bdata->type == SVSB_TYPE_LOW) { /* volt[turn_pt] ~ volt[opp_count - 1] */ - for (i = turn_pt; i < svsb->opp_count; i++) { + for (i = turn_pt; i < bdata->opp_count; i++) { b_sft = BITS8 * (shift_byte % REG_BYTES); vop = (shift_byte < REG_BYTES) ? &vop30 : &vop74; @@ -936,28 +1014,51 @@ static void svs_get_bank_volts_v3(struct svs_platform *svsp) } } - if (svsb->type == SVSB_HIGH) { + if (bdata->type == SVSB_TYPE_HIGH) { opp_start = 0; opp_stop = svsb->turn_pt; - } else if (svsb->type == SVSB_LOW) { + } else if (bdata->type == SVSB_TYPE_LOW) { opp_start = svsb->turn_pt; - opp_stop = svsb->opp_count; + opp_stop = bdata->opp_count; } for (i = opp_start; i < opp_stop; i++) if (svsb->volt_flags & SVSB_REMOVE_DVTFIXED_VOLT) svsb->volt[i] -= svsb->dvt_fixed; + + /* For voltage bin support */ + if (svsb->opp_dfreq[0] > svsb->freq_base) { + svsb->volt[0] = svs_opp_volt_to_bank_volt(svsb->opp_dvolt[0], + bdata->volt_step, + bdata->volt_base); + + /* Find voltage bin turn point */ + for (i = 0; i < bdata->opp_count; i++) { + if (svsb->opp_dfreq[i] <= svsb->freq_base) { + svsb->vbin_turn_pt = i; + break; + } + } + + /* Override svs bank voltages */ + for (i = 1; i < svsb->vbin_turn_pt; i++) + svsb->volt[i] = interpolate(svsb->freq_pct[0], + svsb->freq_pct[svsb->vbin_turn_pt], + svsb->volt[0], + svsb->volt[svsb->vbin_turn_pt], + svsb->freq_pct[i]); + } } -static void svs_set_bank_freq_pct_v3(struct svs_platform *svsp) +static void svs_set_bank_freq_pct_v3(struct svs_platform *svsp, struct svs_bank *svsb) { - struct svs_bank *svsb = svsp->pbank; + const struct svs_bank_pdata *bdata = &svsb->pdata; u32 i, j, *freq_pct, freq_pct74 = 0, freq_pct30 = 0; u32 b_sft, shift_byte = 0, turn_pt; - u32 middle_index = (svsb->opp_count / 2); + u32 middle_index = (bdata->opp_count / 2); - for (i = 0; i < svsb->opp_count; i++) { - if (svsb->opp_dfreq[i] <= svsb->turn_freq_base) { + for (i = 0; i < bdata->opp_count; i++) { + if (svsb->opp_dfreq[i] <= bdata->turn_freq_base) { svsb->turn_pt = i; break; } @@ -967,11 +1068,11 @@ static void svs_set_bank_freq_pct_v3(struct svs_platform *svsp) /* Target is to fill out freq_pct74 / freq_pct30 by algorithm */ if (turn_pt < middle_index) { - if (svsb->type == SVSB_HIGH) { + if (bdata->type == SVSB_TYPE_HIGH) { /* * If we don't handle this situation, - * SVSB_HIGH's FREQPCT74 / FREQPCT30 would keep "0" - * and this leads SVSB_LOW to work abnormally. + * SVSB_TYPE_HIGH's FREQPCT74 / FREQPCT30 would keep "0" + * and this leads SVSB_TYPE_LOW to work abnormally. */ if (turn_pt == 0) freq_pct30 = svsb->freq_pct[0]; @@ -984,15 +1085,15 @@ static void svs_set_bank_freq_pct_v3(struct svs_platform *svsp) *freq_pct |= (svsb->freq_pct[i] << b_sft); shift_byte++; } - } else if (svsb->type == SVSB_LOW) { + } else if (bdata->type == SVSB_TYPE_LOW) { /* * freq_pct[turn_pt] + * freq_pct[opp_count - 7] ~ freq_pct[opp_count -1] */ freq_pct30 = svsb->freq_pct[turn_pt]; shift_byte++; - j = svsb->opp_count - 7; - for (i = j; i < svsb->opp_count; i++) { + j = bdata->opp_count - 7; + for (i = j; i < bdata->opp_count; i++) { b_sft = BITS8 * (shift_byte % REG_BYTES); freq_pct = (shift_byte < REG_BYTES) ? &freq_pct30 : &freq_pct74; @@ -1001,7 +1102,7 @@ static void svs_set_bank_freq_pct_v3(struct svs_platform *svsp) } } } else { - if (svsb->type == SVSB_HIGH) { + if (bdata->type == SVSB_TYPE_HIGH) { /* * freq_pct[0] + * freq_pct[turn_pt - 7] ~ freq_pct[turn_pt - 1] @@ -1016,9 +1117,9 @@ static void svs_set_bank_freq_pct_v3(struct svs_platform *svsp) *freq_pct |= (svsb->freq_pct[i] << b_sft); shift_byte++; } - } else if (svsb->type == SVSB_LOW) { + } else if (bdata->type == SVSB_TYPE_LOW) { /* freq_pct[turn_pt] ~ freq_pct[opp_count - 1] */ - for (i = turn_pt; i < svsb->opp_count; i++) { + for (i = turn_pt; i < bdata->opp_count; i++) { b_sft = BITS8 * (shift_byte % REG_BYTES); freq_pct = (shift_byte < REG_BYTES) ? &freq_pct30 : &freq_pct74; @@ -1032,9 +1133,9 @@ static void svs_set_bank_freq_pct_v3(struct svs_platform *svsp) svs_writel_relaxed(svsp, freq_pct30, FREQPCT30); } -static void svs_get_bank_volts_v2(struct svs_platform *svsp) +static void svs_get_bank_volts_v2(struct svs_platform *svsp, struct svs_bank *svsb) { - struct svs_bank *svsb = svsp->pbank; + const struct svs_bank_pdata *bdata = &svsb->pdata; u32 temp, i; temp = svs_readl_relaxed(svsp, VOP74); @@ -1062,13 +1163,35 @@ static void svs_get_bank_volts_v2(struct svs_platform *svsp) svsb->volt[14], svsb->freq_pct[15]); - for (i = 0; i < svsb->opp_count; i++) + for (i = 0; i < bdata->opp_count; i++) svsb->volt[i] += svsb->volt_od; + + /* For voltage bin support */ + if (svsb->opp_dfreq[0] > svsb->freq_base) { + svsb->volt[0] = svs_opp_volt_to_bank_volt(svsb->opp_dvolt[0], + bdata->volt_step, + bdata->volt_base); + + /* Find voltage bin turn point */ + for (i = 0; i < bdata->opp_count; i++) { + if (svsb->opp_dfreq[i] <= svsb->freq_base) { + svsb->vbin_turn_pt = i; + break; + } + } + + /* Override svs bank voltages */ + for (i = 1; i < svsb->vbin_turn_pt; i++) + svsb->volt[i] = interpolate(svsb->freq_pct[0], + svsb->freq_pct[svsb->vbin_turn_pt], + svsb->volt[0], + svsb->volt[svsb->vbin_turn_pt], + svsb->freq_pct[i]); + } } -static void svs_set_bank_freq_pct_v2(struct svs_platform *svsp) +static void svs_set_bank_freq_pct_v2(struct svs_platform *svsp, struct svs_bank *svsb) { - struct svs_bank *svsb = svsp->pbank; u32 freqpct74_val, freqpct30_val; freqpct74_val = FIELD_PREP(SVSB_FREQPCTS_FLD_PCT0_4, svsb->freq_pct[8]) | @@ -1086,18 +1209,20 @@ static void svs_set_bank_freq_pct_v2(struct svs_platform *svsp) } static void svs_set_bank_phase(struct svs_platform *svsp, + unsigned int bank_idx, enum svsb_phase target_phase) { - struct svs_bank *svsb = svsp->pbank; + struct svs_bank *svsb = &svsp->banks[bank_idx]; + const struct svs_bank_pdata *bdata = &svsb->pdata; u32 des_char, temp_char, det_char, limit_vals, init2vals, ts_calcs; - svs_switch_bank(svsp); + svs_switch_bank(svsp, svsb); des_char = FIELD_PREP(SVSB_DESCHAR_FLD_BDES, svsb->bdes) | FIELD_PREP(SVSB_DESCHAR_FLD_MDES, svsb->mdes); svs_writel_relaxed(svsp, des_char, DESCHAR); - temp_char = FIELD_PREP(SVSB_TEMPCHAR_FLD_VCO, svsb->vco) | + temp_char = FIELD_PREP(SVSB_TEMPCHAR_FLD_VCO, bdata->vco) | FIELD_PREP(SVSB_TEMPCHAR_FLD_MTDES, svsb->mtdes) | FIELD_PREP(SVSB_TEMPCHAR_FLD_DVT_FIXED, svsb->dvt_fixed); svs_writel_relaxed(svsp, temp_char, TEMPCHAR); @@ -1106,11 +1231,11 @@ static void svs_set_bank_phase(struct svs_platform *svsp, FIELD_PREP(SVSB_DETCHAR_FLD_DCMDET, svsb->dcmdet); svs_writel_relaxed(svsp, det_char, DETCHAR); - svs_writel_relaxed(svsp, svsb->dc_config, DCCONFIG); - svs_writel_relaxed(svsp, svsb->age_config, AGECONFIG); + svs_writel_relaxed(svsp, bdata->dc_config, DCCONFIG); + svs_writel_relaxed(svsp, bdata->age_config, AGECONFIG); svs_writel_relaxed(svsp, SVSB_RUNCONFIG_DEFAULT, RUNCONFIG); - svsb->set_freq_pct(svsp); + bdata->set_freq_pct(svsp, svsb); limit_vals = FIELD_PREP(SVSB_LIMITVALS_FLD_DTLO, SVSB_VAL_DTLO) | FIELD_PREP(SVSB_LIMITVALS_FLD_DTHI, SVSB_VAL_DTHI) | @@ -1120,13 +1245,13 @@ static void svs_set_bank_phase(struct svs_platform *svsp, svs_writel_relaxed(svsp, SVSB_DET_WINDOW, DETWINDOW); svs_writel_relaxed(svsp, SVSB_DET_MAX, CONFIG); - svs_writel_relaxed(svsp, svsb->chk_shift, CHKSHIFT); - svs_writel_relaxed(svsp, svsb->ctl0, CTL0); + svs_writel_relaxed(svsp, bdata->chk_shift, CHKSHIFT); + svs_writel_relaxed(svsp, bdata->ctl0, CTL0); svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS); switch (target_phase) { case SVSB_PHASE_INIT01: - svs_writel_relaxed(svsp, svsb->vboot, VBOOT); + svs_writel_relaxed(svsp, bdata->vboot, VBOOT); svs_writel_relaxed(svsp, SVSB_INTEN_INIT0x, INTEN); svs_writel_relaxed(svsp, SVSB_PTPEN_INIT01, SVSEN); break; @@ -1152,18 +1277,20 @@ static void svs_set_bank_phase(struct svs_platform *svsp, } static inline void svs_save_bank_register_data(struct svs_platform *svsp, + unsigned short bank_idx, enum svsb_phase phase) { - struct svs_bank *svsb = svsp->pbank; + struct svs_bank *svsb = &svsp->banks[bank_idx]; enum svs_reg_index rg_i; for (rg_i = DESCHAR; rg_i < SVS_REG_MAX; rg_i++) svsb->reg_data[phase][rg_i] = svs_readl_relaxed(svsp, rg_i); } -static inline void svs_error_isr_handler(struct svs_platform *svsp) +static inline void svs_error_isr_handler(struct svs_platform *svsp, + unsigned short bank_idx) { - struct svs_bank *svsb = svsp->pbank; + struct svs_bank *svsb = &svsp->banks[bank_idx]; dev_err(svsb->dev, "%s: CORESEL = 0x%08x\n", __func__, svs_readl_relaxed(svsp, CORESEL)); @@ -1175,27 +1302,29 @@ static inline void svs_error_isr_handler(struct svs_platform *svsp) svs_readl_relaxed(svsp, SMSTATE1)); dev_err(svsb->dev, "TEMP = 0x%08x\n", svs_readl_relaxed(svsp, TEMP)); - svs_save_bank_register_data(svsp, SVSB_PHASE_ERROR); + svs_save_bank_register_data(svsp, bank_idx, SVSB_PHASE_ERROR); svsb->phase = SVSB_PHASE_ERROR; svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN); svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS); } -static inline void svs_init01_isr_handler(struct svs_platform *svsp) +static inline void svs_init01_isr_handler(struct svs_platform *svsp, + unsigned short bank_idx) { - struct svs_bank *svsb = svsp->pbank; + struct svs_bank *svsb = &svsp->banks[bank_idx]; + u32 val; dev_info(svsb->dev, "%s: VDN74~30:0x%08x~0x%08x, DC:0x%08x\n", __func__, svs_readl_relaxed(svsp, VDESIGN74), svs_readl_relaxed(svsp, VDESIGN30), svs_readl_relaxed(svsp, DCVALUES)); - svs_save_bank_register_data(svsp, SVSB_PHASE_INIT01); + svs_save_bank_register_data(svsp, bank_idx, SVSB_PHASE_INIT01); svsb->phase = SVSB_PHASE_INIT01; - svsb->dc_voffset_in = ~(svs_readl_relaxed(svsp, DCVALUES) & - GENMASK(15, 0)) + 1; + val = ~(svs_readl_relaxed(svsp, DCVALUES) & GENMASK(15, 0)) + 1; + svsb->dc_voffset_in = val & GENMASK(15, 0); if (svsb->volt_flags & SVSB_INIT01_VOLT_IGNORE || (svsb->dc_voffset_in & SVSB_DC_SIGNED_BIT && svsb->volt_flags & SVSB_INIT01_VOLT_INC_ONLY)) @@ -1209,32 +1338,36 @@ static inline void svs_init01_isr_handler(struct svs_platform *svsp) svsb->core_sel &= ~SVSB_DET_CLK_EN; } -static inline void svs_init02_isr_handler(struct svs_platform *svsp) +static inline void svs_init02_isr_handler(struct svs_platform *svsp, + unsigned short bank_idx) { - struct svs_bank *svsb = svsp->pbank; + struct svs_bank *svsb = &svsp->banks[bank_idx]; + const struct svs_bank_pdata *bdata = &svsb->pdata; dev_info(svsb->dev, "%s: VOP74~30:0x%08x~0x%08x, DC:0x%08x\n", __func__, svs_readl_relaxed(svsp, VOP74), svs_readl_relaxed(svsp, VOP30), svs_readl_relaxed(svsp, DCVALUES)); - svs_save_bank_register_data(svsp, SVSB_PHASE_INIT02); + svs_save_bank_register_data(svsp, bank_idx, SVSB_PHASE_INIT02); svsb->phase = SVSB_PHASE_INIT02; - svsb->get_volts(svsp); + bdata->get_volts(svsp, svsb); svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN); svs_writel_relaxed(svsp, SVSB_INTSTS_F0_COMPLETE, INTSTS); } -static inline void svs_mon_mode_isr_handler(struct svs_platform *svsp) +static inline void svs_mon_mode_isr_handler(struct svs_platform *svsp, + unsigned short bank_idx) { - struct svs_bank *svsb = svsp->pbank; + struct svs_bank *svsb = &svsp->banks[bank_idx]; + const struct svs_bank_pdata *bdata = &svsb->pdata; - svs_save_bank_register_data(svsp, SVSB_PHASE_MON); + svs_save_bank_register_data(svsp, bank_idx, SVSB_PHASE_MON); svsb->phase = SVSB_PHASE_MON; - svsb->get_volts(svsp); + bdata->get_volts(svsp, svsb); svsb->temp = svs_readl_relaxed(svsp, TEMP) & GENMASK(7, 0); svs_writel_relaxed(svsp, SVSB_INTSTS_FLD_MONVOP, INTSTS); @@ -1243,37 +1376,38 @@ static inline void svs_mon_mode_isr_handler(struct svs_platform *svsp) static irqreturn_t svs_isr(int irq, void *data) { struct svs_platform *svsp = data; + const struct svs_bank_pdata *bdata; struct svs_bank *svsb = NULL; unsigned long flags; u32 idx, int_sts, svs_en; for (idx = 0; idx < svsp->bank_max; idx++) { svsb = &svsp->banks[idx]; + bdata = &svsb->pdata; WARN(!svsb, "%s: svsb(%s) is null", __func__, svsb->name); spin_lock_irqsave(&svs_lock, flags); - svsp->pbank = svsb; /* Find out which svs bank fires interrupt */ - if (svsb->int_st & svs_readl_relaxed(svsp, INTST)) { + if (bdata->int_st & svs_readl_relaxed(svsp, INTST)) { spin_unlock_irqrestore(&svs_lock, flags); continue; } - svs_switch_bank(svsp); + svs_switch_bank(svsp, svsb); int_sts = svs_readl_relaxed(svsp, INTSTS); svs_en = svs_readl_relaxed(svsp, SVSEN); if (int_sts == SVSB_INTSTS_F0_COMPLETE && svs_en == SVSB_PTPEN_INIT01) - svs_init01_isr_handler(svsp); + svs_init01_isr_handler(svsp, idx); else if (int_sts == SVSB_INTSTS_F0_COMPLETE && svs_en == SVSB_PTPEN_INIT02) - svs_init02_isr_handler(svsp); + svs_init02_isr_handler(svsp, idx); else if (int_sts & SVSB_INTSTS_FLD_MONVOP) - svs_mon_mode_isr_handler(svsp); + svs_mon_mode_isr_handler(svsp, idx); else - svs_error_isr_handler(svsp); + svs_error_isr_handler(svsp, idx); spin_unlock_irqrestore(&svs_lock, flags); break; @@ -1288,20 +1422,35 @@ static irqreturn_t svs_isr(int irq, void *data) return IRQ_HANDLED; } +static bool svs_mode_available(struct svs_platform *svsp, u8 mode) +{ + int i; + + for (i = 0; i < svsp->bank_max; i++) + if (svsp->banks[i].mode_support & mode) + return true; + return false; +} + static int svs_init01(struct svs_platform *svsp) { + const struct svs_bank_pdata *bdata; struct svs_bank *svsb; unsigned long flags, time_left; bool search_done; int ret = 0, r; u32 opp_freq, opp_vboot, buck_volt, idx, i; + if (!svs_mode_available(svsp, SVSB_MODE_INIT01)) + return 0; + /* Keep CPUs' core power on for svs_init01 initialization */ cpuidle_pause_and_lock(); /* Svs bank init01 preparation - power enable */ for (idx = 0; idx < svsp->bank_max; idx++) { svsb = &svsp->banks[idx]; + bdata = &svsb->pdata; if (!(svsb->mode_support & SVSB_MODE_INIT01)) continue; @@ -1309,7 +1458,7 @@ static int svs_init01(struct svs_platform *svsp) ret = regulator_enable(svsb->buck); if (ret) { dev_err(svsb->dev, "%s enable fail: %d\n", - svsb->buck_name, ret); + bdata->buck_name, ret); goto svs_init01_resume_cpuidle; } @@ -1324,7 +1473,7 @@ static int svs_init01(struct svs_platform *svsp) svsb->pm_runtime_enabled_count++; } - ret = pm_runtime_get_sync(svsb->opp_dev); + ret = pm_runtime_resume_and_get(svsb->opp_dev); if (ret < 0) { dev_err(svsb->dev, "mtcmos on fail: %d\n", ret); goto svs_init01_resume_cpuidle; @@ -1339,6 +1488,7 @@ static int svs_init01(struct svs_platform *svsp) */ for (idx = 0; idx < svsp->bank_max; idx++) { svsb = &svsp->banks[idx]; + bdata = &svsb->pdata; if (!(svsb->mode_support & SVSB_MODE_INIT01)) continue; @@ -1348,11 +1498,11 @@ static int svs_init01(struct svs_platform *svsp) * fix to that freq until svs_init01 is done. */ search_done = false; - opp_vboot = svs_bank_volt_to_opp_volt(svsb->vboot, - svsb->volt_step, - svsb->volt_base); + opp_vboot = svs_bank_volt_to_opp_volt(bdata->vboot, + bdata->volt_step, + bdata->volt_base); - for (i = 0; i < svsb->opp_count; i++) { + for (i = 0; i < bdata->opp_count; i++) { opp_freq = svsb->opp_dfreq[i]; if (!search_done && svsb->opp_dvolt[i] <= opp_vboot) { ret = dev_pm_opp_adjust_voltage(svsb->opp_dev, @@ -1384,13 +1534,14 @@ static int svs_init01(struct svs_platform *svsp) /* Svs bank init01 begins */ for (idx = 0; idx < svsp->bank_max; idx++) { svsb = &svsp->banks[idx]; + bdata = &svsb->pdata; if (!(svsb->mode_support & SVSB_MODE_INIT01)) continue; - opp_vboot = svs_bank_volt_to_opp_volt(svsb->vboot, - svsb->volt_step, - svsb->volt_base); + opp_vboot = svs_bank_volt_to_opp_volt(bdata->vboot, + bdata->volt_step, + bdata->volt_base); buck_volt = regulator_get_voltage(svsb->buck); if (buck_volt != opp_vboot) { @@ -1402,8 +1553,7 @@ static int svs_init01(struct svs_platform *svsp) } spin_lock_irqsave(&svs_lock, flags); - svsp->pbank = svsb; - svs_set_bank_phase(svsp, SVSB_PHASE_INIT01); + svs_set_bank_phase(svsp, idx, SVSB_PHASE_INIT01); spin_unlock_irqrestore(&svs_lock, flags); time_left = wait_for_completion_timeout(&svsb->init_completion, @@ -1418,11 +1568,12 @@ static int svs_init01(struct svs_platform *svsp) svs_init01_finish: for (idx = 0; idx < svsp->bank_max; idx++) { svsb = &svsp->banks[idx]; + bdata = &svsb->pdata; if (!(svsb->mode_support & SVSB_MODE_INIT01)) continue; - for (i = 0; i < svsb->opp_count; i++) { + for (i = 0; i < bdata->opp_count; i++) { r = dev_pm_opp_enable(svsb->opp_dev, svsb->opp_dfreq[i]); if (r) @@ -1448,7 +1599,7 @@ svs_init01_finish: r = regulator_disable(svsb->buck); if (r) dev_err(svsb->dev, "%s disable fail: %d\n", - svsb->buck_name, r); + bdata->buck_name, r); } svs_init01_resume_cpuidle: @@ -1459,10 +1610,15 @@ svs_init01_resume_cpuidle: static int svs_init02(struct svs_platform *svsp) { + const struct svs_bank_pdata *bdata; struct svs_bank *svsb; unsigned long flags, time_left; + int ret; u32 idx; + if (!svs_mode_available(svsp, SVSB_MODE_INIT02)) + return 0; + for (idx = 0; idx < svsp->bank_max; idx++) { svsb = &svsp->banks[idx]; @@ -1471,15 +1627,15 @@ static int svs_init02(struct svs_platform *svsp) reinit_completion(&svsb->init_completion); spin_lock_irqsave(&svs_lock, flags); - svsp->pbank = svsb; - svs_set_bank_phase(svsp, SVSB_PHASE_INIT02); + svs_set_bank_phase(svsp, idx, SVSB_PHASE_INIT02); spin_unlock_irqrestore(&svs_lock, flags); time_left = wait_for_completion_timeout(&svsb->init_completion, msecs_to_jiffies(5000)); if (!time_left) { dev_err(svsb->dev, "init02 completion timeout\n"); - return -EBUSY; + ret = -EBUSY; + goto out_of_init02; } } @@ -1490,19 +1646,29 @@ static int svs_init02(struct svs_platform *svsp) */ for (idx = 0; idx < svsp->bank_max; idx++) { svsb = &svsp->banks[idx]; + bdata = &svsb->pdata; if (!(svsb->mode_support & SVSB_MODE_INIT02)) continue; - if (svsb->type == SVSB_HIGH || svsb->type == SVSB_LOW) { + if (bdata->type == SVSB_TYPE_HIGH || bdata->type == SVSB_TYPE_LOW) { if (svs_sync_bank_volts_from_opp(svsb)) { dev_err(svsb->dev, "sync volt fail\n"); - return -EPERM; + ret = -EPERM; + goto out_of_init02; } } } return 0; + +out_of_init02: + for (idx = 0; idx < svsp->bank_max; idx++) { + svsb = &svsp->banks[idx]; + svs_bank_disable_and_restore_default_volts(svsp, svsb); + } + + return ret; } static void svs_mon_mode(struct svs_platform *svsp) @@ -1518,8 +1684,7 @@ static void svs_mon_mode(struct svs_platform *svsp) continue; spin_lock_irqsave(&svs_lock, flags); - svsp->pbank = svsb; - svs_set_bank_phase(svsp, SVSB_PHASE_MON); + svs_set_bank_phase(svsp, idx, SVSB_PHASE_MON); spin_unlock_irqrestore(&svs_lock, flags); } } @@ -1544,24 +1709,13 @@ static int svs_start(struct svs_platform *svsp) static int svs_suspend(struct device *dev) { struct svs_platform *svsp = dev_get_drvdata(dev); - struct svs_bank *svsb; - unsigned long flags; int ret; u32 idx; for (idx = 0; idx < svsp->bank_max; idx++) { - svsb = &svsp->banks[idx]; + struct svs_bank *svsb = &svsp->banks[idx]; - /* This might wait for svs_isr() process */ - spin_lock_irqsave(&svs_lock, flags); - svsp->pbank = svsb; - svs_switch_bank(svsp); - svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN); - svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS); - spin_unlock_irqrestore(&svs_lock, flags); - - svsb->phase = SVSB_PHASE_ERROR; - svs_adjust_pm_opp_volts(svsb); + svs_bank_disable_and_restore_default_volts(svsp, svsb); } ret = reset_control_assert(svsp->rst); @@ -1594,12 +1748,16 @@ static int svs_resume(struct device *dev) ret = svs_init02(svsp); if (ret) - goto out_of_resume; + goto svs_resume_reset_assert; svs_mon_mode(svsp); return 0; +svs_resume_reset_assert: + dev_err(svsp->dev, "assert reset: %d\n", + reset_control_assert(svsp->rst)); + out_of_resume: clk_disable_unprepare(svsp->main_clk); return ret; @@ -1607,8 +1765,10 @@ out_of_resume: static int svs_bank_resource_setup(struct svs_platform *svsp) { + const struct svs_bank_pdata *bdata; struct svs_bank *svsb; struct dev_pm_opp *opp; + char tz_name_buf[20]; unsigned long freq; int count, ret; u32 idx, i; @@ -1617,35 +1777,23 @@ static int svs_bank_resource_setup(struct svs_platform *svsp) for (idx = 0; idx < svsp->bank_max; idx++) { svsb = &svsp->banks[idx]; + bdata = &svsb->pdata; - switch (svsb->sw_id) { - case SVSB_CPU_LITTLE: - svsb->name = "SVSB_CPU_LITTLE"; - break; - case SVSB_CPU_BIG: - svsb->name = "SVSB_CPU_BIG"; - break; - case SVSB_CCI: - svsb->name = "SVSB_CCI"; - break; - case SVSB_GPU: - if (svsb->type == SVSB_HIGH) - svsb->name = "SVSB_GPU_HIGH"; - else if (svsb->type == SVSB_LOW) - svsb->name = "SVSB_GPU_LOW"; - else - svsb->name = "SVSB_GPU"; - break; - default: - dev_err(svsb->dev, "unknown sw_id: %u\n", svsb->sw_id); + if (bdata->sw_id >= SVSB_SWID_MAX || bdata->type >= SVSB_TYPE_MAX) { + dev_err(svsb->dev, "unknown bank sw_id or type\n"); return -EINVAL; } - svsb->dev = devm_kzalloc(svsp->dev, sizeof(*svsb->dev), - GFP_KERNEL); + svsb->dev = devm_kzalloc(svsp->dev, sizeof(*svsb->dev), GFP_KERNEL); if (!svsb->dev) return -ENOMEM; + svsb->name = devm_kasprintf(svsp->dev, GFP_KERNEL, "%s%s", + svs_swid_names[bdata->sw_id], + svs_type_names[bdata->type]); + if (!svsb->name) + return -ENOMEM; + ret = dev_set_name(svsb->dev, "%s", svsb->name); if (ret) return ret; @@ -1663,32 +1811,34 @@ static int svs_bank_resource_setup(struct svs_platform *svsp) if (svsb->mode_support & SVSB_MODE_INIT01) { svsb->buck = devm_regulator_get_optional(svsb->opp_dev, - svsb->buck_name); + bdata->buck_name); if (IS_ERR(svsb->buck)) { dev_err(svsb->dev, "cannot get \"%s-supply\"\n", - svsb->buck_name); + bdata->buck_name); return PTR_ERR(svsb->buck); } } - if (svsb->mode_support & SVSB_MODE_MON) { - svsb->tzd = thermal_zone_get_zone_by_name(svsb->tzone_name); + if (!IS_ERR_OR_NULL(bdata->tzone_name)) { + snprintf(tz_name_buf, ARRAY_SIZE(tz_name_buf), + "%s-thermal", bdata->tzone_name); + svsb->tzd = thermal_zone_get_zone_by_name(tz_name_buf); if (IS_ERR(svsb->tzd)) { dev_err(svsb->dev, "cannot get \"%s\" thermal zone\n", - svsb->tzone_name); + tz_name_buf); return PTR_ERR(svsb->tzd); } } count = dev_pm_opp_get_opp_count(svsb->opp_dev); - if (svsb->opp_count != count) { + if (bdata->opp_count != count) { dev_err(svsb->dev, "opp_count not \"%u\" but get \"%d\"?\n", - svsb->opp_count, count); + bdata->opp_count, count); return count; } - for (i = 0, freq = U32_MAX; i < svsb->opp_count; i++, freq--) { + for (i = 0, freq = ULONG_MAX; i < bdata->opp_count; i++, freq--) { opp = dev_pm_opp_find_freq_floor(svsb->opp_dev, &freq); if (IS_ERR(opp)) { dev_err(svsb->dev, "cannot find freq = %ld\n", @@ -1707,103 +1857,116 @@ static int svs_bank_resource_setup(struct svs_platform *svsp) return 0; } -static int svs_thermal_efuse_get_data(struct svs_platform *svsp) +static int svs_get_efuse_data(struct svs_platform *svsp, + const char *nvmem_cell_name, + u32 **svsp_efuse, size_t *svsp_efuse_max) { struct nvmem_cell *cell; - /* Thermal efuse parsing */ - cell = nvmem_cell_get(svsp->dev, "t-calibration-data"); - if (IS_ERR_OR_NULL(cell)) { - dev_err(svsp->dev, "no \"t-calibration-data\"? %ld\n", PTR_ERR(cell)); + cell = nvmem_cell_get(svsp->dev, nvmem_cell_name); + if (IS_ERR(cell)) { + dev_err(svsp->dev, "no \"%s\"? %ld\n", + nvmem_cell_name, PTR_ERR(cell)); return PTR_ERR(cell); } - svsp->tefuse = nvmem_cell_read(cell, &svsp->tefuse_max); - if (IS_ERR(svsp->tefuse)) { - dev_err(svsp->dev, "cannot read thermal efuse: %ld\n", - PTR_ERR(svsp->tefuse)); + *svsp_efuse = nvmem_cell_read(cell, svsp_efuse_max); + if (IS_ERR(*svsp_efuse)) { nvmem_cell_put(cell); - return PTR_ERR(svsp->tefuse); + return PTR_ERR(*svsp_efuse); } - svsp->tefuse_max /= sizeof(u32); + *svsp_efuse_max /= sizeof(u32); nvmem_cell_put(cell); return 0; } -static bool svs_mt8192_efuse_parsing(struct svs_platform *svsp) +static u32 svs_get_fuse_val(u32 *fuse_array, const struct svs_fusemap *fmap, u8 nbits) { - struct svs_bank *svsb; - u32 idx, i, vmin, golden_temp; - int ret; + u32 val; - for (i = 0; i < svsp->efuse_max; i++) + if (fmap->index < 0) + return FUSE_DATA_NOT_VALID; + + val = fuse_array[fmap->index] >> fmap->ofst; + val &= GENMASK(nbits - 1, 0); + + return val; +} + +static bool svs_is_available(struct svs_platform *svsp) +{ + int i, num_populated = 0; + + /* If at least two fuse arrays are populated, SVS is calibrated */ + for (i = 0; i < svsp->efuse_max; i++) { if (svsp->efuse[i]) - dev_info(svsp->dev, "M_HW_RES%d: 0x%08x\n", - i, svsp->efuse[i]); + num_populated++; - if (!svsp->efuse[9]) { - dev_notice(svsp->dev, "svs_efuse[9] = 0x0?\n"); - return false; + if (num_populated > 1) + return true; } - /* Svs efuse parsing */ - vmin = (svsp->efuse[19] >> 4) & GENMASK(1, 0); + return false; +} - for (idx = 0; idx < svsp->bank_max; idx++) { - svsb = &svsp->banks[idx]; +static bool svs_common_parse_efuse(struct svs_platform *svsp, + const struct svs_platform_data *pdata) +{ + const struct svs_fusemap *gfmap = pdata->glb_fuse_map; + struct svs_fusemap tfm = { 0, 24 }; + u32 golden_temp, val; + u8 ft_pgm, vmin; + int i; - if (vmin == 0x1) - svsb->vmin = 0x1e; + if (!svs_is_available(svsp)) + return false; - if (svsb->type == SVSB_LOW) { - svsb->mtdes = svsp->efuse[10] & GENMASK(7, 0); - svsb->bdes = (svsp->efuse[10] >> 16) & GENMASK(7, 0); - svsb->mdes = (svsp->efuse[10] >> 24) & GENMASK(7, 0); - svsb->dcbdet = (svsp->efuse[17]) & GENMASK(7, 0); - svsb->dcmdet = (svsp->efuse[17] >> 8) & GENMASK(7, 0); - } else if (svsb->type == SVSB_HIGH) { - svsb->mtdes = svsp->efuse[9] & GENMASK(7, 0); - svsb->bdes = (svsp->efuse[9] >> 16) & GENMASK(7, 0); - svsb->mdes = (svsp->efuse[9] >> 24) & GENMASK(7, 0); - svsb->dcbdet = (svsp->efuse[17] >> 16) & GENMASK(7, 0); - svsb->dcmdet = (svsp->efuse[17] >> 24) & GENMASK(7, 0); - } + /* Get golden temperature from SVS-Thermal calibration */ + val = svs_get_fuse_val(svsp->tefuse, &tfm, 8); - svsb->vmax += svsb->dvt_fixed; - } + /* If golden temp is not programmed, use the default of 50 */ + golden_temp = val ? val : 50; - ret = svs_thermal_efuse_get_data(svsp); - if (ret) - return false; + /* Parse fused SVS calibration */ + ft_pgm = svs_get_fuse_val(svsp->efuse, &gfmap[GLB_FT_PGM], 8); + vmin = svs_get_fuse_val(svsp->efuse, &gfmap[GLB_VMIN], 2); - for (i = 0; i < svsp->tefuse_max; i++) - if (svsp->tefuse[i] != 0) - break; + for (i = 0; i < svsp->bank_max; i++) { + struct svs_bank *svsb = &svsp->banks[i]; + const struct svs_bank_pdata *bdata = &svsb->pdata; + const struct svs_fusemap *dfmap = bdata->dev_fuse_map; - if (i == svsp->tefuse_max) - golden_temp = 50; /* All thermal efuse data are 0 */ - else - golden_temp = (svsp->tefuse[0] >> 24) & GENMASK(7, 0); + if (vmin == 1) + svsb->vmin = 0x1e; - for (idx = 0; idx < svsp->bank_max; idx++) { - svsb = &svsp->banks[idx]; - svsb->mts = 500; - svsb->bts = (((500 * golden_temp + 250460) / 1000) - 25) * 4; + if (ft_pgm == 0) + svsb->volt_flags |= SVSB_INIT01_VOLT_IGNORE; + + svsb->mtdes = svs_get_fuse_val(svsp->efuse, &dfmap[BDEV_MTDES], 8); + svsb->bdes = svs_get_fuse_val(svsp->efuse, &dfmap[BDEV_BDES], 8); + svsb->mdes = svs_get_fuse_val(svsp->efuse, &dfmap[BDEV_MDES], 8); + svsb->dcbdet = svs_get_fuse_val(svsp->efuse, &dfmap[BDEV_DCBDET], 8); + svsb->dcmdet = svs_get_fuse_val(svsp->efuse, &dfmap[BDEV_DCMDET], 8); + svsb->vmax += svsb->dvt_fixed; + + svsb->mts = (svsp->ts_coeff * 2) / 1000; + svsb->bts = (((500 * golden_temp + svsp->ts_coeff) / 1000) - 25) * 4; } return true; } -static bool svs_mt8183_efuse_parsing(struct svs_platform *svsp) +static bool svs_mt8183_efuse_parsing(struct svs_platform *svsp, + const struct svs_platform_data *pdata) { struct svs_bank *svsb; + const struct svs_bank_pdata *bdata; int format[6], x_roomt[6], o_vtsmcu[5], o_vtsabb, tb_roomt = 0; int adc_ge_t, adc_oe_t, ge, oe, gain, degc_cali, adc_cali_en_t; int o_slope, o_slope_sign, ts_id; u32 idx, i, ft_pgm, mts, temp0, temp1, temp2; - int ret; for (i = 0; i < svsp->efuse_max; i++) if (svsp->efuse[i]) @@ -1816,73 +1979,48 @@ static bool svs_mt8183_efuse_parsing(struct svs_platform *svsp) } /* Svs efuse parsing */ - ft_pgm = (svsp->efuse[0] >> 4) & GENMASK(3, 0); + ft_pgm = svs_get_fuse_val(svsp->efuse, &pdata->glb_fuse_map[GLB_FT_PGM], 4); for (idx = 0; idx < svsp->bank_max; idx++) { svsb = &svsp->banks[idx]; + bdata = &svsb->pdata; + const struct svs_fusemap *dfmap = bdata->dev_fuse_map; if (ft_pgm <= 1) svsb->volt_flags |= SVSB_INIT01_VOLT_IGNORE; - switch (svsb->sw_id) { - case SVSB_CPU_LITTLE: - svsb->bdes = svsp->efuse[16] & GENMASK(7, 0); - svsb->mdes = (svsp->efuse[16] >> 8) & GENMASK(7, 0); - svsb->dcbdet = (svsp->efuse[16] >> 16) & GENMASK(7, 0); - svsb->dcmdet = (svsp->efuse[16] >> 24) & GENMASK(7, 0); - svsb->mtdes = (svsp->efuse[17] >> 16) & GENMASK(7, 0); + svsb->mtdes = svs_get_fuse_val(svsp->efuse, &dfmap[BDEV_MTDES], 8); + svsb->bdes = svs_get_fuse_val(svsp->efuse, &dfmap[BDEV_BDES], 8); + svsb->mdes = svs_get_fuse_val(svsp->efuse, &dfmap[BDEV_MDES], 8); + svsb->dcbdet = svs_get_fuse_val(svsp->efuse, &dfmap[BDEV_DCBDET], 8); + svsb->dcmdet = svs_get_fuse_val(svsp->efuse, &dfmap[BDEV_DCMDET], 8); + switch (bdata->sw_id) { + case SVSB_SWID_CPU_LITTLE: + case SVSB_SWID_CCI: if (ft_pgm <= 3) svsb->volt_od += 10; else svsb->volt_od += 2; break; - case SVSB_CPU_BIG: - svsb->bdes = svsp->efuse[18] & GENMASK(7, 0); - svsb->mdes = (svsp->efuse[18] >> 8) & GENMASK(7, 0); - svsb->dcbdet = (svsp->efuse[18] >> 16) & GENMASK(7, 0); - svsb->dcmdet = (svsp->efuse[18] >> 24) & GENMASK(7, 0); - svsb->mtdes = svsp->efuse[17] & GENMASK(7, 0); - + case SVSB_SWID_CPU_BIG: if (ft_pgm <= 3) svsb->volt_od += 15; else svsb->volt_od += 12; break; - case SVSB_CCI: - svsb->bdes = svsp->efuse[4] & GENMASK(7, 0); - svsb->mdes = (svsp->efuse[4] >> 8) & GENMASK(7, 0); - svsb->dcbdet = (svsp->efuse[4] >> 16) & GENMASK(7, 0); - svsb->dcmdet = (svsp->efuse[4] >> 24) & GENMASK(7, 0); - svsb->mtdes = (svsp->efuse[5] >> 16) & GENMASK(7, 0); - - if (ft_pgm <= 3) - svsb->volt_od += 10; - else - svsb->volt_od += 2; - break; - case SVSB_GPU: - svsb->bdes = svsp->efuse[6] & GENMASK(7, 0); - svsb->mdes = (svsp->efuse[6] >> 8) & GENMASK(7, 0); - svsb->dcbdet = (svsp->efuse[6] >> 16) & GENMASK(7, 0); - svsb->dcmdet = (svsp->efuse[6] >> 24) & GENMASK(7, 0); - svsb->mtdes = svsp->efuse[5] & GENMASK(7, 0); - - if (ft_pgm >= 2) { + case SVSB_SWID_GPU: + if (ft_pgm != FUSE_DATA_NOT_VALID && ft_pgm >= 2) { svsb->freq_base = 800000000; /* 800MHz */ svsb->dvt_fixed = 2; } break; default: - dev_err(svsb->dev, "unknown sw_id: %u\n", svsb->sw_id); + dev_err(svsb->dev, "unknown sw_id: %u\n", bdata->sw_id); return false; } } - ret = svs_thermal_efuse_get_data(svsp); - if (ret) - return false; - /* Thermal efuse parsing */ adc_ge_t = (svsp->tefuse[1] >> 22) & GENMASK(9, 0); adc_oe_t = (svsp->tefuse[1] >> 12) & GENMASK(9, 0); @@ -1899,26 +2037,27 @@ static bool svs_mt8183_efuse_parsing(struct svs_platform *svsp) o_slope_sign = (svsp->tefuse[0] >> 7) & BIT(0); ts_id = (svsp->tefuse[1] >> 9) & BIT(0); - o_slope = (svsp->tefuse[0] >> 26) & GENMASK(5, 0); - - if (adc_cali_en_t == 1) { - if (!ts_id) - o_slope = 0; - - if (adc_ge_t < 265 || adc_ge_t > 758 || - adc_oe_t < 265 || adc_oe_t > 758 || - o_vtsmcu[0] < -8 || o_vtsmcu[0] > 484 || - o_vtsmcu[1] < -8 || o_vtsmcu[1] > 484 || - o_vtsmcu[2] < -8 || o_vtsmcu[2] > 484 || - o_vtsmcu[3] < -8 || o_vtsmcu[3] > 484 || - o_vtsmcu[4] < -8 || o_vtsmcu[4] > 484 || - o_vtsabb < -8 || o_vtsabb > 484 || - degc_cali < 1 || degc_cali > 63) { - dev_err(svsp->dev, "bad thermal efuse, no mon mode\n"); - goto remove_mt8183_svsb_mon_mode; - } + if (!ts_id) { + o_slope = 1534; } else { - dev_err(svsp->dev, "no thermal efuse, no mon mode\n"); + o_slope = (svsp->tefuse[0] >> 26) & GENMASK(5, 0); + if (!o_slope_sign) + o_slope = 1534 + o_slope * 10; + else + o_slope = 1534 - o_slope * 10; + } + + if (adc_cali_en_t == 0 || + adc_ge_t < 265 || adc_ge_t > 758 || + adc_oe_t < 265 || adc_oe_t > 758 || + o_vtsmcu[0] < -8 || o_vtsmcu[0] > 484 || + o_vtsmcu[1] < -8 || o_vtsmcu[1] > 484 || + o_vtsmcu[2] < -8 || o_vtsmcu[2] > 484 || + o_vtsmcu[3] < -8 || o_vtsmcu[3] > 484 || + o_vtsmcu[4] < -8 || o_vtsmcu[4] > 484 || + o_vtsabb < -8 || o_vtsabb > 484 || + degc_cali < 1 || degc_cali > 63) { + dev_err(svsp->dev, "bad thermal efuse, no mon mode\n"); goto remove_mt8183_svsb_mon_mode; } @@ -1937,42 +2076,35 @@ static bool svs_mt8183_efuse_parsing(struct svs_platform *svsp) x_roomt[i] = (((format[i] * 10000) / 4096) * 10000) / gain; temp0 = (10000 * 100000 / gain) * 15 / 18; - - if (!o_slope_sign) - mts = (temp0 * 10) / (1534 + o_slope * 10); - else - mts = (temp0 * 10) / (1534 - o_slope * 10); + mts = (temp0 * 10) / o_slope; for (idx = 0; idx < svsp->bank_max; idx++) { svsb = &svsp->banks[idx]; + bdata = &svsb->pdata; svsb->mts = mts; - switch (svsb->sw_id) { - case SVSB_CPU_LITTLE: + switch (bdata->sw_id) { + case SVSB_SWID_CPU_LITTLE: tb_roomt = x_roomt[3]; break; - case SVSB_CPU_BIG: + case SVSB_SWID_CPU_BIG: tb_roomt = x_roomt[4]; break; - case SVSB_CCI: + case SVSB_SWID_CCI: tb_roomt = x_roomt[3]; break; - case SVSB_GPU: + case SVSB_SWID_GPU: tb_roomt = x_roomt[1]; break; default: - dev_err(svsb->dev, "unknown sw_id: %u\n", svsb->sw_id); + dev_err(svsb->dev, "unknown sw_id: %u\n", bdata->sw_id); goto remove_mt8183_svsb_mon_mode; } temp0 = (degc_cali * 10 / 2); temp1 = ((10000 * 100000 / 4096 / gain) * oe + tb_roomt * 10) * 15 / 18; - - if (!o_slope_sign) - temp2 = temp1 * 100 / (1534 + o_slope * 10); - else - temp2 = temp1 * 100 / (1534 - o_slope * 10); + temp2 = temp1 * 100 / o_slope; svsb->bts = (temp0 + temp2 - 250) * 4 / 10; } @@ -1988,32 +2120,6 @@ remove_mt8183_svsb_mon_mode: return true; } -static bool svs_is_efuse_data_correct(struct svs_platform *svsp) -{ - struct nvmem_cell *cell; - - /* Get svs efuse by nvmem */ - cell = nvmem_cell_get(svsp->dev, "svs-calibration-data"); - if (IS_ERR(cell)) { - dev_err(svsp->dev, "no \"svs-calibration-data\"? %ld\n", - PTR_ERR(cell)); - return false; - } - - svsp->efuse = nvmem_cell_read(cell, &svsp->efuse_max); - if (IS_ERR(svsp->efuse)) { - dev_err(svsp->dev, "cannot read svs efuse: %ld\n", - PTR_ERR(svsp->efuse)); - nvmem_cell_put(cell); - return false; - } - - svsp->efuse_max /= sizeof(u32); - nvmem_cell_put(cell); - - return svsp->efuse_parsing(svsp); -} - static struct device *svs_get_subsys_device(struct svs_platform *svsp, const char *node_name) { @@ -2027,14 +2133,12 @@ static struct device *svs_get_subsys_device(struct svs_platform *svsp, } pdev = of_find_device_by_node(np); + of_node_put(np); if (!pdev) { - of_node_put(np); dev_err(svsp->dev, "cannot find pdev by %s\n", node_name); return ERR_PTR(-ENXIO); } - of_node_put(np); - return &pdev->dev; } @@ -2044,11 +2148,6 @@ static struct device *svs_add_device_link(struct svs_platform *svsp, struct device *dev; struct device_link *sup_link; - if (!node_name) { - dev_err(svsp->dev, "node name cannot be null\n"); - return ERR_PTR(-EINVAL); - } - dev = svs_get_subsys_device(svsp, node_name); if (IS_ERR(dev)) return dev; @@ -2066,34 +2165,63 @@ static struct device *svs_add_device_link(struct svs_platform *svsp, return dev; } +static void svs_put_device(void *_dev) +{ + struct device *dev = _dev; + + put_device(dev); +} + static int svs_mt8192_platform_probe(struct svs_platform *svsp) { struct device *dev; - struct svs_bank *svsb; u32 idx; + int ret; svsp->rst = devm_reset_control_get_optional(svsp->dev, "svs_rst"); if (IS_ERR(svsp->rst)) return dev_err_probe(svsp->dev, PTR_ERR(svsp->rst), "cannot get svs reset control\n"); - dev = svs_add_device_link(svsp, "lvts"); + dev = svs_add_device_link(svsp, "thermal-sensor"); if (IS_ERR(dev)) return dev_err_probe(svsp->dev, PTR_ERR(dev), "failed to get lvts device\n"); + put_device(dev); for (idx = 0; idx < svsp->bank_max; idx++) { - svsb = &svsp->banks[idx]; - - if (svsb->type == SVSB_HIGH) - svsb->opp_dev = svs_add_device_link(svsp, "mali"); - else if (svsb->type == SVSB_LOW) - svsb->opp_dev = svs_get_subsys_device(svsp, "mali"); + struct svs_bank *svsb = &svsp->banks[idx]; + const struct svs_bank_pdata *bdata = &svsb->pdata; + + switch (bdata->sw_id) { + case SVSB_SWID_CPU_LITTLE: + case SVSB_SWID_CPU_BIG: + svsb->opp_dev = get_cpu_device(bdata->cpu_id); + get_device(svsb->opp_dev); + break; + case SVSB_SWID_CCI: + svsb->opp_dev = svs_add_device_link(svsp, "cci"); + break; + case SVSB_SWID_GPU: + if (bdata->type == SVSB_TYPE_LOW) + svsb->opp_dev = svs_get_subsys_device(svsp, "gpu"); + else + svsb->opp_dev = svs_add_device_link(svsp, "gpu"); + break; + default: + dev_err(svsb->dev, "unknown sw_id: %u\n", bdata->sw_id); + return -EINVAL; + } if (IS_ERR(svsb->opp_dev)) return dev_err_probe(svsp->dev, PTR_ERR(svsb->opp_dev), "failed to get OPP device for bank %d\n", idx); + + ret = devm_add_action_or_reset(svsp->dev, svs_put_device, + svsb->opp_dev); + if (ret) + return ret; } return 0; @@ -2102,30 +2230,33 @@ static int svs_mt8192_platform_probe(struct svs_platform *svsp) static int svs_mt8183_platform_probe(struct svs_platform *svsp) { struct device *dev; - struct svs_bank *svsb; u32 idx; + int ret; - dev = svs_add_device_link(svsp, "thermal"); + dev = svs_add_device_link(svsp, "thermal-sensor"); if (IS_ERR(dev)) return dev_err_probe(svsp->dev, PTR_ERR(dev), "failed to get thermal device\n"); + put_device(dev); for (idx = 0; idx < svsp->bank_max; idx++) { - svsb = &svsp->banks[idx]; - - switch (svsb->sw_id) { - case SVSB_CPU_LITTLE: - case SVSB_CPU_BIG: - svsb->opp_dev = get_cpu_device(svsb->cpu_id); + struct svs_bank *svsb = &svsp->banks[idx]; + const struct svs_bank_pdata *bdata = &svsb->pdata; + + switch (bdata->sw_id) { + case SVSB_SWID_CPU_LITTLE: + case SVSB_SWID_CPU_BIG: + svsb->opp_dev = get_cpu_device(bdata->cpu_id); + get_device(svsb->opp_dev); break; - case SVSB_CCI: + case SVSB_SWID_CCI: svsb->opp_dev = svs_add_device_link(svsp, "cci"); break; - case SVSB_GPU: + case SVSB_SWID_GPU: svsb->opp_dev = svs_add_device_link(svsp, "gpu"); break; default: - dev_err(svsb->dev, "unknown sw_id: %u\n", svsb->sw_id); + dev_err(svsb->dev, "unknown sw_id: %u\n", bdata->sw_id); return -EINVAL; } @@ -2133,177 +2264,554 @@ static int svs_mt8183_platform_probe(struct svs_platform *svsp) return dev_err_probe(svsp->dev, PTR_ERR(svsb->opp_dev), "failed to get OPP device for bank %d\n", idx); + + ret = devm_add_action_or_reset(svsp->dev, svs_put_device, + svsb->opp_dev); + if (ret) + return ret; } return 0; } +static struct svs_bank svs_mt8195_banks[] = { + { + .pdata = (const struct svs_bank_pdata) { + .sw_id = SVSB_SWID_GPU, + .type = SVSB_TYPE_LOW, + .set_freq_pct = svs_set_bank_freq_pct_v3, + .get_volts = svs_get_bank_volts_v3, + .opp_count = MAX_OPP_ENTRIES, + .turn_freq_base = 640000000, + .volt_step = 6250, + .volt_base = 400000, + .age_config = 0x555555, + .dc_config = 0x1, + .vco = 0x18, + .chk_shift = 0x87, + .int_st = BIT(0), + .ctl0 = 0x00540003, + .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) { + { 10, 16 }, { 10, 24 }, { 10, 0 }, { 8, 0 }, { 8, 8 } + } + }, + .mode_support = SVSB_MODE_INIT02, + .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT, + .freq_base = 640000000, + .core_sel = 0x0fff0100, + .dvt_fixed = 0x1, + .vmax = 0x38, + .vmin = 0x14, + }, + { + .pdata = (const struct svs_bank_pdata) { + .sw_id = SVSB_SWID_GPU, + .type = SVSB_TYPE_HIGH, + .set_freq_pct = svs_set_bank_freq_pct_v3, + .get_volts = svs_get_bank_volts_v3, + .tzone_name = "gpu", + .opp_count = MAX_OPP_ENTRIES, + .turn_freq_base = 640000000, + .volt_step = 6250, + .volt_base = 400000, + .age_config = 0x555555, + .dc_config = 0x1, + .vco = 0x18, + .chk_shift = 0x87, + .int_st = BIT(1), + .ctl0 = 0x00540003, + .tzone_htemp = 85000, + .tzone_htemp_voffset = 0, + .tzone_ltemp = 25000, + .tzone_ltemp_voffset = 7, + .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) { + { 9, 16 }, { 9, 24 }, { 9, 0 }, { 8, 0 }, { 8, 8 } + }, + }, + .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT | SVSB_MON_VOLT_IGNORE, + .mode_support = SVSB_MODE_INIT02 | SVSB_MODE_MON, + .freq_base = 880000000, + .core_sel = 0x0fff0101, + .dvt_fixed = 0x6, + .vmax = 0x38, + .vmin = 0x14, + }, +}; + static struct svs_bank svs_mt8192_banks[] = { { - .sw_id = SVSB_GPU, - .type = SVSB_LOW, - .set_freq_pct = svs_set_bank_freq_pct_v3, - .get_volts = svs_get_bank_volts_v3, - .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT, - .mode_support = SVSB_MODE_INIT02, - .opp_count = MAX_OPP_ENTRIES, - .freq_base = 688000000, - .turn_freq_base = 688000000, - .volt_step = 6250, - .volt_base = 400000, - .vmax = 0x60, - .vmin = 0x1a, - .age_config = 0x555555, - .dc_config = 0x1, - .dvt_fixed = 0x1, - .vco = 0x18, - .chk_shift = 0x87, - .core_sel = 0x0fff0100, - .int_st = BIT(0), - .ctl0 = 0x00540003, + .pdata = (const struct svs_bank_pdata) { + .sw_id = SVSB_SWID_GPU, + .type = SVSB_TYPE_LOW, + .set_freq_pct = svs_set_bank_freq_pct_v3, + .get_volts = svs_get_bank_volts_v3, + .tzone_name = "gpu", + .opp_count = MAX_OPP_ENTRIES, + .turn_freq_base = 688000000, + .volt_step = 6250, + .volt_base = 400000, + .age_config = 0x555555, + .dc_config = 0x1, + .vco = 0x18, + .chk_shift = 0x87, + .int_st = BIT(0), + .ctl0 = 0x00540003, + .tzone_htemp = 85000, + .tzone_htemp_voffset = 0, + .tzone_ltemp = 25000, + .tzone_ltemp_voffset = 7, + .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) { + { 10, 16 }, { 10, 24 }, { 10, 0 }, { 17, 0 }, { 17, 8 } + } + }, + .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT, + .mode_support = SVSB_MODE_INIT02, + .freq_base = 688000000, + .core_sel = 0x0fff0100, + .dvt_fixed = 0x1, + .vmax = 0x60, + .vmin = 0x1a, + }, + { + .pdata = (const struct svs_bank_pdata) { + .sw_id = SVSB_SWID_GPU, + .type = SVSB_TYPE_HIGH, + .set_freq_pct = svs_set_bank_freq_pct_v3, + .get_volts = svs_get_bank_volts_v3, + .tzone_name = "gpu", + .opp_count = MAX_OPP_ENTRIES, + .turn_freq_base = 688000000, + .volt_step = 6250, + .volt_base = 400000, + .age_config = 0x555555, + .dc_config = 0x1, + .vco = 0x18, + .chk_shift = 0x87, + .int_st = BIT(1), + .ctl0 = 0x00540003, + .tzone_htemp = 85000, + .tzone_htemp_voffset = 0, + .tzone_ltemp = 25000, + .tzone_ltemp_voffset = 7, + .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) { + { 9, 16 }, { 9, 24 }, { 17, 0 }, { 17, 16 }, { 17, 24 } + } + }, + .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT | SVSB_MON_VOLT_IGNORE, + .mode_support = SVSB_MODE_INIT02 | SVSB_MODE_MON, + .freq_base = 902000000, + .core_sel = 0x0fff0101, + .dvt_fixed = 0x6, + .vmax = 0x60, + .vmin = 0x1a, + }, +}; + +static struct svs_bank svs_mt8188_banks[] = { + { + .pdata = (const struct svs_bank_pdata) { + .sw_id = SVSB_SWID_GPU, + .type = SVSB_TYPE_LOW, + .set_freq_pct = svs_set_bank_freq_pct_v3, + .get_volts = svs_get_bank_volts_v3, + .opp_count = MAX_OPP_ENTRIES, + .turn_freq_base = 640000000, + .volt_step = 6250, + .volt_base = 400000, + .age_config = 0x555555, + .dc_config = 0x555555, + .vco = 0x10, + .chk_shift = 0x87, + .int_st = BIT(0), + .ctl0 = 0x00100003, + .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) { + { 5, 16 }, { 5, 24 }, { 5, 0 }, { 15, 16 }, { 15, 24 } + } + }, + .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT, + .mode_support = SVSB_MODE_INIT02, + .freq_base = 640000000, + .core_sel = 0x0fff0000, + .dvt_fixed = 0x1, + .vmax = 0x38, + .vmin = 0x1c, }, { - .sw_id = SVSB_GPU, - .type = SVSB_HIGH, - .set_freq_pct = svs_set_bank_freq_pct_v3, - .get_volts = svs_get_bank_volts_v3, - .tzone_name = "gpu1", - .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT | - SVSB_MON_VOLT_IGNORE, - .mode_support = SVSB_MODE_INIT02 | SVSB_MODE_MON, - .opp_count = MAX_OPP_ENTRIES, - .freq_base = 902000000, - .turn_freq_base = 688000000, - .volt_step = 6250, - .volt_base = 400000, - .vmax = 0x60, - .vmin = 0x1a, - .age_config = 0x555555, - .dc_config = 0x1, - .dvt_fixed = 0x6, - .vco = 0x18, - .chk_shift = 0x87, - .core_sel = 0x0fff0101, - .int_st = BIT(1), - .ctl0 = 0x00540003, - .tzone_htemp = 85000, - .tzone_htemp_voffset = 0, - .tzone_ltemp = 25000, - .tzone_ltemp_voffset = 7, + .pdata = (const struct svs_bank_pdata) { + .sw_id = SVSB_SWID_GPU, + .type = SVSB_TYPE_HIGH, + .set_freq_pct = svs_set_bank_freq_pct_v3, + .get_volts = svs_get_bank_volts_v3, + .tzone_name = "gpu", + .opp_count = MAX_OPP_ENTRIES, + .turn_freq_base = 640000000, + .volt_step = 6250, + .volt_base = 400000, + .age_config = 0x555555, + .dc_config = 0x555555, + .vco = 0x10, + .chk_shift = 0x87, + .int_st = BIT(1), + .ctl0 = 0x00100003, + .tzone_htemp = 85000, + .tzone_htemp_voffset = 0, + .tzone_ltemp = 25000, + .tzone_ltemp_voffset = 7, + .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) { + { 4, 16 }, { 4, 24 }, { 4, 0 }, { 14, 0 }, { 14, 8 } + } + }, + .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT | SVSB_MON_VOLT_IGNORE, + .mode_support = SVSB_MODE_INIT02 | SVSB_MODE_MON, + .freq_base = 880000000, + .core_sel = 0x0fff0001, + .dvt_fixed = 0x4, + .vmax = 0x38, + .vmin = 0x1c, + }, +}; + +static struct svs_bank svs_mt8186_banks[] = { + { + .pdata = (const struct svs_bank_pdata) { + .sw_id = SVSB_SWID_CPU_BIG, + .type = SVSB_TYPE_LOW, + .set_freq_pct = svs_set_bank_freq_pct_v3, + .get_volts = svs_get_bank_volts_v3, + .cpu_id = 6, + .opp_count = MAX_OPP_ENTRIES, + .turn_freq_base = 1670000000, + .volt_step = 6250, + .volt_base = 400000, + .age_config = 0x1, + .dc_config = 0x1, + .vco = 0x10, + .chk_shift = 0x87, + .int_st = BIT(0), + .ctl0 = 0x00540003, + .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) { + { 3, 16 }, { 3, 24 }, { 3, 0 }, { 14, 16 }, { 14, 24 } + } + }, + .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT, + .volt_od = 4, + .mode_support = SVSB_MODE_INIT02, + .freq_base = 1670000000, + .core_sel = 0x0fff0100, + .dvt_fixed = 0x3, + .vmax = 0x59, + .vmin = 0x20, + }, + { + .pdata = (const struct svs_bank_pdata) { + .sw_id = SVSB_SWID_CPU_BIG, + .type = SVSB_TYPE_HIGH, + .set_freq_pct = svs_set_bank_freq_pct_v3, + .get_volts = svs_get_bank_volts_v3, + .cpu_id = 6, + .tzone_name = "cpu-big", + .opp_count = MAX_OPP_ENTRIES, + .turn_freq_base = 1670000000, + .volt_step = 6250, + .volt_base = 400000, + .age_config = 0x1, + .dc_config = 0x1, + .vco = 0x10, + .chk_shift = 0x87, + .int_st = BIT(1), + .ctl0 = 0x00540003, + .tzone_htemp = 85000, + .tzone_htemp_voffset = 8, + .tzone_ltemp = 25000, + .tzone_ltemp_voffset = 8, + .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) { + { 2, 16 }, { 2, 24 }, { 2, 0 }, { 13, 0 }, { 13, 8 } + } + }, + .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT | SVSB_MON_VOLT_IGNORE, + .volt_od = 4, + .mode_support = SVSB_MODE_INIT02 | SVSB_MODE_MON, + .freq_base = 2050000000, + .core_sel = 0x0fff0101, + .dvt_fixed = 0x6, + .vmax = 0x73, + .vmin = 0x20, + }, + { + .pdata = (const struct svs_bank_pdata) { + .sw_id = SVSB_SWID_CPU_LITTLE, + .set_freq_pct = svs_set_bank_freq_pct_v2, + .get_volts = svs_get_bank_volts_v2, + .cpu_id = 0, + .tzone_name = "cpu-little", + .opp_count = MAX_OPP_ENTRIES, + .volt_step = 6250, + .volt_base = 400000, + .age_config = 0x1, + .dc_config = 0x1, + .vco = 0x10, + .chk_shift = 0x87, + .int_st = BIT(2), + .ctl0 = 0x3210000f, + .tzone_htemp = 85000, + .tzone_htemp_voffset = 8, + .tzone_ltemp = 25000, + .tzone_ltemp_voffset = 8, + .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) { + { 4, 16 }, { 4, 24 }, { 4, 0 }, { 14, 0 }, { 14, 8 } + } + }, + .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT | SVSB_MON_VOLT_IGNORE, + .volt_od = 3, + .mode_support = SVSB_MODE_INIT02 | SVSB_MODE_MON, + .freq_base = 2000000000, + .core_sel = 0x0fff0102, + .dvt_fixed = 0x6, + .vmax = 0x65, + .vmin = 0x20, + }, + { + .pdata = (const struct svs_bank_pdata) { + .sw_id = SVSB_SWID_CCI, + .set_freq_pct = svs_set_bank_freq_pct_v2, + .get_volts = svs_get_bank_volts_v2, + .tzone_name = "cci", + .opp_count = MAX_OPP_ENTRIES, + .volt_step = 6250, + .volt_base = 400000, + .age_config = 0x1, + .dc_config = 0x1, + .vco = 0x10, + .chk_shift = 0x87, + .int_st = BIT(3), + .ctl0 = 0x3210000f, + .tzone_htemp = 85000, + .tzone_htemp_voffset = 8, + .tzone_ltemp = 25000, + .tzone_ltemp_voffset = 8, + .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) { + { 5, 16 }, { 5, 24 }, { 5, 0 }, { 15, 16 }, { 15, 24 } + } + }, + .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT | SVSB_MON_VOLT_IGNORE, + .volt_od = 3, + .mode_support = SVSB_MODE_INIT02 | SVSB_MODE_MON, + .freq_base = 1400000000, + .core_sel = 0x0fff0103, + .dvt_fixed = 0x6, + .vmax = 0x65, + .vmin = 0x20, + }, + { + .pdata = (const struct svs_bank_pdata) { + .sw_id = SVSB_SWID_GPU, + .set_freq_pct = svs_set_bank_freq_pct_v2, + .get_volts = svs_get_bank_volts_v2, + .tzone_name = "gpu", + .opp_count = MAX_OPP_ENTRIES, + .volt_step = 6250, + .volt_base = 400000, + .age_config = 0x555555, + .dc_config = 0x1, + .vco = 0x10, + .chk_shift = 0x87, + .int_st = BIT(4), + .ctl0 = 0x00100003, + .tzone_htemp = 85000, + .tzone_htemp_voffset = 8, + .tzone_ltemp = 25000, + .tzone_ltemp_voffset = 7, + .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) { + { 6, 16 }, { 6, 24 }, { 6, 0 }, { 15, 8 }, { 15, 0 } + } + }, + .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT | SVSB_MON_VOLT_IGNORE, + .mode_support = SVSB_MODE_INIT02 | SVSB_MODE_MON, + .freq_base = 850000000, + .core_sel = 0x0fff0104, + .dvt_fixed = 0x4, + .vmax = 0x58, + .vmin = 0x20, }, }; static struct svs_bank svs_mt8183_banks[] = { { - .sw_id = SVSB_CPU_LITTLE, - .set_freq_pct = svs_set_bank_freq_pct_v2, - .get_volts = svs_get_bank_volts_v2, - .cpu_id = 0, - .buck_name = "proc", - .volt_flags = SVSB_INIT01_VOLT_INC_ONLY, - .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02, - .opp_count = MAX_OPP_ENTRIES, - .freq_base = 1989000000, - .vboot = 0x30, - .volt_step = 6250, - .volt_base = 500000, - .vmax = 0x64, - .vmin = 0x18, - .age_config = 0x555555, - .dc_config = 0x555555, - .dvt_fixed = 0x7, - .vco = 0x10, - .chk_shift = 0x77, - .core_sel = 0x8fff0000, - .int_st = BIT(0), - .ctl0 = 0x00010001, + .pdata = (const struct svs_bank_pdata) { + .sw_id = SVSB_SWID_CPU_LITTLE, + .set_freq_pct = svs_set_bank_freq_pct_v2, + .get_volts = svs_get_bank_volts_v2, + .cpu_id = 0, + .buck_name = "proc", + .opp_count = MAX_OPP_ENTRIES, + .vboot = 0x30, + .volt_step = 6250, + .volt_base = 500000, + .age_config = 0x555555, + .dc_config = 0x555555, + .vco = 0x10, + .chk_shift = 0x77, + .int_st = BIT(0), + .ctl0 = 0x00010001, + .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) { + { 16, 0 }, { 16, 8 }, { 17, 16 }, { 16, 16 }, { 16, 24 } + } + }, + .volt_flags = SVSB_INIT01_VOLT_INC_ONLY, + .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02, + .freq_base = 1989000000, + .core_sel = 0x8fff0000, + .dvt_fixed = 0x7, + .vmax = 0x64, + .vmin = 0x18, + }, { - .sw_id = SVSB_CPU_BIG, - .set_freq_pct = svs_set_bank_freq_pct_v2, - .get_volts = svs_get_bank_volts_v2, - .cpu_id = 4, - .buck_name = "proc", - .volt_flags = SVSB_INIT01_VOLT_INC_ONLY, - .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02, - .opp_count = MAX_OPP_ENTRIES, - .freq_base = 1989000000, - .vboot = 0x30, - .volt_step = 6250, - .volt_base = 500000, - .vmax = 0x58, - .vmin = 0x10, - .age_config = 0x555555, - .dc_config = 0x555555, - .dvt_fixed = 0x7, - .vco = 0x10, - .chk_shift = 0x77, - .core_sel = 0x8fff0001, - .int_st = BIT(1), - .ctl0 = 0x00000001, + .pdata = (const struct svs_bank_pdata) { + .sw_id = SVSB_SWID_CPU_BIG, + .set_freq_pct = svs_set_bank_freq_pct_v2, + .get_volts = svs_get_bank_volts_v2, + .cpu_id = 4, + .buck_name = "proc", + .opp_count = MAX_OPP_ENTRIES, + .vboot = 0x30, + .volt_step = 6250, + .volt_base = 500000, + .age_config = 0x555555, + .dc_config = 0x555555, + .vco = 0x10, + .chk_shift = 0x77, + .int_st = BIT(1), + .ctl0 = 0x00000001, + .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) { + { 18, 0 }, { 18, 8 }, { 17, 0 }, { 18, 16 }, { 18, 24 } + } + }, + .volt_flags = SVSB_INIT01_VOLT_INC_ONLY, + .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02, + .freq_base = 1989000000, + .core_sel = 0x8fff0001, + .dvt_fixed = 0x7, + .vmax = 0x58, + .vmin = 0x10, + }, { - .sw_id = SVSB_CCI, - .set_freq_pct = svs_set_bank_freq_pct_v2, - .get_volts = svs_get_bank_volts_v2, - .buck_name = "proc", - .volt_flags = SVSB_INIT01_VOLT_INC_ONLY, - .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02, - .opp_count = MAX_OPP_ENTRIES, - .freq_base = 1196000000, - .vboot = 0x30, - .volt_step = 6250, - .volt_base = 500000, - .vmax = 0x64, - .vmin = 0x18, - .age_config = 0x555555, - .dc_config = 0x555555, - .dvt_fixed = 0x7, - .vco = 0x10, - .chk_shift = 0x77, - .core_sel = 0x8fff0002, - .int_st = BIT(2), - .ctl0 = 0x00100003, + .pdata = (const struct svs_bank_pdata) { + .sw_id = SVSB_SWID_CCI, + .set_freq_pct = svs_set_bank_freq_pct_v2, + .get_volts = svs_get_bank_volts_v2, + .buck_name = "proc", + .opp_count = MAX_OPP_ENTRIES, + .vboot = 0x30, + .volt_step = 6250, + .volt_base = 500000, + .age_config = 0x555555, + .dc_config = 0x555555, + .vco = 0x10, + .chk_shift = 0x77, + .int_st = BIT(2), + .ctl0 = 0x00100003, + .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) { + { 4, 0 }, { 4, 8 }, { 5, 16 }, { 4, 16 }, { 4, 24 } + } + }, + .volt_flags = SVSB_INIT01_VOLT_INC_ONLY, + .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02, + .freq_base = 1196000000, + .core_sel = 0x8fff0002, + .dvt_fixed = 0x7, + .vmax = 0x64, + .vmin = 0x18, }, { - .sw_id = SVSB_GPU, - .set_freq_pct = svs_set_bank_freq_pct_v2, - .get_volts = svs_get_bank_volts_v2, - .buck_name = "mali", - .tzone_name = "tzts2", - .volt_flags = SVSB_INIT01_PD_REQ | - SVSB_INIT01_VOLT_INC_ONLY, - .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02 | - SVSB_MODE_MON, - .opp_count = MAX_OPP_ENTRIES, - .freq_base = 900000000, - .vboot = 0x30, - .volt_step = 6250, - .volt_base = 500000, - .vmax = 0x40, - .vmin = 0x14, - .age_config = 0x555555, - .dc_config = 0x555555, - .dvt_fixed = 0x3, - .vco = 0x10, - .chk_shift = 0x77, - .core_sel = 0x8fff0003, - .int_st = BIT(3), - .ctl0 = 0x00050001, - .tzone_htemp = 85000, - .tzone_htemp_voffset = 0, - .tzone_ltemp = 25000, - .tzone_ltemp_voffset = 3, + .pdata = (const struct svs_bank_pdata) { + .sw_id = SVSB_SWID_GPU, + .set_freq_pct = svs_set_bank_freq_pct_v2, + .get_volts = svs_get_bank_volts_v2, + .buck_name = "mali", + .tzone_name = "gpu", + .opp_count = MAX_OPP_ENTRIES, + .vboot = 0x30, + .volt_step = 6250, + .volt_base = 500000, + .age_config = 0x555555, + .dc_config = 0x555555, + .vco = 0x10, + .chk_shift = 0x77, + .int_st = BIT(3), + .ctl0 = 0x00050001, + .tzone_htemp = 85000, + .tzone_htemp_voffset = 0, + .tzone_ltemp = 25000, + .tzone_ltemp_voffset = 3, + .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) { + { 6, 0 }, { 6, 8 }, { 5, 0 }, { 6, 16 }, { 6, 24 } + } + }, + .volt_flags = SVSB_INIT01_PD_REQ | SVSB_INIT01_VOLT_INC_ONLY, + .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02 | SVSB_MODE_MON, + .freq_base = 900000000, + .core_sel = 0x8fff0003, + .dvt_fixed = 0x3, + .vmax = 0x40, + .vmin = 0x14, }, }; +static const struct svs_platform_data svs_mt8195_platform_data = { + .name = "mt8195-svs", + .banks = svs_mt8195_banks, + .efuse_parsing = svs_common_parse_efuse, + .probe = svs_mt8192_platform_probe, + .regs = svs_regs_v2, + .bank_max = ARRAY_SIZE(svs_mt8195_banks), + .ts_coeff = SVSB_TS_COEFF_MT8195, + .glb_fuse_map = (const struct svs_fusemap[GLB_MAX]) { + { 0, 0 }, { 19, 4 } + } +}; + static const struct svs_platform_data svs_mt8192_platform_data = { .name = "mt8192-svs", .banks = svs_mt8192_banks, - .efuse_parsing = svs_mt8192_efuse_parsing, + .efuse_parsing = svs_common_parse_efuse, .probe = svs_mt8192_platform_probe, .regs = svs_regs_v2, .bank_max = ARRAY_SIZE(svs_mt8192_banks), + .ts_coeff = SVSB_TS_COEFF_MT8195, + .glb_fuse_map = (const struct svs_fusemap[GLB_MAX]) { + /* FT_PGM not present */ + { -1, 0 }, { 19, 4 } + } +}; + +static const struct svs_platform_data svs_mt8188_platform_data = { + .name = "mt8188-svs", + .banks = svs_mt8188_banks, + .efuse_parsing = svs_common_parse_efuse, + .probe = svs_mt8192_platform_probe, + .regs = svs_regs_v2, + .bank_max = ARRAY_SIZE(svs_mt8188_banks), + .ts_coeff = SVSB_TS_COEFF_MT8195, + .glb_fuse_map = (const struct svs_fusemap[GLB_MAX]) { + /* FT_PGM and VMIN not present */ + { -1, 0 }, { -1, 0 } + } +}; + +static const struct svs_platform_data svs_mt8186_platform_data = { + .name = "mt8186-svs", + .banks = svs_mt8186_banks, + .efuse_parsing = svs_common_parse_efuse, + .probe = svs_mt8192_platform_probe, + .regs = svs_regs_v2, + .bank_max = ARRAY_SIZE(svs_mt8186_banks), + .ts_coeff = SVSB_TS_COEFF_MT8186, + .glb_fuse_map = (const struct svs_fusemap[GLB_MAX]) { + /* FT_PGM and VMIN not present */ + { -1, 0 }, { -1, 0 } + } }; static const struct svs_platform_data svs_mt8183_platform_data = { @@ -2313,133 +2821,123 @@ static const struct svs_platform_data svs_mt8183_platform_data = { .probe = svs_mt8183_platform_probe, .regs = svs_regs_v2, .bank_max = ARRAY_SIZE(svs_mt8183_banks), + .glb_fuse_map = (const struct svs_fusemap[GLB_MAX]) { + /* VMIN not present */ + { 0, 4 }, { -1, 0 } + } }; static const struct of_device_id svs_of_match[] = { - { - .compatible = "mediatek,mt8192-svs", - .data = &svs_mt8192_platform_data, - }, { - .compatible = "mediatek,mt8183-svs", - .data = &svs_mt8183_platform_data, - }, { - /* Sentinel */ - }, + { .compatible = "mediatek,mt8195-svs", .data = &svs_mt8195_platform_data }, + { .compatible = "mediatek,mt8192-svs", .data = &svs_mt8192_platform_data }, + { .compatible = "mediatek,mt8188-svs", .data = &svs_mt8188_platform_data }, + { .compatible = "mediatek,mt8186-svs", .data = &svs_mt8186_platform_data }, + { .compatible = "mediatek,mt8183-svs", .data = &svs_mt8183_platform_data }, + { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, svs_of_match); -static struct svs_platform *svs_platform_probe(struct platform_device *pdev) +static int svs_probe(struct platform_device *pdev) { struct svs_platform *svsp; const struct svs_platform_data *svsp_data; - int ret; + int ret, svsp_irq; svsp_data = of_device_get_match_data(&pdev->dev); - if (!svsp_data) { - dev_err(&pdev->dev, "no svs platform data?\n"); - return ERR_PTR(-EPERM); - } svsp = devm_kzalloc(&pdev->dev, sizeof(*svsp), GFP_KERNEL); if (!svsp) - return ERR_PTR(-ENOMEM); + return -ENOMEM; svsp->dev = &pdev->dev; - svsp->name = svsp_data->name; svsp->banks = svsp_data->banks; - svsp->efuse_parsing = svsp_data->efuse_parsing; - svsp->probe = svsp_data->probe; svsp->regs = svsp_data->regs; svsp->bank_max = svsp_data->bank_max; + svsp->ts_coeff = svsp_data->ts_coeff; - ret = svsp->probe(svsp); + ret = svsp_data->probe(svsp); if (ret) - return ERR_PTR(ret); - - return svsp; -} + return ret; -static int svs_probe(struct platform_device *pdev) -{ - struct svs_platform *svsp; - int svsp_irq, ret; + ret = svs_get_efuse_data(svsp, "svs-calibration-data", + &svsp->efuse, &svsp->efuse_max); + if (ret) + return dev_err_probe(&pdev->dev, ret, "Cannot read SVS calibration\n"); - svsp = svs_platform_probe(pdev); - if (IS_ERR(svsp)) - return PTR_ERR(svsp); + ret = svs_get_efuse_data(svsp, "t-calibration-data", + &svsp->tefuse, &svsp->tefuse_max); + if (ret) { + dev_err_probe(&pdev->dev, ret, "Cannot read SVS-Thermal calibration\n"); + goto svs_probe_free_efuse; + } - if (!svs_is_efuse_data_correct(svsp)) { - dev_notice(svsp->dev, "efuse data isn't correct\n"); - ret = -EPERM; - goto svs_probe_free_resource; + if (!svsp_data->efuse_parsing(svsp, svsp_data)) { + ret = dev_err_probe(svsp->dev, -EINVAL, "efuse data parsing failed\n"); + goto svs_probe_free_tefuse; } ret = svs_bank_resource_setup(svsp); if (ret) { - dev_err(svsp->dev, "svs bank resource setup fail: %d\n", ret); - goto svs_probe_free_resource; + dev_err_probe(svsp->dev, ret, "svs bank resource setup fail\n"); + goto svs_probe_free_tefuse; } svsp_irq = platform_get_irq(pdev, 0); if (svsp_irq < 0) { ret = svsp_irq; - goto svs_probe_free_resource; - } - - ret = devm_request_threaded_irq(svsp->dev, svsp_irq, NULL, svs_isr, - IRQF_ONESHOT, svsp->name, svsp); - if (ret) { - dev_err(svsp->dev, "register irq(%d) failed: %d\n", - svsp_irq, ret); - goto svs_probe_free_resource; + goto svs_probe_free_tefuse; } svsp->main_clk = devm_clk_get(svsp->dev, "main"); if (IS_ERR(svsp->main_clk)) { - dev_err(svsp->dev, "failed to get clock: %ld\n", - PTR_ERR(svsp->main_clk)); - ret = PTR_ERR(svsp->main_clk); - goto svs_probe_free_resource; + ret = dev_err_probe(svsp->dev, PTR_ERR(svsp->main_clk), + "failed to get clock\n"); + goto svs_probe_free_tefuse; } ret = clk_prepare_enable(svsp->main_clk); if (ret) { - dev_err(svsp->dev, "cannot enable main clk: %d\n", ret); - goto svs_probe_free_resource; + dev_err_probe(svsp->dev, ret, "cannot enable main clk\n"); + goto svs_probe_free_tefuse; } svsp->base = of_iomap(svsp->dev->of_node, 0); if (IS_ERR_OR_NULL(svsp->base)) { - dev_err(svsp->dev, "cannot find svs register base\n"); - ret = -EINVAL; + ret = dev_err_probe(svsp->dev, -EINVAL, "cannot find svs register base\n"); goto svs_probe_clk_disable; } + ret = devm_request_threaded_irq(svsp->dev, svsp_irq, NULL, svs_isr, + IRQF_ONESHOT, svsp_data->name, svsp); + if (ret) { + dev_err_probe(svsp->dev, ret, "register irq(%d) failed\n", svsp_irq); + goto svs_probe_iounmap; + } + ret = svs_start(svsp); if (ret) { - dev_err(svsp->dev, "svs start fail: %d\n", ret); + dev_err_probe(svsp->dev, ret, "svs start fail\n"); goto svs_probe_iounmap; } +#ifdef CONFIG_DEBUG_FS ret = svs_create_debug_cmds(svsp); if (ret) { - dev_err(svsp->dev, "svs create debug cmds fail: %d\n", ret); + dev_err_probe(svsp->dev, ret, "svs create debug cmds fail\n"); goto svs_probe_iounmap; } +#endif return 0; svs_probe_iounmap: iounmap(svsp->base); - svs_probe_clk_disable: clk_disable_unprepare(svsp->main_clk); - -svs_probe_free_resource: - if (!IS_ERR_OR_NULL(svsp->efuse)) - kfree(svsp->efuse); - if (!IS_ERR_OR_NULL(svsp->tefuse)) - kfree(svsp->tefuse); - +svs_probe_free_tefuse: + kfree(svsp->tefuse); +svs_probe_free_efuse: + kfree(svsp->efuse); return ret; } @@ -2457,5 +2955,6 @@ static struct platform_driver svs_driver = { module_platform_driver(svs_driver); MODULE_AUTHOR("Roger Lu <roger.lu@mediatek.com>"); +MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>"); MODULE_DESCRIPTION("MediaTek SVS driver"); MODULE_LICENSE("GPL"); |
