xref: /openbmc/qemu/hw/misc/bcm2835_thermal.c (revision 99c641370b52348b2893b2cd19624bf9a416ccfa)
1*99c64137SPhilippe Mathieu-Daudé /*
2*99c64137SPhilippe Mathieu-Daudé  * BCM2835 dummy thermal sensor
3*99c64137SPhilippe Mathieu-Daudé  *
4*99c64137SPhilippe Mathieu-Daudé  * Copyright (C) 2019 Philippe Mathieu-Daudé <f4bug@amsat.org>
5*99c64137SPhilippe Mathieu-Daudé  *
6*99c64137SPhilippe Mathieu-Daudé  * SPDX-License-Identifier: GPL-2.0-or-later
7*99c64137SPhilippe Mathieu-Daudé  */
8*99c64137SPhilippe Mathieu-Daudé 
9*99c64137SPhilippe Mathieu-Daudé #include "qemu/osdep.h"
10*99c64137SPhilippe Mathieu-Daudé #include "qemu/log.h"
11*99c64137SPhilippe Mathieu-Daudé #include "qapi/error.h"
12*99c64137SPhilippe Mathieu-Daudé #include "hw/misc/bcm2835_thermal.h"
13*99c64137SPhilippe Mathieu-Daudé #include "hw/registerfields.h"
14*99c64137SPhilippe Mathieu-Daudé #include "migration/vmstate.h"
15*99c64137SPhilippe Mathieu-Daudé 
16*99c64137SPhilippe Mathieu-Daudé REG32(CTL, 0)
17*99c64137SPhilippe Mathieu-Daudé FIELD(CTL, POWER_DOWN, 0, 1)
18*99c64137SPhilippe Mathieu-Daudé FIELD(CTL, RESET, 1, 1)
19*99c64137SPhilippe Mathieu-Daudé FIELD(CTL, BANDGAP_CTRL, 2, 3)
20*99c64137SPhilippe Mathieu-Daudé FIELD(CTL, INTERRUPT_ENABLE, 5, 1)
21*99c64137SPhilippe Mathieu-Daudé FIELD(CTL, DIRECT, 6, 1)
22*99c64137SPhilippe Mathieu-Daudé FIELD(CTL, INTERRUPT_CLEAR, 7, 1)
23*99c64137SPhilippe Mathieu-Daudé FIELD(CTL, HOLD, 8, 10)
24*99c64137SPhilippe Mathieu-Daudé FIELD(CTL, RESET_DELAY, 18, 8)
25*99c64137SPhilippe Mathieu-Daudé FIELD(CTL, REGULATOR_ENABLE, 26, 1)
26*99c64137SPhilippe Mathieu-Daudé 
27*99c64137SPhilippe Mathieu-Daudé REG32(STAT, 4)
28*99c64137SPhilippe Mathieu-Daudé FIELD(STAT, DATA, 0, 10)
29*99c64137SPhilippe Mathieu-Daudé FIELD(STAT, VALID, 10, 1)
30*99c64137SPhilippe Mathieu-Daudé FIELD(STAT, INTERRUPT, 11, 1)
31*99c64137SPhilippe Mathieu-Daudé 
32*99c64137SPhilippe Mathieu-Daudé #define THERMAL_OFFSET_C 412
33*99c64137SPhilippe Mathieu-Daudé #define THERMAL_COEFF  (-0.538f)
34*99c64137SPhilippe Mathieu-Daudé 
35*99c64137SPhilippe Mathieu-Daudé static uint16_t bcm2835_thermal_temp2adc(int temp_C)
36*99c64137SPhilippe Mathieu-Daudé {
37*99c64137SPhilippe Mathieu-Daudé     return (temp_C - THERMAL_OFFSET_C) / THERMAL_COEFF;
38*99c64137SPhilippe Mathieu-Daudé }
39*99c64137SPhilippe Mathieu-Daudé 
40*99c64137SPhilippe Mathieu-Daudé static uint64_t bcm2835_thermal_read(void *opaque, hwaddr addr, unsigned size)
41*99c64137SPhilippe Mathieu-Daudé {
42*99c64137SPhilippe Mathieu-Daudé     Bcm2835ThermalState *s = BCM2835_THERMAL(opaque);
43*99c64137SPhilippe Mathieu-Daudé     uint32_t val = 0;
44*99c64137SPhilippe Mathieu-Daudé 
45*99c64137SPhilippe Mathieu-Daudé     switch (addr) {
46*99c64137SPhilippe Mathieu-Daudé     case A_CTL:
47*99c64137SPhilippe Mathieu-Daudé         val = s->ctl;
48*99c64137SPhilippe Mathieu-Daudé         break;
49*99c64137SPhilippe Mathieu-Daudé     case A_STAT:
50*99c64137SPhilippe Mathieu-Daudé         /* Temperature is constantly 25°C. */
51*99c64137SPhilippe Mathieu-Daudé         val = FIELD_DP32(bcm2835_thermal_temp2adc(25), STAT, VALID, true);
52*99c64137SPhilippe Mathieu-Daudé         break;
53*99c64137SPhilippe Mathieu-Daudé     default:
54*99c64137SPhilippe Mathieu-Daudé         /* MemoryRegionOps are aligned, so this can not happen. */
55*99c64137SPhilippe Mathieu-Daudé         g_assert_not_reached();
56*99c64137SPhilippe Mathieu-Daudé     }
57*99c64137SPhilippe Mathieu-Daudé     return val;
58*99c64137SPhilippe Mathieu-Daudé }
59*99c64137SPhilippe Mathieu-Daudé 
60*99c64137SPhilippe Mathieu-Daudé static void bcm2835_thermal_write(void *opaque, hwaddr addr,
61*99c64137SPhilippe Mathieu-Daudé                                   uint64_t value, unsigned size)
62*99c64137SPhilippe Mathieu-Daudé {
63*99c64137SPhilippe Mathieu-Daudé     Bcm2835ThermalState *s = BCM2835_THERMAL(opaque);
64*99c64137SPhilippe Mathieu-Daudé 
65*99c64137SPhilippe Mathieu-Daudé     switch (addr) {
66*99c64137SPhilippe Mathieu-Daudé     case A_CTL:
67*99c64137SPhilippe Mathieu-Daudé         s->ctl = value;
68*99c64137SPhilippe Mathieu-Daudé         break;
69*99c64137SPhilippe Mathieu-Daudé     case A_STAT:
70*99c64137SPhilippe Mathieu-Daudé         qemu_log_mask(LOG_GUEST_ERROR, "%s: write 0x%" PRIx64
71*99c64137SPhilippe Mathieu-Daudé                                        " to 0x%" HWADDR_PRIx "\n",
72*99c64137SPhilippe Mathieu-Daudé                        __func__, value, addr);
73*99c64137SPhilippe Mathieu-Daudé         break;
74*99c64137SPhilippe Mathieu-Daudé     default:
75*99c64137SPhilippe Mathieu-Daudé         /* MemoryRegionOps are aligned, so this can not happen. */
76*99c64137SPhilippe Mathieu-Daudé         g_assert_not_reached();
77*99c64137SPhilippe Mathieu-Daudé     }
78*99c64137SPhilippe Mathieu-Daudé }
79*99c64137SPhilippe Mathieu-Daudé 
80*99c64137SPhilippe Mathieu-Daudé static const MemoryRegionOps bcm2835_thermal_ops = {
81*99c64137SPhilippe Mathieu-Daudé     .read = bcm2835_thermal_read,
82*99c64137SPhilippe Mathieu-Daudé     .write = bcm2835_thermal_write,
83*99c64137SPhilippe Mathieu-Daudé     .impl.max_access_size = 4,
84*99c64137SPhilippe Mathieu-Daudé     .valid.min_access_size = 4,
85*99c64137SPhilippe Mathieu-Daudé     .endianness = DEVICE_NATIVE_ENDIAN,
86*99c64137SPhilippe Mathieu-Daudé };
87*99c64137SPhilippe Mathieu-Daudé 
88*99c64137SPhilippe Mathieu-Daudé static void bcm2835_thermal_reset(DeviceState *dev)
89*99c64137SPhilippe Mathieu-Daudé {
90*99c64137SPhilippe Mathieu-Daudé     Bcm2835ThermalState *s = BCM2835_THERMAL(dev);
91*99c64137SPhilippe Mathieu-Daudé 
92*99c64137SPhilippe Mathieu-Daudé     s->ctl = 0;
93*99c64137SPhilippe Mathieu-Daudé }
94*99c64137SPhilippe Mathieu-Daudé 
95*99c64137SPhilippe Mathieu-Daudé static void bcm2835_thermal_realize(DeviceState *dev, Error **errp)
96*99c64137SPhilippe Mathieu-Daudé {
97*99c64137SPhilippe Mathieu-Daudé     Bcm2835ThermalState *s = BCM2835_THERMAL(dev);
98*99c64137SPhilippe Mathieu-Daudé 
99*99c64137SPhilippe Mathieu-Daudé     memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_thermal_ops,
100*99c64137SPhilippe Mathieu-Daudé                           s, TYPE_BCM2835_THERMAL, 8);
101*99c64137SPhilippe Mathieu-Daudé     sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
102*99c64137SPhilippe Mathieu-Daudé }
103*99c64137SPhilippe Mathieu-Daudé 
104*99c64137SPhilippe Mathieu-Daudé static const VMStateDescription bcm2835_thermal_vmstate = {
105*99c64137SPhilippe Mathieu-Daudé     .name = "bcm2835_thermal",
106*99c64137SPhilippe Mathieu-Daudé     .version_id = 1,
107*99c64137SPhilippe Mathieu-Daudé     .minimum_version_id = 1,
108*99c64137SPhilippe Mathieu-Daudé     .fields = (VMStateField[]) {
109*99c64137SPhilippe Mathieu-Daudé         VMSTATE_UINT32(ctl, Bcm2835ThermalState),
110*99c64137SPhilippe Mathieu-Daudé         VMSTATE_END_OF_LIST()
111*99c64137SPhilippe Mathieu-Daudé     }
112*99c64137SPhilippe Mathieu-Daudé };
113*99c64137SPhilippe Mathieu-Daudé 
114*99c64137SPhilippe Mathieu-Daudé static void bcm2835_thermal_class_init(ObjectClass *klass, void *data)
115*99c64137SPhilippe Mathieu-Daudé {
116*99c64137SPhilippe Mathieu-Daudé     DeviceClass *dc = DEVICE_CLASS(klass);
117*99c64137SPhilippe Mathieu-Daudé 
118*99c64137SPhilippe Mathieu-Daudé     dc->realize = bcm2835_thermal_realize;
119*99c64137SPhilippe Mathieu-Daudé     dc->reset = bcm2835_thermal_reset;
120*99c64137SPhilippe Mathieu-Daudé     dc->vmsd = &bcm2835_thermal_vmstate;
121*99c64137SPhilippe Mathieu-Daudé }
122*99c64137SPhilippe Mathieu-Daudé 
123*99c64137SPhilippe Mathieu-Daudé static const TypeInfo bcm2835_thermal_info = {
124*99c64137SPhilippe Mathieu-Daudé     .name = TYPE_BCM2835_THERMAL,
125*99c64137SPhilippe Mathieu-Daudé     .parent = TYPE_SYS_BUS_DEVICE,
126*99c64137SPhilippe Mathieu-Daudé     .instance_size = sizeof(Bcm2835ThermalState),
127*99c64137SPhilippe Mathieu-Daudé     .class_init = bcm2835_thermal_class_init,
128*99c64137SPhilippe Mathieu-Daudé };
129*99c64137SPhilippe Mathieu-Daudé 
130*99c64137SPhilippe Mathieu-Daudé static void bcm2835_thermal_register_types(void)
131*99c64137SPhilippe Mathieu-Daudé {
132*99c64137SPhilippe Mathieu-Daudé     type_register_static(&bcm2835_thermal_info);
133*99c64137SPhilippe Mathieu-Daudé }
134*99c64137SPhilippe Mathieu-Daudé 
135*99c64137SPhilippe Mathieu-Daudé type_init(bcm2835_thermal_register_types)
136