nouveau_pm.c revision e614b2e7ca9f9946cede13b34c950b92af6fa7ef
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 6764f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs if (pm->voltage.supported && pm->voltage_set && perflvl->voltage) { 6864f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs ret = pm->voltage_set(dev, perflvl->voltage); 6964f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs if (ret) { 7064f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs NV_ERROR(dev, "voltage_set %d failed: %d\n", 7164f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs perflvl->voltage, ret); 7264f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs } 7364f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs } 7464f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs 755c6dc6575460a0afe56d8cae7666e769e08ef942Ben Skeggs nouveau_pm_clock_set(dev, perflvl, PLL_CORE, perflvl->core); 765c6dc6575460a0afe56d8cae7666e769e08ef942Ben Skeggs nouveau_pm_clock_set(dev, perflvl, PLL_SHADER, perflvl->shader); 775c6dc6575460a0afe56d8cae7666e769e08ef942Ben Skeggs nouveau_pm_clock_set(dev, perflvl, PLL_MEMORY, perflvl->memory); 785c6dc6575460a0afe56d8cae7666e769e08ef942Ben Skeggs nouveau_pm_clock_set(dev, perflvl, PLL_UNK05, perflvl->unk05); 7964f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs 8064f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs pm->cur = perflvl; 8164f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs return 0; 8264f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs} 8364f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs 8464f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggsstatic int 856f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggsnouveau_pm_profile_set(struct drm_device *dev, const char *profile) 866f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs{ 876f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 886f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 896f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs struct nouveau_pm_level *perflvl = NULL; 906f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 916f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs /* safety precaution, for now */ 926f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (nouveau_perflvl_wr != 7777) 936f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs return -EPERM; 946f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 956f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (!pm->clock_set) 966f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs return -EINVAL; 976f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 986f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (!strncmp(profile, "boot", 4)) 996f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs perflvl = &pm->boot; 1006f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs else { 1016f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs int pl = simple_strtol(profile, NULL, 10); 1026f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs int i; 1036f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 1046f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs for (i = 0; i < pm->nr_perflvl; i++) { 1056f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (pm->perflvl[i].id == pl) { 1066f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs perflvl = &pm->perflvl[i]; 1076f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs break; 1086f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs } 1096f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs } 1106f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 1116f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (!perflvl) 1126f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs return -EINVAL; 1136f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs } 1146f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 1156f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs NV_INFO(dev, "setting performance level: %s\n", profile); 11664f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs return nouveau_pm_perflvl_set(dev, perflvl); 1176f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs} 1186f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 1196f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggsstatic int 120330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsnouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) 121330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 122330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 123330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 124330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs int ret; 125330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 126330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (!pm->clock_get) 127330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs return -EINVAL; 128330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 129330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs memset(perflvl, 0, sizeof(*perflvl)); 130330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 131330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ret = pm->clock_get(dev, PLL_CORE); 132330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (ret > 0) 133330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->core = ret; 134330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 135330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ret = pm->clock_get(dev, PLL_MEMORY); 136330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (ret > 0) 137330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->memory = ret; 138330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 139330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ret = pm->clock_get(dev, PLL_SHADER); 140330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (ret > 0) 141330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->shader = ret; 142330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 143330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ret = pm->clock_get(dev, PLL_UNK05); 144330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (ret > 0) 145330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->unk05 = ret; 146330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 147330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (pm->voltage.supported && pm->voltage_get) { 148330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ret = pm->voltage_get(dev); 149330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (ret > 0) 150330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->voltage = ret; 151330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs } 152330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 153330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs return 0; 154330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 155330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 156330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsstatic void 157330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsnouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len) 158330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 159e614b2e7ca9f9946cede13b34c950b92af6fa7efMartin Peres char c[16], s[16], v[16], f[16], t[16]; 1600fbb114af7ea63227599460c412fb8796556a169Francisco Jerez 1610fbb114af7ea63227599460c412fb8796556a169Francisco Jerez c[0] = '\0'; 1620fbb114af7ea63227599460c412fb8796556a169Francisco Jerez if (perflvl->core) 1630fbb114af7ea63227599460c412fb8796556a169Francisco Jerez snprintf(c, sizeof(c), " core %dMHz", perflvl->core / 1000); 164330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 165330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs s[0] = '\0'; 166330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (perflvl->shader) 167330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs snprintf(s, sizeof(s), " shader %dMHz", perflvl->shader / 1000); 168330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 169330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs v[0] = '\0'; 170330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (perflvl->voltage) 171330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs snprintf(v, sizeof(v), " voltage %dmV", perflvl->voltage * 10); 172330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 173330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs f[0] = '\0'; 174330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (perflvl->fanspeed) 175330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs snprintf(f, sizeof(f), " fanspeed %d%%", perflvl->fanspeed); 176330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 177e614b2e7ca9f9946cede13b34c950b92af6fa7efMartin Peres t[0] = '\0'; 178e614b2e7ca9f9946cede13b34c950b92af6fa7efMartin Peres if (perflvl->timing) 179e614b2e7ca9f9946cede13b34c950b92af6fa7efMartin Peres snprintf(t, sizeof(t), " timing %d", perflvl->timing->id); 180e614b2e7ca9f9946cede13b34c950b92af6fa7efMartin Peres 181e614b2e7ca9f9946cede13b34c950b92af6fa7efMartin Peres snprintf(ptr, len, "memory %dMHz%s%s%s%s%s\n", perflvl->memory / 1000, 182e614b2e7ca9f9946cede13b34c950b92af6fa7efMartin Peres c, s, v, f, t); 183330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 184330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 185330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsstatic ssize_t 186330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsnouveau_pm_get_perflvl_info(struct device *d, 187330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct device_attribute *a, char *buf) 188330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 189330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_level *perflvl = (struct nouveau_pm_level *)a; 190330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs char *ptr = buf; 191330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs int len = PAGE_SIZE; 192330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 193330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs snprintf(ptr, len, "%d: ", perflvl->id); 194330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ptr += strlen(buf); 195330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs len -= strlen(buf); 196330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 197330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs nouveau_pm_perflvl_info(perflvl, ptr, len); 198330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs return strlen(buf); 199330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 200330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 201330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsstatic ssize_t 202330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsnouveau_pm_get_perflvl(struct device *d, struct device_attribute *a, char *buf) 203330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 20434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = pci_get_drvdata(to_pci_dev(d)); 205330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 206330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 207330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_level cur; 208330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs int len = PAGE_SIZE, ret; 209330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs char *ptr = buf; 210330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 211330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (!pm->cur) 212330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs snprintf(ptr, len, "setting: boot\n"); 213330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs else if (pm->cur == &pm->boot) 214330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs snprintf(ptr, len, "setting: boot\nc: "); 215330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs else 216330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs snprintf(ptr, len, "setting: static %d\nc: ", pm->cur->id); 217330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ptr += strlen(buf); 218330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs len -= strlen(buf); 219330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 220330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ret = nouveau_pm_perflvl_get(dev, &cur); 221330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (ret == 0) 222330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs nouveau_pm_perflvl_info(&cur, ptr, len); 223330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs return strlen(buf); 224330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 225330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 226330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsstatic ssize_t 227330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsnouveau_pm_set_perflvl(struct device *d, struct device_attribute *a, 228330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs const char *buf, size_t count) 229330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 23034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = pci_get_drvdata(to_pci_dev(d)); 2316f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs int ret; 2326f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 2336f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs ret = nouveau_pm_profile_set(dev, buf); 2346f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (ret) 2356f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs return ret; 2366f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs return strlen(buf); 237330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 238330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 2395c4abd09bdefb41d0c80055aa9d98433624ce1f0Francisco Jerezstatic DEVICE_ATTR(performance_level, S_IRUGO | S_IWUSR, 2405c4abd09bdefb41d0c80055aa9d98433624ce1f0Francisco Jerez nouveau_pm_get_perflvl, nouveau_pm_set_perflvl); 241330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 24234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic int 24334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_sysfs_init(struct drm_device *dev) 244330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 245330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 246330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 247330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct device *d = &dev->pdev->dev; 248330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs int ret, i; 249330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 250330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ret = device_create_file(d, &dev_attr_performance_level); 251330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (ret) 252330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs return ret; 253330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 254330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs for (i = 0; i < pm->nr_perflvl; i++) { 255330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_level *perflvl = &pm->perflvl[i]; 256330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 257330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->dev_attr.attr.name = perflvl->name; 258330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->dev_attr.attr.mode = S_IRUGO; 259330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->dev_attr.show = nouveau_pm_get_perflvl_info; 260330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->dev_attr.store = NULL; 261330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs sysfs_attr_init(&perflvl->dev_attr.attr); 262330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 263330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ret = device_create_file(d, &perflvl->dev_attr); 264330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (ret) { 265330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs NV_ERROR(dev, "failed pervlvl %d sysfs: %d\n", 266330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->id, i); 267330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->dev_attr.attr.name = NULL; 268330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs nouveau_pm_fini(dev); 269330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs return ret; 270330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs } 271330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs } 272330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 273330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs return 0; 274330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 275330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 27634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic void 27734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_sysfs_fini(struct drm_device *dev) 278330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 279330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 280330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 281330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct device *d = &dev->pdev->dev; 282330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs int i; 283330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 284330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs device_remove_file(d, &dev_attr_performance_level); 285330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs for (i = 0; i < pm->nr_perflvl; i++) { 286330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_level *pl = &pm->perflvl[i]; 287330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 288330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (!pl->dev_attr.attr.name) 289330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs break; 290330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 291330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs device_remove_file(d, &pl->dev_attr); 292330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs } 29334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 29434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 295b54262f3c828ee17e27632d0d60255281c02e1a5Martin Peres#ifdef CONFIG_HWMON 29634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t 29734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf) 29834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 29934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = dev_get_drvdata(d); 3008155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez struct drm_nouveau_private *dev_priv = dev->dev_private; 3018155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 30234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 3038155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez return snprintf(buf, PAGE_SIZE, "%d\n", pm->temp_get(dev)*1000); 30434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 30534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, nouveau_hwmon_show_temp, 30634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NULL, 0); 30734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 30834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t 30934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_max_temp(struct device *d, struct device_attribute *a, char *buf) 31034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 31134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = dev_get_drvdata(d); 31234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 31334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 31434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; 31534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 31634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return snprintf(buf, PAGE_SIZE, "%d\n", temp->down_clock*1000); 31734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 31834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t 31934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_set_max_temp(struct device *d, struct device_attribute *a, 32034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres const char *buf, size_t count) 32134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 32234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = dev_get_drvdata(d); 32334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 32434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 32534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; 32634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres long value; 32734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 3285c4abd09bdefb41d0c80055aa9d98433624ce1f0Francisco Jerez if (strict_strtol(buf, 10, &value) == -EINVAL) 32934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return count; 33034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 33134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres temp->down_clock = value/1000; 33234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 33334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_temp_safety_checks(dev); 33434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 33534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return count; 33634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 33734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, nouveau_hwmon_max_temp, 33834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_hwmon_set_max_temp, 33934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 0); 34034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 34134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t 34234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_critical_temp(struct device *d, struct device_attribute *a, 34334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres char *buf) 34434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 34534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = dev_get_drvdata(d); 34634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 34734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 34834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; 34934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 35034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return snprintf(buf, PAGE_SIZE, "%d\n", temp->critical*1000); 35134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 35234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t 35334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a, 35434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres const char *buf, 35534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres size_t count) 35634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 35734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = dev_get_drvdata(d); 35834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 35934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 36034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; 36134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres long value; 36234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 3635c4abd09bdefb41d0c80055aa9d98433624ce1f0Francisco Jerez if (strict_strtol(buf, 10, &value) == -EINVAL) 36434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return count; 36534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 36634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres temp->critical = value/1000; 36734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 36834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_temp_safety_checks(dev); 36934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 37034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return count; 37134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 37234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR, 37334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_hwmon_critical_temp, 37434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_hwmon_set_critical_temp, 37534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 0); 37634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 37734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t nouveau_hwmon_show_name(struct device *dev, 37834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct device_attribute *attr, 37934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres char *buf) 38034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 38134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return sprintf(buf, "nouveau\n"); 38234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 38334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic SENSOR_DEVICE_ATTR(name, S_IRUGO, nouveau_hwmon_show_name, NULL, 0); 38434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 38534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t nouveau_hwmon_show_update_rate(struct device *dev, 38634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct device_attribute *attr, 38734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres char *buf) 38834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 38934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return sprintf(buf, "1000\n"); 39034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 39134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic SENSOR_DEVICE_ATTR(update_rate, S_IRUGO, 39234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_hwmon_show_update_rate, 39334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NULL, 0); 39434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 39534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic struct attribute *hwmon_attributes[] = { 39634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres &sensor_dev_attr_temp1_input.dev_attr.attr, 39734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres &sensor_dev_attr_temp1_max.dev_attr.attr, 39834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres &sensor_dev_attr_temp1_crit.dev_attr.attr, 39934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres &sensor_dev_attr_name.dev_attr.attr, 40034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres &sensor_dev_attr_update_rate.dev_attr.attr, 40134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NULL 40234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres}; 40334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 40434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic const struct attribute_group hwmon_attrgroup = { 40534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres .attrs = hwmon_attributes, 40634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres}; 407b54262f3c828ee17e27632d0d60255281c02e1a5Martin Peres#endif 40834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 40934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic int 41034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_init(struct drm_device *dev) 41134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 412b54262f3c828ee17e27632d0d60255281c02e1a5Martin Peres#ifdef CONFIG_HWMON 41334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 4148155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 41534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct device *hwmon_dev; 41634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres int ret; 41734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 4188155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez if (!pm->temp_get) 4198155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez return -ENODEV; 42034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 42134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres hwmon_dev = hwmon_device_register(&dev->pdev->dev); 42234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres if (IS_ERR(hwmon_dev)) { 42334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres ret = PTR_ERR(hwmon_dev); 42434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NV_ERROR(dev, 42534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres "Unable to register hwmon device: %d\n", ret); 42634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return ret; 42734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 42834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres dev_set_drvdata(hwmon_dev, dev); 42907cfe0e7a820ecad078c04e9c2a102521709145dLucas Stach ret = sysfs_create_group(&dev->pdev->dev.kobj, &hwmon_attrgroup); 43034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres if (ret) { 43134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NV_ERROR(dev, 43234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres "Unable to create hwmon sysfs file: %d\n", ret); 43334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres hwmon_device_unregister(hwmon_dev); 43434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return ret; 43534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 43634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 4378155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez pm->hwmon = hwmon_dev; 438b54262f3c828ee17e27632d0d60255281c02e1a5Martin Peres#endif 43934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return 0; 44034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 44134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 44234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic void 44334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_fini(struct drm_device *dev) 44434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 445b54262f3c828ee17e27632d0d60255281c02e1a5Martin Peres#ifdef CONFIG_HWMON 44634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 4478155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 44834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 4498155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez if (pm->hwmon) { 4508c06a3e02062a9beb71a9444c49fb0fbcaa1eed3Lucas Stach sysfs_remove_group(&dev->pdev->dev.kobj, &hwmon_attrgroup); 4518155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez hwmon_device_unregister(pm->hwmon); 45234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 453b54262f3c828ee17e27632d0d60255281c02e1a5Martin Peres#endif 45434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 45534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 4561f962797fb1343f02cbacb94d80c4560d47b67a9Martin Peres#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY) 4576032649df9f456f379be8d51f64488cacbfa8317Ben Skeggsstatic int 4586032649df9f456f379be8d51f64488cacbfa8317Ben Skeggsnouveau_pm_acpi_event(struct notifier_block *nb, unsigned long val, void *data) 4596032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs{ 4606032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs struct drm_nouveau_private *dev_priv = 4616032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs container_of(nb, struct drm_nouveau_private, engine.pm.acpi_nb); 4626032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs struct drm_device *dev = dev_priv->dev; 4636032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs struct acpi_bus_event *entry = (struct acpi_bus_event *)data; 4646032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs 4656032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs if (strcmp(entry->device_class, "ac_adapter") == 0) { 4666032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs bool ac = power_supply_is_system_supplied(); 4676032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs 4686032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs NV_DEBUG(dev, "power supply changed: %s\n", ac ? "AC" : "DC"); 4696032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs } 4706032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs 4716032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs return NOTIFY_OK; 4726032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs} 4736032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs#endif 4746032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs 47534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresint 47634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_pm_init(struct drm_device *dev) 47734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 47834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 47934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 48034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres char info[256]; 48134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres int ret, i; 48234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 483e614b2e7ca9f9946cede13b34c950b92af6fa7efMartin Peres nouveau_mem_timing_init(dev); 48434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_volt_init(dev); 48534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_perf_init(dev); 48634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_temp_init(dev); 48734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 48834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NV_INFO(dev, "%d available performance level(s)\n", pm->nr_perflvl); 48934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres for (i = 0; i < pm->nr_perflvl; i++) { 49034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_pm_perflvl_info(&pm->perflvl[i], info, sizeof(info)); 49134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NV_INFO(dev, "%d: %s", pm->perflvl[i].id, info); 49234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 49334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 49434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres /* determine current ("boot") performance level */ 49534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres ret = nouveau_pm_perflvl_get(dev, &pm->boot); 49634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres if (ret == 0) { 49701e542c65de11a47e726ebef63f5e59b4a74568dMartin Peres strncpy(pm->boot.name, "boot", 4); 49834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres pm->cur = &pm->boot; 49934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 50034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info)); 50134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NV_INFO(dev, "c: %s", info); 50234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 50334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 50434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres /* switch performance levels now if requested */ 50534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres if (nouveau_perflvl != NULL) { 50634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres ret = nouveau_pm_profile_set(dev, nouveau_perflvl); 50734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres if (ret) { 50834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NV_ERROR(dev, "error setting perflvl \"%s\": %d\n", 50934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_perflvl, ret); 51034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 51134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 51234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 51334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_sysfs_init(dev); 51434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_hwmon_init(dev); 5151f962797fb1343f02cbacb94d80c4560d47b67a9Martin Peres#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY) 5166032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs pm->acpi_nb.notifier_call = nouveau_pm_acpi_event; 5176032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs register_acpi_notifier(&pm->acpi_nb); 5186032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs#endif 51934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 52034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return 0; 52134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 52234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 52334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresvoid 52434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_pm_fini(struct drm_device *dev) 52534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 52634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 52734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 52834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 52934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres if (pm->cur != &pm->boot) 53034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_pm_perflvl_set(dev, &pm->boot); 531330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 5327760fcb020b41352af4e675ce65a6aa0e93c170fRoy Spliet nouveau_temp_fini(dev); 533330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs nouveau_perf_fini(dev); 534330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs nouveau_volt_fini(dev); 535e614b2e7ca9f9946cede13b34c950b92af6fa7efMartin Peres nouveau_mem_timing_fini(dev); 53634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 5371f962797fb1343f02cbacb94d80c4560d47b67a9Martin Peres#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY) 5386032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs unregister_acpi_notifier(&pm->acpi_nb); 5396032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs#endif 54034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_hwmon_fini(dev); 54134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_sysfs_fini(dev); 542330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 543330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 54464f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggsvoid 54564f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggsnouveau_pm_resume(struct drm_device *dev) 54664f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs{ 54764f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 54864f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 54964f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs struct nouveau_pm_level *perflvl; 55064f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs 551317495b25ec1f0beb0dbac8ee0dfec59a1addf03Ben Skeggs if (!pm->cur || pm->cur == &pm->boot) 55264f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs return; 55364f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs 55464f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs perflvl = pm->cur; 55564f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs pm->cur = &pm->boot; 55664f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs nouveau_pm_perflvl_set(dev, perflvl); 55764f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs} 558