uboot/drivers/thermal/imx_tmu.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright 2017~2020 NXP
   4 *
   5 */
   6
   7#include <config.h>
   8#include <common.h>
   9#include <asm/global_data.h>
  10#include <asm/io.h>
  11#include <asm/arch/clock.h>
  12#include <asm/arch/sys_proto.h>
  13#include <dm.h>
  14#include <dm/device-internal.h>
  15#include <dm/device.h>
  16#include <errno.h>
  17#include <fuse.h>
  18#include <linux/delay.h>
  19#include <malloc.h>
  20#include <thermal.h>
  21
  22DECLARE_GLOBAL_DATA_PTR;
  23
  24#define SITES_MAX       16
  25#define FLAGS_VER2      0x1
  26#define FLAGS_VER3      0x2
  27
  28#define TMR_DISABLE     0x0
  29#define TMR_ME          0x80000000
  30#define TMR_ALPF        0x0c000000
  31#define TMTMIR_DEFAULT  0x00000002
  32#define TIER_DISABLE    0x0
  33
  34#define TER_EN                  0x80000000
  35#define TER_ADC_PD              0x40000000
  36#define TER_ALPF                0x3
  37
  38/*
  39 * i.MX TMU Registers
  40 */
  41struct imx_tmu_site_regs {
  42        u32 tritsr;             /* Immediate Temperature Site Register */
  43        u32 tratsr;             /* Average Temperature Site Register */
  44        u8 res0[0x8];
  45};
  46
  47struct imx_tmu_regs {
  48        u32 tmr;        /* Mode Register */
  49        u32 tsr;        /* Status Register */
  50        u32 tmtmir;     /* Temperature measurement interval Register */
  51        u8 res0[0x14];
  52        u32 tier;       /* Interrupt Enable Register */
  53        u32 tidr;       /* Interrupt Detect Register */
  54        u32 tiscr;      /* Interrupt Site Capture Register */
  55        u32 ticscr;     /* Interrupt Critical Site Capture Register */
  56        u8 res1[0x10];
  57        u32 tmhtcrh;    /* High Temperature Capture Register */
  58        u32 tmhtcrl;    /* Low Temperature Capture Register */
  59        u8 res2[0x8];
  60        u32 tmhtitr;    /* High Temperature Immediate Threshold */
  61        u32 tmhtatr;    /* High Temperature Average Threshold */
  62        u32 tmhtactr;   /* High Temperature Average Crit Threshold */
  63        u8 res3[0x24];
  64        u32 ttcfgr;     /* Temperature Configuration Register */
  65        u32 tscfgr;     /* Sensor Configuration Register */
  66        u8 res4[0x78];
  67        struct imx_tmu_site_regs site[SITES_MAX];
  68        u8 res5[0x9f8];
  69        u32 ipbrr0;     /* IP Block Revision Register 0 */
  70        u32 ipbrr1;     /* IP Block Revision Register 1 */
  71        u8 res6[0x310];
  72        u32 ttr0cr;     /* Temperature Range 0 Control Register */
  73        u32 ttr1cr;     /* Temperature Range 1 Control Register */
  74        u32 ttr2cr;     /* Temperature Range 2 Control Register */
  75        u32 ttr3cr;     /* Temperature Range 3 Control Register */
  76};
  77
  78struct imx_tmu_regs_v2 {
  79        u32 ter;        /* TMU enable Register */
  80        u32 tsr;        /* Status Register */
  81        u32 tier;       /* Interrupt enable register */
  82        u32 tidr;       /* Interrupt detect  register */
  83        u32 tmhtitr;    /* Monitor high temperature immediate threshold register */
  84        u32 tmhtatr;    /* Monitor high temperature average threshold register */
  85        u32 tmhtactr;   /* TMU monitor high temperature average critical  threshold register */
  86        u32 tscr;       /* Sensor value capture register */
  87        u32 tritsr;     /* Report immediate temperature site register 0 */
  88        u32 tratsr;     /* Report average temperature site register 0 */
  89        u32 tasr;       /* Amplifier setting register */
  90        u32 ttmc;       /* Test MUX control */
  91        u32 tcaliv;
  92};
  93
  94struct imx_tmu_regs_v3 {
  95        u32 ter;        /* TMU enable Register */
  96        u32 tps;        /* Status Register */
  97        u32 tier;       /* Interrupt enable register */
  98        u32 tidr;       /* Interrupt detect  register */
  99        u32 tmhtitr;    /* Monitor high temperature immediate threshold register */
 100        u32 tmhtatr;    /* Monitor high temperature average threshold register */
 101        u32 tmhtactr;   /* TMU monitor high temperature average critical  threshold register */
 102        u32 tscr;       /* Sensor value capture register */
 103        u32 tritsr;     /* Report immediate temperature site register 0 */
 104        u32 tratsr;     /* Report average temperature site register 0 */
 105        u32 tasr;       /* Amplifier setting register */
 106        u32 ttmc;       /* Test MUX control */
 107        u32 tcaliv0;
 108        u32 tcaliv1;
 109        u32 tcaliv_m40;
 110        u32 trim;
 111};
 112
 113union tmu_regs {
 114        struct imx_tmu_regs regs_v1;
 115        struct imx_tmu_regs_v2 regs_v2;
 116        struct imx_tmu_regs_v3 regs_v3;
 117};
 118
 119struct imx_tmu_plat {
 120        int critical;
 121        int alert;
 122        int polling_delay;
 123        int id;
 124        bool zone_node;
 125        union tmu_regs *regs;
 126};
 127
 128static int read_temperature(struct udevice *dev, int *temp)
 129{
 130        struct imx_tmu_plat *pdata = dev_get_plat(dev);
 131        ulong drv_data = dev_get_driver_data(dev);
 132        u32 val;
 133        u32 retry = 10;
 134        u32 valid = 0;
 135
 136        do {
 137                mdelay(100);
 138                retry--;
 139
 140                if (drv_data & FLAGS_VER3) {
 141                        val = readl(&pdata->regs->regs_v3.tritsr);
 142                        valid = val & (1 << (30 + pdata->id));
 143                } else if (drv_data & FLAGS_VER2) {
 144                        val = readl(&pdata->regs->regs_v2.tritsr);
 145                        /*
 146                         * Check if TEMP is in valid range, the V bit in TRITSR
 147                         * only reflects the RAW uncalibrated data
 148                         */
 149                        valid =  ((val & 0xff) < 10 || (val & 0xff) > 125) ? 0 : 1;
 150                } else {
 151                        val = readl(&pdata->regs->regs_v1.site[pdata->id].tritsr);
 152                        valid = val & 0x80000000;
 153                }
 154        } while (!valid && retry > 0);
 155
 156        if (retry > 0) {
 157                if (drv_data & FLAGS_VER3) {
 158                        val = (val >> (pdata->id * 16)) & 0xff;
 159                        if (val & 0x80) /* Negative */
 160                                val = (~(val & 0x7f) + 1);
 161
 162                        *temp = val;
 163                        if (*temp < -40 || *temp > 125) /* Check the range */
 164                                return -EINVAL;
 165
 166                        *temp *= 1000;
 167                } else {
 168                        *temp = (val & 0xff) * 1000;
 169                }
 170        } else {
 171                return -EINVAL;
 172        }
 173
 174        return 0;
 175}
 176
 177int imx_tmu_get_temp(struct udevice *dev, int *temp)
 178{
 179        struct imx_tmu_plat *pdata = dev_get_plat(dev);
 180        int cpu_tmp = 0;
 181        int ret;
 182
 183        ret = read_temperature(dev, &cpu_tmp);
 184        if (ret)
 185                return ret;
 186
 187        while (cpu_tmp >= pdata->alert) {
 188                printf("CPU Temperature (%dC) has beyond alert (%dC), close to critical (%dC)", cpu_tmp, pdata->alert, pdata->critical);
 189                puts(" waiting...\n");
 190                mdelay(pdata->polling_delay);
 191                ret = read_temperature(dev, &cpu_tmp);
 192                if (ret)
 193                        return ret;
 194        }
 195
 196        *temp = cpu_tmp / 1000;
 197
 198        return 0;
 199}
 200
 201static const struct dm_thermal_ops imx_tmu_ops = {
 202        .get_temp       = imx_tmu_get_temp,
 203};
 204
 205static int imx_tmu_calibration(struct udevice *dev)
 206{
 207        int i, val, len, ret;
 208        u32 range[4];
 209        const fdt32_t *calibration;
 210        struct imx_tmu_plat *pdata = dev_get_plat(dev);
 211        ulong drv_data = dev_get_driver_data(dev);
 212
 213        debug("%s\n", __func__);
 214
 215        if (drv_data & (FLAGS_VER2 | FLAGS_VER3))
 216                return 0;
 217
 218        ret = dev_read_u32_array(dev, "fsl,tmu-range", range, 4);
 219        if (ret) {
 220                printf("TMU: missing calibration range, ret = %d.\n", ret);
 221                return ret;
 222        }
 223
 224        /* Init temperature range registers */
 225        writel(range[0], &pdata->regs->regs_v1.ttr0cr);
 226        writel(range[1], &pdata->regs->regs_v1.ttr1cr);
 227        writel(range[2], &pdata->regs->regs_v1.ttr2cr);
 228        writel(range[3], &pdata->regs->regs_v1.ttr3cr);
 229
 230        calibration = dev_read_prop(dev, "fsl,tmu-calibration", &len);
 231        if (!calibration || len % 8) {
 232                printf("TMU: invalid calibration data.\n");
 233                return -ENODEV;
 234        }
 235
 236        for (i = 0; i < len; i += 8, calibration += 2) {
 237                val = fdt32_to_cpu(*calibration);
 238                writel(val, &pdata->regs->regs_v1.ttcfgr);
 239                val = fdt32_to_cpu(*(calibration + 1));
 240                writel(val, &pdata->regs->regs_v1.tscfgr);
 241        }
 242
 243        return 0;
 244}
 245
 246void __weak imx_tmu_arch_init(void *reg_base)
 247{
 248}
 249
 250static void imx_tmu_init(struct udevice *dev)
 251{
 252        struct imx_tmu_plat *pdata = dev_get_plat(dev);
 253        ulong drv_data = dev_get_driver_data(dev);
 254
 255        debug("%s\n", __func__);
 256
 257        if (drv_data & FLAGS_VER3) {
 258                /* Disable monitoring */
 259                writel(0x0, &pdata->regs->regs_v3.ter);
 260
 261                /* Disable interrupt, using polling instead */
 262                writel(0x0, &pdata->regs->regs_v3.tier);
 263
 264        } else if (drv_data & FLAGS_VER2) {
 265                /* Disable monitoring */
 266                writel(0x0, &pdata->regs->regs_v2.ter);
 267
 268                /* Disable interrupt, using polling instead */
 269                writel(0x0, &pdata->regs->regs_v2.tier);
 270        } else {
 271                /* Disable monitoring */
 272                writel(TMR_DISABLE, &pdata->regs->regs_v1.tmr);
 273
 274                /* Disable interrupt, using polling instead */
 275                writel(TIER_DISABLE, &pdata->regs->regs_v1.tier);
 276
 277                /* Set update_interval */
 278                writel(TMTMIR_DEFAULT, &pdata->regs->regs_v1.tmtmir);
 279        }
 280
 281        imx_tmu_arch_init((void *)pdata->regs);
 282}
 283
 284static int imx_tmu_enable_msite(struct udevice *dev)
 285{
 286        struct imx_tmu_plat *pdata = dev_get_plat(dev);
 287        ulong drv_data = dev_get_driver_data(dev);
 288        u32 reg;
 289
 290        debug("%s\n", __func__);
 291
 292        if (!pdata->regs)
 293                return -EIO;
 294
 295        if (drv_data & FLAGS_VER3) {
 296                reg = readl(&pdata->regs->regs_v3.ter);
 297                reg &= ~TER_EN;
 298                writel(reg, &pdata->regs->regs_v3.ter);
 299
 300                writel(pdata->id << 30, &pdata->regs->regs_v3.tps);
 301
 302                reg &= ~TER_ALPF;
 303                reg |= 0x1;
 304                reg &= ~TER_ADC_PD;
 305                writel(reg, &pdata->regs->regs_v3.ter);
 306
 307                /* Enable monitor */
 308                reg |= TER_EN;
 309                writel(reg, &pdata->regs->regs_v3.ter);
 310        } else if (drv_data & FLAGS_VER2) {
 311                reg = readl(&pdata->regs->regs_v2.ter);
 312                reg &= ~TER_EN;
 313                writel(reg, &pdata->regs->regs_v2.ter);
 314
 315                reg &= ~TER_ALPF;
 316                reg |= 0x1;
 317                writel(reg, &pdata->regs->regs_v2.ter);
 318
 319                /* Enable monitor */
 320                reg |= TER_EN;
 321                writel(reg, &pdata->regs->regs_v2.ter);
 322        } else {
 323                /* Clear the ME before setting MSITE and ALPF*/
 324                reg = readl(&pdata->regs->regs_v1.tmr);
 325                reg &= ~TMR_ME;
 326                writel(reg, &pdata->regs->regs_v1.tmr);
 327
 328                reg |= 1 << (15 - pdata->id);
 329                reg |= TMR_ALPF;
 330                writel(reg, &pdata->regs->regs_v1.tmr);
 331
 332                /* Enable ME */
 333                reg |= TMR_ME;
 334                writel(reg, &pdata->regs->regs_v1.tmr);
 335        }
 336
 337        return 0;
 338}
 339
 340static int imx_tmu_bind(struct udevice *dev)
 341{
 342        struct imx_tmu_plat *pdata = dev_get_plat(dev);
 343        int ret;
 344        ofnode node, offset;
 345        const char *name;
 346        const void *prop;
 347        int minc, maxc;
 348
 349        debug("%s dev name %s\n", __func__, dev->name);
 350
 351        prop = dev_read_prop(dev, "compatible", NULL);
 352        if (!prop)
 353                return 0;
 354
 355        pdata->zone_node = 1;
 356        /* default alert/crit temps based on temp grade */
 357        get_cpu_temp_grade(&minc, &maxc);
 358        pdata->critical = maxc * 1000;
 359        pdata->alert = (maxc - 10) * 1000;
 360
 361        node = ofnode_path("/thermal-zones");
 362        ofnode_for_each_subnode(offset, node) {
 363                /* Bind the subnode to this driver */
 364                name = ofnode_get_name(offset);
 365
 366                ret = device_bind_with_driver_data(dev, dev->driver, name,
 367                                                   dev->driver_data, offset,
 368                                                   NULL);
 369                if (ret)
 370                        printf("Error binding driver '%s': %d\n",
 371                               dev->driver->name, ret);
 372        }
 373
 374        return 0;
 375}
 376
 377static int imx_tmu_parse_fdt(struct udevice *dev)
 378{
 379        struct imx_tmu_plat *pdata = dev_get_plat(dev), *p_parent_data;
 380        struct ofnode_phandle_args args;
 381        ofnode trips_np;
 382        int ret;
 383
 384        debug("%s dev name %s\n", __func__, dev->name);
 385
 386        if (pdata->zone_node) {
 387                pdata->regs = (union tmu_regs *)dev_read_addr_ptr(dev);
 388
 389                if (!pdata->regs)
 390                        return -EINVAL;
 391                return 0;
 392        }
 393
 394        p_parent_data = dev_get_plat(dev->parent);
 395        if (p_parent_data->zone_node)
 396                pdata->regs = p_parent_data->regs;
 397
 398        ret = dev_read_phandle_with_args(dev, "thermal-sensors",
 399                                         "#thermal-sensor-cells",
 400                                         0, 0, &args);
 401        if (ret)
 402                return ret;
 403
 404        if (!ofnode_equal(args.node, dev_ofnode(dev->parent)))
 405                return -EFAULT;
 406
 407        if (args.args_count >= 1)
 408                pdata->id = args.args[0];
 409        else
 410                pdata->id = 0;
 411
 412        debug("args.args_count %d, id %d\n", args.args_count, pdata->id);
 413
 414        pdata->polling_delay = dev_read_u32_default(dev, "polling-delay", 1000);
 415
 416        trips_np = ofnode_path("/thermal-zones/cpu-thermal/trips");
 417        ofnode_for_each_subnode(trips_np, trips_np) {
 418                const char *type;
 419
 420                type = ofnode_get_property(trips_np, "type", NULL);
 421                if (!type)
 422                        continue;
 423                if (!strcmp(type, "critical"))
 424                        pdata->critical = ofnode_read_u32_default(trips_np, "temperature", 85);
 425                else if (strcmp(type, "passive") == 0)
 426                        pdata->alert = ofnode_read_u32_default(trips_np, "temperature", 80);
 427                else
 428                        continue;
 429        }
 430
 431        debug("id %d polling_delay %d, critical %d, alert %d\n",
 432              pdata->id, pdata->polling_delay, pdata->critical, pdata->alert);
 433
 434        return 0;
 435}
 436
 437static int imx_tmu_probe(struct udevice *dev)
 438{
 439        struct imx_tmu_plat *pdata = dev_get_plat(dev);
 440        int ret;
 441
 442        ret = imx_tmu_parse_fdt(dev);
 443        if (ret) {
 444                printf("Error in parsing TMU FDT %d\n", ret);
 445                return ret;
 446        }
 447
 448        if (pdata->zone_node) {
 449                imx_tmu_init(dev);
 450                imx_tmu_calibration(dev);
 451                imx_tmu_enable_msite(dev);
 452        } else {
 453                imx_tmu_enable_msite(dev);
 454        }
 455
 456        return 0;
 457}
 458
 459static const struct udevice_id imx_tmu_ids[] = {
 460        { .compatible = "fsl,imx8mq-tmu", },
 461        { .compatible = "fsl,imx8mm-tmu", .data = FLAGS_VER2, },
 462        { .compatible = "fsl,imx8mp-tmu", .data = FLAGS_VER3, },
 463        { }
 464};
 465
 466U_BOOT_DRIVER(imx_tmu) = {
 467        .name   = "imx_tmu",
 468        .id     = UCLASS_THERMAL,
 469        .ops    = &imx_tmu_ops,
 470        .of_match = imx_tmu_ids,
 471        .bind = imx_tmu_bind,
 472        .probe  = imx_tmu_probe,
 473        .plat_auto      = sizeof(struct imx_tmu_plat),
 474        .flags  = DM_FLAG_PRE_RELOC,
 475};
 476