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" 29a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs#include "nouveau_gpio.h" 30330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 316032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs#ifdef CONFIG_ACPI 326032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs#include <linux/acpi.h> 336032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs#endif 346032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs#include <linux/power_supply.h> 3534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres#include <linux/hwmon.h> 3634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres#include <linux/hwmon-sysfs.h> 3734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 38330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsstatic int 39a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggsnouveau_pwmfan_get(struct drm_device *dev) 40a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs{ 41a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 42a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 43a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs struct gpio_func gpio; 44a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs u32 divs, duty; 45a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs int ret; 46a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs 471e05415733b0d4668fbce92856fafabfa1a33333Ben Skeggs if (!pm->pwm_get) 48a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs return -ENODEV; 49a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs 50a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs ret = nouveau_gpio_find(dev, 0, DCB_GPIO_PWM_FAN, 0xff, &gpio); 51a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs if (ret == 0) { 52a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs ret = pm->pwm_get(dev, gpio.line, &divs, &duty); 53a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs if (ret == 0) { 54a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs divs = max(divs, duty); 55a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs if (dev_priv->card_type <= NV_40 || (gpio.log[0] & 1)) 56a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs duty = divs - duty; 57a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs return (duty * 100) / divs; 58a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs } 59a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs 60a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs return nouveau_gpio_func_get(dev, gpio.func) * 100; 61a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs } 62a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs 63a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs return -ENODEV; 64a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs} 65a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs 66a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggsstatic int 67a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggsnouveau_pwmfan_set(struct drm_device *dev, int percent) 68a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs{ 69a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 70a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 71a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs struct gpio_func gpio; 72a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs u32 divs, duty; 73a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs int ret; 74a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs 751e05415733b0d4668fbce92856fafabfa1a33333Ben Skeggs if (!pm->pwm_set) 76a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs return -ENODEV; 77a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs 78a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs ret = nouveau_gpio_find(dev, 0, DCB_GPIO_PWM_FAN, 0xff, &gpio); 79a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs if (ret == 0) { 80a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs divs = pm->pwm_divisor; 81a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs if (pm->fan.pwm_freq) { 82a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs /*XXX: PNVIO clock more than likely... */ 83a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs divs = 135000 / pm->fan.pwm_freq; 84a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs if (dev_priv->chipset < 0xa3) 85a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs divs /= 4; 86a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs } 87a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs 88a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs duty = ((divs * percent) + 99) / 100; 89a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs if (dev_priv->card_type <= NV_40 || (gpio.log[0] & 1)) 90a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs duty = divs - duty; 91a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs 92a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs return pm->pwm_set(dev, gpio.line, divs, duty); 93a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs } 94a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs 95a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs return -ENODEV; 96a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs} 97a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs 98a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggsstatic int 990b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggsnouveau_pm_perflvl_aux(struct drm_device *dev, struct nouveau_pm_level *perflvl, 1000b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs struct nouveau_pm_level *a, struct nouveau_pm_level *b) 10164f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs{ 10264f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 10364f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 10464f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs int ret; 10564f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs 10611b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres /*XXX: not on all boards, we should control based on temperature 10711b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres * on recent boards.. or maybe on some other factor we don't 10811b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres * know about? 10911b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres */ 1100b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs if (a->fanspeed && b->fanspeed && b->fanspeed > a->fanspeed) { 111a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs ret = nouveau_pwmfan_set(dev, perflvl->fanspeed); 1120b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs if (ret && ret != -ENODEV) { 1130b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs NV_ERROR(dev, "fanspeed set failed: %d\n", ret); 1140b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs return ret; 1150b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs } 116771e1035b9bfdb0c3f0e34bd281d73b721a10adbBen Skeggs } 117771e1035b9bfdb0c3f0e34bd281d73b721a10adbBen Skeggs 1180b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs if (pm->voltage.supported && pm->voltage_set) { 119d2edab4acffb35a6e24259886d377774efd37e6eBen Skeggs if (perflvl->volt_min && b->volt_min > a->volt_min) { 1200b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs ret = pm->voltage_set(dev, perflvl->volt_min); 1210b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs if (ret) { 1220b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs NV_ERROR(dev, "voltage set failed: %d\n", ret); 1230b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs return ret; 1240b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs } 12564f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs } 12664f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs } 12764f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs 1280b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs return 0; 1290b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs} 1300b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs 1310b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggsstatic int 1320b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggsnouveau_pm_perflvl_set(struct drm_device *dev, struct nouveau_pm_level *perflvl) 1330b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs{ 1340b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 1350b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 1360b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs void *state; 1370b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs int ret; 1380b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs 1390b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs if (perflvl == pm->cur) 1400b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs return 0; 1410b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs 1420b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs ret = nouveau_pm_perflvl_aux(dev, perflvl, pm->cur, perflvl); 1430b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs if (ret) 1440b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs return ret; 1450b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs 146ff2b6c6e587cf2add3071b3a9a5c61abbbaf4677Ben Skeggs state = pm->clocks_pre(dev, perflvl); 147ff2b6c6e587cf2add3071b3a9a5c61abbbaf4677Ben Skeggs if (IS_ERR(state)) 148ff2b6c6e587cf2add3071b3a9a5c61abbbaf4677Ben Skeggs return PTR_ERR(state); 149ff2b6c6e587cf2add3071b3a9a5c61abbbaf4677Ben Skeggs pm->clocks_set(dev, state); 15064f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs 1510b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs ret = nouveau_pm_perflvl_aux(dev, perflvl, perflvl, pm->cur); 1520b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs if (ret) 1530b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs return ret; 1540b627a0b23404d97d1720c0c1abaee602aee9518Ben Skeggs 15564f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs pm->cur = perflvl; 15664f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs return 0; 15764f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs} 15864f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs 15964f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggsstatic int 1606f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggsnouveau_pm_profile_set(struct drm_device *dev, const char *profile) 1616f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs{ 1626f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 1636f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 1646f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs struct nouveau_pm_level *perflvl = NULL; 1656f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 1666f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs /* safety precaution, for now */ 1676f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (nouveau_perflvl_wr != 7777) 1686f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs return -EPERM; 1696f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 1706f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (!strncmp(profile, "boot", 4)) 1716f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs perflvl = &pm->boot; 1726f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs else { 1736f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs int pl = simple_strtol(profile, NULL, 10); 1746f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs int i; 1756f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 1766f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs for (i = 0; i < pm->nr_perflvl; i++) { 1776f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (pm->perflvl[i].id == pl) { 1786f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs perflvl = &pm->perflvl[i]; 1796f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs break; 1806f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs } 1816f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs } 1826f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 1836f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (!perflvl) 1846f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs return -EINVAL; 1856f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs } 1866f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 1876f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs NV_INFO(dev, "setting performance level: %s\n", profile); 18864f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs return nouveau_pm_perflvl_set(dev, perflvl); 1896f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs} 1906f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 1916f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggsstatic int 192330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsnouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) 193330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 194330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 195330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 196330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs int ret; 197330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 198330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs memset(perflvl, 0, sizeof(*perflvl)); 199330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 200ff2b6c6e587cf2add3071b3a9a5c61abbbaf4677Ben Skeggs ret = pm->clocks_get(dev, perflvl); 201ff2b6c6e587cf2add3071b3a9a5c61abbbaf4677Ben Skeggs if (ret) 202ff2b6c6e587cf2add3071b3a9a5c61abbbaf4677Ben Skeggs return ret; 203330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 204330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (pm->voltage.supported && pm->voltage_get) { 205330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ret = pm->voltage_get(dev); 2063b5565ddfd8fe71f6470a5d240a6bb50ba90d4ffBen Skeggs if (ret > 0) { 2073b5565ddfd8fe71f6470a5d240a6bb50ba90d4ffBen Skeggs perflvl->volt_min = ret; 2083b5565ddfd8fe71f6470a5d240a6bb50ba90d4ffBen Skeggs perflvl->volt_max = ret; 2093b5565ddfd8fe71f6470a5d240a6bb50ba90d4ffBen Skeggs } 210330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs } 211330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 212a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs ret = nouveau_pwmfan_get(dev); 213a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs if (ret > 0) 214a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs perflvl->fanspeed = ret; 215771e1035b9bfdb0c3f0e34bd281d73b721a10adbBen Skeggs 216330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs return 0; 217330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 218330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 219330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsstatic void 220330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsnouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len) 221330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 22293dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs char c[16], s[16], v[32], f[16], t[16], m[16]; 2230fbb114af7ea63227599460c412fb8796556a169Francisco Jerez 2240fbb114af7ea63227599460c412fb8796556a169Francisco Jerez c[0] = '\0'; 2250fbb114af7ea63227599460c412fb8796556a169Francisco Jerez if (perflvl->core) 2260fbb114af7ea63227599460c412fb8796556a169Francisco Jerez snprintf(c, sizeof(c), " core %dMHz", perflvl->core / 1000); 227330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 228330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs s[0] = '\0'; 229330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (perflvl->shader) 230330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs snprintf(s, sizeof(s), " shader %dMHz", perflvl->shader / 1000); 231330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 23293dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs m[0] = '\0'; 23393dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs if (perflvl->memory) 23493dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs snprintf(m, sizeof(m), " memory %dMHz", perflvl->memory / 1000); 23593dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs 236330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs v[0] = '\0'; 2373b5565ddfd8fe71f6470a5d240a6bb50ba90d4ffBen Skeggs if (perflvl->volt_min && perflvl->volt_min != perflvl->volt_max) { 2383b5565ddfd8fe71f6470a5d240a6bb50ba90d4ffBen Skeggs snprintf(v, sizeof(v), " voltage %dmV-%dmV", 2393b5565ddfd8fe71f6470a5d240a6bb50ba90d4ffBen Skeggs perflvl->volt_min / 1000, perflvl->volt_max / 1000); 2403b5565ddfd8fe71f6470a5d240a6bb50ba90d4ffBen Skeggs } else 2413b5565ddfd8fe71f6470a5d240a6bb50ba90d4ffBen Skeggs if (perflvl->volt_min) { 2423b5565ddfd8fe71f6470a5d240a6bb50ba90d4ffBen Skeggs snprintf(v, sizeof(v), " voltage %dmV", 2433b5565ddfd8fe71f6470a5d240a6bb50ba90d4ffBen Skeggs perflvl->volt_min / 1000); 2443b5565ddfd8fe71f6470a5d240a6bb50ba90d4ffBen Skeggs } 245330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 246330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs f[0] = '\0'; 247330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (perflvl->fanspeed) 248330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs snprintf(f, sizeof(f), " fanspeed %d%%", perflvl->fanspeed); 249330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 250e614b2e7ca9f9946cede13b34c950b92af6fa7efMartin Peres t[0] = '\0'; 251e614b2e7ca9f9946cede13b34c950b92af6fa7efMartin Peres if (perflvl->timing) 252e614b2e7ca9f9946cede13b34c950b92af6fa7efMartin Peres snprintf(t, sizeof(t), " timing %d", perflvl->timing->id); 253e614b2e7ca9f9946cede13b34c950b92af6fa7efMartin Peres 25493dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs snprintf(ptr, len, "%s%s%s%s%s%s\n", c, s, m, t, v, f); 255330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 256330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 257330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsstatic ssize_t 258330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsnouveau_pm_get_perflvl_info(struct device *d, 259330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct device_attribute *a, char *buf) 260330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 261330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_level *perflvl = (struct nouveau_pm_level *)a; 262330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs char *ptr = buf; 263330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs int len = PAGE_SIZE; 264330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 26593dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs snprintf(ptr, len, "%d:", perflvl->id); 266330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ptr += strlen(buf); 267330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs len -= strlen(buf); 268330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 269330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs nouveau_pm_perflvl_info(perflvl, ptr, len); 270330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs return strlen(buf); 271330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 272330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 273330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsstatic ssize_t 274330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsnouveau_pm_get_perflvl(struct device *d, struct device_attribute *a, char *buf) 275330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 27634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = pci_get_drvdata(to_pci_dev(d)); 277330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 278330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 279330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_level cur; 280330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs int len = PAGE_SIZE, ret; 281330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs char *ptr = buf; 282330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 283330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (!pm->cur) 284330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs snprintf(ptr, len, "setting: boot\n"); 285330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs else if (pm->cur == &pm->boot) 28693dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs snprintf(ptr, len, "setting: boot\nc:"); 287330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs else 28893dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs snprintf(ptr, len, "setting: static %d\nc:", pm->cur->id); 289330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ptr += strlen(buf); 290330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs len -= strlen(buf); 291330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 292330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ret = nouveau_pm_perflvl_get(dev, &cur); 293330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (ret == 0) 294330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs nouveau_pm_perflvl_info(&cur, ptr, len); 295330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs return strlen(buf); 296330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 297330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 298330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsstatic ssize_t 299330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggsnouveau_pm_set_perflvl(struct device *d, struct device_attribute *a, 300330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs const char *buf, size_t count) 301330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 30234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = pci_get_drvdata(to_pci_dev(d)); 3036f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs int ret; 3046f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs 3056f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs ret = nouveau_pm_profile_set(dev, buf); 3066f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs if (ret) 3076f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs return ret; 3086f876986bedf23b40ab707543e88fae7eac27f1fBen Skeggs return strlen(buf); 309330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 310330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 3115c4abd09bdefb41d0c80055aa9d98433624ce1f0Francisco Jerezstatic DEVICE_ATTR(performance_level, S_IRUGO | S_IWUSR, 3125c4abd09bdefb41d0c80055aa9d98433624ce1f0Francisco Jerez nouveau_pm_get_perflvl, nouveau_pm_set_perflvl); 313330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 31434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic int 31534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_sysfs_init(struct drm_device *dev) 316330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 317330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 318330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 319330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct device *d = &dev->pdev->dev; 320330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs int ret, i; 321330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 322330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ret = device_create_file(d, &dev_attr_performance_level); 323330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (ret) 324330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs return ret; 325330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 326330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs for (i = 0; i < pm->nr_perflvl; i++) { 327330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_level *perflvl = &pm->perflvl[i]; 328330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 329330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->dev_attr.attr.name = perflvl->name; 330330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->dev_attr.attr.mode = S_IRUGO; 331330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->dev_attr.show = nouveau_pm_get_perflvl_info; 332330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->dev_attr.store = NULL; 333330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs sysfs_attr_init(&perflvl->dev_attr.attr); 334330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 335330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs ret = device_create_file(d, &perflvl->dev_attr); 336330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (ret) { 337330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs NV_ERROR(dev, "failed pervlvl %d sysfs: %d\n", 338330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->id, i); 339330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs perflvl->dev_attr.attr.name = NULL; 340330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs nouveau_pm_fini(dev); 341330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs return ret; 342330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs } 343330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs } 344330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 345330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs return 0; 346330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 347330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 34834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic void 34934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_sysfs_fini(struct drm_device *dev) 350330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs{ 351330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 352330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 353330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct device *d = &dev->pdev->dev; 354330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs int i; 355330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 356330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs device_remove_file(d, &dev_attr_performance_level); 357330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs for (i = 0; i < pm->nr_perflvl; i++) { 358330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs struct nouveau_pm_level *pl = &pm->perflvl[i]; 359330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 360330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs if (!pl->dev_attr.attr.name) 361330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs break; 362330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 363330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs device_remove_file(d, &pl->dev_attr); 364330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs } 36534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 36634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 367658e86ee2db9500aea529a04008cce10972416bcKen Milmore#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) 36834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t 36934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf) 37034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 37134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = dev_get_drvdata(d); 3728155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez struct drm_nouveau_private *dev_priv = dev->dev_private; 3738155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 37434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 3758155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez return snprintf(buf, PAGE_SIZE, "%d\n", pm->temp_get(dev)*1000); 37634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 37734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, nouveau_hwmon_show_temp, 37834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NULL, 0); 37934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 38034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t 38134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_max_temp(struct device *d, struct device_attribute *a, char *buf) 38234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 38334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = dev_get_drvdata(d); 38434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 38534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 38634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; 38734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 38834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return snprintf(buf, PAGE_SIZE, "%d\n", temp->down_clock*1000); 38934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 39034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t 39134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_set_max_temp(struct device *d, struct device_attribute *a, 39234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres const char *buf, size_t count) 39334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 39434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = dev_get_drvdata(d); 39534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 39634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 39734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; 39834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres long value; 39934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 4005c4abd09bdefb41d0c80055aa9d98433624ce1f0Francisco Jerez if (strict_strtol(buf, 10, &value) == -EINVAL) 40134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return count; 40234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 40334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres temp->down_clock = value/1000; 40434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 40534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_temp_safety_checks(dev); 40634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 40734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return count; 40834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 40934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, nouveau_hwmon_max_temp, 41034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_hwmon_set_max_temp, 41134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 0); 41234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 41334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t 41434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_critical_temp(struct device *d, struct device_attribute *a, 41534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres char *buf) 41634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 41734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = dev_get_drvdata(d); 41834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 41934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 42034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; 42134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 42234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return snprintf(buf, PAGE_SIZE, "%d\n", temp->critical*1000); 42334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 42434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t 42534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a, 42634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres const char *buf, 42734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres size_t count) 42834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 42934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_device *dev = dev_get_drvdata(d); 43034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 43134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 43234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; 43334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres long value; 43434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 4355c4abd09bdefb41d0c80055aa9d98433624ce1f0Francisco Jerez if (strict_strtol(buf, 10, &value) == -EINVAL) 43634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return count; 43734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 43834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres temp->critical = value/1000; 43934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 44034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_temp_safety_checks(dev); 44134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 44234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return count; 44334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 44434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR, 44534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_hwmon_critical_temp, 44634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_hwmon_set_critical_temp, 44734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 0); 44834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 44934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t nouveau_hwmon_show_name(struct device *dev, 45034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct device_attribute *attr, 45134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres char *buf) 45234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 45334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return sprintf(buf, "nouveau\n"); 45434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 45534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic SENSOR_DEVICE_ATTR(name, S_IRUGO, nouveau_hwmon_show_name, NULL, 0); 45634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 45734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic ssize_t nouveau_hwmon_show_update_rate(struct device *dev, 45834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct device_attribute *attr, 45934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres char *buf) 46034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 46134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return sprintf(buf, "1000\n"); 46234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 46334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic SENSOR_DEVICE_ATTR(update_rate, S_IRUGO, 46434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_hwmon_show_update_rate, 46534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NULL, 0); 46634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 46711b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peresstatic ssize_t 46811b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peresnouveau_hwmon_show_fan0_input(struct device *d, struct device_attribute *attr, 46911b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres char *buf) 47011b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres{ 47111b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres struct drm_device *dev = dev_get_drvdata(d); 47211b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 47311b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; 474a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs struct gpio_func gpio; 47511b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres u32 cycles, cur, prev; 47611b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres u64 start; 477a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs int ret; 47811b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 479a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs ret = nouveau_gpio_find(dev, 0, DCB_GPIO_FAN_SENSE, 0xff, &gpio); 480a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs if (ret) 481a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs return ret; 48211b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 48311b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres /* Monitor the GPIO input 0x3b for 250ms. 48411b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres * When the fan spins, it changes the value of GPIO FAN_SENSE. 48511b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres * We get 4 changes (0 -> 1 -> 0 -> 1 -> [...]) per complete rotation. 48611b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres */ 48711b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres start = ptimer->read(dev); 488a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs prev = nouveau_gpio_sense(dev, 0, gpio.line); 48911b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres cycles = 0; 49011b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres do { 491a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs cur = nouveau_gpio_sense(dev, 0, gpio.line); 49211b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres if (prev != cur) { 49311b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres cycles++; 49411b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres prev = cur; 49511b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres } 49611b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 49711b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres usleep_range(500, 1000); /* supports 0 < rpm < 7500 */ 49811b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres } while (ptimer->read(dev) - start < 250000000); 49911b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 50011b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres /* interpolate to get rpm */ 50111b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres return sprintf(buf, "%i\n", cycles / 4 * 4 * 60); 50211b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres} 50311b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peresstatic SENSOR_DEVICE_ATTR(fan0_input, S_IRUGO, nouveau_hwmon_show_fan0_input, 50411b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres NULL, 0); 50511b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 50611b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peresstatic ssize_t 50711b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peresnouveau_hwmon_get_pwm0(struct device *d, struct device_attribute *a, char *buf) 50811b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres{ 50911b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres struct drm_device *dev = dev_get_drvdata(d); 510a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs int ret; 51111b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 512a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs ret = nouveau_pwmfan_get(dev); 51311b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres if (ret < 0) 51411b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres return ret; 51511b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 51611b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres return sprintf(buf, "%i\n", ret); 51711b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres} 51811b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 51911b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peresstatic ssize_t 52011b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peresnouveau_hwmon_set_pwm0(struct device *d, struct device_attribute *a, 52111b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres const char *buf, size_t count) 52211b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres{ 52311b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres struct drm_device *dev = dev_get_drvdata(d); 52411b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 52511b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 52611b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres int ret = -ENODEV; 52711b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres long value; 52811b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 52911b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres if (nouveau_perflvl_wr != 7777) 53011b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres return -EPERM; 53111b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 53211b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres if (strict_strtol(buf, 10, &value) == -EINVAL) 53311b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres return -EINVAL; 53411b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 53511b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres if (value < pm->fan.min_duty) 53611b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres value = pm->fan.min_duty; 53711b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres if (value > pm->fan.max_duty) 53811b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres value = pm->fan.max_duty; 53911b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 540a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs ret = nouveau_pwmfan_set(dev, value); 54111b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres if (ret) 54211b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres return ret; 54311b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 54411b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres return count; 54511b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres} 54611b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 54711b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peresstatic SENSOR_DEVICE_ATTR(pwm0, S_IRUGO | S_IWUSR, 54811b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres nouveau_hwmon_get_pwm0, 54911b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres nouveau_hwmon_set_pwm0, 0); 55011b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 55111b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peresstatic ssize_t 55211b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peresnouveau_hwmon_get_pwm0_min(struct device *d, 55311b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres struct device_attribute *a, char *buf) 55411b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres{ 55511b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres struct drm_device *dev = dev_get_drvdata(d); 55611b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 55711b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 55811b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 55911b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres return sprintf(buf, "%i\n", pm->fan.min_duty); 56011b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres} 56111b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 56211b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peresstatic ssize_t 56311b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peresnouveau_hwmon_set_pwm0_min(struct device *d, struct device_attribute *a, 56411b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres const char *buf, size_t count) 56511b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres{ 56611b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres struct drm_device *dev = dev_get_drvdata(d); 56711b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 56811b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 56911b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres long value; 57011b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 57111b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres if (strict_strtol(buf, 10, &value) == -EINVAL) 57211b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres return -EINVAL; 57311b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 57411b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres if (value < 0) 57511b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres value = 0; 57611b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 57711b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres if (pm->fan.max_duty - value < 10) 57811b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres value = pm->fan.max_duty - 10; 57911b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 58011b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres if (value < 10) 58111b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres pm->fan.min_duty = 10; 58211b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres else 58311b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres pm->fan.min_duty = value; 58411b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 58511b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres return count; 58611b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres} 58711b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 58811b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peresstatic SENSOR_DEVICE_ATTR(pwm0_min, S_IRUGO | S_IWUSR, 58911b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres nouveau_hwmon_get_pwm0_min, 59011b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres nouveau_hwmon_set_pwm0_min, 0); 59111b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 59211b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peresstatic ssize_t 59311b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peresnouveau_hwmon_get_pwm0_max(struct device *d, 59411b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres struct device_attribute *a, char *buf) 59511b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres{ 59611b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres struct drm_device *dev = dev_get_drvdata(d); 59711b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 59811b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 59911b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 60011b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres return sprintf(buf, "%i\n", pm->fan.max_duty); 60111b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres} 60211b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 60311b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peresstatic ssize_t 60411b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peresnouveau_hwmon_set_pwm0_max(struct device *d, struct device_attribute *a, 60511b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres const char *buf, size_t count) 60611b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres{ 60711b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres struct drm_device *dev = dev_get_drvdata(d); 60811b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 60911b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 61011b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres long value; 61111b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 61211b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres if (strict_strtol(buf, 10, &value) == -EINVAL) 61311b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres return -EINVAL; 61411b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 61511b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres if (value < 0) 61611b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres value = 0; 61711b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 61811b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres if (value - pm->fan.min_duty < 10) 61911b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres value = pm->fan.min_duty + 10; 62011b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 62111b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres if (value > 100) 62211b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres pm->fan.max_duty = 100; 62311b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres else 62411b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres pm->fan.max_duty = value; 62511b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 62611b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres return count; 62711b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres} 62811b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 62911b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peresstatic SENSOR_DEVICE_ATTR(pwm0_max, S_IRUGO | S_IWUSR, 63011b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres nouveau_hwmon_get_pwm0_max, 63111b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres nouveau_hwmon_set_pwm0_max, 0); 63211b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 63334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic struct attribute *hwmon_attributes[] = { 63434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres &sensor_dev_attr_temp1_input.dev_attr.attr, 63534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres &sensor_dev_attr_temp1_max.dev_attr.attr, 63634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres &sensor_dev_attr_temp1_crit.dev_attr.attr, 63734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres &sensor_dev_attr_name.dev_attr.attr, 63834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres &sensor_dev_attr_update_rate.dev_attr.attr, 63934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NULL 64034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres}; 64111b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peresstatic struct attribute *hwmon_fan_rpm_attributes[] = { 64211b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres &sensor_dev_attr_fan0_input.dev_attr.attr, 64311b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres NULL 64411b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres}; 64511b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peresstatic struct attribute *hwmon_pwm_fan_attributes[] = { 64611b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres &sensor_dev_attr_pwm0.dev_attr.attr, 64711b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres &sensor_dev_attr_pwm0_min.dev_attr.attr, 64811b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres &sensor_dev_attr_pwm0_max.dev_attr.attr, 64911b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres NULL 65011b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres}; 65134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 65234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic const struct attribute_group hwmon_attrgroup = { 65334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres .attrs = hwmon_attributes, 65434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres}; 65511b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peresstatic const struct attribute_group hwmon_fan_rpm_attrgroup = { 65611b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres .attrs = hwmon_fan_rpm_attributes, 65711b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres}; 65811b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peresstatic const struct attribute_group hwmon_pwm_fan_attrgroup = { 65911b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres .attrs = hwmon_pwm_fan_attributes, 66011b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres}; 661b54262f3c828ee17e27632d0d60255281c02e1a5Martin Peres#endif 66234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 66334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic int 66434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_init(struct drm_device *dev) 66534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 66634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 6678155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 668095f979a539245a46b9e5d600ec9c720b4d928e5Dave Airlie#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) 66934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct device *hwmon_dev; 67011b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres int ret = 0; 67134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 6728155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez if (!pm->temp_get) 6738155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez return -ENODEV; 67434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 67534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres hwmon_dev = hwmon_device_register(&dev->pdev->dev); 67634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres if (IS_ERR(hwmon_dev)) { 67734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres ret = PTR_ERR(hwmon_dev); 67834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NV_ERROR(dev, 67934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres "Unable to register hwmon device: %d\n", ret); 68034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return ret; 68134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 68234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres dev_set_drvdata(hwmon_dev, dev); 68311b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 68411b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres /* default sysfs entries */ 68507cfe0e7a820ecad078c04e9c2a102521709145dLucas Stach ret = sysfs_create_group(&dev->pdev->dev.kobj, &hwmon_attrgroup); 68634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres if (ret) { 68711b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres if (ret) 68811b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres goto error; 68911b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres } 69011b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 69111b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres /* if the card has a pwm fan */ 69211b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres /*XXX: incorrect, need better detection for this, some boards have 69311b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres * the gpio entries for pwm fan control even when there's no 69411b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres * actual fan connected to it... therm table? */ 695a175094cd8f3d46060d8e3510bdca57eb2369a86Ben Skeggs if (nouveau_pwmfan_get(dev) >= 0) { 69611b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres ret = sysfs_create_group(&dev->pdev->dev.kobj, 69711b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres &hwmon_pwm_fan_attrgroup); 69811b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres if (ret) 69911b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres goto error; 70011b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres } 70111b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 70211b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres /* if the card can read the fan rpm */ 703a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs if (nouveau_gpio_func_valid(dev, DCB_GPIO_FAN_SENSE)) { 70411b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres ret = sysfs_create_group(&dev->pdev->dev.kobj, 70511b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres &hwmon_fan_rpm_attrgroup); 70611b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres if (ret) 70711b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres goto error; 70834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 70934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 7108155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez pm->hwmon = hwmon_dev; 71111b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 71234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return 0; 71311b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 71411b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Pereserror: 71511b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres NV_ERROR(dev, "Unable to create some hwmon sysfs files: %d\n", ret); 71611b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres hwmon_device_unregister(hwmon_dev); 71711b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres pm->hwmon = NULL; 71811b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres return ret; 71911b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres#else 72011b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres pm->hwmon = NULL; 72111b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres return 0; 72211b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres#endif 72334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 72434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 72534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresstatic void 72634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_hwmon_fini(struct drm_device *dev) 72734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 728658e86ee2db9500aea529a04008cce10972416bcKen Milmore#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) 72934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 7308155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 73134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 7328155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez if (pm->hwmon) { 7338c06a3e02062a9beb71a9444c49fb0fbcaa1eed3Lucas Stach sysfs_remove_group(&dev->pdev->dev.kobj, &hwmon_attrgroup); 73411b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres sysfs_remove_group(&dev->pdev->dev.kobj, &hwmon_pwm_fan_attrgroup); 73511b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres sysfs_remove_group(&dev->pdev->dev.kobj, &hwmon_fan_rpm_attrgroup); 73611b7d895216f7f954c6cfa0c23b76dccb7a890c1Martin Peres 7378155cac489eb8cc6fd96b9bdefacdf5a56e6ea32Francisco Jerez hwmon_device_unregister(pm->hwmon); 73834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 739b54262f3c828ee17e27632d0d60255281c02e1a5Martin Peres#endif 74034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 74134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 7421f962797fb1343f02cbacb94d80c4560d47b67a9Martin Peres#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY) 7436032649df9f456f379be8d51f64488cacbfa8317Ben Skeggsstatic int 7446032649df9f456f379be8d51f64488cacbfa8317Ben Skeggsnouveau_pm_acpi_event(struct notifier_block *nb, unsigned long val, void *data) 7456032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs{ 7466032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs struct drm_nouveau_private *dev_priv = 7476032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs container_of(nb, struct drm_nouveau_private, engine.pm.acpi_nb); 7486032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs struct drm_device *dev = dev_priv->dev; 7496032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs struct acpi_bus_event *entry = (struct acpi_bus_event *)data; 7506032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs 7516032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs if (strcmp(entry->device_class, "ac_adapter") == 0) { 7526032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs bool ac = power_supply_is_system_supplied(); 7536032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs 7546032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs NV_DEBUG(dev, "power supply changed: %s\n", ac ? "AC" : "DC"); 7556032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs } 7566032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs 7576032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs return NOTIFY_OK; 7586032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs} 7596032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs#endif 7606032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs 76134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresint 76234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_pm_init(struct drm_device *dev) 76334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 76434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 76534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 76634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres char info[256]; 76734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres int ret, i; 76834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 769e614b2e7ca9f9946cede13b34c950b92af6fa7efMartin Peres nouveau_mem_timing_init(dev); 77034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_volt_init(dev); 77134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_perf_init(dev); 77234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_temp_init(dev); 77334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 77434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NV_INFO(dev, "%d available performance level(s)\n", pm->nr_perflvl); 77534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres for (i = 0; i < pm->nr_perflvl; i++) { 77634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_pm_perflvl_info(&pm->perflvl[i], info, sizeof(info)); 77793dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs NV_INFO(dev, "%d:%s", pm->perflvl[i].id, info); 77834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 77934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 78034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres /* determine current ("boot") performance level */ 78134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres ret = nouveau_pm_perflvl_get(dev, &pm->boot); 78234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres if (ret == 0) { 78301e542c65de11a47e726ebef63f5e59b4a74568dMartin Peres strncpy(pm->boot.name, "boot", 4); 78434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres pm->cur = &pm->boot; 78534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 78634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info)); 78793dccbedeb2280ca2c234530236b950b232afa65Ben Skeggs NV_INFO(dev, "c:%s", info); 78834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 78934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 79034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres /* switch performance levels now if requested */ 79134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres if (nouveau_perflvl != NULL) { 79234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres ret = nouveau_pm_profile_set(dev, nouveau_perflvl); 79334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres if (ret) { 79434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres NV_ERROR(dev, "error setting perflvl \"%s\": %d\n", 79534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_perflvl, ret); 79634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 79734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres } 79834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 79934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_sysfs_init(dev); 80034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_hwmon_init(dev); 8011f962797fb1343f02cbacb94d80c4560d47b67a9Martin Peres#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY) 8026032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs pm->acpi_nb.notifier_call = nouveau_pm_acpi_event; 8036032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs register_acpi_notifier(&pm->acpi_nb); 8046032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs#endif 80534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 80634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres return 0; 80734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres} 80834e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 80934e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresvoid 81034e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peresnouveau_pm_fini(struct drm_device *dev) 81134e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres{ 81234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct drm_nouveau_private *dev_priv = dev->dev_private; 81334e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 81434e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 81534e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres if (pm->cur != &pm->boot) 81634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_pm_perflvl_set(dev, &pm->boot); 817330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 8187760fcb020b41352af4e675ce65a6aa0e93c170fRoy Spliet nouveau_temp_fini(dev); 819330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs nouveau_perf_fini(dev); 820330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs nouveau_volt_fini(dev); 821e614b2e7ca9f9946cede13b34c950b92af6fa7efMartin Peres nouveau_mem_timing_fini(dev); 82234e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres 8231f962797fb1343f02cbacb94d80c4560d47b67a9Martin Peres#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY) 8246032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs unregister_acpi_notifier(&pm->acpi_nb); 8256032649df9f456f379be8d51f64488cacbfa8317Ben Skeggs#endif 82634e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_hwmon_fini(dev); 82734e9d85a1aae28b090ec4e72a0f98a5483c198c4Martin Peres nouveau_sysfs_fini(dev); 828330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs} 829330c5988ee78045e6a731c3693251aaa5b0d14e3Ben Skeggs 83064f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggsvoid 83164f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggsnouveau_pm_resume(struct drm_device *dev) 83264f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs{ 83364f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs struct drm_nouveau_private *dev_priv = dev->dev_private; 83464f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 83564f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs struct nouveau_pm_level *perflvl; 83664f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs 837317495b25ec1f0beb0dbac8ee0dfec59a1addf03Ben Skeggs if (!pm->cur || pm->cur == &pm->boot) 83864f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs return; 83964f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs 84064f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs perflvl = pm->cur; 84164f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs pm->cur = &pm->boot; 84264f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs nouveau_pm_perflvl_set(dev, perflvl); 84364f1c11a477cb76e1572ee0793234739e045b3d5Ben Skeggs} 844