diff options
Diffstat (limited to 'drivers/gpu')
89 files changed, 1781 insertions, 1130 deletions
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 9d25dbbe6771..48e38ba22783 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -23,7 +23,7 @@ drm-$(CONFIG_DRM_PANEL) += drm_panel.o  drm-usb-y   := drm_usb.o -drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o +drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o  drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o  drm_kms_helper-$(CONFIG_DRM_KMS_FB_HELPER) += drm_fb_helper.o  drm_kms_helper-$(CONFIG_DRM_KMS_CMA_HELPER) += drm_fb_cma_helper.o diff --git a/drivers/gpu/drm/ast/ast_post.c b/drivers/gpu/drm/ast/ast_post.c index 977cfb35837a..635f6ffc27c2 100644 --- a/drivers/gpu/drm/ast/ast_post.c +++ b/drivers/gpu/drm/ast/ast_post.c @@ -572,7 +572,7 @@ static u32 cbr_scan2(struct ast_private *ast)  		for (loop = 0; loop < CBR_PASSNUM2; loop++) {  			if ((data = cbr_test2(ast)) != 0) {  				data2 &= data; -				if (!data) +				if (!data2)  					return 0;  				break;  			} diff --git a/drivers/gpu/drm/bochs/bochs.h b/drivers/gpu/drm/bochs/bochs.h index 741965c001a6..7eb52dd44b01 100644 --- a/drivers/gpu/drm/bochs/bochs.h +++ b/drivers/gpu/drm/bochs/bochs.h @@ -1,5 +1,6 @@  #include <linux/io.h>  #include <linux/fb.h> +#include <linux/console.h>  #include <drm/drmP.h>  #include <drm/drm_crtc.h> @@ -87,8 +88,6 @@ struct bochs_device {  		struct bochs_framebuffer gfb;  		struct drm_fb_helper helper;  		int size; -		int x1, y1, x2, y2; /* dirty rect */ -		spinlock_t dirty_lock;  		bool initialized;  	} fb;  }; diff --git a/drivers/gpu/drm/bochs/bochs_drv.c b/drivers/gpu/drm/bochs/bochs_drv.c index 395bba261c9a..9c13df29fd20 100644 --- a/drivers/gpu/drm/bochs/bochs_drv.c +++ b/drivers/gpu/drm/bochs/bochs_drv.c @@ -95,6 +95,49 @@ static struct drm_driver bochs_driver = {  };  /* ---------------------------------------------------------------------- */ +/* pm interface                                                           */ + +static int bochs_pm_suspend(struct device *dev) +{ +	struct pci_dev *pdev = to_pci_dev(dev); +	struct drm_device *drm_dev = pci_get_drvdata(pdev); +	struct bochs_device *bochs = drm_dev->dev_private; + +	drm_kms_helper_poll_disable(drm_dev); + +	if (bochs->fb.initialized) { +		console_lock(); +		fb_set_suspend(bochs->fb.helper.fbdev, 1); +		console_unlock(); +	} + +	return 0; +} + +static int bochs_pm_resume(struct device *dev) +{ +	struct pci_dev *pdev = to_pci_dev(dev); +	struct drm_device *drm_dev = pci_get_drvdata(pdev); +	struct bochs_device *bochs = drm_dev->dev_private; + +	drm_helper_resume_force_mode(drm_dev); + +	if (bochs->fb.initialized) { +		console_lock(); +		fb_set_suspend(bochs->fb.helper.fbdev, 0); +		console_unlock(); +	} + +	drm_kms_helper_poll_enable(drm_dev); +	return 0; +} + +static const struct dev_pm_ops bochs_pm_ops = { +	SET_SYSTEM_SLEEP_PM_OPS(bochs_pm_suspend, +				bochs_pm_resume) +}; + +/* ---------------------------------------------------------------------- */  /* pci interface                                                          */  static int bochs_kick_out_firmware_fb(struct pci_dev *pdev) @@ -155,6 +198,7 @@ static struct pci_driver bochs_pci_driver = {  	.id_table =	bochs_pci_tbl,  	.probe =	bochs_pci_probe,  	.remove =	bochs_pci_remove, +	.driver.pm =    &bochs_pm_ops,  };  /* ---------------------------------------------------------------------- */ diff --git a/drivers/gpu/drm/bochs/bochs_fbdev.c b/drivers/gpu/drm/bochs/bochs_fbdev.c index 4da5206b7cc9..561b84474122 100644 --- a/drivers/gpu/drm/bochs/bochs_fbdev.c +++ b/drivers/gpu/drm/bochs/bochs_fbdev.c @@ -190,7 +190,6 @@ int bochs_fbdev_init(struct bochs_device *bochs)  	int ret;  	bochs->fb.helper.funcs = &bochs_fb_helper_funcs; -	spin_lock_init(&bochs->fb.dirty_lock);  	ret = drm_fb_helper_init(bochs->dev, &bochs->fb.helper,  				 1, 1); diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.c b/drivers/gpu/drm/cirrus/cirrus_drv.c index 953fc8aea69c..08ce520f61a5 100644 --- a/drivers/gpu/drm/cirrus/cirrus_drv.c +++ b/drivers/gpu/drm/cirrus/cirrus_drv.c @@ -11,6 +11,7 @@  #include <linux/module.h>  #include <linux/console.h>  #include <drm/drmP.h> +#include <drm/drm_crtc_helper.h>  #include "cirrus_drv.h" @@ -75,6 +76,41 @@ static void cirrus_pci_remove(struct pci_dev *pdev)  	drm_put_dev(dev);  } +static int cirrus_pm_suspend(struct device *dev) +{ +	struct pci_dev *pdev = to_pci_dev(dev); +	struct drm_device *drm_dev = pci_get_drvdata(pdev); +	struct cirrus_device *cdev = drm_dev->dev_private; + +	drm_kms_helper_poll_disable(drm_dev); + +	if (cdev->mode_info.gfbdev) { +		console_lock(); +		fb_set_suspend(cdev->mode_info.gfbdev->helper.fbdev, 1); +		console_unlock(); +	} + +	return 0; +} + +static int cirrus_pm_resume(struct device *dev) +{ +	struct pci_dev *pdev = to_pci_dev(dev); +	struct drm_device *drm_dev = pci_get_drvdata(pdev); +	struct cirrus_device *cdev = drm_dev->dev_private; + +	drm_helper_resume_force_mode(drm_dev); + +	if (cdev->mode_info.gfbdev) { +		console_lock(); +		fb_set_suspend(cdev->mode_info.gfbdev->helper.fbdev, 0); +		console_unlock(); +	} + +	drm_kms_helper_poll_enable(drm_dev); +	return 0; +} +  static const struct file_operations cirrus_driver_fops = {  	.owner = THIS_MODULE,  	.open = drm_open, @@ -103,11 +139,17 @@ static struct drm_driver driver = {  	.dumb_destroy = drm_gem_dumb_destroy,  }; +static const struct dev_pm_ops cirrus_pm_ops = { +	SET_SYSTEM_SLEEP_PM_OPS(cirrus_pm_suspend, +				cirrus_pm_resume) +}; +  static struct pci_driver cirrus_pci_driver = {  	.name = DRIVER_NAME,  	.id_table = pciidlist,  	.probe = cirrus_pci_probe,  	.remove = cirrus_pci_remove, +	.driver.pm = &cirrus_pm_ops,  };  static int __init cirrus_init(void) diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c index 2d64aea83df2..f59433b7610c 100644 --- a/drivers/gpu/drm/cirrus/cirrus_mode.c +++ b/drivers/gpu/drm/cirrus/cirrus_mode.c @@ -308,6 +308,9 @@ static int cirrus_crtc_mode_set(struct drm_crtc *crtc,  	WREG_HDR(hdr);  	cirrus_crtc_do_set_base(crtc, old_fb, x, y, 0); + +	/* Unblank (needed on S3 resume, vgabios doesn't do it then) */ +	outb(0x20, 0x3c0);  	return 0;  } diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index c43825e8f5c1..df281b54db01 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -72,147 +72,6 @@ void drm_helper_move_panel_connectors_to_head(struct drm_device *dev)  }  EXPORT_SYMBOL(drm_helper_move_panel_connectors_to_head); -static bool drm_kms_helper_poll = true; -module_param_named(poll, drm_kms_helper_poll, bool, 0600); - -static void drm_mode_validate_flag(struct drm_connector *connector, -				   int flags) -{ -	struct drm_display_mode *mode; - -	if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE | -		      DRM_MODE_FLAG_3D_MASK)) -		return; - -	list_for_each_entry(mode, &connector->modes, head) { -		if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && -				!(flags & DRM_MODE_FLAG_INTERLACE)) -			mode->status = MODE_NO_INTERLACE; -		if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) && -				!(flags & DRM_MODE_FLAG_DBLSCAN)) -			mode->status = MODE_NO_DBLESCAN; -		if ((mode->flags & DRM_MODE_FLAG_3D_MASK) && -				!(flags & DRM_MODE_FLAG_3D_MASK)) -			mode->status = MODE_NO_STEREO; -	} - -	return; -} - -/** - * drm_helper_probe_single_connector_modes - get complete set of display modes - * @connector: connector to probe - * @maxX: max width for modes - * @maxY: max height for modes - * - * Based on the helper callbacks implemented by @connector try to detect all - * valid modes.  Modes will first be added to the connector's probed_modes list, - * then culled (based on validity and the @maxX, @maxY parameters) and put into - * the normal modes list. - * - * Intended to be use as a generic implementation of the ->fill_modes() - * @connector vfunc for drivers that use the crtc helpers for output mode - * filtering and detection. - * - * Returns: - * The number of modes found on @connector. - */ -int drm_helper_probe_single_connector_modes(struct drm_connector *connector, -					    uint32_t maxX, uint32_t maxY) -{ -	struct drm_device *dev = connector->dev; -	struct drm_display_mode *mode; -	struct drm_connector_helper_funcs *connector_funcs = -		connector->helper_private; -	int count = 0; -	int mode_flags = 0; -	bool verbose_prune = true; - -	WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); - -	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, -			drm_get_connector_name(connector)); -	/* set all modes to the unverified state */ -	list_for_each_entry(mode, &connector->modes, head) -		mode->status = MODE_UNVERIFIED; - -	if (connector->force) { -		if (connector->force == DRM_FORCE_ON) -			connector->status = connector_status_connected; -		else -			connector->status = connector_status_disconnected; -		if (connector->funcs->force) -			connector->funcs->force(connector); -	} else { -		connector->status = connector->funcs->detect(connector, true); -	} - -	/* Re-enable polling in case the global poll config changed. */ -	if (drm_kms_helper_poll != dev->mode_config.poll_running) -		drm_kms_helper_poll_enable(dev); - -	dev->mode_config.poll_running = drm_kms_helper_poll; - -	if (connector->status == connector_status_disconnected) { -		DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n", -			connector->base.id, drm_get_connector_name(connector)); -		drm_mode_connector_update_edid_property(connector, NULL); -		verbose_prune = false; -		goto prune; -	} - -#ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE -	count = drm_load_edid_firmware(connector); -	if (count == 0) -#endif -		count = (*connector_funcs->get_modes)(connector); - -	if (count == 0 && connector->status == connector_status_connected) -		count = drm_add_modes_noedid(connector, 1024, 768); -	if (count == 0) -		goto prune; - -	drm_mode_connector_list_update(connector); - -	if (maxX && maxY) -		drm_mode_validate_size(dev, &connector->modes, maxX, maxY); - -	if (connector->interlace_allowed) -		mode_flags |= DRM_MODE_FLAG_INTERLACE; -	if (connector->doublescan_allowed) -		mode_flags |= DRM_MODE_FLAG_DBLSCAN; -	if (connector->stereo_allowed) -		mode_flags |= DRM_MODE_FLAG_3D_MASK; -	drm_mode_validate_flag(connector, mode_flags); - -	list_for_each_entry(mode, &connector->modes, head) { -		if (mode->status == MODE_OK) -			mode->status = connector_funcs->mode_valid(connector, -								   mode); -	} - -prune: -	drm_mode_prune_invalid(dev, &connector->modes, verbose_prune); - -	if (list_empty(&connector->modes)) -		return 0; - -	list_for_each_entry(mode, &connector->modes, head) -		mode->vrefresh = drm_mode_vrefresh(mode); - -	drm_mode_sort(&connector->modes); - -	DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed modes :\n", connector->base.id, -			drm_get_connector_name(connector)); -	list_for_each_entry(mode, &connector->modes, head) { -		drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); -		drm_mode_debug_printmodeline(mode); -	} - -	return count; -} -EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); -  /**   * drm_helper_encoder_in_use - check if a given encoder is in use   * @encoder: encoder to check @@ -1020,232 +879,3 @@ void drm_helper_resume_force_mode(struct drm_device *dev)  	drm_modeset_unlock_all(dev);  }  EXPORT_SYMBOL(drm_helper_resume_force_mode); - -/** - * drm_kms_helper_hotplug_event - fire off KMS hotplug events - * @dev: drm_device whose connector state changed - * - * This function fires off the uevent for userspace and also calls the - * output_poll_changed function, which is most commonly used to inform the fbdev - * emulation code and allow it to update the fbcon output configuration. - * - * Drivers should call this from their hotplug handling code when a change is - * detected. Note that this function does not do any output detection of its - * own, like drm_helper_hpd_irq_event() does - this is assumed to be done by the - * driver already. - * - * This function must be called from process context with no mode - * setting locks held. - */ -void drm_kms_helper_hotplug_event(struct drm_device *dev) -{ -	/* send a uevent + call fbdev */ -	drm_sysfs_hotplug_event(dev); -	if (dev->mode_config.funcs->output_poll_changed) -		dev->mode_config.funcs->output_poll_changed(dev); -} -EXPORT_SYMBOL(drm_kms_helper_hotplug_event); - -#define DRM_OUTPUT_POLL_PERIOD (10*HZ) -static void output_poll_execute(struct work_struct *work) -{ -	struct delayed_work *delayed_work = to_delayed_work(work); -	struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work); -	struct drm_connector *connector; -	enum drm_connector_status old_status; -	bool repoll = false, changed = false; - -	if (!drm_kms_helper_poll) -		return; - -	mutex_lock(&dev->mode_config.mutex); -	list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - -		/* Ignore forced connectors. */ -		if (connector->force) -			continue; - -		/* Ignore HPD capable connectors and connectors where we don't -		 * want any hotplug detection at all for polling. */ -		if (!connector->polled || connector->polled == DRM_CONNECTOR_POLL_HPD) -			continue; - -		repoll = true; - -		old_status = connector->status; -		/* if we are connected and don't want to poll for disconnect -		   skip it */ -		if (old_status == connector_status_connected && -		    !(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT)) -			continue; - -		connector->status = connector->funcs->detect(connector, false); -		if (old_status != connector->status) { -			const char *old, *new; - -			old = drm_get_connector_status_name(old_status); -			new = drm_get_connector_status_name(connector->status); - -			DRM_DEBUG_KMS("[CONNECTOR:%d:%s] " -				      "status updated from %s to %s\n", -				      connector->base.id, -				      drm_get_connector_name(connector), -				      old, new); - -			changed = true; -		} -	} - -	mutex_unlock(&dev->mode_config.mutex); - -	if (changed) -		drm_kms_helper_hotplug_event(dev); - -	if (repoll) -		schedule_delayed_work(delayed_work, DRM_OUTPUT_POLL_PERIOD); -} - -/** - * drm_kms_helper_poll_disable - disable output polling - * @dev: drm_device - * - * This function disables the output polling work. - * - * Drivers can call this helper from their device suspend implementation. It is - * not an error to call this even when output polling isn't enabled or arlready - * disabled. - */ -void drm_kms_helper_poll_disable(struct drm_device *dev) -{ -	if (!dev->mode_config.poll_enabled) -		return; -	cancel_delayed_work_sync(&dev->mode_config.output_poll_work); -} -EXPORT_SYMBOL(drm_kms_helper_poll_disable); - -/** - * drm_kms_helper_poll_enable - re-enable output polling. - * @dev: drm_device - * - * This function re-enables the output polling work. - * - * Drivers can call this helper from their device resume implementation. It is - * an error to call this when the output polling support has not yet been set - * up. - */ -void drm_kms_helper_poll_enable(struct drm_device *dev) -{ -	bool poll = false; -	struct drm_connector *connector; - -	if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll) -		return; - -	list_for_each_entry(connector, &dev->mode_config.connector_list, head) { -		if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | -					 DRM_CONNECTOR_POLL_DISCONNECT)) -			poll = true; -	} - -	if (poll) -		schedule_delayed_work(&dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD); -} -EXPORT_SYMBOL(drm_kms_helper_poll_enable); - -/** - * drm_kms_helper_poll_init - initialize and enable output polling - * @dev: drm_device - * - * This function intializes and then also enables output polling support for - * @dev. Drivers which do not have reliable hotplug support in hardware can use - * this helper infrastructure to regularly poll such connectors for changes in - * their connection state. - * - * Drivers can control which connectors are polled by setting the - * DRM_CONNECTOR_POLL_CONNECT and DRM_CONNECTOR_POLL_DISCONNECT flags. On - * connectors where probing live outputs can result in visual distortion drivers - * should not set the DRM_CONNECTOR_POLL_DISCONNECT flag to avoid this. - * Connectors which have no flag or only DRM_CONNECTOR_POLL_HPD set are - * completely ignored by the polling logic. - * - * Note that a connector can be both polled and probed from the hotplug handler, - * in case the hotplug interrupt is known to be unreliable. - */ -void drm_kms_helper_poll_init(struct drm_device *dev) -{ -	INIT_DELAYED_WORK(&dev->mode_config.output_poll_work, output_poll_execute); -	dev->mode_config.poll_enabled = true; - -	drm_kms_helper_poll_enable(dev); -} -EXPORT_SYMBOL(drm_kms_helper_poll_init); - -/** - * drm_kms_helper_poll_fini - disable output polling and clean it up - * @dev: drm_device - */ -void drm_kms_helper_poll_fini(struct drm_device *dev) -{ -	drm_kms_helper_poll_disable(dev); -} -EXPORT_SYMBOL(drm_kms_helper_poll_fini); - -/** - * drm_helper_hpd_irq_event - hotplug processing - * @dev: drm_device - * - * Drivers can use this helper function to run a detect cycle on all connectors - * which have the DRM_CONNECTOR_POLL_HPD flag set in their &polled member. All - * other connectors are ignored, which is useful to avoid reprobing fixed - * panels. - * - * This helper function is useful for drivers which can't or don't track hotplug - * interrupts for each connector. - * - * Drivers which support hotplug interrupts for each connector individually and - * which have a more fine-grained detect logic should bypass this code and - * directly call drm_kms_helper_hotplug_event() in case the connector state - * changed. - * - * This function must be called from process context with no mode - * setting locks held. - * - * Note that a connector can be both polled and probed from the hotplug handler, - * in case the hotplug interrupt is known to be unreliable. - */ -bool drm_helper_hpd_irq_event(struct drm_device *dev) -{ -	struct drm_connector *connector; -	enum drm_connector_status old_status; -	bool changed = false; - -	if (!dev->mode_config.poll_enabled) -		return false; - -	mutex_lock(&dev->mode_config.mutex); -	list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - -		/* Only handle HPD capable connectors. */ -		if (!(connector->polled & DRM_CONNECTOR_POLL_HPD)) -			continue; - -		old_status = connector->status; - -		connector->status = connector->funcs->detect(connector, false); -		DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n", -			      connector->base.id, -			      drm_get_connector_name(connector), -			      drm_get_connector_status_name(old_status), -			      drm_get_connector_status_name(connector->status)); -		if (old_status != connector->status) -			changed = true; -	} - -	mutex_unlock(&dev->mode_config.mutex); - -	if (changed) -		drm_kms_helper_hotplug_event(dev); - -	return changed; -} -EXPORT_SYMBOL(drm_helper_hpd_irq_event); diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 27671489477d..4b6e6f3ba0a1 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -577,7 +577,9 @@ static u32 drm_dp_i2c_functionality(struct i2c_adapter *adapter)  /*   * Transfer a single I2C-over-AUX message and handle various error conditions, - * retrying the transaction as appropriate. + * retrying the transaction as appropriate.  It is assumed that the + * aux->transfer function does not modify anything in the msg other than the + * reply field.   */  static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)  { @@ -665,11 +667,26 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,  {  	struct drm_dp_aux *aux = adapter->algo_data;  	unsigned int i, j; +	struct drm_dp_aux_msg msg; +	int err = 0; -	for (i = 0; i < num; i++) { -		struct drm_dp_aux_msg msg; -		int err; +	memset(&msg, 0, sizeof(msg)); +	for (i = 0; i < num; i++) { +		msg.address = msgs[i].addr; +		msg.request = (msgs[i].flags & I2C_M_RD) ? +			DP_AUX_I2C_READ : +			DP_AUX_I2C_WRITE; +		msg.request |= DP_AUX_I2C_MOT; +		/* Send a bare address packet to start the transaction. +		 * Zero sized messages specify an address only (bare +		 * address) transaction. +		 */ +		msg.buffer = NULL; +		msg.size = 0; +		err = drm_dp_i2c_do_msg(aux, &msg); +		if (err < 0) +			break;  		/*  		 * Many hardware implementations support FIFOs larger than a  		 * single byte, but it has been empirically determined that @@ -678,30 +695,28 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,  		 * transferred byte-by-byte.  		 */  		for (j = 0; j < msgs[i].len; j++) { -			memset(&msg, 0, sizeof(msg)); -			msg.address = msgs[i].addr; - -			msg.request = (msgs[i].flags & I2C_M_RD) ? -					DP_AUX_I2C_READ : -					DP_AUX_I2C_WRITE; - -			/* -			 * All messages except the last one are middle-of- -			 * transfer messages. -			 */ -			if ((i < num - 1) || (j < msgs[i].len - 1)) -				msg.request |= DP_AUX_I2C_MOT; -  			msg.buffer = msgs[i].buf + j;  			msg.size = 1;  			err = drm_dp_i2c_do_msg(aux, &msg);  			if (err < 0) -				return err; +				break;  		} +		if (err < 0) +			break;  	} +	if (err >= 0) +		err = num; +	/* Send a bare address packet to close out the transaction. +	 * Zero sized messages specify an address only (bare +	 * address) transaction. +	 */ +	msg.request &= ~DP_AUX_I2C_MOT; +	msg.buffer = NULL; +	msg.size = 0; +	(void)drm_dp_i2c_do_msg(aux, &msg); -	return num; +	return err;  }  static const struct i2c_algorithm drm_dp_i2c_algo = { diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 71e2d3fcd6ee..04a209e2b66d 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -207,8 +207,6 @@ int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node)  		return 0;  	} -	WARN(1, "no hole found for node 0x%lx + 0x%lx\n", -	     node->start, node->size);  	return -ENOSPC;  }  EXPORT_SYMBOL(drm_mm_reserve_node); diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index e768d35ff22e..d2b1c03b3d71 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -203,9 +203,9 @@ EXPORT_SYMBOL(drm_primary_helper_update);   *   * Provides a default plane disable handler for primary planes.  This is handler   * is called in response to a userspace SetPlane operation on the plane with a - * NULL framebuffer parameter.  We call the driver's modeset handler with a NULL - * framebuffer to disable the CRTC if no other planes are currently enabled. - * If other planes are still enabled on the same CRTC, we return -EBUSY. + * NULL framebuffer parameter.  It unconditionally fails the disable call with + * -EINVAL the only way to disable the primary plane without driver support is + * to disable the entier CRTC. Which does not match the plane ->disable hook.   *   * Note that some hardware may be able to disable the primary plane without   * disabling the whole CRTC.  Drivers for such hardware should provide their @@ -214,34 +214,11 @@ EXPORT_SYMBOL(drm_primary_helper_update);   * disabled primary plane).   *   * RETURNS: - * Zero on success, error code on failure + * Unconditionally returns -EINVAL.   */  int drm_primary_helper_disable(struct drm_plane *plane)  { -	struct drm_plane *p; -	struct drm_mode_set set = { -		.crtc = plane->crtc, -		.fb = NULL, -	}; - -	if (plane->crtc == NULL || plane->fb == NULL) -		/* Already disabled */ -		return 0; - -	list_for_each_entry(p, &plane->dev->mode_config.plane_list, head) -		if (p != plane && p->fb) { -			DRM_DEBUG_KMS("Cannot disable primary plane while other planes are still active on CRTC.\n"); -			return -EBUSY; -		} - -	/* -	 * N.B.  We call set_config() directly here rather than -	 * drm_mode_set_config_internal() since drm_mode_setplane() already -	 * handles the basic refcounting and we don't need the special -	 * cross-CRTC refcounting (no chance of stealing connectors from -	 * other CRTC's with this update). -	 */ -	return plane->crtc->funcs->set_config(&set); +	return -EINVAL;  }  EXPORT_SYMBOL(drm_primary_helper_disable); diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c new file mode 100644 index 000000000000..e70f54d4a581 --- /dev/null +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -0,0 +1,426 @@ +/* + * Copyright (c) 2006-2008 Intel Corporation + * Copyright (c) 2007 Dave Airlie <airlied@linux.ie> + * + * DRM core CRTC related functions + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission.  The copyright holders make no representations + * about the suitability of this software for any purpose.  It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + * + * Authors: + *      Keith Packard + *	Eric Anholt <eric@anholt.net> + *      Dave Airlie <airlied@linux.ie> + *      Jesse Barnes <jesse.barnes@intel.com> + */ + +#include <linux/export.h> +#include <linux/moduleparam.h> + +#include <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_fb_helper.h> +#include <drm/drm_edid.h> + +/** + * DOC: output probing helper overview + * + * This library provides some helper code for output probing. It provides an + * implementation of the core connector->fill_modes interface with + * drm_helper_probe_single_connector_modes. + * + * It also provides support for polling connectors with a work item and for + * generic hotplug interrupt handling where the driver doesn't or cannot keep + * track of a per-connector hpd interrupt. + * + * This helper library can be used independently of the modeset helper library. + * Drivers can also overwrite different parts e.g. use their own hotplug + * handling code to avoid probing unrelated outputs. + */ + +static bool drm_kms_helper_poll = true; +module_param_named(poll, drm_kms_helper_poll, bool, 0600); + +static void drm_mode_validate_flag(struct drm_connector *connector, +				   int flags) +{ +	struct drm_display_mode *mode; + +	if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE | +		      DRM_MODE_FLAG_3D_MASK)) +		return; + +	list_for_each_entry(mode, &connector->modes, head) { +		if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && +				!(flags & DRM_MODE_FLAG_INTERLACE)) +			mode->status = MODE_NO_INTERLACE; +		if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) && +				!(flags & DRM_MODE_FLAG_DBLSCAN)) +			mode->status = MODE_NO_DBLESCAN; +		if ((mode->flags & DRM_MODE_FLAG_3D_MASK) && +				!(flags & DRM_MODE_FLAG_3D_MASK)) +			mode->status = MODE_NO_STEREO; +	} + +	return; +} + +/** + * drm_helper_probe_single_connector_modes - get complete set of display modes + * @connector: connector to probe + * @maxX: max width for modes + * @maxY: max height for modes + * + * Based on the helper callbacks implemented by @connector try to detect all + * valid modes.  Modes will first be added to the connector's probed_modes list, + * then culled (based on validity and the @maxX, @maxY parameters) and put into + * the normal modes list. + * + * Intended to be use as a generic implementation of the ->fill_modes() + * @connector vfunc for drivers that use the crtc helpers for output mode + * filtering and detection. + * + * Returns: + * The number of modes found on @connector. + */ +int drm_helper_probe_single_connector_modes(struct drm_connector *connector, +					    uint32_t maxX, uint32_t maxY) +{ +	struct drm_device *dev = connector->dev; +	struct drm_display_mode *mode; +	struct drm_connector_helper_funcs *connector_funcs = +		connector->helper_private; +	int count = 0; +	int mode_flags = 0; +	bool verbose_prune = true; + +	WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); + +	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, +			drm_get_connector_name(connector)); +	/* set all modes to the unverified state */ +	list_for_each_entry(mode, &connector->modes, head) +		mode->status = MODE_UNVERIFIED; + +	if (connector->force) { +		if (connector->force == DRM_FORCE_ON) +			connector->status = connector_status_connected; +		else +			connector->status = connector_status_disconnected; +		if (connector->funcs->force) +			connector->funcs->force(connector); +	} else { +		connector->status = connector->funcs->detect(connector, true); +	} + +	/* Re-enable polling in case the global poll config changed. */ +	if (drm_kms_helper_poll != dev->mode_config.poll_running) +		drm_kms_helper_poll_enable(dev); + +	dev->mode_config.poll_running = drm_kms_helper_poll; + +	if (connector->status == connector_status_disconnected) { +		DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n", +			connector->base.id, drm_get_connector_name(connector)); +		drm_mode_connector_update_edid_property(connector, NULL); +		verbose_prune = false; +		goto prune; +	} + +#ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE +	count = drm_load_edid_firmware(connector); +	if (count == 0) +#endif +		count = (*connector_funcs->get_modes)(connector); + +	if (count == 0 && connector->status == connector_status_connected) +		count = drm_add_modes_noedid(connector, 1024, 768); +	if (count == 0) +		goto prune; + +	drm_mode_connector_list_update(connector); + +	if (maxX && maxY) +		drm_mode_validate_size(dev, &connector->modes, maxX, maxY); + +	if (connector->interlace_allowed) +		mode_flags |= DRM_MODE_FLAG_INTERLACE; +	if (connector->doublescan_allowed) +		mode_flags |= DRM_MODE_FLAG_DBLSCAN; +	if (connector->stereo_allowed) +		mode_flags |= DRM_MODE_FLAG_3D_MASK; +	drm_mode_validate_flag(connector, mode_flags); + +	list_for_each_entry(mode, &connector->modes, head) { +		if (mode->status == MODE_OK) +			mode->status = connector_funcs->mode_valid(connector, +								   mode); +	} + +prune: +	drm_mode_prune_invalid(dev, &connector->modes, verbose_prune); + +	if (list_empty(&connector->modes)) +		return 0; + +	list_for_each_entry(mode, &connector->modes, head) +		mode->vrefresh = drm_mode_vrefresh(mode); + +	drm_mode_sort(&connector->modes); + +	DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed modes :\n", connector->base.id, +			drm_get_connector_name(connector)); +	list_for_each_entry(mode, &connector->modes, head) { +		drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); +		drm_mode_debug_printmodeline(mode); +	} + +	return count; +} +EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); + +/** + * drm_kms_helper_hotplug_event - fire off KMS hotplug events + * @dev: drm_device whose connector state changed + * + * This function fires off the uevent for userspace and also calls the + * output_poll_changed function, which is most commonly used to inform the fbdev + * emulation code and allow it to update the fbcon output configuration. + * + * Drivers should call this from their hotplug handling code when a change is + * detected. Note that this function does not do any output detection of its + * own, like drm_helper_hpd_irq_event() does - this is assumed to be done by the + * driver already. + * + * This function must be called from process context with no mode + * setting locks held. + */ +void drm_kms_helper_hotplug_event(struct drm_device *dev) +{ +	/* send a uevent + call fbdev */ +	drm_sysfs_hotplug_event(dev); +	if (dev->mode_config.funcs->output_poll_changed) +		dev->mode_config.funcs->output_poll_changed(dev); +} +EXPORT_SYMBOL(drm_kms_helper_hotplug_event); + +#define DRM_OUTPUT_POLL_PERIOD (10*HZ) +static void output_poll_execute(struct work_struct *work) +{ +	struct delayed_work *delayed_work = to_delayed_work(work); +	struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work); +	struct drm_connector *connector; +	enum drm_connector_status old_status; +	bool repoll = false, changed = false; + +	if (!drm_kms_helper_poll) +		return; + +	mutex_lock(&dev->mode_config.mutex); +	list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + +		/* Ignore forced connectors. */ +		if (connector->force) +			continue; + +		/* Ignore HPD capable connectors and connectors where we don't +		 * want any hotplug detection at all for polling. */ +		if (!connector->polled || connector->polled == DRM_CONNECTOR_POLL_HPD) +			continue; + +		repoll = true; + +		old_status = connector->status; +		/* if we are connected and don't want to poll for disconnect +		   skip it */ +		if (old_status == connector_status_connected && +		    !(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT)) +			continue; + +		connector->status = connector->funcs->detect(connector, false); +		if (old_status != connector->status) { +			const char *old, *new; + +			old = drm_get_connector_status_name(old_status); +			new = drm_get_connector_status_name(connector->status); + +			DRM_DEBUG_KMS("[CONNECTOR:%d:%s] " +				      "status updated from %s to %s\n", +				      connector->base.id, +				      drm_get_connector_name(connector), +				      old, new); + +			changed = true; +		} +	} + +	mutex_unlock(&dev->mode_config.mutex); + +	if (changed) +		drm_kms_helper_hotplug_event(dev); + +	if (repoll) +		schedule_delayed_work(delayed_work, DRM_OUTPUT_POLL_PERIOD); +} + +/** + * drm_kms_helper_poll_disable - disable output polling + * @dev: drm_device + * + * This function disables the output polling work. + * + * Drivers can call this helper from their device suspend implementation. It is + * not an error to call this even when output polling isn't enabled or arlready + * disabled. + */ +void drm_kms_helper_poll_disable(struct drm_device *dev) +{ +	if (!dev->mode_config.poll_enabled) +		return; +	cancel_delayed_work_sync(&dev->mode_config.output_poll_work); +} +EXPORT_SYMBOL(drm_kms_helper_poll_disable); + +/** + * drm_kms_helper_poll_enable - re-enable output polling. + * @dev: drm_device + * + * This function re-enables the output polling work. + * + * Drivers can call this helper from their device resume implementation. It is + * an error to call this when the output polling support has not yet been set + * up. + */ +void drm_kms_helper_poll_enable(struct drm_device *dev) +{ +	bool poll = false; +	struct drm_connector *connector; + +	if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll) +		return; + +	list_for_each_entry(connector, &dev->mode_config.connector_list, head) { +		if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | +					 DRM_CONNECTOR_POLL_DISCONNECT)) +			poll = true; +	} + +	if (poll) +		schedule_delayed_work(&dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD); +} +EXPORT_SYMBOL(drm_kms_helper_poll_enable); + +/** + * drm_kms_helper_poll_init - initialize and enable output polling + * @dev: drm_device + * + * This function intializes and then also enables output polling support for + * @dev. Drivers which do not have reliable hotplug support in hardware can use + * this helper infrastructure to regularly poll such connectors for changes in + * their connection state. + * + * Drivers can control which connectors are polled by setting the + * DRM_CONNECTOR_POLL_CONNECT and DRM_CONNECTOR_POLL_DISCONNECT flags. On + * connectors where probing live outputs can result in visual distortion drivers + * should not set the DRM_CONNECTOR_POLL_DISCONNECT flag to avoid this. + * Connectors which have no flag or only DRM_CONNECTOR_POLL_HPD set are + * completely ignored by the polling logic. + * + * Note that a connector can be both polled and probed from the hotplug handler, + * in case the hotplug interrupt is known to be unreliable. + */ +void drm_kms_helper_poll_init(struct drm_device *dev) +{ +	INIT_DELAYED_WORK(&dev->mode_config.output_poll_work, output_poll_execute); +	dev->mode_config.poll_enabled = true; + +	drm_kms_helper_poll_enable(dev); +} +EXPORT_SYMBOL(drm_kms_helper_poll_init); + +/** + * drm_kms_helper_poll_fini - disable output polling and clean it up + * @dev: drm_device + */ +void drm_kms_helper_poll_fini(struct drm_device *dev) +{ +	drm_kms_helper_poll_disable(dev); +} +EXPORT_SYMBOL(drm_kms_helper_poll_fini); + +/** + * drm_helper_hpd_irq_event - hotplug processing + * @dev: drm_device + * + * Drivers can use this helper function to run a detect cycle on all connectors + * which have the DRM_CONNECTOR_POLL_HPD flag set in their &polled member. All + * other connectors are ignored, which is useful to avoid reprobing fixed + * panels. + * + * This helper function is useful for drivers which can't or don't track hotplug + * interrupts for each connector. + * + * Drivers which support hotplug interrupts for each connector individually and + * which have a more fine-grained detect logic should bypass this code and + * directly call drm_kms_helper_hotplug_event() in case the connector state + * changed. + * + * This function must be called from process context with no mode + * setting locks held. + * + * Note that a connector can be both polled and probed from the hotplug handler, + * in case the hotplug interrupt is known to be unreliable. + */ +bool drm_helper_hpd_irq_event(struct drm_device *dev) +{ +	struct drm_connector *connector; +	enum drm_connector_status old_status; +	bool changed = false; + +	if (!dev->mode_config.poll_enabled) +		return false; + +	mutex_lock(&dev->mode_config.mutex); +	list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + +		/* Only handle HPD capable connectors. */ +		if (!(connector->polled & DRM_CONNECTOR_POLL_HPD)) +			continue; + +		old_status = connector->status; + +		connector->status = connector->funcs->detect(connector, false); +		DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n", +			      connector->base.id, +			      drm_get_connector_name(connector), +			      drm_get_connector_status_name(old_status), +			      drm_get_connector_status_name(connector->status)); +		if (old_status != connector->status) +			changed = true; +	} + +	mutex_unlock(&dev->mode_config.mutex); + +	if (changed) +		drm_kms_helper_hotplug_event(dev); + +	return changed; +} +EXPORT_SYMBOL(drm_helper_hpd_irq_event); diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index e930d4fe29c7..1ef5ab9c9d51 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -145,6 +145,7 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,  	plane->crtc = crtc;  	plane->fb = crtc->primary->fb; +	drm_framebuffer_reference(plane->fb);  	return 0;  } diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c index c786cd4f457b..2a3ad24276f8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c @@ -263,7 +263,7 @@ struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,  	buffer->sgt = sgt;  	exynos_gem_obj->base.import_attach = attach; -	DRM_DEBUG_PRIME("dma_addr = 0x%x, size = 0x%lx\n", buffer->dma_addr, +	DRM_DEBUG_PRIME("dma_addr = %pad, size = 0x%lx\n", &buffer->dma_addr,  								buffer->size);  	return &exynos_gem_obj->base; diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index eb73e3bf2a0c..4ac438187568 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1426,9 +1426,9 @@ static int exynos_dsi_probe(struct platform_device *pdev)  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	dsi->reg_base = devm_ioremap_resource(&pdev->dev, res); -	if (!dsi->reg_base) { +	if (IS_ERR(dsi->reg_base)) {  		dev_err(&pdev->dev, "failed to remap io region\n"); -		return -EADDRNOTAVAIL; +		return PTR_ERR(dsi->reg_base);  	}  	dsi->phy = devm_phy_get(&pdev->dev, "dsim"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 7afead9c3f30..852f2dadaebd 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -220,7 +220,7 @@ static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos)  	win_data->enabled = true; -	DRM_DEBUG_KMS("dma_addr = 0x%x\n", win_data->dma_addr); +	DRM_DEBUG_KMS("dma_addr = %pad\n", &win_data->dma_addr);  	if (ctx->vblank_on)  		schedule_work(&ctx->work); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0905cd915589..108e1ec2fa4b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1308,6 +1308,7 @@ struct intel_vbt_data {  	struct {  		u16 pwm_freq_hz; +		bool present;  		bool active_low_pwm;  	} backlight; @@ -1953,6 +1954,9 @@ struct drm_i915_cmd_table {  #define IS_ULT(dev)		(IS_HSW_ULT(dev) || IS_BDW_ULT(dev))  #define IS_HSW_GT3(dev)		(IS_HASWELL(dev) && \  				 ((dev)->pdev->device & 0x00F0) == 0x0020) +/* ULX machines are also considered ULT. */ +#define IS_HSW_ULX(dev)		((dev)->pdev->device == 0x0A0E || \ +				 (dev)->pdev->device == 0x0A1E)  #define IS_PRELIMINARY_HW(intel_info) ((intel_info)->is_preliminary)  /* @@ -2431,20 +2435,18 @@ int i915_gem_context_open(struct drm_device *dev, struct drm_file *file);  int i915_gem_context_enable(struct drm_i915_private *dev_priv);  void i915_gem_context_close(struct drm_device *dev, struct drm_file *file);  int i915_switch_context(struct intel_ring_buffer *ring, -			struct drm_file *file, struct i915_hw_context *to); +			struct i915_hw_context *to);  struct i915_hw_context *  i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id);  void i915_gem_context_free(struct kref *ctx_ref);  static inline void i915_gem_context_reference(struct i915_hw_context *ctx)  { -	if (ctx->obj && HAS_HW_CONTEXTS(ctx->obj->base.dev)) -		kref_get(&ctx->ref); +	kref_get(&ctx->ref);  }  static inline void i915_gem_context_unreference(struct i915_hw_context *ctx)  { -	if (ctx->obj && HAS_HW_CONTEXTS(ctx->obj->base.dev)) -		kref_put(&ctx->ref, i915_gem_context_free); +	kref_put(&ctx->ref, i915_gem_context_free);  }  static inline bool i915_gem_context_is_default(const struct i915_hw_context *c) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 6370a761d137..2871ce75f438 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2790,7 +2790,7 @@ int i915_gpu_idle(struct drm_device *dev)  	/* Flush everything onto the inactive list. */  	for_each_ring(ring, dev_priv, i) { -		ret = i915_switch_context(ring, NULL, ring->default_context); +		ret = i915_switch_context(ring, ring->default_context);  		if (ret)  			return ret; diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 6043062ffce7..d72db15afa02 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -96,9 +96,6 @@  #define GEN6_CONTEXT_ALIGN (64<<10)  #define GEN7_CONTEXT_ALIGN 4096 -static int do_switch(struct intel_ring_buffer *ring, -		     struct i915_hw_context *to); -  static void do_ppgtt_cleanup(struct i915_hw_ppgtt *ppgtt)  {  	struct drm_device *dev = ppgtt->base.dev; @@ -185,13 +182,15 @@ void i915_gem_context_free(struct kref *ctx_ref)  						   typeof(*ctx), ref);  	struct i915_hw_ppgtt *ppgtt = NULL; -	/* We refcount even the aliasing PPGTT to keep the code symmetric */ -	if (USES_PPGTT(ctx->obj->base.dev)) -		ppgtt = ctx_to_ppgtt(ctx); +	if (ctx->obj) { +		/* We refcount even the aliasing PPGTT to keep the code symmetric */ +		if (USES_PPGTT(ctx->obj->base.dev)) +			ppgtt = ctx_to_ppgtt(ctx); -	/* XXX: Free up the object before tearing down the address space, in -	 * case we're bound in the PPGTT */ -	drm_gem_object_unreference(&ctx->obj->base); +		/* XXX: Free up the object before tearing down the address space, in +		 * case we're bound in the PPGTT */ +		drm_gem_object_unreference(&ctx->obj->base); +	}  	if (ppgtt)  		kref_put(&ppgtt->ref, ppgtt_release); @@ -232,32 +231,32 @@ __create_hw_context(struct drm_device *dev,  		return ERR_PTR(-ENOMEM);  	kref_init(&ctx->ref); -	ctx->obj = i915_gem_alloc_object(dev, dev_priv->hw_context_size); -	INIT_LIST_HEAD(&ctx->link); -	if (ctx->obj == NULL) { -		kfree(ctx); -		DRM_DEBUG_DRIVER("Context object allocated failed\n"); -		return ERR_PTR(-ENOMEM); -	} +	list_add_tail(&ctx->link, &dev_priv->context_list); -	if (INTEL_INFO(dev)->gen >= 7) { -		ret = i915_gem_object_set_cache_level(ctx->obj, -						      I915_CACHE_L3_LLC); -		/* Failure shouldn't ever happen this early */ -		if (WARN_ON(ret)) +	if (dev_priv->hw_context_size) { +		ctx->obj = i915_gem_alloc_object(dev, dev_priv->hw_context_size); +		if (ctx->obj == NULL) { +			ret = -ENOMEM;  			goto err_out; -	} +		} -	list_add_tail(&ctx->link, &dev_priv->context_list); +		if (INTEL_INFO(dev)->gen >= 7) { +			ret = i915_gem_object_set_cache_level(ctx->obj, +							      I915_CACHE_L3_LLC); +			/* Failure shouldn't ever happen this early */ +			if (WARN_ON(ret)) +				goto err_out; +		} +	}  	/* Default context will never have a file_priv */ -	if (file_priv == NULL) -		return ctx; - -	ret = idr_alloc(&file_priv->context_idr, ctx, DEFAULT_CONTEXT_ID, 0, -			GFP_KERNEL); -	if (ret < 0) -		goto err_out; +	if (file_priv != NULL) { +		ret = idr_alloc(&file_priv->context_idr, ctx, +				DEFAULT_CONTEXT_ID, 0, GFP_KERNEL); +		if (ret < 0) +			goto err_out; +	} else +		ret = DEFAULT_CONTEXT_ID;  	ctx->file_priv = file_priv;  	ctx->id = ret; @@ -294,7 +293,7 @@ i915_gem_create_context(struct drm_device *dev,  	if (IS_ERR(ctx))  		return ctx; -	if (is_global_default_ctx) { +	if (is_global_default_ctx && ctx->obj) {  		/* We may need to do things with the shrinker which  		 * require us to immediately switch back to the default  		 * context. This can cause a problem as pinning the @@ -342,7 +341,7 @@ i915_gem_create_context(struct drm_device *dev,  	return ctx;  err_unpin: -	if (is_global_default_ctx) +	if (is_global_default_ctx && ctx->obj)  		i915_gem_object_ggtt_unpin(ctx->obj);  err_destroy:  	i915_gem_context_unreference(ctx); @@ -352,32 +351,22 @@ err_destroy:  void i915_gem_context_reset(struct drm_device *dev)  {  	struct drm_i915_private *dev_priv = dev->dev_private; -	struct intel_ring_buffer *ring;  	int i; -	if (!HAS_HW_CONTEXTS(dev)) -		return; -  	/* Prevent the hardware from restoring the last context (which hung) on  	 * the next switch */  	for (i = 0; i < I915_NUM_RINGS; i++) { -		struct i915_hw_context *dctx; -		if (!(INTEL_INFO(dev)->ring_mask & (1<<i))) -			continue; +		struct intel_ring_buffer *ring = &dev_priv->ring[i]; +		struct i915_hw_context *dctx = ring->default_context;  		/* Do a fake switch to the default context */ -		ring = &dev_priv->ring[i]; -		dctx = ring->default_context; -		if (WARN_ON(!dctx)) +		if (ring->last_context == dctx)  			continue;  		if (!ring->last_context)  			continue; -		if (ring->last_context == dctx) -			continue; - -		if (i == RCS) { +		if (dctx->obj && i == RCS) {  			WARN_ON(i915_gem_obj_ggtt_pin(dctx->obj,  						      get_context_alignment(dev), 0));  			/* Fake a finish/inactive */ @@ -394,44 +383,35 @@ void i915_gem_context_reset(struct drm_device *dev)  int i915_gem_context_init(struct drm_device *dev)  {  	struct drm_i915_private *dev_priv = dev->dev_private; -	struct intel_ring_buffer *ring; +	struct i915_hw_context *ctx;  	int i; -	if (!HAS_HW_CONTEXTS(dev)) -		return 0; -  	/* Init should only be called once per module load. Eventually the  	 * restriction on the context_disabled check can be loosened. */  	if (WARN_ON(dev_priv->ring[RCS].default_context))  		return 0; -	dev_priv->hw_context_size = round_up(get_context_size(dev), 4096); - -	if (dev_priv->hw_context_size > (1<<20)) { -		DRM_DEBUG_DRIVER("Disabling HW Contexts; invalid size\n"); -		return -E2BIG; +	if (HAS_HW_CONTEXTS(dev)) { +		dev_priv->hw_context_size = round_up(get_context_size(dev), 4096); +		if (dev_priv->hw_context_size > (1<<20)) { +			DRM_DEBUG_DRIVER("Disabling HW Contexts; invalid size %d\n", +					 dev_priv->hw_context_size); +			dev_priv->hw_context_size = 0; +		}  	} -	dev_priv->ring[RCS].default_context = -		i915_gem_create_context(dev, NULL, USES_PPGTT(dev)); - -	if (IS_ERR_OR_NULL(dev_priv->ring[RCS].default_context)) { -		DRM_DEBUG_DRIVER("Disabling HW Contexts; create failed %ld\n", -				 PTR_ERR(dev_priv->ring[RCS].default_context)); -		return PTR_ERR(dev_priv->ring[RCS].default_context); +	ctx = i915_gem_create_context(dev, NULL, USES_PPGTT(dev)); +	if (IS_ERR(ctx)) { +		DRM_ERROR("Failed to create default global context (error %ld)\n", +			  PTR_ERR(ctx)); +		return PTR_ERR(ctx);  	} -	for (i = RCS + 1; i < I915_NUM_RINGS; i++) { -		if (!(INTEL_INFO(dev)->ring_mask & (1<<i))) -			continue; - -		ring = &dev_priv->ring[i]; +	/* NB: RCS will hold a ref for all rings */ +	for (i = 0; i < I915_NUM_RINGS; i++) +		dev_priv->ring[i].default_context = ctx; -		/* NB: RCS will hold a ref for all rings */ -		ring->default_context = dev_priv->ring[RCS].default_context; -	} - -	DRM_DEBUG_DRIVER("HW context support initialized\n"); +	DRM_DEBUG_DRIVER("%s context support initialized\n", dev_priv->hw_context_size ? "HW" : "fake");  	return 0;  } @@ -441,33 +421,30 @@ void i915_gem_context_fini(struct drm_device *dev)  	struct i915_hw_context *dctx = dev_priv->ring[RCS].default_context;  	int i; -	if (!HAS_HW_CONTEXTS(dev)) -		return; - -	/* The only known way to stop the gpu from accessing the hw context is -	 * to reset it. Do this as the very last operation to avoid confusing -	 * other code, leading to spurious errors. */ -	intel_gpu_reset(dev); +	if (dctx->obj) { +		/* The only known way to stop the gpu from accessing the hw context is +		 * to reset it. Do this as the very last operation to avoid confusing +		 * other code, leading to spurious errors. */ +		intel_gpu_reset(dev); -	/* When default context is created and switched to, base object refcount -	 * will be 2 (+1 from object creation and +1 from do_switch()). -	 * i915_gem_context_fini() will be called after gpu_idle() has switched -	 * to default context. So we need to unreference the base object once -	 * to offset the do_switch part, so that i915_gem_context_unreference() -	 * can then free the base object correctly. */ -	WARN_ON(!dev_priv->ring[RCS].last_context); -	if (dev_priv->ring[RCS].last_context == dctx) { -		/* Fake switch to NULL context */ -		WARN_ON(dctx->obj->active); -		i915_gem_object_ggtt_unpin(dctx->obj); -		i915_gem_context_unreference(dctx); -		dev_priv->ring[RCS].last_context = NULL; +		/* When default context is created and switched to, base object refcount +		 * will be 2 (+1 from object creation and +1 from do_switch()). +		 * i915_gem_context_fini() will be called after gpu_idle() has switched +		 * to default context. So we need to unreference the base object once +		 * to offset the do_switch part, so that i915_gem_context_unreference() +		 * can then free the base object correctly. */ +		WARN_ON(!dev_priv->ring[RCS].last_context); +		if (dev_priv->ring[RCS].last_context == dctx) { +			/* Fake switch to NULL context */ +			WARN_ON(dctx->obj->active); +			i915_gem_object_ggtt_unpin(dctx->obj); +			i915_gem_context_unreference(dctx); +			dev_priv->ring[RCS].last_context = NULL; +		}  	}  	for (i = 0; i < I915_NUM_RINGS; i++) {  		struct intel_ring_buffer *ring = &dev_priv->ring[i]; -		if (!(INTEL_INFO(dev)->ring_mask & (1<<i))) -			continue;  		if (ring->last_context)  			i915_gem_context_unreference(ring->last_context); @@ -478,7 +455,6 @@ void i915_gem_context_fini(struct drm_device *dev)  	i915_gem_object_ggtt_unpin(dctx->obj);  	i915_gem_context_unreference(dctx); -	dev_priv->mm.aliasing_ppgtt = NULL;  }  int i915_gem_context_enable(struct drm_i915_private *dev_priv) @@ -486,9 +462,6 @@ int i915_gem_context_enable(struct drm_i915_private *dev_priv)  	struct intel_ring_buffer *ring;  	int ret, i; -	if (!HAS_HW_CONTEXTS(dev_priv->dev)) -		return 0; -  	/* This is the only place the aliasing PPGTT gets enabled, which means  	 * it has to happen before we bail on reset */  	if (dev_priv->mm.aliasing_ppgtt) { @@ -503,7 +476,7 @@ int i915_gem_context_enable(struct drm_i915_private *dev_priv)  	BUG_ON(!dev_priv->ring[RCS].default_context);  	for_each_ring(ring, dev_priv, i) { -		ret = do_switch(ring, ring->default_context); +		ret = i915_switch_context(ring, ring->default_context);  		if (ret)  			return ret;  	} @@ -526,19 +499,6 @@ static int context_idr_cleanup(int id, void *p, void *data)  int i915_gem_context_open(struct drm_device *dev, struct drm_file *file)  {  	struct drm_i915_file_private *file_priv = file->driver_priv; -	struct drm_i915_private *dev_priv = dev->dev_private; - -	if (!HAS_HW_CONTEXTS(dev)) { -		/* Cheat for hang stats */ -		file_priv->private_default_ctx = -			kzalloc(sizeof(struct i915_hw_context), GFP_KERNEL); - -		if (file_priv->private_default_ctx == NULL) -			return -ENOMEM; - -		file_priv->private_default_ctx->vm = &dev_priv->gtt.base; -		return 0; -	}  	idr_init(&file_priv->context_idr); @@ -559,14 +519,10 @@ void i915_gem_context_close(struct drm_device *dev, struct drm_file *file)  {  	struct drm_i915_file_private *file_priv = file->driver_priv; -	if (!HAS_HW_CONTEXTS(dev)) { -		kfree(file_priv->private_default_ctx); -		return; -	} -  	idr_for_each(&file_priv->context_idr, context_idr_cleanup, NULL); -	i915_gem_context_unreference(file_priv->private_default_ctx);  	idr_destroy(&file_priv->context_idr); + +	i915_gem_context_unreference(file_priv->private_default_ctx);  }  struct i915_hw_context * @@ -574,9 +530,6 @@ i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id)  {  	struct i915_hw_context *ctx; -	if (!HAS_HW_CONTEXTS(file_priv->dev_priv->dev)) -		return file_priv->private_default_ctx; -  	ctx = (struct i915_hw_context *)idr_find(&file_priv->context_idr, id);  	if (!ctx)  		return ERR_PTR(-ENOENT); @@ -758,7 +711,6 @@ unpin_out:  /**   * i915_switch_context() - perform a GPU context switch.   * @ring: ring for which we'll execute the context switch - * @file_priv: file_priv associated with the context, may be NULL   * @to: the context to switch to   *   * The context life cycle is simple. The context refcount is incremented and @@ -767,24 +719,30 @@ unpin_out:   * object while letting the normal object tracking destroy the backing BO.   */  int i915_switch_context(struct intel_ring_buffer *ring, -			struct drm_file *file,  			struct i915_hw_context *to)  {  	struct drm_i915_private *dev_priv = ring->dev->dev_private;  	WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); -	BUG_ON(file && to == NULL); - -	/* We have the fake context */ -	if (!HAS_HW_CONTEXTS(ring->dev)) { -		ring->last_context = to; +	if (to->obj == NULL) { /* We have the fake context */ +		if (to != ring->last_context) { +			i915_gem_context_reference(to); +			if (ring->last_context) +				i915_gem_context_unreference(ring->last_context); +			ring->last_context = to; +		}  		return 0;  	}  	return do_switch(ring, to);  } +static bool hw_context_enabled(struct drm_device *dev) +{ +	return to_i915(dev)->hw_context_size; +} +  int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,  				  struct drm_file *file)  { @@ -793,7 +751,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,  	struct i915_hw_context *ctx;  	int ret; -	if (!HAS_HW_CONTEXTS(dev)) +	if (!hw_context_enabled(dev))  		return -ENODEV;  	ret = i915_mutex_lock_interruptible(dev); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 7447160155a3..2c9d9cbaf653 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1221,7 +1221,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,  	if (ret)  		goto err; -	ret = i915_switch_context(ring, file, ctx); +	ret = i915_switch_context(ring, ctx);  	if (ret)  		goto err; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index ab5e93c30aa2..154b0f8bb88d 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -34,25 +34,35 @@ static void gen8_setup_private_ppat(struct drm_i915_private *dev_priv);  bool intel_enable_ppgtt(struct drm_device *dev, bool full)  { -	if (i915.enable_ppgtt == 0 || !HAS_ALIASING_PPGTT(dev)) +	if (i915.enable_ppgtt == 0)  		return false;  	if (i915.enable_ppgtt == 1 && full)  		return false; +	return true; +} + +static int sanitize_enable_ppgtt(struct drm_device *dev, int enable_ppgtt) +{ +	if (enable_ppgtt == 0 || !HAS_ALIASING_PPGTT(dev)) +		return 0; + +	if (enable_ppgtt == 1) +		return 1; + +	if (enable_ppgtt == 2 && HAS_PPGTT(dev)) +		return 2; +  #ifdef CONFIG_INTEL_IOMMU  	/* Disable ppgtt on SNB if VT-d is on. */  	if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped) {  		DRM_INFO("Disabling PPGTT because VT-d is on\n"); -		return false; +		return 0;  	}  #endif -	/* Full ppgtt disabled by default for now due to issues. */ -	if (full) -		return false; /* HAS_PPGTT(dev) */ -	else -		return HAS_ALIASING_PPGTT(dev); +	return HAS_ALIASING_PPGTT(dev) ? 1 : 0;  }  #define GEN6_PPGTT_PD_ENTRIES 512 @@ -2031,6 +2041,14 @@ int i915_gem_gtt_init(struct drm_device *dev)  		 gtt->base.total >> 20);  	DRM_DEBUG_DRIVER("GMADR size = %ldM\n", gtt->mappable_end >> 20);  	DRM_DEBUG_DRIVER("GTT stolen size = %zdM\n", gtt->stolen_size >> 20); +	/* +	 * i915.enable_ppgtt is read-only, so do an early pass to validate the +	 * user's requested state against the hardware/driver capabilities.  We +	 * do this now so that we can print out any log messages once rather +	 * than every time we check intel_enable_ppgtt(). +	 */ +	i915.enable_ppgtt = sanitize_enable_ppgtt(dev, i915.enable_ppgtt); +	DRM_DEBUG_DRIVER("ppgtt mode: %i\n", i915.enable_ppgtt);  	return 0;  } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 7753249b3a95..f98ba4e6e70b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1362,10 +1362,20 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,  	spin_lock(&dev_priv->irq_lock);  	for (i = 1; i < HPD_NUM_PINS; i++) { -		WARN_ONCE(hpd[i] & hotplug_trigger && -			  dev_priv->hpd_stats[i].hpd_mark == HPD_DISABLED, -			  "Received HPD interrupt (0x%08x) on pin %d (0x%08x) although disabled\n", -			  hotplug_trigger, i, hpd[i]); +		if (hpd[i] & hotplug_trigger && +		    dev_priv->hpd_stats[i].hpd_mark == HPD_DISABLED) { +			/* +			 * On GMCH platforms the interrupt mask bits only +			 * prevent irq generation, not the setting of the +			 * hotplug bits itself. So only WARN about unexpected +			 * interrupts on saner platforms. +			 */ +			WARN_ONCE(INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev), +				  "Received HPD interrupt (0x%08x) on pin %d (0x%08x) although disabled\n", +				  hotplug_trigger, i, hpd[i]); + +			continue; +		}  		if (!(hpd[i] & hotplug_trigger) ||  		    dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 9f5b18d9d885..c77af69c2d8f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -827,6 +827,7 @@ enum punit_power_well {  # define MI_FLUSH_ENABLE				(1 << 12)  # define ASYNC_FLIP_PERF_DISABLE			(1 << 14)  # define MODE_IDLE					(1 << 9) +# define STOP_RING					(1 << 8)  #define GEN6_GT_MODE	0x20d0  #define GEN7_GT_MODE	0x7008 diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 4867f4cc0938..fa486c5fbb02 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -287,6 +287,9 @@ parse_lfp_backlight(struct drm_i915_private *dev_priv, struct bdb_header *bdb)  	const struct bdb_lfp_backlight_data *backlight_data;  	const struct bdb_lfp_backlight_data_entry *entry; +	/* Err to enabling backlight if no backlight block. */ +	dev_priv->vbt.backlight.present = true; +  	backlight_data = find_section(bdb, BDB_LVDS_BACKLIGHT);  	if (!backlight_data)  		return; @@ -299,6 +302,13 @@ parse_lfp_backlight(struct drm_i915_private *dev_priv, struct bdb_header *bdb)  	entry = &backlight_data->data[panel_type]; +	dev_priv->vbt.backlight.present = entry->type == BDB_BACKLIGHT_TYPE_PWM; +	if (!dev_priv->vbt.backlight.present) { +		DRM_DEBUG_KMS("PWM backlight not present in VBT (type %u)\n", +			      entry->type); +		return; +	} +  	dev_priv->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz;  	dev_priv->vbt.backlight.active_low_pwm = entry->active_low_pwm;  	DRM_DEBUG_KMS("VBT backlight PWM modulation frequency %u Hz, " diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index 83b7629e4367..f27f7b282465 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -374,6 +374,9 @@ struct bdb_lvds_lfp_data {  	struct bdb_lvds_lfp_data_entry data[16];  } __packed; +#define BDB_BACKLIGHT_TYPE_NONE	0 +#define BDB_BACKLIGHT_TYPE_PWM	2 +  struct bdb_lfp_backlight_data_entry {  	u8 type:2;  	u8 active_low_pwm:1; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index dae976f51d83..48aa516a1ac0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9654,11 +9654,22 @@ intel_pipe_config_compare(struct drm_device *dev,  	PIPE_CONF_CHECK_I(pipe_src_w);  	PIPE_CONF_CHECK_I(pipe_src_h); -	PIPE_CONF_CHECK_I(gmch_pfit.control); -	/* pfit ratios are autocomputed by the hw on gen4+ */ -	if (INTEL_INFO(dev)->gen < 4) -		PIPE_CONF_CHECK_I(gmch_pfit.pgm_ratios); -	PIPE_CONF_CHECK_I(gmch_pfit.lvds_border_bits); +	/* +	 * FIXME: BIOS likes to set up a cloned config with lvds+external +	 * screen. Since we don't yet re-compute the pipe config when moving +	 * just the lvds port away to another pipe the sw tracking won't match. +	 * +	 * Proper atomic modesets with recomputed global state will fix this. +	 * Until then just don't check gmch state for inherited modes. +	 */ +	if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_INHERITED_MODE)) { +		PIPE_CONF_CHECK_I(gmch_pfit.control); +		/* pfit ratios are autocomputed by the hw on gen4+ */ +		if (INTEL_INFO(dev)->gen < 4) +			PIPE_CONF_CHECK_I(gmch_pfit.pgm_ratios); +		PIPE_CONF_CHECK_I(gmch_pfit.lvds_border_bits); +	} +  	PIPE_CONF_CHECK_I(pch_pfit.enabled);  	if (current_config->pch_pfit.enabled) {  		PIPE_CONF_CHECK_I(pch_pfit.pos); @@ -11384,15 +11395,6 @@ void intel_modeset_init(struct drm_device *dev)  	}  } -static void -intel_connector_break_all_links(struct intel_connector *connector) -{ -	connector->base.dpms = DRM_MODE_DPMS_OFF; -	connector->base.encoder = NULL; -	connector->encoder->connectors_active = false; -	connector->encoder->base.crtc = NULL; -} -  static void intel_enable_pipe_a(struct drm_device *dev)  {  	struct intel_connector *connector; @@ -11474,8 +11476,17 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)  			if (connector->encoder->base.crtc != &crtc->base)  				continue; -			intel_connector_break_all_links(connector); +			connector->base.dpms = DRM_MODE_DPMS_OFF; +			connector->base.encoder = NULL;  		} +		/* multiple connectors may have the same encoder: +		 *  handle them and break crtc link separately */ +		list_for_each_entry(connector, &dev->mode_config.connector_list, +				    base.head) +			if (connector->encoder->base.crtc == &crtc->base) { +				connector->encoder->base.crtc = NULL; +				connector->encoder->connectors_active = false; +			}  		WARN_ON(crtc->active);  		crtc->base.enabled = false; @@ -11557,6 +11568,8 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder)  				      drm_get_encoder_name(&encoder->base));  			encoder->disable(encoder);  		} +		encoder->base.crtc = NULL; +		encoder->connectors_active = false;  		/* Inconsistent output/port/pipe state happens presumably due to  		 * a bug in one of the get_hw_state functions. Or someplace else @@ -11567,8 +11580,8 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder)  				    base.head) {  			if (connector->encoder != encoder)  				continue; - -			intel_connector_break_all_links(connector); +			connector->base.dpms = DRM_MODE_DPMS_OFF; +			connector->base.encoder = NULL;  		}  	}  	/* Enabled encoders without active connectors will be fixed in @@ -11616,6 +11629,8 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)  			    base.head) {  		memset(&crtc->config, 0, sizeof(crtc->config)); +		crtc->config.quirks |= PIPE_CONFIG_QUIRK_INHERITED_MODE; +  		crtc->active = dev_priv->display.get_pipe_config(crtc,  								 &crtc->config); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index a0dad1a2f819..5ca68aa9f237 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -105,7 +105,8 @@ intel_dp_max_link_bw(struct intel_dp *intel_dp)  	case DP_LINK_BW_2_7:  		break;  	case DP_LINK_BW_5_4: /* 1.2 capable displays may advertise higher bw */ -		if ((IS_HASWELL(dev) || INTEL_INFO(dev)->gen >= 8) && +		if (((IS_HASWELL(dev) && !IS_HSW_ULX(dev)) || +		     INTEL_INFO(dev)->gen >= 8) &&  		    intel_dp->dpcd[DP_DPCD_REV] >= 0x12)  			max_link_bw = DP_LINK_BW_5_4;  		else @@ -575,7 +576,8 @@ out:  	return ret;  } -#define HEADER_SIZE	4 +#define BARE_ADDRESS_SIZE	3 +#define HEADER_SIZE		(BARE_ADDRESS_SIZE + 1)  static ssize_t  intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)  { @@ -592,7 +594,7 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)  	switch (msg->request & ~DP_AUX_I2C_MOT) {  	case DP_AUX_NATIVE_WRITE:  	case DP_AUX_I2C_WRITE: -		txsize = HEADER_SIZE + msg->size; +		txsize = msg->size ? HEADER_SIZE + msg->size : BARE_ADDRESS_SIZE;  		rxsize = 1;  		if (WARN_ON(txsize > 20)) @@ -611,7 +613,7 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)  	case DP_AUX_NATIVE_READ:  	case DP_AUX_I2C_READ: -		txsize = HEADER_SIZE; +		txsize = msg->size ? HEADER_SIZE : BARE_ADDRESS_SIZE;  		rxsize = msg->size + 1;  		if (WARN_ON(rxsize > 20)) @@ -3618,7 +3620,8 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,  {  	struct drm_connector *connector = &intel_connector->base;  	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); -	struct drm_device *dev = intel_dig_port->base.base.dev; +	struct intel_encoder *intel_encoder = &intel_dig_port->base; +	struct drm_device *dev = intel_encoder->base.dev;  	struct drm_i915_private *dev_priv = dev->dev_private;  	struct drm_display_mode *fixed_mode = NULL;  	bool has_dpcd; @@ -3628,6 +3631,14 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,  	if (!is_edp(intel_dp))  		return true; +	/* The VDD bit needs a power domain reference, so if the bit is already +	 * enabled when we boot, grab this reference. */ +	if (edp_have_panel_vdd(intel_dp)) { +		enum intel_display_power_domain power_domain; +		power_domain = intel_display_port_power_domain(intel_encoder); +		intel_display_power_get(dev_priv, power_domain); +	} +  	/* Cache DPCD and EDID for edp. */  	intel_edp_panel_vdd_on(intel_dp);  	has_dpcd = intel_dp_get_dpcd(intel_dp); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 0542de982260..328b1a70264b 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -236,7 +236,8 @@ struct intel_crtc_config {  	 * tracked with quirk flags so that fastboot and state checker can act  	 * accordingly.  	 */ -#define PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS (1<<0) /* unreliable sync mode.flags */ +#define PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS	(1<<0) /* unreliable sync mode.flags */ +#define PIPE_CONFIG_QUIRK_INHERITED_MODE	(1<<1) /* mode inherited from firmware */  	unsigned long quirks;  	/* User requested mode, only valid as a starting point to diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index b4d44e62f0c7..fce4a0d93c0b 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -132,6 +132,16 @@ static int intelfb_create(struct drm_fb_helper *helper,  	mutex_lock(&dev->struct_mutex); +	if (intel_fb && +	    (sizes->fb_width > intel_fb->base.width || +	     sizes->fb_height > intel_fb->base.height)) { +		DRM_DEBUG_KMS("BIOS fb too small (%dx%d), we require (%dx%d)," +			      " releasing it\n", +			      intel_fb->base.width, intel_fb->base.height, +			      sizes->fb_width, sizes->fb_height); +		drm_framebuffer_unreference(&intel_fb->base); +		intel_fb = ifbdev->fb = NULL; +	}  	if (!intel_fb || WARN_ON(!intel_fb->obj)) {  		DRM_DEBUG_KMS("no BIOS fb, allocating a new one\n");  		ret = intelfb_alloc(helper, sizes); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index b0413e190625..157267aa3561 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -821,11 +821,11 @@ static void intel_disable_hdmi(struct intel_encoder *encoder)  	}  } -static int hdmi_portclock_limit(struct intel_hdmi *hdmi) +static int hdmi_portclock_limit(struct intel_hdmi *hdmi, bool respect_dvi_limit)  {  	struct drm_device *dev = intel_hdmi_to_dev(hdmi); -	if (!hdmi->has_hdmi_sink || IS_G4X(dev)) +	if ((respect_dvi_limit && !hdmi->has_hdmi_sink) || IS_G4X(dev))  		return 165000;  	else if (IS_HASWELL(dev) || INTEL_INFO(dev)->gen >= 8)  		return 300000; @@ -837,7 +837,8 @@ static enum drm_mode_status  intel_hdmi_mode_valid(struct drm_connector *connector,  		      struct drm_display_mode *mode)  { -	if (mode->clock > hdmi_portclock_limit(intel_attached_hdmi(connector))) +	if (mode->clock > hdmi_portclock_limit(intel_attached_hdmi(connector), +					       true))  		return MODE_CLOCK_HIGH;  	if (mode->clock < 20000)  		return MODE_CLOCK_LOW; @@ -879,7 +880,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,  	struct drm_device *dev = encoder->base.dev;  	struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;  	int clock_12bpc = pipe_config->adjusted_mode.crtc_clock * 3 / 2; -	int portclock_limit = hdmi_portclock_limit(intel_hdmi); +	int portclock_limit = hdmi_portclock_limit(intel_hdmi, false);  	int desired_bpp;  	if (intel_hdmi->color_range_auto) { diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index cb058408c70e..0eead16aeda7 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -1065,6 +1065,11 @@ int intel_panel_setup_backlight(struct drm_connector *connector)  	unsigned long flags;  	int ret; +	if (!dev_priv->vbt.backlight.present) { +		DRM_DEBUG_KMS("native backlight control not available per VBT\n"); +		return 0; +	} +  	/* set level and max in panel struct */  	spin_lock_irqsave(&dev_priv->backlight_lock, flags);  	ret = dev_priv->display.setup_backlight(intel_connector); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 5874716774a7..19e94c3edc19 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1545,6 +1545,16 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)  	DRM_DEBUG_KMS("FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm); +	if (IS_I915GM(dev) && enabled) { +		struct intel_framebuffer *fb; + +		fb = to_intel_framebuffer(enabled->primary->fb); + +		/* self-refresh seems busted with untiled */ +		if (fb->obj->tiling_mode == I915_TILING_NONE) +			enabled = NULL; +	} +  	/*  	 * Overlay gets an aggressive default since video jitter is bad.  	 */ diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 6bc68bdcf433..79fb4cc2137c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -437,32 +437,41 @@ static void ring_setup_phys_status_page(struct intel_ring_buffer *ring)  	I915_WRITE(HWS_PGA, addr);  } -static int init_ring_common(struct intel_ring_buffer *ring) +static bool stop_ring(struct intel_ring_buffer *ring)  { -	struct drm_device *dev = ring->dev; -	struct drm_i915_private *dev_priv = dev->dev_private; -	struct drm_i915_gem_object *obj = ring->obj; -	int ret = 0; -	u32 head; +	struct drm_i915_private *dev_priv = to_i915(ring->dev); -	gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); +	if (!IS_GEN2(ring->dev)) { +		I915_WRITE_MODE(ring, _MASKED_BIT_ENABLE(STOP_RING)); +		if (wait_for_atomic((I915_READ_MODE(ring) & MODE_IDLE) != 0, 1000)) { +			DRM_ERROR("%s :timed out trying to stop ring\n", ring->name); +			return false; +		} +	} -	/* Stop the ring if it's running. */  	I915_WRITE_CTL(ring, 0);  	I915_WRITE_HEAD(ring, 0);  	ring->write_tail(ring, 0); -	if (wait_for_atomic((I915_READ_MODE(ring) & MODE_IDLE) != 0, 1000)) -		DRM_ERROR("%s :timed out trying to stop ring\n", ring->name); -	if (I915_NEED_GFX_HWS(dev)) -		intel_ring_setup_status_page(ring); -	else -		ring_setup_phys_status_page(ring); +	if (!IS_GEN2(ring->dev)) { +		(void)I915_READ_CTL(ring); +		I915_WRITE_MODE(ring, _MASKED_BIT_DISABLE(STOP_RING)); +	} -	head = I915_READ_HEAD(ring) & HEAD_ADDR; +	return (I915_READ_HEAD(ring) & HEAD_ADDR) == 0; +} -	/* G45 ring initialization fails to reset head to zero */ -	if (head != 0) { +static int init_ring_common(struct intel_ring_buffer *ring) +{ +	struct drm_device *dev = ring->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_i915_gem_object *obj = ring->obj; +	int ret = 0; + +	gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); + +	if (!stop_ring(ring)) { +		/* G45 ring initialization often fails to reset head to zero */  		DRM_DEBUG_KMS("%s head not reset to zero "  			      "ctl %08x head %08x tail %08x start %08x\n",  			      ring->name, @@ -471,9 +480,7 @@ static int init_ring_common(struct intel_ring_buffer *ring)  			      I915_READ_TAIL(ring),  			      I915_READ_START(ring)); -		I915_WRITE_HEAD(ring, 0); - -		if (I915_READ_HEAD(ring) & HEAD_ADDR) { +		if (!stop_ring(ring)) {  			DRM_ERROR("failed to set %s head to zero "  				  "ctl %08x head %08x tail %08x start %08x\n",  				  ring->name, @@ -481,9 +488,16 @@ static int init_ring_common(struct intel_ring_buffer *ring)  				  I915_READ_HEAD(ring),  				  I915_READ_TAIL(ring),  				  I915_READ_START(ring)); +			ret = -EIO; +			goto out;  		}  	} +	if (I915_NEED_GFX_HWS(dev)) +		intel_ring_setup_status_page(ring); +	else +		ring_setup_phys_status_page(ring); +  	/* Initialize the ring. This must happen _after_ we've cleared the ring  	 * registers with the above sequence (the readback of the HEAD registers  	 * also enforces ordering), otherwise the hw might lose the new ring diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 270a6a973438..2b91c4b4d34b 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -34,6 +34,7 @@ struct  intel_hw_status_page {  #define I915_WRITE_IMR(ring, val) I915_WRITE(RING_IMR((ring)->mmio_base), val)  #define I915_READ_MODE(ring) I915_READ(RING_MI_MODE((ring)->mmio_base)) +#define I915_WRITE_MODE(ring, val) I915_WRITE(RING_MI_MODE((ring)->mmio_base), val)  enum intel_ring_hangcheck_action {  	HANGCHECK_IDLE = 0, diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c index 3e6c0f3ed592..ef9957dbac94 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c @@ -510,9 +510,8 @@ static void update_cursor(struct drm_crtc *crtc)  					MDP4_DMA_CURSOR_BLEND_CONFIG_CURSOR_EN);  		} else {  			/* disable cursor: */ -			mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_BASE(dma), 0); -			mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_BLEND_CONFIG(dma), -					MDP4_DMA_CURSOR_BLEND_CONFIG_FORMAT(CURSOR_ARGB)); +			mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_BASE(dma), +					mdp4_kms->blank_cursor_iova);  		}  		/* and drop the iova ref + obj rev when done scanning out: */ @@ -574,11 +573,9 @@ static int mdp4_crtc_cursor_set(struct drm_crtc *crtc,  	if (old_bo) {  		/* drop our previous reference: */ -		msm_gem_put_iova(old_bo, mdp4_kms->id); -		drm_gem_object_unreference_unlocked(old_bo); +		drm_flip_work_queue(&mdp4_crtc->unref_cursor_work, old_bo);  	} -	crtc_flush(crtc);  	request_pending(crtc, PENDING_CURSOR);  	return 0; diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c index c740ccd1cc67..8edd531cb621 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c @@ -70,12 +70,12 @@ irqreturn_t mdp4_irq(struct msm_kms *kms)  	VERB("status=%08x", status); +	mdp_dispatch_irqs(mdp_kms, status); +  	for (id = 0; id < priv->num_crtcs; id++)  		if (status & mdp4_crtc_vblank(priv->crtcs[id]))  			drm_handle_vblank(dev, id); -	mdp_dispatch_irqs(mdp_kms, status); -  	return IRQ_HANDLED;  } diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c index 272e707c9487..0bb4faa17523 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c @@ -144,6 +144,10 @@ static void mdp4_preclose(struct msm_kms *kms, struct drm_file *file)  static void mdp4_destroy(struct msm_kms *kms)  {  	struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms)); +	if (mdp4_kms->blank_cursor_iova) +		msm_gem_put_iova(mdp4_kms->blank_cursor_bo, mdp4_kms->id); +	if (mdp4_kms->blank_cursor_bo) +		drm_gem_object_unreference(mdp4_kms->blank_cursor_bo);  	kfree(mdp4_kms);  } @@ -372,6 +376,23 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)  		goto fail;  	} +	mutex_lock(&dev->struct_mutex); +	mdp4_kms->blank_cursor_bo = msm_gem_new(dev, SZ_16K, MSM_BO_WC); +	mutex_unlock(&dev->struct_mutex); +	if (IS_ERR(mdp4_kms->blank_cursor_bo)) { +		ret = PTR_ERR(mdp4_kms->blank_cursor_bo); +		dev_err(dev->dev, "could not allocate blank-cursor bo: %d\n", ret); +		mdp4_kms->blank_cursor_bo = NULL; +		goto fail; +	} + +	ret = msm_gem_get_iova(mdp4_kms->blank_cursor_bo, mdp4_kms->id, +			&mdp4_kms->blank_cursor_iova); +	if (ret) { +		dev_err(dev->dev, "could not pin blank-cursor bo: %d\n", ret); +		goto fail; +	} +  	return kms;  fail: diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h index 66a4d31aec80..715520c54cde 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h @@ -44,6 +44,10 @@ struct mdp4_kms {  	struct clk *lut_clk;  	struct mdp_irq error_handler; + +	/* empty/blank cursor bo to use when cursor is "disabled" */ +	struct drm_gem_object *blank_cursor_bo; +	uint32_t blank_cursor_iova;  };  #define to_mdp4_kms(x) container_of(x, struct mdp4_kms, base) diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c index 353d494a497f..f2b985bc2adf 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c @@ -71,11 +71,11 @@ static void mdp5_irq_mdp(struct mdp_kms *mdp_kms)  	VERB("status=%08x", status); +	mdp_dispatch_irqs(mdp_kms, status); +  	for (id = 0; id < priv->num_crtcs; id++)  		if (status & mdp5_crtc_vblank(priv->crtcs[id]))  			drm_handle_vblank(dev, id); - -	mdp_dispatch_irqs(mdp_kms, status);  }  irqreturn_t mdp5_irq(struct msm_kms *kms) diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index 6c6d7d4c9b4e..a752ab83b810 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -62,11 +62,8 @@ static int msm_fbdev_create(struct drm_fb_helper *helper,  	dma_addr_t paddr;  	int ret, size; -	/* only doing ARGB32 since this is what is needed to alpha-blend -	 * with video overlays: -	 */  	sizes->surface_bpp = 32; -	sizes->surface_depth = 32; +	sizes->surface_depth = 24;  	DBG("create fbdev: %dx%d@%d (%dx%d)", sizes->surface_width,  			sizes->surface_height, sizes->surface_bpp, diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 3da8264d3039..bb8026daebc9 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -118,8 +118,10 @@ static void put_pages(struct drm_gem_object *obj)  		if (iommu_present(&platform_bus_type))  			drm_gem_put_pages(obj, msm_obj->pages, true, false); -		else +		else {  			drm_mm_remove_node(msm_obj->vram_node); +			drm_free_large(msm_obj->pages); +		}  		msm_obj->pages = NULL;  	} diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxgm107.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxgm107.c index 1dc37b1ddbfa..b0d0fb2f4d08 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxgm107.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxgm107.c @@ -863,7 +863,7 @@ gm107_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)  {  	mmio_data(0x003000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);  	mmio_data(0x008000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS); -	mmio_data(0x060000, 0x1000, NV_MEM_ACCESS_RW); +	mmio_data(0x200000, 0x1000, NV_MEM_ACCESS_RW);  	mmio_list(0x40800c, 0x00000000,  8, 1);  	mmio_list(0x408010, 0x80000000,  0, 0); @@ -877,6 +877,8 @@ gm107_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)  	mmio_list(0x418e24, 0x00000000,  8, 0);  	mmio_list(0x418e28, 0x80000030,  0, 0); +	mmio_list(0x4064c8, 0x018002c0,  0, 0); +  	mmio_list(0x418810, 0x80000000, 12, 2);  	mmio_list(0x419848, 0x10000000, 12, 2);  	mmio_list(0x419c2c, 0x10000000, 12, 2); diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c index e9df94f96d78..222e8ebb669d 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c @@ -109,7 +109,7 @@ nouveau_bios_shadow_pramin(struct nouveau_bios *bios)  			return;  		} -		addr = (u64)(addr >> 8) << 8; +		addr = (addr & 0xffffff00) << 8;  		if (!addr) {  			addr  = (u64)nv_rd32(bios, 0x001700) << 16;  			addr += 0xf0000; @@ -168,7 +168,8 @@ nouveau_bios_shadow_prom(struct nouveau_bios *bios)  	 */  	i = 16;  	do { -		if ((nv_rd32(bios, 0x300000) & 0xffff) == 0xaa55) +		u32 data = le32_to_cpu(nv_rd32(bios, 0x300000)) & 0xffff; +		if (data == 0xaa55)  			break;  	} while (i--); @@ -176,14 +177,15 @@ nouveau_bios_shadow_prom(struct nouveau_bios *bios)  		goto out;  	/* read entire bios image to system memory */ -	bios->size = ((nv_rd32(bios, 0x300000) >> 16) & 0xff) * 512; +	bios->size = (le32_to_cpu(nv_rd32(bios, 0x300000)) >> 16) & 0xff; +	bios->size = bios->size * 512;  	if (!bios->size)  		goto out;  	bios->data = kmalloc(bios->size, GFP_KERNEL);  	if (bios->data) { -		for (i = 0; i < bios->size; i+=4) -			nv_wo32(bios, i, nv_rd32(bios, 0x300000 + i)); +		for (i = 0; i < bios->size; i += 4) +			((u32 *)bios->data)[i/4] = nv_rd32(bios, 0x300000 + i);  	}  	/* check the PCI record header */ diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index 83face3f608f..279206997e5c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -389,9 +389,6 @@ bool nouveau_acpi_rom_supported(struct pci_dev *pdev)  	acpi_status status;  	acpi_handle dhandle, rom_handle; -	if (!nouveau_dsm_priv.dsm_detected && !nouveau_dsm_priv.optimus_detected) -		return false; -  	dhandle = ACPI_HANDLE(&pdev->dev);  	if (!dhandle)  		return false; diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 3ff030dc1ee3..da764a4ed958 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -764,9 +764,9 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,  	}  	ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence); -	mutex_unlock(&chan->cli->mutex);  	if (ret)  		goto fail_unreserve; +	mutex_unlock(&chan->cli->mutex);  	/* Update the crtc struct and cleanup */  	crtc->primary->fb = fb; diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 355157e4f78d..e3c47a8005ff 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -33,6 +33,7 @@ struct omap_crtc {  	int pipe;  	enum omap_channel channel;  	struct omap_overlay_manager_info info; +	struct drm_encoder *current_encoder;  	/*  	 * Temporary: eventually this will go away, but it is needed @@ -120,13 +121,25 @@ static void omap_crtc_start_update(struct omap_overlay_manager *mgr)  {  } +static void set_enabled(struct drm_crtc *crtc, bool enable); +  static int omap_crtc_enable(struct omap_overlay_manager *mgr)  { +	struct omap_crtc *omap_crtc = omap_crtcs[mgr->id]; + +	dispc_mgr_setup(omap_crtc->channel, &omap_crtc->info); +	dispc_mgr_set_timings(omap_crtc->channel, +			&omap_crtc->timings); +	set_enabled(&omap_crtc->base, true); +  	return 0;  }  static void omap_crtc_disable(struct omap_overlay_manager *mgr)  { +	struct omap_crtc *omap_crtc = omap_crtcs[mgr->id]; + +	set_enabled(&omap_crtc->base, false);  }  static void omap_crtc_set_timings(struct omap_overlay_manager *mgr, @@ -184,7 +197,6 @@ static void omap_crtc_destroy(struct drm_crtc *crtc)  	WARN_ON(omap_crtc->apply_irq.registered);  	omap_irq_unregister(crtc->dev, &omap_crtc->error_irq); -	omap_crtc->plane->funcs->destroy(omap_crtc->plane);  	drm_crtc_cleanup(crtc);  	kfree(omap_crtc); @@ -338,17 +350,23 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,  	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);  	struct drm_plane *primary = crtc->primary;  	struct drm_gem_object *bo; +	unsigned long flags;  	DBG("%d -> %d (event=%p)", primary->fb ? primary->fb->base.id : -1,  			fb->base.id, event); +	spin_lock_irqsave(&dev->event_lock, flags); +  	if (omap_crtc->old_fb) { +		spin_unlock_irqrestore(&dev->event_lock, flags);  		dev_err(dev->dev, "already a pending flip\n");  		return -EINVAL;  	}  	omap_crtc->event = event; -	primary->fb = fb; +	omap_crtc->old_fb = primary->fb = fb; + +	spin_unlock_irqrestore(&dev->event_lock, flags);  	/*  	 * Hold a reference temporarily until the crtc is updated @@ -528,38 +546,46 @@ static void set_enabled(struct drm_crtc *crtc, bool enable)  	struct drm_device *dev = crtc->dev;  	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);  	enum omap_channel channel = omap_crtc->channel; -	struct omap_irq_wait *wait = NULL; +	struct omap_irq_wait *wait; +	u32 framedone_irq, vsync_irq; +	int ret;  	if (dispc_mgr_is_enabled(channel) == enable)  		return; -	/* ignore sync-lost irqs during enable/disable */ +	/* +	 * Digit output produces some sync lost interrupts during the first +	 * frame when enabling, so we need to ignore those. +	 */  	omap_irq_unregister(crtc->dev, &omap_crtc->error_irq); -	if (dispc_mgr_get_framedone_irq(channel)) { -		if (!enable) { -			wait = omap_irq_wait_init(dev, -					dispc_mgr_get_framedone_irq(channel), 1); -		} +	framedone_irq = dispc_mgr_get_framedone_irq(channel); +	vsync_irq = dispc_mgr_get_vsync_irq(channel); + +	if (enable) { +		wait = omap_irq_wait_init(dev, vsync_irq, 1);  	} else {  		/* -		 * When we disable digit output, we need to wait until fields -		 * are done.  Otherwise the DSS is still working, and turning -		 * off the clocks prevents DSS from going to OFF mode. And when -		 * enabling, we need to wait for the extra sync losts +		 * When we disable the digit output, we need to wait for +		 * FRAMEDONE to know that DISPC has finished with the output. +		 * +		 * OMAP2/3 does not have FRAMEDONE irq for digit output, and in +		 * that case we need to use vsync interrupt, and wait for both +		 * even and odd frames.  		 */ -		wait = omap_irq_wait_init(dev, -				dispc_mgr_get_vsync_irq(channel), 2); + +		if (framedone_irq) +			wait = omap_irq_wait_init(dev, framedone_irq, 1); +		else +			wait = omap_irq_wait_init(dev, vsync_irq, 2);  	}  	dispc_mgr_enable(channel, enable); -	if (wait) { -		int ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100)); -		if (ret) { -			dev_err(dev->dev, "%s: timeout waiting for %s\n", -					omap_crtc->name, enable ? "enable" : "disable"); -		} +	ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100)); +	if (ret) { +		dev_err(dev->dev, "%s: timeout waiting for %s\n", +				omap_crtc->name, enable ? "enable" : "disable");  	}  	omap_irq_register(crtc->dev, &omap_crtc->error_irq); @@ -586,8 +612,12 @@ static void omap_crtc_pre_apply(struct omap_drm_apply *apply)  		}  	} +	if (omap_crtc->current_encoder && encoder != omap_crtc->current_encoder) +		omap_encoder_set_enabled(omap_crtc->current_encoder, false); + +	omap_crtc->current_encoder = encoder; +  	if (!omap_crtc->enabled) { -		set_enabled(&omap_crtc->base, false);  		if (encoder)  			omap_encoder_set_enabled(encoder, false);  	} else { @@ -596,13 +626,7 @@ static void omap_crtc_pre_apply(struct omap_drm_apply *apply)  			omap_encoder_update(encoder, omap_crtc->mgr,  					&omap_crtc->timings);  			omap_encoder_set_enabled(encoder, true); -			omap_crtc->full_update = false;  		} - -		dispc_mgr_setup(omap_crtc->channel, &omap_crtc->info); -		dispc_mgr_set_timings(omap_crtc->channel, -				&omap_crtc->timings); -		set_enabled(&omap_crtc->base, true);  	}  	omap_crtc->full_update = false; @@ -613,10 +637,30 @@ static void omap_crtc_post_apply(struct omap_drm_apply *apply)  	/* nothing needed for post-apply */  } +void omap_crtc_flush(struct drm_crtc *crtc) +{ +	struct omap_crtc *omap_crtc = to_omap_crtc(crtc); +	int loops = 0; + +	while (!list_empty(&omap_crtc->pending_applies) || +		!list_empty(&omap_crtc->queued_applies) || +		omap_crtc->event || omap_crtc->old_fb) { + +		if (++loops > 10) { +			dev_err(crtc->dev->dev, +				"omap_crtc_flush() timeout\n"); +			break; +		} + +		schedule_timeout_uninterruptible(msecs_to_jiffies(20)); +	} +} +  static const char *channel_names[] = {  		[OMAP_DSS_CHANNEL_LCD] = "lcd",  		[OMAP_DSS_CHANNEL_DIGIT] = "tv",  		[OMAP_DSS_CHANNEL_LCD2] = "lcd2", +		[OMAP_DSS_CHANNEL_LCD3] = "lcd3",  };  void omap_crtc_pre_init(void) diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index bf39fcc49e0f..c8270e4b26f3 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -513,12 +513,18 @@ static int dev_load(struct drm_device *dev, unsigned long flags)  static int dev_unload(struct drm_device *dev)  {  	struct omap_drm_private *priv = dev->dev_private; +	int i;  	DBG("unload: dev=%p", dev);  	drm_kms_helper_poll_fini(dev);  	omap_fbdev_free(dev); + +	/* flush crtcs so the fbs get released */ +	for (i = 0; i < priv->num_crtcs; i++) +		omap_crtc_flush(priv->crtcs[i]); +  	omap_modeset_free(dev);  	omap_gem_deinit(dev); @@ -696,10 +702,11 @@ static int pdev_remove(struct platform_device *device)  {  	DBG(""); +	drm_put_dev(platform_get_drvdata(device)); +  	omap_disconnect_dssdevs();  	omap_crtc_pre_uninit(); -	drm_put_dev(platform_get_drvdata(device));  	return 0;  } @@ -726,18 +733,33 @@ static struct platform_driver pdev = {  static int __init omap_drm_init(void)  { +	int r; +  	DBG("init"); -	if (platform_driver_register(&omap_dmm_driver)) { -		/* we can continue on without DMM.. so not fatal */ -		dev_err(NULL, "DMM registration failed\n"); + +	r = platform_driver_register(&omap_dmm_driver); +	if (r) { +		pr_err("DMM driver registration failed\n"); +		return r; +	} + +	r = platform_driver_register(&pdev); +	if (r) { +		pr_err("omapdrm driver registration failed\n"); +		platform_driver_unregister(&omap_dmm_driver); +		return r;  	} -	return platform_driver_register(&pdev); + +	return 0;  }  static void __exit omap_drm_fini(void)  {  	DBG("fini"); +  	platform_driver_unregister(&pdev); + +	platform_driver_unregister(&omap_dmm_driver);  }  /* need late_initcall() so we load after dss_driver's are loaded */ diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index 428b2981fd68..284b80fc3c54 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -163,6 +163,7 @@ void omap_crtc_pre_init(void);  void omap_crtc_pre_uninit(void);  struct drm_crtc *omap_crtc_init(struct drm_device *dev,  		struct drm_plane *plane, enum omap_channel channel, int id); +void omap_crtc_flush(struct drm_crtc *crtc);  struct drm_plane *omap_plane_init(struct drm_device *dev,  		int plane_id, bool private_plane); diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c index d2b8c49bfb4a..8b019602ffe6 100644 --- a/drivers/gpu/drm/omapdrm/omap_fb.c +++ b/drivers/gpu/drm/omapdrm/omap_fb.c @@ -218,6 +218,20 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,  		info->rotation_type = OMAP_DSS_ROT_TILER;  		info->screen_width  = omap_gem_tiled_stride(plane->bo, orient);  	} else { +		switch (win->rotation & 0xf) { +		case 0: +		case BIT(DRM_ROTATE_0): +			/* OK */ +			break; + +		default: +			dev_warn(fb->dev->dev, +				"rotation '%d' ignored for non-tiled fb\n", +				win->rotation); +			win->rotation = 0; +			break; +		} +  		info->paddr         = get_linear_addr(plane, format, 0, x, y);  		info->rotation_type = OMAP_DSS_ROT_DMA;  		info->screen_width  = plane->pitch; diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index 002988d09021..1388ca7f87e8 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -371,6 +371,9 @@ void omap_fbdev_free(struct drm_device *dev)  	fbdev = to_omap_fbdev(priv->fbdev); +	/* release the ref taken in omap_fbdev_create() */ +	omap_gem_put_paddr(fbdev->bo); +  	/* this will free the backing object */  	if (fbdev->fb) {  		drm_framebuffer_unregister_private(fbdev->fb); diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index c8d972763889..95dbce286a41 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -980,12 +980,9 @@ int omap_gem_resume(struct device *dev)  #ifdef CONFIG_DEBUG_FS  void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m)  { -	struct drm_device *dev = obj->dev;  	struct omap_gem_object *omap_obj = to_omap_bo(obj);  	uint64_t off; -	WARN_ON(!mutex_is_locked(&dev->struct_mutex)); -  	off = drm_vma_node_start(&obj->vma_node);  	seq_printf(m, "%08x: %2d (%2d) %08llx %08Zx (%2d) %p %4d", @@ -1050,10 +1047,10 @@ static inline bool is_waiting(struct omap_gem_sync_waiter *waiter)  {  	struct omap_gem_object *omap_obj = waiter->omap_obj;  	if ((waiter->op & OMAP_GEM_READ) && -			(omap_obj->sync->read_complete < waiter->read_target)) +			(omap_obj->sync->write_complete < waiter->write_target))  		return true;  	if ((waiter->op & OMAP_GEM_WRITE) && -			(omap_obj->sync->write_complete < waiter->write_target)) +			(omap_obj->sync->read_complete < waiter->read_target))  		return true;  	return false;  } @@ -1229,6 +1226,8 @@ int omap_gem_op_async(struct drm_gem_object *obj, enum omap_gem_op op,  		}  		spin_unlock(&sync_lock); + +		kfree(waiter);  	}  	/* no waiting.. */ diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index 046d5e660c04..3cf31ee59aac 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -225,6 +225,11 @@ int omap_plane_mode_set(struct drm_plane *plane,  		omap_plane->apply_done_cb.arg = arg;  	} +	if (plane->fb) +		drm_framebuffer_unreference(plane->fb); + +	drm_framebuffer_reference(fb); +  	plane->fb = fb;  	plane->crtc = crtc; @@ -241,10 +246,13 @@ static int omap_plane_update(struct drm_plane *plane,  	struct omap_plane *omap_plane = to_omap_plane(plane);  	omap_plane->enabled = true; -	if (plane->fb) -		drm_framebuffer_unreference(plane->fb); - -	drm_framebuffer_reference(fb); +	/* omap_plane_mode_set() takes adjusted src */ +	switch (omap_plane->win.rotation & 0xf) { +	case BIT(DRM_ROTATE_90): +	case BIT(DRM_ROTATE_270): +		swap(src_w, src_h); +		break; +	}  	return omap_plane_mode_set(plane, crtc, fb,  			crtc_x, crtc_y, crtc_w, crtc_h, diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index fb187c78978f..c31c12b4e666 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1177,27 +1177,43 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,  		/* Set NUM_BANKS. */  		if (rdev->family >= CHIP_TAHITI) { -			unsigned tileb, index, num_banks, tile_split_bytes; +			unsigned index, num_banks; -			/* Calculate the macrotile mode index. */ -			tile_split_bytes = 64 << tile_split; -			tileb = 8 * 8 * target_fb->bits_per_pixel / 8; -			tileb = min(tile_split_bytes, tileb); +			if (rdev->family >= CHIP_BONAIRE) { +				unsigned tileb, tile_split_bytes; -			for (index = 0; tileb > 64; index++) { -				tileb >>= 1; -			} +				/* Calculate the macrotile mode index. */ +				tile_split_bytes = 64 << tile_split; +				tileb = 8 * 8 * target_fb->bits_per_pixel / 8; +				tileb = min(tile_split_bytes, tileb); -			if (index >= 16) { -				DRM_ERROR("Wrong screen bpp (%u) or tile split (%u)\n", -					  target_fb->bits_per_pixel, tile_split); -				return -EINVAL; -			} +				for (index = 0; tileb > 64; index++) +					tileb >>= 1; + +				if (index >= 16) { +					DRM_ERROR("Wrong screen bpp (%u) or tile split (%u)\n", +						  target_fb->bits_per_pixel, tile_split); +					return -EINVAL; +				} -			if (rdev->family >= CHIP_BONAIRE)  				num_banks = (rdev->config.cik.macrotile_mode_array[index] >> 6) & 0x3; -			else +			} else { +				switch (target_fb->bits_per_pixel) { +				case 8: +					index = 10; +					break; +				case 16: +					index = SI_TILE_MODE_COLOR_2D_SCANOUT_16BPP; +					break; +				default: +				case 32: +					index = SI_TILE_MODE_COLOR_2D_SCANOUT_32BPP; +					break; +				} +  				num_banks = (rdev->config.si.tile_mode_array[index] >> 20) & 0x3; +			} +  			fb_format |= EVERGREEN_GRPH_NUM_BANKS(num_banks);  		} else {  			/* NI and older. */ @@ -1720,8 +1736,9 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)  		}  		/* otherwise, pick one of the plls */  		if ((rdev->family == CHIP_KAVERI) || -		    (rdev->family == CHIP_KABINI)) { -			/* KB/KV has PPLL1 and PPLL2 */ +		    (rdev->family == CHIP_KABINI) || +		    (rdev->family == CHIP_MULLINS)) { +			/* KB/KV/ML has PPLL1 and PPLL2 */  			pll_in_use = radeon_get_pll_use_mask(crtc);  			if (!(pll_in_use & (1 << ATOM_PPLL2)))  				return ATOM_PPLL2; @@ -1885,6 +1902,9 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc,  	    (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT))  		is_tvcv = true; +	if (!radeon_crtc->adjusted_clock) +		return -EINVAL; +  	atombios_crtc_set_pll(crtc, adjusted_mode);  	if (ASIC_IS_DCE4(rdev)) diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 8b0ab170cef9..54e4f52549af 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -142,7 +142,8 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,  	return recv_bytes;  } -#define HEADER_SIZE 4 +#define BARE_ADDRESS_SIZE 3 +#define HEADER_SIZE (BARE_ADDRESS_SIZE + 1)  static ssize_t  radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) @@ -160,13 +161,19 @@ radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)  	tx_buf[0] = msg->address & 0xff;  	tx_buf[1] = msg->address >> 8;  	tx_buf[2] = msg->request << 4; -	tx_buf[3] = msg->size - 1; +	tx_buf[3] = msg->size ? (msg->size - 1) : 0;  	switch (msg->request & ~DP_AUX_I2C_MOT) {  	case DP_AUX_NATIVE_WRITE:  	case DP_AUX_I2C_WRITE: +		/* tx_size needs to be 4 even for bare address packets since the atom +		 * table needs the info in tx_buf[3]. +		 */  		tx_size = HEADER_SIZE + msg->size; -		tx_buf[3] |= tx_size << 4; +		if (msg->size == 0) +			tx_buf[3] |= BARE_ADDRESS_SIZE << 4; +		else +			tx_buf[3] |= tx_size << 4;  		memcpy(tx_buf + HEADER_SIZE, msg->buffer, msg->size);  		ret = radeon_process_aux_ch(chan,  					    tx_buf, tx_size, NULL, 0, delay, &ack); @@ -176,8 +183,14 @@ radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)  		break;  	case DP_AUX_NATIVE_READ:  	case DP_AUX_I2C_READ: +		/* tx_size needs to be 4 even for bare address packets since the atom +		 * table needs the info in tx_buf[3]. +		 */  		tx_size = HEADER_SIZE; -		tx_buf[3] |= tx_size << 4; +		if (msg->size == 0) +			tx_buf[3] |= BARE_ADDRESS_SIZE << 4; +		else +			tx_buf[3] |= tx_size << 4;  		ret = radeon_process_aux_ch(chan,  					    tx_buf, tx_size, msg->buffer, msg->size, delay, &ack);  		break; @@ -186,7 +199,7 @@ radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)  		break;  	} -	if (ret > 0) +	if (ret >= 0)  		msg->reply = ack >> 4;  	return ret; @@ -194,98 +207,16 @@ radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)  void radeon_dp_aux_init(struct radeon_connector *radeon_connector)  { -	struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; - -	dig_connector->dp_i2c_bus->aux.dev = radeon_connector->base.kdev; -	dig_connector->dp_i2c_bus->aux.transfer = radeon_dp_aux_transfer; -} - -int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, -			 u8 write_byte, u8 *read_byte) -{ -	struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; -	struct radeon_i2c_chan *auxch = i2c_get_adapdata(adapter); -	u16 address = algo_data->address; -	u8 msg[5]; -	u8 reply[2]; -	unsigned retry; -	int msg_bytes; -	int reply_bytes = 1;  	int ret; -	u8 ack; -	/* Set up the address */ -	msg[0] = address; -	msg[1] = address >> 8; +	radeon_connector->ddc_bus->rec.hpd = radeon_connector->hpd.hpd; +	radeon_connector->ddc_bus->aux.dev = radeon_connector->base.kdev; +	radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer; +	ret = drm_dp_aux_register_i2c_bus(&radeon_connector->ddc_bus->aux); +	if (!ret) +		radeon_connector->ddc_bus->has_aux = true; -	/* Set up the command byte */ -	if (mode & MODE_I2C_READ) { -		msg[2] = DP_AUX_I2C_READ << 4; -		msg_bytes = 4; -		msg[3] = msg_bytes << 4; -	} else { -		msg[2] = DP_AUX_I2C_WRITE << 4; -		msg_bytes = 5; -		msg[3] = msg_bytes << 4; -		msg[4] = write_byte; -	} - -	/* special handling for start/stop */ -	if (mode & (MODE_I2C_START | MODE_I2C_STOP)) -		msg[3] = 3 << 4; - -	/* Set MOT bit for all but stop */ -	if ((mode & MODE_I2C_STOP) == 0) -		msg[2] |= DP_AUX_I2C_MOT << 4; - -	for (retry = 0; retry < 7; retry++) { -		ret = radeon_process_aux_ch(auxch, -					    msg, msg_bytes, reply, reply_bytes, 0, &ack); -		if (ret == -EBUSY) -			continue; -		else if (ret < 0) { -			DRM_DEBUG_KMS("aux_ch failed %d\n", ret); -			return ret; -		} - -		switch ((ack >> 4) & DP_AUX_NATIVE_REPLY_MASK) { -		case DP_AUX_NATIVE_REPLY_ACK: -			/* I2C-over-AUX Reply field is only valid -			 * when paired with AUX ACK. -			 */ -			break; -		case DP_AUX_NATIVE_REPLY_NACK: -			DRM_DEBUG_KMS("aux_ch native nack\n"); -			return -EREMOTEIO; -		case DP_AUX_NATIVE_REPLY_DEFER: -			DRM_DEBUG_KMS("aux_ch native defer\n"); -			usleep_range(500, 600); -			continue; -		default: -			DRM_ERROR("aux_ch invalid native reply 0x%02x\n", ack); -			return -EREMOTEIO; -		} - -		switch ((ack >> 4) & DP_AUX_I2C_REPLY_MASK) { -		case DP_AUX_I2C_REPLY_ACK: -			if (mode == MODE_I2C_READ) -				*read_byte = reply[0]; -			return ret; -		case DP_AUX_I2C_REPLY_NACK: -			DRM_DEBUG_KMS("aux_i2c nack\n"); -			return -EREMOTEIO; -		case DP_AUX_I2C_REPLY_DEFER: -			DRM_DEBUG_KMS("aux_i2c defer\n"); -			usleep_range(400, 500); -			break; -		default: -			DRM_ERROR("aux_i2c invalid reply 0x%02x\n", ack); -			return -EREMOTEIO; -		} -	} - -	DRM_DEBUG_KMS("aux i2c too many retries, giving up\n"); -	return -EREMOTEIO; +	WARN(ret, "drm_dp_aux_register_i2c_bus() failed with error %d\n", ret);  }  /***** general DP utility functions *****/ @@ -420,12 +351,11 @@ static u8 radeon_dp_encoder_service(struct radeon_device *rdev,  u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector)  { -	struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;  	struct drm_device *dev = radeon_connector->base.dev;  	struct radeon_device *rdev = dev->dev_private;  	return radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_GET_SINK_TYPE, 0, -					 dig_connector->dp_i2c_bus->rec.i2c_id, 0); +					 radeon_connector->ddc_bus->rec.i2c_id, 0);  }  static void radeon_dp_probe_oui(struct radeon_connector *radeon_connector) @@ -436,11 +366,11 @@ static void radeon_dp_probe_oui(struct radeon_connector *radeon_connector)  	if (!(dig_connector->dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT))  		return; -	if (drm_dp_dpcd_read(&dig_connector->dp_i2c_bus->aux, DP_SINK_OUI, buf, 3)) +	if (drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_SINK_OUI, buf, 3) == 3)  		DRM_DEBUG_KMS("Sink OUI: %02hx%02hx%02hx\n",  			      buf[0], buf[1], buf[2]); -	if (drm_dp_dpcd_read(&dig_connector->dp_i2c_bus->aux, DP_BRANCH_OUI, buf, 3)) +	if (drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_BRANCH_OUI, buf, 3) == 3)  		DRM_DEBUG_KMS("Branch OUI: %02hx%02hx%02hx\n",  			      buf[0], buf[1], buf[2]);  } @@ -451,7 +381,7 @@ bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector)  	u8 msg[DP_DPCD_SIZE];  	int ret, i; -	ret = drm_dp_dpcd_read(&dig_connector->dp_i2c_bus->aux, DP_DPCD_REV, msg, +	ret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_DPCD_REV, msg,  			       DP_DPCD_SIZE);  	if (ret > 0) {  		memcpy(dig_connector->dpcd, msg, DP_DPCD_SIZE); @@ -489,21 +419,23 @@ int radeon_dp_get_panel_mode(struct drm_encoder *encoder,  	if (dp_bridge != ENCODER_OBJECT_ID_NONE) {  		/* DP bridge chips */ -		drm_dp_dpcd_readb(&dig_connector->dp_i2c_bus->aux, -				  DP_EDP_CONFIGURATION_CAP, &tmp); -		if (tmp & 1) -			panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; -		else if ((dp_bridge == ENCODER_OBJECT_ID_NUTMEG) || -			 (dp_bridge == ENCODER_OBJECT_ID_TRAVIS)) -			panel_mode = DP_PANEL_MODE_INTERNAL_DP1_MODE; -		else -			panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE; +		if (drm_dp_dpcd_readb(&radeon_connector->ddc_bus->aux, +				      DP_EDP_CONFIGURATION_CAP, &tmp) == 1) { +			if (tmp & 1) +				panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; +			else if ((dp_bridge == ENCODER_OBJECT_ID_NUTMEG) || +				 (dp_bridge == ENCODER_OBJECT_ID_TRAVIS)) +				panel_mode = DP_PANEL_MODE_INTERNAL_DP1_MODE; +			else +				panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE; +		}  	} else if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {  		/* eDP */ -		drm_dp_dpcd_readb(&dig_connector->dp_i2c_bus->aux, -				  DP_EDP_CONFIGURATION_CAP, &tmp); -		if (tmp & 1) -			panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; +		if (drm_dp_dpcd_readb(&radeon_connector->ddc_bus->aux, +				      DP_EDP_CONFIGURATION_CAP, &tmp) == 1) { +			if (tmp & 1) +				panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; +		}  	}  	return panel_mode; @@ -554,7 +486,8 @@ bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector)  	u8 link_status[DP_LINK_STATUS_SIZE];  	struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; -	if (drm_dp_dpcd_read_link_status(&dig->dp_i2c_bus->aux, link_status) <= 0) +	if (drm_dp_dpcd_read_link_status(&radeon_connector->ddc_bus->aux, link_status) +	    <= 0)  		return false;  	if (drm_dp_channel_eq_ok(link_status, dig->dp_lane_count))  		return false; @@ -574,7 +507,7 @@ void radeon_dp_set_rx_power_state(struct drm_connector *connector,  	/* power up/down the sink */  	if (dig_connector->dpcd[0] >= 0x11) { -		drm_dp_dpcd_writeb(&dig_connector->dp_i2c_bus->aux, +		drm_dp_dpcd_writeb(&radeon_connector->ddc_bus->aux,  				   DP_SET_POWER, power_state);  		usleep_range(1000, 2000);  	} @@ -878,11 +811,15 @@ void radeon_dp_link_train(struct drm_encoder *encoder,  	else  		dp_info.enc_id |= ATOM_DP_CONFIG_LINK_A; -	drm_dp_dpcd_readb(&dig_connector->dp_i2c_bus->aux, DP_MAX_LANE_COUNT, &tmp); -	if (ASIC_IS_DCE5(rdev) && (tmp & DP_TPS3_SUPPORTED)) -		dp_info.tp3_supported = true; -	else +	if (drm_dp_dpcd_readb(&radeon_connector->ddc_bus->aux, DP_MAX_LANE_COUNT, &tmp) +	    == 1) { +		if (ASIC_IS_DCE5(rdev) && (tmp & DP_TPS3_SUPPORTED)) +			dp_info.tp3_supported = true; +		else +			dp_info.tp3_supported = false; +	} else {  		dp_info.tp3_supported = false; +	}  	memcpy(dp_info.dpcd, dig_connector->dpcd, DP_RECEIVER_CAP_SIZE);  	dp_info.rdev = rdev; @@ -890,7 +827,7 @@ void radeon_dp_link_train(struct drm_encoder *encoder,  	dp_info.connector = connector;  	dp_info.dp_lane_count = dig_connector->dp_lane_count;  	dp_info.dp_clock = dig_connector->dp_clock; -	dp_info.aux = &dig_connector->dp_i2c_bus->aux; +	dp_info.aux = &radeon_connector->ddc_bus->aux;  	if (radeon_dp_link_train_init(&dp_info))  		goto done; diff --git a/drivers/gpu/drm/radeon/ci_dpm.c b/drivers/gpu/drm/radeon/ci_dpm.c index cad89a977527..10dae4106c08 100644 --- a/drivers/gpu/drm/radeon/ci_dpm.c +++ b/drivers/gpu/drm/radeon/ci_dpm.c @@ -21,8 +21,10 @@   *   */ +#include <linux/firmware.h>  #include "drmP.h"  #include "radeon.h" +#include "radeon_ucode.h"  #include "cikd.h"  #include "r600_dpm.h"  #include "ci_dpm.h" @@ -202,24 +204,29 @@ static void ci_initialize_powertune_defaults(struct radeon_device *rdev)  	struct ci_power_info *pi = ci_get_pi(rdev);  	switch (rdev->pdev->device) { +	case 0x6649:  	case 0x6650: +	case 0x6651:  	case 0x6658:  	case 0x665C: +	case 0x665D:  	default:  		pi->powertune_defaults = &defaults_bonaire_xt;  		break; -	case 0x6651: -	case 0x665D: -		pi->powertune_defaults = &defaults_bonaire_pro; -		break;  	case 0x6640: -		pi->powertune_defaults = &defaults_saturn_xt; -		break;  	case 0x6641: -		pi->powertune_defaults = &defaults_saturn_pro; +	case 0x6646: +	case 0x6647: +		pi->powertune_defaults = &defaults_saturn_xt;  		break;  	case 0x67B8:  	case 0x67B0: +		pi->powertune_defaults = &defaults_hawaii_xt; +		break; +	case 0x67BA: +	case 0x67B1: +		pi->powertune_defaults = &defaults_hawaii_pro; +		break;  	case 0x67A0:  	case 0x67A1:  	case 0x67A2: @@ -228,11 +235,7 @@ static void ci_initialize_powertune_defaults(struct radeon_device *rdev)  	case 0x67AA:  	case 0x67B9:  	case 0x67BE: -		pi->powertune_defaults = &defaults_hawaii_xt; -		break; -	case 0x67BA: -	case 0x67B1: -		pi->powertune_defaults = &defaults_hawaii_pro; +		pi->powertune_defaults = &defaults_bonaire_xt;  		break;  	} @@ -5146,6 +5149,12 @@ int ci_dpm_init(struct radeon_device *rdev)  	pi->mclk_dpm_key_disabled = 0;  	pi->pcie_dpm_key_disabled = 0; +	/* mclk dpm is unstable on some R7 260X cards with the old mc ucode */ +	if ((rdev->pdev->device == 0x6658) && +	    (rdev->mc_fw->size == (BONAIRE_MC_UCODE_SIZE * 4))) { +		pi->mclk_dpm_key_disabled = 1; +	} +  	pi->caps_sclk_ds = true;  	pi->mclk_strobe_mode_threshold = 40000; diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index 745143c2358f..d2fd98968085 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -38,6 +38,7 @@ MODULE_FIRMWARE("radeon/BONAIRE_me.bin");  MODULE_FIRMWARE("radeon/BONAIRE_ce.bin");  MODULE_FIRMWARE("radeon/BONAIRE_mec.bin");  MODULE_FIRMWARE("radeon/BONAIRE_mc.bin"); +MODULE_FIRMWARE("radeon/BONAIRE_mc2.bin");  MODULE_FIRMWARE("radeon/BONAIRE_rlc.bin");  MODULE_FIRMWARE("radeon/BONAIRE_sdma.bin");  MODULE_FIRMWARE("radeon/BONAIRE_smc.bin"); @@ -46,6 +47,7 @@ MODULE_FIRMWARE("radeon/HAWAII_me.bin");  MODULE_FIRMWARE("radeon/HAWAII_ce.bin");  MODULE_FIRMWARE("radeon/HAWAII_mec.bin");  MODULE_FIRMWARE("radeon/HAWAII_mc.bin"); +MODULE_FIRMWARE("radeon/HAWAII_mc2.bin");  MODULE_FIRMWARE("radeon/HAWAII_rlc.bin");  MODULE_FIRMWARE("radeon/HAWAII_sdma.bin");  MODULE_FIRMWARE("radeon/HAWAII_smc.bin"); @@ -61,6 +63,12 @@ MODULE_FIRMWARE("radeon/KABINI_ce.bin");  MODULE_FIRMWARE("radeon/KABINI_mec.bin");  MODULE_FIRMWARE("radeon/KABINI_rlc.bin");  MODULE_FIRMWARE("radeon/KABINI_sdma.bin"); +MODULE_FIRMWARE("radeon/MULLINS_pfp.bin"); +MODULE_FIRMWARE("radeon/MULLINS_me.bin"); +MODULE_FIRMWARE("radeon/MULLINS_ce.bin"); +MODULE_FIRMWARE("radeon/MULLINS_mec.bin"); +MODULE_FIRMWARE("radeon/MULLINS_rlc.bin"); +MODULE_FIRMWARE("radeon/MULLINS_sdma.bin");  extern int r600_ih_ring_alloc(struct radeon_device *rdev);  extern void r600_ih_ring_fini(struct radeon_device *rdev); @@ -1471,6 +1479,43 @@ static const u32 hawaii_mgcg_cgcg_init[] =  	0xd80c, 0xff000ff0, 0x00000100  }; +static const u32 godavari_golden_registers[] = +{ +	0x55e4, 0xff607fff, 0xfc000100, +	0x6ed8, 0x00010101, 0x00010000, +	0x9830, 0xffffffff, 0x00000000, +	0x98302, 0xf00fffff, 0x00000400, +	0x6130, 0xffffffff, 0x00010000, +	0x5bb0, 0x000000f0, 0x00000070, +	0x5bc0, 0xf0311fff, 0x80300000, +	0x98f8, 0x73773777, 0x12010001, +	0x98fc, 0xffffffff, 0x00000010, +	0x8030, 0x00001f0f, 0x0000100a, +	0x2f48, 0x73773777, 0x12010001, +	0x2408, 0x000fffff, 0x000c007f, +	0x8a14, 0xf000003f, 0x00000007, +	0x8b24, 0xffffffff, 0x00ff0fff, +	0x30a04, 0x0000ff0f, 0x00000000, +	0x28a4c, 0x07ffffff, 0x06000000, +	0x4d8, 0x00000fff, 0x00000100, +	0xd014, 0x00010000, 0x00810001, +	0xd814, 0x00010000, 0x00810001, +	0x3e78, 0x00000001, 0x00000002, +	0xc768, 0x00000008, 0x00000008, +	0xc770, 0x00000f00, 0x00000800, +	0xc774, 0x00000f00, 0x00000800, +	0xc798, 0x00ffffff, 0x00ff7fbf, +	0xc79c, 0x00ffffff, 0x00ff7faf, +	0x8c00, 0x000000ff, 0x00000001, +	0x214f8, 0x01ff01ff, 0x00000002, +	0x21498, 0x007ff800, 0x00200000, +	0x2015c, 0xffffffff, 0x00000f40, +	0x88c4, 0x001f3ae3, 0x00000082, +	0x88d4, 0x0000001f, 0x00000010, +	0x30934, 0xffffffff, 0x00000000 +}; + +  static void cik_init_golden_registers(struct radeon_device *rdev)  {  	switch (rdev->family) { @@ -1502,6 +1547,20 @@ static void cik_init_golden_registers(struct radeon_device *rdev)  						 kalindi_golden_spm_registers,  						 (const u32)ARRAY_SIZE(kalindi_golden_spm_registers));  		break; +	case CHIP_MULLINS: +		radeon_program_register_sequence(rdev, +						 kalindi_mgcg_cgcg_init, +						 (const u32)ARRAY_SIZE(kalindi_mgcg_cgcg_init)); +		radeon_program_register_sequence(rdev, +						 godavari_golden_registers, +						 (const u32)ARRAY_SIZE(godavari_golden_registers)); +		radeon_program_register_sequence(rdev, +						 kalindi_golden_common_registers, +						 (const u32)ARRAY_SIZE(kalindi_golden_common_registers)); +		radeon_program_register_sequence(rdev, +						 kalindi_golden_spm_registers, +						 (const u32)ARRAY_SIZE(kalindi_golden_spm_registers)); +		break;  	case CHIP_KAVERI:  		radeon_program_register_sequence(rdev,  						 spectre_mgcg_cgcg_init, @@ -1703,20 +1762,20 @@ int ci_mc_load_microcode(struct radeon_device *rdev)  	const __be32 *fw_data;  	u32 running, blackout = 0;  	u32 *io_mc_regs; -	int i, ucode_size, regs_size; +	int i, regs_size, ucode_size;  	if (!rdev->mc_fw)  		return -EINVAL; +	ucode_size = rdev->mc_fw->size / 4; +  	switch (rdev->family) {  	case CHIP_BONAIRE:  		io_mc_regs = (u32 *)&bonaire_io_mc_regs; -		ucode_size = CIK_MC_UCODE_SIZE;  		regs_size = BONAIRE_IO_MC_REGS_SIZE;  		break;  	case CHIP_HAWAII:  		io_mc_regs = (u32 *)&hawaii_io_mc_regs; -		ucode_size = HAWAII_MC_UCODE_SIZE;  		regs_size = HAWAII_IO_MC_REGS_SIZE;  		break;  	default: @@ -1783,7 +1842,7 @@ static int cik_init_microcode(struct radeon_device *rdev)  	const char *chip_name;  	size_t pfp_req_size, me_req_size, ce_req_size,  		mec_req_size, rlc_req_size, mc_req_size = 0, -		sdma_req_size, smc_req_size = 0; +		sdma_req_size, smc_req_size = 0, mc2_req_size = 0;  	char fw_name[30];  	int err; @@ -1797,7 +1856,8 @@ static int cik_init_microcode(struct radeon_device *rdev)  		ce_req_size = CIK_CE_UCODE_SIZE * 4;  		mec_req_size = CIK_MEC_UCODE_SIZE * 4;  		rlc_req_size = BONAIRE_RLC_UCODE_SIZE * 4; -		mc_req_size = CIK_MC_UCODE_SIZE * 4; +		mc_req_size = BONAIRE_MC_UCODE_SIZE * 4; +		mc2_req_size = BONAIRE_MC2_UCODE_SIZE * 4;  		sdma_req_size = CIK_SDMA_UCODE_SIZE * 4;  		smc_req_size = ALIGN(BONAIRE_SMC_UCODE_SIZE, 4);  		break; @@ -1809,6 +1869,7 @@ static int cik_init_microcode(struct radeon_device *rdev)  		mec_req_size = CIK_MEC_UCODE_SIZE * 4;  		rlc_req_size = BONAIRE_RLC_UCODE_SIZE * 4;  		mc_req_size = HAWAII_MC_UCODE_SIZE * 4; +		mc2_req_size = HAWAII_MC2_UCODE_SIZE * 4;  		sdma_req_size = CIK_SDMA_UCODE_SIZE * 4;  		smc_req_size = ALIGN(HAWAII_SMC_UCODE_SIZE, 4);  		break; @@ -1830,6 +1891,15 @@ static int cik_init_microcode(struct radeon_device *rdev)  		rlc_req_size = KB_RLC_UCODE_SIZE * 4;  		sdma_req_size = CIK_SDMA_UCODE_SIZE * 4;  		break; +	case CHIP_MULLINS: +		chip_name = "MULLINS"; +		pfp_req_size = CIK_PFP_UCODE_SIZE * 4; +		me_req_size = CIK_ME_UCODE_SIZE * 4; +		ce_req_size = CIK_CE_UCODE_SIZE * 4; +		mec_req_size = CIK_MEC_UCODE_SIZE * 4; +		rlc_req_size = ML_RLC_UCODE_SIZE * 4; +		sdma_req_size = CIK_SDMA_UCODE_SIZE * 4; +		break;  	default: BUG();  	} @@ -1904,16 +1974,22 @@ static int cik_init_microcode(struct radeon_device *rdev)  	/* No SMC, MC ucode on APUs */  	if (!(rdev->flags & RADEON_IS_IGP)) { -		snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); +		snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc2.bin", chip_name);  		err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev); -		if (err) -			goto out; -		if (rdev->mc_fw->size != mc_req_size) { +		if (err) { +			snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); +			err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev); +			if (err) +				goto out; +		} +		if ((rdev->mc_fw->size != mc_req_size) && +		    (rdev->mc_fw->size != mc2_req_size)){  			printk(KERN_ERR  			       "cik_mc: Bogus length %zu in firmware \"%s\"\n",  			       rdev->mc_fw->size, fw_name);  			err = -EINVAL;  		} +		DRM_INFO("%s: %zu bytes\n", fw_name, rdev->mc_fw->size);  		snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name);  		err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev); @@ -3262,6 +3338,7 @@ static void cik_gpu_init(struct radeon_device *rdev)  		gb_addr_config = BONAIRE_GB_ADDR_CONFIG_GOLDEN;  		break;  	case CHIP_KABINI: +	case CHIP_MULLINS:  	default:  		rdev->config.cik.max_shader_engines = 1;  		rdev->config.cik.max_tile_pipes = 2; @@ -3692,6 +3769,7 @@ int cik_copy_cpdma(struct radeon_device *rdev,  	r = radeon_fence_emit(rdev, fence, ring->idx);  	if (r) {  		radeon_ring_unlock_undo(rdev, ring); +		radeon_semaphore_free(rdev, &sem, NULL);  		return r;  	} @@ -5790,6 +5868,9 @@ static int cik_rlc_resume(struct radeon_device *rdev)  	case CHIP_KABINI:  		size = KB_RLC_UCODE_SIZE;  		break; +	case CHIP_MULLINS: +		size = ML_RLC_UCODE_SIZE; +		break;  	}  	cik_rlc_stop(rdev); @@ -6538,6 +6619,7 @@ void cik_get_csb_buffer(struct radeon_device *rdev, volatile u32 *buffer)  		buffer[count++] = cpu_to_le32(0x00000000);  		break;  	case CHIP_KABINI: +	case CHIP_MULLINS:  		buffer[count++] = cpu_to_le32(0x00000000); /* XXX */  		buffer[count++] = cpu_to_le32(0x00000000);  		break; @@ -6683,6 +6765,19 @@ static void cik_disable_interrupt_state(struct radeon_device *rdev)  		WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);  		WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);  	} +	/* pflip */ +	if (rdev->num_crtc >= 2) { +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); +	} +	if (rdev->num_crtc >= 4) { +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); +	} +	if (rdev->num_crtc >= 6) { +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); +	}  	/* dac hotplug */  	WREG32(DAC_AUTODETECT_INT_CONTROL, 0); @@ -7039,6 +7134,25 @@ int cik_irq_set(struct radeon_device *rdev)  		WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, crtc6);  	} +	if (rdev->num_crtc >= 2) { +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK); +	} +	if (rdev->num_crtc >= 4) { +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK); +	} +	if (rdev->num_crtc >= 6) { +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK); +	} +  	WREG32(DC_HPD1_INT_CONTROL, hpd1);  	WREG32(DC_HPD2_INT_CONTROL, hpd2);  	WREG32(DC_HPD3_INT_CONTROL, hpd3); @@ -7075,6 +7189,29 @@ static inline void cik_irq_ack(struct radeon_device *rdev)  	rdev->irq.stat_regs.cik.disp_int_cont5 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE5);  	rdev->irq.stat_regs.cik.disp_int_cont6 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE6); +	rdev->irq.stat_regs.cik.d1grph_int = RREG32(GRPH_INT_STATUS + +		EVERGREEN_CRTC0_REGISTER_OFFSET); +	rdev->irq.stat_regs.cik.d2grph_int = RREG32(GRPH_INT_STATUS + +		EVERGREEN_CRTC1_REGISTER_OFFSET); +	if (rdev->num_crtc >= 4) { +		rdev->irq.stat_regs.cik.d3grph_int = RREG32(GRPH_INT_STATUS + +			EVERGREEN_CRTC2_REGISTER_OFFSET); +		rdev->irq.stat_regs.cik.d4grph_int = RREG32(GRPH_INT_STATUS + +			EVERGREEN_CRTC3_REGISTER_OFFSET); +	} +	if (rdev->num_crtc >= 6) { +		rdev->irq.stat_regs.cik.d5grph_int = RREG32(GRPH_INT_STATUS + +			EVERGREEN_CRTC4_REGISTER_OFFSET); +		rdev->irq.stat_regs.cik.d6grph_int = RREG32(GRPH_INT_STATUS + +			EVERGREEN_CRTC5_REGISTER_OFFSET); +	} + +	if (rdev->irq.stat_regs.cik.d1grph_int & GRPH_PFLIP_INT_OCCURRED) +		WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_CLEAR); +	if (rdev->irq.stat_regs.cik.d2grph_int & GRPH_PFLIP_INT_OCCURRED) +		WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_CLEAR);  	if (rdev->irq.stat_regs.cik.disp_int & LB_D1_VBLANK_INTERRUPT)  		WREG32(LB_VBLANK_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VBLANK_ACK);  	if (rdev->irq.stat_regs.cik.disp_int & LB_D1_VLINE_INTERRUPT) @@ -7085,6 +7222,12 @@ static inline void cik_irq_ack(struct radeon_device *rdev)  		WREG32(LB_VLINE_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VLINE_ACK);  	if (rdev->num_crtc >= 4) { +		if (rdev->irq.stat_regs.cik.d3grph_int & GRPH_PFLIP_INT_OCCURRED) +			WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, +			       GRPH_PFLIP_INT_CLEAR); +		if (rdev->irq.stat_regs.cik.d4grph_int & GRPH_PFLIP_INT_OCCURRED) +			WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, +			       GRPH_PFLIP_INT_CLEAR);  		if (rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT)  			WREG32(LB_VBLANK_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VBLANK_ACK);  		if (rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VLINE_INTERRUPT) @@ -7096,6 +7239,12 @@ static inline void cik_irq_ack(struct radeon_device *rdev)  	}  	if (rdev->num_crtc >= 6) { +		if (rdev->irq.stat_regs.cik.d5grph_int & GRPH_PFLIP_INT_OCCURRED) +			WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, +			       GRPH_PFLIP_INT_CLEAR); +		if (rdev->irq.stat_regs.cik.d6grph_int & GRPH_PFLIP_INT_OCCURRED) +			WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, +			       GRPH_PFLIP_INT_CLEAR);  		if (rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT)  			WREG32(LB_VBLANK_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VBLANK_ACK);  		if (rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VLINE_INTERRUPT) @@ -7447,6 +7596,15 @@ restart_ih:  				break;  			}  			break; +		case 8: /* D1 page flip */ +		case 10: /* D2 page flip */ +		case 12: /* D3 page flip */ +		case 14: /* D4 page flip */ +		case 16: /* D5 page flip */ +		case 18: /* D6 page flip */ +			DRM_DEBUG("IH: D%d flip\n", ((src_id - 8) >> 1) + 1); +			radeon_crtc_handle_flip(rdev, (src_id - 8) >> 1); +			break;  		case 42: /* HPD hotplug */  			switch (src_data) {  			case 0: diff --git a/drivers/gpu/drm/radeon/cik_sdma.c b/drivers/gpu/drm/radeon/cik_sdma.c index 89b4afa5041c..72e464c79a88 100644 --- a/drivers/gpu/drm/radeon/cik_sdma.c +++ b/drivers/gpu/drm/radeon/cik_sdma.c @@ -562,6 +562,7 @@ int cik_copy_dma(struct radeon_device *rdev,  	r = radeon_fence_emit(rdev, fence, ring->idx);  	if (r) {  		radeon_ring_unlock_undo(rdev, ring); +		radeon_semaphore_free(rdev, &sem, NULL);  		return r;  	} @@ -597,7 +598,7 @@ int cik_sdma_ring_test(struct radeon_device *rdev,  	tmp = 0xCAFEDEAD;  	writel(tmp, ptr); -	r = radeon_ring_lock(rdev, ring, 4); +	r = radeon_ring_lock(rdev, ring, 5);  	if (r) {  		DRM_ERROR("radeon: dma failed to lock ring %d (%d).\n", ring->idx, r);  		return r; diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h index 213873270d5f..dd7926394a8f 100644 --- a/drivers/gpu/drm/radeon/cikd.h +++ b/drivers/gpu/drm/radeon/cikd.h @@ -888,6 +888,15 @@  #       define DC_HPD6_RX_INTERRUPT                     (1 << 18)  #define DISP_INTERRUPT_STATUS_CONTINUE6                 0x6780 +/* 0x6858, 0x7458, 0x10058, 0x10c58, 0x11858, 0x12458 */ +#define GRPH_INT_STATUS                                 0x6858 +#       define GRPH_PFLIP_INT_OCCURRED                  (1 << 0) +#       define GRPH_PFLIP_INT_CLEAR                     (1 << 8) +/* 0x685c, 0x745c, 0x1005c, 0x10c5c, 0x1185c, 0x1245c */ +#define GRPH_INT_CONTROL                                0x685c +#       define GRPH_PFLIP_INT_MASK                      (1 << 0) +#       define GRPH_PFLIP_INT_TYPE                      (1 << 8) +  #define	DAC_AUTODETECT_INT_CONTROL			0x67c8  #define DC_HPD1_INT_STATUS                              0x601c diff --git a/drivers/gpu/drm/radeon/dce6_afmt.c b/drivers/gpu/drm/radeon/dce6_afmt.c index 94e858751994..0a65dc7e93e7 100644 --- a/drivers/gpu/drm/radeon/dce6_afmt.c +++ b/drivers/gpu/drm/radeon/dce6_afmt.c @@ -309,11 +309,17 @@ int dce6_audio_init(struct radeon_device *rdev)  	rdev->audio.enabled = true; -	if (ASIC_IS_DCE8(rdev)) +	if (ASIC_IS_DCE81(rdev)) /* KV: 4 streams, 7 endpoints */ +		rdev->audio.num_pins = 7; +	else if (ASIC_IS_DCE83(rdev)) /* KB: 2 streams, 3 endpoints */ +		rdev->audio.num_pins = 3; +	else if (ASIC_IS_DCE8(rdev)) /* BN/HW: 6 streams, 7 endpoints */ +		rdev->audio.num_pins = 7; +	else if (ASIC_IS_DCE61(rdev)) /* TN: 4 streams, 6 endpoints */  		rdev->audio.num_pins = 6; -	else if (ASIC_IS_DCE61(rdev)) -		rdev->audio.num_pins = 4; -	else +	else if (ASIC_IS_DCE64(rdev)) /* OL: 2 streams, 2 endpoints */ +		rdev->audio.num_pins = 2; +	else /* SI: 6 streams, 6 endpoints */  		rdev->audio.num_pins = 6;  	for (i = 0; i < rdev->audio.num_pins; i++) { diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index b406546440da..0f7a51a3694f 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -4371,7 +4371,6 @@ int evergreen_irq_set(struct radeon_device *rdev)  	u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0;  	u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6;  	u32 grbm_int_cntl = 0; -	u32 grph1 = 0, grph2 = 0, grph3 = 0, grph4 = 0, grph5 = 0, grph6 = 0;  	u32 afmt1 = 0, afmt2 = 0, afmt3 = 0, afmt4 = 0, afmt5 = 0, afmt6 = 0;  	u32 dma_cntl, dma_cntl1 = 0;  	u32 thermal_int = 0; @@ -4554,15 +4553,21 @@ int evergreen_irq_set(struct radeon_device *rdev)  		WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, crtc6);  	} -	WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, grph1); -	WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, grph2); +	WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, +	       GRPH_PFLIP_INT_MASK); +	WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, +	       GRPH_PFLIP_INT_MASK);  	if (rdev->num_crtc >= 4) { -		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, grph3); -		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, grph4); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK);  	}  	if (rdev->num_crtc >= 6) { -		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, grph5); -		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, grph6); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK);  	}  	WREG32(DC_HPD1_INT_CONTROL, hpd1); @@ -4951,6 +4956,15 @@ restart_ih:  				break;  			}  			break; +		case 8: /* D1 page flip */ +		case 10: /* D2 page flip */ +		case 12: /* D3 page flip */ +		case 14: /* D4 page flip */ +		case 16: /* D5 page flip */ +		case 18: /* D6 page flip */ +			DRM_DEBUG("IH: D%d flip\n", ((src_id - 8) >> 1) + 1); +			radeon_crtc_handle_flip(rdev, (src_id - 8) >> 1); +			break;  		case 42: /* HPD hotplug */  			switch (src_data) {  			case 0: diff --git a/drivers/gpu/drm/radeon/evergreen_dma.c b/drivers/gpu/drm/radeon/evergreen_dma.c index 287fe966d7de..478caefe0fef 100644 --- a/drivers/gpu/drm/radeon/evergreen_dma.c +++ b/drivers/gpu/drm/radeon/evergreen_dma.c @@ -151,6 +151,7 @@ int evergreen_copy_dma(struct radeon_device *rdev,  	r = radeon_fence_emit(rdev, fence, ring->idx);  	if (r) {  		radeon_ring_unlock_undo(rdev, ring); +		radeon_semaphore_free(rdev, &sem, NULL);  		return r;  	} diff --git a/drivers/gpu/drm/radeon/kv_dpm.c b/drivers/gpu/drm/radeon/kv_dpm.c index 16ec9d56a234..3f6e817d97ee 100644 --- a/drivers/gpu/drm/radeon/kv_dpm.c +++ b/drivers/gpu/drm/radeon/kv_dpm.c @@ -546,6 +546,52 @@ static int kv_set_divider_value(struct radeon_device *rdev,  	return 0;  } +static u32 kv_convert_vid2_to_vid7(struct radeon_device *rdev, +				   struct sumo_vid_mapping_table *vid_mapping_table, +				   u32 vid_2bit) +{ +	struct radeon_clock_voltage_dependency_table *vddc_sclk_table = +		&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; +	u32 i; + +	if (vddc_sclk_table && vddc_sclk_table->count) { +		if (vid_2bit < vddc_sclk_table->count) +			return vddc_sclk_table->entries[vid_2bit].v; +		else +			return vddc_sclk_table->entries[vddc_sclk_table->count - 1].v; +	} else { +		for (i = 0; i < vid_mapping_table->num_entries; i++) { +			if (vid_mapping_table->entries[i].vid_2bit == vid_2bit) +				return vid_mapping_table->entries[i].vid_7bit; +		} +		return vid_mapping_table->entries[vid_mapping_table->num_entries - 1].vid_7bit; +	} +} + +static u32 kv_convert_vid7_to_vid2(struct radeon_device *rdev, +				   struct sumo_vid_mapping_table *vid_mapping_table, +				   u32 vid_7bit) +{ +	struct radeon_clock_voltage_dependency_table *vddc_sclk_table = +		&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; +	u32 i; + +	if (vddc_sclk_table && vddc_sclk_table->count) { +		for (i = 0; i < vddc_sclk_table->count; i++) { +			if (vddc_sclk_table->entries[i].v == vid_7bit) +				return i; +		} +		return vddc_sclk_table->count - 1; +	} else { +		for (i = 0; i < vid_mapping_table->num_entries; i++) { +			if (vid_mapping_table->entries[i].vid_7bit == vid_7bit) +				return vid_mapping_table->entries[i].vid_2bit; +		} + +		return vid_mapping_table->entries[vid_mapping_table->num_entries - 1].vid_2bit; +	} +} +  static u16 kv_convert_8bit_index_to_voltage(struct radeon_device *rdev,  					    u16 voltage)  { @@ -556,9 +602,9 @@ static u16 kv_convert_2bit_index_to_voltage(struct radeon_device *rdev,  					    u32 vid_2bit)  {  	struct kv_power_info *pi = kv_get_pi(rdev); -	u32 vid_8bit = sumo_convert_vid2_to_vid7(rdev, -						 &pi->sys_info.vid_mapping_table, -						 vid_2bit); +	u32 vid_8bit = kv_convert_vid2_to_vid7(rdev, +					       &pi->sys_info.vid_mapping_table, +					       vid_2bit);  	return kv_convert_8bit_index_to_voltage(rdev, (u16)vid_8bit);  } @@ -639,7 +685,7 @@ static int kv_force_lowest_valid(struct radeon_device *rdev)  static int kv_unforce_levels(struct radeon_device *rdev)  { -	if (rdev->family == CHIP_KABINI) +	if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS)  		return kv_notify_message_to_smu(rdev, PPSMC_MSG_NoForcedLevel);  	else  		return kv_set_enabled_levels(rdev); @@ -1362,13 +1408,20 @@ static int kv_update_uvd_dpm(struct radeon_device *rdev, bool gate)  	struct radeon_uvd_clock_voltage_dependency_table *table =  		&rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table;  	int ret; +	u32 mask;  	if (!gate) { -		if (!pi->caps_uvd_dpm || table->count || pi->caps_stable_p_state) +		if (table->count)  			pi->uvd_boot_level = table->count - 1;  		else  			pi->uvd_boot_level = 0; +		if (!pi->caps_uvd_dpm || pi->caps_stable_p_state) { +			mask = 1 << pi->uvd_boot_level; +		} else { +			mask = 0x1f; +		} +  		ret = kv_copy_bytes_to_smc(rdev,  					   pi->dpm_table_start +  					   offsetof(SMU7_Fusion_DpmTable, UvdBootLevel), @@ -1377,11 +1430,9 @@ static int kv_update_uvd_dpm(struct radeon_device *rdev, bool gate)  		if (ret)  			return ret; -		if (!pi->caps_uvd_dpm || -		    pi->caps_stable_p_state) -			kv_send_msg_to_smc_with_parameter(rdev, -							  PPSMC_MSG_UVDDPM_SetEnabledMask, -							  (1 << pi->uvd_boot_level)); +		kv_send_msg_to_smc_with_parameter(rdev, +						  PPSMC_MSG_UVDDPM_SetEnabledMask, +						  mask);  	}  	return kv_enable_uvd_dpm(rdev, !gate); @@ -1617,7 +1668,7 @@ static void kv_dpm_powergate_acp(struct radeon_device *rdev, bool gate)  	if (pi->acp_power_gated == gate)  		return; -	if (rdev->family == CHIP_KABINI) +	if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS)  		return;  	pi->acp_power_gated = gate; @@ -1786,7 +1837,7 @@ int kv_dpm_set_power_state(struct radeon_device *rdev)  		}  	} -	if (rdev->family == CHIP_KABINI) { +	if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) {  		if (pi->enable_dpm) {  			kv_set_valid_clock_range(rdev, new_ps);  			kv_update_dfs_bypass_settings(rdev, new_ps); @@ -1812,6 +1863,8 @@ int kv_dpm_set_power_state(struct radeon_device *rdev)  				return ret;  			}  			kv_update_sclk_t(rdev); +			if (rdev->family == CHIP_MULLINS) +				kv_enable_nb_dpm(rdev);  		}  	} else {  		if (pi->enable_dpm) { @@ -1862,7 +1915,7 @@ void kv_dpm_reset_asic(struct radeon_device *rdev)  {  	struct kv_power_info *pi = kv_get_pi(rdev); -	if (rdev->family == CHIP_KABINI) { +	if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) {  		kv_force_lowest_valid(rdev);  		kv_init_graphics_levels(rdev);  		kv_program_bootup_state(rdev); @@ -1901,14 +1954,41 @@ static void kv_construct_max_power_limits_table(struct radeon_device *rdev,  static void kv_patch_voltage_values(struct radeon_device *rdev)  {  	int i; -	struct radeon_uvd_clock_voltage_dependency_table *table = +	struct radeon_uvd_clock_voltage_dependency_table *uvd_table =  		&rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table; +	struct radeon_vce_clock_voltage_dependency_table *vce_table = +		&rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table; +	struct radeon_clock_voltage_dependency_table *samu_table = +		&rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table; +	struct radeon_clock_voltage_dependency_table *acp_table = +		&rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table; -	if (table->count) { -		for (i = 0; i < table->count; i++) -			table->entries[i].v = +	if (uvd_table->count) { +		for (i = 0; i < uvd_table->count; i++) +			uvd_table->entries[i].v =  				kv_convert_8bit_index_to_voltage(rdev, -								 table->entries[i].v); +								 uvd_table->entries[i].v); +	} + +	if (vce_table->count) { +		for (i = 0; i < vce_table->count; i++) +			vce_table->entries[i].v = +				kv_convert_8bit_index_to_voltage(rdev, +								 vce_table->entries[i].v); +	} + +	if (samu_table->count) { +		for (i = 0; i < samu_table->count; i++) +			samu_table->entries[i].v = +				kv_convert_8bit_index_to_voltage(rdev, +								 samu_table->entries[i].v); +	} + +	if (acp_table->count) { +		for (i = 0; i < acp_table->count; i++) +			acp_table->entries[i].v = +				kv_convert_8bit_index_to_voltage(rdev, +								 acp_table->entries[i].v);  	}  } @@ -1941,7 +2021,7 @@ static int kv_force_dpm_highest(struct radeon_device *rdev)  			break;  	} -	if (rdev->family == CHIP_KABINI) +	if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS)  		return kv_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_DPM_ForceState, i);  	else  		return kv_set_enabled_level(rdev, i); @@ -1961,7 +2041,7 @@ static int kv_force_dpm_lowest(struct radeon_device *rdev)  			break;  	} -	if (rdev->family == CHIP_KABINI) +	if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS)  		return kv_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_DPM_ForceState, i);  	else  		return kv_set_enabled_level(rdev, i); @@ -2118,7 +2198,7 @@ static void kv_apply_state_adjust_rules(struct radeon_device *rdev,  	else  		pi->battery_state = false; -	if (rdev->family == CHIP_KABINI) { +	if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) {  		ps->dpm0_pg_nb_ps_lo = 0x1;  		ps->dpm0_pg_nb_ps_hi = 0x0;  		ps->dpmx_nb_ps_lo = 0x1; @@ -2179,7 +2259,7 @@ static int kv_calculate_nbps_level_settings(struct radeon_device *rdev)  	if (pi->lowest_valid > pi->highest_valid)  		return -EINVAL; -	if (rdev->family == CHIP_KABINI) { +	if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) {  		for (i = pi->lowest_valid; i <= pi->highest_valid; i++) {  			pi->graphics_level[i].GnbSlow = 1;  			pi->graphics_level[i].ForceNbPs1 = 0; @@ -2253,9 +2333,9 @@ static void kv_init_graphics_levels(struct radeon_device *rdev)  				break;  			kv_set_divider_value(rdev, i, table->entries[i].clk); -			vid_2bit = sumo_convert_vid7_to_vid2(rdev, -							     &pi->sys_info.vid_mapping_table, -							     table->entries[i].v); +			vid_2bit = kv_convert_vid7_to_vid2(rdev, +							   &pi->sys_info.vid_mapping_table, +							   table->entries[i].v);  			kv_set_vid(rdev, i, vid_2bit);  			kv_set_at(rdev, i, pi->at[i]);  			kv_dpm_power_level_enabled_for_throttle(rdev, i, true); @@ -2324,7 +2404,7 @@ static void kv_program_nbps_index_settings(struct radeon_device *rdev,  	struct kv_power_info *pi = kv_get_pi(rdev);  	u32 nbdpmconfig1; -	if (rdev->family == CHIP_KABINI) +	if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS)  		return;  	if (pi->sys_info.nb_dpm_enable) { @@ -2631,9 +2711,6 @@ int kv_dpm_init(struct radeon_device *rdev)          pi->sram_end = SMC_RAM_END; -	if (rdev->family == CHIP_KABINI) -		pi->high_voltage_t = 4001; -  	pi->enable_nb_dpm = true;  	pi->caps_power_containment = true; diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 6e887d004eba..bbc189fd3ddc 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2839,6 +2839,7 @@ int r600_copy_cpdma(struct radeon_device *rdev,  	r = radeon_fence_emit(rdev, fence, ring->idx);  	if (r) {  		radeon_ring_unlock_undo(rdev, ring); +		radeon_semaphore_free(rdev, &sem, NULL);  		return r;  	} @@ -3505,7 +3506,6 @@ int r600_irq_set(struct radeon_device *rdev)  	u32 hpd1, hpd2, hpd3, hpd4 = 0, hpd5 = 0, hpd6 = 0;  	u32 grbm_int_cntl = 0;  	u32 hdmi0, hdmi1; -	u32 d1grph = 0, d2grph = 0;  	u32 dma_cntl;  	u32 thermal_int = 0; @@ -3614,8 +3614,8 @@ int r600_irq_set(struct radeon_device *rdev)  	WREG32(CP_INT_CNTL, cp_int_cntl);  	WREG32(DMA_CNTL, dma_cntl);  	WREG32(DxMODE_INT_MASK, mode_int); -	WREG32(D1GRPH_INTERRUPT_CONTROL, d1grph); -	WREG32(D2GRPH_INTERRUPT_CONTROL, d2grph); +	WREG32(D1GRPH_INTERRUPT_CONTROL, DxGRPH_PFLIP_INT_MASK); +	WREG32(D2GRPH_INTERRUPT_CONTROL, DxGRPH_PFLIP_INT_MASK);  	WREG32(GRBM_INT_CNTL, grbm_int_cntl);  	if (ASIC_IS_DCE3(rdev)) {  		WREG32(DC_HPD1_INT_CONTROL, hpd1); @@ -3918,6 +3918,14 @@ restart_ih:  				break;  			}  			break; +		case 9: /* D1 pflip */ +			DRM_DEBUG("IH: D1 flip\n"); +			radeon_crtc_handle_flip(rdev, 0); +			break; +		case 11: /* D2 pflip */ +			DRM_DEBUG("IH: D2 flip\n"); +			radeon_crtc_handle_flip(rdev, 1); +			break;  		case 19: /* HPD/DAC hotplug */  			switch (src_data) {  			case 0: diff --git a/drivers/gpu/drm/radeon/r600_dma.c b/drivers/gpu/drm/radeon/r600_dma.c index 53fcb28f5578..4969cef44a19 100644 --- a/drivers/gpu/drm/radeon/r600_dma.c +++ b/drivers/gpu/drm/radeon/r600_dma.c @@ -489,6 +489,7 @@ int r600_copy_dma(struct radeon_device *rdev,  	r = radeon_fence_emit(rdev, fence, ring->idx);  	if (r) {  		radeon_ring_unlock_undo(rdev, ring); +		radeon_semaphore_free(rdev, &sem, NULL);  		return r;  	} diff --git a/drivers/gpu/drm/radeon/r600_dpm.c b/drivers/gpu/drm/radeon/r600_dpm.c index cbf7e3269f84..9c61b74ef441 100644 --- a/drivers/gpu/drm/radeon/r600_dpm.c +++ b/drivers/gpu/drm/radeon/r600_dpm.c @@ -158,16 +158,18 @@ u32 r600_dpm_get_vblank_time(struct radeon_device *rdev)  	u32 line_time_us, vblank_lines;  	u32 vblank_time_us = 0xffffffff; /* if the displays are off, vblank time is max */ -	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { -		radeon_crtc = to_radeon_crtc(crtc); -		if (crtc->enabled && radeon_crtc->enabled && radeon_crtc->hw_mode.clock) { -			line_time_us = (radeon_crtc->hw_mode.crtc_htotal * 1000) / -				radeon_crtc->hw_mode.clock; -			vblank_lines = radeon_crtc->hw_mode.crtc_vblank_end - -				radeon_crtc->hw_mode.crtc_vdisplay + -				(radeon_crtc->v_border * 2); -			vblank_time_us = vblank_lines * line_time_us; -			break; +	if (rdev->num_crtc && rdev->mode_info.mode_config_initialized) { +		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { +			radeon_crtc = to_radeon_crtc(crtc); +			if (crtc->enabled && radeon_crtc->enabled && radeon_crtc->hw_mode.clock) { +				line_time_us = (radeon_crtc->hw_mode.crtc_htotal * 1000) / +					radeon_crtc->hw_mode.clock; +				vblank_lines = radeon_crtc->hw_mode.crtc_vblank_end - +					radeon_crtc->hw_mode.crtc_vdisplay + +					(radeon_crtc->v_border * 2); +				vblank_time_us = vblank_lines * line_time_us; +				break; +			}  		}  	} @@ -181,14 +183,15 @@ u32 r600_dpm_get_vrefresh(struct radeon_device *rdev)  	struct radeon_crtc *radeon_crtc;  	u32 vrefresh = 0; -	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { -		radeon_crtc = to_radeon_crtc(crtc); -		if (crtc->enabled && radeon_crtc->enabled && radeon_crtc->hw_mode.clock) { -			vrefresh = radeon_crtc->hw_mode.vrefresh; -			break; +	if (rdev->num_crtc && rdev->mode_info.mode_config_initialized) { +		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { +			radeon_crtc = to_radeon_crtc(crtc); +			if (crtc->enabled && radeon_crtc->enabled && radeon_crtc->hw_mode.clock) { +				vrefresh = radeon_crtc->hw_mode.vrefresh; +				break; +			}  		}  	} -  	return vrefresh;  } diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index f21db7a0b34d..68528619834a 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -730,6 +730,12 @@ struct cik_irq_stat_regs {  	u32 disp_int_cont4;  	u32 disp_int_cont5;  	u32 disp_int_cont6; +	u32 d1grph_int; +	u32 d2grph_int; +	u32 d3grph_int; +	u32 d4grph_int; +	u32 d5grph_int; +	u32 d6grph_int;  };  union radeon_irq_stat_regs { @@ -739,7 +745,7 @@ union radeon_irq_stat_regs {  	struct cik_irq_stat_regs cik;  }; -#define RADEON_MAX_HPD_PINS 6 +#define RADEON_MAX_HPD_PINS 7  #define RADEON_MAX_CRTCS 6  #define RADEON_MAX_AFMT_BLOCKS 7 @@ -2321,6 +2327,7 @@ struct radeon_device {  	bool have_disp_power_ref;  }; +bool radeon_is_px(struct drm_device *dev);  int radeon_device_init(struct radeon_device *rdev,  		       struct drm_device *ddev,  		       struct pci_dev *pdev, @@ -2631,6 +2638,9 @@ void r100_pll_errata_after_index(struct radeon_device *rdev);  #define ASIC_IS_DCE64(rdev) ((rdev->family == CHIP_OLAND))  #define ASIC_IS_NODCE(rdev) ((rdev->family == CHIP_HAINAN))  #define ASIC_IS_DCE8(rdev) ((rdev->family >= CHIP_BONAIRE)) +#define ASIC_IS_DCE81(rdev) ((rdev->family == CHIP_KAVERI)) +#define ASIC_IS_DCE82(rdev) ((rdev->family == CHIP_BONAIRE)) +#define ASIC_IS_DCE83(rdev) ((rdev->family == CHIP_KABINI))  #define ASIC_IS_LOMBOK(rdev) ((rdev->ddev->pdev->device == 0x6849) || \  			      (rdev->ddev->pdev->device == 0x6850) || \ diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index b8a24a75d4ff..be20e62dac83 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -2516,6 +2516,7 @@ int radeon_asic_init(struct radeon_device *rdev)  		break;  	case CHIP_KAVERI:  	case CHIP_KABINI: +	case CHIP_MULLINS:  		rdev->asic = &kv_asic;  		/* set num crtcs */  		if (rdev->family == CHIP_KAVERI) { diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c index fa9a9c02751e..a9fb0d016d38 100644 --- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c +++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c @@ -59,7 +59,7 @@ struct atpx_mux {  	u16 mux;  } __packed; -bool radeon_is_px(void) { +bool radeon_has_atpx(void) {  	return radeon_atpx_priv.atpx_detected;  } @@ -528,6 +528,13 @@ static bool radeon_atpx_detect(void)  		has_atpx |= (radeon_atpx_pci_probe_handle(pdev) == true);  	} +	/* some newer PX laptops mark the dGPU as a non-VGA display device */ +	while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) { +		vga_count++; + +		has_atpx |= (radeon_atpx_pci_probe_handle(pdev) == true); +	} +  	if (has_atpx && vga_count == 2) {  		acpi_get_name(radeon_atpx_priv.atpx.handle, ACPI_FULL_PATHNAME, &buffer);  		printk(KERN_INFO "VGA switcheroo: detected switching method %s handle\n", diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index c566b486ca08..ea50e0ae7bf7 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -1261,21 +1261,6 @@ static const struct drm_connector_funcs radeon_dvi_connector_funcs = {  	.force = radeon_dvi_force,  }; -static void radeon_dp_connector_destroy(struct drm_connector *connector) -{ -	struct radeon_connector *radeon_connector = to_radeon_connector(connector); -	struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; - -	if (radeon_connector->edid) -		kfree(radeon_connector->edid); -	if (radeon_dig_connector->dp_i2c_bus) -		radeon_i2c_destroy(radeon_dig_connector->dp_i2c_bus); -	kfree(radeon_connector->con_priv); -	drm_sysfs_connector_remove(connector); -	drm_connector_cleanup(connector); -	kfree(connector); -} -  static int radeon_dp_get_modes(struct drm_connector *connector)  {  	struct radeon_connector *radeon_connector = to_radeon_connector(connector); @@ -1553,7 +1538,7 @@ static const struct drm_connector_funcs radeon_dp_connector_funcs = {  	.detect = radeon_dp_detect,  	.fill_modes = drm_helper_probe_single_connector_modes,  	.set_property = radeon_connector_set_property, -	.destroy = radeon_dp_connector_destroy, +	.destroy = radeon_connector_destroy,  	.force = radeon_dvi_force,  }; @@ -1562,7 +1547,7 @@ static const struct drm_connector_funcs radeon_edp_connector_funcs = {  	.detect = radeon_dp_detect,  	.fill_modes = drm_helper_probe_single_connector_modes,  	.set_property = radeon_lvds_set_property, -	.destroy = radeon_dp_connector_destroy, +	.destroy = radeon_connector_destroy,  	.force = radeon_dvi_force,  }; @@ -1571,7 +1556,7 @@ static const struct drm_connector_funcs radeon_lvds_bridge_connector_funcs = {  	.detect = radeon_dp_detect,  	.fill_modes = drm_helper_probe_single_connector_modes,  	.set_property = radeon_lvds_set_property, -	.destroy = radeon_dp_connector_destroy, +	.destroy = radeon_connector_destroy,  	.force = radeon_dvi_force,  }; @@ -1668,17 +1653,10 @@ radeon_add_atom_connector(struct drm_device *dev,  		radeon_dig_connector->igp_lane_info = igp_lane_info;  		radeon_connector->con_priv = radeon_dig_connector;  		if (i2c_bus->valid) { -			/* add DP i2c bus */ -			if (connector_type == DRM_MODE_CONNECTOR_eDP) -				radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch"); -			else -				radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch"); -			if (radeon_dig_connector->dp_i2c_bus) +			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); +			if (radeon_connector->ddc_bus)  				has_aux = true;  			else -				DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n"); -			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); -			if (!radeon_connector->ddc_bus)  				DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");  		}  		switch (connector_type) { @@ -1893,10 +1871,6 @@ radeon_add_atom_connector(struct drm_device *dev,  			drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type);  			drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);  			if (i2c_bus->valid) { -				/* add DP i2c bus */ -				radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch"); -				if (!radeon_dig_connector->dp_i2c_bus) -					DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");  				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);  				if (radeon_connector->ddc_bus)  					has_aux = true; @@ -1942,14 +1916,10 @@ radeon_add_atom_connector(struct drm_device *dev,  			drm_connector_init(dev, &radeon_connector->base, &radeon_edp_connector_funcs, connector_type);  			drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);  			if (i2c_bus->valid) { -				/* add DP i2c bus */ -				radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch"); -				if (radeon_dig_connector->dp_i2c_bus) +				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); +				if (radeon_connector->ddc_bus)  					has_aux = true;  				else -					DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n"); -				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); -				if (!radeon_connector->ddc_bus)  					DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");  			}  			drm_object_attach_property(&radeon_connector->base.base, diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 835516d2d257..0e770bbf7e29 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -99,14 +99,18 @@ static const char radeon_family_name[][16] = {  	"KAVERI",  	"KABINI",  	"HAWAII", +	"MULLINS",  	"LAST",  }; -#if defined(CONFIG_VGA_SWITCHEROO) -bool radeon_is_px(void); -#else -static inline bool radeon_is_px(void) { return false; } -#endif +bool radeon_is_px(struct drm_device *dev) +{ +	struct radeon_device *rdev = dev->dev_private; + +	if (rdev->flags & RADEON_IS_PX) +		return true; +	return false; +}  /**   * radeon_program_register_sequence - program an array of registers. @@ -1082,7 +1086,7 @@ static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero  {  	struct drm_device *dev = pci_get_drvdata(pdev); -	if (radeon_is_px() && state == VGA_SWITCHEROO_OFF) +	if (radeon_is_px(dev) && state == VGA_SWITCHEROO_OFF)  		return;  	if (state == VGA_SWITCHEROO_ON) { @@ -1301,9 +1305,7 @@ int radeon_device_init(struct radeon_device *rdev,  	 * ignore it */  	vga_client_register(rdev->pdev, rdev, NULL, radeon_vga_set_decode); -	if (radeon_runtime_pm == 1) -		runtime = true; -	if ((radeon_runtime_pm == -1) && radeon_is_px()) +	if (rdev->flags & RADEON_IS_PX)  		runtime = true;  	vga_switcheroo_register_client(rdev->pdev, &radeon_switcheroo_ops, runtime);  	if (runtime) diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 386cfa4c194d..408b6ac53f0b 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -284,6 +284,10 @@ void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id)  	u32 update_pending;  	int vpos, hpos; +	/* can happen during initialization */ +	if (radeon_crtc == NULL) +		return; +  	spin_lock_irqsave(&rdev->ddev->event_lock, flags);  	work = radeon_crtc->unpin_work;  	if (work == NULL || @@ -759,19 +763,18 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)  	if (radeon_connector_encoder_get_dp_bridge_encoder_id(&radeon_connector->base) !=  	    ENCODER_OBJECT_ID_NONE) { -		struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; - -		if (dig->dp_i2c_bus) +		if (radeon_connector->ddc_bus->has_aux)  			radeon_connector->edid = drm_get_edid(&radeon_connector->base, -							      &dig->dp_i2c_bus->adapter); +							      &radeon_connector->ddc_bus->aux.ddc);  	} else if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||  		   (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) {  		struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;  		if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT || -		     dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) && dig->dp_i2c_bus) +		     dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) && +		    radeon_connector->ddc_bus->has_aux)  			radeon_connector->edid = drm_get_edid(&radeon_connector->base, -							      &dig->dp_i2c_bus->adapter); +							      &radeon_connector->ddc_bus->aux.ddc);  		else if (radeon_connector->ddc_bus && !radeon_connector->edid)  			radeon_connector->edid = drm_get_edid(&radeon_connector->base,  							      &radeon_connector->ddc_bus->adapter); @@ -827,20 +830,52 @@ static void avivo_reduce_ratio(unsigned *nom, unsigned *den,  	/* make sure nominator is large enough */          if (*nom < nom_min) { -		tmp = (nom_min + *nom - 1) / *nom; +		tmp = DIV_ROUND_UP(nom_min, *nom);  		*nom *= tmp;  		*den *= tmp;  	}  	/* make sure the denominator is large enough */  	if (*den < den_min) { -		tmp = (den_min + *den - 1) / *den; +		tmp = DIV_ROUND_UP(den_min, *den);  		*nom *= tmp;  		*den *= tmp;  	}  }  /** + * avivo_get_fb_ref_div - feedback and ref divider calculation + * + * @nom: nominator + * @den: denominator + * @post_div: post divider + * @fb_div_max: feedback divider maximum + * @ref_div_max: reference divider maximum + * @fb_div: resulting feedback divider + * @ref_div: resulting reference divider + * + * Calculate feedback and reference divider for a given post divider. Makes + * sure we stay within the limits. + */ +static void avivo_get_fb_ref_div(unsigned nom, unsigned den, unsigned post_div, +				 unsigned fb_div_max, unsigned ref_div_max, +				 unsigned *fb_div, unsigned *ref_div) +{ +	/* limit reference * post divider to a maximum */ +	ref_div_max = min(128 / post_div, ref_div_max); + +	/* get matching reference and feedback divider */ +	*ref_div = min(max(DIV_ROUND_CLOSEST(den, post_div), 1u), ref_div_max); +	*fb_div = DIV_ROUND_CLOSEST(nom * *ref_div * post_div, den); + +	/* limit fb divider to its maximum */ +        if (*fb_div > fb_div_max) { +		*ref_div = DIV_ROUND_CLOSEST(*ref_div * fb_div_max, *fb_div); +		*fb_div = fb_div_max; +	} +} + +/**   * radeon_compute_pll_avivo - compute PLL paramaters   *   * @pll: information about the PLL @@ -861,11 +896,14 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll,  			      u32 *ref_div_p,  			      u32 *post_div_p)  { +	unsigned target_clock = pll->flags & RADEON_PLL_USE_FRAC_FB_DIV ? +		freq : freq / 10; +  	unsigned fb_div_min, fb_div_max, fb_div;  	unsigned post_div_min, post_div_max, post_div;  	unsigned ref_div_min, ref_div_max, ref_div;  	unsigned post_div_best, diff_best; -	unsigned nom, den, tmp; +	unsigned nom, den;  	/* determine allowed feedback divider range */  	fb_div_min = pll->min_feedback_div; @@ -881,14 +919,18 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll,  		ref_div_min = pll->reference_div;  	else  		ref_div_min = pll->min_ref_div; -	ref_div_max = pll->max_ref_div; + +	if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV && +	    pll->flags & RADEON_PLL_USE_REF_DIV) +		ref_div_max = pll->reference_div; +	else +		ref_div_max = pll->max_ref_div;  	/* determine allowed post divider range */  	if (pll->flags & RADEON_PLL_USE_POST_DIV) {  		post_div_min = pll->post_div;  		post_div_max = pll->post_div;  	} else { -		unsigned target_clock = freq / 10;  		unsigned vco_min, vco_max;  		if (pll->flags & RADEON_PLL_IS_LCD) { @@ -899,6 +941,11 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll,  			vco_max = pll->pll_out_max;  		} +		if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) { +			vco_min *= 10; +			vco_max *= 10; +		} +  		post_div_min = vco_min / target_clock;  		if ((target_clock * post_div_min) < vco_min)  			++post_div_min; @@ -913,7 +960,7 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll,  	}  	/* represent the searched ratio as fractional number */ -	nom = pll->flags & RADEON_PLL_USE_FRAC_FB_DIV ? freq : freq / 10; +	nom = target_clock;  	den = pll->reference_freq;  	/* reduce the numbers to a simpler ratio */ @@ -927,7 +974,12 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll,  	diff_best = ~0;  	for (post_div = post_div_min; post_div <= post_div_max; ++post_div) { -		unsigned diff = abs(den - den / post_div * post_div); +		unsigned diff; +		avivo_get_fb_ref_div(nom, den, post_div, fb_div_max, +				     ref_div_max, &fb_div, &ref_div); +		diff = abs(target_clock - (pll->reference_freq * fb_div) / +			(ref_div * post_div)); +  		if (diff < diff_best || (diff == diff_best &&  		    !(pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP))) { @@ -937,29 +989,24 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll,  	}  	post_div = post_div_best; -	/* get matching reference and feedback divider */ -	ref_div = max(den / post_div, 1u); -	fb_div = nom; - -	/* we're almost done, but reference and feedback -	   divider might be to large now */ - -	tmp = ref_div; - -        if (fb_div > fb_div_max) { -		ref_div = ref_div * fb_div_max / fb_div; -		fb_div = fb_div_max; -	} - -	if (ref_div > ref_div_max) { -		ref_div = ref_div_max; -		fb_div = nom * ref_div_max / tmp; -	} +	/* get the feedback and reference divider for the optimal value */ +	avivo_get_fb_ref_div(nom, den, post_div, fb_div_max, ref_div_max, +			     &fb_div, &ref_div);  	/* reduce the numbers to a simpler ratio once more */  	/* this also makes sure that the reference divider is large enough */  	avivo_reduce_ratio(&fb_div, &ref_div, fb_div_min, ref_div_min); +	/* avoid high jitter with small fractional dividers */ +	if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV && (fb_div % 10)) { +		fb_div_min = max(fb_div_min, (9 - (fb_div % 10)) * 20 + 60); +		if (fb_div < fb_div_min) { +			unsigned tmp = DIV_ROUND_UP(fb_div_min, fb_div); +			fb_div *= tmp; +			ref_div *= tmp; +		} +	} +  	/* and finally save the result */  	if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) {  		*fb_div_p = fb_div / 10; @@ -976,7 +1023,7 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll,  	*post_div_p = post_div;  	DRM_DEBUG_KMS("%d - %d, pll dividers - fb: %d.%d ref: %d, post %d\n", -		      freq, *dot_clock_p, *fb_div_p, *frac_fb_div_p, +		      freq, *dot_clock_p * 10, *fb_div_p, *frac_fb_div_p,  		      ref_div, post_div);  } diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index d0eba48dd74e..c00a2f585185 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -115,6 +115,7 @@ extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc,  				      unsigned int flags,  				      int *vpos, int *hpos, ktime_t *stime,  				      ktime_t *etime); +extern bool radeon_is_px(struct drm_device *dev);  extern const struct drm_ioctl_desc radeon_ioctls_kms[];  extern int radeon_max_kms_ioctl;  int radeon_mmap(struct file *filp, struct vm_area_struct *vma); @@ -144,11 +145,9 @@ void radeon_debugfs_cleanup(struct drm_minor *minor);  #if defined(CONFIG_VGA_SWITCHEROO)  void radeon_register_atpx_handler(void);  void radeon_unregister_atpx_handler(void); -bool radeon_is_px(void);  #else  static inline void radeon_register_atpx_handler(void) {}  static inline void radeon_unregister_atpx_handler(void) {} -static inline bool radeon_is_px(void) { return false; }  #endif  int radeon_no_wb; @@ -186,7 +185,7 @@ module_param_named(dynclks, radeon_dynclks, int, 0444);  MODULE_PARM_DESC(r4xx_atom, "Enable ATOMBIOS modesetting for R4xx");  module_param_named(r4xx_atom, radeon_r4xx_atom, int, 0444); -MODULE_PARM_DESC(vramlimit, "Restrict VRAM for testing"); +MODULE_PARM_DESC(vramlimit, "Restrict VRAM for testing, in megabytes");  module_param_named(vramlimit, radeon_vram_limit, int, 0600);  MODULE_PARM_DESC(agpmode, "AGP Mode (-1 == PCI)"); @@ -405,12 +404,7 @@ static int radeon_pmops_runtime_suspend(struct device *dev)  	struct drm_device *drm_dev = pci_get_drvdata(pdev);  	int ret; -	if (radeon_runtime_pm == 0) { -		pm_runtime_forbid(dev); -		return -EBUSY; -	} - -	if (radeon_runtime_pm == -1 && !radeon_is_px()) { +	if (!radeon_is_px(drm_dev)) {  		pm_runtime_forbid(dev);  		return -EBUSY;  	} @@ -434,10 +428,7 @@ static int radeon_pmops_runtime_resume(struct device *dev)  	struct drm_device *drm_dev = pci_get_drvdata(pdev);  	int ret; -	if (radeon_runtime_pm == 0) -		return -EINVAL; - -	if (radeon_runtime_pm == -1 && !radeon_is_px()) +	if (!radeon_is_px(drm_dev))  		return -EINVAL;  	drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; @@ -462,14 +453,7 @@ static int radeon_pmops_runtime_idle(struct device *dev)  	struct drm_device *drm_dev = pci_get_drvdata(pdev);  	struct drm_crtc *crtc; -	if (radeon_runtime_pm == 0) { -		pm_runtime_forbid(dev); -		return -EBUSY; -	} - -	/* are we PX enabled? */ -	if (radeon_runtime_pm == -1 && !radeon_is_px()) { -		DRM_DEBUG_DRIVER("failing to power off - not px\n"); +	if (!radeon_is_px(drm_dev)) {  		pm_runtime_forbid(dev);  		return -EBUSY;  	} diff --git a/drivers/gpu/drm/radeon/radeon_family.h b/drivers/gpu/drm/radeon/radeon_family.h index 614ad549297f..4b7b87f71a63 100644 --- a/drivers/gpu/drm/radeon/radeon_family.h +++ b/drivers/gpu/drm/radeon/radeon_family.h @@ -97,6 +97,7 @@ enum radeon_family {  	CHIP_KAVERI,  	CHIP_KABINI,  	CHIP_HAWAII, +	CHIP_MULLINS,  	CHIP_LAST,  }; @@ -115,6 +116,7 @@ enum radeon_chip_flags {  	RADEON_NEW_MEMMAP = 0x00400000UL,  	RADEON_IS_PCI = 0x00800000UL,  	RADEON_IS_IGPGART = 0x01000000UL, +	RADEON_IS_PX = 0x02000000UL,  };  #endif diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index e24ca6ab96de..7b944142a9fd 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -64,8 +64,7 @@ bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool use_aux)  		radeon_router_select_ddc_port(radeon_connector);  	if (use_aux) { -		struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; -		ret = i2c_transfer(&dig->dp_i2c_bus->adapter, msgs, 2); +		ret = i2c_transfer(&radeon_connector->ddc_bus->aux.ddc, msgs, 2);  	} else {  		ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2);  	} @@ -950,16 +949,16 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,  		/* set the radeon bit adapter */  		snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),  			 "Radeon i2c bit bus %s", name); -		i2c->adapter.algo_data = &i2c->algo.bit; -		i2c->algo.bit.pre_xfer = pre_xfer; -		i2c->algo.bit.post_xfer = post_xfer; -		i2c->algo.bit.setsda = set_data; -		i2c->algo.bit.setscl = set_clock; -		i2c->algo.bit.getsda = get_data; -		i2c->algo.bit.getscl = get_clock; -		i2c->algo.bit.udelay = 10; -		i2c->algo.bit.timeout = usecs_to_jiffies(2200);	/* from VESA */ -		i2c->algo.bit.data = i2c; +		i2c->adapter.algo_data = &i2c->bit; +		i2c->bit.pre_xfer = pre_xfer; +		i2c->bit.post_xfer = post_xfer; +		i2c->bit.setsda = set_data; +		i2c->bit.setscl = set_clock; +		i2c->bit.getsda = get_data; +		i2c->bit.getscl = get_clock; +		i2c->bit.udelay = 10; +		i2c->bit.timeout = usecs_to_jiffies(2200);	/* from VESA */ +		i2c->bit.data = i2c;  		ret = i2c_bit_add_bus(&i2c->adapter);  		if (ret) {  			DRM_ERROR("Failed to register bit i2c %s\n", name); @@ -974,46 +973,13 @@ out_free:  } -struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev, -					     struct radeon_i2c_bus_rec *rec, -					     const char *name) -{ -	struct radeon_i2c_chan *i2c; -	int ret; - -	i2c = kzalloc(sizeof(struct radeon_i2c_chan), GFP_KERNEL); -	if (i2c == NULL) -		return NULL; - -	i2c->rec = *rec; -	i2c->adapter.owner = THIS_MODULE; -	i2c->adapter.class = I2C_CLASS_DDC; -	i2c->adapter.dev.parent = &dev->pdev->dev; -	i2c->dev = dev; -	snprintf(i2c->adapter.name, sizeof(i2c->adapter.name), -		 "Radeon aux bus %s", name); -	i2c_set_adapdata(&i2c->adapter, i2c); -	i2c->adapter.algo_data = &i2c->algo.dp; -	i2c->algo.dp.aux_ch = radeon_dp_i2c_aux_ch; -	i2c->algo.dp.address = 0; -	ret = i2c_dp_aux_add_bus(&i2c->adapter); -	if (ret) { -		DRM_INFO("Failed to register i2c %s\n", name); -		goto out_free; -	} - -	return i2c; -out_free: -	kfree(i2c); -	return NULL; - -} -  void radeon_i2c_destroy(struct radeon_i2c_chan *i2c)  {  	if (!i2c)  		return;  	i2c_del_adapter(&i2c->adapter); +	if (i2c->has_aux) +		drm_dp_aux_unregister_i2c_bus(&i2c->aux);  	kfree(i2c);  } diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 3e49342a20e6..0cc47f12d995 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -35,9 +35,9 @@  #include <linux/pm_runtime.h>  #if defined(CONFIG_VGA_SWITCHEROO) -bool radeon_is_px(void); +bool radeon_has_atpx(void);  #else -static inline bool radeon_is_px(void) { return false; } +static inline bool radeon_has_atpx(void) { return false; }  #endif  /** @@ -107,6 +107,11 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags)  		flags |= RADEON_IS_PCI;  	} +	if ((radeon_runtime_pm != 0) && +	    radeon_has_atpx() && +	    ((flags & RADEON_IS_IGP) == 0)) +		flags |= RADEON_IS_PX; +  	/* radeon_device_init should report only fatal error  	 * like memory allocation failure or iomapping failure,  	 * or memory manager initialization failure, it must @@ -137,8 +142,7 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags)  				"Error during ACPI methods call\n");  	} -	if ((radeon_runtime_pm == 1) || -	    ((radeon_runtime_pm == -1) && radeon_is_px())) { +	if (radeon_is_px(dev)) {  		pm_runtime_use_autosuspend(dev->dev);  		pm_runtime_set_autosuspend_delay(dev->dev, 5000);  		pm_runtime_set_active(dev->dev); @@ -568,12 +572,17 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)  		}  		r = radeon_vm_init(rdev, &fpriv->vm); -		if (r) +		if (r) { +			kfree(fpriv);  			return r; +		}  		r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false); -		if (r) +		if (r) { +			radeon_vm_fini(rdev, &fpriv->vm); +			kfree(fpriv);  			return r; +		}  		/* map the ib pool buffer read only into  		 * virtual address space */ diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 832d9fa1a4c4..6ddf31a2d34e 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -187,12 +187,10 @@ struct radeon_pll {  struct radeon_i2c_chan {  	struct i2c_adapter adapter;  	struct drm_device *dev; -	union { -		struct i2c_algo_bit_data bit; -		struct i2c_algo_dp_aux_data dp; -	} algo; +	struct i2c_algo_bit_data bit;  	struct radeon_i2c_bus_rec rec;  	struct drm_dp_aux aux; +	bool has_aux;  };  /* mostly for macs, but really any system without connector tables */ @@ -440,7 +438,6 @@ struct radeon_encoder {  struct radeon_connector_atom_dig {  	uint32_t igp_lane_info;  	/* displayport */ -	struct radeon_i2c_chan *dp_i2c_bus;  	u8 dpcd[DP_RECEIVER_CAP_SIZE];  	u8 dp_sink_type;  	int dp_clock; @@ -702,8 +699,6 @@ extern void atombios_dig_transmitter_setup(struct drm_encoder *encoder,  					   uint8_t lane_set);  extern void radeon_atom_ext_encoder_setup_ddc(struct drm_encoder *encoder);  extern struct drm_encoder *radeon_get_external_encoder(struct drm_encoder *encoder); -extern int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, -				u8 write_byte, u8 *read_byte);  void radeon_atom_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le);  extern void radeon_i2c_init(struct radeon_device *rdev); @@ -715,9 +710,6 @@ extern void radeon_i2c_add(struct radeon_device *rdev,  			   const char *name);  extern struct radeon_i2c_chan *radeon_i2c_lookup(struct radeon_device *rdev,  						 struct radeon_i2c_bus_rec *i2c_bus); -extern struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev, -						    struct radeon_i2c_bus_rec *rec, -						    const char *name);  extern struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,  						 struct radeon_i2c_bus_rec *rec,  						 const char *name); diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index ee738a524639..f30b8426eee2 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -603,7 +603,6 @@ static const struct attribute_group *hwmon_groups[] = {  static int radeon_hwmon_init(struct radeon_device *rdev)  {  	int err = 0; -	struct device *hwmon_dev;  	switch (rdev->pm.int_thermal_type) {  	case THERMAL_TYPE_RV6XX: @@ -616,11 +615,11 @@ static int radeon_hwmon_init(struct radeon_device *rdev)  	case THERMAL_TYPE_KV:  		if (rdev->asic->pm.get_temperature == NULL)  			return err; -		hwmon_dev = hwmon_device_register_with_groups(rdev->dev, -							      "radeon", rdev, -							      hwmon_groups); -		if (IS_ERR(hwmon_dev)) { -			err = PTR_ERR(hwmon_dev); +		rdev->pm.int_hwmon_dev = hwmon_device_register_with_groups(rdev->dev, +									   "radeon", rdev, +									   hwmon_groups); +		if (IS_ERR(rdev->pm.int_hwmon_dev)) { +			err = PTR_ERR(rdev->pm.int_hwmon_dev);  			dev_err(rdev->dev,  				"Unable to register hwmon device: %d\n", err);  		} @@ -632,6 +631,12 @@ static int radeon_hwmon_init(struct radeon_device *rdev)  	return err;  } +static void radeon_hwmon_fini(struct radeon_device *rdev) +{ +	if (rdev->pm.int_hwmon_dev) +		hwmon_device_unregister(rdev->pm.int_hwmon_dev); +} +  static void radeon_dpm_thermal_work_handler(struct work_struct *work)  {  	struct radeon_device *rdev = @@ -1257,6 +1262,7 @@ int radeon_pm_init(struct radeon_device *rdev)  	case CHIP_RV670:  	case CHIP_RS780:  	case CHIP_RS880: +	case CHIP_RV770:  	case CHIP_BARTS:  	case CHIP_TURKS:  	case CHIP_CAICOS: @@ -1273,7 +1279,6 @@ int radeon_pm_init(struct radeon_device *rdev)  		else  			rdev->pm.pm_method = PM_METHOD_PROFILE;  		break; -	case CHIP_RV770:  	case CHIP_RV730:  	case CHIP_RV710:  	case CHIP_RV740: @@ -1295,6 +1300,7 @@ int radeon_pm_init(struct radeon_device *rdev)  	case CHIP_KABINI:  	case CHIP_KAVERI:  	case CHIP_HAWAII: +	case CHIP_MULLINS:  		/* DPM requires the RLC, RV770+ dGPU requires SMC */  		if (!rdev->rlc_fw)  			rdev->pm.pm_method = PM_METHOD_PROFILE; @@ -1353,6 +1359,8 @@ static void radeon_pm_fini_old(struct radeon_device *rdev)  		device_remove_file(rdev->dev, &dev_attr_power_method);  	} +	radeon_hwmon_fini(rdev); +  	if (rdev->pm.power_state)  		kfree(rdev->pm.power_state);  } @@ -1372,6 +1380,8 @@ static void radeon_pm_fini_dpm(struct radeon_device *rdev)  	}  	radeon_dpm_fini(rdev); +	radeon_hwmon_fini(rdev); +  	if (rdev->pm.power_state)  		kfree(rdev->pm.power_state);  } @@ -1397,12 +1407,14 @@ static void radeon_pm_compute_clocks_old(struct radeon_device *rdev)  	rdev->pm.active_crtcs = 0;  	rdev->pm.active_crtc_count = 0; -	list_for_each_entry(crtc, -		&ddev->mode_config.crtc_list, head) { -		radeon_crtc = to_radeon_crtc(crtc); -		if (radeon_crtc->enabled) { -			rdev->pm.active_crtcs |= (1 << radeon_crtc->crtc_id); -			rdev->pm.active_crtc_count++; +	if (rdev->num_crtc && rdev->mode_info.mode_config_initialized) { +		list_for_each_entry(crtc, +				    &ddev->mode_config.crtc_list, head) { +			radeon_crtc = to_radeon_crtc(crtc); +			if (radeon_crtc->enabled) { +				rdev->pm.active_crtcs |= (1 << radeon_crtc->crtc_id); +				rdev->pm.active_crtc_count++; +			}  		}  	} @@ -1469,12 +1481,14 @@ static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev)  	/* update active crtc counts */  	rdev->pm.dpm.new_active_crtcs = 0;  	rdev->pm.dpm.new_active_crtc_count = 0; -	list_for_each_entry(crtc, -		&ddev->mode_config.crtc_list, head) { -		radeon_crtc = to_radeon_crtc(crtc); -		if (crtc->enabled) { -			rdev->pm.dpm.new_active_crtcs |= (1 << radeon_crtc->crtc_id); -			rdev->pm.dpm.new_active_crtc_count++; +	if (rdev->num_crtc && rdev->mode_info.mode_config_initialized) { +		list_for_each_entry(crtc, +				    &ddev->mode_config.crtc_list, head) { +			radeon_crtc = to_radeon_crtc(crtc); +			if (crtc->enabled) { +				rdev->pm.dpm.new_active_crtcs |= (1 << radeon_crtc->crtc_id); +				rdev->pm.dpm.new_active_crtc_count++; +			}  		}  	} diff --git a/drivers/gpu/drm/radeon/radeon_ucode.h b/drivers/gpu/drm/radeon/radeon_ucode.h index a77cd274dfc3..4e7c3269b183 100644 --- a/drivers/gpu/drm/radeon/radeon_ucode.h +++ b/drivers/gpu/drm/radeon/radeon_ucode.h @@ -52,14 +52,20 @@  #define BONAIRE_RLC_UCODE_SIZE       2048  #define KB_RLC_UCODE_SIZE            2560  #define KV_RLC_UCODE_SIZE            2560 +#define ML_RLC_UCODE_SIZE            2560  /* MC */  #define BTC_MC_UCODE_SIZE            6024  #define CAYMAN_MC_UCODE_SIZE         6037  #define SI_MC_UCODE_SIZE             7769 +#define TAHITI_MC_UCODE_SIZE         7808 +#define PITCAIRN_MC_UCODE_SIZE       7775 +#define VERDE_MC_UCODE_SIZE          7875  #define OLAND_MC_UCODE_SIZE          7863 -#define CIK_MC_UCODE_SIZE            7866 +#define BONAIRE_MC_UCODE_SIZE        7866 +#define BONAIRE_MC2_UCODE_SIZE       7948  #define HAWAII_MC_UCODE_SIZE         7933 +#define HAWAII_MC2_UCODE_SIZE        8091  /* SDMA */  #define CIK_SDMA_UCODE_SIZE          1050 diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index 5748bdaeacce..1b65ae2433cd 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c @@ -99,6 +99,7 @@ int radeon_uvd_init(struct radeon_device *rdev)  	case CHIP_KABINI:  	case CHIP_KAVERI:  	case CHIP_HAWAII: +	case CHIP_MULLINS:  		fw_name = FIRMWARE_BONAIRE;  		break; @@ -465,6 +466,10 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,  	cmd = radeon_get_ib_value(p, p->idx) >> 1;  	if (cmd < 0x4) { +		if (end <= start) { +			DRM_ERROR("invalid reloc offset %X!\n", offset); +			return -EINVAL; +		}  		if ((end - start) < buf_sizes[cmd]) {  			DRM_ERROR("buffer (%d) to small (%d / %d)!\n", cmd,  				  (unsigned)(end - start), buf_sizes[cmd]); diff --git a/drivers/gpu/drm/radeon/radeon_vce.c b/drivers/gpu/drm/radeon/radeon_vce.c index 76e9904bc537..f73324c81491 100644 --- a/drivers/gpu/drm/radeon/radeon_vce.c +++ b/drivers/gpu/drm/radeon/radeon_vce.c @@ -66,6 +66,7 @@ int radeon_vce_init(struct radeon_device *rdev)  	case CHIP_BONAIRE:  	case CHIP_KAVERI:  	case CHIP_KABINI: +	case CHIP_MULLINS:  		fw_name = FIRMWARE_BONAIRE;  		break; @@ -613,7 +614,7 @@ void radeon_vce_fence_emit(struct radeon_device *rdev,  			   struct radeon_fence *fence)  {  	struct radeon_ring *ring = &rdev->ring[fence->ring]; -	uint32_t addr = rdev->fence_drv[fence->ring].gpu_addr; +	uint64_t addr = rdev->fence_drv[fence->ring].gpu_addr;  	radeon_ring_write(ring, VCE_CMD_FENCE);  	radeon_ring_write(ring, addr); diff --git a/drivers/gpu/drm/radeon/rv770_dma.c b/drivers/gpu/drm/radeon/rv770_dma.c index aca8cbe8a335..bbf2e076ee45 100644 --- a/drivers/gpu/drm/radeon/rv770_dma.c +++ b/drivers/gpu/drm/radeon/rv770_dma.c @@ -86,6 +86,7 @@ int rv770_copy_dma(struct radeon_device *rdev,  	r = radeon_fence_emit(rdev, fence, ring->idx);  	if (r) {  		radeon_ring_unlock_undo(rdev, ring); +		radeon_semaphore_free(rdev, &sem, NULL);  		return r;  	} diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index d589475fe9e6..22a63c98ba14 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -39,30 +39,35 @@ MODULE_FIRMWARE("radeon/TAHITI_pfp.bin");  MODULE_FIRMWARE("radeon/TAHITI_me.bin");  MODULE_FIRMWARE("radeon/TAHITI_ce.bin");  MODULE_FIRMWARE("radeon/TAHITI_mc.bin"); +MODULE_FIRMWARE("radeon/TAHITI_mc2.bin");  MODULE_FIRMWARE("radeon/TAHITI_rlc.bin");  MODULE_FIRMWARE("radeon/TAHITI_smc.bin");  MODULE_FIRMWARE("radeon/PITCAIRN_pfp.bin");  MODULE_FIRMWARE("radeon/PITCAIRN_me.bin");  MODULE_FIRMWARE("radeon/PITCAIRN_ce.bin");  MODULE_FIRMWARE("radeon/PITCAIRN_mc.bin"); +MODULE_FIRMWARE("radeon/PITCAIRN_mc2.bin");  MODULE_FIRMWARE("radeon/PITCAIRN_rlc.bin");  MODULE_FIRMWARE("radeon/PITCAIRN_smc.bin");  MODULE_FIRMWARE("radeon/VERDE_pfp.bin");  MODULE_FIRMWARE("radeon/VERDE_me.bin");  MODULE_FIRMWARE("radeon/VERDE_ce.bin");  MODULE_FIRMWARE("radeon/VERDE_mc.bin"); +MODULE_FIRMWARE("radeon/VERDE_mc2.bin");  MODULE_FIRMWARE("radeon/VERDE_rlc.bin");  MODULE_FIRMWARE("radeon/VERDE_smc.bin");  MODULE_FIRMWARE("radeon/OLAND_pfp.bin");  MODULE_FIRMWARE("radeon/OLAND_me.bin");  MODULE_FIRMWARE("radeon/OLAND_ce.bin");  MODULE_FIRMWARE("radeon/OLAND_mc.bin"); +MODULE_FIRMWARE("radeon/OLAND_mc2.bin");  MODULE_FIRMWARE("radeon/OLAND_rlc.bin");  MODULE_FIRMWARE("radeon/OLAND_smc.bin");  MODULE_FIRMWARE("radeon/HAINAN_pfp.bin");  MODULE_FIRMWARE("radeon/HAINAN_me.bin");  MODULE_FIRMWARE("radeon/HAINAN_ce.bin");  MODULE_FIRMWARE("radeon/HAINAN_mc.bin"); +MODULE_FIRMWARE("radeon/HAINAN_mc2.bin");  MODULE_FIRMWARE("radeon/HAINAN_rlc.bin");  MODULE_FIRMWARE("radeon/HAINAN_smc.bin"); @@ -1467,36 +1472,33 @@ int si_mc_load_microcode(struct radeon_device *rdev)  	const __be32 *fw_data;  	u32 running, blackout = 0;  	u32 *io_mc_regs; -	int i, ucode_size, regs_size; +	int i, regs_size, ucode_size;  	if (!rdev->mc_fw)  		return -EINVAL; +	ucode_size = rdev->mc_fw->size / 4; +  	switch (rdev->family) {  	case CHIP_TAHITI:  		io_mc_regs = (u32 *)&tahiti_io_mc_regs; -		ucode_size = SI_MC_UCODE_SIZE;  		regs_size = TAHITI_IO_MC_REGS_SIZE;  		break;  	case CHIP_PITCAIRN:  		io_mc_regs = (u32 *)&pitcairn_io_mc_regs; -		ucode_size = SI_MC_UCODE_SIZE;  		regs_size = TAHITI_IO_MC_REGS_SIZE;  		break;  	case CHIP_VERDE:  	default:  		io_mc_regs = (u32 *)&verde_io_mc_regs; -		ucode_size = SI_MC_UCODE_SIZE;  		regs_size = TAHITI_IO_MC_REGS_SIZE;  		break;  	case CHIP_OLAND:  		io_mc_regs = (u32 *)&oland_io_mc_regs; -		ucode_size = OLAND_MC_UCODE_SIZE;  		regs_size = TAHITI_IO_MC_REGS_SIZE;  		break;  	case CHIP_HAINAN:  		io_mc_regs = (u32 *)&hainan_io_mc_regs; -		ucode_size = OLAND_MC_UCODE_SIZE;  		regs_size = TAHITI_IO_MC_REGS_SIZE;  		break;  	} @@ -1552,7 +1554,7 @@ static int si_init_microcode(struct radeon_device *rdev)  	const char *chip_name;  	const char *rlc_chip_name;  	size_t pfp_req_size, me_req_size, ce_req_size, rlc_req_size, mc_req_size; -	size_t smc_req_size; +	size_t smc_req_size, mc2_req_size;  	char fw_name[30];  	int err; @@ -1567,6 +1569,7 @@ static int si_init_microcode(struct radeon_device *rdev)  		ce_req_size = SI_CE_UCODE_SIZE * 4;  		rlc_req_size = SI_RLC_UCODE_SIZE * 4;  		mc_req_size = SI_MC_UCODE_SIZE * 4; +		mc2_req_size = TAHITI_MC_UCODE_SIZE * 4;  		smc_req_size = ALIGN(TAHITI_SMC_UCODE_SIZE, 4);  		break;  	case CHIP_PITCAIRN: @@ -1577,6 +1580,7 @@ static int si_init_microcode(struct radeon_device *rdev)  		ce_req_size = SI_CE_UCODE_SIZE * 4;  		rlc_req_size = SI_RLC_UCODE_SIZE * 4;  		mc_req_size = SI_MC_UCODE_SIZE * 4; +		mc2_req_size = PITCAIRN_MC_UCODE_SIZE * 4;  		smc_req_size = ALIGN(PITCAIRN_SMC_UCODE_SIZE, 4);  		break;  	case CHIP_VERDE: @@ -1587,6 +1591,7 @@ static int si_init_microcode(struct radeon_device *rdev)  		ce_req_size = SI_CE_UCODE_SIZE * 4;  		rlc_req_size = SI_RLC_UCODE_SIZE * 4;  		mc_req_size = SI_MC_UCODE_SIZE * 4; +		mc2_req_size = VERDE_MC_UCODE_SIZE * 4;  		smc_req_size = ALIGN(VERDE_SMC_UCODE_SIZE, 4);  		break;  	case CHIP_OLAND: @@ -1596,7 +1601,7 @@ static int si_init_microcode(struct radeon_device *rdev)  		me_req_size = SI_PM4_UCODE_SIZE * 4;  		ce_req_size = SI_CE_UCODE_SIZE * 4;  		rlc_req_size = SI_RLC_UCODE_SIZE * 4; -		mc_req_size = OLAND_MC_UCODE_SIZE * 4; +		mc_req_size = mc2_req_size = OLAND_MC_UCODE_SIZE * 4;  		smc_req_size = ALIGN(OLAND_SMC_UCODE_SIZE, 4);  		break;  	case CHIP_HAINAN: @@ -1606,7 +1611,7 @@ static int si_init_microcode(struct radeon_device *rdev)  		me_req_size = SI_PM4_UCODE_SIZE * 4;  		ce_req_size = SI_CE_UCODE_SIZE * 4;  		rlc_req_size = SI_RLC_UCODE_SIZE * 4; -		mc_req_size = OLAND_MC_UCODE_SIZE * 4; +		mc_req_size = mc2_req_size = OLAND_MC_UCODE_SIZE * 4;  		smc_req_size = ALIGN(HAINAN_SMC_UCODE_SIZE, 4);  		break;  	default: BUG(); @@ -1659,16 +1664,22 @@ static int si_init_microcode(struct radeon_device *rdev)  		err = -EINVAL;  	} -	snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); +	snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc2.bin", chip_name);  	err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev); -	if (err) -		goto out; -	if (rdev->mc_fw->size != mc_req_size) { +	if (err) { +		snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); +		err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev); +		if (err) +			goto out; +	} +	if ((rdev->mc_fw->size != mc_req_size) && +	    (rdev->mc_fw->size != mc2_req_size)) {  		printk(KERN_ERR  		       "si_mc: Bogus length %zu in firmware \"%s\"\n",  		       rdev->mc_fw->size, fw_name);  		err = -EINVAL;  	} +	DRM_INFO("%s: %zu bytes\n", fw_name, rdev->mc_fw->size);  	snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name);  	err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev); @@ -5769,7 +5780,6 @@ int si_irq_set(struct radeon_device *rdev)  	u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0;  	u32 hpd1 = 0, hpd2 = 0, hpd3 = 0, hpd4 = 0, hpd5 = 0, hpd6 = 0;  	u32 grbm_int_cntl = 0; -	u32 grph1 = 0, grph2 = 0, grph3 = 0, grph4 = 0, grph5 = 0, grph6 = 0;  	u32 dma_cntl, dma_cntl1;  	u32 thermal_int = 0; @@ -5908,16 +5918,22 @@ int si_irq_set(struct radeon_device *rdev)  	}  	if (rdev->num_crtc >= 2) { -		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, grph1); -		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, grph2); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK);  	}  	if (rdev->num_crtc >= 4) { -		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, grph3); -		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, grph4); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK);  	}  	if (rdev->num_crtc >= 6) { -		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, grph5); -		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, grph6); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK); +		WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, +		       GRPH_PFLIP_INT_MASK);  	}  	if (!ASIC_IS_NODCE(rdev)) { @@ -6281,6 +6297,15 @@ restart_ih:  				break;  			}  			break; +		case 8: /* D1 page flip */ +		case 10: /* D2 page flip */ +		case 12: /* D3 page flip */ +		case 14: /* D4 page flip */ +		case 16: /* D5 page flip */ +		case 18: /* D6 page flip */ +			DRM_DEBUG("IH: D%d flip\n", ((src_id - 8) >> 1) + 1); +			radeon_crtc_handle_flip(rdev, (src_id - 8) >> 1); +			break;  		case 42: /* HPD hotplug */  			switch (src_data) {  			case 0: diff --git a/drivers/gpu/drm/radeon/si_dma.c b/drivers/gpu/drm/radeon/si_dma.c index cf0fdad8c278..de0ca070122f 100644 --- a/drivers/gpu/drm/radeon/si_dma.c +++ b/drivers/gpu/drm/radeon/si_dma.c @@ -213,6 +213,7 @@ int si_copy_dma(struct radeon_device *rdev,  	r = radeon_fence_emit(rdev, fence, ring->idx);  	if (r) {  		radeon_ring_unlock_undo(rdev, ring); +		radeon_semaphore_free(rdev, &sem, NULL);  		return r;  	} diff --git a/drivers/gpu/drm/radeon/uvd_v1_0.c b/drivers/gpu/drm/radeon/uvd_v1_0.c index 0a243f0e5d68..be42c8125203 100644 --- a/drivers/gpu/drm/radeon/uvd_v1_0.c +++ b/drivers/gpu/drm/radeon/uvd_v1_0.c @@ -83,7 +83,10 @@ int uvd_v1_0_init(struct radeon_device *rdev)  	int r;  	/* raise clocks while booting up the VCPU */ -	radeon_set_uvd_clocks(rdev, 53300, 40000); +	if (rdev->family < CHIP_RV740) +		radeon_set_uvd_clocks(rdev, 10000, 10000); +	else +		radeon_set_uvd_clocks(rdev, 53300, 40000);  	r = uvd_v1_0_start(rdev);  	if (r) @@ -407,7 +410,10 @@ int uvd_v1_0_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)  	struct radeon_fence *fence = NULL;  	int r; -	r = radeon_set_uvd_clocks(rdev, 53300, 40000); +	if (rdev->family < CHIP_RV740) +		r = radeon_set_uvd_clocks(rdev, 10000, 10000); +	else +		r = radeon_set_uvd_clocks(rdev, 53300, 40000);  	if (r) {  		DRM_ERROR("radeon: failed to raise UVD clocks (%d).\n", r);  		return r; diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 36c717af6cf9..edb871d7d395 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -312,7 +312,7 @@ static void tegra_crtc_disable(struct drm_crtc *crtc)  	struct drm_device *drm = crtc->dev;  	struct drm_plane *plane; -	list_for_each_entry(plane, &drm->mode_config.plane_list, head) { +	drm_for_each_legacy_plane(plane, &drm->mode_config.plane_list) {  		if (plane->crtc == crtc) {  			tegra_plane_disable(plane);  			plane->crtc = NULL; diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c index d536ed381fbd..005c19bd92df 100644 --- a/drivers/gpu/drm/tegra/dpaux.c +++ b/drivers/gpu/drm/tegra/dpaux.c @@ -99,55 +99,73 @@ static void tegra_dpaux_read_fifo(struct tegra_dpaux *dpaux, u8 *buffer,  static ssize_t tegra_dpaux_transfer(struct drm_dp_aux *aux,  				    struct drm_dp_aux_msg *msg)  { -	unsigned long value = DPAUX_DP_AUXCTL_TRANSACTREQ;  	unsigned long timeout = msecs_to_jiffies(250);  	struct tegra_dpaux *dpaux = to_dpaux(aux);  	unsigned long status;  	ssize_t ret = 0; +	u32 value; -	if (msg->size < 1 || msg->size > 16) +	/* Tegra has 4x4 byte DP AUX transmit and receive FIFOs. */ +	if (msg->size > 16)  		return -EINVAL; -	tegra_dpaux_writel(dpaux, msg->address, DPAUX_DP_AUXADDR); +	/* +	 * Allow zero-sized messages only for I2C, in which case they specify +	 * address-only transactions. +	 */ +	if (msg->size < 1) { +		switch (msg->request & ~DP_AUX_I2C_MOT) { +		case DP_AUX_I2C_WRITE: +		case DP_AUX_I2C_READ: +			value = DPAUX_DP_AUXCTL_CMD_ADDRESS_ONLY; +			break; + +		default: +			return -EINVAL; +		} +	} else { +		/* For non-zero-sized messages, set the CMDLEN field. */ +		value = DPAUX_DP_AUXCTL_CMDLEN(msg->size - 1); +	}  	switch (msg->request & ~DP_AUX_I2C_MOT) {  	case DP_AUX_I2C_WRITE:  		if (msg->request & DP_AUX_I2C_MOT) -			value = DPAUX_DP_AUXCTL_CMD_MOT_WR; +			value |= DPAUX_DP_AUXCTL_CMD_MOT_WR;  		else -			value = DPAUX_DP_AUXCTL_CMD_I2C_WR; +			value |= DPAUX_DP_AUXCTL_CMD_I2C_WR;  		break;  	case DP_AUX_I2C_READ:  		if (msg->request & DP_AUX_I2C_MOT) -			value = DPAUX_DP_AUXCTL_CMD_MOT_RD; +			value |= DPAUX_DP_AUXCTL_CMD_MOT_RD;  		else -			value = DPAUX_DP_AUXCTL_CMD_I2C_RD; +			value |= DPAUX_DP_AUXCTL_CMD_I2C_RD;  		break;  	case DP_AUX_I2C_STATUS:  		if (msg->request & DP_AUX_I2C_MOT) -			value = DPAUX_DP_AUXCTL_CMD_MOT_RQ; +			value |= DPAUX_DP_AUXCTL_CMD_MOT_RQ;  		else -			value = DPAUX_DP_AUXCTL_CMD_I2C_RQ; +			value |= DPAUX_DP_AUXCTL_CMD_I2C_RQ;  		break;  	case DP_AUX_NATIVE_WRITE: -		value = DPAUX_DP_AUXCTL_CMD_AUX_WR; +		value |= DPAUX_DP_AUXCTL_CMD_AUX_WR;  		break;  	case DP_AUX_NATIVE_READ: -		value = DPAUX_DP_AUXCTL_CMD_AUX_RD; +		value |= DPAUX_DP_AUXCTL_CMD_AUX_RD;  		break;  	default:  		return -EINVAL;  	} -	value |= DPAUX_DP_AUXCTL_CMDLEN(msg->size - 1); +	tegra_dpaux_writel(dpaux, msg->address, DPAUX_DP_AUXADDR);  	tegra_dpaux_writel(dpaux, value, DPAUX_DP_AUXCTL);  	if ((msg->request & DP_AUX_I2C_READ) == 0) { @@ -198,7 +216,7 @@ static ssize_t tegra_dpaux_transfer(struct drm_dp_aux *aux,  		break;  	} -	if (msg->reply == DP_AUX_NATIVE_REPLY_ACK) { +	if ((msg->size > 0) && (msg->reply == DP_AUX_NATIVE_REPLY_ACK)) {  		if (msg->request & DP_AUX_I2C_READ) {  			size_t count = value & DPAUX_DP_AUXSTAT_REPLY_MASK; diff --git a/drivers/gpu/drm/tegra/dpaux.h b/drivers/gpu/drm/tegra/dpaux.h index 4f5bf10fdff9..806e245ca787 100644 --- a/drivers/gpu/drm/tegra/dpaux.h +++ b/drivers/gpu/drm/tegra/dpaux.h @@ -32,6 +32,7 @@  #define DPAUX_DP_AUXCTL_CMD_I2C_RQ (2 << 12)  #define DPAUX_DP_AUXCTL_CMD_I2C_RD (1 << 12)  #define DPAUX_DP_AUXCTL_CMD_I2C_WR (0 << 12) +#define DPAUX_DP_AUXCTL_CMD_ADDRESS_ONLY (1 << 8)  #define DPAUX_DP_AUXCTL_CMDLEN(x) ((x) & 0xff)  #define DPAUX_DP_AUXSTAT 0x31 diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 931490b9cfed..87df0b3674fd 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -1214,14 +1214,36 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv,  		SVGA3dCmdSurfaceDMA dma;  	} *cmd;  	int ret; +	SVGA3dCmdSurfaceDMASuffix *suffix; +	uint32_t bo_size;  	cmd = container_of(header, struct vmw_dma_cmd, header); +	suffix = (SVGA3dCmdSurfaceDMASuffix *)((unsigned long) &cmd->dma + +					       header->size - sizeof(*suffix)); + +	/* Make sure device and verifier stays in sync. */ +	if (unlikely(suffix->suffixSize != sizeof(*suffix))) { +		DRM_ERROR("Invalid DMA suffix size.\n"); +		return -EINVAL; +	} +  	ret = vmw_translate_guest_ptr(dev_priv, sw_context,  				      &cmd->dma.guest.ptr,  				      &vmw_bo);  	if (unlikely(ret != 0))  		return ret; +	/* Make sure DMA doesn't cross BO boundaries. */ +	bo_size = vmw_bo->base.num_pages * PAGE_SIZE; +	if (unlikely(cmd->dma.guest.ptr.offset > bo_size)) { +		DRM_ERROR("Invalid DMA offset.\n"); +		return -EINVAL; +	} + +	bo_size -= cmd->dma.guest.ptr.offset; +	if (unlikely(suffix->maximumOffset > bo_size)) +		suffix->maximumOffset = bo_size; +  	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,  				user_surface_converter, &cmd->dma.host.sid,  				NULL); diff --git a/drivers/gpu/host1x/hw/intr_hw.c b/drivers/gpu/host1x/hw/intr_hw.c index db9017adfe2b..498b37e39058 100644 --- a/drivers/gpu/host1x/hw/intr_hw.c +++ b/drivers/gpu/host1x/hw/intr_hw.c @@ -47,7 +47,7 @@ static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id)  	unsigned long reg;  	int i, id; -	for (i = 0; i <= BIT_WORD(host->info->nb_pts); i++) { +	for (i = 0; i < DIV_ROUND_UP(host->info->nb_pts, 32); i++) {  		reg = host1x_sync_readl(host,  			HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i));  		for_each_set_bit(id, ®, BITS_PER_LONG) { @@ -64,7 +64,7 @@ static void _host1x_intr_disable_all_syncpt_intrs(struct host1x *host)  {  	u32 i; -	for (i = 0; i <= BIT_WORD(host->info->nb_pts); ++i) { +	for (i = 0; i < DIV_ROUND_UP(host->info->nb_pts, 32); ++i) {  		host1x_sync_writel(host, 0xffffffffu,  			HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(i));  		host1x_sync_writel(host, 0xffffffffu,  | 
