]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/gpu/drm/nouveau/nouveau_backlight.c
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu
[mv-sheeva.git] / drivers / gpu / drm / nouveau / nouveau_backlight.c
index 00a55dfdba82dc2d6a8a26ad91168774a71fc06c..fa22b28e8777c53738b9331e95c9e02efbdf7616 100644 (file)
 #include "nouveau_drv.h"
 #include "nouveau_drm.h"
 #include "nouveau_reg.h"
+#include "nouveau_encoder.h"
 
-static int nv40_get_intensity(struct backlight_device *bd)
+static int
+nv40_get_intensity(struct backlight_device *bd)
 {
        struct drm_device *dev = bl_get_data(bd);
        int val = (nv_rd32(dev, NV40_PMC_BACKLIGHT) & NV40_PMC_BACKLIGHT_MASK)
@@ -47,7 +49,8 @@ static int nv40_get_intensity(struct backlight_device *bd)
        return val;
 }
 
-static int nv40_set_intensity(struct backlight_device *bd)
+static int
+nv40_set_intensity(struct backlight_device *bd)
 {
        struct drm_device *dev = bl_get_data(bd);
        int val = bd->props.brightness;
@@ -65,30 +68,8 @@ static const struct backlight_ops nv40_bl_ops = {
        .update_status = nv40_set_intensity,
 };
 
-static int nv50_get_intensity(struct backlight_device *bd)
-{
-       struct drm_device *dev = bl_get_data(bd);
-
-       return nv_rd32(dev, NV50_PDISPLAY_SOR_BACKLIGHT);
-}
-
-static int nv50_set_intensity(struct backlight_device *bd)
-{
-       struct drm_device *dev = bl_get_data(bd);
-       int val = bd->props.brightness;
-
-       nv_wr32(dev, NV50_PDISPLAY_SOR_BACKLIGHT,
-               val | NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE);
-       return 0;
-}
-
-static const struct backlight_ops nv50_bl_ops = {
-       .options = BL_CORE_SUSPENDRESUME,
-       .get_brightness = nv50_get_intensity,
-       .update_status = nv50_set_intensity,
-};
-
-static int nouveau_nv40_backlight_init(struct drm_connector *connector)
+static int
+nv40_backlight_init(struct drm_connector *connector)
 {
        struct drm_device *dev = connector->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -113,34 +94,129 @@ static int nouveau_nv40_backlight_init(struct drm_connector *connector)
        return 0;
 }
 
-static int nouveau_nv50_backlight_init(struct drm_connector *connector)
+static int
+nv50_get_intensity(struct backlight_device *bd)
+{
+       struct nouveau_encoder *nv_encoder = bl_get_data(bd);
+       struct drm_device *dev = nv_encoder->base.base.dev;
+       int or = nv_encoder->or;
+       u32 div = 1025;
+       u32 val;
+
+       val  = nv_rd32(dev, NV50_PDISP_SOR_PWM_CTL(or));
+       val &= NV50_PDISP_SOR_PWM_CTL_VAL;
+       return ((val * 100) + (div / 2)) / div;
+}
+
+static int
+nv50_set_intensity(struct backlight_device *bd)
+{
+       struct nouveau_encoder *nv_encoder = bl_get_data(bd);
+       struct drm_device *dev = nv_encoder->base.base.dev;
+       int or = nv_encoder->or;
+       u32 div = 1025;
+       u32 val = (bd->props.brightness * div) / 100;
+
+       nv_wr32(dev, NV50_PDISP_SOR_PWM_CTL(or),
+                    NV50_PDISP_SOR_PWM_CTL_NEW | val);
+       return 0;
+}
+
+static const struct backlight_ops nv50_bl_ops = {
+       .options = BL_CORE_SUSPENDRESUME,
+       .get_brightness = nv50_get_intensity,
+       .update_status = nv50_set_intensity,
+};
+
+static int
+nva3_get_intensity(struct backlight_device *bd)
+{
+       struct nouveau_encoder *nv_encoder = bl_get_data(bd);
+       struct drm_device *dev = nv_encoder->base.base.dev;
+       int or = nv_encoder->or;
+       u32 div, val;
+
+       div  = nv_rd32(dev, NV50_PDISP_SOR_PWM_DIV(or));
+       val  = nv_rd32(dev, NV50_PDISP_SOR_PWM_CTL(or));
+       val &= NVA3_PDISP_SOR_PWM_CTL_VAL;
+       if (div && div >= val)
+               return ((val * 100) + (div / 2)) / div;
+
+       return 100;
+}
+
+static int
+nva3_set_intensity(struct backlight_device *bd)
+{
+       struct nouveau_encoder *nv_encoder = bl_get_data(bd);
+       struct drm_device *dev = nv_encoder->base.base.dev;
+       int or = nv_encoder->or;
+       u32 div, val;
+
+       div = nv_rd32(dev, NV50_PDISP_SOR_PWM_DIV(or));
+       val = (bd->props.brightness * div) / 100;
+       if (div) {
+               nv_wr32(dev, NV50_PDISP_SOR_PWM_CTL(or), val |
+                            NV50_PDISP_SOR_PWM_CTL_NEW |
+                            NVA3_PDISP_SOR_PWM_CTL_UNK);
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static const struct backlight_ops nva3_bl_ops = {
+       .options = BL_CORE_SUSPENDRESUME,
+       .get_brightness = nva3_get_intensity,
+       .update_status = nva3_set_intensity,
+};
+
+static int
+nv50_backlight_init(struct drm_connector *connector)
 {
        struct drm_device *dev = connector->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_encoder *nv_encoder;
        struct backlight_properties props;
        struct backlight_device *bd;
+       const struct backlight_ops *ops;
+
+       nv_encoder = find_encoder(connector, OUTPUT_LVDS);
+       if (!nv_encoder) {
+               nv_encoder = find_encoder(connector, OUTPUT_DP);
+               if (!nv_encoder)
+                       return -ENODEV;
+       }
 
-       if (!nv_rd32(dev, NV50_PDISPLAY_SOR_BACKLIGHT))
+       if (!nv_rd32(dev, NV50_PDISP_SOR_PWM_CTL(nv_encoder->or)))
                return 0;
 
+       if (dev_priv->chipset <= 0xa0 ||
+           dev_priv->chipset == 0xaa ||
+           dev_priv->chipset == 0xac)
+               ops = &nv50_bl_ops;
+       else
+               ops = &nva3_bl_ops;
+
        memset(&props, 0, sizeof(struct backlight_properties));
        props.type = BACKLIGHT_RAW;
-       props.max_brightness = 1025;
-       bd = backlight_device_register("nv_backlight", &connector->kdev, dev,
-                                      &nv50_bl_ops, &props);
+       props.max_brightness = 100;
+       bd = backlight_device_register("nv_backlight", &connector->kdev,
+                                      nv_encoder, ops, &props);
        if (IS_ERR(bd))
                return PTR_ERR(bd);
 
        dev_priv->backlight = bd;
-       bd->props.brightness = nv50_get_intensity(bd);
+       bd->props.brightness = bd->ops->get_brightness(bd);
        backlight_update_status(bd);
        return 0;
 }
 
-int nouveau_backlight_init(struct drm_connector *connector)
+int
+nouveau_backlight_init(struct drm_device *dev)
 {
-       struct drm_device *dev = connector->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct drm_connector *connector;
 
 #ifdef CONFIG_ACPI
        if (acpi_video_backlight_support()) {
@@ -150,21 +226,28 @@ int nouveau_backlight_init(struct drm_connector *connector)
        }
 #endif
 
-       switch (dev_priv->card_type) {
-       case NV_40:
-               return nouveau_nv40_backlight_init(connector);
-       case NV_50:
-               return nouveau_nv50_backlight_init(connector);
-       default:
-               break;
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS &&
+                   connector->connector_type != DRM_MODE_CONNECTOR_eDP)
+                       continue;
+
+               switch (dev_priv->card_type) {
+               case NV_40:
+                       return nv40_backlight_init(connector);
+               case NV_50:
+                       return nv50_backlight_init(connector);
+               default:
+                       break;
+               }
        }
 
+
        return 0;
 }
 
-void nouveau_backlight_exit(struct drm_connector *connector)
+void
+nouveau_backlight_exit(struct drm_device *dev)
 {
-       struct drm_device *dev = connector->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
 
        if (dev_priv->backlight) {