From 02a841d434513c7b3620250271c372fabce56de5 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 4 Jul 2012 23:44:54 +1000 Subject: drm/nouveau: restructure source tree, split core from drm implementation Future work will be headed in the way of separating the policy supplied by the nouveau drm module from the mechanisms provided by the driver core. There will be a couple of major classes (subdev, engine) of driver modules that have clearly defined tasks, and the further directory structure change is to reflect this. No code changes here whatsoever, aside from fixing up a couple of include file pathnames. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/nouveau/nouveau_pm.c') diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c index da3e7c3abab7..dc34664572c1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.c +++ b/drivers/gpu/drm/nouveau/nouveau_pm.c @@ -26,7 +26,7 @@ #include "nouveau_drv.h" #include "nouveau_pm.h" -#include "nouveau_gpio.h" +#include #ifdef CONFIG_ACPI #include -- cgit v1.2.1 From e0996aea4c349ba302b63203b7d5cab6034dbdca Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 10 Jul 2012 12:20:17 +1000 Subject: drm/nouveau/gpio: port gpio to subdev interfaces v2: Ben Skeggs - rebase on top of v3.6-rc6 with gpio reset patch integrated already Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_pm.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers/gpu/drm/nouveau/nouveau_pm.c') diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c index dc34664572c1..fd74cbf7ef69 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.c +++ b/drivers/gpu/drm/nouveau/nouveau_pm.c @@ -26,7 +26,7 @@ #include "nouveau_drv.h" #include "nouveau_pm.h" -#include +#include #ifdef CONFIG_ACPI #include @@ -40,7 +40,7 @@ nouveau_pwmfan_get(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_pm_engine *pm = &dev_priv->engine.pm; - struct gpio_func gpio; + struct dcb_gpio_func gpio; u32 divs, duty; int ret; @@ -68,7 +68,7 @@ nouveau_pwmfan_set(struct drm_device *dev, int percent) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_pm_engine *pm = &dev_priv->engine.pm; - struct gpio_func gpio; + struct dcb_gpio_func gpio; u32 divs, duty; int ret; @@ -555,24 +555,21 @@ nouveau_hwmon_show_fan0_input(struct device *d, struct device_attribute *attr, struct drm_device *dev = dev_get_drvdata(d); struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; - struct gpio_func gpio; u32 cycles, cur, prev; u64 start; - int ret; - ret = nouveau_gpio_find(dev, 0, DCB_GPIO_FAN_SENSE, 0xff, &gpio); - if (ret) - return ret; + if (!nouveau_gpio_func_valid(dev, DCB_GPIO_FAN_SENSE)) + return -ENODEV; /* Monitor the GPIO input 0x3b for 250ms. * When the fan spins, it changes the value of GPIO FAN_SENSE. * We get 4 changes (0 -> 1 -> 0 -> 1 -> [...]) per complete rotation. */ start = ptimer->read(dev); - prev = nouveau_gpio_sense(dev, 0, gpio.line); + prev = nouveau_gpio_func_get(dev, DCB_GPIO_FAN_SENSE); cycles = 0; do { - cur = nouveau_gpio_sense(dev, 0, gpio.line); + cur = nouveau_gpio_func_get(dev, DCB_GPIO_FAN_SENSE); if (prev != cur) { cycles++; prev = cur; -- cgit v1.2.1 From 5a5c7432bbbd2e318dff107b4ff960ab543a7cef Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 11 Jul 2012 16:08:25 +1000 Subject: drm/nouveau/timer: port to subdev interfaces Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_pm.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm/nouveau/nouveau_pm.c') diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c index fd74cbf7ef69..539e81c416cd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.c +++ b/drivers/gpu/drm/nouveau/nouveau_pm.c @@ -194,8 +194,7 @@ nouveau_pm_trigger(struct drm_device *dev) /* change perflvl, if necessary */ if (perflvl != pm->cur) { - struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; - u64 time0 = ptimer->read(dev); + u64 time0 = nv_timer_read(dev); NV_INFO(dev, "setting performance level: %d", perflvl->id); ret = nouveau_pm_perflvl_set(dev, perflvl); @@ -203,7 +202,7 @@ nouveau_pm_trigger(struct drm_device *dev) NV_INFO(dev, "> reclocking failed: %d\n\n", ret); NV_INFO(dev, "> reclocking took %lluns\n\n", - ptimer->read(dev) - time0); + nv_timer_read(dev) - time0); } } @@ -553,8 +552,6 @@ nouveau_hwmon_show_fan0_input(struct device *d, struct device_attribute *attr, char *buf) { struct drm_device *dev = dev_get_drvdata(d); - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; u32 cycles, cur, prev; u64 start; @@ -565,7 +562,7 @@ nouveau_hwmon_show_fan0_input(struct device *d, struct device_attribute *attr, * When the fan spins, it changes the value of GPIO FAN_SENSE. * We get 4 changes (0 -> 1 -> 0 -> 1 -> [...]) per complete rotation. */ - start = ptimer->read(dev); + start = nv_timer_read(dev); prev = nouveau_gpio_func_get(dev, DCB_GPIO_FAN_SENSE); cycles = 0; do { @@ -576,7 +573,7 @@ nouveau_hwmon_show_fan0_input(struct device *d, struct device_attribute *attr, } usleep_range(500, 1000); /* supports 0 < rpm < 7500 */ - } while (ptimer->read(dev) - start < 250000000); + } while (nv_timer_read(dev) - start < 250000000); /* interpolate to get rpm */ return sprintf(buf, "%i\n", cycles / 4 * 4 * 60); -- cgit v1.2.1 From 77145f1cbdf8d28b46ff8070ca749bad821e0774 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 31 Jul 2012 16:16:21 +1000 Subject: drm/nouveau: port remainder of drm code, and rip out compat layer v2: Ben Skeggs - fill in nouveau_pm.dev to prevent oops - fix ppc issues (build + OF shadow) Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_pm.c | 254 ++++++++++++++++++++++------------- 1 file changed, 160 insertions(+), 94 deletions(-) (limited to 'drivers/gpu/drm/nouveau/nouveau_pm.c') diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c index 539e81c416cd..3c55ec2366d3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.c +++ b/drivers/gpu/drm/nouveau/nouveau_pm.c @@ -22,12 +22,6 @@ * Authors: Ben Skeggs */ -#include "drmP.h" - -#include "nouveau_drv.h" -#include "nouveau_pm.h" -#include - #ifdef CONFIG_ACPI #include #endif @@ -35,29 +29,48 @@ #include #include +#include "drmP.h" + +#include "nouveau_drm.h" +#include "nouveau_pm.h" + +#include +#include +#include + +MODULE_PARM_DESC(perflvl, "Performance level (default: boot)"); +static char *nouveau_perflvl; +module_param_named(perflvl, nouveau_perflvl, charp, 0400); + +MODULE_PARM_DESC(perflvl_wr, "Allow perflvl changes (warning: dangerous!)"); +static int nouveau_perflvl_wr; +module_param_named(perflvl_wr, nouveau_perflvl_wr, int, 0400); + static int nouveau_pwmfan_get(struct drm_device *dev) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; - struct dcb_gpio_func gpio; + struct nouveau_pm *pm = nouveau_pm(dev); + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_device *device = nv_device(drm->device); + struct nouveau_gpio *gpio = nouveau_gpio(device); + struct dcb_gpio_func func; u32 divs, duty; int ret; if (!pm->pwm_get) return -ENODEV; - ret = nouveau_gpio_find(dev, 0, DCB_GPIO_PWM_FAN, 0xff, &gpio); + ret = gpio->find(gpio, 0, DCB_GPIO_PWM_FAN, 0xff, &func); if (ret == 0) { - ret = pm->pwm_get(dev, gpio.line, &divs, &duty); + ret = pm->pwm_get(dev, func.line, &divs, &duty); if (ret == 0 && divs) { divs = max(divs, duty); - if (dev_priv->card_type <= NV_40 || (gpio.log[0] & 1)) + if (device->card_type <= NV_40 || (func.log[0] & 1)) duty = divs - duty; return (duty * 100) / divs; } - return nouveau_gpio_func_get(dev, gpio.func) * 100; + return gpio->get(gpio, 0, func.func, func.line) * 100; } return -ENODEV; @@ -66,30 +79,32 @@ nouveau_pwmfan_get(struct drm_device *dev) static int nouveau_pwmfan_set(struct drm_device *dev, int percent) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; - struct dcb_gpio_func gpio; + struct nouveau_pm *pm = nouveau_pm(dev); + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_device *device = nv_device(drm->device); + struct nouveau_gpio *gpio = nouveau_gpio(device); + struct dcb_gpio_func func; u32 divs, duty; int ret; if (!pm->pwm_set) return -ENODEV; - ret = nouveau_gpio_find(dev, 0, DCB_GPIO_PWM_FAN, 0xff, &gpio); + ret = gpio->find(gpio, 0, DCB_GPIO_PWM_FAN, 0xff, &func); if (ret == 0) { divs = pm->fan.pwm_divisor; if (pm->fan.pwm_freq) { /*XXX: PNVIO clock more than likely... */ divs = 135000 / pm->fan.pwm_freq; - if (dev_priv->chipset < 0xa3) + if (nv_device(drm->device)->chipset < 0xa3) divs /= 4; } duty = ((divs * percent) + 99) / 100; - if (dev_priv->card_type <= NV_40 || (gpio.log[0] & 1)) + if (device->card_type <= NV_40 || (func.log[0] & 1)) duty = divs - duty; - ret = pm->pwm_set(dev, gpio.line, divs, duty); + ret = pm->pwm_set(dev, func.line, divs, duty); if (!ret) pm->fan.percent = percent; return ret; @@ -102,8 +117,8 @@ static int nouveau_pm_perflvl_aux(struct drm_device *dev, struct nouveau_pm_level *perflvl, struct nouveau_pm_level *a, struct nouveau_pm_level *b) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_pm *pm = nouveau_pm(dev); int ret; /*XXX: not on all boards, we should control based on temperature @@ -113,7 +128,7 @@ nouveau_pm_perflvl_aux(struct drm_device *dev, struct nouveau_pm_level *perflvl, if (a->fanspeed && b->fanspeed && b->fanspeed > a->fanspeed) { ret = nouveau_pwmfan_set(dev, perflvl->fanspeed); if (ret && ret != -ENODEV) { - NV_ERROR(dev, "fanspeed set failed: %d\n", ret); + NV_ERROR(drm, "fanspeed set failed: %d\n", ret); return ret; } } @@ -122,7 +137,7 @@ nouveau_pm_perflvl_aux(struct drm_device *dev, struct nouveau_pm_level *perflvl, if (perflvl->volt_min && b->volt_min > a->volt_min) { ret = pm->voltage_set(dev, perflvl->volt_min); if (ret) { - NV_ERROR(dev, "voltage set failed: %d\n", ret); + NV_ERROR(drm, "voltage set failed: %d\n", ret); return ret; } } @@ -134,8 +149,7 @@ nouveau_pm_perflvl_aux(struct drm_device *dev, struct nouveau_pm_level *perflvl, static int nouveau_pm_perflvl_set(struct drm_device *dev, struct nouveau_pm_level *perflvl) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_pm *pm = nouveau_pm(dev); void *state; int ret; @@ -171,8 +185,9 @@ error: void nouveau_pm_trigger(struct drm_device *dev) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_timer *ptimer = nouveau_timer(drm->device); + struct nouveau_pm *pm = nouveau_pm(dev); struct nouveau_pm_profile *profile = NULL; struct nouveau_pm_level *perflvl = NULL; int ret; @@ -194,23 +209,22 @@ nouveau_pm_trigger(struct drm_device *dev) /* change perflvl, if necessary */ if (perflvl != pm->cur) { - u64 time0 = nv_timer_read(dev); + u64 time0 = ptimer->read(ptimer); - NV_INFO(dev, "setting performance level: %d", perflvl->id); + NV_INFO(drm, "setting performance level: %d", perflvl->id); ret = nouveau_pm_perflvl_set(dev, perflvl); if (ret) - NV_INFO(dev, "> reclocking failed: %d\n\n", ret); + NV_INFO(drm, "> reclocking failed: %d\n\n", ret); - NV_INFO(dev, "> reclocking took %lluns\n\n", - nv_timer_read(dev) - time0); + NV_INFO(drm, "> reclocking took %lluns\n\n", + ptimer->read(ptimer) - time0); } } static struct nouveau_pm_profile * profile_find(struct drm_device *dev, const char *string) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_pm *pm = nouveau_pm(dev); struct nouveau_pm_profile *profile; list_for_each_entry(profile, &pm->profiles, head) { @@ -224,8 +238,7 @@ profile_find(struct drm_device *dev, const char *string) static int nouveau_pm_profile_set(struct drm_device *dev, const char *profile) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_pm *pm = nouveau_pm(dev); struct nouveau_pm_profile *ac = NULL, *dc = NULL; char string[16], *cur = string, *ptr; @@ -278,8 +291,7 @@ const struct nouveau_pm_profile_func nouveau_pm_static_profile_func = { static int nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_pm *pm = nouveau_pm(dev); int ret; memset(perflvl, 0, sizeof(*perflvl)); @@ -361,8 +373,7 @@ static ssize_t nouveau_pm_get_perflvl(struct device *d, struct device_attribute *a, char *buf) { struct drm_device *dev = pci_get_drvdata(to_pci_dev(d)); - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_pm *pm = nouveau_pm(dev); struct nouveau_pm_level cur; int len = PAGE_SIZE, ret; char *ptr = buf; @@ -397,8 +408,8 @@ static DEVICE_ATTR(performance_level, S_IRUGO | S_IWUSR, static int nouveau_sysfs_init(struct drm_device *dev) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_pm *pm = nouveau_pm(dev); struct device *d = &dev->pdev->dev; int ret, i; @@ -417,7 +428,7 @@ nouveau_sysfs_init(struct drm_device *dev) ret = device_create_file(d, &perflvl->dev_attr); if (ret) { - NV_ERROR(dev, "failed pervlvl %d sysfs: %d\n", + NV_ERROR(drm, "failed pervlvl %d sysfs: %d\n", perflvl->id, i); perflvl->dev_attr.attr.name = NULL; nouveau_pm_fini(dev); @@ -431,8 +442,7 @@ nouveau_sysfs_init(struct drm_device *dev) static void nouveau_sysfs_fini(struct drm_device *dev) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_pm *pm = nouveau_pm(dev); struct device *d = &dev->pdev->dev; int i; @@ -452,8 +462,7 @@ static ssize_t nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf) { struct drm_device *dev = dev_get_drvdata(d); - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_pm *pm = nouveau_pm(dev); return snprintf(buf, PAGE_SIZE, "%d\n", pm->temp_get(dev)*1000); } @@ -464,8 +473,7 @@ static ssize_t nouveau_hwmon_max_temp(struct device *d, struct device_attribute *a, char *buf) { struct drm_device *dev = dev_get_drvdata(d); - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_pm *pm = nouveau_pm(dev); struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; return snprintf(buf, PAGE_SIZE, "%d\n", temp->down_clock*1000); @@ -475,8 +483,7 @@ nouveau_hwmon_set_max_temp(struct device *d, struct device_attribute *a, const char *buf, size_t count) { struct drm_device *dev = dev_get_drvdata(d); - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_pm *pm = nouveau_pm(dev); struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; long value; @@ -498,8 +505,7 @@ nouveau_hwmon_critical_temp(struct device *d, struct device_attribute *a, char *buf) { struct drm_device *dev = dev_get_drvdata(d); - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_pm *pm = nouveau_pm(dev); struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; return snprintf(buf, PAGE_SIZE, "%d\n", temp->critical*1000); @@ -510,8 +516,7 @@ nouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a, size_t count) { struct drm_device *dev = dev_get_drvdata(d); - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_pm *pm = nouveau_pm(dev); struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; long value; @@ -552,28 +557,32 @@ nouveau_hwmon_show_fan0_input(struct device *d, struct device_attribute *attr, char *buf) { struct drm_device *dev = dev_get_drvdata(d); + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_timer *ptimer = nouveau_timer(drm->device); + struct nouveau_gpio *gpio = nouveau_gpio(drm->device); + struct dcb_gpio_func func; u32 cycles, cur, prev; u64 start; - if (!nouveau_gpio_func_valid(dev, DCB_GPIO_FAN_SENSE)) + if (gpio->find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, &func)) return -ENODEV; /* Monitor the GPIO input 0x3b for 250ms. * When the fan spins, it changes the value of GPIO FAN_SENSE. * We get 4 changes (0 -> 1 -> 0 -> 1 -> [...]) per complete rotation. */ - start = nv_timer_read(dev); - prev = nouveau_gpio_func_get(dev, DCB_GPIO_FAN_SENSE); + start = ptimer->read(ptimer); + prev = gpio->get(gpio, 0, func.func, func.line); cycles = 0; do { - cur = nouveau_gpio_func_get(dev, DCB_GPIO_FAN_SENSE); + cur = gpio->get(gpio, 0, func.func, func.line); if (prev != cur) { cycles++; prev = cur; } usleep_range(500, 1000); /* supports 0 < rpm < 7500 */ - } while (nv_timer_read(dev) - start < 250000000); + } while (ptimer->read(ptimer) - start < 250000000); /* interpolate to get rpm */ return sprintf(buf, "%i\n", cycles / 4 * 4 * 60); @@ -599,8 +608,7 @@ nouveau_hwmon_set_pwm0(struct device *d, struct device_attribute *a, const char *buf, size_t count) { struct drm_device *dev = dev_get_drvdata(d); - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_pm *pm = nouveau_pm(dev); int ret = -ENODEV; long value; @@ -631,8 +639,7 @@ nouveau_hwmon_get_pwm0_min(struct device *d, struct device_attribute *a, char *buf) { struct drm_device *dev = dev_get_drvdata(d); - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_pm *pm = nouveau_pm(dev); return sprintf(buf, "%i\n", pm->fan.min_duty); } @@ -642,8 +649,7 @@ nouveau_hwmon_set_pwm0_min(struct device *d, struct device_attribute *a, const char *buf, size_t count) { struct drm_device *dev = dev_get_drvdata(d); - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_pm *pm = nouveau_pm(dev); long value; if (kstrtol(buf, 10, &value) == -EINVAL) @@ -672,8 +678,7 @@ nouveau_hwmon_get_pwm0_max(struct device *d, struct device_attribute *a, char *buf) { struct drm_device *dev = dev_get_drvdata(d); - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_pm *pm = nouveau_pm(dev); return sprintf(buf, "%i\n", pm->fan.max_duty); } @@ -683,8 +688,7 @@ nouveau_hwmon_set_pwm0_max(struct device *d, struct device_attribute *a, const char *buf, size_t count) { struct drm_device *dev = dev_get_drvdata(d); - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_pm *pm = nouveau_pm(dev); long value; if (kstrtol(buf, 10, &value) == -EINVAL) @@ -741,8 +745,11 @@ static const struct attribute_group hwmon_pwm_fan_attrgroup = { static int nouveau_hwmon_init(struct drm_device *dev) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_pm *pm = nouveau_pm(dev); + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_gpio *gpio = nouveau_gpio(drm->device); + struct dcb_gpio_func func; + #if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) struct device *hwmon_dev; int ret = 0; @@ -753,8 +760,7 @@ nouveau_hwmon_init(struct drm_device *dev) hwmon_dev = hwmon_device_register(&dev->pdev->dev); if (IS_ERR(hwmon_dev)) { ret = PTR_ERR(hwmon_dev); - NV_ERROR(dev, - "Unable to register hwmon device: %d\n", ret); + NV_ERROR(drm, "Unable to register hwmon device: %d\n", ret); return ret; } dev_set_drvdata(hwmon_dev, dev); @@ -778,7 +784,7 @@ nouveau_hwmon_init(struct drm_device *dev) } /* if the card can read the fan rpm */ - if (nouveau_gpio_func_valid(dev, DCB_GPIO_FAN_SENSE)) { + if (!gpio->find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, &func)) { ret = sysfs_create_group(&dev->pdev->dev.kobj, &hwmon_fan_rpm_attrgroup); if (ret) @@ -790,7 +796,7 @@ nouveau_hwmon_init(struct drm_device *dev) return 0; error: - NV_ERROR(dev, "Unable to create some hwmon sysfs files: %d\n", ret); + NV_ERROR(drm, "Unable to create some hwmon sysfs files: %d\n", ret); hwmon_device_unregister(hwmon_dev); pm->hwmon = NULL; return ret; @@ -804,8 +810,7 @@ static void nouveau_hwmon_fini(struct drm_device *dev) { #if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_pm *pm = nouveau_pm(dev); if (pm->hwmon) { sysfs_remove_group(&dev->pdev->dev.kobj, &hwmon_attrgroup); @@ -823,16 +828,15 @@ nouveau_hwmon_fini(struct drm_device *dev) static int nouveau_pm_acpi_event(struct notifier_block *nb, unsigned long val, void *data) { - struct drm_nouveau_private *dev_priv = - container_of(nb, struct drm_nouveau_private, engine.pm.acpi_nb); - struct drm_device *dev = dev_priv->dev; + struct nouveau_pm *pm = container_of(nb, struct nouveau_pm, acpi_nb); + struct nouveau_drm *drm = nouveau_drm(pm->dev); struct acpi_bus_event *entry = (struct acpi_bus_event *)data; if (strcmp(entry->device_class, "ac_adapter") == 0) { bool ac = power_supply_is_system_supplied(); - NV_DEBUG(dev, "power supply changed: %s\n", ac ? "AC" : "DC"); - nouveau_pm_trigger(dev); + NV_DEBUG(drm, "power supply changed: %s\n", ac ? "AC" : "DC"); + nouveau_pm_trigger(pm->dev); } return NOTIFY_OK; @@ -842,11 +846,72 @@ nouveau_pm_acpi_event(struct notifier_block *nb, unsigned long val, void *data) int nouveau_pm_init(struct drm_device *dev) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_device *device = nouveau_dev(dev); + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_pm *pm; char info[256]; int ret, i; + pm = drm->pm = kzalloc(sizeof(*pm), GFP_KERNEL); + if (!pm) + return -ENOMEM; + + pm->dev = dev; + + if (device->card_type < NV_40) { + pm->clocks_get = nv04_pm_clocks_get; + pm->clocks_pre = nv04_pm_clocks_pre; + pm->clocks_set = nv04_pm_clocks_set; + if (nouveau_gpio(drm->device)) { + pm->voltage_get = nouveau_voltage_gpio_get; + pm->voltage_set = nouveau_voltage_gpio_set; + } + } else + if (device->card_type < NV_50) { + pm->clocks_get = nv40_pm_clocks_get; + pm->clocks_pre = nv40_pm_clocks_pre; + pm->clocks_set = nv40_pm_clocks_set; + pm->voltage_get = nouveau_voltage_gpio_get; + pm->voltage_set = nouveau_voltage_gpio_set; + pm->temp_get = nv40_temp_get; + pm->pwm_get = nv40_pm_pwm_get; + pm->pwm_set = nv40_pm_pwm_set; + } else + if (device->card_type < NV_C0) { + if (device->chipset < 0xa3 || + device->chipset == 0xaa || + device->chipset == 0xac) { + pm->clocks_get = nv50_pm_clocks_get; + pm->clocks_pre = nv50_pm_clocks_pre; + pm->clocks_set = nv50_pm_clocks_set; + } else { + pm->clocks_get = nva3_pm_clocks_get; + pm->clocks_pre = nva3_pm_clocks_pre; + pm->clocks_set = nva3_pm_clocks_set; + } + pm->voltage_get = nouveau_voltage_gpio_get; + pm->voltage_set = nouveau_voltage_gpio_set; + if (device->chipset == 0x50) + pm->temp_get = nv40_temp_get; + else + pm->temp_get = nv84_temp_get; + pm->pwm_get = nv50_pm_pwm_get; + pm->pwm_set = nv50_pm_pwm_set; + } else + if (device->card_type < NV_E0) { + pm->clocks_get = nvc0_pm_clocks_get; + pm->clocks_pre = nvc0_pm_clocks_pre; + pm->clocks_set = nvc0_pm_clocks_set; + pm->voltage_get = nouveau_voltage_gpio_get; + pm->voltage_set = nouveau_voltage_gpio_set; + pm->temp_get = nv84_temp_get; + if (device->card_type < NV_D0) { + pm->pwm_get = nv50_pm_pwm_get; + pm->pwm_set = nv50_pm_pwm_set; + } + } + + /* parse aux tables from vbios */ nouveau_volt_init(dev); nouveau_temp_init(dev); @@ -854,7 +919,7 @@ nouveau_pm_init(struct drm_device *dev) /* determine current ("boot") performance level */ ret = nouveau_pm_perflvl_get(dev, &pm->boot); if (ret) { - NV_ERROR(dev, "failed to determine boot perflvl\n"); + NV_ERROR(drm, "failed to determine boot perflvl\n"); return ret; } @@ -874,14 +939,14 @@ nouveau_pm_init(struct drm_device *dev) nouveau_perf_init(dev); /* display available performance levels */ - NV_INFO(dev, "%d available performance level(s)\n", pm->nr_perflvl); + NV_INFO(drm, "%d available performance level(s)\n", pm->nr_perflvl); for (i = 0; i < pm->nr_perflvl; i++) { nouveau_pm_perflvl_info(&pm->perflvl[i], info, sizeof(info)); - NV_INFO(dev, "%d:%s", pm->perflvl[i].id, info); + NV_INFO(drm, "%d:%s", pm->perflvl[i].id, info); } nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info)); - NV_INFO(dev, "c:%s", info); + NV_INFO(drm, "c:%s", info); /* switch performance levels now if requested */ if (nouveau_perflvl != NULL) @@ -903,8 +968,7 @@ nouveau_pm_init(struct drm_device *dev) void nouveau_pm_fini(struct drm_device *dev) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_pm *pm = nouveau_pm(dev); struct nouveau_pm_profile *profile, *tmp; list_for_each_entry_safe(profile, tmp, &pm->profiles, head) { @@ -924,13 +988,15 @@ nouveau_pm_fini(struct drm_device *dev) #endif nouveau_hwmon_fini(dev); nouveau_sysfs_fini(dev); + + nouveau_drm(dev)->pm = NULL; + kfree(pm); } void nouveau_pm_resume(struct drm_device *dev) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_pm *pm = nouveau_pm(dev); struct nouveau_pm_level *perflvl; if (!pm->cur || pm->cur == &pm->boot) -- cgit v1.2.1 From d89c8ce07168ef6cd16c71d0a9f618829e866e87 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Tue, 25 Sep 2012 10:31:40 +0400 Subject: drm/nouveau: fix pm initialization order If nouveau_pm_perflvl_get() fails, pm->profiles list will be left uninitialized, which causes oops during nouveau_pm_fini(). Move INIT_LIST_HEAD before call to nouveau_pm_perflvl_get(). Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_pm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/nouveau/nouveau_pm.c') diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c index 3c55ec2366d3..d2f2de67f688 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.c +++ b/drivers/gpu/drm/nouveau/nouveau_pm.c @@ -916,6 +916,8 @@ nouveau_pm_init(struct drm_device *dev) nouveau_volt_init(dev); nouveau_temp_init(dev); + INIT_LIST_HEAD(&pm->profiles); + /* determine current ("boot") performance level */ ret = nouveau_pm_perflvl_get(dev, &pm->boot); if (ret) { @@ -927,7 +929,6 @@ nouveau_pm_init(struct drm_device *dev) strncpy(pm->boot.profile.name, "boot", 4); pm->boot.profile.func = &nouveau_pm_static_profile_func; - INIT_LIST_HEAD(&pm->profiles); list_add(&pm->boot.profile.head, &pm->profiles); pm->profile_ac = &pm->boot.profile; -- cgit v1.2.1 From 7d70e9c1c69a5d22588ff5977249ac944d7cdfb0 Mon Sep 17 00:00:00 2001 From: Martin Peres Date: Thu, 16 Aug 2012 11:00:55 +0200 Subject: drm/nouveau/therm: rework thermal table parsing As an accident, it should also fix temperature reading on nv4x. v2: introduce nvbios_therm_entry as advised by darktama Signed-off-by: Martin Peres Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_pm.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/gpu/drm/nouveau/nouveau_pm.c') diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c index d2f2de67f688..bdd50953488c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.c +++ b/drivers/gpu/drm/nouveau/nouveau_pm.c @@ -891,10 +891,7 @@ nouveau_pm_init(struct drm_device *dev) } pm->voltage_get = nouveau_voltage_gpio_get; pm->voltage_set = nouveau_voltage_gpio_set; - if (device->chipset == 0x50) - pm->temp_get = nv40_temp_get; - else - pm->temp_get = nv84_temp_get; + pm->temp_get = nv84_temp_get; pm->pwm_get = nv50_pm_pwm_get; pm->pwm_set = nv50_pm_pwm_set; } else -- cgit v1.2.1 From aa1b9b4836a8ab093ec06b0780553566a5430da7 Mon Sep 17 00:00:00 2001 From: Martin Peres Date: Sun, 2 Sep 2012 02:55:58 +0200 Subject: drm/nouveau/therm: move thermal-related functions to the therm subdev It looks scary because of the size, but I tried to keep the differences minimal. Further patches will fix the actual "driver" code and add new features. v2: change filenames, split to submodules v3: add a missing include v4: Ben Skeggs - fixed set_defaults() to allow min_duty < 30 (thermal table will override this if it's actually necessary) - fixed set_defaults() to not provide pwm_freq so nv4x (which only has pwm_div) can actually work. the boards using pwm_freq will have a thermal table entry to provide us the value. - removed unused files Signed-off-by: Martin Peres Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_pm.c | 244 ++++++++++------------------------- 1 file changed, 70 insertions(+), 174 deletions(-) (limited to 'drivers/gpu/drm/nouveau/nouveau_pm.c') diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c index bdd50953488c..8317e82b86ce 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.c +++ b/drivers/gpu/drm/nouveau/nouveau_pm.c @@ -34,9 +34,9 @@ #include "nouveau_drm.h" #include "nouveau_pm.h" -#include #include #include +#include MODULE_PARM_DESC(perflvl, "Performance level (default: boot)"); static char *nouveau_perflvl; @@ -46,87 +46,22 @@ MODULE_PARM_DESC(perflvl_wr, "Allow perflvl changes (warning: dangerous!)"); static int nouveau_perflvl_wr; module_param_named(perflvl_wr, nouveau_perflvl_wr, int, 0400); -static int -nouveau_pwmfan_get(struct drm_device *dev) -{ - struct nouveau_pm *pm = nouveau_pm(dev); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_device *device = nv_device(drm->device); - struct nouveau_gpio *gpio = nouveau_gpio(device); - struct dcb_gpio_func func; - u32 divs, duty; - int ret; - - if (!pm->pwm_get) - return -ENODEV; - - ret = gpio->find(gpio, 0, DCB_GPIO_PWM_FAN, 0xff, &func); - if (ret == 0) { - ret = pm->pwm_get(dev, func.line, &divs, &duty); - if (ret == 0 && divs) { - divs = max(divs, duty); - if (device->card_type <= NV_40 || (func.log[0] & 1)) - duty = divs - duty; - return (duty * 100) / divs; - } - - return gpio->get(gpio, 0, func.func, func.line) * 100; - } - - return -ENODEV; -} - -static int -nouveau_pwmfan_set(struct drm_device *dev, int percent) -{ - struct nouveau_pm *pm = nouveau_pm(dev); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_device *device = nv_device(drm->device); - struct nouveau_gpio *gpio = nouveau_gpio(device); - struct dcb_gpio_func func; - u32 divs, duty; - int ret; - - if (!pm->pwm_set) - return -ENODEV; - - ret = gpio->find(gpio, 0, DCB_GPIO_PWM_FAN, 0xff, &func); - if (ret == 0) { - divs = pm->fan.pwm_divisor; - if (pm->fan.pwm_freq) { - /*XXX: PNVIO clock more than likely... */ - divs = 135000 / pm->fan.pwm_freq; - if (nv_device(drm->device)->chipset < 0xa3) - divs /= 4; - } - - duty = ((divs * percent) + 99) / 100; - if (device->card_type <= NV_40 || (func.log[0] & 1)) - duty = divs - duty; - - ret = pm->pwm_set(dev, func.line, divs, duty); - if (!ret) - pm->fan.percent = percent; - return ret; - } - - return -ENODEV; -} - static int nouveau_pm_perflvl_aux(struct drm_device *dev, struct nouveau_pm_level *perflvl, struct nouveau_pm_level *a, struct nouveau_pm_level *b) { struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_pm *pm = nouveau_pm(dev); + struct nouveau_therm *therm = nouveau_therm(drm); int ret; /*XXX: not on all boards, we should control based on temperature * on recent boards.. or maybe on some other factor we don't * know about? */ - if (a->fanspeed && b->fanspeed && b->fanspeed > a->fanspeed) { - ret = nouveau_pwmfan_set(dev, perflvl->fanspeed); + if (therm && therm->fan_set && + a->fanspeed && b->fanspeed && b->fanspeed > a->fanspeed) { + ret = therm->fan_set(therm, perflvl->fanspeed); if (ret && ret != -ENODEV) { NV_ERROR(drm, "fanspeed set failed: %d\n", ret); return ret; @@ -291,7 +226,9 @@ const struct nouveau_pm_profile_func nouveau_pm_static_profile_func = { static int nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) { + struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_pm *pm = nouveau_pm(dev); + struct nouveau_therm *therm = nouveau_therm(drm->device); int ret; memset(perflvl, 0, sizeof(*perflvl)); @@ -310,9 +247,11 @@ nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) } } - ret = nouveau_pwmfan_get(dev); - if (ret > 0) - perflvl->fanspeed = ret; + if (therm && therm->fan_get) { + ret = therm->fan_get(therm); + if (ret >= 0) + perflvl->fanspeed = ret; + } nouveau_mem_timing_read(dev, &perflvl->timing); return 0; @@ -462,9 +401,10 @@ static ssize_t nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf) { struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_pm *pm = nouveau_pm(dev); + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_therm *therm = nouveau_therm(drm->device); - return snprintf(buf, PAGE_SIZE, "%d\n", pm->temp_get(dev)*1000); + return snprintf(buf, PAGE_SIZE, "%d\n", therm->temp_get(therm) * 1000); } static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, nouveau_hwmon_show_temp, NULL, 0); @@ -473,26 +413,25 @@ static ssize_t nouveau_hwmon_max_temp(struct device *d, struct device_attribute *a, char *buf) { struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_pm *pm = nouveau_pm(dev); - struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_therm *therm = nouveau_therm(drm->device); - return snprintf(buf, PAGE_SIZE, "%d\n", temp->down_clock*1000); + return snprintf(buf, PAGE_SIZE, "%d\n", + therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK) * 1000); } static ssize_t nouveau_hwmon_set_max_temp(struct device *d, struct device_attribute *a, const char *buf, size_t count) { struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_pm *pm = nouveau_pm(dev); - struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_therm *therm = nouveau_therm(drm->device); long value; if (kstrtol(buf, 10, &value) == -EINVAL) return count; - temp->down_clock = value/1000; - - nouveau_temp_safety_checks(dev); + therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK, value / 1000); return count; } @@ -505,10 +444,11 @@ nouveau_hwmon_critical_temp(struct device *d, struct device_attribute *a, char *buf) { struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_pm *pm = nouveau_pm(dev); - struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_therm *therm = nouveau_therm(drm->device); - return snprintf(buf, PAGE_SIZE, "%d\n", temp->critical*1000); + return snprintf(buf, PAGE_SIZE, "%d\n", + therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL) * 1000); } static ssize_t nouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a, @@ -516,16 +456,14 @@ nouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a, size_t count) { struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_pm *pm = nouveau_pm(dev); - struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp; + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_therm *therm = nouveau_therm(drm->device); long value; if (kstrtol(buf, 10, &value) == -EINVAL) return count; - temp->critical = value/1000; - - nouveau_temp_safety_checks(dev); + therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL, value / 1000); return count; } @@ -558,34 +496,9 @@ nouveau_hwmon_show_fan0_input(struct device *d, struct device_attribute *attr, { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_timer *ptimer = nouveau_timer(drm->device); - struct nouveau_gpio *gpio = nouveau_gpio(drm->device); - struct dcb_gpio_func func; - u32 cycles, cur, prev; - u64 start; - - if (gpio->find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, &func)) - return -ENODEV; - - /* Monitor the GPIO input 0x3b for 250ms. - * When the fan spins, it changes the value of GPIO FAN_SENSE. - * We get 4 changes (0 -> 1 -> 0 -> 1 -> [...]) per complete rotation. - */ - start = ptimer->read(ptimer); - prev = gpio->get(gpio, 0, func.func, func.line); - cycles = 0; - do { - cur = gpio->get(gpio, 0, func.func, func.line); - if (prev != cur) { - cycles++; - prev = cur; - } + struct nouveau_therm *therm = nouveau_therm(drm->device); - usleep_range(500, 1000); /* supports 0 < rpm < 7500 */ - } while (ptimer->read(ptimer) - start < 250000000); - - /* interpolate to get rpm */ - return sprintf(buf, "%i\n", cycles / 4 * 4 * 60); + return snprintf(buf, PAGE_SIZE, "%d\n", therm->fan_sense(therm)); } static SENSOR_DEVICE_ATTR(fan0_input, S_IRUGO, nouveau_hwmon_show_fan0_input, NULL, 0); @@ -594,9 +507,11 @@ static ssize_t nouveau_hwmon_get_pwm0(struct device *d, struct device_attribute *a, char *buf) { struct drm_device *dev = dev_get_drvdata(d); + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_therm *therm = nouveau_therm(drm->device); int ret; - ret = nouveau_pwmfan_get(dev); + ret = therm->fan_get(therm); if (ret < 0) return ret; @@ -608,7 +523,8 @@ nouveau_hwmon_set_pwm0(struct device *d, struct device_attribute *a, const char *buf, size_t count) { struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_pm *pm = nouveau_pm(dev); + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_therm *therm = nouveau_therm(drm->device); int ret = -ENODEV; long value; @@ -618,12 +534,7 @@ nouveau_hwmon_set_pwm0(struct device *d, struct device_attribute *a, if (kstrtol(buf, 10, &value) == -EINVAL) return -EINVAL; - if (value < pm->fan.min_duty) - value = pm->fan.min_duty; - if (value > pm->fan.max_duty) - value = pm->fan.max_duty; - - ret = nouveau_pwmfan_set(dev, value); + ret = therm->fan_set(therm, value); if (ret) return ret; @@ -639,9 +550,15 @@ nouveau_hwmon_get_pwm0_min(struct device *d, struct device_attribute *a, char *buf) { struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_pm *pm = nouveau_pm(dev); + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_therm *therm = nouveau_therm(drm->device); + int ret; + + ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MIN_DUTY); + if (ret < 0) + return ret; - return sprintf(buf, "%i\n", pm->fan.min_duty); + return sprintf(buf, "%i\n", ret); } static ssize_t @@ -649,22 +566,17 @@ nouveau_hwmon_set_pwm0_min(struct device *d, struct device_attribute *a, const char *buf, size_t count) { struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_pm *pm = nouveau_pm(dev); + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_therm *therm = nouveau_therm(drm->device); long value; + int ret; if (kstrtol(buf, 10, &value) == -EINVAL) return -EINVAL; - if (value < 0) - value = 0; - - if (pm->fan.max_duty - value < 10) - value = pm->fan.max_duty - 10; - - if (value < 10) - pm->fan.min_duty = 10; - else - pm->fan.min_duty = value; + ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MIN_DUTY, value); + if (ret < 0) + return ret; return count; } @@ -678,9 +590,15 @@ nouveau_hwmon_get_pwm0_max(struct device *d, struct device_attribute *a, char *buf) { struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_pm *pm = nouveau_pm(dev); + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_therm *therm = nouveau_therm(drm->device); + int ret; - return sprintf(buf, "%i\n", pm->fan.max_duty); + ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MAX_DUTY); + if (ret < 0) + return ret; + + return sprintf(buf, "%i\n", ret); } static ssize_t @@ -688,22 +606,17 @@ nouveau_hwmon_set_pwm0_max(struct device *d, struct device_attribute *a, const char *buf, size_t count) { struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_pm *pm = nouveau_pm(dev); + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_therm *therm = nouveau_therm(drm->device); long value; + int ret; if (kstrtol(buf, 10, &value) == -EINVAL) return -EINVAL; - if (value < 0) - value = 0; - - if (value - pm->fan.min_duty < 10) - value = pm->fan.min_duty + 10; - - if (value > 100) - pm->fan.max_duty = 100; - else - pm->fan.max_duty = value; + ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MAX_DUTY, value); + if (ret < 0) + return ret; return count; } @@ -747,14 +660,14 @@ nouveau_hwmon_init(struct drm_device *dev) { struct nouveau_pm *pm = nouveau_pm(dev); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_gpio *gpio = nouveau_gpio(drm->device); - struct dcb_gpio_func func; + struct nouveau_therm *therm = nouveau_therm(drm->device); #if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) struct device *hwmon_dev; int ret = 0; - if (!pm->temp_get) + if (!therm || !therm->temp_get || !therm->attr_get || + !therm->attr_set || therm->temp_get(therm) < 0) return -ENODEV; hwmon_dev = hwmon_device_register(&dev->pdev->dev); @@ -776,7 +689,7 @@ nouveau_hwmon_init(struct drm_device *dev) /*XXX: incorrect, need better detection for this, some boards have * the gpio entries for pwm fan control even when there's no * actual fan connected to it... therm table? */ - if (nouveau_pwmfan_get(dev) >= 0) { + if (therm->fan_get && therm->fan_get(therm) >= 0) { ret = sysfs_create_group(&dev->pdev->dev.kobj, &hwmon_pwm_fan_attrgroup); if (ret) @@ -784,7 +697,7 @@ nouveau_hwmon_init(struct drm_device *dev) } /* if the card can read the fan rpm */ - if (!gpio->find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, &func)) { + if (therm->fan_sense(therm) >= 0) { ret = sysfs_create_group(&dev->pdev->dev.kobj, &hwmon_fan_rpm_attrgroup); if (ret) @@ -873,9 +786,6 @@ nouveau_pm_init(struct drm_device *dev) pm->clocks_set = nv40_pm_clocks_set; pm->voltage_get = nouveau_voltage_gpio_get; pm->voltage_set = nouveau_voltage_gpio_set; - pm->temp_get = nv40_temp_get; - pm->pwm_get = nv40_pm_pwm_get; - pm->pwm_set = nv40_pm_pwm_set; } else if (device->card_type < NV_C0) { if (device->chipset < 0xa3 || @@ -891,9 +801,6 @@ nouveau_pm_init(struct drm_device *dev) } pm->voltage_get = nouveau_voltage_gpio_get; pm->voltage_set = nouveau_voltage_gpio_set; - pm->temp_get = nv84_temp_get; - pm->pwm_get = nv50_pm_pwm_get; - pm->pwm_set = nv50_pm_pwm_set; } else if (device->card_type < NV_E0) { pm->clocks_get = nvc0_pm_clocks_get; @@ -901,17 +808,11 @@ nouveau_pm_init(struct drm_device *dev) pm->clocks_set = nvc0_pm_clocks_set; pm->voltage_get = nouveau_voltage_gpio_get; pm->voltage_set = nouveau_voltage_gpio_set; - pm->temp_get = nv84_temp_get; - if (device->card_type < NV_D0) { - pm->pwm_get = nv50_pm_pwm_get; - pm->pwm_set = nv50_pm_pwm_set; - } } /* parse aux tables from vbios */ nouveau_volt_init(dev); - nouveau_temp_init(dev); INIT_LIST_HEAD(&pm->profiles); @@ -950,9 +851,6 @@ nouveau_pm_init(struct drm_device *dev) if (nouveau_perflvl != NULL) nouveau_pm_profile_set(dev, nouveau_perflvl); - /* determine the current fan speed */ - pm->fan.percent = nouveau_pwmfan_get(dev); - nouveau_sysfs_init(dev); nouveau_hwmon_init(dev); #if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY) @@ -977,7 +875,6 @@ nouveau_pm_fini(struct drm_device *dev) if (pm->cur != &pm->boot) nouveau_pm_perflvl_set(dev, &pm->boot); - nouveau_temp_fini(dev); nouveau_perf_fini(dev); nouveau_volt_fini(dev); @@ -1003,5 +900,4 @@ nouveau_pm_resume(struct drm_device *dev) perflvl = pm->cur; pm->cur = &pm->boot; nouveau_pm_perflvl_set(dev, perflvl); - nouveau_pwmfan_set(dev, pm->fan.percent); } -- cgit v1.2.1 From c9cbf135065c0a674d43451127a10e48a53f9054 Mon Sep 17 00:00:00 2001 From: Martin Peres Date: Tue, 4 Sep 2012 13:39:40 +0200 Subject: drm/nouveau/hwmon: rename pwm0* to pmw1* to follow hwmon's rules This was reported by tizbac on IRC. Signed-off-by: Martin Peres Reviewed-by: Ben Skeggs Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_pm.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers/gpu/drm/nouveau/nouveau_pm.c') diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c index 8317e82b86ce..0dca191ee173 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.c +++ b/drivers/gpu/drm/nouveau/nouveau_pm.c @@ -504,7 +504,7 @@ static SENSOR_DEVICE_ATTR(fan0_input, S_IRUGO, nouveau_hwmon_show_fan0_input, NULL, 0); static ssize_t -nouveau_hwmon_get_pwm0(struct device *d, struct device_attribute *a, char *buf) +nouveau_hwmon_get_pwm1(struct device *d, struct device_attribute *a, char *buf) { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); @@ -519,7 +519,7 @@ nouveau_hwmon_get_pwm0(struct device *d, struct device_attribute *a, char *buf) } static ssize_t -nouveau_hwmon_set_pwm0(struct device *d, struct device_attribute *a, +nouveau_hwmon_set_pwm1(struct device *d, struct device_attribute *a, const char *buf, size_t count) { struct drm_device *dev = dev_get_drvdata(d); @@ -541,12 +541,12 @@ nouveau_hwmon_set_pwm0(struct device *d, struct device_attribute *a, return count; } -static SENSOR_DEVICE_ATTR(pwm0, S_IRUGO | S_IWUSR, - nouveau_hwmon_get_pwm0, - nouveau_hwmon_set_pwm0, 0); +static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, + nouveau_hwmon_get_pwm1, + nouveau_hwmon_set_pwm1, 0); static ssize_t -nouveau_hwmon_get_pwm0_min(struct device *d, +nouveau_hwmon_get_pwm1_min(struct device *d, struct device_attribute *a, char *buf) { struct drm_device *dev = dev_get_drvdata(d); @@ -562,7 +562,7 @@ nouveau_hwmon_get_pwm0_min(struct device *d, } static ssize_t -nouveau_hwmon_set_pwm0_min(struct device *d, struct device_attribute *a, +nouveau_hwmon_set_pwm1_min(struct device *d, struct device_attribute *a, const char *buf, size_t count) { struct drm_device *dev = dev_get_drvdata(d); @@ -581,12 +581,12 @@ nouveau_hwmon_set_pwm0_min(struct device *d, struct device_attribute *a, return count; } -static SENSOR_DEVICE_ATTR(pwm0_min, S_IRUGO | S_IWUSR, - nouveau_hwmon_get_pwm0_min, - nouveau_hwmon_set_pwm0_min, 0); +static SENSOR_DEVICE_ATTR(pwm1_min, S_IRUGO | S_IWUSR, + nouveau_hwmon_get_pwm1_min, + nouveau_hwmon_set_pwm1_min, 0); static ssize_t -nouveau_hwmon_get_pwm0_max(struct device *d, +nouveau_hwmon_get_pwm1_max(struct device *d, struct device_attribute *a, char *buf) { struct drm_device *dev = dev_get_drvdata(d); @@ -602,7 +602,7 @@ nouveau_hwmon_get_pwm0_max(struct device *d, } static ssize_t -nouveau_hwmon_set_pwm0_max(struct device *d, struct device_attribute *a, +nouveau_hwmon_set_pwm1_max(struct device *d, struct device_attribute *a, const char *buf, size_t count) { struct drm_device *dev = dev_get_drvdata(d); @@ -621,9 +621,9 @@ nouveau_hwmon_set_pwm0_max(struct device *d, struct device_attribute *a, return count; } -static SENSOR_DEVICE_ATTR(pwm0_max, S_IRUGO | S_IWUSR, - nouveau_hwmon_get_pwm0_max, - nouveau_hwmon_set_pwm0_max, 0); +static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO | S_IWUSR, + nouveau_hwmon_get_pwm1_max, + nouveau_hwmon_set_pwm1_max, 0); static struct attribute *hwmon_attributes[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, @@ -638,9 +638,9 @@ static struct attribute *hwmon_fan_rpm_attributes[] = { NULL }; static struct attribute *hwmon_pwm_fan_attributes[] = { - &sensor_dev_attr_pwm0.dev_attr.attr, - &sensor_dev_attr_pwm0_min.dev_attr.attr, - &sensor_dev_attr_pwm0_max.dev_attr.attr, + &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_pwm1_min.dev_attr.attr, + &sensor_dev_attr_pwm1_max.dev_attr.attr, NULL }; -- cgit v1.2.1 From 2f951a5db5b55f65eb02d9a90aa7cecafde9f8b8 Mon Sep 17 00:00:00 2001 From: Martin Peres Date: Tue, 4 Sep 2012 13:52:00 +0200 Subject: drm/nouveau/therm: add support for fan-control modes For now, only 2 control modes are available: - NONE: The fan is never touched (default) - MANUAL: The fan is set to the user-defined fan speed (pwm1) This patch introduces a distinction between ptherm internal fan management and external fan management. The latter is bound to respect the fan mode while the first can still select the speed it wants unless the NONE mode is selected. This is important for automatic fan management. Signed-off-by: Martin Peres Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_pm.c | 40 ++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'drivers/gpu/drm/nouveau/nouveau_pm.c') diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c index 0dca191ee173..b9d5335df742 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.c +++ b/drivers/gpu/drm/nouveau/nouveau_pm.c @@ -503,6 +503,45 @@ nouveau_hwmon_show_fan0_input(struct device *d, struct device_attribute *attr, static SENSOR_DEVICE_ATTR(fan0_input, S_IRUGO, nouveau_hwmon_show_fan0_input, NULL, 0); + static ssize_t +nouveau_hwmon_get_pwm1_enable(struct device *d, + struct device_attribute *a, char *buf) +{ + struct drm_device *dev = dev_get_drvdata(d); + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_therm *therm = nouveau_therm(drm->device); + int ret; + + ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MODE); + if (ret < 0) + return ret; + + return sprintf(buf, "%i\n", ret); +} + +static ssize_t +nouveau_hwmon_set_pwm1_enable(struct device *d, struct device_attribute *a, + const char *buf, size_t count) +{ + struct drm_device *dev = dev_get_drvdata(d); + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_therm *therm = nouveau_therm(drm->device); + long value; + int ret; + + if (strict_strtol(buf, 10, &value) == -EINVAL) + return -EINVAL; + + ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MODE, value); + if (ret) + return ret; + else + return count; +} +static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, + nouveau_hwmon_get_pwm1_enable, + nouveau_hwmon_set_pwm1_enable, 0); + static ssize_t nouveau_hwmon_get_pwm1(struct device *d, struct device_attribute *a, char *buf) { @@ -638,6 +677,7 @@ static struct attribute *hwmon_fan_rpm_attributes[] = { NULL }; static struct attribute *hwmon_pwm_fan_attributes[] = { + &sensor_dev_attr_pwm1_enable.dev_attr.attr, &sensor_dev_attr_pwm1.dev_attr.attr, &sensor_dev_attr_pwm1_min.dev_attr.attr, &sensor_dev_attr_pwm1_max.dev_attr.attr, -- cgit v1.2.1