uboot/drivers/thermal/imx_scu_thermal.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright 2019 NXP
   4 */
   5
   6#include <config.h>
   7#include <common.h>
   8#include <dm.h>
   9#include <errno.h>
  10#include <log.h>
  11#include <thermal.h>
  12#include <asm/global_data.h>
  13#include <dm/device-internal.h>
  14#include <dm/device.h>
  15#include <asm/arch/sci/sci.h>
  16#include <linux/delay.h>
  17#include <linux/libfdt.h>
  18
  19DECLARE_GLOBAL_DATA_PTR;
  20
  21struct imx_sc_thermal_plat {
  22        int critical;
  23        int alert;
  24        int polling_delay;
  25        int id;
  26        bool zone_node;
  27};
  28
  29static int read_temperature(struct udevice *dev, int *temp)
  30{
  31        s16 celsius;
  32        s8 tenths;
  33        int ret;
  34
  35        sc_rsrc_t *sensor_rsrc = (sc_rsrc_t *)dev_get_driver_data(dev);
  36
  37        struct imx_sc_thermal_plat *pdata = dev_get_plat(dev);
  38
  39        if (!temp)
  40                return -EINVAL;
  41
  42        ret = sc_misc_get_temp(-1, sensor_rsrc[pdata->id], SC_C_TEMP,
  43                               &celsius, &tenths);
  44        if (ret) {
  45                printf("Error: get temperature failed! (error = %d)\n", ret);
  46                return ret;
  47        }
  48
  49        *temp = celsius * 1000 + tenths * 100;
  50
  51        return 0;
  52}
  53
  54int imx_sc_thermal_get_temp(struct udevice *dev, int *temp)
  55{
  56        struct imx_sc_thermal_plat *pdata = dev_get_plat(dev);
  57        int cpu_temp = 0;
  58        int ret;
  59
  60        ret = read_temperature(dev, &cpu_temp);
  61        if (ret)
  62                return ret;
  63
  64        while (cpu_temp >= pdata->alert) {
  65                printf("CPU Temperature (%dC) beyond alert (%dC), close to critical (%dC)",
  66                       cpu_temp, pdata->alert, pdata->critical);
  67                puts(" waiting...\n");
  68                mdelay(pdata->polling_delay);
  69                ret = read_temperature(dev, &cpu_temp);
  70                if (ret)
  71                        return ret;
  72                if (cpu_temp >= pdata->alert && !pdata->alert)
  73                        break;
  74        }
  75
  76        *temp = cpu_temp / 1000;
  77
  78        return 0;
  79}
  80
  81static const struct dm_thermal_ops imx_sc_thermal_ops = {
  82        .get_temp       = imx_sc_thermal_get_temp,
  83};
  84
  85static int imx_sc_thermal_probe(struct udevice *dev)
  86{
  87        debug("%s dev name %s\n", __func__, dev->name);
  88        return 0;
  89}
  90
  91static int imx_sc_thermal_bind(struct udevice *dev)
  92{
  93        struct imx_sc_thermal_plat *pdata = dev_get_plat(dev);
  94        int reg, ret;
  95        int offset;
  96        const char *name;
  97        const void *prop;
  98
  99        debug("%s dev name %s\n", __func__, dev->name);
 100
 101        prop = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "compatible",
 102                           NULL);
 103        if (!prop)
 104                return 0;
 105
 106        pdata->zone_node = 1;
 107
 108        reg = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "tsens-num", 0);
 109        if (reg == 0) {
 110                printf("%s: no temp sensor number provided!\n", __func__);
 111                return -EINVAL;
 112        }
 113
 114        offset = fdt_subnode_offset(gd->fdt_blob, 0, "thermal-zones");
 115        fdt_for_each_subnode(offset, gd->fdt_blob, offset) {
 116                /* Bind the subnode to this driver */
 117                name = fdt_get_name(gd->fdt_blob, offset, NULL);
 118
 119                ret = device_bind_with_driver_data(dev, dev->driver, name,
 120                                                   dev->driver_data,
 121                                                   offset_to_ofnode(offset),
 122                                                   NULL);
 123                if (ret)
 124                        printf("Error binding driver '%s': %d\n",
 125                               dev->driver->name, ret);
 126        }
 127        return 0;
 128}
 129
 130static int imx_sc_thermal_of_to_plat(struct udevice *dev)
 131{
 132        struct imx_sc_thermal_plat *pdata = dev_get_plat(dev);
 133        struct fdtdec_phandle_args args;
 134        const char *type;
 135        int ret;
 136        int trips_np;
 137
 138        debug("%s dev name %s\n", __func__, dev->name);
 139
 140        if (pdata->zone_node)
 141                return 0;
 142
 143        ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev_of_offset(dev),
 144                                             "thermal-sensors",
 145                                             "#thermal-sensor-cells",
 146                                             0, 0, &args);
 147        if (ret)
 148                return ret;
 149
 150        if (args.node != dev_of_offset(dev->parent))
 151                return -EFAULT;
 152
 153        if (args.args_count >= 1)
 154                pdata->id = args.args[0];
 155        else
 156                pdata->id = 0;
 157
 158        debug("args.args_count %d, id %d\n", args.args_count, pdata->id);
 159
 160        pdata->polling_delay = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
 161                                              "polling-delay", 1000);
 162
 163        trips_np = fdt_subnode_offset(gd->fdt_blob, dev_of_offset(dev),
 164                                      "trips");
 165        fdt_for_each_subnode(trips_np, gd->fdt_blob, trips_np) {
 166                type = fdt_getprop(gd->fdt_blob, trips_np, "type", NULL);
 167                if (type) {
 168                        if (strcmp(type, "critical") == 0) {
 169                                pdata->critical = fdtdec_get_int(gd->fdt_blob,
 170                                                                 trips_np,
 171                                                                 "temperature",
 172                                                                 85);
 173                        } else if (strcmp(type, "passive") == 0) {
 174                                pdata->alert = fdtdec_get_int(gd->fdt_blob,
 175                                                              trips_np,
 176                                                              "temperature",
 177                                                              80);
 178                        }
 179                }
 180        }
 181
 182        debug("id %d polling_delay %d, critical %d, alert %d\n", pdata->id,
 183              pdata->polling_delay, pdata->critical, pdata->alert);
 184
 185        return 0;
 186}
 187
 188static const sc_rsrc_t imx8qm_sensor_rsrc[] = {
 189        SC_R_A53, SC_R_A72, SC_R_GPU_0_PID0, SC_R_GPU_1_PID0,
 190        SC_R_DRC_0, SC_R_DRC_1, SC_R_VPU_PID0, SC_R_PMIC_0,
 191        SC_R_PMIC_1, SC_R_PMIC_2,
 192};
 193
 194static const sc_rsrc_t imx8qxp_sensor_rsrc[] = {
 195        SC_R_SYSTEM, SC_R_DRC_0, SC_R_PMIC_0,
 196        SC_R_PMIC_1, SC_R_PMIC_2,
 197};
 198
 199static const struct udevice_id imx_sc_thermal_ids[] = {
 200        { .compatible = "nxp,imx8qm-sc-tsens", .data =
 201                (ulong)&imx8qm_sensor_rsrc, },
 202        { .compatible = "nxp,imx8qxp-sc-tsens", .data =
 203                (ulong)&imx8qxp_sensor_rsrc, },
 204        { }
 205};
 206
 207U_BOOT_DRIVER(imx_sc_thermal) = {
 208        .name   = "imx_sc_thermal",
 209        .id     = UCLASS_THERMAL,
 210        .ops    = &imx_sc_thermal_ops,
 211        .of_match = imx_sc_thermal_ids,
 212        .bind = imx_sc_thermal_bind,
 213        .probe  = imx_sc_thermal_probe,
 214        .of_to_plat = imx_sc_thermal_of_to_plat,
 215        .plat_auto      = sizeof(struct imx_sc_thermal_plat),
 216        .flags  = DM_FLAG_PRE_RELOC,
 217};
 218