1// SPDX-License-Identifier: GPL-2.0 2 3/* 4 * Copyright 2016-2019 HabanaLabs, Ltd. 5 * All Rights Reserved. 6 */ 7 8#include "goyaP.h" 9 10void goya_set_pll_profile(struct hl_device *hdev, enum hl_pll_frequency freq) 11{ 12 struct goya_device *goya = hdev->asic_specific; 13 14 switch (freq) { 15 case PLL_HIGH: 16 hl_set_frequency(hdev, MME_PLL, hdev->high_pll); 17 hl_set_frequency(hdev, TPC_PLL, hdev->high_pll); 18 hl_set_frequency(hdev, IC_PLL, hdev->high_pll); 19 break; 20 case PLL_LOW: 21 hl_set_frequency(hdev, MME_PLL, GOYA_PLL_FREQ_LOW); 22 hl_set_frequency(hdev, TPC_PLL, GOYA_PLL_FREQ_LOW); 23 hl_set_frequency(hdev, IC_PLL, GOYA_PLL_FREQ_LOW); 24 break; 25 case PLL_LAST: 26 hl_set_frequency(hdev, MME_PLL, goya->mme_clk); 27 hl_set_frequency(hdev, TPC_PLL, goya->tpc_clk); 28 hl_set_frequency(hdev, IC_PLL, goya->ic_clk); 29 break; 30 default: 31 dev_err(hdev->dev, "unknown frequency setting\n"); 32 } 33} 34 35int goya_get_clk_rate(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk) 36{ 37 long value; 38 39 if (hl_device_disabled_or_in_reset(hdev)) 40 return -ENODEV; 41 42 value = hl_get_frequency(hdev, MME_PLL, false); 43 44 if (value < 0) { 45 dev_err(hdev->dev, "Failed to retrieve device max clock %ld\n", 46 value); 47 return value; 48 } 49 50 *max_clk = (value / 1000 / 1000); 51 52 value = hl_get_frequency(hdev, MME_PLL, true); 53 54 if (value < 0) { 55 dev_err(hdev->dev, 56 "Failed to retrieve device current clock %ld\n", 57 value); 58 return value; 59 } 60 61 *cur_clk = (value / 1000 / 1000); 62 63 return 0; 64} 65 66static ssize_t mme_clk_show(struct device *dev, struct device_attribute *attr, 67 char *buf) 68{ 69 struct hl_device *hdev = dev_get_drvdata(dev); 70 long value; 71 72 if (hl_device_disabled_or_in_reset(hdev)) 73 return -ENODEV; 74 75 value = hl_get_frequency(hdev, MME_PLL, false); 76 77 if (value < 0) 78 return value; 79 80 return sprintf(buf, "%lu\n", value); 81} 82 83static ssize_t mme_clk_store(struct device *dev, struct device_attribute *attr, 84 const char *buf, size_t count) 85{ 86 struct hl_device *hdev = dev_get_drvdata(dev); 87 struct goya_device *goya = hdev->asic_specific; 88 int rc; 89 long value; 90 91 if (hl_device_disabled_or_in_reset(hdev)) { 92 count = -ENODEV; 93 goto fail; 94 } 95 96 if (hdev->pm_mng_profile == PM_AUTO) { 97 count = -EPERM; 98 goto fail; 99 } 100 101 rc = kstrtoul(buf, 0, &value); 102 103 if (rc) { 104 count = -EINVAL; 105 goto fail; 106 } 107 108 hl_set_frequency(hdev, MME_PLL, value); 109 goya->mme_clk = value; 110 111fail: 112 return count; 113} 114 115static ssize_t tpc_clk_show(struct device *dev, struct device_attribute *attr, 116 char *buf) 117{ 118 struct hl_device *hdev = dev_get_drvdata(dev); 119 long value; 120 121 if (hl_device_disabled_or_in_reset(hdev)) 122 return -ENODEV; 123 124 value = hl_get_frequency(hdev, TPC_PLL, false); 125 126 if (value < 0) 127 return value; 128 129 return sprintf(buf, "%lu\n", value); 130} 131 132static ssize_t tpc_clk_store(struct device *dev, struct device_attribute *attr, 133 const char *buf, size_t count) 134{ 135 struct hl_device *hdev = dev_get_drvdata(dev); 136 struct goya_device *goya = hdev->asic_specific; 137 int rc; 138 long value; 139 140 if (hl_device_disabled_or_in_reset(hdev)) { 141 count = -ENODEV; 142 goto fail; 143 } 144 145 if (hdev->pm_mng_profile == PM_AUTO) { 146 count = -EPERM; 147 goto fail; 148 } 149 150 rc = kstrtoul(buf, 0, &value); 151 152 if (rc) { 153 count = -EINVAL; 154 goto fail; 155 } 156 157 hl_set_frequency(hdev, TPC_PLL, value); 158 goya->tpc_clk = value; 159 160fail: 161 return count; 162} 163 164static ssize_t ic_clk_show(struct device *dev, struct device_attribute *attr, 165 char *buf) 166{ 167 struct hl_device *hdev = dev_get_drvdata(dev); 168 long value; 169 170 if (hl_device_disabled_or_in_reset(hdev)) 171 return -ENODEV; 172 173 value = hl_get_frequency(hdev, IC_PLL, false); 174 175 if (value < 0) 176 return value; 177 178 return sprintf(buf, "%lu\n", value); 179} 180 181static ssize_t ic_clk_store(struct device *dev, struct device_attribute *attr, 182 const char *buf, size_t count) 183{ 184 struct hl_device *hdev = dev_get_drvdata(dev); 185 struct goya_device *goya = hdev->asic_specific; 186 int rc; 187 long value; 188 189 if (hl_device_disabled_or_in_reset(hdev)) { 190 count = -ENODEV; 191 goto fail; 192 } 193 194 if (hdev->pm_mng_profile == PM_AUTO) { 195 count = -EPERM; 196 goto fail; 197 } 198 199 rc = kstrtoul(buf, 0, &value); 200 201 if (rc) { 202 count = -EINVAL; 203 goto fail; 204 } 205 206 hl_set_frequency(hdev, IC_PLL, value); 207 goya->ic_clk = value; 208 209fail: 210 return count; 211} 212 213static ssize_t mme_clk_curr_show(struct device *dev, 214 struct device_attribute *attr, char *buf) 215{ 216 struct hl_device *hdev = dev_get_drvdata(dev); 217 long value; 218 219 if (hl_device_disabled_or_in_reset(hdev)) 220 return -ENODEV; 221 222 value = hl_get_frequency(hdev, MME_PLL, true); 223 224 if (value < 0) 225 return value; 226 227 return sprintf(buf, "%lu\n", value); 228} 229 230static ssize_t tpc_clk_curr_show(struct device *dev, 231 struct device_attribute *attr, char *buf) 232{ 233 struct hl_device *hdev = dev_get_drvdata(dev); 234 long value; 235 236 if (hl_device_disabled_or_in_reset(hdev)) 237 return -ENODEV; 238 239 value = hl_get_frequency(hdev, TPC_PLL, true); 240 241 if (value < 0) 242 return value; 243 244 return sprintf(buf, "%lu\n", value); 245} 246 247static ssize_t ic_clk_curr_show(struct device *dev, 248 struct device_attribute *attr, char *buf) 249{ 250 struct hl_device *hdev = dev_get_drvdata(dev); 251 long value; 252 253 if (hl_device_disabled_or_in_reset(hdev)) 254 return -ENODEV; 255 256 value = hl_get_frequency(hdev, IC_PLL, true); 257 258 if (value < 0) 259 return value; 260 261 return sprintf(buf, "%lu\n", value); 262} 263 264static ssize_t pm_mng_profile_show(struct device *dev, 265 struct device_attribute *attr, char *buf) 266{ 267 struct hl_device *hdev = dev_get_drvdata(dev); 268 269 if (hl_device_disabled_or_in_reset(hdev)) 270 return -ENODEV; 271 272 return sprintf(buf, "%s\n", 273 (hdev->pm_mng_profile == PM_AUTO) ? "auto" : 274 (hdev->pm_mng_profile == PM_MANUAL) ? "manual" : 275 "unknown"); 276} 277 278static ssize_t pm_mng_profile_store(struct device *dev, 279 struct device_attribute *attr, const char *buf, size_t count) 280{ 281 struct hl_device *hdev = dev_get_drvdata(dev); 282 283 if (hl_device_disabled_or_in_reset(hdev)) { 284 count = -ENODEV; 285 goto out; 286 } 287 288 mutex_lock(&hdev->fpriv_list_lock); 289 290 if (hdev->compute_ctx) { 291 dev_err(hdev->dev, 292 "Can't change PM profile while compute context is opened on the device\n"); 293 count = -EPERM; 294 goto unlock_mutex; 295 } 296 297 if (strncmp("auto", buf, strlen("auto")) == 0) { 298 /* Make sure we are in LOW PLL when changing modes */ 299 if (hdev->pm_mng_profile == PM_MANUAL) { 300 hdev->curr_pll_profile = PLL_HIGH; 301 hdev->pm_mng_profile = PM_AUTO; 302 hl_device_set_frequency(hdev, PLL_LOW); 303 } 304 } else if (strncmp("manual", buf, strlen("manual")) == 0) { 305 if (hdev->pm_mng_profile == PM_AUTO) { 306 /* Must release the lock because the work thread also 307 * takes this lock. But before we release it, set 308 * the mode to manual so nothing will change if a user 309 * suddenly opens the device 310 */ 311 hdev->pm_mng_profile = PM_MANUAL; 312 313 mutex_unlock(&hdev->fpriv_list_lock); 314 315 /* Flush the current work so we can return to the user 316 * knowing that he is the only one changing frequencies 317 */ 318 flush_delayed_work(&hdev->work_freq); 319 320 return count; 321 } 322 } else { 323 dev_err(hdev->dev, "value should be auto or manual\n"); 324 count = -EINVAL; 325 } 326 327unlock_mutex: 328 mutex_unlock(&hdev->fpriv_list_lock); 329out: 330 return count; 331} 332 333static ssize_t high_pll_show(struct device *dev, struct device_attribute *attr, 334 char *buf) 335{ 336 struct hl_device *hdev = dev_get_drvdata(dev); 337 338 if (hl_device_disabled_or_in_reset(hdev)) 339 return -ENODEV; 340 341 return sprintf(buf, "%u\n", hdev->high_pll); 342} 343 344static ssize_t high_pll_store(struct device *dev, struct device_attribute *attr, 345 const char *buf, size_t count) 346{ 347 struct hl_device *hdev = dev_get_drvdata(dev); 348 long value; 349 int rc; 350 351 if (hl_device_disabled_or_in_reset(hdev)) { 352 count = -ENODEV; 353 goto out; 354 } 355 356 rc = kstrtoul(buf, 0, &value); 357 358 if (rc) { 359 count = -EINVAL; 360 goto out; 361 } 362 363 hdev->high_pll = value; 364 365out: 366 return count; 367} 368 369static DEVICE_ATTR_RW(high_pll); 370static DEVICE_ATTR_RW(ic_clk); 371static DEVICE_ATTR_RO(ic_clk_curr); 372static DEVICE_ATTR_RW(mme_clk); 373static DEVICE_ATTR_RO(mme_clk_curr); 374static DEVICE_ATTR_RW(pm_mng_profile); 375static DEVICE_ATTR_RW(tpc_clk); 376static DEVICE_ATTR_RO(tpc_clk_curr); 377 378static struct attribute *goya_dev_attrs[] = { 379 &dev_attr_high_pll.attr, 380 &dev_attr_ic_clk.attr, 381 &dev_attr_ic_clk_curr.attr, 382 &dev_attr_mme_clk.attr, 383 &dev_attr_mme_clk_curr.attr, 384 &dev_attr_pm_mng_profile.attr, 385 &dev_attr_tpc_clk.attr, 386 &dev_attr_tpc_clk_curr.attr, 387 NULL, 388}; 389 390void goya_add_device_attr(struct hl_device *hdev, 391 struct attribute_group *dev_attr_grp) 392{ 393 dev_attr_grp->attrs = goya_dev_attrs; 394} 395