forked from mirrors/linux
		
	drm/nouveau/kms: switch to drm fbdev helpers
This removes support for accelerated fbcon rendering, and fixes a number of races/crashes/issues around suspend/resume/module unload etc. Losing HW accelerated rendering isn't ideal, but it's been significantly reduced in performance since the removal of accelerated scrolling in the kernel anyway - not to mention, can be racey (skips cpu<->gpu sync) from certain contexts. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
		
							parent
							
								
									99d0701afd
								
							
						
					
					
						commit
						4a16dd9d18
					
				
					 12 changed files with 15 additions and 1581 deletions
				
			
		| 
						 | 
					@ -54,10 +54,6 @@ nouveau-y += nouveau_bios.o
 | 
				
			||||||
nouveau-y += nouveau_connector.o
 | 
					nouveau-y += nouveau_connector.o
 | 
				
			||||||
nouveau-y += nouveau_display.o
 | 
					nouveau-y += nouveau_display.o
 | 
				
			||||||
nouveau-y += nouveau_dp.o
 | 
					nouveau-y += nouveau_dp.o
 | 
				
			||||||
nouveau-y += nouveau_fbcon.o
 | 
					 | 
				
			||||||
nouveau-y += nv04_fbcon.o
 | 
					 | 
				
			||||||
nouveau-y += nv50_fbcon.o
 | 
					 | 
				
			||||||
nouveau-y += nvc0_fbcon.o
 | 
					 | 
				
			||||||
include $(src)/dispnv04/Kbuild
 | 
					include $(src)/dispnv04/Kbuild
 | 
				
			||||||
include $(src)/dispnv50/Kbuild
 | 
					include $(src)/dispnv50/Kbuild
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,6 +23,7 @@
 | 
				
			||||||
 * DEALINGS IN THE SOFTWARE.
 | 
					 * DEALINGS IN THE SOFTWARE.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#include <drm/drm_crtc_helper.h>
 | 
					#include <drm/drm_crtc_helper.h>
 | 
				
			||||||
 | 
					#include <drm/drm_fb_helper.h>
 | 
				
			||||||
#include <drm/drm_fourcc.h>
 | 
					#include <drm/drm_fourcc.h>
 | 
				
			||||||
#include <drm/drm_plane_helper.h>
 | 
					#include <drm/drm_plane_helper.h>
 | 
				
			||||||
#include <drm/drm_vblank.h>
 | 
					#include <drm/drm_vblank.h>
 | 
				
			||||||
| 
						 | 
					@ -37,7 +38,6 @@
 | 
				
			||||||
#include "nouveau_crtc.h"
 | 
					#include "nouveau_crtc.h"
 | 
				
			||||||
#include "hw.h"
 | 
					#include "hw.h"
 | 
				
			||||||
#include "nvreg.h"
 | 
					#include "nvreg.h"
 | 
				
			||||||
#include "nouveau_fbcon.h"
 | 
					 | 
				
			||||||
#include "disp.h"
 | 
					#include "disp.h"
 | 
				
			||||||
