Loading drivers/thermal/tegra/soctherm.c +204 −30 Original line number Diff line number Diff line Loading @@ -136,6 +136,21 @@ #define CAR_SUPER_CCLKG_DIVIDER 0x36c #define CDIVG_USE_THERM_CONTROLS_MASK BIT(30) /* ccroc register offsets needed for enabling HW throttling for Tegra132 */ #define CCROC_SUPER_CCLKG_DIVIDER 0x024 #define CCROC_GLOBAL_CFG 0x148 #define CCROC_THROT_PSKIP_RAMP_CPU 0x150 #define CCROC_THROT_PSKIP_RAMP_SEQ_BYPASS_MODE_MASK BIT(31) #define CCROC_THROT_PSKIP_RAMP_DURATION_MASK (0xffff << 8) #define CCROC_THROT_PSKIP_RAMP_STEP_MASK 0xff #define CCROC_THROT_PSKIP_CTRL_CPU 0x154 #define CCROC_THROT_PSKIP_CTRL_ENB_MASK BIT(31) #define CCROC_THROT_PSKIP_CTRL_DIVIDEND_MASK (0xff << 8) #define CCROC_THROT_PSKIP_CTRL_DIVISOR_MASK 0xff /* get val from register(r) mask bits(m) */ #define REG_GET_MASK(r, m) (((r) & (m)) >> (ffs(m) - 1)) /* set val(v) to mask bits(m) of register(r) */ Loading @@ -158,6 +173,13 @@ #define THROT_DELAY_CTRL(throt) (THROT_DELAY_LITE + \ (THROT_OFFSET * throt)) /* get CCROC_THROT_PSKIP_xxx offset per HIGH/MED/LOW vect*/ #define CCROC_THROT_OFFSET 0x0c #define CCROC_THROT_PSKIP_CTRL_CPU_REG(vect) (CCROC_THROT_PSKIP_CTRL_CPU + \ (CCROC_THROT_OFFSET * vect)) #define CCROC_THROT_PSKIP_RAMP_CPU_REG(vect) (CCROC_THROT_PSKIP_RAMP_CPU + \ (CCROC_THROT_OFFSET * vect)) /* get THERMCTL_LEVELx offset per CPU/GPU/MEM/TSENSE rg and LEVEL0~3 lv */ #define THERMCTL_LVL_REGS_SIZE 0x20 #define THERMCTL_LVL_REG(rg, lv) ((rg) + ((lv) * THERMCTL_LVL_REGS_SIZE)) Loading Loading @@ -195,6 +217,7 @@ struct soctherm_throt_cfg { const char *name; unsigned int id; u8 priority; u8 cpu_throt_level; u32 cpu_throt_depth; struct thermal_cooling_device *cdev; bool init; Loading @@ -206,6 +229,7 @@ struct tegra_soctherm { struct clk *clock_soctherm; void __iomem *regs; void __iomem *clk_regs; void __iomem *ccroc_regs; u32 *calib; struct thermal_zone_device **thermctl_tzs; Loading Loading @@ -241,6 +265,31 @@ static inline u32 clk_readl(struct tegra_soctherm *ts, u32 reg) return readl(ts->clk_regs + reg); } /** * ccroc_writel() - writes a value to a CCROC register * @ts: pointer to a struct tegra_soctherm * @v: the value to write * @reg: the register offset * * Writes @v to @reg. No return value. */ static inline void ccroc_writel(struct tegra_soctherm *ts, u32 value, u32 reg) { writel(value, (ts->ccroc_regs + reg)); } /** * ccroc_readl() - reads specified register from CCROC IP block * @ts: pointer to a struct tegra_soctherm * @reg: register address to be read * * Return: the value of the register */ static inline u32 ccroc_readl(struct tegra_soctherm *ts, u32 reg) { return readl(ts->ccroc_regs + reg); } static void enable_tsensor(struct tegra_soctherm *tegra, unsigned int i) { const struct tegra_tsensor *sensor = &tegra->soc->tsensors[i]; Loading Loading @@ -552,9 +601,6 @@ static int tegra_soctherm_set_hwtrips(struct device *dev, sg->name, temperature); set_throttle: if (ts->soc->use_ccroc) return 0; ret = get_hot_temp(tz, &trip, &temperature); if (ret) { dev_warn(dev, "throttrip: %s: missing hot temperature\n", Loading Loading @@ -676,9 +722,6 @@ static int regs_show(struct seq_file *s, void *data) state = REG_GET_MASK(r, SENSOR_TEMP2_MEM_TEMP_MASK); seq_printf(s, " MEM(%d)\n", translate_temp(state)); if (ts->soc->use_ccroc) return 0; for (i = 0; i < ts->soc->num_ttgs; i++) { seq_printf(s, "%s:\n", ttgs[i]->name); for (level = 0; level < 4; level++) { Loading Loading @@ -779,12 +822,17 @@ static int regs_show(struct seq_file *s, void *data) seq_printf(s, "enabled(%d)\n", state); r = readl(ts->regs + CPU_PSKIP_STATUS); if (ts->soc->use_ccroc) { state = REG_GET_MASK(r, XPU_PSKIP_STATUS_ENABLED_MASK); seq_printf(s, "CPU PSKIP STATUS: enabled(%d)\n", state); } else { state = REG_GET_MASK(r, XPU_PSKIP_STATUS_M_MASK); seq_printf(s, "CPU PSKIP STATUS: M(%d) ", state); state = REG_GET_MASK(r, XPU_PSKIP_STATUS_N_MASK); seq_printf(s, "N(%d) ", state); state = REG_GET_MASK(r, XPU_PSKIP_STATUS_ENABLED_MASK); seq_printf(s, "enabled(%d)\n", state); } return 0; } Loading Loading @@ -939,7 +987,20 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev) } stc->priority = val; r = of_property_read_u32(np_stcc, "nvidia,cpu-throt-percent", if (ts->soc->use_ccroc) { r = of_property_read_u32(np_stcc, "nvidia,cpu-throt-level", &val); if (r) { dev_info(dev, "throttle-cfg: %s: missing cpu-throt-level\n", name); continue; } stc->cpu_throt_level = val; } else { r = of_property_read_u32(np_stcc, "nvidia,cpu-throt-percent", &val); if (r) { dev_info(dev, Loading @@ -948,6 +1009,7 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev) continue; } stc->cpu_throt_depth = val; } tcd = thermal_of_cooling_device_register(np_stcc, (char *)name, ts, Loading @@ -967,6 +1029,96 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev) of_node_put(np_stc); } /** * throttlectl_cpu_level_cfg() - programs CCROC NV_THERM level config * @level: describing the level LOW/MED/HIGH of throttling * * It's necessary to set up the CPU-local CCROC NV_THERM instance with * the M/N values desired for each level. This function does this. * * This function pre-programs the CCROC NV_THERM levels in terms of * pre-configured "Low", "Medium" or "Heavy" throttle levels which are * mapped to THROT_LEVEL_LOW, THROT_LEVEL_MED and THROT_LEVEL_HVY. */ static void throttlectl_cpu_level_cfg(struct tegra_soctherm *ts, int level) { u8 depth, dividend; u32 r; switch (level) { case TEGRA_SOCTHERM_THROT_LEVEL_LOW: depth = 50; break; case TEGRA_SOCTHERM_THROT_LEVEL_MED: depth = 75; break; case TEGRA_SOCTHERM_THROT_LEVEL_HIGH: depth = 80; break; case TEGRA_SOCTHERM_THROT_LEVEL_NONE: return; default: return; } dividend = THROT_DEPTH_DIVIDEND(depth); /* setup PSKIP in ccroc nv_therm registers */ r = ccroc_readl(ts, CCROC_THROT_PSKIP_RAMP_CPU_REG(level)); r = REG_SET_MASK(r, CCROC_THROT_PSKIP_RAMP_DURATION_MASK, 0xff); r = REG_SET_MASK(r, CCROC_THROT_PSKIP_RAMP_STEP_MASK, 0xf); ccroc_writel(ts, r, CCROC_THROT_PSKIP_RAMP_CPU_REG(level)); r = ccroc_readl(ts, CCROC_THROT_PSKIP_CTRL_CPU_REG(level)); r = REG_SET_MASK(r, CCROC_THROT_PSKIP_CTRL_ENB_MASK, 1); r = REG_SET_MASK(r, CCROC_THROT_PSKIP_CTRL_DIVIDEND_MASK, dividend); r = REG_SET_MASK(r, CCROC_THROT_PSKIP_CTRL_DIVISOR_MASK, 0xff); ccroc_writel(ts, r, CCROC_THROT_PSKIP_CTRL_CPU_REG(level)); } /** * throttlectl_cpu_level_select() - program CPU pulse skipper config * @throt: the LIGHT/HEAVY of throttle event id * * Pulse skippers are used to throttle clock frequencies. This * function programs the pulse skippers based on @throt and platform * data. This function is used on SoCs which have CPU-local pulse * skipper control, such as T13x. It programs soctherm's interface to * Denver:CCROC NV_THERM in terms of Low, Medium and HIGH throttling * vectors. PSKIP_BYPASS mode is set as required per HW spec. */ static void throttlectl_cpu_level_select(struct tegra_soctherm *ts, enum soctherm_throttle_id throt) { u32 r, throt_vect; /* Denver:CCROC NV_THERM interface N:3 Mapping */ switch (ts->throt_cfgs[throt].cpu_throt_level) { case TEGRA_SOCTHERM_THROT_LEVEL_LOW: throt_vect = THROT_VECT_LOW; break; case TEGRA_SOCTHERM_THROT_LEVEL_MED: throt_vect = THROT_VECT_MED; break; case TEGRA_SOCTHERM_THROT_LEVEL_HIGH: throt_vect = THROT_VECT_HIGH; break; default: throt_vect = THROT_VECT_NONE; break; } r = readl(ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_CPU)); r = REG_SET_MASK(r, THROT_PSKIP_CTRL_ENABLE_MASK, 1); r = REG_SET_MASK(r, THROT_PSKIP_CTRL_VECT_CPU_MASK, throt_vect); r = REG_SET_MASK(r, THROT_PSKIP_CTRL_VECT2_CPU_MASK, throt_vect); writel(r, ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_CPU)); /* bypass sequencer in soc_therm as it is programmed in ccroc */ r = REG_SET_MASK(0, THROT_PSKIP_RAMP_SEQ_BYPASS_MODE_MASK, 1); writel(r, ts->regs + THROT_PSKIP_RAMP(throt, THROTTLE_DEV_CPU)); } /** * throttlectl_cpu_mn() - program CPU pulse skipper configuration * @throt: the LIGHT/HEAVY of throttle event id Loading Loading @@ -1017,6 +1169,9 @@ static void soctherm_throttle_program(struct tegra_soctherm *ts, return; /* Setup PSKIP parameters */ if (ts->soc->use_ccroc) throttlectl_cpu_level_select(ts, throt); else throttlectl_cpu_mn(ts, throt); r = REG_SET_MASK(0, THROT_PRIORITY_LITE_PRIO_MASK, stc.priority); Loading @@ -1040,16 +1195,31 @@ static void tegra_soctherm_throttle(struct device *dev) u32 v; int i; /* configure LOW, MED and HIGH levels for CCROC NV_THERM */ if (ts->soc->use_ccroc) { throttlectl_cpu_level_cfg(ts, TEGRA_SOCTHERM_THROT_LEVEL_LOW); throttlectl_cpu_level_cfg(ts, TEGRA_SOCTHERM_THROT_LEVEL_MED); throttlectl_cpu_level_cfg(ts, TEGRA_SOCTHERM_THROT_LEVEL_HIGH); } /* Thermal HW throttle programming */ for (i = 0; i < THROTTLE_SIZE; i++) soctherm_throttle_program(ts, i); v = REG_SET_MASK(0, THROT_GLOBAL_ENB_MASK, 1); if (ts->soc->use_ccroc) { ccroc_writel(ts, v, CCROC_GLOBAL_CFG); v = ccroc_readl(ts, CCROC_SUPER_CCLKG_DIVIDER); v = REG_SET_MASK(v, CDIVG_USE_THERM_CONTROLS_MASK, 1); ccroc_writel(ts, v, CCROC_SUPER_CCLKG_DIVIDER); } else { writel(v, ts->regs + THROT_GLOBAL_CFG); v = clk_readl(ts, CAR_SUPER_CCLKG_DIVIDER); v = REG_SET_MASK(v, CDIVG_USE_THERM_CONTROLS_MASK, 1); clk_writel(ts, v, CAR_SUPER_CCLKG_DIVIDER); } /* initialize stats collection */ v = STATS_CTL_CLR_DN | STATS_CTL_EN_DN | Loading Loading @@ -1084,9 +1254,6 @@ static void soctherm_init(struct platform_device *pdev) writel(pdiv, tegra->regs + SENSOR_PDIV); writel(hotspot, tegra->regs + SENSOR_HOTSPOT_OFF); if (tegra->soc->use_ccroc) return; /* Configure hw throttle */ tegra_soctherm_throttle(&pdev->dev); } Loading Loading @@ -1157,6 +1324,14 @@ static int tegra_soctherm_probe(struct platform_device *pdev) dev_err(&pdev->dev, "can't get car clk registers"); return PTR_ERR(tegra->clk_regs); } } else { res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ccroc-reg"); tegra->ccroc_regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(tegra->ccroc_regs)) { dev_err(&pdev->dev, "can't get ccroc registers"); return PTR_ERR(tegra->ccroc_regs); } } tegra->reset = devm_reset_control_get(&pdev->dev, "soctherm"); Loading Loading @@ -1207,7 +1382,6 @@ static int tegra_soctherm_probe(struct platform_device *pdev) if (err) return err; if (!tegra->soc->use_ccroc) soctherm_init_hw_throt_cdev(pdev); soctherm_init(pdev); Loading drivers/thermal/tegra/tegra132-soctherm.c +17 −0 Original line number Diff line number Diff line Loading @@ -28,7 +28,11 @@ #define TEGRA132_THERMTRIP_CPU_THRESH_MASK (0xff << 8) #define TEGRA132_THERMTRIP_TSENSE_THRESH_MASK 0xff #define TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK (0xff << 17) #define TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK (0xff << 9) #define TEGRA132_THRESH_GRAIN 1000 #define TEGRA132_BPTT 8 static const struct tegra_tsensor_configuration tegra132_tsensor_config = { .tall = 16300, Loading @@ -51,6 +55,9 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_cpu = { .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA132_THERMTRIP_CPU_EN_MASK, .thermtrip_threshold_mask = TEGRA132_THERMTRIP_CPU_THRESH_MASK, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_CPU, .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK, }; static const struct tegra_tsensor_group tegra132_tsensor_group_gpu = { Loading @@ -66,6 +73,9 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_gpu = { .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA132_THERMTRIP_GPU_EN_MASK, .thermtrip_threshold_mask = TEGRA132_THERMTRIP_GPUMEM_THRESH_MASK, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_GPU, .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK, }; static const struct tegra_tsensor_group tegra132_tsensor_group_pll = { Loading @@ -79,6 +89,9 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_pll = { .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA132_THERMTRIP_TSENSE_EN_MASK, .thermtrip_threshold_mask = TEGRA132_THERMTRIP_TSENSE_THRESH_MASK, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_TSENSE, .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK, }; static const struct tegra_tsensor_group tegra132_tsensor_group_mem = { Loading @@ -94,6 +107,9 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_mem = { .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA132_THERMTRIP_MEM_EN_MASK, .thermtrip_threshold_mask = TEGRA132_THERMTRIP_GPUMEM_THRESH_MASK, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_MEM, .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK, }; static const struct tegra_tsensor_group *tegra132_tsensor_groups[] = { Loading Loading @@ -193,5 +209,6 @@ const struct tegra_soctherm_soc tegra132_soctherm = { .num_ttgs = ARRAY_SIZE(tegra132_tsensor_groups), .tfuse = &tegra132_soctherm_fuse, .thresh_grain = TEGRA132_THRESH_GRAIN, .bptt = TEGRA132_BPTT, .use_ccroc = true, }; include/dt-bindings/thermal/tegra124-soctherm.h +5 −0 Original line number Diff line number Diff line Loading @@ -11,4 +11,9 @@ #define TEGRA124_SOCTHERM_SENSOR_PLLX 3 #define TEGRA124_SOCTHERM_SENSOR_NUM 4 #define TEGRA_SOCTHERM_THROT_LEVEL_LOW 0 #define TEGRA_SOCTHERM_THROT_LEVEL_MED 1 #define TEGRA_SOCTHERM_THROT_LEVEL_HIGH 2 #define TEGRA_SOCTHERM_THROT_LEVEL_NONE -1 #endif Loading
drivers/thermal/tegra/soctherm.c +204 −30 Original line number Diff line number Diff line Loading @@ -136,6 +136,21 @@ #define CAR_SUPER_CCLKG_DIVIDER 0x36c #define CDIVG_USE_THERM_CONTROLS_MASK BIT(30) /* ccroc register offsets needed for enabling HW throttling for Tegra132 */ #define CCROC_SUPER_CCLKG_DIVIDER 0x024 #define CCROC_GLOBAL_CFG 0x148 #define CCROC_THROT_PSKIP_RAMP_CPU 0x150 #define CCROC_THROT_PSKIP_RAMP_SEQ_BYPASS_MODE_MASK BIT(31) #define CCROC_THROT_PSKIP_RAMP_DURATION_MASK (0xffff << 8) #define CCROC_THROT_PSKIP_RAMP_STEP_MASK 0xff #define CCROC_THROT_PSKIP_CTRL_CPU 0x154 #define CCROC_THROT_PSKIP_CTRL_ENB_MASK BIT(31) #define CCROC_THROT_PSKIP_CTRL_DIVIDEND_MASK (0xff << 8) #define CCROC_THROT_PSKIP_CTRL_DIVISOR_MASK 0xff /* get val from register(r) mask bits(m) */ #define REG_GET_MASK(r, m) (((r) & (m)) >> (ffs(m) - 1)) /* set val(v) to mask bits(m) of register(r) */ Loading @@ -158,6 +173,13 @@ #define THROT_DELAY_CTRL(throt) (THROT_DELAY_LITE + \ (THROT_OFFSET * throt)) /* get CCROC_THROT_PSKIP_xxx offset per HIGH/MED/LOW vect*/ #define CCROC_THROT_OFFSET 0x0c #define CCROC_THROT_PSKIP_CTRL_CPU_REG(vect) (CCROC_THROT_PSKIP_CTRL_CPU + \ (CCROC_THROT_OFFSET * vect)) #define CCROC_THROT_PSKIP_RAMP_CPU_REG(vect) (CCROC_THROT_PSKIP_RAMP_CPU + \ (CCROC_THROT_OFFSET * vect)) /* get THERMCTL_LEVELx offset per CPU/GPU/MEM/TSENSE rg and LEVEL0~3 lv */ #define THERMCTL_LVL_REGS_SIZE 0x20 #define THERMCTL_LVL_REG(rg, lv) ((rg) + ((lv) * THERMCTL_LVL_REGS_SIZE)) Loading Loading @@ -195,6 +217,7 @@ struct soctherm_throt_cfg { const char *name; unsigned int id; u8 priority; u8 cpu_throt_level; u32 cpu_throt_depth; struct thermal_cooling_device *cdev; bool init; Loading @@ -206,6 +229,7 @@ struct tegra_soctherm { struct clk *clock_soctherm; void __iomem *regs; void __iomem *clk_regs; void __iomem *ccroc_regs; u32 *calib; struct thermal_zone_device **thermctl_tzs; Loading Loading @@ -241,6 +265,31 @@ static inline u32 clk_readl(struct tegra_soctherm *ts, u32 reg) return readl(ts->clk_regs + reg); } /** * ccroc_writel() - writes a value to a CCROC register * @ts: pointer to a struct tegra_soctherm * @v: the value to write * @reg: the register offset * * Writes @v to @reg. No return value. */ static inline void ccroc_writel(struct tegra_soctherm *ts, u32 value, u32 reg) { writel(value, (ts->ccroc_regs + reg)); } /** * ccroc_readl() - reads specified register from CCROC IP block * @ts: pointer to a struct tegra_soctherm * @reg: register address to be read * * Return: the value of the register */ static inline u32 ccroc_readl(struct tegra_soctherm *ts, u32 reg) { return readl(ts->ccroc_regs + reg); } static void enable_tsensor(struct tegra_soctherm *tegra, unsigned int i) { const struct tegra_tsensor *sensor = &tegra->soc->tsensors[i]; Loading Loading @@ -552,9 +601,6 @@ static int tegra_soctherm_set_hwtrips(struct device *dev, sg->name, temperature); set_throttle: if (ts->soc->use_ccroc) return 0; ret = get_hot_temp(tz, &trip, &temperature); if (ret) { dev_warn(dev, "throttrip: %s: missing hot temperature\n", Loading Loading @@ -676,9 +722,6 @@ static int regs_show(struct seq_file *s, void *data) state = REG_GET_MASK(r, SENSOR_TEMP2_MEM_TEMP_MASK); seq_printf(s, " MEM(%d)\n", translate_temp(state)); if (ts->soc->use_ccroc) return 0; for (i = 0; i < ts->soc->num_ttgs; i++) { seq_printf(s, "%s:\n", ttgs[i]->name); for (level = 0; level < 4; level++) { Loading Loading @@ -779,12 +822,17 @@ static int regs_show(struct seq_file *s, void *data) seq_printf(s, "enabled(%d)\n", state); r = readl(ts->regs + CPU_PSKIP_STATUS); if (ts->soc->use_ccroc) { state = REG_GET_MASK(r, XPU_PSKIP_STATUS_ENABLED_MASK); seq_printf(s, "CPU PSKIP STATUS: enabled(%d)\n", state); } else { state = REG_GET_MASK(r, XPU_PSKIP_STATUS_M_MASK); seq_printf(s, "CPU PSKIP STATUS: M(%d) ", state); state = REG_GET_MASK(r, XPU_PSKIP_STATUS_N_MASK); seq_printf(s, "N(%d) ", state); state = REG_GET_MASK(r, XPU_PSKIP_STATUS_ENABLED_MASK); seq_printf(s, "enabled(%d)\n", state); } return 0; } Loading Loading @@ -939,7 +987,20 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev) } stc->priority = val; r = of_property_read_u32(np_stcc, "nvidia,cpu-throt-percent", if (ts->soc->use_ccroc) { r = of_property_read_u32(np_stcc, "nvidia,cpu-throt-level", &val); if (r) { dev_info(dev, "throttle-cfg: %s: missing cpu-throt-level\n", name); continue; } stc->cpu_throt_level = val; } else { r = of_property_read_u32(np_stcc, "nvidia,cpu-throt-percent", &val); if (r) { dev_info(dev, Loading @@ -948,6 +1009,7 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev) continue; } stc->cpu_throt_depth = val; } tcd = thermal_of_cooling_device_register(np_stcc, (char *)name, ts, Loading @@ -967,6 +1029,96 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev) of_node_put(np_stc); } /** * throttlectl_cpu_level_cfg() - programs CCROC NV_THERM level config * @level: describing the level LOW/MED/HIGH of throttling * * It's necessary to set up the CPU-local CCROC NV_THERM instance with * the M/N values desired for each level. This function does this. * * This function pre-programs the CCROC NV_THERM levels in terms of * pre-configured "Low", "Medium" or "Heavy" throttle levels which are * mapped to THROT_LEVEL_LOW, THROT_LEVEL_MED and THROT_LEVEL_HVY. */ static void throttlectl_cpu_level_cfg(struct tegra_soctherm *ts, int level) { u8 depth, dividend; u32 r; switch (level) { case TEGRA_SOCTHERM_THROT_LEVEL_LOW: depth = 50; break; case TEGRA_SOCTHERM_THROT_LEVEL_MED: depth = 75; break; case TEGRA_SOCTHERM_THROT_LEVEL_HIGH: depth = 80; break; case TEGRA_SOCTHERM_THROT_LEVEL_NONE: return; default: return; } dividend = THROT_DEPTH_DIVIDEND(depth); /* setup PSKIP in ccroc nv_therm registers */ r = ccroc_readl(ts, CCROC_THROT_PSKIP_RAMP_CPU_REG(level)); r = REG_SET_MASK(r, CCROC_THROT_PSKIP_RAMP_DURATION_MASK, 0xff); r = REG_SET_MASK(r, CCROC_THROT_PSKIP_RAMP_STEP_MASK, 0xf); ccroc_writel(ts, r, CCROC_THROT_PSKIP_RAMP_CPU_REG(level)); r = ccroc_readl(ts, CCROC_THROT_PSKIP_CTRL_CPU_REG(level)); r = REG_SET_MASK(r, CCROC_THROT_PSKIP_CTRL_ENB_MASK, 1); r = REG_SET_MASK(r, CCROC_THROT_PSKIP_CTRL_DIVIDEND_MASK, dividend); r = REG_SET_MASK(r, CCROC_THROT_PSKIP_CTRL_DIVISOR_MASK, 0xff); ccroc_writel(ts, r, CCROC_THROT_PSKIP_CTRL_CPU_REG(level)); } /** * throttlectl_cpu_level_select() - program CPU pulse skipper config * @throt: the LIGHT/HEAVY of throttle event id * * Pulse skippers are used to throttle clock frequencies. This * function programs the pulse skippers based on @throt and platform * data. This function is used on SoCs which have CPU-local pulse * skipper control, such as T13x. It programs soctherm's interface to * Denver:CCROC NV_THERM in terms of Low, Medium and HIGH throttling * vectors. PSKIP_BYPASS mode is set as required per HW spec. */ static void throttlectl_cpu_level_select(struct tegra_soctherm *ts, enum soctherm_throttle_id throt) { u32 r, throt_vect; /* Denver:CCROC NV_THERM interface N:3 Mapping */ switch (ts->throt_cfgs[throt].cpu_throt_level) { case TEGRA_SOCTHERM_THROT_LEVEL_LOW: throt_vect = THROT_VECT_LOW; break; case TEGRA_SOCTHERM_THROT_LEVEL_MED: throt_vect = THROT_VECT_MED; break; case TEGRA_SOCTHERM_THROT_LEVEL_HIGH: throt_vect = THROT_VECT_HIGH; break; default: throt_vect = THROT_VECT_NONE; break; } r = readl(ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_CPU)); r = REG_SET_MASK(r, THROT_PSKIP_CTRL_ENABLE_MASK, 1); r = REG_SET_MASK(r, THROT_PSKIP_CTRL_VECT_CPU_MASK, throt_vect); r = REG_SET_MASK(r, THROT_PSKIP_CTRL_VECT2_CPU_MASK, throt_vect); writel(r, ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_CPU)); /* bypass sequencer in soc_therm as it is programmed in ccroc */ r = REG_SET_MASK(0, THROT_PSKIP_RAMP_SEQ_BYPASS_MODE_MASK, 1); writel(r, ts->regs + THROT_PSKIP_RAMP(throt, THROTTLE_DEV_CPU)); } /** * throttlectl_cpu_mn() - program CPU pulse skipper configuration * @throt: the LIGHT/HEAVY of throttle event id Loading Loading @@ -1017,6 +1169,9 @@ static void soctherm_throttle_program(struct tegra_soctherm *ts, return; /* Setup PSKIP parameters */ if (ts->soc->use_ccroc) throttlectl_cpu_level_select(ts, throt); else throttlectl_cpu_mn(ts, throt); r = REG_SET_MASK(0, THROT_PRIORITY_LITE_PRIO_MASK, stc.priority); Loading @@ -1040,16 +1195,31 @@ static void tegra_soctherm_throttle(struct device *dev) u32 v; int i; /* configure LOW, MED and HIGH levels for CCROC NV_THERM */ if (ts->soc->use_ccroc) { throttlectl_cpu_level_cfg(ts, TEGRA_SOCTHERM_THROT_LEVEL_LOW); throttlectl_cpu_level_cfg(ts, TEGRA_SOCTHERM_THROT_LEVEL_MED); throttlectl_cpu_level_cfg(ts, TEGRA_SOCTHERM_THROT_LEVEL_HIGH); } /* Thermal HW throttle programming */ for (i = 0; i < THROTTLE_SIZE; i++) soctherm_throttle_program(ts, i); v = REG_SET_MASK(0, THROT_GLOBAL_ENB_MASK, 1); if (ts->soc->use_ccroc) { ccroc_writel(ts, v, CCROC_GLOBAL_CFG); v = ccroc_readl(ts, CCROC_SUPER_CCLKG_DIVIDER); v = REG_SET_MASK(v, CDIVG_USE_THERM_CONTROLS_MASK, 1); ccroc_writel(ts, v, CCROC_SUPER_CCLKG_DIVIDER); } else { writel(v, ts->regs + THROT_GLOBAL_CFG); v = clk_readl(ts, CAR_SUPER_CCLKG_DIVIDER); v = REG_SET_MASK(v, CDIVG_USE_THERM_CONTROLS_MASK, 1); clk_writel(ts, v, CAR_SUPER_CCLKG_DIVIDER); } /* initialize stats collection */ v = STATS_CTL_CLR_DN | STATS_CTL_EN_DN | Loading Loading @@ -1084,9 +1254,6 @@ static void soctherm_init(struct platform_device *pdev) writel(pdiv, tegra->regs + SENSOR_PDIV); writel(hotspot, tegra->regs + SENSOR_HOTSPOT_OFF); if (tegra->soc->use_ccroc) return; /* Configure hw throttle */ tegra_soctherm_throttle(&pdev->dev); } Loading Loading @@ -1157,6 +1324,14 @@ static int tegra_soctherm_probe(struct platform_device *pdev) dev_err(&pdev->dev, "can't get car clk registers"); return PTR_ERR(tegra->clk_regs); } } else { res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ccroc-reg"); tegra->ccroc_regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(tegra->ccroc_regs)) { dev_err(&pdev->dev, "can't get ccroc registers"); return PTR_ERR(tegra->ccroc_regs); } } tegra->reset = devm_reset_control_get(&pdev->dev, "soctherm"); Loading Loading @@ -1207,7 +1382,6 @@ static int tegra_soctherm_probe(struct platform_device *pdev) if (err) return err; if (!tegra->soc->use_ccroc) soctherm_init_hw_throt_cdev(pdev); soctherm_init(pdev); Loading
drivers/thermal/tegra/tegra132-soctherm.c +17 −0 Original line number Diff line number Diff line Loading @@ -28,7 +28,11 @@ #define TEGRA132_THERMTRIP_CPU_THRESH_MASK (0xff << 8) #define TEGRA132_THERMTRIP_TSENSE_THRESH_MASK 0xff #define TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK (0xff << 17) #define TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK (0xff << 9) #define TEGRA132_THRESH_GRAIN 1000 #define TEGRA132_BPTT 8 static const struct tegra_tsensor_configuration tegra132_tsensor_config = { .tall = 16300, Loading @@ -51,6 +55,9 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_cpu = { .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA132_THERMTRIP_CPU_EN_MASK, .thermtrip_threshold_mask = TEGRA132_THERMTRIP_CPU_THRESH_MASK, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_CPU, .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK, }; static const struct tegra_tsensor_group tegra132_tsensor_group_gpu = { Loading @@ -66,6 +73,9 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_gpu = { .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA132_THERMTRIP_GPU_EN_MASK, .thermtrip_threshold_mask = TEGRA132_THERMTRIP_GPUMEM_THRESH_MASK, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_GPU, .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK, }; static const struct tegra_tsensor_group tegra132_tsensor_group_pll = { Loading @@ -79,6 +89,9 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_pll = { .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA132_THERMTRIP_TSENSE_EN_MASK, .thermtrip_threshold_mask = TEGRA132_THERMTRIP_TSENSE_THRESH_MASK, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_TSENSE, .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK, }; static const struct tegra_tsensor_group tegra132_tsensor_group_mem = { Loading @@ -94,6 +107,9 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_mem = { .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA132_THERMTRIP_MEM_EN_MASK, .thermtrip_threshold_mask = TEGRA132_THERMTRIP_GPUMEM_THRESH_MASK, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_MEM, .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK, }; static const struct tegra_tsensor_group *tegra132_tsensor_groups[] = { Loading Loading @@ -193,5 +209,6 @@ const struct tegra_soctherm_soc tegra132_soctherm = { .num_ttgs = ARRAY_SIZE(tegra132_tsensor_groups), .tfuse = &tegra132_soctherm_fuse, .thresh_grain = TEGRA132_THRESH_GRAIN, .bptt = TEGRA132_BPTT, .use_ccroc = true, };
include/dt-bindings/thermal/tegra124-soctherm.h +5 −0 Original line number Diff line number Diff line Loading @@ -11,4 +11,9 @@ #define TEGRA124_SOCTHERM_SENSOR_PLLX 3 #define TEGRA124_SOCTHERM_SENSOR_NUM 4 #define TEGRA_SOCTHERM_THROT_LEVEL_LOW 0 #define TEGRA_SOCTHERM_THROT_LEVEL_MED 1 #define TEGRA_SOCTHERM_THROT_LEVEL_HIGH 2 #define TEGRA_SOCTHERM_THROT_LEVEL_NONE -1 #endif