nouveau_pm.c revision 5c4abd09bdefb41d0c80055aa9d98433624ce1f0
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 3034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres#include <linux/hwmon.h> 3134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres#include <linux/hwmon-sysfs.h> 3234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 33330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsstatic int 346f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggsnouveau_pm_clock_set(struct drm_device *dev, u8 id, u32 khz) 356f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs{ 366f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 376f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 386f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs void *pre_state; 396f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 406f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (khz == 0) 416f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs return 0; 426f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 436f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs pre_state = pm->clock_pre(dev, id, khz); 446f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (IS_ERR(pre_state)) 456f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs return PTR_ERR(pre_state); 466f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 476f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (pre_state) 486f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs pm->clock_set(dev, pre_state); 496f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs return 0; 506f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs} 516f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 526f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggsstatic int 5364f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggsnouveau_pm_perflvl_set(struct drm_device *dev, struct nouveau_pm_level *perflvl) 5464f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs{ 5564f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 5664f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 5764f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs int ret; 5864f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs 5964f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs if (perflvl == pm->cur) 6064f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs return 0; 6164f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs 6264f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs if (pm->voltage.supported && pm->voltage_set && perflvl->voltage) { 6364f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs ret = pm->voltage_set(dev, perflvl->voltage); 6464f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs if (ret) { 6564f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs NV_ERROR(dev, "voltage_set %d failed: %d\n", 6664f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs perflvl->voltage, ret); 6764f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs } 6864f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs } 6964f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs 7064f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs nouveau_pm_clock_set(dev, PLL_CORE, perflvl->core); 7164f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs nouveau_pm_clock_set(dev, PLL_SHADER, perflvl->shader); 7264f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs nouveau_pm_clock_set(dev, PLL_MEMORY, perflvl->memory); 7364f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs nouveau_pm_clock_set(dev, PLL_UNK05, perflvl->unk05); 7464f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs 7564f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs pm->cur = perflvl; 7664f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs return 0; 7764f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs} 7864f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs 7964f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggsstatic int 806f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggsnouveau_pm_profile_set(struct drm_device *dev, const char *profile) 816f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs{ 826f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 836f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 846f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs struct nouveau_pm_level *perflvl = NULL; 856f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 866f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs /* safety precaution, for now */ 876f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (nouveau_perflvl_wr != 7777) 886f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs return -EPERM; 896f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 906f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (!pm->clock_set) 916f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs return -EINVAL; 926f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 936f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (!strncmp(profile, "boot", 4)) 946f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs perflvl = &pm->boot; 956f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs else { 966f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs int pl = simple_strtol(profile, NULL, 10); 976f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs int i; 986f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 996f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs for (i = 0; i < pm->nr_perflvl; i++) { 1006f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (pm->perflvl[i].id == pl) { 1016f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs perflvl = &pm->perflvl[i]; 1026f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs break; 1036f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs } 1046f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs } 1056f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 1066f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (!perflvl) 1076f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs return -EINVAL; 1086f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs } 1096f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 1106f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs NV_INFO(dev, "setting performance level: %s\n", profile); 11164f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs return nouveau_pm_perflvl_set(dev, perflvl); 1126f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs} 1136f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 1146f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggsstatic int 115330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsnouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) 116330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 117330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 118330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 119330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs int ret; 120330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 121330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (!pm->clock_get) 122330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs return -EINVAL; 123330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 124330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs memset(perflvl, 0, sizeof(*perflvl)); 125330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 126330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ret = pm->clock_get(dev, PLL_CORE); 127330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (ret > 0) 128330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->core = ret; 129330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 130330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ret = pm->clock_get(dev, PLL_MEMORY); 131330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (ret > 0) 132330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->memory = ret; 133330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 134330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ret = pm->clock_get(dev, PLL_SHADER); 135330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (ret > 0) 136330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->shader = ret; 137330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 138330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ret = pm->clock_get(dev, PLL_UNK05); 139330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (ret > 0) 140330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->unk05 = ret; 141330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 142330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (pm->voltage.supported && pm->voltage_get) { 143330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ret = pm->voltage_get(dev); 144330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (ret > 0) 145330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->voltage = ret; 146330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs } 147330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 148330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs return 0; 149330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 150330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 151330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsstatic void 152330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsnouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len) 153330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 1540fbb114af7ea63227599460c412fb8796556a169Francisco Jerez char c[16], s[16], v[16], f[16]; 1550fbb114af7ea63227599460c412fb8796556a169Francisco Jerez 1560fbb114af7ea63227599460c412fb8796556a169Francisco Jerez c[0] = '\0'; 1570fbb114af7ea63227599460c412fb8796556a169Francisco Jerez if (perflvl->core) 1580fbb114af7ea63227599460c412fb8796556a169Francisco Jerez snprintf(c, sizeof(c), " core %dMHz", perflvl->core / 1000); 159330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 160330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs s[0] = '\0'; 161330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (perflvl->shader) 162330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs snprintf(s, sizeof(s), " shader %dMHz", perflvl->shader / 1000); 163330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 164330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs v[0] = '\0'; 165330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (perflvl->voltage) 166330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs snprintf(v, sizeof(v), " voltage %dmV", perflvl->voltage * 10); 167330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 168330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs f[0] = '\0'; 169330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (perflvl->fanspeed) 170330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs snprintf(f, sizeof(f), " fanspeed %d%%", perflvl->fanspeed); 171330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 1720fbb114af7ea63227599460c412fb8796556a169Francisco Jerez snprintf(ptr, len, "memory %dMHz%s%s%s%s\n", perflvl->memory / 1000, 1730fbb114af7ea63227599460c412fb8796556a169Francisco Jerez c, s, v, f); 174330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 175330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 176330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsstatic ssize_t 177330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsnouveau_pm_get_perflvl_info(struct device *d, 178330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct device_attribute *a, char *buf) 179330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 180330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_level *perflvl = (struct nouveau_pm_level *)a; 181330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs char *ptr = buf; 182330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs int len = PAGE_SIZE; 183330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 184330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs snprintf(ptr, len, "%d: ", perflvl->id); 185330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ptr += strlen(buf); 186330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs len -= strlen(buf); 187330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 188330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs nouveau_pm_perflvl_info(perflvl, ptr, len); 189330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs return strlen(buf); 190330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 191330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 192330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsstatic ssize_t 193330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsnouveau_pm_get_perflvl(struct device *d, struct device_attribute *a, char *buf) 194330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 19534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = pci_get_drvdata(to_pci_dev(d)); 196330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 197330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 198330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_level cur; 199330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs int len = PAGE_SIZE, ret; 200330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs char *ptr = buf; 201330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 202330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (!pm->cur) 203330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs snprintf(ptr, len, "setting: boot\n"); 204330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs else if (pm->cur == &pm->boot) 205330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs snprintf(ptr, len, "setting: boot\nc: "); 206330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs else 207330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs snprintf(ptr, len, "setting: static %d\nc: ", pm->cur->id); 208330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ptr += strlen(buf); 209330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs len -= strlen(buf); 210330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 211330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ret = nouveau_pm_perflvl_get(dev, &cur); 212330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (ret == 0) 213330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs nouveau_pm_perflvl_info(&cur, ptr, len); 214330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs return strlen(buf); 215330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 216330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 217330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsstatic ssize_t 218330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsnouveau_pm_set_perflvl(struct device *d, struct device_attribute *a, 219330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs const char *buf, size_t count) 220330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 22134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = pci_get_drvdata(to_pci_dev(d)); 2226f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs int ret; 2236f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 2246f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs ret = nouveau_pm_profile_set(dev, buf); 2256f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (ret) 2266f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs return ret; 2276f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs return strlen(buf); 228330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 229330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 2305c4abd09bdefb41d0c80055aa9d98433624ce1f0Francisco Jerezstatic DEVICE_ATTR(performance_level, S_IRUGO | S_IWUSR, 2315c4abd09bdefb41d0c80055aa9d98433624ce1f0Francisco Jerez nouveau_pm_get_perflvl, nouveau_pm_set_perflvl); 232330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 23334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic int 23434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_sysfs_init(struct drm_device *dev) 235330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 236330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 237330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 238330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct device *d = &dev->pdev->dev; 239330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs int ret, i; 240330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 241330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ret = device_create_file(d, &dev_attr_performance_level); 242330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (ret) 243330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs return ret; 244330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 245330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs for (i = 0; i < pm->nr_perflvl; i++) { 246330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_level *perflvl = &pm->perflvl[i]; 247330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 248330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->dev_attr.attr.name = perflvl->name; 249330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->dev_attr.attr.mode = S_IRUGO; 250330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->dev_attr.show = nouveau_pm_get_perflvl_info; 251330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->dev_attr.store = NULL; 252330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs sysfs_attr_init(&perflvl->dev_attr.attr); 253330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 254330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ret = device_create_file(d, &perflvl->dev_attr); 255330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (ret) { 256330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs NV_ERROR(dev, "failed pervlvl %d sysfs: %d\n", 257330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->id, i); 258330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->dev_attr.attr.name = NULL; 259330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs nouveau_pm_fini(dev); 260330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs return ret; 261330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs } 262330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs } 263330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 264330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs return 0; 265330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 266330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 26734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic void 26834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_sysfs_fini(struct drm_device *dev) 269330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 270330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 271330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 272330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct device *d = &dev->pdev->dev; 273330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs int i; 274330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 275330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs device_remove_file(d, &dev_attr_performance_level); 276330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs for (i = 0; i < pm->nr_perflvl; i++) { 277330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_level *pl = &pm->perflvl[i]; 278330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 279330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (!pl->dev_attr.attr.name) 280330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs break; 281330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 282330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs device_remove_file(d, &pl->dev_attr); 283330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs } 28434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 28534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 28634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t 28734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf) 28834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 28934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = dev_get_drvdata(d); 2908155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez struct drm_nouveau_private *dev_priv = dev->dev_private; 2918155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 29234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 2938155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez return snprintf(buf, PAGE_SIZE, "%d\n", pm->temp_get(dev)*1000); 29434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 29534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, nouveau_hwmon_show_temp, 29634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NULL, 0); 29734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 29834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t 29934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_max_temp(struct device *d, struct device_attribute *a, char *buf) 30034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 30134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = dev_get_drvdata(d); 30234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 30334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 30434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; 30534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 30634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return snprintf(buf, PAGE_SIZE, "%d\n", temp->down_clock*1000); 30734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 30834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t 30934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_set_max_temp(struct device *d, struct device_attribute *a, 31034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres const char *buf, size_t count) 31134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 31234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = dev_get_drvdata(d); 31334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 31434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 31534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; 31634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres long value; 31734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 3185c4abd09bdefb41d0c80055aa9d98433624ce1f0Francisco Jerez if (strict_strtol(buf, 10, &value) == -EINVAL) 31934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return count; 32034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 32134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres temp->down_clock = value/1000; 32234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 32334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_temp_safety_checks(dev); 32434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 32534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return count; 32634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 32734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, nouveau_hwmon_max_temp, 32834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_hwmon_set_max_temp, 32934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 0); 33034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 33134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t 33234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_critical_temp(struct device *d, struct device_attribute *a, 33334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres char *buf) 33434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 33534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = dev_get_drvdata(d); 33634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 33734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 33834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; 33934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 34034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return snprintf(buf, PAGE_SIZE, "%d\n", temp->critical*1000); 34134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 34234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t 34334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a, 34434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres const char *buf, 34534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres size_t count) 34634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 34734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = dev_get_drvdata(d); 34834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 34934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 35034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; 35134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres long value; 35234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 3535c4abd09bdefb41d0c80055aa9d98433624ce1f0Francisco Jerez if (strict_strtol(buf, 10, &value) == -EINVAL) 35434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return count; 35534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 35634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres temp->critical = value/1000; 35734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 35834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_temp_safety_checks(dev); 35934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 36034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return count; 36134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 36234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR, 36334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_hwmon_critical_temp, 36434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_hwmon_set_critical_temp, 36534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 0); 36634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 36734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t nouveau_hwmon_show_name(struct device *dev, 36834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct device_attribute *attr, 36934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres char *buf) 37034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 37134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return sprintf(buf, "nouveau\n"); 37234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 37334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic SENSOR_DEVICE_ATTR(name, S_IRUGO, nouveau_hwmon_show_name, NULL, 0); 37434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 37534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t nouveau_hwmon_show_update_rate(struct device *dev, 37634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct device_attribute *attr, 37734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres char *buf) 37834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 37934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return sprintf(buf, "1000\n"); 38034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 38134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic SENSOR_DEVICE_ATTR(update_rate, S_IRUGO, 38234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_hwmon_show_update_rate, 38334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NULL, 0); 38434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 38534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic struct attribute *hwmon_attributes[] = { 38634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres &sensor_dev_attr_temp1_input.dev_attr.attr, 38734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres &sensor_dev_attr_temp1_max.dev_attr.attr, 38834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres &sensor_dev_attr_temp1_crit.dev_attr.attr, 38934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres &sensor_dev_attr_name.dev_attr.attr, 39034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres &sensor_dev_attr_update_rate.dev_attr.attr, 39134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NULL 39234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres}; 39334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 39434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic const struct attribute_group hwmon_attrgroup = { 39534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres .attrs = hwmon_attributes, 39634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres}; 39734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 39834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic int 39934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_init(struct drm_device *dev) 40034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 40134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 4028155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 40334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct device *hwmon_dev; 40434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres int ret; 40534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 4068155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez if (!pm->temp_get) 4078155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez return -ENODEV; 40834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 40934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres hwmon_dev = hwmon_device_register(&dev->pdev->dev); 41034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres if (IS_ERR(hwmon_dev)) { 41134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres ret = PTR_ERR(hwmon_dev); 41234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NV_ERROR(dev, 41334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres "Unable to register hwmon device: %d\n", ret); 41434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return ret; 41534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 41634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres dev_set_drvdata(hwmon_dev, dev); 41734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres ret = sysfs_create_group(&hwmon_dev->kobj, 41834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres &hwmon_attrgroup); 41934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres if (ret) { 42034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NV_ERROR(dev, 42134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres "Unable to create hwmon sysfs file: %d\n", ret); 42234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres hwmon_device_unregister(hwmon_dev); 42334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return ret; 42434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 42534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 4268155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez pm->hwmon = hwmon_dev; 42734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 42834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return 0; 42934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 43034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 43134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic void 43234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_fini(struct drm_device *dev) 43334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 43434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 4358155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 43634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 4378155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez if (pm->hwmon) { 4388155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez sysfs_remove_group(&pm->hwmon->kobj, &hwmon_attrgroup); 4398155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez hwmon_device_unregister(pm->hwmon); 44034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 44134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 44234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 44334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresint 44434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_pm_init(struct drm_device *dev) 44534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 44634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 44734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 44834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres char info[256]; 44934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres int ret, i; 45034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 45134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_volt_init(dev); 45234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_perf_init(dev); 45334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_temp_init(dev); 45434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 45534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NV_INFO(dev, "%d available performance level(s)\n", pm->nr_perflvl); 45634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres for (i = 0; i < pm->nr_perflvl; i++) { 45734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_pm_perflvl_info(&pm->perflvl[i], info, sizeof(info)); 45834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NV_INFO(dev, "%d: %s", pm->perflvl[i].id, info); 45934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 46034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 46134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres /* determine current ("boot") performance level */ 46234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres ret = nouveau_pm_perflvl_get(dev, &pm->boot); 46334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres if (ret == 0) { 46434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres pm->cur = &pm->boot; 46534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 46634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info)); 46734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NV_INFO(dev, "c: %s", info); 46834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 46934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 47034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres /* switch performance levels now if requested */ 47134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres if (nouveau_perflvl != NULL) { 47234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres ret = nouveau_pm_profile_set(dev, nouveau_perflvl); 47334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres if (ret) { 47434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NV_ERROR(dev, "error setting perflvl \"%s\": %d\n", 47534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_perflvl, ret); 47634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 47734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 47834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 47934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_sysfs_init(dev); 48034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_hwmon_init(dev); 48134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 48234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return 0; 48334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 48434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 48534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresvoid 48634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_pm_fini(struct drm_device *dev) 48734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 48834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 48934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 49034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 49134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres if (pm->cur != &pm->boot) 49234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_pm_perflvl_set(dev, &pm->boot); 493330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 494330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs nouveau_perf_fini(dev); 495330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs nouveau_volt_fini(dev); 49634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_temp_fini(dev); 49734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 49834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_hwmon_fini(dev); 49934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_sysfs_fini(dev); 500330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 501330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 50264f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggsvoid 50364f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggsnouveau_pm_resume(struct drm_device *dev) 50464f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs{ 50564f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 50664f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 50764f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs struct nouveau_pm_level *perflvl; 50864f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs 50964f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs if (pm->cur == &pm->boot) 51064f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs return; 51164f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs 51264f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs perflvl = pm->cur; 51364f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs pm->cur = &pm->boot; 51464f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs nouveau_pm_perflvl_set(dev, perflvl); 51564f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs} 516