NV50: Implement DPMS.
authorMaarten Maathuis <madman2003@gmail.com>
Thu, 26 Jun 2008 23:16:36 +0000 (01:16 +0200)
committerMaarten Maathuis <madman2003@gmail.com>
Thu, 26 Jun 2008 23:16:36 +0000 (01:16 +0200)
linux-core/nv50_dac.c
linux-core/nv50_kms_wrapper.c
linux-core/nv50_output.h
linux-core/nv50_sor.c

index b237241..f51ecf9 100644 (file)
@@ -96,6 +96,43 @@ static int nv50_dac_set_clock_mode(struct nv50_output *output)
        return 0;
 }
 
+static int nv50_dac_set_power_mode(struct nv50_output *output, int mode)
+{
+       struct drm_nouveau_private *dev_priv = output->dev->dev_private;
+       uint32_t val;
+       int or = nv50_output_or_offset(output);
+
+       NV50_DEBUG("or %d\n", or);
+
+       /* wait for it to be done */
+       while (NV_READ(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(or)) & NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_PENDING);
+
+       val = NV_READ(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(or)) & ~0x7F;
+
+       if (mode != DPMSModeOn)
+               val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_BLANKED;
+
+       switch (mode) {
+               case DPMSModeStandby:
+                       val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_HSYNC_OFF;
+                       break;
+               case DPMSModeSuspend:
+                       val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_VSYNC_OFF;
+                       break;
+               case DPMSModeOff:
+                       val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_OFF;
+                       val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_HSYNC_OFF;
+                       val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_VSYNC_OFF;
+                       break;
+               default:
+                       break;
+       }
+
+       NV_WRITE(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(or), val | NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_PENDING);
+
+       return 0;
+}
+
 static int nv50_dac_destroy(struct nv50_output *output)
 {
        struct drm_device *dev = output->dev;
@@ -172,6 +209,7 @@ int nv50_dac_create(struct drm_device *dev, int dcb_entry)
        output->validate_mode = nv50_dac_validate_mode;
        output->execute_mode = nv50_dac_execute_mode;
        output->set_clock_mode = nv50_dac_set_clock_mode;
+       output->set_power_mode = nv50_dac_set_power_mode;
        output->detect = NULL; /* TODO */
        output->destroy = nv50_dac_destroy;
 
index 8b97882..79eb296 100644 (file)
@@ -640,6 +640,18 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set)
                /* next line changes crtc, so putting it here is important */
                display->last_crtc = crtc->index;
 
+               /* this is executed immediately */
+               list_for_each_entry(output, &display->outputs, head) {
+                       if (output->crtc != crtc)
+                               continue;
+
+                       rval = output->set_power_mode(output, DPMSModeOn);
+                       if (rval != 0) {
+                               DRM_ERROR("output set power mode failed\n");
+                               goto out;
+                       }
+               }
+
                /* blank any unused crtcs */
                list_for_each_entry(crtc, &display->crtcs, head) {
                        if (!(crtc_mask & (1 << crtc->index)))
@@ -654,9 +666,6 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set)
        return 0;
 
 out:
-       if (display)
-               display->update(display);
-
        kfree(hw_mode);
 
        if (rval != 0)
@@ -938,12 +947,31 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u
        }
 }
 
+static bool nv50_kms_connector_set_property(struct drm_connector *connector,
+                                       struct drm_property *property,
+                                       uint64_t value)
+{
+       struct drm_device *dev = connector->dev;
+
+       if (property == dev->mode_config.dpms_property && connector->encoder) {
+               struct nv50_output *output = to_nv50_output(connector->encoder);
+
+               if (!output->set_power_mode(output, (int) value))
+                       return true;
+               else
+                       return false;
+       }
+
+       return false;
+}
+
 static const struct drm_connector_funcs nv50_kms_connector_funcs = {
        .save = NULL,
        .restore = NULL,
        .detect = nv50_kms_connector_detect,
        .destroy = nv50_kms_connector_destroy,
        .fill_modes = nv50_kms_connector_fill_modes,
+       .set_property = nv50_kms_connector_set_property
 };
 
 static int nv50_kms_connectors_init(struct drm_device *dev)
index bdee282..7a6f9c7 100644 (file)
@@ -49,6 +49,8 @@ struct nv50_output {
        int (*validate_mode) (struct nv50_output *output, struct nouveau_hw_mode *mode);
        int (*execute_mode) (struct nv50_output *output, bool disconnect);
        int (*set_clock_mode) (struct nv50_output *output);
+       /* this is not a normal modeset call, it is a direct register write, so it's executed immediately */
+       int (*set_power_mode) (struct nv50_output *output, int mode);
        bool (*detect) (struct nv50_output *output);
        int (*destroy) (struct nv50_output *output);
 };
index fca9612..8419280 100644 (file)
@@ -114,6 +114,29 @@ static int nv50_sor_set_clock_mode(struct nv50_output *output)
        return 0;
 }
 
+static int nv50_sor_set_power_mode(struct nv50_output *output, int mode)
+{
+       struct drm_nouveau_private *dev_priv = output->dev->dev_private;
+       uint32_t val;
+       int or = nv50_output_or_offset(output);
+
+       NV50_DEBUG("or %d\n", nv50_output_or_offset(output));
+
+       /* wait for it to be done */
+       while (NV_READ(NV50_PDISPLAY_SOR_REGS_DPMS_CTRL(or)) & NV50_PDISPLAY_SOR_REGS_DPMS_CTRL_PENDING);
+
+       val = NV_READ(NV50_PDISPLAY_SOR_REGS_DPMS_CTRL(or));
+
+       if (mode == DPMSModeOn)
+               val |= NV50_PDISPLAY_SOR_REGS_DPMS_CTRL_ON;
+       else
+               val &= ~NV50_PDISPLAY_SOR_REGS_DPMS_CTRL_ON;
+
+       NV_WRITE(NV50_PDISPLAY_SOR_REGS_DPMS_CTRL(or), val | NV50_PDISPLAY_SOR_REGS_DPMS_CTRL_PENDING);
+
+       return 0;
+}
+
 static int nv50_sor_destroy(struct nv50_output *output)
 {
        struct drm_device *dev = output->dev;
@@ -194,6 +217,7 @@ int nv50_sor_create(struct drm_device *dev, int dcb_entry)
        output->validate_mode = nv50_sor_validate_mode;
        output->execute_mode = nv50_sor_execute_mode;
        output->set_clock_mode = nv50_sor_set_clock_mode;
+       output->set_power_mode = nv50_sor_set_power_mode;
        output->detect = NULL;
        output->destroy = nv50_sor_destroy;