Konstantin Porotchkin | 486f868 | 2018-06-07 18:31:14 +0300 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2018 Marvell International Ltd. |
| 3 | * |
| 4 | * SPDX-License-Identifier: BSD-3-Clause |
| 5 | * https://spdx.org/licenses |
| 6 | */ |
| 7 | |
| 8 | #include <debug.h> |
| 9 | #include <delay_timer.h> |
| 10 | #include <mmio.h> |
| 11 | #include <mvebu_def.h> |
| 12 | #include <thermal.h> |
| 13 | |
| 14 | #define THERMAL_TIMEOUT 1200 |
| 15 | |
| 16 | #define THERMAL_SEN_CTRL_LSB_STRT_OFFSET 0 |
| 17 | #define THERMAL_SEN_CTRL_LSB_STRT_MASK \ |
| 18 | (0x1 << THERMAL_SEN_CTRL_LSB_STRT_OFFSET) |
| 19 | #define THERMAL_SEN_CTRL_LSB_RST_OFFSET 1 |
| 20 | #define THERMAL_SEN_CTRL_LSB_RST_MASK \ |
| 21 | (0x1 << THERMAL_SEN_CTRL_LSB_RST_OFFSET) |
| 22 | #define THERMAL_SEN_CTRL_LSB_EN_OFFSET 2 |
| 23 | #define THERMAL_SEN_CTRL_LSB_EN_MASK \ |
| 24 | (0x1 << THERMAL_SEN_CTRL_LSB_EN_OFFSET) |
| 25 | |
| 26 | #define THERMAL_SEN_CTRL_STATS_VALID_OFFSET 16 |
| 27 | #define THERMAL_SEN_CTRL_STATS_VALID_MASK \ |
| 28 | (0x1 << THERMAL_SEN_CTRL_STATS_VALID_OFFSET) |
| 29 | #define THERMAL_SEN_CTRL_STATS_TEMP_OUT_OFFSET 0 |
| 30 | #define THERMAL_SEN_CTRL_STATS_TEMP_OUT_MASK \ |
| 31 | (0x3FF << THERMAL_SEN_CTRL_STATS_TEMP_OUT_OFFSET) |
| 32 | |
| 33 | #define THERMAL_SEN_OUTPUT_MSB 512 |
| 34 | #define THERMAL_SEN_OUTPUT_COMP 1024 |
| 35 | |
| 36 | struct tsen_regs { |
| 37 | uint32_t ext_tsen_ctrl_lsb; |
| 38 | uint32_t ext_tsen_ctrl_msb; |
| 39 | uint32_t ext_tsen_status; |
| 40 | }; |
| 41 | |
| 42 | static int ext_tsen_probe(struct tsen_config *tsen_cfg) |
| 43 | { |
| 44 | uint32_t reg, timeout = 0; |
| 45 | struct tsen_regs *base; |
| 46 | |
| 47 | if (tsen_cfg == NULL && tsen_cfg->regs_base == NULL) { |
| 48 | ERROR("initial thermal sensor configuration is missing\n"); |
| 49 | return -1; |
| 50 | } |
| 51 | base = (struct tsen_regs *)tsen_cfg->regs_base; |
| 52 | |
| 53 | INFO("initializing thermal sensor\n"); |
| 54 | |
| 55 | /* initialize thermal sensor hardware reset once */ |
| 56 | reg = mmio_read_32((uintptr_t)&base->ext_tsen_ctrl_lsb); |
| 57 | reg &= ~THERMAL_SEN_CTRL_LSB_RST_OFFSET; /* de-assert TSEN_RESET */ |
| 58 | reg |= THERMAL_SEN_CTRL_LSB_EN_MASK; /* set TSEN_EN to 1 */ |
| 59 | reg |= THERMAL_SEN_CTRL_LSB_STRT_MASK; /* set TSEN_START to 1 */ |
| 60 | mmio_write_32((uintptr_t)&base->ext_tsen_ctrl_lsb, reg); |
| 61 | |
| 62 | reg = mmio_read_32((uintptr_t)&base->ext_tsen_status); |
| 63 | while ((reg & THERMAL_SEN_CTRL_STATS_VALID_MASK) == 0 && |
| 64 | timeout < THERMAL_TIMEOUT) { |
| 65 | udelay(100); |
| 66 | reg = mmio_read_32((uintptr_t)&base->ext_tsen_status); |
| 67 | timeout++; |
| 68 | } |
| 69 | |
| 70 | if ((reg & THERMAL_SEN_CTRL_STATS_VALID_MASK) == 0) { |
| 71 | ERROR("thermal sensor is not ready\n"); |
| 72 | return -1; |
| 73 | } |
| 74 | |
| 75 | tsen_cfg->tsen_ready = 1; |
| 76 | |
| 77 | VERBOSE("thermal sensor was initialized\n"); |
| 78 | |
| 79 | return 0; |
| 80 | } |
| 81 | |
| 82 | static int ext_tsen_read(struct tsen_config *tsen_cfg, int *temp) |
| 83 | { |
| 84 | uint32_t reg; |
| 85 | struct tsen_regs *base; |
| 86 | |
| 87 | if (tsen_cfg == NULL && !tsen_cfg->tsen_ready) { |
| 88 | ERROR("thermal sensor was not initialized\n"); |
| 89 | return -1; |
| 90 | } |
| 91 | base = (struct tsen_regs *)tsen_cfg->regs_base; |
| 92 | |
| 93 | reg = mmio_read_32((uintptr_t)&base->ext_tsen_status); |
| 94 | reg = ((reg & THERMAL_SEN_CTRL_STATS_TEMP_OUT_MASK) >> |
| 95 | THERMAL_SEN_CTRL_STATS_TEMP_OUT_OFFSET); |
| 96 | |
| 97 | /* |
| 98 | * TSEN output format is signed as a 2s complement number |
| 99 | * ranging from-512 to +511. when MSB is set, need to |
| 100 | * calculate the complement number |
| 101 | */ |
| 102 | if (reg >= THERMAL_SEN_OUTPUT_MSB) |
| 103 | reg -= THERMAL_SEN_OUTPUT_COMP; |
| 104 | |
| 105 | if (tsen_cfg->tsen_divisor == 0) { |
| 106 | ERROR("thermal sensor divisor cannot be zero\n"); |
| 107 | return -1; |
| 108 | } |
| 109 | |
| 110 | *temp = ((tsen_cfg->tsen_gain * ((int)reg)) + |
| 111 | tsen_cfg->tsen_offset) / tsen_cfg->tsen_divisor; |
| 112 | |
| 113 | return 0; |
| 114 | } |
| 115 | |
| 116 | static struct tsen_config tsen_cfg = { |
| 117 | .tsen_offset = 153400, |
| 118 | .tsen_gain = 425, |
| 119 | .tsen_divisor = 1000, |
| 120 | .tsen_ready = 0, |
| 121 | .regs_base = (void *)MVEBU_AP_EXT_TSEN_BASE, |
| 122 | .ptr_tsen_probe = ext_tsen_probe, |
| 123 | .ptr_tsen_read = ext_tsen_read |
| 124 | }; |
| 125 | |
| 126 | struct tsen_config *marvell_thermal_config_get(void) |
| 127 | { |
| 128 | return &tsen_cfg; |
| 129 | } |