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