1 /* $NetBSD: meson_thermal.c,v 1.7 2024/02/07 04:20:26 msaitoh Exp $ */ 2 3 /* 4 * Copyright (c) 2021 Ryo Shimizu 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 17 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: meson_thermal.c,v 1.7 2024/02/07 04:20:26 msaitoh Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/types.h> 34 #include <sys/bus.h> 35 #include <sys/device.h> 36 37 #include <dev/fdt/fdtvar.h> 38 #include <dev/sysmon/sysmonvar.h> 39 40 #define TS_CFG_REG1 0x01 41 #define TS_CFG_REG1_ANA_EN_VCM __BIT(10) 42 #define TS_CFG_REG1_ANA_EN_VBG __BIT(9) 43 #define TS_CFG_REG1_FILTER_EN __BIT(5) 44 #define TS_CFG_REG1_DEM_EN __BIT(3) 45 #define TS_CFG_REG1_ANA_CH_SEL __BITS(2,0) 46 #define TS_CFG_REG2 0x02 47 #define TS_CFG_REG3 0x03 48 #define TS_CFG_REG4 0x04 49 #define TS_CFG_REG5 0x05 50 #define TS_CFG_REG6 0x06 51 #define TS_CFG_REG7 0x07 52 #define TS_STAT0_REG 0x10 53 #define TS_STAT0_FILTER_OUT __BITS(15,0) 54 #define TS_STAT1_REG 0x11 55 #define TS_STAT2_REG 0x12 56 #define TS_STAT3_REG 0x13 57 #define TS_STAT4_REG 0x14 58 #define TS_STAT5_REG 0x15 59 #define TS_STAT6_REG 0x16 60 #define TS_STAT7_REG 0x17 61 #define TS_STAT8_REG 0x18 62 #define TS_STAT9_REG 0x19 63 64 #define THERMAL_READ_REG(sc, reg) \ 65 bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg) * 4) 66 #define THERMAL_WRITE_REG(sc, reg, val) \ 67 bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg) * 4, (val)) 68 69 #define AOSECURE_READ(sc, reg) \ 70 bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh_ao, (reg)) 71 #define AOSECURE_WRITE(sc, reg, val) \ 72 bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh_ao, (reg), (val)) 73 74 75 struct meson_thermal_config { 76 const char *name; 77 bus_size_t aosec_reg; 78 }; 79 80 static struct meson_thermal_config thermal_cpu_conf = { 81 .name = "CPU", 82 .aosec_reg = 0x128 83 }; 84 85 static struct meson_thermal_config thermal_ddr_conf = { 86 .name = "DDR", 87 .aosec_reg = 0xf0 88 }; 89 90 static const struct device_compatible_entry compat_data[] = { 91 { .compat = "amlogic,g12a-cpu-thermal", .data = &thermal_cpu_conf }, 92 { .compat = "amlogic,g12a-ddr-thermal", .data = &thermal_ddr_conf }, 93 DEVICE_COMPAT_EOL 94 }; 95 96 struct meson_thermal_softc { 97 device_t sc_dev; 98 bus_space_tag_t sc_bst; 99 bus_space_handle_t sc_bsh; 100 bus_space_handle_t sc_bsh_ao; 101 const struct meson_thermal_config *sc_conf; 102 int sc_phandle; 103 int sc_ao_calib; 104 105 struct sysmon_envsys *sc_sme; 106 envsys_data_t sc_sensor_temp; 107 }; 108 109 110 static void 111 meson_thermal_init(struct meson_thermal_softc *sc) 112 { 113 uint32_t val; 114 115 val = THERMAL_READ_REG(sc, TS_CFG_REG1); 116 val |= TS_CFG_REG1_ANA_EN_VCM; 117 val |= TS_CFG_REG1_ANA_EN_VBG; 118 val |= TS_CFG_REG1_FILTER_EN; 119 val |= TS_CFG_REG1_DEM_EN; 120 val &= ~TS_CFG_REG1_ANA_CH_SEL; 121 val |= __SHIFTIN(3, TS_CFG_REG1_ANA_CH_SEL); 122 THERMAL_WRITE_REG(sc, TS_CFG_REG1, val); 123 124 /* read calibration value in ao-secure */ 125 #define TS_AO_CALIB_VERSION_MASK __BITS(31,24) 126 #define TS_AO_CALIB_SIGN_MASK __BIT(15) 127 #define TS_AO_CALIB_TEMP_MASK __BITS(14,0) 128 val = AOSECURE_READ(sc, sc->sc_conf->aosec_reg); 129 if ((val & TS_AO_CALIB_VERSION_MASK) != 0) { 130 sc->sc_ao_calib = (val & TS_AO_CALIB_TEMP_MASK); 131 if ((val & TS_AO_CALIB_SIGN_MASK) != 0) 132 sc->sc_ao_calib *= -1; 133 } else { 134 sc->sc_ao_calib = 0; 135 } 136 } 137 138 static int 139 meson_get_temperature(struct meson_thermal_softc *sc) 140 { 141 int val, temp; 142 int64_t factor, uptat; 143 144 val = THERMAL_READ_REG(sc, TS_STAT0_REG) & TS_STAT0_FILTER_OUT; 145 146 #define CALIB_A 9411 147 #define CALIB_B 3159 148 #define CALIB_m_1024 4342 /* 4.24 */ 149 #define CALIB_n_1024 3318 /* 3.24 */ 150 151 factor = (val * CALIB_n_1024) / 1024; 152 uptat = (val * CALIB_m_1024) / 1024; 153 154 uptat = (uptat * (1 << 16)) / ((1 << 16) + factor); 155 temp = ((uptat + sc->sc_ao_calib) * CALIB_A); 156 temp = (temp - (CALIB_B * (1 << 16))) * 100000LL / (1 << 16); 157 158 return temp; /* microcelsius */ 159 } 160 161 static void 162 meson_thermal_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 163 { 164 struct meson_thermal_softc *sc = sme->sme_cookie; 165 166 edata->value_cur = meson_get_temperature(sc) + 273150000; 167 edata->state = ENVSYS_SVALID; 168 } 169 170 static int 171 meson_thermal_match(device_t parent, cfdata_t cf, void *aux) 172 { 173 struct fdt_attach_args * const faa = aux; 174 175 return of_compatible_match(faa->faa_phandle, compat_data); 176 } 177 178 static void 179 meson_thermal_attach(device_t parent, device_t self, void *aux) 180 { 181 struct meson_thermal_softc * const sc = device_private(self); 182 struct fdt_attach_args * const faa = aux; 183 bus_addr_t addr; 184 bus_size_t size, aosize; 185 int phandle, phandle_aosec; 186 187 sc->sc_dev = self; 188 sc->sc_bst = faa->faa_bst; 189 sc->sc_phandle = phandle = faa->faa_phandle; 190 sc->sc_conf = of_compatible_lookup(phandle, compat_data)->data; 191 192 if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 193 aprint_error(": couldn't get registers\n"); 194 goto attach_failure0; 195 } 196 if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { 197 aprint_error(": couldn't map registers\n"); 198 goto attach_failure0; 199 } 200 201 phandle_aosec = fdtbus_get_phandle(phandle, "amlogic,ao-secure"); 202 if (fdtbus_get_reg(phandle_aosec, 0, &addr, &aosize) != 0) { 203 aprint_error(": couldn't get registers\n"); 204 goto attach_failure1; 205 } 206 if (bus_space_map(sc->sc_bst, addr, aosize, 0, &sc->sc_bsh_ao) != 0) { 207 aprint_error(": couldn't map registers\n"); 208 goto attach_failure1; 209 } 210 211 if (fdtbus_clock_enable_index(phandle, 0, true) != 0) { 212 aprint_error(": couldn't enable clock\n"); 213 goto attach_failure2; 214 } 215 216 meson_thermal_init(sc); 217 218 aprint_naive("\n"); 219 aprint_normal(": %s TEMP Sensor\n", sc->sc_conf->name); 220 221 sc->sc_sme = sysmon_envsys_create(); 222 sc->sc_sme->sme_name = device_xname(self); 223 sc->sc_sme->sme_cookie = sc; 224 sc->sc_sme->sme_flags = 0; 225 sc->sc_sme->sme_events_timeout = 1; 226 sc->sc_sme->sme_refresh = meson_thermal_refresh; 227 sc->sc_sensor_temp.units = ENVSYS_STEMP; 228 sc->sc_sensor_temp.state = ENVSYS_SINVALID; 229 snprintf(sc->sc_sensor_temp.desc, ENVSYS_DESCLEN, 230 "%s", sc->sc_conf->name); 231 232 sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor_temp); 233 sysmon_envsys_register(sc->sc_sme); 234 235 meson_thermal_refresh(sc->sc_sme, &sc->sc_sensor_temp); 236 return; 237 238 attach_failure2: 239 bus_space_unmap(sc->sc_bst, sc->sc_bsh_ao, aosize); 240 attach_failure1: 241 bus_space_unmap(sc->sc_bst, sc->sc_bsh, size); 242 attach_failure0: 243 return; 244 } 245 246 CFATTACH_DECL_NEW(meson_thermal, sizeof(struct meson_thermal_softc), 247 meson_thermal_match, meson_thermal_attach, NULL, NULL); 248