1/* 2 * Copyright 2017, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13#include <platsupport/mach/tmu.h> 14#include "../../services.h" 15 16#include <string.h> 17 18#define TRIMINFO_RELOAD (1) 19 20#define CORE_EN (1) 21#define TRIP_EN (1<<12) 22#define TRIP_ONLYCURRENT (0<<13) 23#define TRIP_CUR_PAST3_0 (4<<13) 24#define TRIP_CUR_PAST7_0 (5<<13) 25#define TRIP_CUR_PAST11_0 (6<<13) 26#define TRIP_CUR_PAST15_0 (7<<13) 27 28#define INTEN_RISE0 (1) 29#define INTEN_RISE1 (1<<4) 30#define INTEN_RISE2 (1<<8) 31#define INTEN_FALL0 (1<<16) 32#define INTEN_FALL1 (1<<20) 33#define INTEN_FALL2 (1<<24) 34 35#define INT_RISE(x) (BIT(((x) * 4))) 36#define INT_FALL(x) INT_RISE(3 + (x)) 37 38#define TRIM_INFO_MASK (0xFF) 39 40#define INT_ALL ( INT_RISE(0) | INT_RISE(1) | INT_RISE(2) \ 41 | INT_FALL(0) | INT_FALL(1) | INT_FALL(2) ) 42 43#define EMUL_EN (1) 44 45/* EFUSE related definition. */ 46#define EFUSE_MIN_VALUE 40 47#define EFUSE_MAX_VALUE 100 48#define EFUSE_INIT_VALUE 55 49 50#define TMU_SAVE_NUM 10 51#define TMU_DC_OFFSET 25 52 53/* Miscellaneous definitions. */ 54#define SLOPE 0x10008802 55#define MUX_ADDR_VALUE 6 56 57/* Device access macros. */ 58#define TMU_REG(vbase, offset) (*(volatile unsigned int *)(vbase + offset)) 59 60struct tmu_regs { 61 uint32_t res0[5]; /* 0x00 */ 62 uint32_t triminfo_con; /* 0x14 */ 63 uint32_t res1[2]; /* 0x18 */ 64 uint32_t con; /* 0x20 */ 65 uint32_t res2[1]; /* 0x24 */ 66 uint32_t stat; /* 0x28 */ 67 uint32_t sampling_interval; /* 0x2C */ 68 uint32_t cnt0; /* 0x30 */ 69 uint32_t cnt1; /* 0x34 */ 70 uint32_t res3[2]; /* 0x38 */ 71 uint32_t temperature; /* 0x40 */ 72 uint32_t res4[3]; /* 0x44 */ 73 uint32_t threshold_rise; /* 0x50 */ 74 uint32_t threshold_fall; /* 0x54 */ 75 uint32_t res5[2]; /* 0x58 */ 76 uint32_t past_temp[4]; /* 0x60 */ 77 uint32_t int_enable; /* 0x70 */ 78 uint32_t int_stat; /* 0x74 */ 79 uint32_t int_clear; /* 0x78 */ 80 uint32_t res6[1]; /* 0x7C */ 81 uint32_t emul_con; /* 0x80 */ 82}; 83typedef volatile struct tmu_regs tmu_regs_t; 84 85static tmu_regs_t* _tmu_regs[NTMU]; 86 87static inline tmu_regs_t* 88tmu_priv_get_regs(tmu_t* tmu) 89{ 90 return (tmu_regs_t*)tmu->priv; 91} 92 93static int 94do_exynos_tmu_init(enum tmu_id id, void* vaddr, tmu_t* tmu) 95{ 96 tmu_regs_t* regs; 97 uint32_t v; 98 uint32_t te1, te2; 99 100 memset(tmu, 0, sizeof(*tmu)); 101 102 /* Check bounds */ 103 if (id < 0 || id >= NTMU) { 104 return -1; 105 } 106 /* Initialise memory map */ 107 if (vaddr) { 108 _tmu_regs[id] = vaddr; 109 } 110 if (_tmu_regs[id] == NULL) { 111 return -1; 112 } 113 114 regs = _tmu_regs[id]; 115 tmu->priv = (void*)_tmu_regs[id]; 116 117 /* Reset alarms */ 118 regs->int_enable = 0; 119 regs->int_clear = INT_ALL; 120 regs->threshold_rise = 0; 121 regs->threshold_fall = 0; 122 123 /* Reload TRIMINFO_CON for using efuse. */ 124 regs->triminfo_con = TRIMINFO_RELOAD; 125 while (regs->triminfo_con & TRIMINFO_RELOAD); 126 /* Get the compensation parameter. */ 127 v = regs->triminfo_con; 128 te1 = (v >> 0) & TRIM_INFO_MASK; 129 te2 = (v >> 8) & TRIM_INFO_MASK; 130 131 /* Ensure the parameters are in range */ 132 if ((EFUSE_MIN_VALUE > te1) || (te1 > EFUSE_MAX_VALUE) || (te2 != 0)) { 133 te1 = EFUSE_INIT_VALUE; 134 } 135 tmu->t_off = te1 - TMU_DC_OFFSET; 136 137 /* Need to initialize register setting after getting parameter info. */ 138 /* [28:23] vref [11:8] slope - Tunning parameter */ 139 regs->con = SLOPE; 140 141 /* Enable the TMU */ 142 regs->con |= (MUX_ADDR_VALUE << 20) | CORE_EN; 143 while (regs->temperature == 0); 144 145 /* Clear the reading */ 146 v = regs->temperature; 147 return 0; 148} 149 150int 151exynos4_tmu_init(enum tmu_id id, void* vaddr, tmu_t* tmu) 152{ 153 return do_exynos_tmu_init(id, vaddr, tmu); 154} 155 156int 157exynos5_tmu_init(enum tmu_id id, void* vaddr, tmu_t* tmu) 158{ 159 return do_exynos_tmu_init(id, vaddr, tmu); 160} 161 162int 163exynos_tmu_init(enum tmu_id id, ps_io_ops_t* io_ops, tmu_t* tmu) 164{ 165 /* Check bounds */ 166 if (id < 0 || id >= NTMU) { 167 return -1; 168 } 169 /* Map the memory */ 170 MAP_IF_NULL(io_ops, EXYNOS_TMU, _tmu_regs[id]); 171 if (_tmu_regs[id] == NULL) { 172 return -1; 173 } 174 return do_exynos_tmu_init(id, (void*)_tmu_regs[id], tmu); 175} 176 177int 178exynos_tmu_get_temperature(tmu_t* tmu) 179{ 180 tmu_regs_t* regs; 181 uint32_t currTemp; 182 temperature_t temperature; 183 regs = tmu_priv_get_regs(tmu); 184 185 /* After reading temperature code from register, compensating 186 * its value and calculating celsius temperature, 187 * get current temperature. 188 */ 189 currTemp = regs->temperature & 0xff; 190 191 /* compensate and calculate current temperature */ 192 temperature = currTemp - tmu->t_off; 193 if (temperature < 0) { 194 /* temperature code range are between min 25 and 125 */ 195 LOG_ERROR("Invalid temperature from TMU"); 196 } 197 198 return temperature; 199} 200 201void 202exynos_tmu_handle_irq(tmu_t* tmu) 203{ 204 tmu_regs_t* regs; 205 uint32_t sts; 206 temperature_t t = exynos_tmu_get_temperature(tmu); 207 regs = tmu_priv_get_regs(tmu); 208 209 sts = regs->int_stat; 210 if (sts & INT_RISE(0)) { 211 assert(tmu->rising_alarm); 212 tmu->rising_alarm(tmu, t, 0, 1, tmu->rising_token); 213 } 214 if (sts & INT_RISE(1)) { 215 assert(tmu->rising_alarm); 216 tmu->rising_alarm(tmu, t, 1, 1, tmu->rising_token); 217 } 218 if (sts & INT_RISE(2)) { 219 assert(tmu->rising_alarm); 220 tmu->rising_alarm(tmu, t, 2, 1, tmu->rising_token); 221 } 222 if (sts & INT_FALL(0)) { 223 assert(tmu->falling_alarm); 224 tmu->rising_alarm(tmu, t, 0, 0, tmu->falling_token); 225 } 226 if (sts & INT_FALL(1)) { 227 assert(tmu->falling_alarm); 228 tmu->rising_alarm(tmu, t, 1, 0, tmu->falling_token); 229 } 230 if (sts & INT_FALL(2)) { 231 assert(tmu->falling_alarm); 232 tmu->rising_alarm(tmu, t, 2, 0, tmu->falling_token); 233 } 234 regs->int_clear = sts; 235} 236 237int 238exynos_tmu_set_alarms_rising(tmu_t* tmu, 239 temperature_t level0, 240 temperature_t level1, 241 temperature_t level2, 242 tmu_alarm_callback cb, 243 void* token) 244{ 245 tmu_regs_t* regs; 246 uint32_t threshold; 247 uint32_t int_enable; 248 249 regs = tmu_priv_get_regs(tmu); 250 251 threshold = 0; 252 int_enable = regs->int_enable & ~(INT_RISE(0) | INT_RISE(1) | INT_RISE(2)); 253 if (level0 >= 0) { 254 threshold |= (level0 + tmu->t_off) << 0; 255 int_enable |= INT_RISE(0); 256 } 257 if (level1 >= 0) { 258 threshold |= (level0 + tmu->t_off) << 0; 259 int_enable |= INT_RISE(1); 260 } 261 if (level2 >= 0) { 262 threshold |= (level0 + tmu->t_off) << 0; 263 int_enable |= INT_RISE(2); 264 } 265 regs->threshold_rise = threshold; 266 regs->int_enable = int_enable; 267 return 0; 268} 269 270int 271exynos_tmu_set_alarms_falling(tmu_t* tmu, 272 temperature_t level0, 273 temperature_t level1, 274 temperature_t level2, 275 tmu_alarm_callback cb, 276 void* token) 277{ 278 tmu_regs_t* regs; 279 uint32_t threshold; 280 uint32_t int_enable; 281 282 regs = tmu_priv_get_regs(tmu); 283 284 threshold = 0; 285 int_enable = regs->int_enable & ~(INT_FALL(0) | INT_FALL(1) | INT_FALL(2)); 286 if (level0 >= 0) { 287 threshold |= (level0 + tmu->t_off) << 0; 288 int_enable |= INT_FALL(0); 289 } 290 if (level1 >= 0) { 291 threshold |= (level0 + tmu->t_off) << 0; 292 int_enable |= INT_FALL(1); 293 } 294 if (level2 >= 0) { 295 threshold |= (level0 + tmu->t_off) << 0; 296 int_enable |= INT_FALL(2); 297 } 298 regs->threshold_fall = threshold; 299 regs->int_enable = int_enable; 300 return 0; 301} 302