diff options
| -rw-r--r-- | linux-core/nv50_dac.c | 38 | ||||
| -rw-r--r-- | linux-core/nv50_kms_wrapper.c | 34 | ||||
| -rw-r--r-- | linux-core/nv50_output.h | 2 | ||||
| -rw-r--r-- | 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; | 
