--- nouveau_backlight.c.orig 2016-08-04 20:59:42.590183002 -0400 +++ /usr/src/linux-source-4.6/drivers/gpu/drm/nouveau/nouveau_backlight.c 2016-08-09 10:52:46.527464118 -0400 @@ -35,6 +35,84 @@ #include "nouveau_drm.h" #include "nouveau_reg.h" #include "nouveau_encoder.h" +#include "nvif/device.h" +#include "nvkm/subdev/bios/gpio.h" + +#define NV30_BL_MIN_LEVEL 0x16d +#define NV30_BL_MAX_LEVEL 0x534 + +static int +nv30_get_intensity(struct backlight_device *bd) +{ + struct nouveau_drm *drm = bl_get_data(bd); + struct nvif_object *device = &drm->device.object; + int val = (nvif_rd32(device, NV30_PMC_BACKLIGHT) & + NV30_PMC_BACKLIGHT_MASK) >> 16; + + if (val == 0x00) + return 0; + + return val - NV30_BL_MIN_LEVEL + 1; +} + +static int +nv30_set_intensity(struct backlight_device *bd) +{ + struct nouveau_drm *drm = bl_get_data(bd); + struct nvif_object *device = &drm->device.object; + int val = bd->props.brightness; + int level; + + if (val == 0) + level = 0x00; + + else + level = val + NV30_BL_MIN_LEVEL - 1; + + nvif_wr32(device, NV30_PMC_BACKLIGHT, + (level << 16) + 0x80000535); /* workaround for disabled backlight after waking from suspend */ + + return 0; +} + +static const struct backlight_ops nv30_bl_ops = { + .options = BL_CORE_SUSPENDRESUME, + .get_brightness = nv30_get_intensity, + .update_status = nv30_set_intensity, +}; + +static int +nv30_backlight_init(struct drm_connector *connector) +{ + struct nouveau_drm *drm = nouveau_drm(connector->dev); + struct nvif_object *device = &drm->device.object; + struct backlight_properties props; + struct backlight_device *bd; + + struct dcb_gpio_func func; + struct nvkm_gpio *gpio = nvxx_gpio(&drm->device); + int ret; + ret = nvkm_gpio_find(gpio, 0, 0x00, 0xff, &func); + + if (ret != 0) + return 0; + + if (!(nvif_rd32(device, NV30_PMC_BACKLIGHT) & NV30_PMC_BACKLIGHT_MASK)) + return 0; + + memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; + props.max_brightness = NV30_BL_MAX_LEVEL - NV30_BL_MIN_LEVEL; /* includes an additional 0x00 level (backlight off) */ + bd = backlight_device_register("nv_backlight", connector->kdev, drm, + &nv30_bl_ops, &props); + if (IS_ERR(bd)) + return PTR_ERR(bd); + drm->backlight = bd; + bd->props.brightness = nv30_get_intensity(bd); + backlight_update_status(bd); + + return 0; +} static int nv40_get_intensity(struct backlight_device *bd) @@ -227,6 +305,8 @@ continue; switch (device->info.family) { + case NV_DEVICE_INFO_V0_RANKINE: + return nv30_backlight_init(connector); case NV_DEVICE_INFO_V0_CURIE: return nv40_backlight_init(connector); case NV_DEVICE_INFO_V0_TESLA: