From 701011224c048e064295ee12e8a02f7f66d4175a Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Fri, 27 Jun 2008 01:16:36 +0200 Subject: NV50: Implement DPMS. --- linux-core/nv50_dac.c | 38 ++++++++++++++++++++++++++++++++++++++ linux-core/nv50_kms_wrapper.c | 34 +++++++++++++++++++++++++++++++--- linux-core/nv50_output.h | 2 ++ linux-core/nv50_sor.c | 24 ++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 3 deletions(-) diff --git a/linux-core/nv50_dac.c b/linux-core/nv50_dac.c index b237241e..f51ecf9d 100644 --- a/linux-core/nv50_dac.c +++ b/linux-core/nv50_dac.c @@ -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; diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 8b97882a..79eb2964 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -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) diff --git a/linux-core/nv50_output.h b/linux-core/nv50_output.h index bdee2826..7a6f9c7e 100644 --- a/linux-core/nv50_output.h +++ b/linux-core/nv50_output.h @@ -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); }; diff --git a/linux-core/nv50_sor.c b/linux-core/nv50_sor.c index fca9612f..84192803 100644 --- a/linux-core/nv50_sor.c +++ b/linux-core/nv50_sor.c @@ -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; -- cgit v1.2.3