aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilippe Mathieu-Daudé <f4bug@amsat.org>2019-10-20 01:47:00 +0200
committerPeter Maydell <peter.maydell@linaro.org>2019-10-24 17:16:29 +0100
commite81d0270e360de0dd1ca0607b59a5ff3f967b14c (patch)
treebfa3b33833cb66081c34d8ac114c4fca9cc26cb7
parenta54ce80d408295b24ac1f15da8dc67ff6ed01206 (diff)
downloadqemu-arm-e81d0270e360de0dd1ca0607b59a5ff3f967b14c.tar.gz
hw/misc/bcm2835_thermal: Add a dummy BCM2835 thermal sensor
We will soon implement the SYS_timer. This timer is used by Linux in the thermal subsystem, so once available, the subsystem will be enabled and poll the temperature sensors. We need to provide the minimum required to keep Linux booting. Add a dummy thermal sensor returning ~25°C based on: https://github.com/raspberrypi/linux/blob/rpi-5.3.y/drivers/thermal/broadcom/bcm2835_thermal.c Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-id: 20191019234715.25750-2-f4bug@amsat.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--hw/misc/Makefile.objs1
-rw-r--r--hw/misc/bcm2835_thermal.c135
-rw-r--r--include/hw/misc/bcm2835_thermal.h27
3 files changed, 163 insertions, 0 deletions
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index a150680966..c89f3816a5 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -53,6 +53,7 @@ common-obj-$(CONFIG_OMAP) += omap_tap.o
common-obj-$(CONFIG_RASPI) += bcm2835_mbox.o
common-obj-$(CONFIG_RASPI) += bcm2835_property.o
common-obj-$(CONFIG_RASPI) += bcm2835_rng.o
+common-obj-$(CONFIG_RASPI) += bcm2835_thermal.o
common-obj-$(CONFIG_SLAVIO) += slavio_misc.o
common-obj-$(CONFIG_ZYNQ) += zynq_slcr.o
common-obj-$(CONFIG_ZYNQ) += zynq-xadc.o
diff --git a/hw/misc/bcm2835_thermal.c b/hw/misc/bcm2835_thermal.c
new file mode 100644
index 0000000000..c6f3b1ad60
--- /dev/null
+++ b/hw/misc/bcm2835_thermal.c
@@ -0,0 +1,135 @@
+/*
+ * BCM2835 dummy thermal sensor
+ *
+ * Copyright (C) 2019 Philippe Mathieu-Daudé <f4bug@amsat.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+#include "hw/misc/bcm2835_thermal.h"
+#include "hw/registerfields.h"
+#include "migration/vmstate.h"
+
+REG32(CTL, 0)
+FIELD(CTL, POWER_DOWN, 0, 1)
+FIELD(CTL, RESET, 1, 1)
+FIELD(CTL, BANDGAP_CTRL, 2, 3)
+FIELD(CTL, INTERRUPT_ENABLE, 5, 1)
+FIELD(CTL, DIRECT, 6, 1)
+FIELD(CTL, INTERRUPT_CLEAR, 7, 1)
+FIELD(CTL, HOLD, 8, 10)
+FIELD(CTL, RESET_DELAY, 18, 8)
+FIELD(CTL, REGULATOR_ENABLE, 26, 1)
+
+REG32(STAT, 4)
+FIELD(STAT, DATA, 0, 10)
+FIELD(STAT, VALID, 10, 1)
+FIELD(STAT, INTERRUPT, 11, 1)
+
+#define THERMAL_OFFSET_C 412
+#define THERMAL_COEFF (-0.538f)
+
+static uint16_t bcm2835_thermal_temp2adc(int temp_C)
+{
+ return (temp_C - THERMAL_OFFSET_C) / THERMAL_COEFF;
+}
+
+static uint64_t bcm2835_thermal_read(void *opaque, hwaddr addr, unsigned size)
+{
+ Bcm2835ThermalState *s = BCM2835_THERMAL(opaque);
+ uint32_t val = 0;
+
+ switch (addr) {
+ case A_CTL:
+ val = s->ctl;
+ break;
+ case A_STAT:
+ /* Temperature is constantly 25°C. */
+ val = FIELD_DP32(bcm2835_thermal_temp2adc(25), STAT, VALID, true);
+ break;
+ default:
+ /* MemoryRegionOps are aligned, so this can not happen. */
+ g_assert_not_reached();
+ }
+ return val;
+}
+
+static void bcm2835_thermal_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ Bcm2835ThermalState *s = BCM2835_THERMAL(opaque);
+
+ switch (addr) {
+ case A_CTL:
+ s->ctl = value;
+ break;
+ case A_STAT:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: write 0x%" PRIx64
+ " to 0x%" HWADDR_PRIx "\n",
+ __func__, value, addr);
+ break;
+ default:
+ /* MemoryRegionOps are aligned, so this can not happen. */
+ g_assert_not_reached();
+ }
+}
+
+static const MemoryRegionOps bcm2835_thermal_ops = {
+ .read = bcm2835_thermal_read,
+ .write = bcm2835_thermal_write,
+ .impl.max_access_size = 4,
+ .valid.min_access_size = 4,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void bcm2835_thermal_reset(DeviceState *dev)
+{
+ Bcm2835ThermalState *s = BCM2835_THERMAL(dev);
+
+ s->ctl = 0;
+}
+
+static void bcm2835_thermal_realize(DeviceState *dev, Error **errp)
+{
+ Bcm2835ThermalState *s = BCM2835_THERMAL(dev);
+
+ memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_thermal_ops,
+ s, TYPE_BCM2835_THERMAL, 8);
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
+}
+
+static const VMStateDescription bcm2835_thermal_vmstate = {
+ .name = "bcm2835_thermal",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(ctl, Bcm2835ThermalState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void bcm2835_thermal_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = bcm2835_thermal_realize;
+ dc->reset = bcm2835_thermal_reset;
+ dc->vmsd = &bcm2835_thermal_vmstate;
+}
+
+static const TypeInfo bcm2835_thermal_info = {
+ .name = TYPE_BCM2835_THERMAL,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(Bcm2835ThermalState),
+ .class_init = bcm2835_thermal_class_init,
+};
+
+static void bcm2835_thermal_register_types(void)
+{
+ type_register_static(&bcm2835_thermal_info);
+}
+
+type_init(bcm2835_thermal_register_types)
diff --git a/include/hw/misc/bcm2835_thermal.h b/include/hw/misc/bcm2835_thermal.h
new file mode 100644
index 0000000000..c3651b27ec
--- /dev/null
+++ b/include/hw/misc/bcm2835_thermal.h
@@ -0,0 +1,27 @@
+/*
+ * BCM2835 dummy thermal sensor
+ *
+ * Copyright (C) 2019 Philippe Mathieu-Daudé <f4bug@amsat.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_MISC_BCM2835_THERMAL_H
+#define HW_MISC_BCM2835_THERMAL_H
+
+#include "hw/sysbus.h"
+
+#define TYPE_BCM2835_THERMAL "bcm2835-thermal"
+
+#define BCM2835_THERMAL(obj) \
+ OBJECT_CHECK(Bcm2835ThermalState, (obj), TYPE_BCM2835_THERMAL)
+
+typedef struct {
+ /*< private >*/
+ SysBusDevice parent_obj;
+ /*< public >*/
+ MemoryRegion iomem;
+ uint32_t ctl;
+} Bcm2835ThermalState;
+
+#endif