#include "nouveau_dma.h"
 | 
					#include "nouveau_dma.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -915,14 +915,6 @@ nv04_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
 | 
				
			||||||
			       struct drm_framebuffer *fb,
 | 
								       struct drm_framebuffer *fb,
 | 
				
			||||||
			       int x, int y, enum mode_set_atomic state)
 | 
								       int x, int y, enum mode_set_atomic state)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(crtc->dev);
 | 
					 | 
				
			||||||
	struct drm_device *dev = drm->dev;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (state == ENTER_ATOMIC_MODE_SET)
 | 
					 | 
				
			||||||
		nouveau_fbcon_accel_save_disable(dev);
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		nouveau_fbcon_accel_restore(dev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return nv04_crtc_do_mode_set_base(crtc, fb, x, y, true);
 | 
						return nv04_crtc_do_mode_set_base(crtc, fb, x, y, true);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -64,7 +64,6 @@
 | 
				
			||||||
#include "nouveau_connector.h"
 | 
					#include "nouveau_connector.h"
 | 
				
			||||||
#include "nouveau_encoder.h"
 | 
					#include "nouveau_encoder.h"
 | 
				
			||||||
#include "nouveau_fence.h"
 | 
					#include "nouveau_fence.h"
 | 
				
			||||||
#include "nouveau_fbcon.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <subdev/bios/dp.h>
 | 
					#include <subdev/bios/dp.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2446,7 +2445,7 @@ nv50_disp_atomic_state_alloc(struct drm_device *dev)
 | 
				
			||||||
static const struct drm_mode_config_funcs
 | 
					static const struct drm_mode_config_funcs
 | 
				
			||||||
nv50_disp_func = {
 | 
					nv50_disp_func = {
 | 
				
			||||||
	.fb_create = nouveau_user_framebuffer_create,
 | 
						.fb_create = nouveau_user_framebuffer_create,
 | 
				
			||||||
	.output_poll_changed = nouveau_fbcon_output_poll_changed,
 | 
						.output_poll_changed = drm_fb_helper_output_poll_changed,
 | 
				
			||||||
	.atomic_check = nv50_disp_atomic_check,
 | 
						.atomic_check = nv50_disp_atomic_check,
 | 
				
			||||||
	.atomic_commit = nv50_disp_atomic_commit,
 | 
						.atomic_commit = nv50_disp_atomic_commit,
 | 
				
			||||||
	.atomic_state_alloc = nv50_disp_atomic_state_alloc,
 | 
						.atomic_state_alloc = nv50_disp_atomic_state_alloc,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,7 +35,6 @@
 | 
				
			||||||
#include <drm/drm_probe_helper.h>
 | 
					#include <drm/drm_probe_helper.h>
 | 
				
			||||||
#include <drm/drm_vblank.h>
 | 
					#include <drm/drm_vblank.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "nouveau_fbcon.h"
 | 
					 | 
				
			||||||
#include "nouveau_crtc.h"
 | 
					#include "nouveau_crtc.h"
 | 
				
			||||||
#include "nouveau_gem.h"
 | 
					#include "nouveau_gem.h"
 | 
				
			||||||
#include "nouveau_connector.h"
 | 
					#include "nouveau_connector.h"
 | 
				
			||||||
| 
						 | 
					@ -392,7 +391,7 @@ nouveau_user_framebuffer_create(struct drm_device *dev,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
 | 
					static const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
 | 
				
			||||||
	.fb_create = nouveau_user_framebuffer_create,
 | 
						.fb_create = nouveau_user_framebuffer_create,
 | 
				
			||||||
	.output_poll_changed = nouveau_fbcon_output_poll_changed,
 | 
						.output_poll_changed = drm_fb_helper_output_poll_changed,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -788,6 +787,9 @@ nouveau_display_suspend(struct drm_device *dev, bool runtime)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nouveau_display *disp = nouveau_display(dev);
 | 
						struct nouveau_display *disp = nouveau_display(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Disable console. */
 | 
				
			||||||
 | 
						drm_fb_helper_set_suspend_unlocked(dev->fb_helper, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (drm_drv_uses_atomic_modeset(dev)) {
 | 
						if (drm_drv_uses_atomic_modeset(dev)) {
 | 
				
			||||||
		if (!runtime) {
 | 
							if (!runtime) {
 | 
				
			||||||
			disp->suspend = drm_atomic_helper_suspend(dev);
 | 
								disp->suspend = drm_atomic_helper_suspend(dev);
 | 
				
			||||||
| 
						 | 
					@ -815,8 +817,10 @@ nouveau_display_resume(struct drm_device *dev, bool runtime)
 | 
				
			||||||
			drm_atomic_helper_resume(dev, disp->suspend);
 | 
								drm_atomic_helper_resume(dev, disp->suspend);
 | 
				
			||||||
			disp->suspend = NULL;
 | 
								disp->suspend = NULL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Enable console. */
 | 
				
			||||||
 | 
						drm_fb_helper_set_suspend_unlocked(dev->fb_helper, false);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,6 +33,7 @@
 | 
				
			||||||
#include <drm/drm_aperture.h>
 | 
					#include <drm/drm_aperture.h>
 | 
				
			||||||
#include <drm/drm_crtc_helper.h>
 | 
					#include <drm/drm_crtc_helper.h>
 | 
				
			||||||
#include <drm/drm_drv.h>
 | 
					#include <drm/drm_drv.h>
 | 
				
			||||||
 | 
					#include <drm/drm_fb_helper.h>
 | 
				
			||||||
#include <drm/drm_gem_ttm_helper.h>
 | 
					#include <drm/drm_gem_ttm_helper.h>
 | 
				
			||||||
#include <drm/drm_ioctl.h>
 | 
					#include <drm/drm_ioctl.h>
 | 
				
			||||||
#include <drm/drm_vblank.h>
 | 
					#include <drm/drm_vblank.h>
 | 
				
			||||||
| 
						 | 
					@ -62,7 +63,6 @@
 | 
				
			||||||
#include "nouveau_bios.h"
 | 
					#include "nouveau_bios.h"
 | 
				
			||||||
#include "nouveau_ioctl.h"
 | 
					#include "nouveau_ioctl.h"
 | 
				
			||||||
#include "nouveau_abi16.h"
 | 
					#include "nouveau_abi16.h"
 | 
				
			||||||
#include "nouveau_fbcon.h"
 | 
					 | 
				
			||||||
#include "nouveau_fence.h"
 | 
					#include "nouveau_fence.h"
 | 
				
			||||||
#include "nouveau_debugfs.h"
 | 
					#include "nouveau_debugfs.h"
 | 
				
			||||||
#include "nouveau_usif.h"
 | 
					#include "nouveau_usif.h"
 | 
				
			||||||
| 
						 | 
					@ -611,7 +611,6 @@ nouveau_drm_device_init(struct drm_device *dev)
 | 
				
			||||||
	nouveau_hwmon_init(dev);
 | 
						nouveau_hwmon_init(dev);
 | 
				
			||||||
	nouveau_svm_init(drm);
 | 
						nouveau_svm_init(drm);
 | 
				
			||||||
	nouveau_dmem_init(drm);
 | 
						nouveau_dmem_init(drm);
 | 
				
			||||||
	nouveau_fbcon_init(dev);
 | 
					 | 
				
			||||||
	nouveau_led_init(dev);
 | 
						nouveau_led_init(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (nouveau_pmops_runtime()) {
 | 
						if (nouveau_pmops_runtime()) {
 | 
				
			||||||
| 
						 | 
					@ -655,7 +654,6 @@ nouveau_drm_device_fini(struct drm_device *dev)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	nouveau_led_fini(dev);
 | 
						nouveau_led_fini(dev);
 | 
				
			||||||
	nouveau_fbcon_fini(dev);
 | 
					 | 
				
			||||||
	nouveau_dmem_fini(drm);
 | 
						nouveau_dmem_fini(drm);
 | 
				
			||||||
	nouveau_svm_fini(drm);
 | 
						nouveau_svm_fini(drm);
 | 
				
			||||||
	nouveau_hwmon_fini(dev);
 | 
						nouveau_hwmon_fini(dev);
 | 
				
			||||||
| 
						 | 
					@ -809,6 +807,11 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		goto fail_drm_dev_init;
 | 
							goto fail_drm_dev_init;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (nouveau_drm(drm_dev)->client.device.info.ram_size <= 32 * 1024 * 1024)
 | 
				
			||||||
 | 
							drm_fbdev_generic_setup(drm_dev, 8);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							drm_fbdev_generic_setup(drm_dev, 32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	quirk_broken_nv_runpm(pdev);
 | 
						quirk_broken_nv_runpm(pdev);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -865,8 +868,6 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime)
 | 
				
			||||||
	nouveau_led_suspend(dev);
 | 
						nouveau_led_suspend(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dev->mode_config.num_crtc) {
 | 
						if (dev->mode_config.num_crtc) {
 | 
				
			||||||
		NV_DEBUG(drm, "suspending console...\n");
 | 
					 | 
				
			||||||
		nouveau_fbcon_set_suspend(dev, 1);
 | 
					 | 
				
			||||||
		NV_DEBUG(drm, "suspending display...\n");
 | 
							NV_DEBUG(drm, "suspending display...\n");
 | 
				
			||||||
		ret = nouveau_display_suspend(dev, runtime);
 | 
							ret = nouveau_display_suspend(dev, runtime);
 | 
				
			||||||
		if (ret)
 | 
							if (ret)
 | 
				
			||||||
| 
						 | 
					@ -940,8 +941,6 @@ nouveau_do_resume(struct drm_device *dev, bool runtime)
 | 
				
			||||||
	if (dev->mode_config.num_crtc) {
 | 
						if (dev->mode_config.num_crtc) {
 | 
				
			||||||
		NV_DEBUG(drm, "resuming display...\n");
 | 
							NV_DEBUG(drm, "resuming display...\n");
 | 
				
			||||||
		nouveau_display_resume(dev, runtime);
 | 
							nouveau_display_resume(dev, runtime);
 | 
				
			||||||
		NV_DEBUG(drm, "resuming console...\n");
 | 
					 | 
				
			||||||
		nouveau_fbcon_set_suspend(dev, 0);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	nouveau_led_resume(dev);
 | 
						nouveau_led_resume(dev);
 | 
				
			||||||
| 
						 | 
					@ -1296,7 +1295,6 @@ static void nouveau_display_options(void)
 | 
				
			||||||
	DRM_DEBUG_DRIVER("... tv_disable   : %d\n", nouveau_tv_disable);
 | 
						DRM_DEBUG_DRIVER("... tv_disable   : %d\n", nouveau_tv_disable);
 | 
				
			||||||
	DRM_DEBUG_DRIVER("... ignorelid    : %d\n", nouveau_ignorelid);
 | 
						DRM_DEBUG_DRIVER("... ignorelid    : %d\n", nouveau_ignorelid);
 | 
				
			||||||
	DRM_DEBUG_DRIVER("... duallink     : %d\n", nouveau_duallink);
 | 
						DRM_DEBUG_DRIVER("... duallink     : %d\n", nouveau_duallink);
 | 
				
			||||||
	DRM_DEBUG_DRIVER("... nofbaccel    : %d\n", nouveau_nofbaccel);
 | 
					 | 
				
			||||||
	DRM_DEBUG_DRIVER("... config       : %s\n", nouveau_config);
 | 
						DRM_DEBUG_DRIVER("... config       : %s\n", nouveau_config);
 | 
				
			||||||
	DRM_DEBUG_DRIVER("... debug        : %s\n", nouveau_debug);
 | 
						DRM_DEBUG_DRIVER("... debug        : %s\n", nouveau_debug);
 | 
				
			||||||
	DRM_DEBUG_DRIVER("... noaccel      : %d\n", nouveau_noaccel);
 | 
						DRM_DEBUG_DRIVER("... noaccel      : %d\n", nouveau_noaccel);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -183,7 +183,6 @@ struct nouveau_drm {
 | 
				
			||||||
	struct nouveau_channel *cechan;
 | 
						struct nouveau_channel *cechan;
 | 
				
			||||||
	struct nouveau_channel *channel;
 | 
						struct nouveau_channel *channel;
 | 
				
			||||||
	struct nvkm_gpuobj *notify;
 | 
						struct nvkm_gpuobj *notify;
 | 
				
			||||||
	struct nouveau_fbdev *fbcon;
 | 
					 | 
				
			||||||
	struct nvif_object ntfy;
 | 
						struct nvif_object ntfy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* nv10-nv40 tiling regions */
 | 
						/* nv10-nv40 tiling regions */
 | 
				
			||||||
| 
						 | 
					@ -198,8 +197,6 @@ struct nouveau_drm {
 | 
				
			||||||
	struct work_struct hpd_work;
 | 
						struct work_struct hpd_work;
 | 
				
			||||||
	spinlock_t hpd_lock;
 | 
						spinlock_t hpd_lock;
 | 
				
			||||||
	u32 hpd_pending;
 | 
						u32 hpd_pending;
 | 
				
			||||||
	struct work_struct fbcon_work;
 | 
					 | 
				
			||||||
	int fbcon_new_state;
 | 
					 | 
				
			||||||
#ifdef CONFIG_ACPI
 | 
					#ifdef CONFIG_ACPI
 | 
				
			||||||
	struct notifier_block acpi_nb;
 | 
						struct notifier_block acpi_nb;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,614 +0,0 @@
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Copyright © 2007 David Airlie
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Permission is hereby granted, free of charge, to any person obtaining a
 | 
					 | 
				
			||||||
 * copy of this software and associated documentation files (the "Software"),
 | 
					 | 
				
			||||||
 * to deal in the Software without restriction, including without limitation
 | 
					 | 
				
			||||||
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 | 
					 | 
				
			||||||
 * and/or sell copies of the Software, and to permit persons to whom the
 | 
					 | 
				
			||||||
 * Software is furnished to do so, subject to the following conditions:
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The above copyright notice and this permission notice (including the next
 | 
					 | 
				
			||||||
 * paragraph) shall be included in all copies or substantial portions of the
 | 
					 | 
				
			||||||
 * Software.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
					 | 
				
			||||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
					 | 
				
			||||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 | 
					 | 
				
			||||||
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
					 | 
				
			||||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
					 | 
				
			||||||
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 | 
					 | 
				
			||||||
 * DEALINGS IN THE SOFTWARE.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Authors:
 | 
					 | 
				
			||||||
 *     David Airlie
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <linux/module.h>
 | 
					 | 
				
			||||||
#include <linux/kernel.h>
 | 
					 | 
				
			||||||
#include <linux/errno.h>
 | 
					 | 
				
			||||||
#include <linux/string.h>
 | 
					 | 
				
			||||||
#include <linux/mm.h>
 | 
					 | 
				
			||||||
#include <linux/tty.h>
 | 
					 | 
				
			||||||
#include <linux/sysrq.h>
 | 
					 | 
				
			||||||
#include <linux/delay.h>
 | 
					 | 
				
			||||||
#include <linux/init.h>
 | 
					 | 
				
			||||||
#include <linux/screen_info.h>
 | 
					 | 
				
			||||||
#include <linux/vga_switcheroo.h>
 | 
					 | 
				
			||||||
#include <linux/console.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <drm/drm_crtc.h>
 | 
					 | 
				
			||||||
#include <drm/drm_crtc_helper.h>
 | 
					 | 
				
			||||||
#include <drm/drm_probe_helper.h>
 | 
					 | 
				
			||||||
#include <drm/drm_fb_helper.h>
 | 
					 | 
				
			||||||
#include <drm/drm_fourcc.h>
 | 
					 | 
				
			||||||
#include <drm/drm_atomic.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "nouveau_drv.h"
 | 
					 | 
				
			||||||
#include "nouveau_gem.h"
 | 
					 | 
				
			||||||
#include "nouveau_bo.h"
 | 
					 | 
				
			||||||
#include "nouveau_fbcon.h"
 | 
					 | 
				
			||||||
#include "nouveau_chan.h"
 | 
					 | 
				
			||||||
#include "nouveau_vmm.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "nouveau_crtc.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
MODULE_PARM_DESC(nofbaccel, "Disable fbcon acceleration");
 | 
					 | 
				
			||||||
int nouveau_nofbaccel = 0;
 | 
					 | 
				
			||||||
module_param_named(nofbaccel, nouveau_nofbaccel, int, 0400);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
MODULE_PARM_DESC(fbcon_bpp, "fbcon bits-per-pixel (default: auto)");
 | 
					 | 
				
			||||||
static int nouveau_fbcon_bpp;
 | 
					 | 
				
			||||||
module_param_named(fbcon_bpp, nouveau_fbcon_bpp, int, 0400);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
nouveau_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_fbdev *fbcon = info->par;
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev);
 | 
					 | 
				
			||||||
	struct nvif_device *device = &drm->client.device;
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (info->state != FBINFO_STATE_RUNNING)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = -ENODEV;
 | 
					 | 
				
			||||||
	if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) &&
 | 
					 | 
				
			||||||
	    mutex_trylock(&drm->client.mutex)) {
 | 
					 | 
				
			||||||
		if (device->info.family < NV_DEVICE_INFO_V0_TESLA)
 | 
					 | 
				
			||||||
			ret = nv04_fbcon_fillrect(info, rect);
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
		if (device->info.family < NV_DEVICE_INFO_V0_FERMI)
 | 
					 | 
				
			||||||
			ret = nv50_fbcon_fillrect(info, rect);
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			ret = nvc0_fbcon_fillrect(info, rect);
 | 
					 | 
				
			||||||
		mutex_unlock(&drm->client.mutex);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (ret == 0)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (ret != -ENODEV)
 | 
					 | 
				
			||||||
		nouveau_fbcon_gpu_lockup(info);
 | 
					 | 
				
			||||||
	drm_fb_helper_cfb_fillrect(info, rect);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
nouveau_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *image)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_fbdev *fbcon = info->par;
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev);
 | 
					 | 
				
			||||||
	struct nvif_device *device = &drm->client.device;
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (info->state != FBINFO_STATE_RUNNING)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = -ENODEV;
 | 
					 | 
				
			||||||
	if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) &&
 | 
					 | 
				
			||||||
	    mutex_trylock(&drm->client.mutex)) {
 | 
					 | 
				
			||||||
		if (device->info.family < NV_DEVICE_INFO_V0_TESLA)
 | 
					 | 
				
			||||||
			ret = nv04_fbcon_copyarea(info, image);
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
		if (device->info.family < NV_DEVICE_INFO_V0_FERMI)
 | 
					 | 
				
			||||||
			ret = nv50_fbcon_copyarea(info, image);
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			ret = nvc0_fbcon_copyarea(info, image);
 | 
					 | 
				
			||||||
		mutex_unlock(&drm->client.mutex);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (ret == 0)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (ret != -ENODEV)
 | 
					 | 
				
			||||||
		nouveau_fbcon_gpu_lockup(info);
 | 
					 | 
				
			||||||
	drm_fb_helper_cfb_copyarea(info, image);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
nouveau_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_fbdev *fbcon = info->par;
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev);
 | 
					 | 
				
			||||||
	struct nvif_device *device = &drm->client.device;
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (info->state != FBINFO_STATE_RUNNING)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = -ENODEV;
 | 
					 | 
				
			||||||
	if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) &&
 | 
					 | 
				
			||||||
	    mutex_trylock(&drm->client.mutex)) {
 | 
					 | 
				
			||||||
		if (device->info.family < NV_DEVICE_INFO_V0_TESLA)
 | 
					 | 
				
			||||||
			ret = nv04_fbcon_imageblit(info, image);
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
		if (device->info.family < NV_DEVICE_INFO_V0_FERMI)
 | 
					 | 
				
			||||||
			ret = nv50_fbcon_imageblit(info, image);
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			ret = nvc0_fbcon_imageblit(info, image);
 | 
					 | 
				
			||||||
		mutex_unlock(&drm->client.mutex);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (ret == 0)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (ret != -ENODEV)
 | 
					 | 
				
			||||||
		nouveau_fbcon_gpu_lockup(info);
 | 
					 | 
				
			||||||
	drm_fb_helper_cfb_imageblit(info, image);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int
 | 
					 | 
				
			||||||
nouveau_fbcon_sync(struct fb_info *info)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_fbdev *fbcon = info->par;
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev);
 | 
					 | 
				
			||||||
	struct nouveau_channel *chan = drm->channel;
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!chan || !chan->accel_done || in_interrupt() ||
 | 
					 | 
				
			||||||
	    info->state != FBINFO_STATE_RUNNING ||
 | 
					 | 
				
			||||||
	    info->flags & FBINFO_HWACCEL_DISABLED)
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!mutex_trylock(&drm->client.mutex))
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = nouveau_channel_idle(chan);
 | 
					 | 
				
			||||||
	mutex_unlock(&drm->client.mutex);
 | 
					 | 
				
			||||||
	if (ret) {
 | 
					 | 
				
			||||||
		nouveau_fbcon_gpu_lockup(info);
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	chan->accel_done = false;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int
 | 
					 | 
				
			||||||
nouveau_fbcon_open(struct fb_info *info, int user)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_fbdev *fbcon = info->par;
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev);
 | 
					 | 
				
			||||||
	int ret = pm_runtime_get_sync(drm->dev->dev);
 | 
					 | 
				
			||||||
	if (ret < 0 && ret != -EACCES) {
 | 
					 | 
				
			||||||
		pm_runtime_put(drm->dev->dev);
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int
 | 
					 | 
				
			||||||
nouveau_fbcon_release(struct fb_info *info, int user)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_fbdev *fbcon = info->par;
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev);
 | 
					 | 
				
			||||||
	pm_runtime_put(drm->dev->dev);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const struct fb_ops nouveau_fbcon_ops = {
 | 
					 | 
				
			||||||
	.owner = THIS_MODULE,
 | 
					 | 
				
			||||||
	DRM_FB_HELPER_DEFAULT_OPS,
 | 
					 | 
				
			||||||
	.fb_open = nouveau_fbcon_open,
 | 
					 | 
				
			||||||
	.fb_release = nouveau_fbcon_release,
 | 
					 | 
				
			||||||
	.fb_fillrect = nouveau_fbcon_fillrect,
 | 
					 | 
				
			||||||
	.fb_copyarea = nouveau_fbcon_copyarea,
 | 
					 | 
				
			||||||
	.fb_imageblit = nouveau_fbcon_imageblit,
 | 
					 | 
				
			||||||
	.fb_sync = nouveau_fbcon_sync,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const struct fb_ops nouveau_fbcon_sw_ops = {
 | 
					 | 
				
			||||||
	.owner = THIS_MODULE,
 | 
					 | 
				
			||||||
	DRM_FB_HELPER_DEFAULT_OPS,
 | 
					 | 
				
			||||||
	.fb_open = nouveau_fbcon_open,
 | 
					 | 
				
			||||||
	.fb_release = nouveau_fbcon_release,
 | 
					 | 
				
			||||||
	.fb_fillrect = drm_fb_helper_cfb_fillrect,
 | 
					 | 
				
			||||||
	.fb_copyarea = drm_fb_helper_cfb_copyarea,
 | 
					 | 
				
			||||||
	.fb_imageblit = drm_fb_helper_cfb_imageblit,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
nouveau_fbcon_accel_save_disable(struct drm_device *dev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(dev);
 | 
					 | 
				
			||||||
	if (drm->fbcon && drm->fbcon->helper.fbdev) {
 | 
					 | 
				
			||||||
		drm->fbcon->saved_flags = drm->fbcon->helper.fbdev->flags;
 | 
					 | 
				
			||||||
		drm->fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
nouveau_fbcon_accel_restore(struct drm_device *dev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(dev);
 | 
					 | 
				
			||||||
	if (drm->fbcon && drm->fbcon->helper.fbdev) {
 | 
					 | 
				
			||||||
		drm->fbcon->helper.fbdev->flags = drm->fbcon->saved_flags;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
nouveau_fbcon_accel_fini(struct drm_device *dev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(dev);
 | 
					 | 
				
			||||||
	struct nouveau_fbdev *fbcon = drm->fbcon;
 | 
					 | 
				
			||||||
	if (fbcon && drm->channel) {
 | 
					 | 
				
			||||||
		console_lock();
 | 
					 | 
				
			||||||
		if (fbcon->helper.fbdev)
 | 
					 | 
				
			||||||
			fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED;
 | 
					 | 
				
			||||||
		console_unlock();
 | 
					 | 
				
			||||||
		nouveau_channel_idle(drm->channel);
 | 
					 | 
				
			||||||
		nvif_object_dtor(&fbcon->twod);
 | 
					 | 
				
			||||||
		nvif_object_dtor(&fbcon->blit);
 | 
					 | 
				
			||||||
		nvif_object_dtor(&fbcon->gdi);
 | 
					 | 
				
			||||||
		nvif_object_dtor(&fbcon->patt);
 | 
					 | 
				
			||||||
		nvif_object_dtor(&fbcon->rop);
 | 
					 | 
				
			||||||
		nvif_object_dtor(&fbcon->clip);
 | 
					 | 
				
			||||||
		nvif_object_dtor(&fbcon->surf2d);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
nouveau_fbcon_accel_init(struct drm_device *dev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(dev);
 | 
					 | 
				
			||||||
	struct nouveau_fbdev *fbcon = drm->fbcon;
 | 
					 | 
				
			||||||
	struct fb_info *info = fbcon->helper.fbdev;
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA)
 | 
					 | 
				
			||||||
		ret = nv04_fbcon_accel_init(info);
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
	if (drm->client.device.info.family < NV_DEVICE_INFO_V0_FERMI)
 | 
					 | 
				
			||||||
		ret = nv50_fbcon_accel_init(info);
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		ret = nvc0_fbcon_accel_init(info);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (ret == 0)
 | 
					 | 
				
			||||||
		info->fbops = &nouveau_fbcon_ops;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbdev *fbcon)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct fb_info *info = fbcon->helper.fbdev;
 | 
					 | 
				
			||||||
	struct fb_fillrect rect;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Clear the entire fbcon.  The drm will program every connector
 | 
					 | 
				
			||||||
	 * with it's preferred mode.  If the sizes differ, one display will
 | 
					 | 
				
			||||||
	 * quite likely have garbage around the console.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	rect.dx = rect.dy = 0;
 | 
					 | 
				
			||||||
	rect.width = info->var.xres_virtual;
 | 
					 | 
				
			||||||
	rect.height = info->var.yres_virtual;
 | 
					 | 
				
			||||||
	rect.color = 0;
 | 
					 | 
				
			||||||
	rect.rop = ROP_COPY;
 | 
					 | 
				
			||||||
	info->fbops->fb_fillrect(info, &rect);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int
 | 
					 | 
				
			||||||
nouveau_fbcon_create(struct drm_fb_helper *helper,
 | 
					 | 
				
			||||||
		     struct drm_fb_helper_surface_size *sizes)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_fbdev *fbcon =
 | 
					 | 
				
			||||||
		container_of(helper, struct nouveau_fbdev, helper);
 | 
					 | 
				
			||||||
	struct drm_device *dev = fbcon->helper.dev;
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(dev);
 | 
					 | 
				
			||||||
	struct nvif_device *device = &drm->client.device;
 | 
					 | 
				
			||||||
	struct fb_info *info;
 | 
					 | 
				
			||||||
	struct drm_framebuffer *fb;
 | 
					 | 
				
			||||||
	struct nouveau_channel *chan;
 | 
					 | 
				
			||||||
	struct nouveau_bo *nvbo;
 | 
					 | 
				
			||||||
	struct drm_mode_fb_cmd2 mode_cmd = {};
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mode_cmd.width = sizes->surface_width;
 | 
					 | 
				
			||||||
	mode_cmd.height = sizes->surface_height;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mode_cmd.pitches[0] = mode_cmd.width * (sizes->surface_bpp >> 3);
 | 
					 | 
				
			||||||
	mode_cmd.pitches[0] = roundup(mode_cmd.pitches[0], 256);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
 | 
					 | 
				
			||||||
							  sizes->surface_depth);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = nouveau_gem_new(&drm->client, mode_cmd.pitches[0] *
 | 
					 | 
				
			||||||
			      mode_cmd.height, 0, NOUVEAU_GEM_DOMAIN_VRAM,
 | 
					 | 
				
			||||||
			      0, 0x0000, &nvbo);
 | 
					 | 
				
			||||||
	if (ret) {
 | 
					 | 
				
			||||||
		NV_ERROR(drm, "failed to allocate framebuffer\n");
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = nouveau_framebuffer_new(dev, &mode_cmd, &nvbo->bo.base, &fb);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		goto out_unref;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = nouveau_bo_pin(nvbo, NOUVEAU_GEM_DOMAIN_VRAM, false);
 | 
					 | 
				
			||||||
	if (ret) {
 | 
					 | 
				
			||||||
		NV_ERROR(drm, "failed to pin fb: %d\n", ret);
 | 
					 | 
				
			||||||
		goto out_unref;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = nouveau_bo_map(nvbo);
 | 
					 | 
				
			||||||
	if (ret) {
 | 
					 | 
				
			||||||
		NV_ERROR(drm, "failed to map fb: %d\n", ret);
 | 
					 | 
				
			||||||
		goto out_unpin;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	chan = nouveau_nofbaccel ? NULL : drm->channel;
 | 
					 | 
				
			||||||
	if (chan && device->info.family >= NV_DEVICE_INFO_V0_TESLA) {
 | 
					 | 
				
			||||||
		ret = nouveau_vma_new(nvbo, chan->vmm, &fbcon->vma);
 | 
					 | 
				
			||||||
		if (ret) {
 | 
					 | 
				
			||||||
			NV_ERROR(drm, "failed to map fb into chan: %d\n", ret);
 | 
					 | 
				
			||||||
			chan = NULL;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	info = drm_fb_helper_alloc_fbi(helper);
 | 
					 | 
				
			||||||
	if (IS_ERR(info)) {
 | 
					 | 
				
			||||||
		ret = PTR_ERR(info);
 | 
					 | 
				
			||||||
		goto out_unlock;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* setup helper */
 | 
					 | 
				
			||||||
	fbcon->helper.fb = fb;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!chan)
 | 
					 | 
				
			||||||
		info->flags = FBINFO_HWACCEL_DISABLED;
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		info->flags = FBINFO_HWACCEL_COPYAREA |
 | 
					 | 
				
			||||||
			      FBINFO_HWACCEL_FILLRECT |
 | 
					 | 
				
			||||||
			      FBINFO_HWACCEL_IMAGEBLIT;
 | 
					 | 
				
			||||||
	info->fbops = &nouveau_fbcon_sw_ops;
 | 
					 | 
				
			||||||
	info->fix.smem_start = nvbo->bo.resource->bus.offset;
 | 
					 | 
				
			||||||
	info->fix.smem_len = nvbo->bo.base.size;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	info->screen_base = nvbo_kmap_obj_iovirtual(nvbo);
 | 
					 | 
				
			||||||
	info->screen_size = nvbo->bo.base.size;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	drm_fb_helper_fill_info(info, &fbcon->helper, sizes);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (chan)
 | 
					 | 
				
			||||||
		nouveau_fbcon_accel_init(dev);
 | 
					 | 
				
			||||||
	nouveau_fbcon_zfill(dev, fbcon);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* To allow resizeing without swapping buffers */
 | 
					 | 
				
			||||||
	NV_INFO(drm, "allocated %dx%d fb: 0x%llx, bo %p\n",
 | 
					 | 
				
			||||||
		fb->width, fb->height, nvbo->offset, nvbo);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (dev_is_pci(dev->dev))
 | 
					 | 
				
			||||||
		vga_switcheroo_client_fb_set(to_pci_dev(dev->dev), info);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
out_unlock:
 | 
					 | 
				
			||||||
	if (chan)
 | 
					 | 
				
			||||||
		nouveau_vma_del(&fbcon->vma);
 | 
					 | 
				
			||||||
	nouveau_bo_unmap(nvbo);
 | 
					 | 
				
			||||||
out_unpin:
 | 
					 | 
				
			||||||
	nouveau_bo_unpin(nvbo);
 | 
					 | 
				
			||||||
out_unref:
 | 
					 | 
				
			||||||
	nouveau_bo_ref(NULL, &nvbo);
 | 
					 | 
				
			||||||
out:
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int
 | 
					 | 
				
			||||||
nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct drm_framebuffer *fb = fbcon->helper.fb;
 | 
					 | 
				
			||||||
	struct nouveau_bo *nvbo;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	drm_fb_helper_unregister_fbi(&fbcon->helper);
 | 
					 | 
				
			||||||
	drm_fb_helper_fini(&fbcon->helper);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (fb && fb->obj[0]) {
 | 
					 | 
				
			||||||
		nvbo = nouveau_gem_object(fb->obj[0]);
 | 
					 | 
				
			||||||
		nouveau_vma_del(&fbcon->vma);
 | 
					 | 
				
			||||||
		nouveau_bo_unmap(nvbo);
 | 
					 | 
				
			||||||
		nouveau_bo_unpin(nvbo);
 | 
					 | 
				
			||||||
		drm_framebuffer_put(fb);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void nouveau_fbcon_gpu_lockup(struct fb_info *info)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_fbdev *fbcon = info->par;
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	NV_ERROR(drm, "GPU lockup - switching to software fbcon\n");
 | 
					 | 
				
			||||||
	info->flags |= FBINFO_HWACCEL_DISABLED;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = {
 | 
					 | 
				
			||||||
	.fb_probe = nouveau_fbcon_create,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
nouveau_fbcon_set_suspend_work(struct work_struct *work)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = container_of(work, typeof(*drm), fbcon_work);
 | 
					 | 
				
			||||||
	int state = READ_ONCE(drm->fbcon_new_state);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (state == FBINFO_STATE_RUNNING)
 | 
					 | 
				
			||||||
		pm_runtime_get_sync(drm->dev->dev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	console_lock();
 | 
					 | 
				
			||||||
	if (state == FBINFO_STATE_RUNNING)
 | 
					 | 
				
			||||||
		nouveau_fbcon_accel_restore(drm->dev);
 | 
					 | 
				
			||||||
	drm_fb_helper_set_suspend(&drm->fbcon->helper, state);
 | 
					 | 
				
			||||||
	if (state != FBINFO_STATE_RUNNING)
 | 
					 | 
				
			||||||
		nouveau_fbcon_accel_save_disable(drm->dev);
 | 
					 | 
				
			||||||
	console_unlock();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (state == FBINFO_STATE_RUNNING) {
 | 
					 | 
				
			||||||
		nouveau_fbcon_hotplug_resume(drm->fbcon);
 | 
					 | 
				
			||||||
		pm_runtime_mark_last_busy(drm->dev->dev);
 | 
					 | 
				
			||||||
		pm_runtime_put_autosuspend(drm->dev->dev);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
nouveau_fbcon_set_suspend(struct drm_device *dev, int state)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(dev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!drm->fbcon)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	drm->fbcon_new_state = state;
 | 
					 | 
				
			||||||
	/* Since runtime resume can happen as a result of a sysfs operation,
 | 
					 | 
				
			||||||
	 * it's possible we already have the console locked. So handle fbcon
 | 
					 | 
				
			||||||
	 * init/deinit from a seperate work thread
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	schedule_work(&drm->fbcon_work);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
nouveau_fbcon_output_poll_changed(struct drm_device *dev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(dev);
 | 
					 | 
				
			||||||
	struct nouveau_fbdev *fbcon = drm->fbcon;
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!fbcon)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mutex_lock(&fbcon->hotplug_lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = pm_runtime_get(dev->dev);
 | 
					 | 
				
			||||||
	if (ret == 1 || ret == -EACCES) {
 | 
					 | 
				
			||||||
		drm_fb_helper_hotplug_event(&fbcon->helper);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		pm_runtime_mark_last_busy(dev->dev);
 | 
					 | 
				
			||||||
		pm_runtime_put_autosuspend(dev->dev);
 | 
					 | 
				
			||||||
	} else if (ret == 0) {
 | 
					 | 
				
			||||||
		/* If the GPU was already in the process of suspending before
 | 
					 | 
				
			||||||
		 * this event happened, then we can't block here as we'll
 | 
					 | 
				
			||||||
		 * deadlock the runtime pmops since they wait for us to
 | 
					 | 
				
			||||||
		 * finish. So, just defer this event for when we runtime
 | 
					 | 
				
			||||||
		 * resume again. It will be handled by fbcon_work.
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		NV_DEBUG(drm, "fbcon HPD event deferred until runtime resume\n");
 | 
					 | 
				
			||||||
		fbcon->hotplug_waiting = true;
 | 
					 | 
				
			||||||
		pm_runtime_put_noidle(drm->dev->dev);
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		DRM_WARN("fbcon HPD event lost due to RPM failure: %d\n",
 | 
					 | 
				
			||||||
			 ret);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mutex_unlock(&fbcon->hotplug_lock);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
nouveau_fbcon_hotplug_resume(struct nouveau_fbdev *fbcon)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!fbcon)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	drm = nouveau_drm(fbcon->helper.dev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mutex_lock(&fbcon->hotplug_lock);
 | 
					 | 
				
			||||||
	if (fbcon->hotplug_waiting) {
 | 
					 | 
				
			||||||
		fbcon->hotplug_waiting = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		NV_DEBUG(drm, "Handling deferred fbcon HPD events\n");
 | 
					 | 
				
			||||||
		drm_fb_helper_hotplug_event(&fbcon->helper);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	mutex_unlock(&fbcon->hotplug_lock);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int
 | 
					 | 
				
			||||||
nouveau_fbcon_init(struct drm_device *dev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(dev);
 | 
					 | 
				
			||||||
	struct nouveau_fbdev *fbcon;
 | 
					 | 
				
			||||||
	int preferred_bpp = nouveau_fbcon_bpp;
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!dev->mode_config.num_crtc ||
 | 
					 | 
				
			||||||
	    (to_pci_dev(dev->dev)->class >> 8) != PCI_CLASS_DISPLAY_VGA)
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	fbcon = kzalloc(sizeof(struct nouveau_fbdev), GFP_KERNEL);
 | 
					 | 
				
			||||||
	if (!fbcon)
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	drm->fbcon = fbcon;
 | 
					 | 
				
			||||||
	INIT_WORK(&drm->fbcon_work, nouveau_fbcon_set_suspend_work);
 | 
					 | 
				
			||||||
	mutex_init(&fbcon->hotplug_lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	drm_fb_helper_prepare(dev, &fbcon->helper, &nouveau_fbcon_helper_funcs);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = drm_fb_helper_init(dev, &fbcon->helper);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		goto free;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (preferred_bpp != 8 && preferred_bpp != 16 && preferred_bpp != 32) {
 | 
					 | 
				
			||||||
		if (drm->client.device.info.ram_size <= 32 * 1024 * 1024)
 | 
					 | 
				
			||||||
			preferred_bpp = 8;
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
		if (drm->client.device.info.ram_size <= 64 * 1024 * 1024)
 | 
					 | 
				
			||||||
			preferred_bpp = 16;
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			preferred_bpp = 32;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* disable all the possible outputs/crtcs before entering KMS mode */
 | 
					 | 
				
			||||||
	if (!drm_drv_uses_atomic_modeset(dev))
 | 
					 | 
				
			||||||
		drm_helper_disable_unused_functions(dev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = drm_fb_helper_initial_config(&fbcon->helper, preferred_bpp);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		goto fini;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (fbcon->helper.fbdev)
 | 
					 | 
				
			||||||
		fbcon->helper.fbdev->pixmap.buf_align = 4;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fini:
 | 
					 | 
				
			||||||
	drm_fb_helper_fini(&fbcon->helper);
 | 
					 | 
				
			||||||
free:
 | 
					 | 
				
			||||||
	kfree(fbcon);
 | 
					 | 
				
			||||||
	drm->fbcon = NULL;
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
nouveau_fbcon_fini(struct drm_device *dev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(dev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!drm->fbcon)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	drm_kms_helper_poll_fini(dev);
 | 
					 | 
				
			||||||
	nouveau_fbcon_accel_fini(dev);
 | 
					 | 
				
			||||||
	nouveau_fbcon_destroy(dev, drm->fbcon);
 | 
					 | 
				
			||||||
	kfree(drm->fbcon);
 | 
					 | 
				
			||||||
	drm->fbcon = NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,82 +0,0 @@
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Copyright (C) 2008 Maarten Maathuis.
 | 
					 | 
				
			||||||
 * All Rights Reserved.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Permission is hereby granted, free of charge, to any person obtaining
 | 
					 | 
				
			||||||
 * a copy of this software and associated documentation files (the
 | 
					 | 
				
			||||||
 * "Software"), to deal in the Software without restriction, including
 | 
					 | 
				
			||||||
 * without limitation the rights to use, copy, modify, merge, publish,
 | 
					 | 
				
			||||||
 * distribute, sublicense, and/or sell copies of the Software, and to
 | 
					 | 
				
			||||||
 * permit persons to whom the Software is furnished to do so, subject to
 | 
					 | 
				
			||||||
 * the following conditions:
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The above copyright notice and this permission notice (including the
 | 
					 | 
				
			||||||
 * next paragraph) shall be included in all copies or substantial
 | 
					 | 
				
			||||||
 * portions of the Software.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | 
					 | 
				
			||||||
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | 
					 | 
				
			||||||
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 | 
					 | 
				
			||||||
 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
 | 
					 | 
				
			||||||
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 | 
					 | 
				
			||||||
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 | 
					 | 
				
			||||||
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef __NOUVEAU_FBCON_H__
 | 
					 | 
				
			||||||
#define __NOUVEAU_FBCON_H__
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <drm/drm_fb_helper.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "nouveau_display.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct nouveau_vma;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct nouveau_fbdev {
 | 
					 | 
				
			||||||
	struct drm_fb_helper helper; /* must be first */
 | 
					 | 
				
			||||||
	unsigned int saved_flags;
 | 
					 | 
				
			||||||
	struct nvif_object surf2d;
 | 
					 | 
				
			||||||
	struct nvif_object clip;
 | 
					 | 
				
			||||||
	struct nvif_object rop;
 | 
					 | 
				
			||||||
	struct nvif_object patt;
 | 
					 | 
				
			||||||
	struct nvif_object gdi;
 | 
					 | 
				
			||||||
	struct nvif_object blit;
 | 
					 | 
				
			||||||
	struct nvif_object twod;
 | 
					 | 
				
			||||||
	struct nouveau_vma *vma;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct mutex hotplug_lock;
 | 
					 | 
				
			||||||
	bool hotplug_waiting;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void nouveau_fbcon_restore(void);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region);
 | 
					 | 
				
			||||||
int nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
 | 
					 | 
				
			||||||
int nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
 | 
					 | 
				
			||||||
int nv04_fbcon_accel_init(struct fb_info *info);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
 | 
					 | 
				
			||||||
int nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region);
 | 
					 | 
				
			||||||
int nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
 | 
					 | 
				
			||||||
int nv50_fbcon_accel_init(struct fb_info *info);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int nvc0_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
 | 
					 | 
				
			||||||
int nvc0_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region);
 | 
					 | 
				
			||||||
int nvc0_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
 | 
					 | 
				
			||||||
int nvc0_fbcon_accel_init(struct fb_info *info);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void nouveau_fbcon_gpu_lockup(struct fb_info *info);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int nouveau_fbcon_init(struct drm_device *dev);
 | 
					 | 
				
			||||||
void nouveau_fbcon_fini(struct drm_device *dev);
 | 
					 | 
				
			||||||
void nouveau_fbcon_set_suspend(struct drm_device *dev, int state);
 | 
					 | 
				
			||||||
void nouveau_fbcon_accel_save_disable(struct drm_device *dev);
 | 
					 | 
				
			||||||
void nouveau_fbcon_accel_restore(struct drm_device *dev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void nouveau_fbcon_output_poll_changed(struct drm_device *dev);
 | 
					 | 
				
			||||||
void nouveau_fbcon_hotplug_resume(struct nouveau_fbdev *fbcon);
 | 
					 | 
				
			||||||
extern int nouveau_nofbaccel;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif /* __NV50_FBCON_H__ */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
| 
						 | 
					@ -7,7 +7,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "nouveau_drv.h"
 | 
					#include "nouveau_drv.h"
 | 
				
			||||||
#include "nouveau_acpi.h"
 | 
					#include "nouveau_acpi.h"
 | 
				
			||||||
#include "nouveau_fbcon.h"
 | 
					 | 
				
			||||||
#include "nouveau_vga.h"
 | 
					#include "nouveau_vga.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static unsigned int
 | 
					static unsigned int
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,259 +0,0 @@
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Copyright 2009 Ben Skeggs
 | 
					 | 
				
			||||||
 * Copyright 2008 Stuart Bennett
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Permission is hereby granted, free of charge, to any person obtaining a
 | 
					 | 
				
			||||||
 * copy of this software and associated documentation files (the "Software"),
 | 
					 | 
				
			||||||
 * to deal in the Software without restriction, including without limitation
 | 
					 | 
				
			||||||
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 | 
					 | 
				
			||||||
 * and/or sell copies of the Software, and to permit persons to whom the
 | 
					 | 
				
			||||||
 * Software is furnished to do so, subject to the following conditions:
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The above copyright notice and this permission notice (including the next
 | 
					 | 
				
			||||||
 * paragraph) shall be included in all copies or substantial portions of the
 | 
					 | 
				
			||||||
 * Software.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
					 | 
				
			||||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
					 | 
				
			||||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 | 
					 | 
				
			||||||
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
					 | 
				
			||||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
					 | 
				
			||||||
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 | 
					 | 
				
			||||||
 * DEALINGS IN THE SOFTWARE.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
#define NVIF_DEBUG_PRINT_DISABLE
 | 
					 | 
				
			||||||
#include "nouveau_drv.h"
 | 
					 | 
				
			||||||
#include "nouveau_dma.h"
 | 
					 | 
				
			||||||
#include "nouveau_fbcon.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <nvif/push006c.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int
 | 
					 | 
				
			||||||
nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_fbdev *nfbdev = info->par;
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
 | 
					 | 
				
			||||||
	struct nouveau_channel *chan = drm->channel;
 | 
					 | 
				
			||||||
	struct nvif_push *push = chan->chan.push;
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = PUSH_WAIT(push, 4);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_NVSQ(push, NV05F, 0x0300, (region->sy << 16) | region->sx,
 | 
					 | 
				
			||||||
			       0x0304, (region->dy << 16) | region->dx,
 | 
					 | 
				
			||||||
			       0x0308, (region->height << 16) | region->width);
 | 
					 | 
				
			||||||
	PUSH_KICK(push);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int
 | 
					 | 
				
			||||||
nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_fbdev *nfbdev = info->par;
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
 | 
					 | 
				
			||||||
	struct nouveau_channel *chan = drm->channel;
 | 
					 | 
				
			||||||
	struct nvif_push *push = chan->chan.push;
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = PUSH_WAIT(push, 7);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_NVSQ(push, NV04A, 0x02fc, (rect->rop != ROP_COPY) ? 1 : 3);
 | 
					 | 
				
			||||||
	if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
 | 
					 | 
				
			||||||
	    info->fix.visual == FB_VISUAL_DIRECTCOLOR)
 | 
					 | 
				
			||||||
		PUSH_NVSQ(push, NV04A, 0x03fc, ((uint32_t *)info->pseudo_palette)[rect->color]);
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		PUSH_NVSQ(push, NV04A, 0x03fc, rect->color);
 | 
					 | 
				
			||||||
	PUSH_NVSQ(push, NV04A, 0x0400, (rect->dx << 16) | rect->dy,
 | 
					 | 
				
			||||||
			       0x0404, (rect->width << 16) | rect->height);
 | 
					 | 
				
			||||||
	PUSH_KICK(push);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int
 | 
					 | 
				
			||||||
nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_fbdev *nfbdev = info->par;
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
 | 
					 | 
				
			||||||
	struct nouveau_channel *chan = drm->channel;
 | 
					 | 
				
			||||||
	struct nvif_push *push = chan->chan.push;
 | 
					 | 
				
			||||||
	uint32_t fg;
 | 
					 | 
				
			||||||
	uint32_t bg;
 | 
					 | 
				
			||||||
	uint32_t dsize;
 | 
					 | 
				
			||||||
	uint32_t *data = (uint32_t *)image->data;
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (image->depth != 1)
 | 
					 | 
				
			||||||
		return -ENODEV;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = PUSH_WAIT(push, 8);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
 | 
					 | 
				
			||||||
	    info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
 | 
					 | 
				
			||||||
		fg = ((uint32_t *) info->pseudo_palette)[image->fg_color];
 | 
					 | 
				
			||||||
		bg = ((uint32_t *) info->pseudo_palette)[image->bg_color];
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		fg = image->fg_color;
 | 
					 | 
				
			||||||
		bg = image->bg_color;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_NVSQ(push, NV04A, 0x0be4, (image->dy << 16) | (image->dx & 0xffff),
 | 
					 | 
				
			||||||
			       0x0be8, ((image->dy + image->height) << 16) |
 | 
					 | 
				
			||||||
				       ((image->dx + image->width) & 0xffff),
 | 
					 | 
				
			||||||
			       0x0bec, bg,
 | 
					 | 
				
			||||||
			       0x0bf0, fg,
 | 
					 | 
				
			||||||
			       0x0bf4, (image->height << 16) | ALIGN(image->width, 8),
 | 
					 | 
				
			||||||
			       0x0bf8, (image->height << 16) | image->width,
 | 
					 | 
				
			||||||
			       0x0bfc, (image->dy << 16) | (image->dx & 0xffff));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	dsize = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5;
 | 
					 | 
				
			||||||
	while (dsize) {
 | 
					 | 
				
			||||||
		int iter_len = dsize > 128 ? 128 : dsize;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ret = PUSH_WAIT(push, iter_len + 1);
 | 
					 | 
				
			||||||
		if (ret)
 | 
					 | 
				
			||||||
			return ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		PUSH_NVSQ(push, NV04A, 0x0c00, data, iter_len);
 | 
					 | 
				
			||||||
		data += iter_len;
 | 
					 | 
				
			||||||
		dsize -= iter_len;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_KICK(push);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int
 | 
					 | 
				
			||||||
nv04_fbcon_accel_init(struct fb_info *info)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_fbdev *nfbdev = info->par;
 | 
					 | 
				
			||||||
	struct drm_device *dev = nfbdev->helper.dev;
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(dev);
 | 
					 | 
				
			||||||
	struct nouveau_channel *chan = drm->channel;
 | 
					 | 
				
			||||||
	struct nvif_device *device = &drm->client.device;
 | 
					 | 
				
			||||||
	struct nvif_push *push = chan->chan.push;
 | 
					 | 
				
			||||||
	struct nvkm_device *nvkm_device = nvxx_device(&drm->client.device);
 | 
					 | 
				
			||||||
	resource_size_t fb_base = nvkm_device->func->resource_addr(nvkm_device, 1);
 | 
					 | 
				
			||||||
	int surface_fmt, pattern_fmt, rect_fmt;
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (info->var.bits_per_pixel) {
 | 
					 | 
				
			||||||
	case 8:
 | 
					 | 
				
			||||||
		surface_fmt = 1;
 | 
					 | 
				
			||||||
		pattern_fmt = 3;
 | 
					 | 
				
			||||||
		rect_fmt = 3;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case 16:
 | 
					 | 
				
			||||||
		surface_fmt = 4;
 | 
					 | 
				
			||||||
		pattern_fmt = 1;
 | 
					 | 
				
			||||||
		rect_fmt = 1;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case 32:
 | 
					 | 
				
			||||||
		switch (info->var.transp.length) {
 | 
					 | 
				
			||||||
		case 0: /* depth 24 */
 | 
					 | 
				
			||||||
		case 8: /* depth 32 */
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			return -EINVAL;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		surface_fmt = 6;
 | 
					 | 
				
			||||||
		pattern_fmt = 3;
 | 
					 | 
				
			||||||
		rect_fmt = 3;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = nvif_object_ctor(&chan->user, "fbconCtxSurf2d", 0x0062,
 | 
					 | 
				
			||||||
			       device->info.family >= NV_DEVICE_INFO_V0_CELSIUS ?
 | 
					 | 
				
			||||||
			       0x0062 : 0x0042, NULL, 0, &nfbdev->surf2d);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = nvif_object_ctor(&chan->user, "fbconCtxClip", 0x0019, 0x0019,
 | 
					 | 
				
			||||||
			       NULL, 0, &nfbdev->clip);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = nvif_object_ctor(&chan->user, "fbconCtxRop", 0x0043, 0x0043,
 | 
					 | 
				
			||||||
			       NULL, 0, &nfbdev->rop);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = nvif_object_ctor(&chan->user, "fbconCtxPatt", 0x0044, 0x0044,
 | 
					 | 
				
			||||||
			       NULL, 0, &nfbdev->patt);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = nvif_object_ctor(&chan->user, "fbconGdiRectText", 0x004a, 0x004a,
 | 
					 | 
				
			||||||
			       NULL, 0, &nfbdev->gdi);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = nvif_object_ctor(&chan->user, "fbconImageBlit", 0x005f,
 | 
					 | 
				
			||||||
			       device->info.chipset >= 0x11 ? 0x009f : 0x005f,
 | 
					 | 
				
			||||||
			       NULL, 0, &nfbdev->blit);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (PUSH_WAIT(push, 49 + (device->info.chipset >= 0x11 ? 4 : 0))) {
 | 
					 | 
				
			||||||
		nouveau_fbcon_gpu_lockup(info);
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_NVSQ(push, NV042, 0x0000, nfbdev->surf2d.handle);
 | 
					 | 
				
			||||||
	PUSH_NVSQ(push, NV042, 0x0184, chan->vram.handle,
 | 
					 | 
				
			||||||
			       0x0188, chan->vram.handle);
 | 
					 | 
				
			||||||
	PUSH_NVSQ(push, NV042, 0x0300, surface_fmt,
 | 
					 | 
				
			||||||
			       0x0304, info->fix.line_length | (info->fix.line_length << 16),
 | 
					 | 
				
			||||||
			       0x0308, info->fix.smem_start - fb_base,
 | 
					 | 
				
			||||||
			       0x030c, info->fix.smem_start - fb_base);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_NVSQ(push, NV043, 0x0000, nfbdev->rop.handle);
 | 
					 | 
				
			||||||
	PUSH_NVSQ(push, NV043, 0x0300, 0x55);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_NVSQ(push, NV044, 0x0000, nfbdev->patt.handle);
 | 
					 | 
				
			||||||
	PUSH_NVSQ(push, NV044, 0x0300, pattern_fmt,
 | 
					 | 
				
			||||||
#ifdef __BIG_ENDIAN
 | 
					 | 
				
			||||||
			       0x0304, 2,
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
			       0x0304, 1,
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
			       0x0308, 0,
 | 
					 | 
				
			||||||
			       0x030c, 1,
 | 
					 | 
				
			||||||
			       0x0310, ~0,
 | 
					 | 
				
			||||||
			       0x0314, ~0,
 | 
					 | 
				
			||||||
			       0x0318, ~0,
 | 
					 | 
				
			||||||
			       0x031c, ~0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_NVSQ(push, NV019, 0x0000, nfbdev->clip.handle);
 | 
					 | 
				
			||||||
	PUSH_NVSQ(push, NV019, 0x0300, 0,
 | 
					 | 
				
			||||||
			       0x0304, (info->var.yres_virtual << 16) | info->var.xres_virtual);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_NVSQ(push, NV05F, 0x0000, nfbdev->blit.handle);
 | 
					 | 
				
			||||||
	PUSH_NVSQ(push, NV05F, 0x019c, nfbdev->surf2d.handle);
 | 
					 | 
				
			||||||
	PUSH_NVSQ(push, NV05F, 0x02fc, 3);
 | 
					 | 
				
			||||||
	if (nfbdev->blit.oclass == 0x009f) {
 | 
					 | 
				
			||||||
		PUSH_NVSQ(push, NV09F, 0x0120, 0,
 | 
					 | 
				
			||||||
				       0x0124, 1,
 | 
					 | 
				
			||||||
				       0x0128, 2);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_NVSQ(push, NV04A, 0x0000, nfbdev->gdi.handle);
 | 
					 | 
				
			||||||
	PUSH_NVSQ(push, NV04A, 0x0198, nfbdev->surf2d.handle);
 | 
					 | 
				
			||||||
	PUSH_NVSQ(push, NV04A, 0x0188, nfbdev->patt.handle,
 | 
					 | 
				
			||||||
			       0x018c, nfbdev->rop.handle);
 | 
					 | 
				
			||||||
	PUSH_NVSQ(push, NV04A, 0x0304, 1);
 | 
					 | 
				
			||||||
	PUSH_NVSQ(push, NV04A, 0x0300, rect_fmt);
 | 
					 | 
				
			||||||
	PUSH_NVSQ(push, NV04A, 0x02fc, 3);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_KICK(push);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,299 +0,0 @@
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Copyright 2010 Red Hat Inc.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Permission is hereby granted, free of charge, to any person obtaining a
 | 
					 | 
				
			||||||
 * copy of this software and associated documentation files (the "Software"),
 | 
					 | 
				
			||||||
 * to deal in the Software without restriction, including without limitation
 | 
					 | 
				
			||||||
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 | 
					 | 
				
			||||||
 * and/or sell copies of the Software, and to permit persons to whom the
 | 
					 | 
				
			||||||
 * Software is furnished to do so, subject to the following conditions:
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The above copyright notice and this permission notice shall be included in
 | 
					 | 
				
			||||||
 * all copies or substantial portions of the Software.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
					 | 
				
			||||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
					 | 
				
			||||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 | 
					 | 
				
			||||||
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 | 
					 | 
				
			||||||
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 | 
					 | 
				
			||||||
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 | 
					 | 
				
			||||||
 * OTHER DEALINGS IN THE SOFTWARE.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Authors: Ben Skeggs
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
#define NVIF_DEBUG_PRINT_DISABLE
 | 
					 | 
				
			||||||
#include "nouveau_drv.h"
 | 
					 | 
				
			||||||
#include "nouveau_dma.h"
 | 
					 | 
				
			||||||
#include "nouveau_fbcon.h"
 | 
					 | 
				
			||||||
#include "nouveau_vmm.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <nvif/push206e.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <nvhw/class/cl502d.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int
 | 
					 | 
				
			||||||
nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_fbdev *nfbdev = info->par;
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
 | 
					 | 
				
			||||||
	struct nouveau_channel *chan = drm->channel;
 | 
					 | 
				
			||||||
	struct nvif_push *push = chan->chan.push;
 | 
					 | 
				
			||||||
	u32 colour;
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
 | 
					 | 
				
			||||||
	    info->fix.visual == FB_VISUAL_DIRECTCOLOR)
 | 
					 | 
				
			||||||
		colour = ((uint32_t *)info->pseudo_palette)[rect->color];
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		colour = rect->color;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = PUSH_WAIT(push, rect->rop == ROP_COPY ? 7 : 11);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (rect->rop != ROP_COPY) {
 | 
					 | 
				
			||||||
		PUSH_MTHD(push, NV502D, SET_OPERATION,
 | 
					 | 
				
			||||||
			  NVDEF(NV502D, SET_OPERATION, V, ROP_AND));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV502D, SET_RENDER_SOLID_PRIM_COLOR, colour);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV502D, RENDER_SOLID_PRIM_POINT_SET_X(0), rect->dx,
 | 
					 | 
				
			||||||
				RENDER_SOLID_PRIM_POINT_Y(0), rect->dy,
 | 
					 | 
				
			||||||
				RENDER_SOLID_PRIM_POINT_SET_X(1), rect->dx + rect->width,
 | 
					 | 
				
			||||||
				RENDER_SOLID_PRIM_POINT_Y(1), rect->dy + rect->height);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (rect->rop != ROP_COPY) {
 | 
					 | 
				
			||||||
		PUSH_MTHD(push, NV502D, SET_OPERATION,
 | 
					 | 
				
			||||||
			  NVDEF(NV502D, SET_OPERATION, V, SRCCOPY));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_KICK(push);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int
 | 
					 | 
				
			||||||
nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_fbdev *nfbdev = info->par;
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
 | 
					 | 
				
			||||||
	struct nouveau_channel *chan = drm->channel;
 | 
					 | 
				
			||||||
	struct nvif_push *push = chan->chan.push;
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = PUSH_WAIT(push, 12);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV502D, WAIT_FOR_IDLE, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_MEMORY_DST_X0, region->dx,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_MEMORY_DST_Y0, region->dy,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_MEMORY_DST_WIDTH, region->width,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_MEMORY_DST_HEIGHT, region->height);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_MEMORY_SRC_X0_FRAC, 0,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_MEMORY_SRC_X0_INT, region->sx,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_MEMORY_SRC_Y0_FRAC, 0,
 | 
					 | 
				
			||||||
				PIXELS_FROM_MEMORY_SRC_Y0_INT, region->sy);
 | 
					 | 
				
			||||||
	PUSH_KICK(push);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int
 | 
					 | 
				
			||||||
nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_fbdev *nfbdev = info->par;
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
 | 
					 | 
				
			||||||
	struct nouveau_channel *chan = drm->channel;
 | 
					 | 
				
			||||||
	struct nvif_push *push = chan->chan.push;
 | 
					 | 
				
			||||||
	uint32_t dwords, *data = (uint32_t *)image->data;
 | 
					 | 
				
			||||||
	uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel));
 | 
					 | 
				
			||||||
	uint32_t *palette = info->pseudo_palette, bg, fg;
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (image->depth != 1)
 | 
					 | 
				
			||||||
		return -ENODEV;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
 | 
					 | 
				
			||||||
	    info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
 | 
					 | 
				
			||||||
		bg = palette[image->bg_color] | mask;
 | 
					 | 
				
			||||||
		fg = palette[image->fg_color] | mask;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		bg = image->bg_color;
 | 
					 | 
				
			||||||
		fg = image->fg_color;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = PUSH_WAIT(push, 11);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_COLOR0, bg,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_CPU_COLOR1, fg);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_SRC_WIDTH, image->width,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_CPU_SRC_HEIGHT, image->height);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_DST_X0_FRAC, 0,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_CPU_DST_X0_INT, image->dx,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_CPU_DST_Y0_FRAC, 0,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_CPU_DST_Y0_INT, image->dy);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	dwords = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5;
 | 
					 | 
				
			||||||
	while (dwords) {
 | 
					 | 
				
			||||||
		int count = dwords > 2047 ? 2047 : dwords;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ret = PUSH_WAIT(push, count + 1);
 | 
					 | 
				
			||||||
		if (ret)
 | 
					 | 
				
			||||||
			return ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		dwords -= count;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		PUSH_NINC(push, NV502D, PIXELS_FROM_CPU_DATA, data, count);
 | 
					 | 
				
			||||||
		data += count;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_KICK(push);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int
 | 
					 | 
				
			||||||
nv50_fbcon_accel_init(struct fb_info *info)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_fbdev *nfbdev = info->par;
 | 
					 | 
				
			||||||
	struct drm_device *dev = nfbdev->helper.dev;
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(dev);
 | 
					 | 
				
			||||||
	struct nouveau_channel *chan = drm->channel;
 | 
					 | 
				
			||||||
	struct nvif_push *push = chan->chan.push;
 | 
					 | 
				
			||||||
	int ret, format;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (info->var.bits_per_pixel) {
 | 
					 | 
				
			||||||
	case 8:
 | 
					 | 
				
			||||||
		format = NV502D_SET_DST_FORMAT_V_Y8;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case 15:
 | 
					 | 
				
			||||||
		format = NV502D_SET_DST_FORMAT_V_X1R5G5B5;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case 16:
 | 
					 | 
				
			||||||
		format = NV502D_SET_DST_FORMAT_V_R5G6B5;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case 32:
 | 
					 | 
				
			||||||
		switch (info->var.transp.length) {
 | 
					 | 
				
			||||||
		case 0: /* depth 24 */
 | 
					 | 
				
			||||||
		case 8: /* depth 32, just use 24.. */
 | 
					 | 
				
			||||||
			format = NV502D_SET_DST_FORMAT_V_X8R8G8B8;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case 2: /* depth 30 */
 | 
					 | 
				
			||||||
			format = NV502D_SET_DST_FORMAT_V_A2B10G10R10;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			return -EINVAL;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = nvif_object_ctor(&chan->user, "fbconTwoD", 0x502d, 0x502d,
 | 
					 | 
				
			||||||
			       NULL, 0, &nfbdev->twod);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = PUSH_WAIT(push, 56);
 | 
					 | 
				
			||||||
	if (ret) {
 | 
					 | 
				
			||||||
		nouveau_fbcon_gpu_lockup(info);
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV502D, SET_OBJECT, nfbdev->twod.handle);
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV502D, SET_DST_CONTEXT_DMA, chan->vram.handle,
 | 
					 | 
				
			||||||
				SET_SRC_CONTEXT_DMA, chan->vram.handle,
 | 
					 | 
				
			||||||
				SET_SEMAPHORE_CONTEXT_DMA, chan->vram.handle);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV502D, SET_DST_FORMAT,
 | 
					 | 
				
			||||||
		  NVVAL(NV502D, SET_DST_FORMAT, V, format),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				SET_DST_MEMORY_LAYOUT,
 | 
					 | 
				
			||||||
		  NVDEF(NV502D, SET_DST_MEMORY_LAYOUT, V, PITCH));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV502D, SET_DST_PITCH, info->fix.line_length,
 | 
					 | 
				
			||||||
				SET_DST_WIDTH, info->var.xres_virtual,
 | 
					 | 
				
			||||||
				SET_DST_HEIGHT, info->var.yres_virtual,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				SET_DST_OFFSET_UPPER,
 | 
					 | 
				
			||||||
		  NVVAL(NV502D, SET_DST_OFFSET_UPPER, V, upper_32_bits(nfbdev->vma->addr)),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				SET_DST_OFFSET_LOWER,
 | 
					 | 
				
			||||||
		  NVVAL(NV502D, SET_DST_OFFSET_LOWER, V, lower_32_bits(nfbdev->vma->addr)));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV502D, SET_SRC_FORMAT,
 | 
					 | 
				
			||||||
		  NVVAL(NV502D, SET_SRC_FORMAT, V, format),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				SET_SRC_MEMORY_LAYOUT,
 | 
					 | 
				
			||||||
		  NVDEF(NV502D, SET_SRC_MEMORY_LAYOUT, V, PITCH));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV502D, SET_SRC_PITCH, info->fix.line_length,
 | 
					 | 
				
			||||||
				SET_SRC_WIDTH, info->var.xres_virtual,
 | 
					 | 
				
			||||||
				SET_SRC_HEIGHT, info->var.yres_virtual,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				SET_SRC_OFFSET_UPPER,
 | 
					 | 
				
			||||||
		  NVVAL(NV502D, SET_SRC_OFFSET_UPPER, V, upper_32_bits(nfbdev->vma->addr)),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				SET_SRC_OFFSET_LOWER,
 | 
					 | 
				
			||||||
		  NVVAL(NV502D, SET_SRC_OFFSET_LOWER, V, lower_32_bits(nfbdev->vma->addr)));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV502D, SET_CLIP_ENABLE,
 | 
					 | 
				
			||||||
		  NVDEF(NV502D, SET_CLIP_ENABLE, V, FALSE));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV502D, SET_ROP,
 | 
					 | 
				
			||||||
		  NVVAL(NV502D, SET_ROP, V, 0x55));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV502D, SET_OPERATION,
 | 
					 | 
				
			||||||
		  NVDEF(NV502D, SET_OPERATION, V, SRCCOPY));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV502D, SET_MONOCHROME_PATTERN_COLOR_FORMAT,
 | 
					 | 
				
			||||||
		  NVDEF(NV502D, SET_MONOCHROME_PATTERN_COLOR_FORMAT, V, A8R8G8B8),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				SET_MONOCHROME_PATTERN_FORMAT,
 | 
					 | 
				
			||||||
		  NVDEF(NV502D, SET_MONOCHROME_PATTERN_FORMAT, V, LE_M1));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV502D, RENDER_SOLID_PRIM_MODE,
 | 
					 | 
				
			||||||
		  NVDEF(NV502D, RENDER_SOLID_PRIM_MODE, V, RECTS),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				SET_RENDER_SOLID_PRIM_COLOR_FORMAT,
 | 
					 | 
				
			||||||
		  NVVAL(NV502D, SET_RENDER_SOLID_PRIM_COLOR_FORMAT, V, format));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_DATA_TYPE,
 | 
					 | 
				
			||||||
		  NVDEF(NV502D, SET_PIXELS_FROM_CPU_DATA_TYPE, V, INDEX),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_CPU_COLOR_FORMAT,
 | 
					 | 
				
			||||||
		  NVVAL(NV502D, SET_PIXELS_FROM_CPU_COLOR_FORMAT, V, format),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_CPU_INDEX_FORMAT,
 | 
					 | 
				
			||||||
		  NVDEF(NV502D, SET_PIXELS_FROM_CPU_INDEX_FORMAT, V, I1),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_CPU_MONO_FORMAT,
 | 
					 | 
				
			||||||
		  NVDEF(NV502D, SET_PIXELS_FROM_CPU_MONO_FORMAT, V, CGA6_M1),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_CPU_WRAP,
 | 
					 | 
				
			||||||
		  NVDEF(NV502D, SET_PIXELS_FROM_CPU_WRAP, V, WRAP_BYTE));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_MONO_OPACITY,
 | 
					 | 
				
			||||||
		  NVDEF(NV502D, SET_PIXELS_FROM_CPU_MONO_OPACITY, V, OPAQUE));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_CPU_DX_DU_FRAC, 0,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_CPU_DX_DU_INT, 1,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_CPU_DY_DV_FRAC, 0,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_CPU_DY_DV_INT, 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_MEMORY_SAFE_OVERLAP,
 | 
					 | 
				
			||||||
		  NVDEF(NV502D, SET_PIXELS_FROM_MEMORY_SAFE_OVERLAP, V, TRUE));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV502D, SET_PIXELS_FROM_MEMORY_DU_DX_FRAC, 0,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_MEMORY_DU_DX_INT, 1,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_MEMORY_DV_DY_FRAC, 0,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_MEMORY_DV_DY_INT, 1);
 | 
					 | 
				
			||||||
	PUSH_KICK(push);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,297 +0,0 @@
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Copyright 2010 Red Hat Inc.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Permission is hereby granted, free of charge, to any person obtaining a
 | 
					 | 
				
			||||||
 * copy of this software and associated documentation files (the "Software"),
 | 
					 | 
				
			||||||
 * to deal in the Software without restriction, including without limitation
 | 
					 | 
				
			||||||
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 | 
					 | 
				
			||||||
 * and/or sell copies of the Software, and to permit persons to whom the
 | 
					 | 
				
			||||||
 * Software is furnished to do so, subject to the following conditions:
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The above copyright notice and this permission notice shall be included in
 | 
					 | 
				
			||||||
 * all copies or substantial portions of the Software.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
					 | 
				
			||||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
					 | 
				
			||||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 | 
					 | 
				
			||||||
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 | 
					 | 
				
			||||||
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 | 
					 | 
				
			||||||
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 | 
					 | 
				
			||||||
 * OTHER DEALINGS IN THE SOFTWARE.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Authors: Ben Skeggs
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
#define NVIF_DEBUG_PRINT_DISABLE
 | 
					 | 
				
			||||||
#include "nouveau_drv.h"
 | 
					 | 
				
			||||||
#include "nouveau_dma.h"
 | 
					 | 
				
			||||||
#include "nouveau_fbcon.h"
 | 
					 | 
				
			||||||
#include "nouveau_vmm.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <nvif/push906f.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <nvhw/class/cl902d.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int
 | 
					 | 
				
			||||||
nvc0_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_fbdev *nfbdev = info->par;
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
 | 
					 | 
				
			||||||
	struct nouveau_channel *chan = drm->channel;
 | 
					 | 
				
			||||||
	struct nvif_push *push = chan->chan.push;
 | 
					 | 
				
			||||||
	u32 colour;
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
 | 
					 | 
				
			||||||
	    info->fix.visual == FB_VISUAL_DIRECTCOLOR)
 | 
					 | 
				
			||||||
		colour = ((uint32_t *)info->pseudo_palette)[rect->color];
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		colour = rect->color;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = PUSH_WAIT(push, rect->rop == ROP_COPY ? 7 : 9);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (rect->rop != ROP_COPY) {
 | 
					 | 
				
			||||||
		PUSH_IMMD(push, NV902D, SET_OPERATION,
 | 
					 | 
				
			||||||
			  NVDEF(NV902D, SET_OPERATION, V, ROP_AND));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV902D, SET_RENDER_SOLID_PRIM_COLOR, colour);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV902D, RENDER_SOLID_PRIM_POINT_SET_X(0), rect->dx,
 | 
					 | 
				
			||||||
				RENDER_SOLID_PRIM_POINT_Y(0), rect->dy,
 | 
					 | 
				
			||||||
				RENDER_SOLID_PRIM_POINT_SET_X(1), rect->dx + rect->width,
 | 
					 | 
				
			||||||
				RENDER_SOLID_PRIM_POINT_Y(1), rect->dy + rect->height);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (rect->rop != ROP_COPY) {
 | 
					 | 
				
			||||||
		PUSH_IMMD(push, NV902D, SET_OPERATION,
 | 
					 | 
				
			||||||
			  NVDEF(NV902D, SET_OPERATION, V, SRCCOPY));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_KICK(push);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int
 | 
					 | 
				
			||||||
nvc0_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_fbdev *nfbdev = info->par;
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
 | 
					 | 
				
			||||||
	struct nouveau_channel *chan = drm->channel;
 | 
					 | 
				
			||||||
	struct nvif_push *push = chan->chan.push;
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = PUSH_WAIT(push, 11);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_IMMD(push, NV902D, WAIT_FOR_IDLE, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_MEMORY_DST_X0, region->dx,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_MEMORY_DST_Y0, region->dy,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_MEMORY_DST_WIDTH, region->width,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_MEMORY_DST_HEIGHT, region->height);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_MEMORY_SRC_X0_FRAC, 0,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_MEMORY_SRC_X0_INT, region->sx,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_MEMORY_SRC_Y0_FRAC, 0,
 | 
					 | 
				
			||||||
				PIXELS_FROM_MEMORY_SRC_Y0_INT, region->sy);
 | 
					 | 
				
			||||||
	PUSH_KICK(push);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int
 | 
					 | 
				
			||||||
nvc0_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_fbdev *nfbdev = info->par;
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
 | 
					 | 
				
			||||||
	struct nouveau_channel *chan = drm->channel;
 | 
					 | 
				
			||||||
	struct nvif_push *push = chan->chan.push;
 | 
					 | 
				
			||||||
	uint32_t dwords, *data = (uint32_t *)image->data;
 | 
					 | 
				
			||||||
	uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel));
 | 
					 | 
				
			||||||
	uint32_t *palette = info->pseudo_palette, bg, fg;
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (image->depth != 1)
 | 
					 | 
				
			||||||
		return -ENODEV;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
 | 
					 | 
				
			||||||
	    info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
 | 
					 | 
				
			||||||
		bg = palette[image->bg_color] | mask;
 | 
					 | 
				
			||||||
		fg = palette[image->fg_color] | mask;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		bg = image->bg_color;
 | 
					 | 
				
			||||||
		fg = image->fg_color;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = PUSH_WAIT(push, 11);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_CPU_COLOR0, bg,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_CPU_COLOR1, fg);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_CPU_SRC_WIDTH, image->width,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_CPU_SRC_HEIGHT, image->height);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_CPU_DST_X0_FRAC, 0,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_CPU_DST_X0_INT, image->dx,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_CPU_DST_Y0_FRAC, 0,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_CPU_DST_Y0_INT, image->dy);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	dwords = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5;
 | 
					 | 
				
			||||||
	while (dwords) {
 | 
					 | 
				
			||||||
		int count = dwords > 2047 ? 2047 : dwords;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ret = PUSH_WAIT(push, count + 1);
 | 
					 | 
				
			||||||
		if (ret)
 | 
					 | 
				
			||||||
			return ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		dwords -= count;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		PUSH_NINC(push, NV902D, PIXELS_FROM_CPU_DATA, data, count);
 | 
					 | 
				
			||||||
		data += count;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_KICK(push);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int
 | 
					 | 
				
			||||||
nvc0_fbcon_accel_init(struct fb_info *info)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nouveau_fbdev *nfbdev = info->par;
 | 
					 | 
				
			||||||
	struct drm_device *dev = nfbdev->helper.dev;
 | 
					 | 
				
			||||||
	struct nouveau_drm *drm = nouveau_drm(dev);
 | 
					 | 
				
			||||||
	struct nouveau_channel *chan = drm->channel;
 | 
					 | 
				
			||||||
	struct nvif_push *push = chan->chan.push;
 | 
					 | 
				
			||||||
	int ret, format;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = nvif_object_ctor(&chan->user, "fbconTwoD", 0x902d, 0x902d,
 | 
					 | 
				
			||||||
			       NULL, 0, &nfbdev->twod);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (info->var.bits_per_pixel) {
 | 
					 | 
				
			||||||
	case 8:
 | 
					 | 
				
			||||||
		format = NV902D_SET_DST_FORMAT_V_Y8;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case 15:
 | 
					 | 
				
			||||||
		format = NV902D_SET_DST_FORMAT_V_X1R5G5B5;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case 16:
 | 
					 | 
				
			||||||
		format = NV902D_SET_DST_FORMAT_V_R5G6B5;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case 32:
 | 
					 | 
				
			||||||
		switch (info->var.transp.length) {
 | 
					 | 
				
			||||||
		case 0: /* depth 24 */
 | 
					 | 
				
			||||||
		case 8: /* depth 32, just use 24.. */
 | 
					 | 
				
			||||||
			format = NV902D_SET_DST_FORMAT_V_X8R8G8B8;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case 2: /* depth 30 */
 | 
					 | 
				
			||||||
			format = NV902D_SET_DST_FORMAT_V_A2B10G10R10;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			return -EINVAL;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = PUSH_WAIT(push, 52);
 | 
					 | 
				
			||||||
	if (ret) {
 | 
					 | 
				
			||||||
		WARN_ON(1);
 | 
					 | 
				
			||||||
		nouveau_fbcon_gpu_lockup(info);
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV902D, SET_OBJECT, nfbdev->twod.handle);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV902D, SET_DST_FORMAT,
 | 
					 | 
				
			||||||
		  NVVAL(NV902D, SET_DST_FORMAT, V, format),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				SET_DST_MEMORY_LAYOUT,
 | 
					 | 
				
			||||||
		  NVDEF(NV902D, SET_DST_MEMORY_LAYOUT, V, PITCH));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV902D, SET_DST_PITCH, info->fix.line_length,
 | 
					 | 
				
			||||||
				SET_DST_WIDTH, info->var.xres_virtual,
 | 
					 | 
				
			||||||
				SET_DST_HEIGHT, info->var.yres_virtual,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				SET_DST_OFFSET_UPPER,
 | 
					 | 
				
			||||||
		  NVVAL(NV902D, SET_DST_OFFSET_UPPER, V, upper_32_bits(nfbdev->vma->addr)),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				SET_DST_OFFSET_LOWER,
 | 
					 | 
				
			||||||
		  NVVAL(NV902D, SET_DST_OFFSET_LOWER, V, lower_32_bits(nfbdev->vma->addr)));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV902D, SET_SRC_FORMAT,
 | 
					 | 
				
			||||||
		  NVVAL(NV902D, SET_SRC_FORMAT, V, format),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				SET_SRC_MEMORY_LAYOUT,
 | 
					 | 
				
			||||||
		  NVDEF(NV902D, SET_SRC_MEMORY_LAYOUT, V, PITCH));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV902D, SET_SRC_PITCH, info->fix.line_length,
 | 
					 | 
				
			||||||
				SET_SRC_WIDTH, info->var.xres_virtual,
 | 
					 | 
				
			||||||
				SET_SRC_HEIGHT, info->var.yres_virtual,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				SET_SRC_OFFSET_UPPER,
 | 
					 | 
				
			||||||
		  NVVAL(NV902D, SET_SRC_OFFSET_UPPER, V, upper_32_bits(nfbdev->vma->addr)),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				SET_SRC_OFFSET_LOWER,
 | 
					 | 
				
			||||||
		  NVVAL(NV902D, SET_SRC_OFFSET_LOWER, V, lower_32_bits(nfbdev->vma->addr)));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_IMMD(push, NV902D, SET_CLIP_ENABLE,
 | 
					 | 
				
			||||||
		  NVDEF(NV902D, SET_CLIP_ENABLE, V, FALSE));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_IMMD(push, NV902D, SET_ROP,
 | 
					 | 
				
			||||||
		  NVVAL(NV902D, SET_ROP, V, 0x55));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_IMMD(push, NV902D, SET_OPERATION,
 | 
					 | 
				
			||||||
		  NVDEF(NV902D, SET_OPERATION, V, SRCCOPY));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV902D, SET_MONOCHROME_PATTERN_COLOR_FORMAT,
 | 
					 | 
				
			||||||
		  NVDEF(NV902D, SET_MONOCHROME_PATTERN_COLOR_FORMAT, V, A8R8G8B8),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				SET_MONOCHROME_PATTERN_FORMAT,
 | 
					 | 
				
			||||||
		  NVDEF(NV902D, SET_MONOCHROME_PATTERN_FORMAT, V, LE_M1));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV902D, RENDER_SOLID_PRIM_MODE,
 | 
					 | 
				
			||||||
		  NVDEF(NV902D, RENDER_SOLID_PRIM_MODE, V, RECTS),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				SET_RENDER_SOLID_PRIM_COLOR_FORMAT,
 | 
					 | 
				
			||||||
		  NVVAL(NV902D, SET_RENDER_SOLID_PRIM_COLOR_FORMAT, V, format));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_CPU_DATA_TYPE,
 | 
					 | 
				
			||||||
		  NVDEF(NV902D, SET_PIXELS_FROM_CPU_DATA_TYPE, V, INDEX),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_CPU_COLOR_FORMAT,
 | 
					 | 
				
			||||||
		  NVVAL(NV902D, SET_PIXELS_FROM_CPU_COLOR_FORMAT, V, format),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_CPU_INDEX_FORMAT,
 | 
					 | 
				
			||||||
		  NVDEF(NV902D, SET_PIXELS_FROM_CPU_INDEX_FORMAT, V, I1),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_CPU_MONO_FORMAT,
 | 
					 | 
				
			||||||
		  NVDEF(NV902D, SET_PIXELS_FROM_CPU_MONO_FORMAT, V, CGA6_M1),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_CPU_WRAP,
 | 
					 | 
				
			||||||
		  NVDEF(NV902D, SET_PIXELS_FROM_CPU_WRAP, V, WRAP_BYTE));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_IMMD(push, NV902D, SET_PIXELS_FROM_CPU_MONO_OPACITY,
 | 
					 | 
				
			||||||
		  NVDEF(NV902D, SET_PIXELS_FROM_CPU_MONO_OPACITY, V, OPAQUE));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_CPU_DX_DU_FRAC, 0,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_CPU_DX_DU_INT, 1,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_CPU_DY_DV_FRAC, 0,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_CPU_DY_DV_INT, 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_IMMD(push, NV902D, SET_PIXELS_FROM_MEMORY_SAFE_OVERLAP,
 | 
					 | 
				
			||||||
		  NVDEF(NV902D, SET_PIXELS_FROM_MEMORY_SAFE_OVERLAP, V, TRUE));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PUSH_MTHD(push, NV902D, SET_PIXELS_FROM_MEMORY_DU_DX_FRAC, 0,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_MEMORY_DU_DX_INT, 1,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_MEMORY_DV_DY_FRAC, 0,
 | 
					 | 
				
			||||||
				SET_PIXELS_FROM_MEMORY_DV_DY_INT, 1);
 | 
					 | 
				
			||||||
	PUSH_KICK(push);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Loading…
	
		Reference in a new issue