Message ID | 20221126224740.311625-5-marex@denx.de |
---|---|
State | Superseded |
Headers | show |
Series | [1/5] dt-bindings: thermal: imx8mm-thermal: Document optional nvmem-cells | expand |
Hi Marek, I love your patch! Yet something to improve: [auto build test ERROR on shawnguo/for-next] [also build test ERROR on soc/for-next linus/master v6.1-rc7 next-20221130] [cannot apply to robh/for-next rafael-pm/thermal arm/for-next arm/fixes arm64/for-next/core clk/clk-next kvmarm/next rockchip/for-next xilinx-xlnx/master] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Marek-Vasut/dt-bindings-thermal-imx8mm-thermal-Document-optional-nvmem-cells/20221127-064933 base: https://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git for-next patch link: https://lore.kernel.org/r/20221126224740.311625-5-marex%40denx.de patch subject: [PATCH 5/5] thermal/drivers/imx: Add support for loading calibration data from OCOTP config: arm-randconfig-c002-20221128 compiler: clang version 16.0.0 (https://github.com/llvm/llvm-project 6e4cea55f0d1104408b26ac574566a0e4de48036) reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # install arm cross compiling tool for clang build # apt-get install binutils-arm-linux-gnueabi # https://github.com/intel-lab-lkp/linux/commit/f6dcd96ffbcbc0e197a9f97a56b101cd5fa8e70a git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Marek-Vasut/dt-bindings-thermal-imx8mm-thermal-Document-optional-nvmem-cells/20221127-064933 git checkout f6dcd96ffbcbc0e197a9f97a56b101cd5fa8e70a # save the config file mkdir build_dir && cp config build_dir/.config COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm SHELL=/bin/bash drivers/thermal/ If you fix the issue, kindly add following tag where applicable | Reported-by: kernel test robot <lkp@intel.com> All error/warnings (new ones prefixed by >>): >> drivers/thermal/imx8mm_thermal.c:214:2: error: call to undeclared function 'kfree'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] kfree(buf); ^ drivers/thermal/imx8mm_thermal.c:214:2: note: did you mean 'vfree'? include/linux/vmalloc.h:163:13: note: 'vfree' declared here extern void vfree(const void *addr); ^ >> drivers/thermal/imx8mm_thermal.c:218:53: warning: format specifies type 'long' but the argument has type 'size_t' (aka 'unsigned int') [-Wformat] "OCOTP nvmem cell length is %ld, must be 16.\n", len); ~~~ ^~~ %zu include/linux/dev_printk.h:144:65: note: expanded from macro 'dev_err' dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__) ~~~ ^~~~~~~~~~~ include/linux/dev_printk.h:110:23: note: expanded from macro 'dev_printk_index_wrap' _p_func(dev, fmt, ##__VA_ARGS__); \ ~~~ ^~~~~~~~~~~ 1 warning and 1 error generated. Kconfig warnings: (for reference only) WARNING: unmet direct dependencies detected for VIDEO_MEDIATEK_VPU Depends on [n]: MEDIA_SUPPORT [=y] && MEDIA_PLATFORM_SUPPORT [=y] && MEDIA_PLATFORM_DRIVERS [=y] && V4L_MEM2MEM_DRIVERS [=n] && VIDEO_DEV [=y] && (ARCH_MEDIATEK [=n] || COMPILE_TEST [=y]) Selected by [y]: - VIDEO_MEDIATEK_MDP3 [=y] && MEDIA_SUPPORT [=y] && MEDIA_PLATFORM_SUPPORT [=y] && MEDIA_PLATFORM_DRIVERS [=y] && (MTK_IOMMU [=n] || COMPILE_TEST [=y]) && VIDEO_DEV [=y] && (ARCH_MEDIATEK [=n] || COMPILE_TEST [=y]) && HAS_DMA [=y] && REMOTEPROC [=y] vim +/kfree +214 drivers/thermal/imx8mm_thermal.c 193 194 static int imx8mm_tmu_probe_set_calib_v2(struct platform_device *pdev, 195 struct imx8mm_tmu *tmu) 196 { 197 struct device *dev = &pdev->dev; 198 struct nvmem_cell *cell; 199 u32 trim[4] = { 0 }; 200 size_t len; 201 void *buf; 202 203 cell = nvmem_cell_get(dev, "calib"); 204 if (IS_ERR(cell)) 205 return PTR_ERR(cell); 206 207 buf = nvmem_cell_read(cell, &len); 208 nvmem_cell_put(cell); 209 210 if (IS_ERR(buf)) 211 return PTR_ERR(buf); 212 213 memcpy(trim, buf, min(len, sizeof(trim))); > 214 kfree(buf); 215 216 if (len != 16) { 217 dev_err(dev, > 218 "OCOTP nvmem cell length is %ld, must be 16.\n", len); 219 return -EINVAL; 220 } 221 222 /* Blank sample hardware */ 223 if (!trim[0] && !trim[1] && !trim[2] && !trim[3]) { 224 /* Use a default 25C binary codes */ 225 writel(FIELD_PREP(TCALIV_SNSR25C_MASK, 0x63c), 226 tmu->base + TCALIV(0)); 227 writel(FIELD_PREP(TCALIV_SNSR25C_MASK, 0x63c), 228 tmu->base + TCALIV(1)); 229 return 0; 230 } 231 232 writel(FIELD_PREP(TASR_BUF_VERF_SEL_MASK, 233 FIELD_GET(TRIM2_BUF_VERF_SEL_MASK, trim[0])) | 234 FIELD_PREP(TASR_BUF_SLOPE_MASK, 235 FIELD_GET(TRIM2_BUF_SLOP_SEL_MASK, trim[0])), 236 tmu->base + TASR); 237 238 writel(FIELD_PREP(TRIM_BJT_CUR_MASK, 239 FIELD_GET(TRIM2_BJT_CUR_MASK, trim[0])) | 240 FIELD_PREP(TRIM_BGR_MASK, FIELD_GET(TRIM2_BGR_MASK, trim[0])) | 241 FIELD_PREP(TRIM_VLSB_MASK, FIELD_GET(TRIM2_VLSB_MASK, trim[0])) | 242 TRIM_EN_CH, 243 tmu->base + TRIM); 244 245 writel(FIELD_PREP(TCALIV_SNSR25C_MASK, 246 FIELD_GET(TRIM3_TCA25_0_LSB_MASK, trim[1]) | 247 (FIELD_GET(TRIM4_TCA25_0_MSB_MASK, trim[2]) << 4)) | 248 FIELD_PREP(TCALIV_SNSR105C_MASK, 249 FIELD_GET(TRIM4_TCA105_0_MASK, trim[2])), 250 tmu->base + TCALIV(0)); 251 252 writel(FIELD_PREP(TCALIV_SNSR25C_MASK, 253 FIELD_GET(TRIM5_TCA25_1_MASK, trim[3])) | 254 FIELD_PREP(TCALIV_SNSR105C_MASK, 255 FIELD_GET(TRIM5_TCA105_1_MASK, trim[3])), 256 tmu->base + TCALIV(1)); 257 258 writel(FIELD_PREP(TCALIV_SNSR25C_MASK, 259 FIELD_GET(TRIM3_TCA40_0_MASK, trim[1])) | 260 FIELD_PREP(TCALIV_SNSR105C_MASK, 261 FIELD_GET(TRIM4_TCA40_1_MASK, trim[2])), 262 tmu->base + TCALIV(2)); 263 264 return 0; 265 } 266
diff --git a/drivers/thermal/imx8mm_thermal.c b/drivers/thermal/imx8mm_thermal.c index e2c2673025a7a..da09c00ac663a 100644 --- a/drivers/thermal/imx8mm_thermal.c +++ b/drivers/thermal/imx8mm_thermal.c @@ -10,6 +10,7 @@ #include <linux/err.h> #include <linux/io.h> #include <linux/module.h> +#include <linux/nvmem-consumer.h> #include <linux/of.h> #include <linux/of_device.h> #include <linux/platform_device.h> @@ -20,6 +21,22 @@ #define TER 0x0 /* TMU enable */ #define TPS 0x4 #define TRITSR 0x20 /* TMU immediate temp */ +/* TMU calibration data registers */ +#define TASR 0x28 +#define TASR_BUF_SLOPE_MASK GENMASK(19, 16) +#define TASR_BUF_VREF_MASK GENMASK(4, 0) /* TMU_V1 */ +#define TASR_BUF_VERF_SEL_MASK GENMASK(1, 0) /* TMU_V2 */ +#define TCALIV(n) (0x30 + ((n) * 4)) +#define TCALIV_EN BIT(31) +#define TCALIV_HR_MASK GENMASK(23, 16) /* TMU_V1 */ +#define TCALIV_RT_MASK GENMASK(7, 0) /* TMU_V1 */ +#define TCALIV_SNSR105C_MASK GENMASK(27, 16) /* TMU_V2 */ +#define TCALIV_SNSR25C_MASK GENMASK(11, 0) /* TMU_V2 */ +#define TRIM 0x3c +#define TRIM_BJT_CUR_MASK GENMASK(23, 20) +#define TRIM_BGR_MASK GENMASK(31, 28) +#define TRIM_VLSB_MASK GENMASK(15, 12) +#define TRIM_EN_CH BIT(7) #define TER_ADC_PD BIT(30) #define TER_EN BIT(31) @@ -32,6 +49,25 @@ #define SIGN_BIT BIT(7) #define TEMP_VAL_MASK GENMASK(6, 0) +/* TMU OCOTP calibration data bitfields */ +#define ANA0_EN BIT(25) +#define ANA0_BUF_VREF_MASK GENMASK(24, 20) +#define ANA0_BUF_SLOPE_MASK GENMASK(19, 16) +#define ANA0_HR_MASK GENMASK(15, 8) +#define ANA0_RT_MASK GENMASK(7, 0) +#define TRIM2_VLSB_MASK GENMASK(23, 20) +#define TRIM2_BGR_MASK GENMASK(19, 16) +#define TRIM2_BJT_CUR_MASK GENMASK(15, 12) +#define TRIM2_BUF_SLOP_SEL_MASK GENMASK(11, 8) +#define TRIM2_BUF_VERF_SEL_MASK GENMASK(7, 6) +#define TRIM3_TCA25_0_LSB_MASK GENMASK(31, 28) +#define TRIM3_TCA40_0_MASK GENMASK(27, 16) +#define TRIM4_TCA40_1_MASK GENMASK(31, 20) +#define TRIM4_TCA105_0_MASK GENMASK(19, 8) +#define TRIM4_TCA25_0_MSB_MASK GENMASK(7, 0) +#define TRIM5_TCA105_1_MASK GENMASK(23, 12) +#define TRIM5_TCA25_1_MASK GENMASK(11, 0) + #define VER1_TEMP_LOW_LIMIT 10000 #define VER2_TEMP_LOW_LIMIT -40000 #define VER2_TEMP_HIGH_LIMIT 125000 @@ -128,6 +164,129 @@ static void imx8mm_tmu_probe_sel_all(struct imx8mm_tmu *tmu) writel_relaxed(val, tmu->base + TPS); } +static int imx8mm_tmu_probe_set_calib_v1(struct platform_device *pdev, + struct imx8mm_tmu *tmu) +{ + struct device *dev = &pdev->dev; + u32 ana0; + int ret; + + ret = nvmem_cell_read_u32(&pdev->dev, "calib", &ana0); + if (ret) { + dev_warn(dev, "Failed to read OCOTP nvmem cell (%d).\n", ret); + return ret; + } + + writel(FIELD_PREP(TASR_BUF_VREF_MASK, + FIELD_GET(ANA0_BUF_VREF_MASK, ana0)) | + FIELD_PREP(TASR_BUF_SLOPE_MASK, + FIELD_GET(ANA0_BUF_SLOPE_MASK, ana0)), + tmu->base + TASR); + + writel(FIELD_PREP(TCALIV_RT_MASK, FIELD_GET(ANA0_RT_MASK, ana0)) | + FIELD_PREP(TCALIV_HR_MASK, FIELD_GET(ANA0_HR_MASK, ana0)) | + ((ana0 & ANA0_EN) ? TCALIV_EN : 0), + tmu->base + TCALIV(0)); + + return 0; +} + +static int imx8mm_tmu_probe_set_calib_v2(struct platform_device *pdev, + struct imx8mm_tmu *tmu) +{ + struct device *dev = &pdev->dev; + struct nvmem_cell *cell; + u32 trim[4] = { 0 }; + size_t len; + void *buf; + + cell = nvmem_cell_get(dev, "calib"); + if (IS_ERR(cell)) + return PTR_ERR(cell); + + buf = nvmem_cell_read(cell, &len); + nvmem_cell_put(cell); + + if (IS_ERR(buf)) + return PTR_ERR(buf); + + memcpy(trim, buf, min(len, sizeof(trim))); + kfree(buf); + + if (len != 16) { + dev_err(dev, + "OCOTP nvmem cell length is %ld, must be 16.\n", len); + return -EINVAL; + } + + /* Blank sample hardware */ + if (!trim[0] && !trim[1] && !trim[2] && !trim[3]) { + /* Use a default 25C binary codes */ + writel(FIELD_PREP(TCALIV_SNSR25C_MASK, 0x63c), + tmu->base + TCALIV(0)); + writel(FIELD_PREP(TCALIV_SNSR25C_MASK, 0x63c), + tmu->base + TCALIV(1)); + return 0; + } + + writel(FIELD_PREP(TASR_BUF_VERF_SEL_MASK, + FIELD_GET(TRIM2_BUF_VERF_SEL_MASK, trim[0])) | + FIELD_PREP(TASR_BUF_SLOPE_MASK, + FIELD_GET(TRIM2_BUF_SLOP_SEL_MASK, trim[0])), + tmu->base + TASR); + + writel(FIELD_PREP(TRIM_BJT_CUR_MASK, + FIELD_GET(TRIM2_BJT_CUR_MASK, trim[0])) | + FIELD_PREP(TRIM_BGR_MASK, FIELD_GET(TRIM2_BGR_MASK, trim[0])) | + FIELD_PREP(TRIM_VLSB_MASK, FIELD_GET(TRIM2_VLSB_MASK, trim[0])) | + TRIM_EN_CH, + tmu->base + TRIM); + + writel(FIELD_PREP(TCALIV_SNSR25C_MASK, + FIELD_GET(TRIM3_TCA25_0_LSB_MASK, trim[1]) | + (FIELD_GET(TRIM4_TCA25_0_MSB_MASK, trim[2]) << 4)) | + FIELD_PREP(TCALIV_SNSR105C_MASK, + FIELD_GET(TRIM4_TCA105_0_MASK, trim[2])), + tmu->base + TCALIV(0)); + + writel(FIELD_PREP(TCALIV_SNSR25C_MASK, + FIELD_GET(TRIM5_TCA25_1_MASK, trim[3])) | + FIELD_PREP(TCALIV_SNSR105C_MASK, + FIELD_GET(TRIM5_TCA105_1_MASK, trim[3])), + tmu->base + TCALIV(1)); + + writel(FIELD_PREP(TCALIV_SNSR25C_MASK, + FIELD_GET(TRIM3_TCA40_0_MASK, trim[1])) | + FIELD_PREP(TCALIV_SNSR105C_MASK, + FIELD_GET(TRIM4_TCA40_1_MASK, trim[2])), + tmu->base + TCALIV(2)); + + return 0; +} + +static int imx8mm_tmu_probe_set_calib(struct platform_device *pdev, + struct imx8mm_tmu *tmu) +{ + struct device *dev = &pdev->dev; + + /* + * Lack of calibration data OCOTP reference is not considered + * fatal to retain compatibility with old DTs. It is however + * strongly recommended to update such old DTs to get correct + * temperature compensation values for each SoC. + */ + if (!of_find_property(pdev->dev.of_node, "nvmem-cells", NULL)) { + dev_warn(dev, + "No OCOTP nvmem reference found, SoC-specific calibration not loaded. Please update your DT.\n"); + return 0; + } + + if (tmu->socdata->version == TMU_VER1) + return imx8mm_tmu_probe_set_calib_v1(pdev, tmu); + + return imx8mm_tmu_probe_set_calib_v2(pdev, tmu); +} + static int imx8mm_tmu_probe(struct platform_device *pdev) { const struct thermal_soc_data *data; @@ -180,6 +339,10 @@ static int imx8mm_tmu_probe(struct platform_device *pdev) platform_set_drvdata(pdev, tmu); + ret = imx8mm_tmu_probe_set_calib(pdev, tmu); + if (ret) + goto disable_clk; + /* enable all the probes for V2 TMU */ if (tmu->socdata->version == TMU_VER2) imx8mm_tmu_probe_sel_all(tmu);
The TMU TASR, TCALIVn, TRIM registers must be explicitly programmed with calibration values in OCOTP. Add support for reading the OCOTP calibration data and programming those into the TMU hardware. The MX8MM/MX8MN TMUv1 uses only one OCOTP cell, while MX8MP TMUv2 uses 4, the programming differs in each case. Based on U-Boot commits: 70487ff386c ("imx8mm: Load fuse for TMU TCALIV and TASR") ebb9aab318b ("imx: load calibration parameters from fuse for i.MX8MP") Signed-off-by: Marek Vasut <marex@denx.de> --- Cc: Adam Ford <aford173@gmail.com> Cc: Alice Guo <alice.guo@nxp.com> Cc: Amit Kucheria <amitk@kernel.org> Cc: Daniel Lezcano <daniel.lezcano@linaro.org> Cc: Fabio Estevam <festevam@gmail.com> Cc: Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org> Cc: Li Jun <jun.li@nxp.com> Cc: Lucas Stach <l.stach@pengutronix.de> Cc: Markus Niebel <Markus.Niebel@ew.tq-group.com> Cc: NXP Linux Team <linux-imx@nxp.com> Cc: Peng Fan <peng.fan@nxp.com> Cc: Pengutronix Kernel Team <kernel@pengutronix.de> Cc: Rafael J. Wysocki <rafael@kernel.org> Cc: Richard Cochran <richardcochran@gmail.com> Cc: Rob Herring <robh+dt@kernel.org> Cc: Sascha Hauer <s.hauer@pengutronix.de> Cc: Shawn Guo <shawnguo@kernel.org> Cc: Zhang Rui <rui.zhang@intel.com> Cc: devicetree@vger.kernel.org To: linux-pm@vger.kernel.org To: linux-arm-kernel@lists.infradead.org --- drivers/thermal/imx8mm_thermal.c | 163 +++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+)