nouveau_pm.c revision 771e1035b9bfdb0c3f0e34bd281d73b721a10adb
1330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs/* 2330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs * Copyright 2010 Red Hat Inc. 3330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs * 4330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs * Permission is hereby granted, free of charge, to any person obtaining a 5330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs * copy of this software and associated documentation files (the "Software"), 6330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs * to deal in the Software without restriction, including without limitation 7330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs * and/or sell copies of the Software, and to permit persons to whom the 9330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs * Software is furnished to do so, subject to the following conditions: 10330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs * 11330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs * The above copyright notice and this permission notice shall be included in 12330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs * all copies or substantial portions of the Software. 13330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs * 14330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs * OTHER DEALINGS IN THE SOFTWARE. 21330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs * 22330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs * Authors: Ben Skeggs 23330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs */ 24330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 25330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs#include "drmP.h" 26330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 27330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs#include "nouveau_drv.h" 28330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs#include "nouveau_pm.h" 29330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 306032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs#ifdef CONFIG_ACPI 316032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs#include <linux/acpi.h> 326032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs#endif 336032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs#include <linux/power_supply.h> 3434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres#include <linux/hwmon.h> 3534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres#include <linux/hwmon-sysfs.h> 3634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 37330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsstatic int 385c6dc6575460a0afe56d8cae7666e769e08ef942Ben Skeggsnouveau_pm_clock_set(struct drm_device *dev, struct nouveau_pm_level *perflvl, 395c6dc6575460a0afe56d8cae7666e769e08ef942Ben Skeggs u8 id, u32 khz) 406f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs{ 416f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 426f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 436f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs void *pre_state; 446f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 456f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (khz == 0) 466f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs return 0; 476f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 485c6dc6575460a0afe56d8cae7666e769e08ef942Ben Skeggs pre_state = pm->clock_pre(dev, perflvl, id, khz); 496f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (IS_ERR(pre_state)) 506f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs return PTR_ERR(pre_state); 516f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 526f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (pre_state) 536f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs pm->clock_set(dev, pre_state); 546f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs return 0; 556f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs} 566f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 576f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggsstatic int 5864f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggsnouveau_pm_perflvl_set(struct drm_device *dev, struct nouveau_pm_level *perflvl) 5964f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs{ 6064f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 6164f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 6264f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs int ret; 6364f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs 6464f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs if (perflvl == pm->cur) 6564f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs return 0; 6664f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs 67771e1035b9bfdb0c3f0e34bd281d73b721a10adbBen Skeggs if (pm->fanspeed_set && perflvl->fanspeed) { 68771e1035b9bfdb0c3f0e34bd281d73b721a10adbBen Skeggs ret = pm->fanspeed_set(dev, perflvl->fanspeed); 69771e1035b9bfdb0c3f0e34bd281d73b721a10adbBen Skeggs if (ret) 70771e1035b9bfdb0c3f0e34bd281d73b721a10adbBen Skeggs NV_ERROR(dev, "set fanspeed failed: %d\n", ret); 71771e1035b9bfdb0c3f0e34bd281d73b721a10adbBen Skeggs } 72771e1035b9bfdb0c3f0e34bd281d73b721a10adbBen Skeggs 733b5565ddfd8fe71f6470a5d240a6bb50ba90d4ffBen Skeggs if (pm->voltage.supported && pm->voltage_set && perflvl->volt_min) { 743b5565ddfd8fe71f6470a5d240a6bb50ba90d4ffBen Skeggs ret = pm->voltage_set(dev, perflvl->volt_min); 7564f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs if (ret) { 7664f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs NV_ERROR(dev, "voltage_set %d failed: %d\n", 773b5565ddfd8fe71f6470a5d240a6bb50ba90d4ffBen Skeggs perflvl->volt_min, ret); 7864f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs } 7964f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs } 8064f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs 8177e7da6814623927cc4435d992bef9c84075594cBen Skeggs if (pm->clocks_pre) { 8277e7da6814623927cc4435d992bef9c84075594cBen Skeggs void *state = pm->clocks_pre(dev, perflvl); 8377e7da6814623927cc4435d992bef9c84075594cBen Skeggs if (IS_ERR(state)) 8477e7da6814623927cc4435d992bef9c84075594cBen Skeggs return PTR_ERR(state); 8577e7da6814623927cc4435d992bef9c84075594cBen Skeggs pm->clocks_set(dev, state); 8677e7da6814623927cc4435d992bef9c84075594cBen Skeggs } else 87da1dc4cfecdf314241cc5e0c5df1f66b4cc80cc7Ben Skeggs if (pm->clock_set) { 88da1dc4cfecdf314241cc5e0c5df1f66b4cc80cc7Ben Skeggs nouveau_pm_clock_set(dev, perflvl, PLL_CORE, perflvl->core); 89da1dc4cfecdf314241cc5e0c5df1f66b4cc80cc7Ben Skeggs nouveau_pm_clock_set(dev, perflvl, PLL_SHADER, perflvl->shader); 90da1dc4cfecdf314241cc5e0c5df1f66b4cc80cc7Ben Skeggs nouveau_pm_clock_set(dev, perflvl, PLL_MEMORY, perflvl->memory); 91da1dc4cfecdf314241cc5e0c5df1f66b4cc80cc7Ben Skeggs nouveau_pm_clock_set(dev, perflvl, PLL_UNK05, perflvl->unk05); 92da1dc4cfecdf314241cc5e0c5df1f66b4cc80cc7Ben Skeggs } 9364f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs 9464f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs pm->cur = perflvl; 9564f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs return 0; 9664f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs} 9764f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs 9864f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggsstatic int 996f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggsnouveau_pm_profile_set(struct drm_device *dev, const char *profile) 1006f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs{ 1016f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 1026f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 1036f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs struct nouveau_pm_level *perflvl = NULL; 1046f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 1056f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs /* safety precaution, for now */ 1066f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (nouveau_perflvl_wr != 7777) 1076f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs return -EPERM; 1086f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 1096f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (!strncmp(profile, "boot", 4)) 1106f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs perflvl = &pm->boot; 1116f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs else { 1126f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs int pl = simple_strtol(profile, NULL, 10); 1136f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs int i; 1146f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 1156f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs for (i = 0; i < pm->nr_perflvl; i++) { 1166f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (pm->perflvl[i].id == pl) { 1176f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs perflvl = &pm->perflvl[i]; 1186f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs break; 1196f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs } 1206f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs } 1216f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 1226f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (!perflvl) 1236f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs return -EINVAL; 1246f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs } 1256f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 1266f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs NV_INFO(dev, "setting performance level: %s\n", profile); 12764f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs return nouveau_pm_perflvl_set(dev, perflvl); 1286f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs} 1296f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 1306f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggsstatic int 131330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsnouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) 132330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 133330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 134330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 135330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs int ret; 136330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 137330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs memset(perflvl, 0, sizeof(*perflvl)); 138330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 13977e7da6814623927cc4435d992bef9c84075594cBen Skeggs if (pm->clocks_get) { 14077e7da6814623927cc4435d992bef9c84075594cBen Skeggs ret = pm->clocks_get(dev, perflvl); 14177e7da6814623927cc4435d992bef9c84075594cBen Skeggs if (ret) 14277e7da6814623927cc4435d992bef9c84075594cBen Skeggs return ret; 14377e7da6814623927cc4435d992bef9c84075594cBen Skeggs } else 14493dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs if (pm->clock_get) { 14593dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs ret = pm->clock_get(dev, PLL_CORE); 14693dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs if (ret > 0) 14793dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs perflvl->core = ret; 148330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 14993dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs ret = pm->clock_get(dev, PLL_MEMORY); 15093dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs if (ret > 0) 15193dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs perflvl->memory = ret; 152330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 15393dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs ret = pm->clock_get(dev, PLL_SHADER); 15493dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs if (ret > 0) 15593dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs perflvl->shader = ret; 156330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 15793dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs ret = pm->clock_get(dev, PLL_UNK05); 15893dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs if (ret > 0) 15993dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs perflvl->unk05 = ret; 16093dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs } 161330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 162330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (pm->voltage.supported && pm->voltage_get) { 163330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ret = pm->voltage_get(dev); 1643b5565ddfd8fe71f6470a5d240a6bb50ba90d4ffBen Skeggs if (ret > 0) { 1653b5565ddfd8fe71f6470a5d240a6bb50ba90d4ffBen Skeggs perflvl->volt_min = ret; 1663b5565ddfd8fe71f6470a5d240a6bb50ba90d4ffBen Skeggs perflvl->volt_max = ret; 1673b5565ddfd8fe71f6470a5d240a6bb50ba90d4ffBen Skeggs } 168330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs } 169330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 170771e1035b9bfdb0c3f0e34bd281d73b721a10adbBen Skeggs if (pm->fanspeed_get) 171771e1035b9bfdb0c3f0e34bd281d73b721a10adbBen Skeggs perflvl->fanspeed = pm->fanspeed_get(dev); 172771e1035b9bfdb0c3f0e34bd281d73b721a10adbBen Skeggs 173330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs return 0; 174330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 175330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 176330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsstatic void 177330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsnouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len) 178330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 17993dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs char c[16], s[16], v[32], f[16], t[16], m[16]; 1800fbb114af7ea63227599460c412fb8796556a169Francisco Jerez 1810fbb114af7ea63227599460c412fb8796556a169Francisco Jerez c[0] = '\0'; 1820fbb114af7ea63227599460c412fb8796556a169Francisco Jerez if (perflvl->core) 1830fbb114af7ea63227599460c412fb8796556a169Francisco Jerez snprintf(c, sizeof(c), " core %dMHz", perflvl->core / 1000); 184330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 185330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs s[0] = '\0'; 186330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (perflvl->shader) 187330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs snprintf(s, sizeof(s), " shader %dMHz", perflvl->shader / 1000); 188330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 18993dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs m[0] = '\0'; 19093dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs if (perflvl->memory) 19193dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs snprintf(m, sizeof(m), " memory %dMHz", perflvl->memory / 1000); 19293dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs 193330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs v[0] = '\0'; 1943b5565ddfd8fe71f6470a5d240a6bb50ba90d4ffBen Skeggs if (perflvl->volt_min && perflvl->volt_min != perflvl->volt_max) { 1953b5565ddfd8fe71f6470a5d240a6bb50ba90d4ffBen Skeggs snprintf(v, sizeof(v), " voltage %dmV-%dmV", 1963b5565ddfd8fe71f6470a5d240a6bb50ba90d4ffBen Skeggs perflvl->volt_min / 1000, perflvl->volt_max / 1000); 1973b5565ddfd8fe71f6470a5d240a6bb50ba90d4ffBen Skeggs } else 1983b5565ddfd8fe71f6470a5d240a6bb50ba90d4ffBen Skeggs if (perflvl->volt_min) { 1993b5565ddfd8fe71f6470a5d240a6bb50ba90d4ffBen Skeggs snprintf(v, sizeof(v), " voltage %dmV", 2003b5565ddfd8fe71f6470a5d240a6bb50ba90d4ffBen Skeggs perflvl->volt_min / 1000); 2013b5565ddfd8fe71f6470a5d240a6bb50ba90d4ffBen Skeggs } 202330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 203330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs f[0] = '\0'; 204330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (perflvl->fanspeed) 205330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs snprintf(f, sizeof(f), " fanspeed %d%%", perflvl->fanspeed); 206330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 207e614b2e7ca9f9946cede13b34c950b92af6fa7efMartin Peres t[0] = '\0'; 208e614b2e7ca9f9946cede13b34c950b92af6fa7efMartin Peres if (perflvl->timing) 209e614b2e7ca9f9946cede13b34c950b92af6fa7efMartin Peres snprintf(t, sizeof(t), " timing %d", perflvl->timing->id); 210e614b2e7ca9f9946cede13b34c950b92af6fa7efMartin Peres 21193dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs snprintf(ptr, len, "%s%s%s%s%s%s\n", c, s, m, t, v, f); 212330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 213330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 214330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsstatic ssize_t 215330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsnouveau_pm_get_perflvl_info(struct device *d, 216330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct device_attribute *a, char *buf) 217330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 218330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_level *perflvl = (struct nouveau_pm_level *)a; 219330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs char *ptr = buf; 220330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs int len = PAGE_SIZE; 221330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 22293dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs snprintf(ptr, len, "%d:", perflvl->id); 223330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ptr += strlen(buf); 224330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs len -= strlen(buf); 225330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 226330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs nouveau_pm_perflvl_info(perflvl, ptr, len); 227330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs return strlen(buf); 228330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 229330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 230330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsstatic ssize_t 231330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsnouveau_pm_get_perflvl(struct device *d, struct device_attribute *a, char *buf) 232330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 23334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = pci_get_drvdata(to_pci_dev(d)); 234330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 235330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 236330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_level cur; 237330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs int len = PAGE_SIZE, ret; 238330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs char *ptr = buf; 239330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 240330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (!pm->cur) 241330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs snprintf(ptr, len, "setting: boot\n"); 242330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs else if (pm->cur == &pm->boot) 24393dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs snprintf(ptr, len, "setting: boot\nc:"); 244330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs else 24593dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs snprintf(ptr, len, "setting: static %d\nc:", pm->cur->id); 246330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ptr += strlen(buf); 247330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs len -= strlen(buf); 248330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 249330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ret = nouveau_pm_perflvl_get(dev, &cur); 250330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (ret == 0) 251330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs nouveau_pm_perflvl_info(&cur, ptr, len); 252330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs return strlen(buf); 253330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 254330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 255330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsstatic ssize_t 256330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsnouveau_pm_set_perflvl(struct device *d, struct device_attribute *a, 257330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs const char *buf, size_t count) 258330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 25934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = pci_get_drvdata(to_pci_dev(d)); 2606f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs int ret; 2616f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 2626f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs ret = nouveau_pm_profile_set(dev, buf); 2636f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (ret) 2646f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs return ret; 2656f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs return strlen(buf); 266330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 267330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 2685c4abd09bdefb41d0c80055aa9d98433624ce1f0Francisco Jerezstatic DEVICE_ATTR(performance_level, S_IRUGO | S_IWUSR, 2695c4abd09bdefb41d0c80055aa9d98433624ce1f0Francisco Jerez nouveau_pm_get_perflvl, nouveau_pm_set_perflvl); 270330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 27134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic int 27234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_sysfs_init(struct drm_device *dev) 273330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 274330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 275330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 276330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct device *d = &dev->pdev->dev; 277330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs int ret, i; 278330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 279330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ret = device_create_file(d, &dev_attr_performance_level); 280330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (ret) 281330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs return ret; 282330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 283330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs for (i = 0; i < pm->nr_perflvl; i++) { 284330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_level *perflvl = &pm->perflvl[i]; 285330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 286330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->dev_attr.attr.name = perflvl->name; 287330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->dev_attr.attr.mode = S_IRUGO; 288330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->dev_attr.show = nouveau_pm_get_perflvl_info; 289330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->dev_attr.store = NULL; 290330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs sysfs_attr_init(&perflvl->dev_attr.attr); 291330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 292330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ret = device_create_file(d, &perflvl->dev_attr); 293330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (ret) { 294330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs NV_ERROR(dev, "failed pervlvl %d sysfs: %d\n", 295330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->id, i); 296330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->dev_attr.attr.name = NULL; 297330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs nouveau_pm_fini(dev); 298330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs return ret; 299330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs } 300330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs } 301330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 302330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs return 0; 303330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 304330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 30534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic void 30634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_sysfs_fini(struct drm_device *dev) 307330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 308330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 309330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 310330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct device *d = &dev->pdev->dev; 311330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs int i; 312330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 313330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs device_remove_file(d, &dev_attr_performance_level); 314330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs for (i = 0; i < pm->nr_perflvl; i++) { 315330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_level *pl = &pm->perflvl[i]; 316330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 317330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (!pl->dev_attr.attr.name) 318330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs break; 319330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 320330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs device_remove_file(d, &pl->dev_attr); 321330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs } 32234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 32334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 324658e86ee2db9500aea529a04008cce10972416bcKen Milmore#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) 32534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t 32634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf) 32734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 32834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = dev_get_drvdata(d); 3298155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez struct drm_nouveau_private *dev_priv = dev->dev_private; 3308155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 33134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 3328155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez return snprintf(buf, PAGE_SIZE, "%d\n", pm->temp_get(dev)*1000); 33334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 33434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, nouveau_hwmon_show_temp, 33534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NULL, 0); 33634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 33734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t 33834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_max_temp(struct device *d, struct device_attribute *a, char *buf) 33934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 34034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = dev_get_drvdata(d); 34134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 34234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 34334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; 34434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 34534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return snprintf(buf, PAGE_SIZE, "%d\n", temp->down_clock*1000); 34634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 34734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t 34834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_set_max_temp(struct device *d, struct device_attribute *a, 34934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres const char *buf, size_t count) 35034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 35134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = dev_get_drvdata(d); 35234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 35334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 35434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; 35534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres long value; 35634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 3575c4abd09bdefb41d0c80055aa9d98433624ce1f0Francisco Jerez if (strict_strtol(buf, 10, &value) == -EINVAL) 35834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return count; 35934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 36034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres temp->down_clock = value/1000; 36134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 36234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_temp_safety_checks(dev); 36334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 36434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return count; 36534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 36634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, nouveau_hwmon_max_temp, 36734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_hwmon_set_max_temp, 36834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 0); 36934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 37034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t 37134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_critical_temp(struct device *d, struct device_attribute *a, 37234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres char *buf) 37334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 37434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = dev_get_drvdata(d); 37534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 37634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 37734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; 37834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 37934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return snprintf(buf, PAGE_SIZE, "%d\n", temp->critical*1000); 38034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 38134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t 38234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a, 38334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres const char *buf, 38434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres size_t count) 38534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 38634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = dev_get_drvdata(d); 38734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 38834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 38934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; 39034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres long value; 39134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 3925c4abd09bdefb41d0c80055aa9d98433624ce1f0Francisco Jerez if (strict_strtol(buf, 10, &value) == -EINVAL) 39334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return count; 39434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 39534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres temp->critical = value/1000; 39634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 39734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_temp_safety_checks(dev); 39834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 39934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return count; 40034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 40134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR, 40234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_hwmon_critical_temp, 40334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_hwmon_set_critical_temp, 40434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 0); 40534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 40634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t nouveau_hwmon_show_name(struct device *dev, 40734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct device_attribute *attr, 40834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres char *buf) 40934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 41034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return sprintf(buf, "nouveau\n"); 41134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 41234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic SENSOR_DEVICE_ATTR(name, S_IRUGO, nouveau_hwmon_show_name, NULL, 0); 41334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 41434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t nouveau_hwmon_show_update_rate(struct device *dev, 41534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct device_attribute *attr, 41634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres char *buf) 41734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 41834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return sprintf(buf, "1000\n"); 41934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 42034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic SENSOR_DEVICE_ATTR(update_rate, S_IRUGO, 42134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_hwmon_show_update_rate, 42234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NULL, 0); 42334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 42434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic struct attribute *hwmon_attributes[] = { 42534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres &sensor_dev_attr_temp1_input.dev_attr.attr, 42634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres &sensor_dev_attr_temp1_max.dev_attr.attr, 42734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres &sensor_dev_attr_temp1_crit.dev_attr.attr, 42834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres &sensor_dev_attr_name.dev_attr.attr, 42934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres &sensor_dev_attr_update_rate.dev_attr.attr, 43034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NULL 43134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres}; 43234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 43334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic const struct attribute_group hwmon_attrgroup = { 43434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres .attrs = hwmon_attributes, 43534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres}; 436b54262f3c828ee17e27632d0d60255281c02e1a5Martin Peres#endif 43734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 43834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic int 43934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_init(struct drm_device *dev) 44034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 441658e86ee2db9500aea529a04008cce10972416bcKen Milmore#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) 44234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 4438155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 44434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct device *hwmon_dev; 44534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres int ret; 44634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 4478155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez if (!pm->temp_get) 4488155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez return -ENODEV; 44934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 45034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres hwmon_dev = hwmon_device_register(&dev->pdev->dev); 45134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres if (IS_ERR(hwmon_dev)) { 45234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres ret = PTR_ERR(hwmon_dev); 45334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NV_ERROR(dev, 45434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres "Unable to register hwmon device: %d\n", ret); 45534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return ret; 45634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 45734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres dev_set_drvdata(hwmon_dev, dev); 45807cfe0e7a820ecad078c04e9c2a102521709145dLucas Stach ret = sysfs_create_group(&dev->pdev->dev.kobj, &hwmon_attrgroup); 45934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres if (ret) { 46034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NV_ERROR(dev, 46134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres "Unable to create hwmon sysfs file: %d\n", ret); 46234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres hwmon_device_unregister(hwmon_dev); 46334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return ret; 46434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 46534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 4668155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez pm->hwmon = hwmon_dev; 467b54262f3c828ee17e27632d0d60255281c02e1a5Martin Peres#endif 46834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return 0; 46934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 47034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 47134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic void 47234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_fini(struct drm_device *dev) 47334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 474658e86ee2db9500aea529a04008cce10972416bcKen Milmore#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) 47534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 4768155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 47734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 4788155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez if (pm->hwmon) { 4798c06a3e02062a9beb71a9444c49fb0fbcaa1eed3Lucas Stach sysfs_remove_group(&dev->pdev->dev.kobj, &hwmon_attrgroup); 4808155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez hwmon_device_unregister(pm->hwmon); 48134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 482b54262f3c828ee17e27632d0d60255281c02e1a5Martin Peres#endif 48334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 48434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 4851f962797fb1343f02cbacb94d80c4560d47b67a9Martin Peres#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY) 4866032649df9f456f379be8d51f64488cacbfa8317Ben Skeggsstatic int 4876032649df9f456f379be8d51f64488cacbfa8317Ben Skeggsnouveau_pm_acpi_event(struct notifier_block *nb, unsigned long val, void *data) 4886032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs{ 4896032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs struct drm_nouveau_private *dev_priv = 4906032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs container_of(nb, struct drm_nouveau_private, engine.pm.acpi_nb); 4916032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs struct drm_device *dev = dev_priv->dev; 4926032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs struct acpi_bus_event *entry = (struct acpi_bus_event *)data; 4936032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs 4946032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs if (strcmp(entry->device_class, "ac_adapter") == 0) { 4956032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs bool ac = power_supply_is_system_supplied(); 4966032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs 4976032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs NV_DEBUG(dev, "power supply changed: %s\n", ac ? "AC" : "DC"); 4986032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs } 4996032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs 5006032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs return NOTIFY_OK; 5016032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs} 5026032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs#endif 5036032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs 50434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresint 50534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_pm_init(struct drm_device *dev) 50634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 50734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 50834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 50934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres char info[256]; 51034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres int ret, i; 51134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 512e614b2e7ca9f9946cede13b34c950b92af6fa7efMartin Peres nouveau_mem_timing_init(dev); 51334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_volt_init(dev); 51434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_perf_init(dev); 51534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_temp_init(dev); 51634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 51734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NV_INFO(dev, "%d available performance level(s)\n", pm->nr_perflvl); 51834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres for (i = 0; i < pm->nr_perflvl; i++) { 51934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_pm_perflvl_info(&pm->perflvl[i], info, sizeof(info)); 52093dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs NV_INFO(dev, "%d:%s", pm->perflvl[i].id, info); 52134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 52234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 52334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres /* determine current ("boot") performance level */ 52434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres ret = nouveau_pm_perflvl_get(dev, &pm->boot); 52534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres if (ret == 0) { 52601e542c65de11a47e726ebef63f5e59b4a74568dMartin Peres strncpy(pm->boot.name, "boot", 4); 52734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres pm->cur = &pm->boot; 52834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 52934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info)); 53093dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs NV_INFO(dev, "c:%s", info); 53134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 53234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 53334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres /* switch performance levels now if requested */ 53434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres if (nouveau_perflvl != NULL) { 53534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres ret = nouveau_pm_profile_set(dev, nouveau_perflvl); 53634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres if (ret) { 53734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NV_ERROR(dev, "error setting perflvl \"%s\": %d\n", 53834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_perflvl, ret); 53934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 54034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 54134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 54234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_sysfs_init(dev); 54334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_hwmon_init(dev); 5441f962797fb1343f02cbacb94d80c4560d47b67a9Martin Peres#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY) 5456032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs pm->acpi_nb.notifier_call = nouveau_pm_acpi_event; 5466032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs register_acpi_notifier(&pm->acpi_nb); 5476032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs#endif 54834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 54934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return 0; 55034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 55134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 55234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresvoid 55334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_pm_fini(struct drm_device *dev) 55434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 55534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 55634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 55734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 55834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres if (pm->cur != &pm->boot) 55934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_pm_perflvl_set(dev, &pm->boot); 560330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 5617760fcb020b41352af4e675ce65a6aa0e93c170fRoy Spliet nouveau_temp_fini(dev); 562330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs nouveau_perf_fini(dev); 563330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs nouveau_volt_fini(dev); 564e614b2e7ca9f9946cede13b34c950b92af6fa7efMartin Peres nouveau_mem_timing_fini(dev); 56534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 5661f962797fb1343f02cbacb94d80c4560d47b67a9Martin Peres#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY) 5676032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs unregister_acpi_notifier(&pm->acpi_nb); 5686032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs#endif 56934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_hwmon_fini(dev); 57034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_sysfs_fini(dev); 571330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 572330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 57364f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggsvoid 57464f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggsnouveau_pm_resume(struct drm_device *dev) 57564f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs{ 57664f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 57764f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 57864f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs struct nouveau_pm_level *perflvl; 57964f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs 580317495b25ec1f0beb0dbac8ee0dfec59a1addf03Ben Skeggs if (!pm->cur || pm->cur == &pm->boot) 58164f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs return; 58264f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs 58364f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs perflvl = pm->cur; 58464f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs pm->cur = &pm->boot; 58564f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs nouveau_pm_perflvl_set(dev, perflvl); 58664f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs} 587