1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2018-2020 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 
25 #include "export_nvswitch.h"
26 #include "common_nvswitch.h"
27 #include "error_nvswitch.h"
28 #include "lr10/lr10.h"
29 #include "lr10/therm_lr10.h"
30 #include "soe/soeiftherm.h"
31 #include "rmflcncmdif_nvswitch.h"
32 #include "soe/soe_nvswitch.h"
33 
34 #include "nvswitch/lr10/dev_therm.h"
35 #include "nvswitch/lr10/dev_nvlsaw_ip.h"
36 
37 //
38 // Thermal functions
39 //
40 
41 //
42 // Initialize thermal offsets for External Tdiode.
43 //
44 
45 NvlStatus
46 nvswitch_init_thermal_lr10
47 (
48     nvswitch_device *device
49 )
50 {
51     lr10_device *chip_device = NVSWITCH_GET_CHIP_DEVICE_LR10(device);
52 
53      // Mark everything invalid
54     chip_device->tdiode.method = NVSWITCH_THERM_METHOD_UNKNOWN;
55 
56     return NVL_SUCCESS;
57 }
58 
59 static void
60 _nvswitch_read_max_tsense_temperature
61 (
62     nvswitch_device *device,
63     NVSWITCH_CTRL_GET_TEMPERATURE_PARAMS *info,
64     NvU32 channel
65 )
66 {
67     NvU32  offset;
68     NvU32  temperature;
69 
70     temperature = nvswitch_reg_read_32(device, NV_THERM_TSENSE_MAXIMUM_TEMPERATURE);
71     temperature = DRF_VAL(_THERM_TSENSE, _MAXIMUM_TEMPERATURE, _MAXIMUM_TEMPERATURE, temperature);
72 
73     if (channel == NVSWITCH_THERM_CHANNEL_LR10_TSENSE_MAX)
74     {
75         offset = nvswitch_reg_read_32(device, NV_THERM_TSENSE_U2_A_0_BJT_0_TEMPERATURE_MODIFICATIONS);
76         offset = DRF_VAL(_THERM_TSENSE, _U2_A_0_BJT_0_TEMPERATURE_MODIFICATIONS, _TEMPERATURE_OFFSET, offset);
77 
78         // Temperature of the sensor reported equals calculation of the max temperature reported
79         // from the TSENSE HUB plus the temperature offset programmed by SW. This offset needs to
80         // be substracted to get the actual temperature of the sensor.
81         temperature -= offset;
82     }
83 
84     info->temperature[channel] = NV_TSENSE_FXP_9_5_TO_24_8(temperature);
85     info->status[channel] = NVL_SUCCESS;
86 }
87 
88 static void
89 _nvswitch_read_external_tdiode_temperature
90 (
91     nvswitch_device *device,
92     NVSWITCH_CTRL_GET_TEMPERATURE_PARAMS *info,
93     NvU32 channel
94 )
95 {
96 }
97 
98 NvlStatus
99 nvswitch_ctrl_therm_read_temperature_lr10
100 (
101     nvswitch_device *device,
102     NVSWITCH_CTRL_GET_TEMPERATURE_PARAMS *info
103 )
104 {
105     NvU32 channel;
106 
107     if (!info->channelMask)
108     {
109         NVSWITCH_PRINT(device, ERROR,
110             "%s: No channel given in the input.\n",
111             __FUNCTION__);
112 
113         return -NVL_BAD_ARGS;
114     }
115 
116     nvswitch_os_memset(info->temperature, 0x0, sizeof(info->temperature));
117 
118     channel = NVSWITCH_THERM_CHANNEL_LR10_TSENSE_MAX;
119     if (info->channelMask & NVBIT(channel))
120     {
121         _nvswitch_read_max_tsense_temperature(device, info, channel);
122         info->channelMask &= ~NVBIT(channel);
123     }
124 
125     channel = NVSWITCH_THERM_CHANNEL_LR10_TSENSE_OFFSET_MAX;
126     if (info->channelMask & NVBIT(channel))
127     {
128         _nvswitch_read_max_tsense_temperature(device, info, channel);
129         info->channelMask &= ~NVBIT(channel);
130     }
131 
132     channel = NVSWITCH_THERM_CHANNEL_LR10_TDIODE;
133     if (info->channelMask & NVBIT(channel))
134     {
135         _nvswitch_read_external_tdiode_temperature(device, info, channel);
136         info->channelMask &= ~NVBIT(channel);
137     }
138 
139     channel = NVSWITCH_THERM_CHANNEL_LR10_TDIODE_OFFSET;
140     if (info->channelMask & NVBIT(channel))
141     {
142         _nvswitch_read_external_tdiode_temperature(device, info, channel);
143         info->channelMask &= ~NVBIT(channel);
144     }
145 
146     if (info->channelMask)
147     {
148         NVSWITCH_PRINT(device, ERROR,
149             "%s: ChannelMask %x absent on LR10.\n",
150             __FUNCTION__, info->channelMask);
151 
152         return -NVL_BAD_ARGS;
153     }
154 
155     return NVL_SUCCESS;
156 }
157 
158 NvlStatus
159 nvswitch_ctrl_therm_get_temperature_limit_lr10
160 (
161     nvswitch_device *device,
162     NVSWITCH_CTRL_GET_TEMPERATURE_LIMIT_PARAMS *info
163 )
164 {
165     NvU32 threshold;
166     NvU32 temperature;
167 
168     threshold = nvswitch_reg_read_32(device, NV_THERM_TSENSE_THRESHOLD_TEMPERATURES);
169 
170     switch (info->thermalEventId)
171     {
172         case NVSWITCH_CTRL_THERMAL_EVENT_ID_WARN:
173         {
174             // Get Slowdown temperature
175             temperature = DRF_VAL(_THERM_TSENSE, _THRESHOLD_TEMPERATURES,
176                                   _WARNING_TEMPERATURE, threshold);
177             break;
178         }
179         case NVSWITCH_CTRL_THERMAL_EVENT_ID_OVERT:
180         {
181             // Get Shutdown temperature
182             temperature = DRF_VAL(_THERM_TSENSE, _THRESHOLD_TEMPERATURES,
183                                   _OVERTEMP_TEMPERATURE, threshold);
184             break;
185         }
186         default:
187         {
188             NVSWITCH_PRINT(device, ERROR, "Invalid Thermal Event Id: 0x%x\n", info->thermalEventId);
189             return -NVL_BAD_ARGS;
190         }
191     }
192 
193     info->temperatureLimit = NV_TSENSE_FXP_9_5_TO_24_8(temperature);
194 
195     return NVL_SUCCESS;
196 }
197 
198 // Background task to monitor thermal warn and adjust link mode
199 void
200 nvswitch_monitor_thermal_alert_lr10
201 (
202     nvswitch_device *device
203 )
204 {
205     return;
206 }
207 
208 /*
209  * @brief Callback function to recieve thermal messages from SOE.
210  */
211 void
212 nvswitch_therm_soe_callback_lr10
213 (
214     nvswitch_device *device,
215     RM_FLCN_MSG *pGenMsg,
216     void *pParams,
217     NvU32 seqDesc,
218     NV_STATUS status
219 )
220 {
221     RM_SOE_THERM_MSG_SLOWDOWN_STATUS slowdown_status;
222     RM_SOE_THERM_MSG_SHUTDOWN_STATUS shutdown_status;
223     RM_FLCN_MSG_SOE *pMsg = (RM_FLCN_MSG_SOE *)pGenMsg;
224     NvU32 temperature;
225     NvU32 threshold;
226 
227     switch (pMsg->msg.soeTherm.msgType)
228     {
229         case RM_SOE_THERM_MSG_ID_SLOWDOWN_STATUS:
230         {
231             slowdown_status = pMsg->msg.soeTherm.slowdown;
232             if (slowdown_status.bSlowdown)
233             {
234                 if (slowdown_status.source.bTsense) // TSENSE_THERM_ALERT
235                 {
236                     temperature = RM_SOE_NV_TEMP_TO_CELSIUS_TRUNCED(slowdown_status.maxTemperature);
237                     threshold   = RM_SOE_NV_TEMP_TO_CELSIUS_TRUNCED(slowdown_status.warnThreshold);
238 
239                     NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_HOST_THERMAL_EVENT_START,
240                         "NVSWITCH Temperature %dC | TSENSE WARN Threshold %dC\n",
241                         temperature, threshold);
242 
243                     NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_HOST_THERMAL_EVENT_START,
244                         "Thermal Slowdown Engaged | Temp higher than WARN Threshold\n");
245                 }
246 
247                 if (slowdown_status.source.bPmgr) // PMGR_THERM_ALERT
248                 {
249                     NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_HOST_THERMAL_EVENT_START,
250                         "Thermal Slowdown Engaged | PMGR WARN Threshold reached\n");
251                 }
252             }
253             else // REVERT_SLOWDOWN
254             {
255                 temperature = RM_SOE_NV_TEMP_TO_CELSIUS_TRUNCED(slowdown_status.maxTemperature);
256                 threshold   = RM_SOE_NV_TEMP_TO_CELSIUS_TRUNCED(slowdown_status.warnThreshold);
257 
258                 NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_HOST_THERMAL_EVENT_END,
259                     "NVSWITCH Temperature %dC | TSENSE WARN Threshold %dC\n",
260                     temperature, threshold);
261 
262                 NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_HOST_THERMAL_EVENT_END,
263                     "Thermal slowdown Disengaged\n");
264             }
265             break;
266         }
267 
268         case RM_SOE_THERM_MSG_ID_SHUTDOWN_STATUS:
269         {
270             shutdown_status = pMsg->msg.soeTherm.shutdown;
271             if (shutdown_status.source.bTsense) // TSENSE_THERM_SHUTDOWN
272             {
273                 temperature = RM_SOE_NV_TEMP_TO_CELSIUS_TRUNCED(shutdown_status.maxTemperature);
274                 threshold   = RM_SOE_NV_TEMP_TO_CELSIUS_TRUNCED(shutdown_status.overtThreshold);
275 
276                 NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_HOST_THERMAL_SHUTDOWN,
277                     "NVSWITCH Temperature %dC | OVERT Threshold %dC\n",
278                     temperature, threshold);
279 
280                 NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_HOST_THERMAL_SHUTDOWN,
281                     "TSENSE OVERT Threshold reached. Shutting Down\n");
282             }
283 
284 
285             if (shutdown_status.source.bPmgr) // PMGR_THERM_SHUTDOWN
286             {
287                 NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_HOST_THERMAL_EVENT_START,
288                     "PMGR OVERT Threshold reached. Shutting Down\n");
289             }
290             break;
291         }
292         default:
293         {
294             NVSWITCH_PRINT(device, ERROR, "%s Unknown message Id\n", __FUNCTION__);
295             NVSWITCH_ASSERT(0);
296         }
297     }
298 }
299 
300 //
301 // nvswitch_therm_read_voltage
302 //
303 // Temperature and voltage are only available on SKUs which have thermal and
304 // voltage sensors.
305 //
306 
307 NvlStatus
308 nvswitch_ctrl_therm_read_voltage_lr10
309 (
310     nvswitch_device *device,
311     NVSWITCH_CTRL_GET_VOLTAGE_PARAMS *info
312 )
313 {
314     return -NVL_ERR_NOT_SUPPORTED;
315 }
316 
317