From patchwork Thu Jan 27 03:39:53 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roger Lu X-Patchwork-Id: 537212 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 74F2FC433FE for ; Thu, 27 Jan 2022 03:40:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235806AbiA0DkG (ORCPT ); Wed, 26 Jan 2022 22:40:06 -0500 Received: from mailgw01.mediatek.com ([60.244.123.138]:33280 "EHLO mailgw01.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S235849AbiA0DkF (ORCPT ); Wed, 26 Jan 2022 22:40:05 -0500 X-UUID: 35c24717b9564b018508f858bfc3b82c-20220127 X-UUID: 35c24717b9564b018508f858bfc3b82c-20220127 Received: from mtkmbs10n1.mediatek.inc [(172.21.101.34)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1759557088; Thu, 27 Jan 2022 11:40:00 +0800 Received: from mtkcas11.mediatek.inc (172.21.101.40) by mtkmbs10n1.mediatek.inc (172.21.101.34) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.2.792.15; Thu, 27 Jan 2022 11:39:58 +0800 Received: from mtksdaap41.mediatek.inc (172.21.77.4) by mtkcas11.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Thu, 27 Jan 2022 11:39:58 +0800 From: Roger Lu To: Matthias Brugger , Enric Balletbo Serra , Kevin Hilman , Rob Herring , Nicolas Boichat , Stephen Boyd , Philipp Zabel CC: Fan Chen , HenryC Chen , Xiaoqing Liu , Charles Yang , Angus Lin , Mark Rutland , Nishanth Menon , Roger Lu , , , , , , , Guenter Roeck Subject: [PATCH v22 4/7] soc: mediatek: SVS: add monitor mode Date: Thu, 27 Jan 2022 11:39:53 +0800 Message-ID: <20220127033956.24585-5-roger.lu@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20220127033956.24585-1-roger.lu@mediatek.com> References: <20220127033956.24585-1-roger.lu@mediatek.com> MIME-Version: 1.0 X-MTK: N Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org SVS monitor mode is based on different thermal temperature to provide suitable SVS bank voltages. Signed-off-by: Roger Lu --- drivers/soc/mediatek/mtk-svs.c | 253 ++++++++++++++++++++++++++++++++- 1 file changed, 247 insertions(+), 6 deletions(-) diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c index 2d7ea3d607c4..be53470d439c 100644 --- a/drivers/soc/mediatek/mtk-svs.c +++ b/drivers/soc/mediatek/mtk-svs.c @@ -25,6 +25,7 @@ #include #include #include +#include /* svs bank 1-line software id */ #define SVSB_CPU_LITTLE BIT(0) @@ -36,6 +37,7 @@ #define SVSB_MODE_ALL_DISABLE 0 #define SVSB_MODE_INIT01 BIT(1) #define SVSB_MODE_INIT02 BIT(2) +#define SVSB_MODE_MON BIT(3) /* svs bank volt flags */ #define SVSB_INIT01_PD_REQ BIT(0) @@ -49,16 +51,21 @@ #define SVSB_DTLO 0xfe #define SVSB_EN_INIT01 0x1 #define SVSB_EN_INIT02 0x5 +#define SVSB_EN_MON 0x2 #define SVSB_EN_OFF 0x0 #define SVSB_INTEN_INIT0x 0x00005f01 +#define SVSB_INTEN_MONVOPEN 0x00ff0000 #define SVSB_INTSTS_CLEAN 0x00ffffff #define SVSB_INTSTS_COMPLETE 0x1 +#define SVSB_INTSTS_MONVOP 0x00ff0000 #define SVSB_RUNCONFIG_DEFAULT 0x80000000 /* svs bank related setting */ #define MAX_OPP_ENTRIES 16 #define SVSB_DC_SIGNED_BIT BIT(15) #define SVSB_DET_CLK_EN BIT(31) +#define SVSB_TEMP_LOWER_BOUND 0xb2 +#define SVSB_TEMP_UPPER_BOUND 0x64 static DEFINE_SPINLOCK(svs_lock); @@ -67,6 +74,7 @@ static DEFINE_SPINLOCK(svs_lock); * @SVSB_PHASE_ERROR: svs bank encounters unexpected condition * @SVSB_PHASE_INIT01: svs bank basic init for data calibration * @SVSB_PHASE_INIT02: svs bank can provide voltages to opp table + * @SVSB_PHASE_MON: svs bank can provide voltages with thermal effect * @SVSB_PHASE_MAX: total number of svs bank phase (debug purpose) * * Each svs bank has its own independent phase and we enable each svs bank by @@ -74,12 +82,13 @@ static DEFINE_SPINLOCK(svs_lock); * condition, it will fire an irq (PHASE_ERROR) to inform svs software. * * svs bank general phase-enabled order: - * SVSB_PHASE_INIT01 -> SVSB_PHASE_INIT02 + * SVSB_PHASE_INIT01 -> SVSB_PHASE_INIT02 -> SVSB_PHASE_MON */ enum svsb_phase { SVSB_PHASE_ERROR = 0, SVSB_PHASE_INIT01, SVSB_PHASE_INIT02, + SVSB_PHASE_MON, SVSB_PHASE_MAX, }; @@ -210,9 +219,11 @@ static const u32 svs_regs_v2[] = { * @probe: svs platform probe function pointer * @irqflags: svs platform irq settings flags * @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 */ struct svs_platform { char *name; @@ -225,9 +236,11 @@ struct svs_platform { int (*probe)(struct svs_platform *svsp); unsigned long irqflags; size_t efuse_max; + size_t tefuse_max; const u32 *regs; u32 bank_max; u32 *efuse; + u32 *tefuse; }; struct svs_platform_data { @@ -247,11 +260,13 @@ struct svs_platform_data { * @pd_dev: power domain device for SoC mtcmos 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 * @pm_runtime_enabled_count: bank pm runtime enabled count @@ -280,6 +295,13 @@ struct svs_platform_data { * @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 * @mdes: svs efuse data * @mtdes: svs efuse data @@ -297,11 +319,13 @@ struct svs_bank { struct device *pd_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); char *name; char *buck_name; + char *tzone_name; enum svsb_phase phase; s32 volt_od; u32 pm_runtime_enabled_count; @@ -330,6 +354,13 @@ struct svs_bank { 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; @@ -372,11 +403,27 @@ static u32 svs_bank_volt_to_opp_volt(u32 svsb_volt, u32 svsb_volt_step, static int svs_adjust_pm_opp_volts(struct svs_bank *svsb) { - int ret = -EPERM; - u32 i, svsb_volt, opp_volt; + int ret = -EPERM, tzone_temp = 0; + u32 i, svsb_volt, opp_volt, temp_voffset = 0; mutex_lock(&svsb->lock); + /* Get thermal effect */ + if (svsb->phase == SVSB_PHASE_MON) { + 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); + 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; + } + /* vmin <= svsb_volt (opp_volt) <= default opp voltage */ for (i = 0; i < svsb->opp_count; i++) { switch (svsb->phase) { @@ -392,6 +439,13 @@ static int svs_adjust_pm_opp_volts(struct svs_bank *svsb) 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); + break; default: dev_err(svsb->dev, "unknown phase: %u\n", svsb->phase); ret = -EINVAL; @@ -486,7 +540,7 @@ static void svs_set_bank_phase(struct svs_platform *svsp, enum svsb_phase target_phase) { struct svs_bank *svsb = svsp->pbank; - u32 des_char, temp_char, det_char, limit_vals, init2vals; + u32 des_char, temp_char, det_char, limit_vals, init2vals, ts_calcs; svs_switch_bank(svsp); @@ -527,6 +581,12 @@ static void svs_set_bank_phase(struct svs_platform *svsp, svs_writel_relaxed(svsp, init2vals, INIT2VALS); svs_writel_relaxed(svsp, SVSB_EN_INIT02, SVSEN); break; + case SVSB_PHASE_MON: + ts_calcs = (svsb->bts << 12) | svsb->mts; + svs_writel_relaxed(svsp, ts_calcs, TSCALCS); + svs_writel_relaxed(svsp, SVSB_INTEN_MONVOPEN, INTEN); + svs_writel_relaxed(svsp, SVSB_EN_MON, SVSEN); + break; default: dev_err(svsb->dev, "requested unknown target phase: %u\n", target_phase); @@ -546,6 +606,7 @@ static inline void svs_error_isr_handler(struct svs_platform *svsp) dev_err(svsb->dev, "SMSTATE0 = 0x%08x, SMSTATE1 = 0x%08x\n", svs_readl_relaxed(svsp, SMSTATE0), svs_readl_relaxed(svsp, SMSTATE1)); + dev_err(svsb->dev, "TEMP = 0x%08x\n", svs_readl_relaxed(svsp, TEMP)); svsb->phase = SVSB_PHASE_ERROR; svs_writel_relaxed(svsp, SVSB_EN_OFF, SVSEN); @@ -593,6 +654,17 @@ static inline void svs_init02_isr_handler(struct svs_platform *svsp) svs_writel_relaxed(svsp, SVSB_INTSTS_COMPLETE, INTSTS); } +static inline void svs_mon_mode_isr_handler(struct svs_platform *svsp) +{ + struct svs_bank *svsb = svsp->pbank; + + svsb->phase = SVSB_PHASE_MON; + svsb->get_volts(svsp); + + svsb->temp = svs_readl_relaxed(svsp, TEMP) & GENMASK(7, 0); + svs_writel_relaxed(svsp, SVSB_INTSTS_MONVOP, INTSTS); +} + static irqreturn_t svs_isr(int irq, void *data) { struct svs_platform *svsp = data; @@ -623,6 +695,8 @@ static irqreturn_t svs_isr(int irq, void *data) else if (int_sts == SVSB_INTSTS_COMPLETE && svs_en == SVSB_EN_INIT02) svs_init02_isr_handler(svsp); + else if (int_sts & SVSB_INTSTS_MONVOP) + svs_mon_mode_isr_handler(svsp); else svs_error_isr_handler(svsp); @@ -843,6 +917,25 @@ static int svs_init02(struct svs_platform *svsp) return 0; } +static void svs_mon_mode(struct svs_platform *svsp) +{ + struct svs_bank *svsb; + unsigned long flags; + u32 idx; + + for (idx = 0; idx < svsp->bank_max; idx++) { + svsb = &svsp->banks[idx]; + + if (!(svsb->mode_support & SVSB_MODE_MON)) + continue; + + spin_lock_irqsave(&svs_lock, flags); + svsp->pbank = svsb; + svs_set_bank_phase(svsp, SVSB_PHASE_MON); + spin_unlock_irqrestore(&svs_lock, flags); + } +} + static int svs_start(struct svs_platform *svsp) { int ret; @@ -855,6 +948,8 @@ static int svs_start(struct svs_platform *svsp) if (ret) return ret; + svs_mon_mode(svsp); + return 0; } @@ -900,6 +995,8 @@ static int svs_resume(struct device *dev) if (ret) return ret; + svs_mon_mode(svsp); + return 0; } @@ -964,6 +1061,15 @@ static int svs_bank_resource_setup(struct svs_platform *svsp) } } + if (svsb->mode_support & SVSB_MODE_MON) { + svsb->tzd = thermal_zone_get_zone_by_name(svsb->tzone_name); + if (IS_ERR(svsb->tzd)) { + dev_err(svsb->dev, "cannot get \"%s\" thermal zone\n", + svsb->tzone_name); + return PTR_ERR(svsb->tzd); + } + } + count = dev_pm_opp_get_opp_count(svsb->opp_dev); if (svsb->opp_count != count) { dev_err(svsb->dev, @@ -994,7 +1100,11 @@ static int svs_bank_resource_setup(struct svs_platform *svsp) static bool svs_mt8183_efuse_parsing(struct svs_platform *svsp) { struct svs_bank *svsb; - u32 idx, i, ft_pgm; + struct nvmem_cell *cell; + 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; for (i = 0; i < svsp->efuse_max; i++) if (svsp->efuse[i]) @@ -1070,6 +1180,126 @@ static bool svs_mt8183_efuse_parsing(struct svs_platform *svsp) } } + /* Get thermal efuse by nvmem */ + cell = nvmem_cell_get(svsp->dev, "t-calibration-data"); + if (IS_ERR(cell)) { + dev_err(svsp->dev, "no \"t-calibration-data\"? %ld\n", + PTR_ERR(cell)); + goto remove_mt8183_svsb_mon_mode; + } + + 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)); + goto remove_mt8183_svsb_mon_mode; + } + + svsp->tefuse_max /= sizeof(u32); + nvmem_cell_put(cell); + + /* Thermal efuse parsing */ + adc_ge_t = (svsp->tefuse[1] >> 22) & GENMASK(9, 0); + adc_oe_t = (svsp->tefuse[1] >> 12) & GENMASK(9, 0); + + o_vtsmcu[0] = (svsp->tefuse[0] >> 17) & GENMASK(8, 0); + o_vtsmcu[1] = (svsp->tefuse[0] >> 8) & GENMASK(8, 0); + o_vtsmcu[2] = svsp->tefuse[1] & GENMASK(8, 0); + o_vtsmcu[3] = (svsp->tefuse[2] >> 23) & GENMASK(8, 0); + o_vtsmcu[4] = (svsp->tefuse[2] >> 5) & GENMASK(8, 0); + o_vtsabb = (svsp->tefuse[2] >> 14) & GENMASK(8, 0); + + degc_cali = (svsp->tefuse[0] >> 1) & GENMASK(5, 0); + adc_cali_en_t = svsp->tefuse[0] & BIT(0); + 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; + } + } else { + dev_err(svsp->dev, "no thermal efuse, no mon mode\n"); + goto remove_mt8183_svsb_mon_mode; + } + + ge = ((adc_ge_t - 512) * 10000) / 4096; + oe = (adc_oe_t - 512); + gain = (10000 + ge); + + format[0] = (o_vtsmcu[0] + 3350 - oe); + format[1] = (o_vtsmcu[1] + 3350 - oe); + format[2] = (o_vtsmcu[2] + 3350 - oe); + format[3] = (o_vtsmcu[3] + 3350 - oe); + format[4] = (o_vtsmcu[4] + 3350 - oe); + format[5] = (o_vtsabb + 3350 - oe); + + for (i = 0; i < 6; i++) + 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); + + for (idx = 0; idx < svsp->bank_max; idx++) { + svsb = &svsp->banks[idx]; + svsb->mts = mts; + + switch (svsb->sw_id) { + case SVSB_CPU_LITTLE: + tb_roomt = x_roomt[3]; + break; + case SVSB_CPU_BIG: + tb_roomt = x_roomt[4]; + break; + case SVSB_CCI: + tb_roomt = x_roomt[3]; + break; + case SVSB_GPU: + tb_roomt = x_roomt[1]; + break; + default: + dev_err(svsb->dev, "unknown sw_id: %u\n", svsb->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); + + svsb->bts = (temp0 + temp2 - 250) * 4 / 10; + } + + return true; + +remove_mt8183_svsb_mon_mode: + for (idx = 0; idx < svsp->bank_max; idx++) { + svsb = &svsp->banks[idx]; + svsb->mode_support &= ~SVSB_MODE_MON; + } + return true; } @@ -1152,9 +1382,14 @@ static struct device *svs_add_device_link(struct svs_platform *svsp, static int svs_mt8183_platform_probe(struct svs_platform *svsp) { + struct device *dev; struct svs_bank *svsb; u32 idx; + dev = svs_add_device_link(svsp, "thermal"); + if (IS_ERR(dev)) + return PTR_ERR(dev); + for (idx = 0; idx < svsp->bank_max; idx++) { svsb = &svsp->banks[idx]; @@ -1261,9 +1496,11 @@ static struct svs_bank svs_mt8183_banks[] = { .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, + .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02 | + SVSB_MODE_MON, .opp_count = MAX_OPP_ENTRIES, .freq_base = 900000000, .vboot = 0x30, @@ -1279,6 +1516,10 @@ static struct svs_bank svs_mt8183_banks[] = { .core_sel = 0x8fff0003, .int_st = BIT(3), .ctl0 = 0x00050001, + .tzone_htemp = 85000, + .tzone_htemp_voffset = 0, + .tzone_ltemp = 25000, + .tzone_ltemp_voffset = 3, }, }; From patchwork Thu Jan 27 03:39:55 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roger Lu X-Patchwork-Id: 537213 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7F088C43217 for ; Thu, 27 Jan 2022 03:40:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235868AbiA0DkG (ORCPT ); Wed, 26 Jan 2022 22:40:06 -0500 Received: from mailgw02.mediatek.com ([210.61.82.184]:33744 "EHLO mailgw02.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S232316AbiA0DkF (ORCPT ); Wed, 26 Jan 2022 22:40:05 -0500 X-UUID: 25a78d0bb97a46f7aef4ef04436dc8ac-20220127 X-UUID: 25a78d0bb97a46f7aef4ef04436dc8ac-20220127 Received: from mtkexhb02.mediatek.inc [(172.21.101.103)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 434976178; Thu, 27 Jan 2022 11:40:00 +0800 Received: from mtkexhb01.mediatek.inc (172.21.101.102) by mtkmbs07n1.mediatek.inc (172.21.101.16) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Thu, 27 Jan 2022 11:39:59 +0800 Received: from mtkcas11.mediatek.inc (172.21.101.40) by mtkexhb01.mediatek.inc (172.21.101.102) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Thu, 27 Jan 2022 11:39:58 +0800 Received: from mtksdaap41.mediatek.inc (172.21.77.4) by mtkcas11.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Thu, 27 Jan 2022 11:39:58 +0800 From: Roger Lu To: Matthias Brugger , Enric Balletbo Serra , Kevin Hilman , Rob Herring , Nicolas Boichat , Stephen Boyd , Philipp Zabel CC: Fan Chen , HenryC Chen , Xiaoqing Liu , Charles Yang , Angus Lin , Mark Rutland , Nishanth Menon , Roger Lu , , , , , , , Guenter Roeck Subject: [PATCH v22 6/7] dt-bindings: soc: mediatek: add mt8192 svs dt-bindings Date: Thu, 27 Jan 2022 11:39:55 +0800 Message-ID: <20220127033956.24585-7-roger.lu@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20220127033956.24585-1-roger.lu@mediatek.com> References: <20220127033956.24585-1-roger.lu@mediatek.com> MIME-Version: 1.0 X-MTK: N Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Add mt8192 svs compatible/resets in dt-bindings. Signed-off-by: Roger Lu Reviewed-by: Rob Herring --- .../devicetree/bindings/soc/mediatek/mtk-svs.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/mediatek/mtk-svs.yaml b/Documentation/devicetree/bindings/soc/mediatek/mtk-svs.yaml index dfd275f4973c..eecfec13ee8b 100644 --- a/Documentation/devicetree/bindings/soc/mediatek/mtk-svs.yaml +++ b/Documentation/devicetree/bindings/soc/mediatek/mtk-svs.yaml @@ -22,6 +22,7 @@ properties: compatible: enum: - mediatek,mt8183-svs + - mediatek,mt8192-svs reg: maxItems: 1 @@ -50,6 +51,13 @@ properties: - const: svs-calibration-data - const: t-calibration-data + resets: + maxItems: 1 + + reset-names: + items: + - const: svs_rst + required: - compatible - reg From patchwork Thu Jan 27 03:39:56 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roger Lu X-Patchwork-Id: 537214 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 89F79C433FE for ; Thu, 27 Jan 2022 03:40:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235855AbiA0DkF (ORCPT ); Wed, 26 Jan 2022 22:40:05 -0500 Received: from mailgw01.mediatek.com ([60.244.123.138]:33246 "EHLO mailgw01.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S235806AbiA0DkE (ORCPT ); Wed, 26 Jan 2022 22:40:04 -0500 X-UUID: 584a751d501b49bd99f548a29bc77362-20220127 X-UUID: 584a751d501b49bd99f548a29bc77362-20220127 Received: from mtkmbs10n1.mediatek.inc [(172.21.101.34)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1768313893; Thu, 27 Jan 2022 11:40:00 +0800 Received: from mtkexhb02.mediatek.inc (172.21.101.103) by mtkmbs10n1.mediatek.inc (172.21.101.34) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.2.792.15; Thu, 27 Jan 2022 11:39:59 +0800 Received: from mtkcas11.mediatek.inc (172.21.101.40) by mtkexhb02.mediatek.inc (172.21.101.103) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Thu, 27 Jan 2022 11:39:58 +0800 Received: from mtksdaap41.mediatek.inc (172.21.77.4) by mtkcas11.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Thu, 27 Jan 2022 11:39:58 +0800 From: Roger Lu To: Matthias Brugger , Enric Balletbo Serra , Kevin Hilman , Rob Herring , Nicolas Boichat , Stephen Boyd , Philipp Zabel CC: Fan Chen , HenryC Chen , Xiaoqing Liu , Charles Yang , Angus Lin , Mark Rutland , Nishanth Menon , Roger Lu , , , , , , , Guenter Roeck Subject: [PATCH v22 7/7] soc: mediatek: SVS: add mt8192 SVS GPU driver Date: Thu, 27 Jan 2022 11:39:56 +0800 Message-ID: <20220127033956.24585-8-roger.lu@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20220127033956.24585-1-roger.lu@mediatek.com> References: <20220127033956.24585-1-roger.lu@mediatek.com> MIME-Version: 1.0 X-MTK: N Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org mt8192 SVS GPU uses 2-line (high/low bank) HW architecture to provide bank voltages. High bank helps update higher frequency's voltage and low bank helps update lower frequency's voltage. Signed-off-by: Roger Lu --- drivers/soc/mediatek/mtk-svs.c | 471 ++++++++++++++++++++++++++++++++- 1 file changed, 466 insertions(+), 5 deletions(-) diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c index d3977de56335..54af3b4b90a9 100644 --- a/drivers/soc/mediatek/mtk-svs.c +++ b/drivers/soc/mediatek/mtk-svs.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,10 @@ #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) @@ -45,6 +50,8 @@ #define SVSB_INIT01_PD_REQ BIT(0) #define SVSB_INIT01_VOLT_IGNORE BIT(1) #define SVSB_INIT01_VOLT_INC_ONLY BIT(2) +#define SVSB_MON_VOLT_IGNORE BIT(16) +#define SVSB_REMOVE_DVTFIXED_VOLT BIT(24) /* svs bank register common configuration */ #define SVSB_DET_MAX 0xffff @@ -63,7 +70,9 @@ #define SVSB_RUNCONFIG_DEFAULT 0x80000000 /* svs bank related setting */ +#define BITS8 8 #define MAX_OPP_ENTRIES 16 +#define REG_BYTES 4 #define SVSB_DC_SIGNED_BIT BIT(15) #define SVSB_DET_CLK_EN BIT(31) #define SVSB_TEMP_LOWER_BOUND 0xb2 @@ -250,6 +259,7 @@ static const u32 svs_regs_v2[] = { * @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 * @irqflags: svs platform irq settings flags @@ -267,6 +277,7 @@ struct svs_platform { 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); unsigned long irqflags; @@ -309,6 +320,7 @@ struct svs_platform_data { * @pm_runtime_enabled_count: bank pm runtime enabled count * @mode_support: bank mode support. * @freq_base: reference frequency for bank init + * @turn_freq_base: refenrece frequency for turn point * @vboot: voltage request for bank init01 only * @opp_dfreq: default opp frequency table * @opp_dvolt: default opp voltage table @@ -344,6 +356,8 @@ struct svs_platform_data { * @mtdes: svs efuse 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 * * Svs bank will generate suitalbe voltages by below general math equation * and provide these voltages to opp voltage table. @@ -370,6 +384,7 @@ struct svs_bank { u32 pm_runtime_enabled_count; u32 mode_support; u32 freq_base; + u32 turn_freq_base; u32 vboot; u32 opp_dfreq[MAX_OPP_ENTRIES]; u32 opp_dvolt[MAX_OPP_ENTRIES]; @@ -405,6 +420,8 @@ struct svs_bank { u32 mtdes; u32 dcbdet; u32 dcmdet; + u32 turn_pt; + u32 type; }; static u32 percent(u32 numerator, u32 denominator) @@ -440,13 +457,59 @@ static u32 svs_bank_volt_to_opp_volt(u32 svsb_volt, u32 svsb_volt_step, return (svsb_volt * svsb_volt_step) + svsb_volt_base; } +static u32 svs_opp_volt_to_bank_volt(u32 opp_u_volt, u32 svsb_volt_step, + u32 svsb_volt_base) +{ + return (opp_u_volt - svsb_volt_base) / svsb_volt_step; +} + +static int svs_sync_bank_volts_from_opp(struct svs_bank *svsb) +{ + struct dev_pm_opp *opp; + u32 i, opp_u_volt; + + for (i = 0; i < svsb->opp_count; i++) { + opp = dev_pm_opp_find_freq_exact(svsb->opp_dev, + svsb->opp_dfreq[i], + true); + if (IS_ERR(opp)) { + dev_err(svsb->dev, "cannot find freq = %u (%ld)\n", + svsb->opp_dfreq[i], PTR_ERR(opp)); + return PTR_ERR(opp); + } + + 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); + dev_pm_opp_put(opp); + } + + return 0; +} + static int svs_adjust_pm_opp_volts(struct svs_bank *svsb) { int ret = -EPERM, tzone_temp = 0; - u32 i, svsb_volt, opp_volt, temp_voffset = 0; + u32 i, svsb_volt, opp_volt, temp_voffset = 0, opp_start, opp_stop; mutex_lock(&svsb->lock); + /* + * 2-line bank updates its corresponding opp volts. + * 1-line bank updates all opp volts. + */ + if (svsb->type == SVSB_HIGH) { + opp_start = 0; + opp_stop = svsb->turn_pt; + } else if (svsb->type == SVSB_LOW) { + opp_start = svsb->turn_pt; + opp_stop = svsb->opp_count; + } else { + opp_start = 0; + opp_stop = svsb->opp_count; + } + /* Get thermal effect */ if (svsb->phase == SVSB_PHASE_MON) { ret = thermal_zone_get_temp(svsb->tzd, &tzone_temp); @@ -461,10 +524,16 @@ static int svs_adjust_pm_opp_volts(struct svs_bank *svsb) temp_voffset += svsb->tzone_htemp_voffset; else if (tzone_temp <= svsb->tzone_ltemp) temp_voffset += svsb->tzone_ltemp_voffset; + + /* 2-line bank update all opp volts when running mon mode */ + if (svsb->type == SVSB_HIGH || svsb->type == SVSB_LOW) { + opp_start = 0; + opp_stop = svsb->opp_count; + } } /* vmin <= svsb_volt (opp_volt) <= default opp voltage */ - for (i = 0; i < svsb->opp_count; i++) { + for (i = opp_start; i < opp_stop; i++) { switch (svsb->phase) { case SVSB_PHASE_ERROR: opp_volt = svsb->opp_dvolt[i]; @@ -629,9 +698,11 @@ 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\n", svsb->name); + seq_printf(m, "%s: temperature ignore, turn_pt = %u\n", + svsb->name, svsb->turn_pt); else - seq_printf(m, "%s: temperature = %d\n", svsb->name, tzone_temp); + seq_printf(m, "%s: temperature = %d, turn_pt = %u\n", + svsb->name, tzone_temp, svsb->turn_pt); for (i = 0; i < svsb->opp_count; i++) { opp = dev_pm_opp_find_freq_exact(svsb->opp_dev, @@ -774,6 +845,181 @@ 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) +{ + struct svs_bank *svsb = svsp->pbank; + 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); + + if (svsb->phase == SVSB_PHASE_MON && + svsb->volt_flags & SVSB_MON_VOLT_IGNORE) + return; + + vop74 = svs_readl_relaxed(svsp, VOP74); + vop30 = svs_readl_relaxed(svsp, VOP30); + + /* Target is to set svsb->volt[] by algorithm */ + if (turn_pt < middle_index) { + if (svsb->type == SVSB_HIGH) { + /* volt[0] ~ volt[turn_pt - 1] */ + for (i = 0; i < turn_pt; i++) { + b_sft = BITS8 * (shift_byte % REG_BYTES); + vop = (shift_byte < REG_BYTES) ? &vop30 : + &vop74; + svsb->volt[i] = (*vop >> b_sft) & GENMASK(7, 0); + shift_byte++; + } + } else if (svsb->type == SVSB_LOW) { + /* volt[turn_pt] + volt[j] ~ volt[opp_count - 1] */ + j = svsb->opp_count - 7; + svsb->volt[turn_pt] = vop30 & GENMASK(7, 0); + shift_byte++; + for (i = j; i < svsb->opp_count; i++) { + b_sft = BITS8 * (shift_byte % REG_BYTES); + vop = (shift_byte < REG_BYTES) ? &vop30 : + &vop74; + svsb->volt[i] = (*vop >> b_sft) & GENMASK(7, 0); + shift_byte++; + } + + /* volt[turn_pt + 1] ~ volt[j - 1] by interpolate */ + for (i = turn_pt + 1; i < j; i++) + svsb->volt[i] = interpolate(svsb->freq_pct[turn_pt], + svsb->freq_pct[j], + svsb->volt[turn_pt], + svsb->volt[j], + svsb->freq_pct[i]); + } + } else { + if (svsb->type == SVSB_HIGH) { + /* volt[0] + volt[j] ~ volt[turn_pt - 1] */ + j = turn_pt - 7; + svsb->volt[0] = vop30 & GENMASK(7, 0); + shift_byte++; + for (i = j; i < turn_pt; i++) { + b_sft = BITS8 * (shift_byte % REG_BYTES); + vop = (shift_byte < REG_BYTES) ? &vop30 : + &vop74; + svsb->volt[i] = (*vop >> b_sft) & GENMASK(7, 0); + shift_byte++; + } + + /* volt[1] ~ volt[j - 1] by interpolate */ + for (i = 1; i < j; i++) + svsb->volt[i] = interpolate(svsb->freq_pct[0], + svsb->freq_pct[j], + svsb->volt[0], + svsb->volt[j], + svsb->freq_pct[i]); + } else if (svsb->type == SVSB_LOW) { + /* volt[turn_pt] ~ volt[opp_count - 1] */ + for (i = turn_pt; i < svsb->opp_count; i++) { + b_sft = BITS8 * (shift_byte % REG_BYTES); + vop = (shift_byte < REG_BYTES) ? &vop30 : + &vop74; + svsb->volt[i] = (*vop >> b_sft) & GENMASK(7, 0); + shift_byte++; + } + } + } + + if (svsb->type == SVSB_HIGH) { + opp_start = 0; + opp_stop = svsb->turn_pt; + } else if (svsb->type == SVSB_LOW) { + opp_start = svsb->turn_pt; + opp_stop = svsb->opp_count; + } + + for (i = opp_start; i < opp_stop; i++) + if (svsb->volt_flags & SVSB_REMOVE_DVTFIXED_VOLT) + svsb->volt[i] -= svsb->dvt_fixed; +} + +static void svs_set_bank_freq_pct_v3(struct svs_platform *svsp) +{ + struct svs_bank *svsb = svsp->pbank; + 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); + + for (i = 0; i < svsb->opp_count; i++) { + if (svsb->opp_dfreq[i] <= svsb->turn_freq_base) { + svsb->turn_pt = i; + break; + } + } + + turn_pt = svsb->turn_pt; + + /* Target is to fill out freq_pct74 / freq_pct30 by algorithm */ + if (turn_pt < middle_index) { + if (svsb->type == SVSB_HIGH) { + /* + * If we don't handle this situation, + * SVSB_HIGH's FREQPCT74 / FREQPCT30 would keep "0" + * and this leads SVSB_LOW to work abnormally. + */ + if (turn_pt == 0) + freq_pct30 = svsb->freq_pct[0]; + + /* freq_pct[0] ~ freq_pct[turn_pt - 1] */ + for (i = 0; i < turn_pt; i++) { + b_sft = BITS8 * (shift_byte % REG_BYTES); + freq_pct = (shift_byte < REG_BYTES) ? + &freq_pct30 : &freq_pct74; + *freq_pct |= (svsb->freq_pct[i] << b_sft); + shift_byte++; + } + } else if (svsb->type == SVSB_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++) { + b_sft = BITS8 * (shift_byte % REG_BYTES); + freq_pct = (shift_byte < REG_BYTES) ? + &freq_pct30 : &freq_pct74; + *freq_pct |= (svsb->freq_pct[i] << b_sft); + shift_byte++; + } + } + } else { + if (svsb->type == SVSB_HIGH) { + /* + * freq_pct[0] + + * freq_pct[turn_pt - 7] ~ freq_pct[turn_pt - 1] + */ + freq_pct30 = svsb->freq_pct[0]; + shift_byte++; + j = turn_pt - 7; + for (i = j; i < turn_pt; i++) { + b_sft = BITS8 * (shift_byte % REG_BYTES); + freq_pct = (shift_byte < REG_BYTES) ? + &freq_pct30 : &freq_pct74; + *freq_pct |= (svsb->freq_pct[i] << b_sft); + shift_byte++; + } + } else if (svsb->type == SVSB_LOW) { + /* freq_pct[turn_pt] ~ freq_pct[opp_count - 1] */ + for (i = turn_pt; i < svsb->opp_count; i++) { + b_sft = BITS8 * (shift_byte % REG_BYTES); + freq_pct = (shift_byte < REG_BYTES) ? + &freq_pct30 : &freq_pct74; + *freq_pct |= (svsb->freq_pct[i] << b_sft); + shift_byte++; + } + } + } + + svs_writel_relaxed(svsp, freq_pct74, FREQPCT74); + svs_writel_relaxed(svsp, freq_pct30, FREQPCT30); +} + static void svs_get_bank_volts_v2(struct svs_platform *svsp) { struct svs_bank *svsb = svsp->pbank; @@ -1223,6 +1469,25 @@ static int svs_init02(struct svs_platform *svsp) } } + /* + * 2-line high/low bank update its corresponding opp voltages only. + * Therefore, we sync voltages from opp for high/low bank voltages + * consistency. + */ + for (idx = 0; idx < svsp->bank_max; idx++) { + svsb = &svsp->banks[idx]; + + if (!(svsb->mode_support & SVSB_MODE_INIT02)) + continue; + + if (svsb->type == SVSB_HIGH || svsb->type == SVSB_LOW) { + if (svs_sync_bank_volts_from_opp(svsb)) { + dev_err(svsb->dev, "sync volt fail\n"); + return -EPERM; + } + } + } + return 0; } @@ -1267,6 +1532,7 @@ 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++) { @@ -1284,6 +1550,12 @@ static int svs_suspend(struct device *dev) svs_adjust_pm_opp_volts(svsb); } + ret = reset_control_assert(svsp->rst); + if (ret) { + dev_err(svsp->dev, "cannot assert reset %d\n", ret); + return ret; + } + clk_disable_unprepare(svsp->main_clk); return 0; @@ -1300,6 +1572,12 @@ static int svs_resume(struct device *dev) return ret; } + ret = reset_control_deassert(svsp->rst); + if (ret) { + dev_err(svsp->dev, "cannot deassert reset %d\n", ret); + return ret; + } + ret = svs_init02(svsp); if (ret) return ret; @@ -1333,7 +1611,12 @@ static int svs_bank_resource_setup(struct svs_platform *svsp) svsb->name = "SVSB_CCI"; break; case SVSB_GPU: - svsb->name = "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); @@ -1406,6 +1689,84 @@ static int svs_bank_resource_setup(struct svs_platform *svsp) return 0; } +static bool svs_mt8192_efuse_parsing(struct svs_platform *svsp) +{ + struct svs_bank *svsb; + struct nvmem_cell *cell; + u32 idx, i, vmin, golden_temp; + + 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]); + + if (!svsp->efuse[9]) { + dev_notice(svsp->dev, "svs_efuse[9] = 0x0?\n"); + return false; + } + + /* Svs efuse parsing */ + vmin = (svsp->efuse[19] >> 4) & GENMASK(1, 0); + + for (idx = 0; idx < svsp->bank_max; idx++) { + svsb = &svsp->banks[idx]; + + if (vmin == 0x1) + svsb->vmin = 0x1e; + + 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); + } + + svsb->vmax += svsb->dvt_fixed; + } + + /* 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)); + return false; + } + + 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)); + return false; + } + + svsp->tefuse_max /= sizeof(u32); + nvmem_cell_put(cell); + + for (i = 0; i < svsp->tefuse_max; i++) + if (svsp->tefuse[i] != 0) + break; + + if (i == svsp->tefuse_max) + golden_temp = 50; /* All thermal efuse data are 0 */ + else + golden_temp = (svsp->tefuse[0] >> 24) & GENMASK(7, 0); + + for (idx = 0; idx < svsp->bank_max; idx++) { + svsb = &svsp->banks[idx]; + svsb->mts = 500; + svsb->bts = (((500 * golden_temp + 250460) / 1000) - 25) * 4; + } + + return true; +} + static bool svs_mt8183_efuse_parsing(struct svs_platform *svsp) { struct svs_bank *svsb; @@ -1689,6 +2050,38 @@ static struct device *svs_add_device_link(struct svs_platform *svsp, return dev; } +static int svs_mt8192_platform_probe(struct svs_platform *svsp) +{ + struct device *dev; + struct svs_bank *svsb; + u32 idx; + + svsp->rst = devm_reset_control_get_optional(svsp->dev, "svs_rst"); + if (IS_ERR(svsp->rst)) { + dev_err_probe(svsp->dev, PTR_ERR(svsp->rst), + "cannot get svs reset control\n"); + return PTR_ERR(svsp->rst); + } + + dev = svs_add_device_link(svsp, "lvts"); + if (IS_ERR(dev)) + return PTR_ERR(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"); + + if (IS_ERR(svsb->opp_dev)) + return PTR_ERR(svsb->opp_dev); + } + + return 0; +} + static int svs_mt8183_platform_probe(struct svs_platform *svsp) { struct device *dev; @@ -1728,6 +2121,61 @@ static int svs_mt8183_platform_probe(struct svs_platform *svsp) return 0; } +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, + }, + { + .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, + }, +}; + static struct svs_bank svs_mt8183_banks[] = { { .sw_id = SVSB_CPU_LITTLE, @@ -1832,6 +2280,16 @@ static struct svs_bank svs_mt8183_banks[] = { }, }; +static const struct svs_platform_data svs_mt8192_platform_data = { + .name = "mt8192-svs", + .banks = svs_mt8192_banks, + .efuse_parsing = svs_mt8192_efuse_parsing, + .probe = svs_mt8192_platform_probe, + .irqflags = IRQF_TRIGGER_HIGH, + .regs = svs_regs_v2, + .bank_max = ARRAY_SIZE(svs_mt8192_banks), +}; + static const struct svs_platform_data svs_mt8183_platform_data = { .name = "mt8183-svs", .banks = svs_mt8183_banks, @@ -1844,6 +2302,9 @@ static const struct svs_platform_data svs_mt8183_platform_data = { 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, }, {