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