xref: /openbmc/qemu/hw/misc/bcm2835_thermal.c (revision 28ae3179fc52d2e4d870b635c4a412aab99759e7)
199c64137SPhilippe Mathieu-Daudé /*
299c64137SPhilippe Mathieu-Daudé  * BCM2835 dummy thermal sensor
399c64137SPhilippe Mathieu-Daudé  *
499c64137SPhilippe Mathieu-Daudé  * Copyright (C) 2019 Philippe Mathieu-Daudé <f4bug@amsat.org>
599c64137SPhilippe Mathieu-Daudé  *
699c64137SPhilippe Mathieu-Daudé  * SPDX-License-Identifier: GPL-2.0-or-later
799c64137SPhilippe Mathieu-Daudé  */
899c64137SPhilippe Mathieu-Daudé 
999c64137SPhilippe Mathieu-Daudé #include "qemu/osdep.h"
1099c64137SPhilippe Mathieu-Daudé #include "qemu/log.h"
1199c64137SPhilippe Mathieu-Daudé #include "qapi/error.h"
1299c64137SPhilippe Mathieu-Daudé #include "hw/misc/bcm2835_thermal.h"
1399c64137SPhilippe Mathieu-Daudé #include "hw/registerfields.h"
1499c64137SPhilippe Mathieu-Daudé #include "migration/vmstate.h"
1599c64137SPhilippe Mathieu-Daudé 
1699c64137SPhilippe Mathieu-Daudé REG32(CTL, 0)
1799c64137SPhilippe Mathieu-Daudé FIELD(CTL, POWER_DOWN, 0, 1)
1899c64137SPhilippe Mathieu-Daudé FIELD(CTL, RESET, 1, 1)
1999c64137SPhilippe Mathieu-Daudé FIELD(CTL, BANDGAP_CTRL, 2, 3)
2099c64137SPhilippe Mathieu-Daudé FIELD(CTL, INTERRUPT_ENABLE, 5, 1)
2199c64137SPhilippe Mathieu-Daudé FIELD(CTL, DIRECT, 6, 1)
2299c64137SPhilippe Mathieu-Daudé FIELD(CTL, INTERRUPT_CLEAR, 7, 1)
2399c64137SPhilippe Mathieu-Daudé FIELD(CTL, HOLD, 8, 10)
2499c64137SPhilippe Mathieu-Daudé FIELD(CTL, RESET_DELAY, 18, 8)
2599c64137SPhilippe Mathieu-Daudé FIELD(CTL, REGULATOR_ENABLE, 26, 1)
2699c64137SPhilippe Mathieu-Daudé 
2799c64137SPhilippe Mathieu-Daudé REG32(STAT, 4)
2899c64137SPhilippe Mathieu-Daudé FIELD(STAT, DATA, 0, 10)
2999c64137SPhilippe Mathieu-Daudé FIELD(STAT, VALID, 10, 1)
3099c64137SPhilippe Mathieu-Daudé FIELD(STAT, INTERRUPT, 11, 1)
3199c64137SPhilippe Mathieu-Daudé 
3299c64137SPhilippe Mathieu-Daudé #define THERMAL_OFFSET_C 412
3399c64137SPhilippe Mathieu-Daudé #define THERMAL_COEFF  (-0.538f)
3499c64137SPhilippe Mathieu-Daudé 
bcm2835_thermal_temp2adc(int temp_C)3599c64137SPhilippe Mathieu-Daudé static uint16_t bcm2835_thermal_temp2adc(int temp_C)
3699c64137SPhilippe Mathieu-Daudé {
3799c64137SPhilippe Mathieu-Daudé     return (temp_C - THERMAL_OFFSET_C) / THERMAL_COEFF;
3899c64137SPhilippe Mathieu-Daudé }
3999c64137SPhilippe Mathieu-Daudé 
bcm2835_thermal_read(void * opaque,hwaddr addr,unsigned size)4099c64137SPhilippe Mathieu-Daudé static uint64_t bcm2835_thermal_read(void *opaque, hwaddr addr, unsigned size)
4199c64137SPhilippe Mathieu-Daudé {
4299c64137SPhilippe Mathieu-Daudé     Bcm2835ThermalState *s = BCM2835_THERMAL(opaque);
4399c64137SPhilippe Mathieu-Daudé     uint32_t val = 0;
4499c64137SPhilippe Mathieu-Daudé 
4599c64137SPhilippe Mathieu-Daudé     switch (addr) {
4699c64137SPhilippe Mathieu-Daudé     case A_CTL:
4799c64137SPhilippe Mathieu-Daudé         val = s->ctl;
4899c64137SPhilippe Mathieu-Daudé         break;
4999c64137SPhilippe Mathieu-Daudé     case A_STAT:
5099c64137SPhilippe Mathieu-Daudé         /* Temperature is constantly 25°C. */
5199c64137SPhilippe Mathieu-Daudé         val = FIELD_DP32(bcm2835_thermal_temp2adc(25), STAT, VALID, true);
5299c64137SPhilippe Mathieu-Daudé         break;
5399c64137SPhilippe Mathieu-Daudé     default:
5499c64137SPhilippe Mathieu-Daudé         /* MemoryRegionOps are aligned, so this can not happen. */
5599c64137SPhilippe Mathieu-Daudé         g_assert_not_reached();
5699c64137SPhilippe Mathieu-Daudé     }
5799c64137SPhilippe Mathieu-Daudé     return val;
5899c64137SPhilippe Mathieu-Daudé }
5999c64137SPhilippe Mathieu-Daudé 
bcm2835_thermal_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)6099c64137SPhilippe Mathieu-Daudé static void bcm2835_thermal_write(void *opaque, hwaddr addr,
6199c64137SPhilippe Mathieu-Daudé                                   uint64_t value, unsigned size)
6299c64137SPhilippe Mathieu-Daudé {
6399c64137SPhilippe Mathieu-Daudé     Bcm2835ThermalState *s = BCM2835_THERMAL(opaque);
6499c64137SPhilippe Mathieu-Daudé 
6599c64137SPhilippe Mathieu-Daudé     switch (addr) {
6699c64137SPhilippe Mathieu-Daudé     case A_CTL:
6799c64137SPhilippe Mathieu-Daudé         s->ctl = value;
6899c64137SPhilippe Mathieu-Daudé         break;
6999c64137SPhilippe Mathieu-Daudé     case A_STAT:
7099c64137SPhilippe Mathieu-Daudé         qemu_log_mask(LOG_GUEST_ERROR, "%s: write 0x%" PRIx64
7199c64137SPhilippe Mathieu-Daudé                                        " to 0x%" HWADDR_PRIx "\n",
7299c64137SPhilippe Mathieu-Daudé                        __func__, value, addr);
7399c64137SPhilippe Mathieu-Daudé         break;
7499c64137SPhilippe Mathieu-Daudé     default:
7599c64137SPhilippe Mathieu-Daudé         /* MemoryRegionOps are aligned, so this can not happen. */
7699c64137SPhilippe Mathieu-Daudé         g_assert_not_reached();
7799c64137SPhilippe Mathieu-Daudé     }
7899c64137SPhilippe Mathieu-Daudé }
7999c64137SPhilippe Mathieu-Daudé 
8099c64137SPhilippe Mathieu-Daudé static const MemoryRegionOps bcm2835_thermal_ops = {
8199c64137SPhilippe Mathieu-Daudé     .read = bcm2835_thermal_read,
8299c64137SPhilippe Mathieu-Daudé     .write = bcm2835_thermal_write,
837b11e7cfSZheyu Ma     .impl.min_access_size = 4,
8499c64137SPhilippe Mathieu-Daudé     .impl.max_access_size = 4,
8599c64137SPhilippe Mathieu-Daudé     .valid.min_access_size = 4,
867b11e7cfSZheyu Ma     .valid.max_access_size = 4,
8799c64137SPhilippe Mathieu-Daudé     .endianness = DEVICE_NATIVE_ENDIAN,
8899c64137SPhilippe Mathieu-Daudé };
8999c64137SPhilippe Mathieu-Daudé 
bcm2835_thermal_reset(DeviceState * dev)9099c64137SPhilippe Mathieu-Daudé static void bcm2835_thermal_reset(DeviceState *dev)
9199c64137SPhilippe Mathieu-Daudé {
9299c64137SPhilippe Mathieu-Daudé     Bcm2835ThermalState *s = BCM2835_THERMAL(dev);
9399c64137SPhilippe Mathieu-Daudé 
9499c64137SPhilippe Mathieu-Daudé     s->ctl = 0;
9599c64137SPhilippe Mathieu-Daudé }
9699c64137SPhilippe Mathieu-Daudé 
bcm2835_thermal_realize(DeviceState * dev,Error ** errp)9799c64137SPhilippe Mathieu-Daudé static void bcm2835_thermal_realize(DeviceState *dev, Error **errp)
9899c64137SPhilippe Mathieu-Daudé {
9999c64137SPhilippe Mathieu-Daudé     Bcm2835ThermalState *s = BCM2835_THERMAL(dev);
10099c64137SPhilippe Mathieu-Daudé 
10199c64137SPhilippe Mathieu-Daudé     memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_thermal_ops,
10299c64137SPhilippe Mathieu-Daudé                           s, TYPE_BCM2835_THERMAL, 8);
10399c64137SPhilippe Mathieu-Daudé     sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
10499c64137SPhilippe Mathieu-Daudé }
10599c64137SPhilippe Mathieu-Daudé 
10699c64137SPhilippe Mathieu-Daudé static const VMStateDescription bcm2835_thermal_vmstate = {
10799c64137SPhilippe Mathieu-Daudé     .name = "bcm2835_thermal",
10899c64137SPhilippe Mathieu-Daudé     .version_id = 1,
10999c64137SPhilippe Mathieu-Daudé     .minimum_version_id = 1,
110e4ea952fSRichard Henderson     .fields = (const VMStateField[]) {
11199c64137SPhilippe Mathieu-Daudé         VMSTATE_UINT32(ctl, Bcm2835ThermalState),
11299c64137SPhilippe Mathieu-Daudé         VMSTATE_END_OF_LIST()
11399c64137SPhilippe Mathieu-Daudé     }
11499c64137SPhilippe Mathieu-Daudé };
11599c64137SPhilippe Mathieu-Daudé 
bcm2835_thermal_class_init(ObjectClass * klass,void * data)11699c64137SPhilippe Mathieu-Daudé static void bcm2835_thermal_class_init(ObjectClass *klass, void *data)
11799c64137SPhilippe Mathieu-Daudé {
11899c64137SPhilippe Mathieu-Daudé     DeviceClass *dc = DEVICE_CLASS(klass);
11999c64137SPhilippe Mathieu-Daudé 
12099c64137SPhilippe Mathieu-Daudé     dc->realize = bcm2835_thermal_realize;
121*e3d08143SPeter Maydell     device_class_set_legacy_reset(dc, bcm2835_thermal_reset);
12299c64137SPhilippe Mathieu-Daudé     dc->vmsd = &bcm2835_thermal_vmstate;
12399c64137SPhilippe Mathieu-Daudé }
12499c64137SPhilippe Mathieu-Daudé 
12599c64137SPhilippe Mathieu-Daudé static const TypeInfo bcm2835_thermal_info = {
12699c64137SPhilippe Mathieu-Daudé     .name = TYPE_BCM2835_THERMAL,
12799c64137SPhilippe Mathieu-Daudé     .parent = TYPE_SYS_BUS_DEVICE,
12899c64137SPhilippe Mathieu-Daudé     .instance_size = sizeof(Bcm2835ThermalState),
12999c64137SPhilippe Mathieu-Daudé     .class_init = bcm2835_thermal_class_init,
13099c64137SPhilippe Mathieu-Daudé };
13199c64137SPhilippe Mathieu-Daudé 
bcm2835_thermal_register_types(void)13299c64137SPhilippe Mathieu-Daudé static void bcm2835_thermal_register_types(void)
13399c64137SPhilippe Mathieu-Daudé {
13499c64137SPhilippe Mathieu-Daudé     type_register_static(&bcm2835_thermal_info);
13599c64137SPhilippe Mathieu-Daudé }
13699c64137SPhilippe Mathieu-Daudé 
13799c64137SPhilippe Mathieu-Daudé type_init(bcm2835_thermal_register_types)
138