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;
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;
/* 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)))
return 0;
out:
- if (display)
- display->update(display);
-
kfree(hw_mode);
if (rval != 0)
}
}
+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)
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);
};
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;
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;