diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvd0_display.c')
| -rw-r--r-- | drivers/gpu/drm/nouveau/nvd0_display.c | 2141 | 
1 files changed, 0 insertions, 2141 deletions
diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c deleted file mode 100644 index c402fca2b2b..00000000000 --- a/drivers/gpu/drm/nouveau/nvd0_display.c +++ /dev/null @@ -1,2141 +0,0 @@ -/* - * Copyright 2011 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 - */ - -#include <linux/dma-mapping.h> - -#include <drm/drmP.h> -#include <drm/drm_crtc_helper.h> - -#include "nouveau_drm.h" -#include "nouveau_dma.h" -#include "nouveau_gem.h" -#include "nouveau_connector.h" -#include "nouveau_encoder.h" -#include "nouveau_crtc.h" -#include "nouveau_fence.h" -#include "nv50_display.h" - -#include <core/gpuobj.h> - -#include <subdev/timer.h> -#include <subdev/bar.h> -#include <subdev/fb.h> - -#define EVO_DMA_NR 9 - -#define EVO_MASTER  (0x00) -#define EVO_FLIP(c) (0x01 + (c)) -#define EVO_OVLY(c) (0x05 + (c)) -#define EVO_OIMM(c) (0x09 + (c)) -#define EVO_CURS(c) (0x0d + (c)) - -/* offsets in shared sync bo of various structures */ -#define EVO_SYNC(c, o) ((c) * 0x0100 + (o)) -#define EVO_MAST_NTFY     EVO_SYNC(  0, 0x00) -#define EVO_FLIP_SEM0(c)  EVO_SYNC((c), 0x00) -#define EVO_FLIP_SEM1(c)  EVO_SYNC((c), 0x10) - -struct evo { -	int idx; -	dma_addr_t handle; -	u32 *ptr; -	struct { -		u32 offset; -		u16 value; -	} sem; -}; - -struct nvd0_display { -	struct nouveau_gpuobj *mem; -	struct nouveau_bo *sync; -	struct evo evo[9]; - -	struct tasklet_struct tasklet; -	u32 modeset; -}; - -static struct nvd0_display * -nvd0_display(struct drm_device *dev) -{ -	return nouveau_display(dev)->priv; -} - -static struct drm_crtc * -nvd0_display_crtc_get(struct drm_encoder *encoder) -{ -	return nouveau_encoder(encoder)->crtc; -} - -/****************************************************************************** - * EVO channel helpers - *****************************************************************************/ -static inline int -evo_icmd(struct drm_device *dev, int id, u32 mthd, u32 data) -{ -	struct nouveau_device *device = nouveau_dev(dev); -	int ret = 0; -	nv_mask(device, 0x610700 + (id * 0x10), 0x00000001, 0x00000001); -	nv_wr32(device, 0x610704 + (id * 0x10), data); -	nv_mask(device, 0x610704 + (id * 0x10), 0x80000ffc, 0x80000000 | mthd); -	if (!nv_wait(device, 0x610704 + (id * 0x10), 0x80000000, 0x00000000)) -		ret = -EBUSY; -	nv_mask(device, 0x610700 + (id * 0x10), 0x00000001, 0x00000000); -	return ret; -} - -static u32 * -evo_wait(struct drm_device *dev, int id, int nr) -{ -	struct nouveau_device *device = nouveau_dev(dev); -	struct nouveau_drm *drm = nouveau_drm(dev); -	struct nvd0_display *disp = nvd0_display(dev); -	u32 put = nv_rd32(device, 0x640000 + (id * 0x1000)) / 4; - -	if (put + nr >= (PAGE_SIZE / 4)) { -		disp->evo[id].ptr[put] = 0x20000000; - -		nv_wr32(device, 0x640000 + (id * 0x1000), 0x00000000); -		if (!nv_wait(device, 0x640004 + (id * 0x1000), ~0, 0x00000000)) { -			NV_ERROR(drm, "evo %d dma stalled\n", id); -			return NULL; -		} - -		put = 0; -	} - -	return disp->evo[id].ptr + put; -} - -static void -evo_kick(u32 *push, struct drm_device *dev, int id) -{ -	struct nouveau_device *device = nouveau_dev(dev); -	struct nvd0_display *disp = nvd0_display(dev); - -	nv_wr32(device, 0x640000 + (id * 0x1000), (push - disp->evo[id].ptr) << 2); -} - -#define evo_mthd(p,m,s) *((p)++) = (((s) << 18) | (m)) -#define evo_data(p,d)   *((p)++) = (d) - -static int -evo_init_dma(struct drm_device *dev, int ch) -{ -	struct nouveau_device *device = nouveau_dev(dev); -	struct nouveau_drm *drm = nouveau_drm(dev); -	struct nvd0_display *disp = nvd0_display(dev); -	u32 flags; - -	flags = 0x00000000; -	if (ch == EVO_MASTER) -		flags |= 0x01000000; - -	nv_wr32(device, 0x610494 + (ch * 0x0010), (disp->evo[ch].handle >> 8) | 3); -	nv_wr32(device, 0x610498 + (ch * 0x0010), 0x00010000); -	nv_wr32(device, 0x61049c + (ch * 0x0010), 0x00000001); -	nv_mask(device, 0x610490 + (ch * 0x0010), 0x00000010, 0x00000010); -	nv_wr32(device, 0x640000 + (ch * 0x1000), 0x00000000); -	nv_wr32(device, 0x610490 + (ch * 0x0010), 0x00000013 | flags); -	if (!nv_wait(device, 0x610490 + (ch * 0x0010), 0x80000000, 0x00000000)) { -		NV_ERROR(drm, "PDISP: ch%d 0x%08x\n", ch, -			      nv_rd32(device, 0x610490 + (ch * 0x0010))); -		return -EBUSY; -	} - -	nv_mask(device, 0x610090, (1 << ch), (1 << ch)); -	nv_mask(device, 0x6100a0, (1 << ch), (1 << ch)); -	return 0; -} - -static void -evo_fini_dma(struct drm_device *dev, int ch) -{ -	struct nouveau_device *device = nouveau_dev(dev); - -	if (!(nv_rd32(device, 0x610490 + (ch * 0x0010)) & 0x00000010)) -		return; - -	nv_mask(device, 0x610490 + (ch * 0x0010), 0x00000010, 0x00000000); -	nv_mask(device, 0x610490 + (ch * 0x0010), 0x00000003, 0x00000000); -	nv_wait(device, 0x610490 + (ch * 0x0010), 0x80000000, 0x00000000); -	nv_mask(device, 0x610090, (1 << ch), 0x00000000); -	nv_mask(device, 0x6100a0, (1 << ch), 0x00000000); -} - -static inline void -evo_piow(struct drm_device *dev, int ch, u16 mthd, u32 data) -{ -	struct nouveau_device *device = nouveau_dev(dev); -	nv_wr32(device, 0x640000 + (ch * 0x1000) + mthd, data); -} - -static int -evo_init_pio(struct drm_device *dev, int ch) -{ -	struct nouveau_device *device = nouveau_dev(dev); -	struct nouveau_drm *drm = nouveau_drm(dev); - -	nv_wr32(device, 0x610490 + (ch * 0x0010), 0x00000001); -	if (!nv_wait(device, 0x610490 + (ch * 0x0010), 0x00010000, 0x00010000)) { -		NV_ERROR(drm, "PDISP: ch%d 0x%08x\n", ch, -			      nv_rd32(device, 0x610490 + (ch * 0x0010))); -		return -EBUSY; -	} - -	nv_mask(device, 0x610090, (1 << ch), (1 << ch)); -	nv_mask(device, 0x6100a0, (1 << ch), (1 << ch)); -	return 0; -} - -static void -evo_fini_pio(struct drm_device *dev, int ch) -{ -	struct nouveau_device *device = nouveau_dev(dev); - -	if (!(nv_rd32(device, 0x610490 + (ch * 0x0010)) & 0x00000001)) -		return; - -	nv_mask(device, 0x610490 + (ch * 0x0010), 0x00000010, 0x00000010); -	nv_mask(device, 0x610490 + (ch * 0x0010), 0x00000001, 0x00000000); -	nv_wait(device, 0x610490 + (ch * 0x0010), 0x00010000, 0x00000000); -	nv_mask(device, 0x610090, (1 << ch), 0x00000000); -	nv_mask(device, 0x6100a0, (1 << ch), 0x00000000); -} - -static bool -evo_sync_wait(void *data) -{ -	return nouveau_bo_rd32(data, EVO_MAST_NTFY) != 0x00000000; -} - -static int -evo_sync(struct drm_device *dev, int ch) -{ -	struct nouveau_device *device = nouveau_dev(dev); -	struct nvd0_display *disp = nvd0_display(dev); -	u32 *push = evo_wait(dev, ch, 8); -	if (push) { -		nouveau_bo_wr32(disp->sync, EVO_MAST_NTFY, 0x00000000); -		evo_mthd(push, 0x0084, 1); -		evo_data(push, 0x80000000 | EVO_MAST_NTFY); -		evo_mthd(push, 0x0080, 2); -		evo_data(push, 0x00000000); -		evo_data(push, 0x00000000); -		evo_kick(push, dev, ch); -		if (nv_wait_cb(device, evo_sync_wait, disp->sync)) -			return 0; -	} - -	return -EBUSY; -} - -/****************************************************************************** - * Page flipping channel - *****************************************************************************/ -struct nouveau_bo * -nvd0_display_crtc_sema(struct drm_device *dev, int crtc) -{ -	return nvd0_display(dev)->sync; -} - -void -nvd0_display_flip_stop(struct drm_crtc *crtc) -{ -	struct nvd0_display *disp = nvd0_display(crtc->dev); -	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); -	struct evo *evo = &disp->evo[EVO_FLIP(nv_crtc->index)]; -	u32 *push; - -	push = evo_wait(crtc->dev, evo->idx, 8); -	if (push) { -		evo_mthd(push, 0x0084, 1); -		evo_data(push, 0x00000000); -		evo_mthd(push, 0x0094, 1); -		evo_data(push, 0x00000000); -		evo_mthd(push, 0x00c0, 1); -		evo_data(push, 0x00000000); -		evo_mthd(push, 0x0080, 1); -		evo_data(push, 0x00000000); -		evo_kick(push, crtc->dev, evo->idx); -	} -} - -int -nvd0_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, -		       struct nouveau_channel *chan, u32 swap_interval) -{ -	struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb); -	struct nvd0_display *disp = nvd0_display(crtc->dev); -	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); -	struct evo *evo = &disp->evo[EVO_FLIP(nv_crtc->index)]; -	u64 offset; -	u32 *push; -	int ret; - -	swap_interval <<= 4; -	if (swap_interval == 0) -		swap_interval |= 0x100; - -	push = evo_wait(crtc->dev, evo->idx, 128); -	if (unlikely(push == NULL)) -		return -EBUSY; - -	/* synchronise with the rendering channel, if necessary */ -	if (likely(chan)) { -		ret = RING_SPACE(chan, 10); -		if (ret) -			return ret; - - -		offset  = nvc0_fence_crtc(chan, nv_crtc->index); -		offset += evo->sem.offset; - -		BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); -		OUT_RING  (chan, upper_32_bits(offset)); -		OUT_RING  (chan, lower_32_bits(offset)); -		OUT_RING  (chan, 0xf00d0000 | evo->sem.value); -		OUT_RING  (chan, 0x1002); -		BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); -		OUT_RING  (chan, upper_32_bits(offset)); -		OUT_RING  (chan, lower_32_bits(offset ^ 0x10)); -		OUT_RING  (chan, 0x74b1e000); -		OUT_RING  (chan, 0x1001); -		FIRE_RING (chan); -	} else { -		nouveau_bo_wr32(disp->sync, evo->sem.offset / 4, -				0xf00d0000 | evo->sem.value); -		evo_sync(crtc->dev, EVO_MASTER); -	} - -	/* queue the flip */ -	evo_mthd(push, 0x0100, 1); -	evo_data(push, 0xfffe0000); -	evo_mthd(push, 0x0084, 1); -	evo_data(push, swap_interval); -	if (!(swap_interval & 0x00000100)) { -		evo_mthd(push, 0x00e0, 1); -		evo_data(push, 0x40000000); -	} -	evo_mthd(push, 0x0088, 4); -	evo_data(push, evo->sem.offset); -	evo_data(push, 0xf00d0000 | evo->sem.value); -	evo_data(push, 0x74b1e000); -	evo_data(push, NvEvoSync); -	evo_mthd(push, 0x00a0, 2); -	evo_data(push, 0x00000000); -	evo_data(push, 0x00000000); -	evo_mthd(push, 0x00c0, 1); -	evo_data(push, nv_fb->r_dma); -	evo_mthd(push, 0x0110, 2); -	evo_data(push, 0x00000000); -	evo_data(push, 0x00000000); -	evo_mthd(push, 0x0400, 5); -	evo_data(push, nv_fb->nvbo->bo.offset >> 8); -	evo_data(push, 0); -	evo_data(push, (fb->height << 16) | fb->width); -	evo_data(push, nv_fb->r_pitch); -	evo_data(push, nv_fb->r_format); -	evo_mthd(push, 0x0080, 1); -	evo_data(push, 0x00000000); -	evo_kick(push, crtc->dev, evo->idx); - -	evo->sem.offset ^= 0x10; -	evo->sem.value++; -	return 0; -} - -/****************************************************************************** - * CRTC - *****************************************************************************/ -static int -nvd0_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update) -{ -	struct nouveau_drm *drm = nouveau_drm(nv_crtc->base.dev); -	struct drm_device *dev = nv_crtc->base.dev; -	struct nouveau_connector *nv_connector; -	struct drm_connector *connector; -	u32 *push, mode = 0x00; -	u32 mthd; - -	nv_connector = nouveau_crtc_connector_get(nv_crtc); -	connector = &nv_connector->base; -	if (nv_connector->dithering_mode == DITHERING_MODE_AUTO) { -		if (nv_crtc->base.fb->depth > connector->display_info.bpc * 3) -			mode = DITHERING_MODE_DYNAMIC2X2; -	} else { -		mode = nv_connector->dithering_mode; -	} - -	if (nv_connector->dithering_depth == DITHERING_DEPTH_AUTO) { -		if (connector->display_info.bpc >= 8) -			mode |= DITHERING_DEPTH_8BPC; -	} else { -		mode |= nv_connector->dithering_depth; -	} - -	if (nv_device(drm->device)->card_type < NV_E0) -		mthd = 0x0490 + (nv_crtc->index * 0x0300); -	else -		mthd = 0x04a0 + (nv_crtc->index * 0x0300); - -	push = evo_wait(dev, EVO_MASTER, 4); -	if (push) { -		evo_mthd(push, mthd, 1); -		evo_data(push, mode); -		if (update) { -			evo_mthd(push, 0x0080, 1); -			evo_data(push, 0x00000000); -		} -		evo_kick(push, dev, EVO_MASTER); -	} - -	return 0; -} - -static int -nvd0_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update) -{ -	struct drm_display_mode *omode, *umode = &nv_crtc->base.mode; -	struct drm_device *dev = nv_crtc->base.dev; -	struct drm_crtc *crtc = &nv_crtc->base; -	struct nouveau_connector *nv_connector; -	int mode = DRM_MODE_SCALE_NONE; -	u32 oX, oY, *push; - -	/* start off at the resolution we programmed the crtc for, this -	 * effectively handles NONE/FULL scaling -	 */ -	nv_connector = nouveau_crtc_connector_get(nv_crtc); -	if (nv_connector && nv_connector->native_mode) -		mode = nv_connector->scaling_mode; - -	if (mode != DRM_MODE_SCALE_NONE) -		omode = nv_connector->native_mode; -	else -		omode = umode; - -	oX = omode->hdisplay; -	oY = omode->vdisplay; -	if (omode->flags & DRM_MODE_FLAG_DBLSCAN) -		oY *= 2; - -	/* add overscan compensation if necessary, will keep the aspect -	 * ratio the same as the backend mode unless overridden by the -	 * user setting both hborder and vborder properties. -	 */ -	if (nv_connector && ( nv_connector->underscan == UNDERSCAN_ON || -			     (nv_connector->underscan == UNDERSCAN_AUTO && -			      nv_connector->edid && -			      drm_detect_hdmi_monitor(nv_connector->edid)))) { -		u32 bX = nv_connector->underscan_hborder; -		u32 bY = nv_connector->underscan_vborder; -		u32 aspect = (oY << 19) / oX; - -		if (bX) { -			oX -= (bX * 2); -			if (bY) oY -= (bY * 2); -			else    oY  = ((oX * aspect) + (aspect / 2)) >> 19; -		} else { -			oX -= (oX >> 4) + 32; -			if (bY) oY -= (bY * 2); -			else    oY  = ((oX * aspect) + (aspect / 2)) >> 19; -		} -	} - -	/* handle CENTER/ASPECT scaling, taking into account the areas -	 * removed already for overscan compensation -	 */ -	switch (mode) { -	case DRM_MODE_SCALE_CENTER: -		oX = min((u32)umode->hdisplay, oX); -		oY = min((u32)umode->vdisplay, oY); -		/* fall-through */ -	case DRM_MODE_SCALE_ASPECT: -		if (oY < oX) { -			u32 aspect = (umode->hdisplay << 19) / umode->vdisplay; -			oX = ((oY * aspect) + (aspect / 2)) >> 19; -		} else { -			u32 aspect = (umode->vdisplay << 19) / umode->hdisplay; -			oY = ((oX * aspect) + (aspect / 2)) >> 19; -		} -		break; -	default: -		break; -	} - -	push = evo_wait(dev, EVO_MASTER, 8); -	if (push) { -		evo_mthd(push, 0x04c0 + (nv_crtc->index * 0x300), 3); -		evo_data(push, (oY << 16) | oX); -		evo_data(push, (oY << 16) | oX); -		evo_data(push, (oY << 16) | oX); -		evo_mthd(push, 0x0494 + (nv_crtc->index * 0x300), 1); -		evo_data(push, 0x00000000); -		evo_mthd(push, 0x04b8 + (nv_crtc->index * 0x300), 1); -		evo_data(push, (umode->vdisplay << 16) | umode->hdisplay); -		evo_kick(push, dev, EVO_MASTER); -		if (update) { -			nvd0_display_flip_stop(crtc); -			nvd0_display_flip_next(crtc, crtc->fb, NULL, 1); -		} -	} - -	return 0; -} - -static int -nvd0_crtc_set_image(struct nouveau_crtc *nv_crtc, struct drm_framebuffer *fb, -		    int x, int y, bool update) -{ -	struct nouveau_framebuffer *nvfb = nouveau_framebuffer(fb); -	u32 *push; - -	push = evo_wait(fb->dev, EVO_MASTER, 16); -	if (push) { -		evo_mthd(push, 0x0460 + (nv_crtc->index * 0x300), 1); -		evo_data(push, nvfb->nvbo->bo.offset >> 8); -		evo_mthd(push, 0x0468 + (nv_crtc->index * 0x300), 4); -		evo_data(push, (fb->height << 16) | fb->width); -		evo_data(push, nvfb->r_pitch); -		evo_data(push, nvfb->r_format); -		evo_data(push, nvfb->r_dma); -		evo_mthd(push, 0x04b0 + (nv_crtc->index * 0x300), 1); -		evo_data(push, (y << 16) | x); -		if (update) { -			evo_mthd(push, 0x0080, 1); -			evo_data(push, 0x00000000); -		} -		evo_kick(push, fb->dev, EVO_MASTER); -	} - -	nv_crtc->fb.tile_flags = nvfb->r_dma; -	return 0; -} - -static void -nvd0_crtc_cursor_show(struct nouveau_crtc *nv_crtc, bool show, bool update) -{ -	struct drm_device *dev = nv_crtc->base.dev; -	u32 *push = evo_wait(dev, EVO_MASTER, 16); -	if (push) { -		if (show) { -			evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 2); -			evo_data(push, 0x85000000); -			evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8); -			evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1); -			evo_data(push, NvEvoVRAM); -		} else { -			evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 1); -			evo_data(push, 0x05000000); -			evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1); -			evo_data(push, 0x00000000); -		} - -		if (update) { -			evo_mthd(push, 0x0080, 1); -			evo_data(push, 0x00000000); -		} - -		evo_kick(push, dev, EVO_MASTER); -	} -} - -static void -nvd0_crtc_dpms(struct drm_crtc *crtc, int mode) -{ -} - -static void -nvd0_crtc_prepare(struct drm_crtc *crtc) -{ -	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); -	u32 *push; - -	nvd0_display_flip_stop(crtc); - -	push = evo_wait(crtc->dev, EVO_MASTER, 2); -	if (push) { -		evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1); -		evo_data(push, 0x00000000); -		evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 1); -		evo_data(push, 0x03000000); -		evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1); -		evo_data(push, 0x00000000); -		evo_kick(push, crtc->dev, EVO_MASTER); -	} - -	nvd0_crtc_cursor_show(nv_crtc, false, false); -} - -static void -nvd0_crtc_commit(struct drm_crtc *crtc) -{ -	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); -	u32 *push; - -	push = evo_wait(crtc->dev, EVO_MASTER, 32); -	if (push) { -		evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1); -		evo_data(push, nv_crtc->fb.tile_flags); -		evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 4); -		evo_data(push, 0x83000000); -		evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8); -		evo_data(push, 0x00000000); -		evo_data(push, 0x00000000); -		evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1); -		evo_data(push, NvEvoVRAM); -		evo_mthd(push, 0x0430 + (nv_crtc->index * 0x300), 1); -		evo_data(push, 0xffffff00); -		evo_kick(push, crtc->dev, EVO_MASTER); -	} - -	nvd0_crtc_cursor_show(nv_crtc, nv_crtc->cursor.visible, true); -	nvd0_display_flip_next(crtc, crtc->fb, NULL, 1); -} - -static bool -nvd0_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, -		     struct drm_display_mode *adjusted_mode) -{ -	return true; -} - -static int -nvd0_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) -{ -	struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb); -	int ret; - -	ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM); -	if (ret) -		return ret; - -	if (old_fb) { -		nvfb = nouveau_framebuffer(old_fb); -		nouveau_bo_unpin(nvfb->nvbo); -	} - -	return 0; -} - -static int -nvd0_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode, -		   struct drm_display_mode *mode, int x, int y, -		   struct drm_framebuffer *old_fb) -{ -	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); -	struct nouveau_connector *nv_connector; -	u32 ilace = (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 2 : 1; -	u32 vscan = (mode->flags & DRM_MODE_FLAG_DBLSCAN) ? 2 : 1; -	u32 hactive, hsynce, hbackp, hfrontp, hblanke, hblanks; -	u32 vactive, vsynce, vbackp, vfrontp, vblanke, vblanks; -	u32 vblan2e = 0, vblan2s = 1; -	u32 *push; -	int ret; - -	hactive = mode->htotal; -	hsynce  = mode->hsync_end - mode->hsync_start - 1; -	hbackp  = mode->htotal - mode->hsync_end; -	hblanke = hsynce + hbackp; -	hfrontp = mode->hsync_start - mode->hdisplay; -	hblanks = mode->htotal - hfrontp - 1; - -	vactive = mode->vtotal * vscan / ilace; -	vsynce  = ((mode->vsync_end - mode->vsync_start) * vscan / ilace) - 1; -	vbackp  = (mode->vtotal - mode->vsync_end) * vscan / ilace; -	vblanke = vsynce + vbackp; -	vfrontp = (mode->vsync_start - mode->vdisplay) * vscan / ilace; -	vblanks = vactive - vfrontp - 1; -	if (mode->flags & DRM_MODE_FLAG_INTERLACE) { -		vblan2e = vactive + vsynce + vbackp; -		vblan2s = vblan2e + (mode->vdisplay * vscan / ilace); -		vactive = (vactive * 2) + 1; -	} - -	ret = nvd0_crtc_swap_fbs(crtc, old_fb); -	if (ret) -		return ret; - -	push = evo_wait(crtc->dev, EVO_MASTER, 64); -	if (push) { -		evo_mthd(push, 0x0410 + (nv_crtc->index * 0x300), 6); -		evo_data(push, 0x00000000); -		evo_data(push, (vactive << 16) | hactive); -		evo_data(push, ( vsynce << 16) | hsynce); -		evo_data(push, (vblanke << 16) | hblanke); -		evo_data(push, (vblanks << 16) | hblanks); -		evo_data(push, (vblan2e << 16) | vblan2s); -		evo_mthd(push, 0x042c + (nv_crtc->index * 0x300), 1); -		evo_data(push, 0x00000000); /* ??? */ -		evo_mthd(push, 0x0450 + (nv_crtc->index * 0x300), 3); -		evo_data(push, mode->clock * 1000); -		evo_data(push, 0x00200000); /* ??? */ -		evo_data(push, mode->clock * 1000); -		evo_mthd(push, 0x04d0 + (nv_crtc->index * 0x300), 2); -		evo_data(push, 0x00000311); -		evo_data(push, 0x00000100); -		evo_kick(push, crtc->dev, EVO_MASTER); -	} - -	nv_connector = nouveau_crtc_connector_get(nv_crtc); -	nvd0_crtc_set_dither(nv_crtc, false); -	nvd0_crtc_set_scale(nv_crtc, false); -	nvd0_crtc_set_image(nv_crtc, crtc->fb, x, y, false); -	return 0; -} - -static int -nvd0_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, -			struct drm_framebuffer *old_fb) -{ -	struct nouveau_drm *drm = nouveau_drm(crtc->dev); -	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); -	int ret; - -	if (!crtc->fb) { -		NV_DEBUG(drm, "No FB bound\n"); -		return 0; -	} - -	ret = nvd0_crtc_swap_fbs(crtc, old_fb); -	if (ret) -		return ret; - -	nvd0_display_flip_stop(crtc); -	nvd0_crtc_set_image(nv_crtc, crtc->fb, x, y, true); -	nvd0_display_flip_next(crtc, crtc->fb, NULL, 1); -	return 0; -} - -static int -nvd0_crtc_mode_set_base_atomic(struct drm_crtc *crtc, -			       struct drm_framebuffer *fb, int x, int y, -			       enum mode_set_atomic state) -{ -	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); -	nvd0_display_flip_stop(crtc); -	nvd0_crtc_set_image(nv_crtc, fb, x, y, true); -	return 0; -} - -static void -nvd0_crtc_lut_load(struct drm_crtc *crtc) -{ -	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); -	void __iomem *lut = nvbo_kmap_obj_iovirtual(nv_crtc->lut.nvbo); -	int i; - -	for (i = 0; i < 256; i++) { -		writew(0x6000 + (nv_crtc->lut.r[i] >> 2), lut + (i * 0x20) + 0); -		writew(0x6000 + (nv_crtc->lut.g[i] >> 2), lut + (i * 0x20) + 2); -		writew(0x6000 + (nv_crtc->lut.b[i] >> 2), lut + (i * 0x20) + 4); -	} -} - -static int -nvd0_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, -		     uint32_t handle, uint32_t width, uint32_t height) -{ -	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); -	struct drm_device *dev = crtc->dev; -	struct drm_gem_object *gem; -	struct nouveau_bo *nvbo; -	bool visible = (handle != 0); -	int i, ret = 0; - -	if (visible) { -		if (width != 64 || height != 64) -			return -EINVAL; - -		gem = drm_gem_object_lookup(dev, file_priv, handle); -		if (unlikely(!gem)) -			return -ENOENT; -		nvbo = nouveau_gem_object(gem); - -		ret = nouveau_bo_map(nvbo); -		if (ret == 0) { -			for (i = 0; i < 64 * 64; i++) { -				u32 v = nouveau_bo_rd32(nvbo, i); -				nouveau_bo_wr32(nv_crtc->cursor.nvbo, i, v); -			} -			nouveau_bo_unmap(nvbo); -		} - -		drm_gem_object_unreference_unlocked(gem); -	} - -	if (visible != nv_crtc->cursor.visible) { -		nvd0_crtc_cursor_show(nv_crtc, visible, true); -		nv_crtc->cursor.visible = visible; -	} - -	return ret; -} - -static int -nvd0_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) -{ -	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); -	int ch = EVO_CURS(nv_crtc->index); - -	evo_piow(crtc->dev, ch, 0x0084, (y << 16) | (x & 0xffff)); -	evo_piow(crtc->dev, ch, 0x0080, 0x00000000); -	return 0; -} - -static void -nvd0_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, -		    uint32_t start, uint32_t size) -{ -	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); -	u32 end = max(start + size, (u32)256); -	u32 i; - -	for (i = start; i < end; i++) { -		nv_crtc->lut.r[i] = r[i]; -		nv_crtc->lut.g[i] = g[i]; -		nv_crtc->lut.b[i] = b[i]; -	} - -	nvd0_crtc_lut_load(crtc); -} - -static void -nvd0_crtc_destroy(struct drm_crtc *crtc) -{ -	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); -	nouveau_bo_unmap(nv_crtc->cursor.nvbo); -	nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo); -	nouveau_bo_unmap(nv_crtc->lut.nvbo); -	nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo); -	drm_crtc_cleanup(crtc); -	kfree(crtc); -} - -static const struct drm_crtc_helper_funcs nvd0_crtc_hfunc = { -	.dpms = nvd0_crtc_dpms, -	.prepare = nvd0_crtc_prepare, -	.commit = nvd0_crtc_commit, -	.mode_fixup = nvd0_crtc_mode_fixup, -	.mode_set = nvd0_crtc_mode_set, -	.mode_set_base = nvd0_crtc_mode_set_base, -	.mode_set_base_atomic = nvd0_crtc_mode_set_base_atomic, -	.load_lut = nvd0_crtc_lut_load, -}; - -static const struct drm_crtc_funcs nvd0_crtc_func = { -	.cursor_set = nvd0_crtc_cursor_set, -	.cursor_move = nvd0_crtc_cursor_move, -	.gamma_set = nvd0_crtc_gamma_set, -	.set_config = drm_crtc_helper_set_config, -	.destroy = nvd0_crtc_destroy, -	.page_flip = nouveau_crtc_page_flip, -}; - -static void -nvd0_cursor_set_pos(struct nouveau_crtc *nv_crtc, int x, int y) -{ -} - -static void -nvd0_cursor_set_offset(struct nouveau_crtc *nv_crtc, uint32_t offset) -{ -} - -static int -nvd0_crtc_create(struct drm_device *dev, int index) -{ -	struct nouveau_crtc *nv_crtc; -	struct drm_crtc *crtc; -	int ret, i; - -	nv_crtc = kzalloc(sizeof(*nv_crtc), GFP_KERNEL); -	if (!nv_crtc) -		return -ENOMEM; - -	nv_crtc->index = index; -	nv_crtc->set_dither = nvd0_crtc_set_dither; -	nv_crtc->set_scale = nvd0_crtc_set_scale; -	nv_crtc->cursor.set_offset = nvd0_cursor_set_offset; -	nv_crtc->cursor.set_pos = nvd0_cursor_set_pos; -	for (i = 0; i < 256; i++) { -		nv_crtc->lut.r[i] = i << 8; -		nv_crtc->lut.g[i] = i << 8; -		nv_crtc->lut.b[i] = i << 8; -	} - -	crtc = &nv_crtc->base; -	drm_crtc_init(dev, crtc, &nvd0_crtc_func); -	drm_crtc_helper_add(crtc, &nvd0_crtc_hfunc); -	drm_mode_crtc_set_gamma_size(crtc, 256); - -	ret = nouveau_bo_new(dev, 64 * 64 * 4, 0x100, TTM_PL_FLAG_VRAM, -			     0, 0x0000, NULL, &nv_crtc->cursor.nvbo); -	if (!ret) { -		ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM); -		if (!ret) -			ret = nouveau_bo_map(nv_crtc->cursor.nvbo); -		if (ret) -			nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo); -	} - -	if (ret) -		goto out; - -	ret = nouveau_bo_new(dev, 8192, 0x100, TTM_PL_FLAG_VRAM, -			     0, 0x0000, NULL, &nv_crtc->lut.nvbo); -	if (!ret) { -		ret = nouveau_bo_pin(nv_crtc->lut.nvbo, TTM_PL_FLAG_VRAM); -		if (!ret) -			ret = nouveau_bo_map(nv_crtc->lut.nvbo); -		if (ret) -			nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo); -	} - -	if (ret) -		goto out; - -	nvd0_crtc_lut_load(crtc); - -out: -	if (ret) -		nvd0_crtc_destroy(crtc); -	return ret; -} - -/****************************************************************************** - * DAC - *****************************************************************************/ -static void -nvd0_dac_dpms(struct drm_encoder *encoder, int mode) -{ -	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -	struct drm_device *dev = encoder->dev; -	struct nouveau_device *device = nouveau_dev(dev); -	int or = nv_encoder->or; -	u32 dpms_ctrl; - -	dpms_ctrl = 0x80000000; -	if (mode == DRM_MODE_DPMS_STANDBY || mode == DRM_MODE_DPMS_OFF) -		dpms_ctrl |= 0x00000001; -	if (mode == DRM_MODE_DPMS_SUSPEND || mode == DRM_MODE_DPMS_OFF) -		dpms_ctrl |= 0x00000004; - -	nv_wait(device, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000); -	nv_mask(device, 0x61a004 + (or * 0x0800), 0xc000007f, dpms_ctrl); -	nv_wait(device, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000); -} - -static bool -nvd0_dac_mode_fixup(struct drm_encoder *encoder, -		    const struct drm_display_mode *mode, -		    struct drm_display_mode *adjusted_mode) -{ -	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -	struct nouveau_connector *nv_connector; - -	nv_connector = nouveau_encoder_connector_get(nv_encoder); -	if (nv_connector && nv_connector->native_mode) { -		if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) { -			int id = adjusted_mode->base.id; -			*adjusted_mode = *nv_connector->native_mode; -			adjusted_mode->base.id = id; -		} -	} - -	return true; -} - -static void -nvd0_dac_commit(struct drm_encoder *encoder) -{ -} - -static void -nvd0_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, -		  struct drm_display_mode *adjusted_mode) -{ -	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -	struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); -	u32 syncs, magic, *push; - -	syncs = 0x00000001; -	if (mode->flags & DRM_MODE_FLAG_NHSYNC) -		syncs |= 0x00000008; -	if (mode->flags & DRM_MODE_FLAG_NVSYNC) -		syncs |= 0x00000010; - -	magic = 0x31ec6000 | (nv_crtc->index << 25); -	if (mode->flags & DRM_MODE_FLAG_INTERLACE) -		magic |= 0x00000001; - -	nvd0_dac_dpms(encoder, DRM_MODE_DPMS_ON); - -	push = evo_wait(encoder->dev, EVO_MASTER, 8); -	if (push) { -		evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2); -		evo_data(push, syncs); -		evo_data(push, magic); -		evo_mthd(push, 0x0180 + (nv_encoder->or * 0x020), 2); -		evo_data(push, 1 << nv_crtc->index); -		evo_data(push, 0x00ff); -		evo_kick(push, encoder->dev, EVO_MASTER); -	} - -	nv_encoder->crtc = encoder->crtc; -} - -static void -nvd0_dac_disconnect(struct drm_encoder *encoder) -{ -	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -	struct drm_device *dev = encoder->dev; -	u32 *push; - -	if (nv_encoder->crtc) { -		nvd0_crtc_prepare(nv_encoder->crtc); - -		push = evo_wait(dev, EVO_MASTER, 4); -		if (push) { -			evo_mthd(push, 0x0180 + (nv_encoder->or * 0x20), 1); -			evo_data(push, 0x00000000); -			evo_mthd(push, 0x0080, 1); -			evo_data(push, 0x00000000); -			evo_kick(push, dev, EVO_MASTER); -		} - -		nv_encoder->crtc = NULL; -	} -} - -static enum drm_connector_status -nvd0_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) -{ -	enum drm_connector_status status = connector_status_disconnected; -	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -	struct drm_device *dev = encoder->dev; -	struct nouveau_device *device = nouveau_dev(dev); -	int or = nv_encoder->or; -	u32 load; - -	nv_wr32(device, 0x61a00c + (or * 0x800), 0x00100000); -	udelay(9500); -	nv_wr32(device, 0x61a00c + (or * 0x800), 0x80000000); - -	load = nv_rd32(device, 0x61a00c + (or * 0x800)); -	if ((load & 0x38000000) == 0x38000000) -		status = connector_status_connected; - -	nv_wr32(device, 0x61a00c + (or * 0x800), 0x00000000); -	return status; -} - -static void -nvd0_dac_destroy(struct drm_encoder *encoder) -{ -	drm_encoder_cleanup(encoder); -	kfree(encoder); -} - -static const struct drm_encoder_helper_funcs nvd0_dac_hfunc = { -	.dpms = nvd0_dac_dpms, -	.mode_fixup = nvd0_dac_mode_fixup, -	.prepare = nvd0_dac_disconnect, -	.commit = nvd0_dac_commit, -	.mode_set = nvd0_dac_mode_set, -	.disable = nvd0_dac_disconnect, -	.get_crtc = nvd0_display_crtc_get, -	.detect = nvd0_dac_detect -}; - -static const struct drm_encoder_funcs nvd0_dac_func = { -	.destroy = nvd0_dac_destroy, -}; - -static int -nvd0_dac_create(struct drm_connector *connector, struct dcb_output *dcbe) -{ -	struct drm_device *dev = connector->dev; -	struct nouveau_encoder *nv_encoder; -	struct drm_encoder *encoder; - -	nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); -	if (!nv_encoder) -		return -ENOMEM; -	nv_encoder->dcb = dcbe; -	nv_encoder->or = ffs(dcbe->or) - 1; - -	encoder = to_drm_encoder(nv_encoder); -	encoder->possible_crtcs = dcbe->heads; -	encoder->possible_clones = 0; -	drm_encoder_init(dev, encoder, &nvd0_dac_func, DRM_MODE_ENCODER_DAC); -	drm_encoder_helper_add(encoder, &nvd0_dac_hfunc); - -	drm_mode_connector_attach_encoder(connector, encoder); -	return 0; -} - -/****************************************************************************** - * Audio - *****************************************************************************/ -static void -nvd0_audio_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode) -{ -	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -	struct nouveau_connector *nv_connector; -	struct drm_device *dev = encoder->dev; -	struct nouveau_device *device = nouveau_dev(dev); -	int i, or = nv_encoder->or * 0x30; - -	nv_connector = nouveau_encoder_connector_get(nv_encoder); -	if (!drm_detect_monitor_audio(nv_connector->edid)) -		return; - -	nv_mask(device, 0x10ec10 + or, 0x80000003, 0x80000001); - -	drm_edid_to_eld(&nv_connector->base, nv_connector->edid); -	if (nv_connector->base.eld[0]) { -		u8 *eld = nv_connector->base.eld; - -		for (i = 0; i < eld[2] * 4; i++) -			nv_wr32(device, 0x10ec00 + or, (i << 8) | eld[i]); -		for (i = eld[2] * 4; i < 0x60; i++) -			nv_wr32(device, 0x10ec00 + or, (i << 8) | 0x00); - -		nv_mask(device, 0x10ec10 + or, 0x80000002, 0x80000002); -	} -} - -static void -nvd0_audio_disconnect(struct drm_encoder *encoder) -{ -	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -	struct drm_device *dev = encoder->dev; -	struct nouveau_device *device = nouveau_dev(dev); -	int or = nv_encoder->or * 0x30; - -	nv_mask(device, 0x10ec10 + or, 0x80000003, 0x80000000); -} - -/****************************************************************************** - * HDMI - *****************************************************************************/ -static void -nvd0_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode) -{ -	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -	struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); -	struct nouveau_connector *nv_connector; -	struct drm_device *dev = encoder->dev; -	struct nouveau_device *device = nouveau_dev(dev); -	int head = nv_crtc->index * 0x800; -	u32 rekey = 56; /* binary driver, and tegra constant */ -	u32 max_ac_packet; - -	nv_connector = nouveau_encoder_connector_get(nv_encoder); -	if (!drm_detect_hdmi_monitor(nv_connector->edid)) -		return; - -	max_ac_packet  = mode->htotal - mode->hdisplay; -	max_ac_packet -= rekey; -	max_ac_packet -= 18; /* constant from tegra */ -	max_ac_packet /= 32; - -	/* AVI InfoFrame */ -	nv_mask(device, 0x616714 + head, 0x00000001, 0x00000000); -	nv_wr32(device, 0x61671c + head, 0x000d0282); -	nv_wr32(device, 0x616720 + head, 0x0000006f); -	nv_wr32(device, 0x616724 + head, 0x00000000); -	nv_wr32(device, 0x616728 + head, 0x00000000); -	nv_wr32(device, 0x61672c + head, 0x00000000); -	nv_mask(device, 0x616714 + head, 0x00000001, 0x00000001); - -	/* ??? InfoFrame? */ -	nv_mask(device, 0x6167a4 + head, 0x00000001, 0x00000000); -	nv_wr32(device, 0x6167ac + head, 0x00000010); -	nv_mask(device, 0x6167a4 + head, 0x00000001, 0x00000001); - -	/* HDMI_CTRL */ -	nv_mask(device, 0x616798 + head, 0x401f007f, 0x40000000 | rekey | -						  max_ac_packet << 16); - -	/* NFI, audio doesn't work without it though.. */ -	nv_mask(device, 0x616548 + head, 0x00000070, 0x00000000); - -	nvd0_audio_mode_set(encoder, mode); -} - -static void -nvd0_hdmi_disconnect(struct drm_encoder *encoder) -{ -	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -	struct nouveau_crtc *nv_crtc = nouveau_crtc(nv_encoder->crtc); -	struct drm_device *dev = encoder->dev; -	struct nouveau_device *device = nouveau_dev(dev); -	int head = nv_crtc->index * 0x800; - -	nvd0_audio_disconnect(encoder); - -	nv_mask(device, 0x616798 + head, 0x40000000, 0x00000000); -	nv_mask(device, 0x6167a4 + head, 0x00000001, 0x00000000); -	nv_mask(device, 0x616714 + head, 0x00000001, 0x00000000); -} - -/****************************************************************************** - * SOR - *****************************************************************************/ -static inline u32 -nvd0_sor_dp_lane_map(struct drm_device *dev, struct dcb_output *dcb, u8 lane) -{ -	static const u8 nvd0[] = { 16, 8, 0, 24 }; -	return nvd0[lane]; -} - -static void -nvd0_sor_dp_train_set(struct drm_device *dev, struct dcb_output *dcb, u8 pattern) -{ -	struct nouveau_device *device = nouveau_dev(dev); -	const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1); -	const u32 loff = (or * 0x800) + (link * 0x80); -	nv_mask(device, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern); -} - -static void -nvd0_sor_dp_train_adj(struct drm_device *dev, struct dcb_output *dcb, -		      u8 lane, u8 swing, u8 preem) -{ -	struct nouveau_device *device = nouveau_dev(dev); -	struct nouveau_drm *drm = nouveau_drm(dev); -	const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1); -	const u32 loff = (or * 0x800) + (link * 0x80); -	u32 shift = nvd0_sor_dp_lane_map(dev, dcb, lane); -	u32 mask = 0x000000ff << shift; -	u8 *table, *entry, *config = NULL; - -	switch (swing) { -	case 0: preem += 0; break; -	case 1: preem += 4; break; -	case 2: preem += 7; break; -	case 3: preem += 9; break; -	} - -	table = nouveau_dp_bios_data(dev, dcb, &entry); -	if (table) { -		if (table[0] == 0x30) { -			config  = entry + table[4]; -			config += table[5] * preem; -		} else -		if (table[0] == 0x40) { -			config  = table + table[1]; -			config += table[2] * table[3]; -			config += table[6] * preem; -		} -	} - -	if (!config) { -		NV_ERROR(drm, "PDISP: unsupported DP table for chipset\n"); -		return; -	} - -	nv_mask(device, 0x61c118 + loff, mask, config[1] << shift); -	nv_mask(device, 0x61c120 + loff, mask, config[2] << shift); -	nv_mask(device, 0x61c130 + loff, 0x0000ff00, config[3] << 8); -	nv_mask(device, 0x61c13c + loff, 0x00000000, 0x00000000); -} - -static void -nvd0_sor_dp_link_set(struct drm_device *dev, struct dcb_output *dcb, int crtc, -		     int link_nr, u32 link_bw, bool enhframe) -{ -	struct nouveau_device *device = nouveau_dev(dev); -	const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1); -	const u32 loff = (or * 0x800) + (link * 0x80); -	const u32 soff = (or * 0x800); -	u32 dpctrl = nv_rd32(device, 0x61c10c + loff) & ~0x001f4000; -	u32 clksor = nv_rd32(device, 0x612300 + soff) & ~0x007c0000; -	u32 script = 0x0000, lane_mask = 0; -	u8 *table, *entry; -	int i; - -	link_bw /= 27000; - -	table = nouveau_dp_bios_data(dev, dcb, &entry); -	if (table) { -		if      (table[0] == 0x30) entry = ROMPTR(dev, entry[10]); -		else if (table[0] == 0x40) entry = ROMPTR(dev, entry[9]); -		else                       entry = NULL; - -		while (entry) { -			if (entry[0] >= link_bw) -				break; -			entry += 3; -		} - -		nouveau_bios_run_init_table(dev, script, dcb, crtc); -	} - -	clksor |= link_bw << 18; -	dpctrl |= ((1 << link_nr) - 1) << 16; -	if (enhframe) -		dpctrl |= 0x00004000; - -	for (i = 0; i < link_nr; i++) -		lane_mask |= 1 << (nvd0_sor_dp_lane_map(dev, dcb, i) >> 3); - -	nv_wr32(device, 0x612300 + soff, clksor); -	nv_wr32(device, 0x61c10c + loff, dpctrl); -	nv_mask(device, 0x61c130 + loff, 0x0000000f, lane_mask); -} - -static void -nvd0_sor_dp_link_get(struct drm_device *dev, struct dcb_output *dcb, -		     u32 *link_nr, u32 *link_bw) -{ -	struct nouveau_device *device = nouveau_dev(dev); -	const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1); -	const u32 loff = (or * 0x800) + (link * 0x80); -	const u32 soff = (or * 0x800); -	u32 dpctrl = nv_rd32(device, 0x61c10c + loff) & 0x000f0000; -	u32 clksor = nv_rd32(device, 0x612300 + soff); - -	if      (dpctrl > 0x00030000) *link_nr = 4; -	else if (dpctrl > 0x00010000) *link_nr = 2; -	else			      *link_nr = 1; - -	*link_bw  = (clksor & 0x007c0000) >> 18; -	*link_bw *= 27000; -} - -static void -nvd0_sor_dp_calc_tu(struct drm_device *dev, struct dcb_output *dcb, -		    u32 crtc, u32 datarate) -{ -	struct nouveau_device *device = nouveau_dev(dev); -	const u32 symbol = 100000; -	const u32 TU = 64; -	u32 link_nr, link_bw; -	u64 ratio, value; - -	nvd0_sor_dp_link_get(dev, dcb, &link_nr, &link_bw); - -	ratio  = datarate; -	ratio *= symbol; -	do_div(ratio, link_nr * link_bw); - -	value  = (symbol - ratio) * TU; -	value *= ratio; -	do_div(value, symbol); -	do_div(value, symbol); - -	value += 5; -	value |= 0x08000000; - -	nv_wr32(device, 0x616610 + (crtc * 0x800), value); -} - -static void -nvd0_sor_dpms(struct drm_encoder *encoder, int mode) -{ -	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -	struct drm_device *dev = encoder->dev; -	struct nouveau_device *device = nouveau_dev(dev); -	struct drm_encoder *partner; -	int or = nv_encoder->or; -	u32 dpms_ctrl; - -	nv_encoder->last_dpms = mode; - -	list_for_each_entry(partner, &dev->mode_config.encoder_list, head) { -		struct nouveau_encoder *nv_partner = nouveau_encoder(partner); - -		if (partner->encoder_type != DRM_MODE_ENCODER_TMDS) -			continue; - -		if (nv_partner != nv_encoder && -		    nv_partner->dcb->or == nv_encoder->dcb->or) { -			if (nv_partner->last_dpms == DRM_MODE_DPMS_ON) -				return; -			break; -		} -	} - -	dpms_ctrl  = (mode == DRM_MODE_DPMS_ON); -	dpms_ctrl |= 0x80000000; - -	nv_wait(device, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000); -	nv_mask(device, 0x61c004 + (or * 0x0800), 0x80000001, dpms_ctrl); -	nv_wait(device, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000); -	nv_wait(device, 0x61c030 + (or * 0x0800), 0x10000000, 0x00000000); - -	if (nv_encoder->dcb->type == DCB_OUTPUT_DP) { -		struct dp_train_func func = { -			.link_set = nvd0_sor_dp_link_set, -			.train_set = nvd0_sor_dp_train_set, -			.train_adj = nvd0_sor_dp_train_adj -		}; - -		nouveau_dp_dpms(encoder, mode, nv_encoder->dp.datarate, &func); -	} -} - -static bool -nvd0_sor_mode_fixup(struct drm_encoder *encoder, -		    const struct drm_display_mode *mode, -		    struct drm_display_mode *adjusted_mode) -{ -	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -	struct nouveau_connector *nv_connector; - -	nv_connector = nouveau_encoder_connector_get(nv_encoder); -	if (nv_connector && nv_connector->native_mode) { -		if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) { -			int id = adjusted_mode->base.id; -			*adjusted_mode = *nv_connector->native_mode; -			adjusted_mode->base.id = id; -		} -	} - -	return true; -} - -static void -nvd0_sor_disconnect(struct drm_encoder *encoder) -{ -	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -	struct drm_device *dev = encoder->dev; -	u32 *push; - -	if (nv_encoder->crtc) { -		nvd0_crtc_prepare(nv_encoder->crtc); - -		push = evo_wait(dev, EVO_MASTER, 4); -		if (push) { -			evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1); -			evo_data(push, 0x00000000); -			evo_mthd(push, 0x0080, 1); -			evo_data(push, 0x00000000); -			evo_kick(push, dev, EVO_MASTER); -		} - -		nvd0_hdmi_disconnect(encoder); - -		nv_encoder->crtc = NULL; -		nv_encoder->last_dpms = DRM_MODE_DPMS_OFF; -	} -} - -static void -nvd0_sor_prepare(struct drm_encoder *encoder) -{ -	nvd0_sor_disconnect(encoder); -	if (nouveau_encoder(encoder)->dcb->type == DCB_OUTPUT_DP) -		evo_sync(encoder->dev, EVO_MASTER); -} - -static void -nvd0_sor_commit(struct drm_encoder *encoder) -{ -} - -static void -nvd0_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, -		  struct drm_display_mode *mode) -{ -	struct drm_device *dev = encoder->dev; -	struct nouveau_drm *drm = nouveau_drm(dev); -	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -	struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); -	struct nouveau_connector *nv_connector; -	struct nvbios *bios = &drm->vbios; -	u32 mode_ctrl = (1 << nv_crtc->index); -	u32 syncs, magic, *push; -	u32 or_config; - -	syncs = 0x00000001; -	if (mode->flags & DRM_MODE_FLAG_NHSYNC) -		syncs |= 0x00000008; -	if (mode->flags & DRM_MODE_FLAG_NVSYNC) -		syncs |= 0x00000010; - -	magic = 0x31ec6000 | (nv_crtc->index << 25); -	if (mode->flags & DRM_MODE_FLAG_INTERLACE) -		magic |= 0x00000001; - -	nv_connector = nouveau_encoder_connector_get(nv_encoder); -	switch (nv_encoder->dcb->type) { -	case DCB_OUTPUT_TMDS: -		if (nv_encoder->dcb->sorconf.link & 1) { -			if (mode->clock < 165000) -				mode_ctrl |= 0x00000100; -			else -				mode_ctrl |= 0x00000500; -		} else { -			mode_ctrl |= 0x00000200; -		} - -		or_config = (mode_ctrl & 0x00000f00) >> 8; -		if (mode->clock >= 165000) -			or_config |= 0x0100; - -		nvd0_hdmi_mode_set(encoder, mode); -		break; -	case DCB_OUTPUT_LVDS: -		or_config = (mode_ctrl & 0x00000f00) >> 8; -		if (bios->fp_no_ddc) { -			if (bios->fp.dual_link) -				or_config |= 0x0100; -			if (bios->fp.if_is_24bit) -				or_config |= 0x0200; -		} else { -			if (nv_connector->type == DCB_CONNECTOR_LVDS_SPWG) { -				if (((u8 *)nv_connector->edid)[121] == 2) -					or_config |= 0x0100; -			} else -			if (mode->clock >= bios->fp.duallink_transition_clk) { -				or_config |= 0x0100; -			} - -			if (or_config & 0x0100) { -				if (bios->fp.strapless_is_24bit & 2) -					or_config |= 0x0200; -			} else { -				if (bios->fp.strapless_is_24bit & 1) -					or_config |= 0x0200; -			} - -			if (nv_connector->base.display_info.bpc == 8) -				or_config |= 0x0200; - -		} -		break; -	case DCB_OUTPUT_DP: -		if (nv_connector->base.display_info.bpc == 6) { -			nv_encoder->dp.datarate = mode->clock * 18 / 8; -			syncs |= 0x00000002 << 6; -		} else { -			nv_encoder->dp.datarate = mode->clock * 24 / 8; -			syncs |= 0x00000005 << 6; -		} - -		if (nv_encoder->dcb->sorconf.link & 1) -			mode_ctrl |= 0x00000800; -		else -			mode_ctrl |= 0x00000900; - -		or_config = (mode_ctrl & 0x00000f00) >> 8; -		break; -	default: -		BUG_ON(1); -		break; -	} - -	nvd0_sor_dpms(encoder, DRM_MODE_DPMS_ON); - -	if (nv_encoder->dcb->type == DCB_OUTPUT_DP) { -		nvd0_sor_dp_calc_tu(dev, nv_encoder->dcb, nv_crtc->index, -					 nv_encoder->dp.datarate); -	} - -	push = evo_wait(dev, EVO_MASTER, 8); -	if (push) { -		evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2); -		evo_data(push, syncs); -		evo_data(push, magic); -		evo_mthd(push, 0x0200 + (nv_encoder->or * 0x020), 2); -		evo_data(push, mode_ctrl); -		evo_data(push, or_config); -		evo_kick(push, dev, EVO_MASTER); -	} - -	nv_encoder->crtc = encoder->crtc; -} - -static void -nvd0_sor_destroy(struct drm_encoder *encoder) -{ -	drm_encoder_cleanup(encoder); -	kfree(encoder); -} - -static const struct drm_encoder_helper_funcs nvd0_sor_hfunc = { -	.dpms = nvd0_sor_dpms, -	.mode_fixup = nvd0_sor_mode_fixup, -	.prepare = nvd0_sor_prepare, -	.commit = nvd0_sor_commit, -	.mode_set = nvd0_sor_mode_set, -	.disable = nvd0_sor_disconnect, -	.get_crtc = nvd0_display_crtc_get, -}; - -static const struct drm_encoder_funcs nvd0_sor_func = { -	.destroy = nvd0_sor_destroy, -}; - -static int -nvd0_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) -{ -	struct drm_device *dev = connector->dev; -	struct nouveau_encoder *nv_encoder; -	struct drm_encoder *encoder; - -	nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); -	if (!nv_encoder) -		return -ENOMEM; -	nv_encoder->dcb = dcbe; -	nv_encoder->or = ffs(dcbe->or) - 1; -	nv_encoder->last_dpms = DRM_MODE_DPMS_OFF; - -	encoder = to_drm_encoder(nv_encoder); -	encoder->possible_crtcs = dcbe->heads; -	encoder->possible_clones = 0; -	drm_encoder_init(dev, encoder, &nvd0_sor_func, DRM_MODE_ENCODER_TMDS); -	drm_encoder_helper_add(encoder, &nvd0_sor_hfunc); - -	drm_mode_connector_attach_encoder(connector, encoder); -	return 0; -} - -/****************************************************************************** - * IRQ - *****************************************************************************/ -static struct dcb_output * -lookup_dcb(struct drm_device *dev, int id, u32 mc) -{ -	struct nouveau_drm *drm = nouveau_drm(dev); -	int type, or, i, link = -1; - -	if (id < 4) { -		type = DCB_OUTPUT_ANALOG; -		or   = id; -	} else { -		switch (mc & 0x00000f00) { -		case 0x00000000: link = 0; type = DCB_OUTPUT_LVDS; break; -		case 0x00000100: link = 0; type = DCB_OUTPUT_TMDS; break; -		case 0x00000200: link = 1; type = DCB_OUTPUT_TMDS; break; -		case 0x00000500: link = 0; type = DCB_OUTPUT_TMDS; break; -		case 0x00000800: link = 0; type = DCB_OUTPUT_DP; break; -		case 0x00000900: link = 1; type = DCB_OUTPUT_DP; break; -		default: -			NV_ERROR(drm, "PDISP: unknown SOR mc 0x%08x\n", mc); -			return NULL; -		} - -		or = id - 4; -	} - -	for (i = 0; i < drm->vbios.dcb.entries; i++) { -		struct dcb_output *dcb = &drm->vbios.dcb.entry[i]; -		if (dcb->type == type && (dcb->or & (1 << or)) && -		    (link < 0 || link == !(dcb->sorconf.link & 1))) -			return dcb; -	} - -	NV_ERROR(drm, "PDISP: DCB for %d/0x%08x not found\n", id, mc); -	return NULL; -} - -static void -nvd0_display_unk1_handler(struct drm_device *dev, u32 crtc, u32 mask) -{ -	struct nouveau_device *device = nouveau_dev(dev); -	struct dcb_output *dcb; -	int i; - -	for (i = 0; mask && i < 8; i++) { -		u32 mcc = nv_rd32(device, 0x640180 + (i * 0x20)); -		if (!(mcc & (1 << crtc))) -			continue; - -		dcb = lookup_dcb(dev, i, mcc); -		if (!dcb) -			continue; - -		nouveau_bios_run_display_table(dev, 0x0000, -1, dcb, crtc); -	} - -	nv_wr32(device, 0x6101d4, 0x00000000); -	nv_wr32(device, 0x6109d4, 0x00000000); -	nv_wr32(device, 0x6101d0, 0x80000000); -} - -static void -nvd0_display_unk2_handler(struct drm_device *dev, u32 crtc, u32 mask) -{ -	struct nouveau_device *device = nouveau_dev(dev); -	struct nouveau_drm *drm = nouveau_drm(dev); -	struct dcb_output *dcb; -	u32 or, tmp, pclk; -	int i; - -	for (i = 0; mask && i < 8; i++) { -		u32 mcc = nv_rd32(device, 0x640180 + (i * 0x20)); -		if (!(mcc & (1 << crtc))) -			continue; - -		dcb = lookup_dcb(dev, i, mcc); -		if (!dcb) -			continue; - -		nouveau_bios_run_display_table(dev, 0x0000, -2, dcb, crtc); -	} - -	pclk = nv_rd32(device, 0x660450 + (crtc * 0x300)) / 1000; -	NV_DEBUG(drm, "PDISP: crtc %d pclk %d mask 0x%08x\n", -			  crtc, pclk, mask); -	if (pclk && (mask & 0x00010000)) { -		nv50_crtc_set_clock(dev, crtc, pclk); -	} - -	for (i = 0; mask && i < 8; i++) { -		u32 mcp = nv_rd32(device, 0x660180 + (i * 0x20)); -		u32 cfg = nv_rd32(device, 0x660184 + (i * 0x20)); -		if (!(mcp & (1 << crtc))) -			continue; - -		dcb = lookup_dcb(dev, i, mcp); -		if (!dcb) -			continue; -		or = ffs(dcb->or) - 1; - -		nouveau_bios_run_display_table(dev, cfg, pclk, dcb, crtc); - -		nv_wr32(device, 0x612200 + (crtc * 0x800), 0x00000000); -		switch (dcb->type) { -		case DCB_OUTPUT_ANALOG: -			nv_wr32(device, 0x612280 + (or * 0x800), 0x00000000); -			break; -		case DCB_OUTPUT_TMDS: -		case DCB_OUTPUT_LVDS: -		case DCB_OUTPUT_DP: -			if (cfg & 0x00000100) -				tmp = 0x00000101; -			else -				tmp = 0x00000000; - -			nv_mask(device, 0x612300 + (or * 0x800), 0x00000707, tmp); -			break; -		default: -			break; -		} - -		break; -	} - -	nv_wr32(device, 0x6101d4, 0x00000000); -	nv_wr32(device, 0x6109d4, 0x00000000); -	nv_wr32(device, 0x6101d0, 0x80000000); -} - -static void -nvd0_display_unk4_handler(struct drm_device *dev, u32 crtc, u32 mask) -{ -	struct nouveau_device *device = nouveau_dev(dev); -	struct dcb_output *dcb; -	int pclk, i; - -	pclk = nv_rd32(device, 0x660450 + (crtc * 0x300)) / 1000; - -	for (i = 0; mask && i < 8; i++) { -		u32 mcp = nv_rd32(device, 0x660180 + (i * 0x20)); -		u32 cfg = nv_rd32(device, 0x660184 + (i * 0x20)); -		if (!(mcp & (1 << crtc))) -			continue; - -		dcb = lookup_dcb(dev, i, mcp); -		if (!dcb) -			continue; - -		nouveau_bios_run_display_table(dev, cfg, -pclk, dcb, crtc); -	} - -	nv_wr32(device, 0x6101d4, 0x00000000); -	nv_wr32(device, 0x6109d4, 0x00000000); -	nv_wr32(device, 0x6101d0, 0x80000000); -} - -static void -nvd0_display_bh(unsigned long data) -{ -	struct drm_device *dev = (struct drm_device *)data; -	struct nouveau_device *device = nouveau_dev(dev); -	struct nouveau_drm *drm = nouveau_drm(dev); -	struct nvd0_display *disp = nvd0_display(dev); -	u32 mask = 0, crtc = ~0; -	int i; - -	if (drm_debug & (DRM_UT_DRIVER | DRM_UT_KMS)) { -		NV_INFO(drm, "PDISP: modeset req %d\n", disp->modeset); -		NV_INFO(drm, " STAT: 0x%08x 0x%08x 0x%08x\n", -			 nv_rd32(device, 0x6101d0), -			 nv_rd32(device, 0x6101d4), nv_rd32(device, 0x6109d4)); -		for (i = 0; i < 8; i++) { -			NV_INFO(drm, " %s%d: 0x%08x 0x%08x\n", -				i < 4 ? "DAC" : "SOR", i, -				nv_rd32(device, 0x640180 + (i * 0x20)), -				nv_rd32(device, 0x660180 + (i * 0x20))); -		} -	} - -	while (!mask && ++crtc < dev->mode_config.num_crtc) -		mask = nv_rd32(device, 0x6101d4 + (crtc * 0x800)); - -	if (disp->modeset & 0x00000001) -		nvd0_display_unk1_handler(dev, crtc, mask); -	if (disp->modeset & 0x00000002) -		nvd0_display_unk2_handler(dev, crtc, mask); -	if (disp->modeset & 0x00000004) -		nvd0_display_unk4_handler(dev, crtc, mask); -} - -void -nvd0_display_intr(struct drm_device *dev) -{ -	struct nvd0_display *disp = nvd0_display(dev); -	struct nouveau_device *device = nouveau_dev(dev); -	struct nouveau_drm *drm = nouveau_drm(dev); -	u32 intr = nv_rd32(device, 0x610088); - -	if (intr & 0x00000001) { -		u32 stat = nv_rd32(device, 0x61008c); -		nv_wr32(device, 0x61008c, stat); -		intr &= ~0x00000001; -	} - -	if (intr & 0x00000002) { -		u32 stat = nv_rd32(device, 0x61009c); -		int chid = ffs(stat) - 1; -		if (chid >= 0) { -			u32 mthd = nv_rd32(device, 0x6101f0 + (chid * 12)); -			u32 data = nv_rd32(device, 0x6101f4 + (chid * 12)); -			u32 unkn = nv_rd32(device, 0x6101f8 + (chid * 12)); - -			NV_INFO(drm, "EvoCh: chid %d mthd 0x%04x data 0x%08x " -				     "0x%08x 0x%08x\n", -				chid, (mthd & 0x0000ffc), data, mthd, unkn); -			nv_wr32(device, 0x61009c, (1 << chid)); -			nv_wr32(device, 0x6101f0 + (chid * 12), 0x90000000); -		} - -		intr &= ~0x00000002; -	} - -	if (intr & 0x00100000) { -		u32 stat = nv_rd32(device, 0x6100ac); - -		if (stat & 0x00000007) { -			disp->modeset = stat; -			tasklet_schedule(&disp->tasklet); - -			nv_wr32(device, 0x6100ac, (stat & 0x00000007)); -			stat &= ~0x00000007; -		} - -		if (stat) { -			NV_INFO(drm, "PDISP: unknown intr24 0x%08x\n", stat); -			nv_wr32(device, 0x6100ac, stat); -		} - -		intr &= ~0x00100000; -	} - -	intr &= ~0x0f000000; /* vblank, handled in core */ -	if (intr) -		NV_INFO(drm, "PDISP: unknown intr 0x%08x\n", intr); -} - -/****************************************************************************** - * Init - *****************************************************************************/ -void -nvd0_display_fini(struct drm_device *dev) -{ -	int i; - -	/* fini cursors + overlays + flips */ -	for (i = 1; i >= 0; i--) { -		evo_fini_pio(dev, EVO_CURS(i)); -		evo_fini_pio(dev, EVO_OIMM(i)); -		evo_fini_dma(dev, EVO_OVLY(i)); -		evo_fini_dma(dev, EVO_FLIP(i)); -	} - -	/* fini master */ -	evo_fini_dma(dev, EVO_MASTER); -} - -int -nvd0_display_init(struct drm_device *dev) -{ -	struct nvd0_display *disp = nvd0_display(dev); -	struct nouveau_device *device = nouveau_dev(dev); -	struct nouveau_drm *drm = nouveau_drm(dev); -	int ret, i; -	u32 *push; - -	if (nv_rd32(device, 0x6100ac) & 0x00000100) { -		nv_wr32(device, 0x6100ac, 0x00000100); -		nv_mask(device, 0x6194e8, 0x00000001, 0x00000000); -		if (!nv_wait(device, 0x6194e8, 0x00000002, 0x00000000)) { -			NV_ERROR(drm, "PDISP: 0x6194e8 0x%08x\n", -				 nv_rd32(device, 0x6194e8)); -			return -EBUSY; -		} -	} - -	/* nfi what these are exactly, i do know that SOR_MODE_CTRL won't -	 * work at all unless you do the SOR part below. -	 */ -	for (i = 0; i < 3; i++) { -		u32 dac = nv_rd32(device, 0x61a000 + (i * 0x800)); -		nv_wr32(device, 0x6101c0 + (i * 0x800), dac); -	} - -	for (i = 0; i < 4; i++) { -		u32 sor = nv_rd32(device, 0x61c000 + (i * 0x800)); -		nv_wr32(device, 0x6301c4 + (i * 0x800), sor); -	} - -	for (i = 0; i < dev->mode_config.num_crtc; i++) { -		u32 crtc0 = nv_rd32(device, 0x616104 + (i * 0x800)); -		u32 crtc1 = nv_rd32(device, 0x616108 + (i * 0x800)); -		u32 crtc2 = nv_rd32(device, 0x61610c + (i * 0x800)); -		nv_wr32(device, 0x6101b4 + (i * 0x800), crtc0); -		nv_wr32(device, 0x6101b8 + (i * 0x800), crtc1); -		nv_wr32(device, 0x6101bc + (i * 0x800), crtc2); -	} - -	/* point at our hash table / objects, enable interrupts */ -	nv_wr32(device, 0x610010, (disp->mem->addr >> 8) | 9); -	nv_mask(device, 0x6100b0, 0x00000307, 0x00000307); - -	/* init master */ -	ret = evo_init_dma(dev, EVO_MASTER); -	if (ret) -		goto error; - -	/* init flips + overlays + cursors */ -	for (i = 0; i < dev->mode_config.num_crtc; i++) { -		if ((ret = evo_init_dma(dev, EVO_FLIP(i))) || -		    (ret = evo_init_dma(dev, EVO_OVLY(i))) || -		    (ret = evo_init_pio(dev, EVO_OIMM(i))) || -		    (ret = evo_init_pio(dev, EVO_CURS(i)))) -			goto error; -	} - -	push = evo_wait(dev, EVO_MASTER, 32); -	if (!push) { -		ret = -EBUSY; -		goto error; -	} -	evo_mthd(push, 0x0088, 1); -	evo_data(push, NvEvoSync); -	evo_mthd(push, 0x0084, 1); -	evo_data(push, 0x00000000); -	evo_mthd(push, 0x0084, 1); -	evo_data(push, 0x80000000); -	evo_mthd(push, 0x008c, 1); -	evo_data(push, 0x00000000); -	evo_kick(push, dev, EVO_MASTER); - -error: -	if (ret) -		nvd0_display_fini(dev); -	return ret; -} - -void -nvd0_display_destroy(struct drm_device *dev) -{ -	struct nvd0_display *disp = nvd0_display(dev); -	struct pci_dev *pdev = dev->pdev; -	int i; - -	for (i = 0; i < EVO_DMA_NR; i++) { -		struct evo *evo = &disp->evo[i]; -		pci_free_consistent(pdev, PAGE_SIZE, evo->ptr, evo->handle); -	} - -	nouveau_gpuobj_ref(NULL, &disp->mem); -	nouveau_bo_unmap(disp->sync); -	nouveau_bo_ref(NULL, &disp->sync); - -	nouveau_display(dev)->priv = NULL; -	kfree(disp); -} - -int -nvd0_display_create(struct drm_device *dev) -{ -	struct nouveau_device *device = nouveau_dev(dev); -	struct nouveau_drm *drm = nouveau_drm(dev); -	struct nouveau_bar *bar = nouveau_bar(device); -	struct nouveau_fb *pfb = nouveau_fb(device); -	struct dcb_table *dcb = &drm->vbios.dcb; -	struct drm_connector *connector, *tmp; -	struct pci_dev *pdev = dev->pdev; -	struct nvd0_display *disp; -	struct dcb_output *dcbe; -	int crtcs, ret, i; - -	disp = kzalloc(sizeof(*disp), GFP_KERNEL); -	if (!disp) -		return -ENOMEM; - -	nouveau_display(dev)->priv = disp; -	nouveau_display(dev)->dtor = nvd0_display_destroy; -	nouveau_display(dev)->init = nvd0_display_init; -	nouveau_display(dev)->fini = nvd0_display_fini; - -	/* create crtc objects to represent the hw heads */ -	crtcs = nv_rd32(device, 0x022448); -	for (i = 0; i < crtcs; i++) { -		ret = nvd0_crtc_create(dev, i); -		if (ret) -			goto out; -	} - -	/* create encoder/connector objects based on VBIOS DCB table */ -	for (i = 0, dcbe = &dcb->entry[0]; i < dcb->entries; i++, dcbe++) { -		connector = nouveau_connector_create(dev, dcbe->connector); -		if (IS_ERR(connector)) -			continue; - -		if (dcbe->location != DCB_LOC_ON_CHIP) { -			NV_WARN(drm, "skipping off-chip encoder %d/%d\n", -				dcbe->type, ffs(dcbe->or) - 1); -			continue; -		} - -		switch (dcbe->type) { -		case DCB_OUTPUT_TMDS: -		case DCB_OUTPUT_LVDS: -		case DCB_OUTPUT_DP: -			nvd0_sor_create(connector, dcbe); -			break; -		case DCB_OUTPUT_ANALOG: -			nvd0_dac_create(connector, dcbe); -			break; -		default: -			NV_WARN(drm, "skipping unsupported encoder %d/%d\n", -				dcbe->type, ffs(dcbe->or) - 1); -			continue; -		} -	} - -	/* cull any connectors we created that don't have an encoder */ -	list_for_each_entry_safe(connector, tmp, &dev->mode_config.connector_list, head) { -		if (connector->encoder_ids[0]) -			continue; - -		NV_WARN(drm, "%s has no encoders, removing\n", -			drm_get_connector_name(connector)); -		connector->funcs->destroy(connector); -	} - -	/* setup interrupt handling */ -	tasklet_init(&disp->tasklet, nvd0_display_bh, (unsigned long)dev); - -	/* small shared memory area we use for notifiers and semaphores */ -	ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM, -			     0, 0x0000, NULL, &disp->sync); -	if (!ret) { -		ret = nouveau_bo_pin(disp->sync, TTM_PL_FLAG_VRAM); -		if (!ret) -			ret = nouveau_bo_map(disp->sync); -		if (ret) -			nouveau_bo_ref(NULL, &disp->sync); -	} - -	if (ret) -		goto out; - -	/* hash table and dma objects for the memory areas we care about */ -	ret = nouveau_gpuobj_new(nv_object(device), NULL, 0x4000, 0x10000, -				 NVOBJ_FLAG_ZERO_ALLOC, &disp->mem); -	if (ret) -		goto out; - -	/* create evo dma channels */ -	for (i = 0; i < EVO_DMA_NR; i++) { -		struct evo *evo = &disp->evo[i]; -		u64 offset = disp->sync->bo.offset; -		u32 dmao = 0x1000 + (i * 0x100); -		u32 hash = 0x0000 + (i * 0x040); - -		evo->idx = i; -		evo->sem.offset = EVO_SYNC(evo->idx, 0x00); -		evo->ptr = pci_alloc_consistent(pdev, PAGE_SIZE, &evo->handle); -		if (!evo->ptr) { -			ret = -ENOMEM; -			goto out; -		} - -		nv_wo32(disp->mem, dmao + 0x00, 0x00000049); -		nv_wo32(disp->mem, dmao + 0x04, (offset + 0x0000) >> 8); -		nv_wo32(disp->mem, dmao + 0x08, (offset + 0x0fff) >> 8); -		nv_wo32(disp->mem, dmao + 0x0c, 0x00000000); -		nv_wo32(disp->mem, dmao + 0x10, 0x00000000); -		nv_wo32(disp->mem, dmao + 0x14, 0x00000000); -		nv_wo32(disp->mem, hash + 0x00, NvEvoSync); -		nv_wo32(disp->mem, hash + 0x04, 0x00000001 | (i << 27) | -						((dmao + 0x00) << 9)); - -		nv_wo32(disp->mem, dmao + 0x20, 0x00000049); -		nv_wo32(disp->mem, dmao + 0x24, 0x00000000); -		nv_wo32(disp->mem, dmao + 0x28, (pfb->ram.size - 1) >> 8); -		nv_wo32(disp->mem, dmao + 0x2c, 0x00000000); -		nv_wo32(disp->mem, dmao + 0x30, 0x00000000); -		nv_wo32(disp->mem, dmao + 0x34, 0x00000000); -		nv_wo32(disp->mem, hash + 0x08, NvEvoVRAM); -		nv_wo32(disp->mem, hash + 0x0c, 0x00000001 | (i << 27) | -						((dmao + 0x20) << 9)); - -		nv_wo32(disp->mem, dmao + 0x40, 0x00000009); -		nv_wo32(disp->mem, dmao + 0x44, 0x00000000); -		nv_wo32(disp->mem, dmao + 0x48, (pfb->ram.size - 1) >> 8); -		nv_wo32(disp->mem, dmao + 0x4c, 0x00000000); -		nv_wo32(disp->mem, dmao + 0x50, 0x00000000); -		nv_wo32(disp->mem, dmao + 0x54, 0x00000000); -		nv_wo32(disp->mem, hash + 0x10, NvEvoVRAM_LP); -		nv_wo32(disp->mem, hash + 0x14, 0x00000001 | (i << 27) | -						((dmao + 0x40) << 9)); - -		nv_wo32(disp->mem, dmao + 0x60, 0x0fe00009); -		nv_wo32(disp->mem, dmao + 0x64, 0x00000000); -		nv_wo32(disp->mem, dmao + 0x68, (pfb->ram.size - 1) >> 8); -		nv_wo32(disp->mem, dmao + 0x6c, 0x00000000); -		nv_wo32(disp->mem, dmao + 0x70, 0x00000000); -		nv_wo32(disp->mem, dmao + 0x74, 0x00000000); -		nv_wo32(disp->mem, hash + 0x18, NvEvoFB32); -		nv_wo32(disp->mem, hash + 0x1c, 0x00000001 | (i << 27) | -						((dmao + 0x60) << 9)); -	} - -	bar->flush(bar); - -out: -	if (ret) -		nvd0_display_destroy(dev); -	return ret; -}  |