mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-10 23:24:38 +00:00
caa4daa2ae
We use 'priv' for private data but often use 'platdata' for platform data. We can't really use 'pdata' since that is ambiguous (it could mean private or platform data). Rename some of the latter variables to end with 'plat' for consistency. Signed-off-by: Simon Glass <sjg@chromium.org>
216 lines
5 KiB
C
216 lines
5 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Copyright 2019 NXP
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <common.h>
|
|
#include <dm.h>
|
|
#include <errno.h>
|
|
#include <log.h>
|
|
#include <thermal.h>
|
|
#include <dm/device-internal.h>
|
|
#include <dm/device.h>
|
|
#include <asm/arch/sci/sci.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/libfdt.h>
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
struct imx_sc_thermal_plat {
|
|
int critical;
|
|
int alert;
|
|
int polling_delay;
|
|
int id;
|
|
bool zone_node;
|
|
};
|
|
|
|
static int read_temperature(struct udevice *dev, int *temp)
|
|
{
|
|
s16 celsius;
|
|
s8 tenths;
|
|
int ret;
|
|
|
|
sc_rsrc_t *sensor_rsrc = (sc_rsrc_t *)dev_get_driver_data(dev);
|
|
|
|
struct imx_sc_thermal_plat *pdata = dev_get_platdata(dev);
|
|
|
|
if (!temp)
|
|
return -EINVAL;
|
|
|
|
ret = sc_misc_get_temp(-1, sensor_rsrc[pdata->id], SC_C_TEMP,
|
|
&celsius, &tenths);
|
|
if (ret) {
|
|
printf("Error: get temperature failed! (error = %d)\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
*temp = celsius * 1000 + tenths * 100;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int imx_sc_thermal_get_temp(struct udevice *dev, int *temp)
|
|
{
|
|
struct imx_sc_thermal_plat *pdata = dev_get_platdata(dev);
|
|
int cpu_temp = 0;
|
|
int ret;
|
|
|
|
ret = read_temperature(dev, &cpu_temp);
|
|
if (ret)
|
|
return ret;
|
|
|
|
while (cpu_temp >= pdata->alert) {
|
|
printf("CPU Temperature (%dC) beyond alert (%dC), close to critical (%dC)",
|
|
cpu_temp, pdata->alert, pdata->critical);
|
|
puts(" waiting...\n");
|
|
mdelay(pdata->polling_delay);
|
|
ret = read_temperature(dev, &cpu_temp);
|
|
if (ret)
|
|
return ret;
|
|
if (cpu_temp >= pdata->alert && !pdata->alert)
|
|
break;
|
|
}
|
|
|
|
*temp = cpu_temp / 1000;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct dm_thermal_ops imx_sc_thermal_ops = {
|
|
.get_temp = imx_sc_thermal_get_temp,
|
|
};
|
|
|
|
static int imx_sc_thermal_probe(struct udevice *dev)
|
|
{
|
|
debug("%s dev name %s\n", __func__, dev->name);
|
|
return 0;
|
|
}
|
|
|
|
static int imx_sc_thermal_bind(struct udevice *dev)
|
|
{
|
|
struct imx_sc_thermal_plat *pdata = dev_get_platdata(dev);
|
|
int reg, ret;
|
|
int offset;
|
|
const char *name;
|
|
const void *prop;
|
|
|
|
debug("%s dev name %s\n", __func__, dev->name);
|
|
|
|
prop = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "compatible",
|
|
NULL);
|
|
if (!prop)
|
|
return 0;
|
|
|
|
pdata->zone_node = 1;
|
|
|
|
reg = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "tsens-num", 0);
|
|
if (reg == 0) {
|
|
printf("%s: no temp sensor number provided!\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
offset = fdt_subnode_offset(gd->fdt_blob, 0, "thermal-zones");
|
|
fdt_for_each_subnode(offset, gd->fdt_blob, offset) {
|
|
/* Bind the subnode to this driver */
|
|
name = fdt_get_name(gd->fdt_blob, offset, NULL);
|
|
|
|
ret = device_bind_with_driver_data(dev, dev->driver, name,
|
|
dev->driver_data,
|
|
offset_to_ofnode(offset),
|
|
NULL);
|
|
if (ret)
|
|
printf("Error binding driver '%s': %d\n",
|
|
dev->driver->name, ret);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int imx_sc_thermal_ofdata_to_platdata(struct udevice *dev)
|
|
{
|
|
struct imx_sc_thermal_plat *pdata = dev_get_platdata(dev);
|
|
struct fdtdec_phandle_args args;
|
|
const char *type;
|
|
int ret;
|
|
int trips_np;
|
|
|
|
debug("%s dev name %s\n", __func__, dev->name);
|
|
|
|
if (pdata->zone_node)
|
|
return 0;
|
|
|
|
ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev_of_offset(dev),
|
|
"thermal-sensors",
|
|
"#thermal-sensor-cells",
|
|
0, 0, &args);
|
|
if (ret)
|
|
return ret;
|
|
|
|
if (args.node != dev_of_offset(dev->parent))
|
|
return -EFAULT;
|
|
|
|
if (args.args_count >= 1)
|
|
pdata->id = args.args[0];
|
|
else
|
|
pdata->id = 0;
|
|
|
|
debug("args.args_count %d, id %d\n", args.args_count, pdata->id);
|
|
|
|
pdata->polling_delay = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
|
|
"polling-delay", 1000);
|
|
|
|
trips_np = fdt_subnode_offset(gd->fdt_blob, dev_of_offset(dev),
|
|
"trips");
|
|
fdt_for_each_subnode(trips_np, gd->fdt_blob, trips_np) {
|
|
type = fdt_getprop(gd->fdt_blob, trips_np, "type", NULL);
|
|
if (type) {
|
|
if (strcmp(type, "critical") == 0) {
|
|
pdata->critical = fdtdec_get_int(gd->fdt_blob,
|
|
trips_np,
|
|
"temperature",
|
|
85);
|
|
} else if (strcmp(type, "passive") == 0) {
|
|
pdata->alert = fdtdec_get_int(gd->fdt_blob,
|
|
trips_np,
|
|
"temperature",
|
|
80);
|
|
}
|
|
}
|
|
}
|
|
|
|
debug("id %d polling_delay %d, critical %d, alert %d\n", pdata->id,
|
|
pdata->polling_delay, pdata->critical, pdata->alert);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const sc_rsrc_t imx8qm_sensor_rsrc[] = {
|
|
SC_R_A53, SC_R_A72, SC_R_GPU_0_PID0, SC_R_GPU_1_PID0,
|
|
SC_R_DRC_0, SC_R_DRC_1, SC_R_VPU_PID0, SC_R_PMIC_0,
|
|
SC_R_PMIC_1, SC_R_PMIC_2,
|
|
};
|
|
|
|
static const sc_rsrc_t imx8qxp_sensor_rsrc[] = {
|
|
SC_R_SYSTEM, SC_R_DRC_0, SC_R_PMIC_0,
|
|
SC_R_PMIC_1, SC_R_PMIC_2,
|
|
};
|
|
|
|
static const struct udevice_id imx_sc_thermal_ids[] = {
|
|
{ .compatible = "nxp,imx8qm-sc-tsens", .data =
|
|
(ulong)&imx8qm_sensor_rsrc, },
|
|
{ .compatible = "nxp,imx8qxp-sc-tsens", .data =
|
|
(ulong)&imx8qxp_sensor_rsrc, },
|
|
{ }
|
|
};
|
|
|
|
U_BOOT_DRIVER(imx_sc_thermal) = {
|
|
.name = "imx_sc_thermal",
|
|
.id = UCLASS_THERMAL,
|
|
.ops = &imx_sc_thermal_ops,
|
|
.of_match = imx_sc_thermal_ids,
|
|
.bind = imx_sc_thermal_bind,
|
|
.probe = imx_sc_thermal_probe,
|
|
.ofdata_to_platdata = imx_sc_thermal_ofdata_to_platdata,
|
|
.plat_auto = sizeof(struct imx_sc_thermal_plat),
|
|
.flags = DM_FLAG_PRE_RELOC,
|
|
};
|