[go: nahoru, domu]

nouveau_display.c revision 9285462273cbccb27187d5308ed95f94a9ceb1de
16ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs/*
26ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * Copyright (C) 2008 Maarten Maathuis.
36ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * All Rights Reserved.
46ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs *
56ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * Permission is hereby granted, free of charge, to any person obtaining
66ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * a copy of this software and associated documentation files (the
76ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * "Software"), to deal in the Software without restriction, including
86ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * without limitation the rights to use, copy, modify, merge, publish,
96ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * distribute, sublicense, and/or sell copies of the Software, and to
106ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * permit persons to whom the Software is furnished to do so, subject to
116ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * the following conditions:
126ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs *
136ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * The above copyright notice and this permission notice (including the
146ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * next paragraph) shall be included in all copies or substantial
156ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * portions of the Software.
166ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs *
176ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
186ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
196ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
206ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
216ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
226ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
236ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
246ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs *
256ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs */
266ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
27ebb945a94bba2ce8dff7b0942ff2b3f2a52a0a69Ben Skeggs#include "drmP.h"
289a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs#include "drm_crtc_helper.h"
29ebb945a94bba2ce8dff7b0942ff2b3f2a52a0a69Ben Skeggs#include "nouveau_drv.h"
30ebb945a94bba2ce8dff7b0942ff2b3f2a52a0a69Ben Skeggs#include "nouveau_fb.h"
3175c99da6cdd0ec9d70747f9ced3e85b2dd955cdfBen Skeggs#include "nouveau_fbcon.h"
326ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs#include "nouveau_hw.h"
336ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs#include "nouveau_crtc.h"
346ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs#include "nouveau_dma.h"
356ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs#include "nouveau_connector.h"
36ebb945a94bba2ce8dff7b0942ff2b3f2a52a0a69Ben Skeggs#include "nv50_display.h"
376ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
386ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic void
396ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsnouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb)
406ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{
416ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb);
426ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
436ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	if (fb->nvbo)
446ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		drm_gem_object_unreference_unlocked(fb->nvbo->gem);
45ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs
46ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs	drm_framebuffer_cleanup(drm_fb);
47ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs	kfree(fb);
48ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs}
49ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs
50ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggsstatic int
51ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggsnouveau_user_framebuffer_create_handle(struct drm_framebuffer *drm_fb,
52ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs				       struct drm_file *file_priv,
534e03b4af6dd3cff445fc0455805b43b101647bfcFrancisco Jerez				       unsigned int *handle)
546ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{
554e03b4af6dd3cff445fc0455805b43b101647bfcFrancisco Jerez	struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb);
566ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
57967e7bde8739fe3b215f7537e8f1f39c044902afBen Skeggs	return drm_gem_handle_create(file_priv, fb->nvbo->gem, handle);
584e03b4af6dd3cff445fc0455805b43b101647bfcFrancisco Jerez}
59967e7bde8739fe3b215f7537e8f1f39c044902afBen Skeggs
60ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggsstatic const struct drm_framebuffer_funcs nouveau_framebuffer_funcs = {
61ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs	.destroy = nouveau_user_framebuffer_destroy,
62ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs	.create_handle = nouveau_user_framebuffer_create_handle,
63ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs};
64ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs
65ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggsint
66ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggsnouveau_framebuffer_init(struct drm_device *dev,
67ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs			 struct nouveau_framebuffer *nv_fb,
68ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs			 struct drm_mode_fb_cmd2 *mode_cmd,
69ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs			 struct nouveau_bo *nvbo)
70ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs{
71ebb945a94bba2ce8dff7b0942ff2b3f2a52a0a69Ben Skeggs	struct drm_nouveau_private *dev_priv = dev->dev_private;
72ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs	struct drm_framebuffer *fb = &nv_fb->base;
73ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs	int ret;
746ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
756ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	ret = drm_framebuffer_init(dev, fb, &nouveau_framebuffer_funcs);
76ebb945a94bba2ce8dff7b0942ff2b3f2a52a0a69Ben Skeggs	if (ret) {
77ebb945a94bba2ce8dff7b0942ff2b3f2a52a0a69Ben Skeggs		return ret;
78ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs	}
79ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs
80ebb945a94bba2ce8dff7b0942ff2b3f2a52a0a69Ben Skeggs	drm_helper_mode_fill_fb_struct(fb, mode_cmd);
816ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	nv_fb->nvbo = nvbo;
826ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
839a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	if (dev_priv->card_type >= NV_50) {
849a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs		u32 tile_flags = nouveau_bo_tile_layout(nvbo);
85a1606a9596e54da90ad6209071b357a4c1b0fa82Ben Skeggs		if (tile_flags == 0x7a00 ||
869a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs		    tile_flags == 0xfe00)
87ebb945a94bba2ce8dff7b0942ff2b3f2a52a0a69Ben Skeggs			nv_fb->r_dma = NvEvoFB32;
889f9f51fcb92ba3c1f395e0908407c8c1f5305a31Ben Skeggs		else
899a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs		if (tile_flags == 0x7000)
909f9f51fcb92ba3c1f395e0908407c8c1f5305a31Ben Skeggs			nv_fb->r_dma = NvEvoFB16;
919f9f51fcb92ba3c1f395e0908407c8c1f5305a31Ben Skeggs		else
92ebb945a94bba2ce8dff7b0942ff2b3f2a52a0a69Ben Skeggs			nv_fb->r_dma = NvEvoVRAM_LP;
939f9f51fcb92ba3c1f395e0908407c8c1f5305a31Ben Skeggs
949f9f51fcb92ba3c1f395e0908407c8c1f5305a31Ben Skeggs		switch (fb->depth) {
959a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs		case  8: nv_fb->r_format = NV50_EVO_CRTC_FB_DEPTH_8; break;
969a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs		case 15: nv_fb->r_format = NV50_EVO_CRTC_FB_DEPTH_15; break;
97ebb945a94bba2ce8dff7b0942ff2b3f2a52a0a69Ben Skeggs		case 16: nv_fb->r_format = NV50_EVO_CRTC_FB_DEPTH_16; break;
98d87897d4c853a5c136f60efa858d0d4cb3740f57Ben Skeggs		case 24:
99a1606a9596e54da90ad6209071b357a4c1b0fa82Ben Skeggs		case 32: nv_fb->r_format = NV50_EVO_CRTC_FB_DEPTH_24; break;
1009a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs		case 30: nv_fb->r_format = NV50_EVO_CRTC_FB_DEPTH_30; break;
1019a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs		default:
102ce48fa93a6f5cadd4141a921dfb4129c8850374eMaarten Maathuis			 NV_ERROR(dev, "unknown depth %d\n", fb->depth);
10385b2331b3437a55c21cce3ee1ea0bd12301ecb56Daniel Vetter			 return -EINVAL;
104ce48fa93a6f5cadd4141a921dfb4129c8850374eMaarten Maathuis		}
105ce48fa93a6f5cadd4141a921dfb4129c8850374eMaarten Maathuis
106ce48fa93a6f5cadd4141a921dfb4129c8850374eMaarten Maathuis		if (dev_priv->chipset == 0x50)
107967e7bde8739fe3b215f7537e8f1f39c044902afBen Skeggs			nv_fb->r_format |= (tile_flags << 8);
1089a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs
1099a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs		if (!tile_flags) {
1109a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs			if (dev_priv->card_type < NV_D0)
1119a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs				nv_fb->r_pitch = 0x00100000 | fb->pitches[0];
1129a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs			else
1139a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs				nv_fb->r_pitch = 0x01000000 | fb->pitches[0];
1149a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs		} else {
1159a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs			u32 mode = nvbo->tile_mode;
1169a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs			if (dev_priv->card_type >= NV_C0)
117967e7bde8739fe3b215f7537e8f1f39c044902afBen Skeggs				mode >>= 4;
1189a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs			nv_fb->r_pitch = ((fb->pitches[0] / 4) << 4) | mode;
1199a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs		}
1209a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	}
1219a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs
1229a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	return 0;
1239a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs}
1249a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs
1259a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggsstatic struct drm_framebuffer *
1269a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggsnouveau_user_framebuffer_create(struct drm_device *dev,
1279a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs				struct drm_file *file_priv,
1289a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs				struct drm_mode_fb_cmd2 *mode_cmd)
1299a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs{
1309a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	struct nouveau_framebuffer *nouveau_fb;
13162841ab726def838472dfaaee571a0d30a2ce1e0Ben Skeggs	struct drm_gem_object *gem;
1329a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	int ret;
1339a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs
1349a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]);
1359a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	if (!gem)
1369a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs		return ERR_PTR(-ENOENT);
1379a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs
1389a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	nouveau_fb = kzalloc(sizeof(struct nouveau_framebuffer), GFP_KERNEL);
1399a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	if (!nouveau_fb)
1404e03b4af6dd3cff445fc0455805b43b101647bfcFrancisco Jerez		return ERR_PTR(-ENOMEM);
1414e03b4af6dd3cff445fc0455805b43b101647bfcFrancisco Jerez
1429a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	ret = nouveau_framebuffer_init(dev, nouveau_fb, mode_cmd, nouveau_gem_object(gem));
1439a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	if (ret) {
1449a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs		drm_gem_object_unreference(gem);
1459a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs		return ERR_PTR(ret);
1469a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	}
1479a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs
1489a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	return &nouveau_fb->base;
1499a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs}
1509a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs
1519a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggsstatic const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
1529a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	.fb_create = nouveau_user_framebuffer_create,
1539a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	.output_poll_changed = nouveau_fbcon_output_poll_changed,
1549a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs};
1559a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs
1569a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs
1579a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggsstruct drm_prop_enum_list {
1589a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	u8 gen_mask;
1599a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	int type;
1609a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	char *name;
1619a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs};
1629a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs
1639a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggsstatic struct drm_prop_enum_list underscan[] = {
1649a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	{ 6, UNDERSCAN_AUTO, "auto" },
1659a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	{ 6, UNDERSCAN_OFF, "off" },
1669a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	{ 6, UNDERSCAN_ON, "on" },
1679a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	{}
1689a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs};
1699a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs
1709a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggsstatic struct drm_prop_enum_list dither_mode[] = {
1719a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	{ 7, DITHERING_MODE_AUTO, "auto" },
1729a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	{ 7, DITHERING_MODE_OFF, "off" },
1739a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	{ 1, DITHERING_MODE_ON, "on" },
1749a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	{ 6, DITHERING_MODE_STATIC2X2, "static 2x2" },
1759a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	{ 6, DITHERING_MODE_DYNAMIC2X2, "dynamic 2x2" },
1769a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	{ 4, DITHERING_MODE_TEMPORAL, "temporal" },
1779a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	{}
1789a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs};
1799a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs
1806ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic struct drm_prop_enum_list dither_depth[] = {
1819a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	{ 6, DITHERING_DEPTH_AUTO, "auto" },
1826ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	{ 6, DITHERING_DEPTH_6BPC, "6 bpc" },
1834e03b4af6dd3cff445fc0455805b43b101647bfcFrancisco Jerez	{ 6, DITHERING_DEPTH_8BPC, "8 bpc" },
1844e03b4af6dd3cff445fc0455805b43b101647bfcFrancisco Jerez	{}
1856ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs};
1869a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs
1879a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs#define PROP_ENUM(p,gen,n,list) do {                                           \
1889a391ad8a2cdd7e5be9b6aabb56f4a46683ba377Ben Skeggs	struct drm_prop_enum_list *l = (list);                                 \
1896ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	int c = 0;                                                             \
190ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs	while (l->gen_mask) {                                                  \
191ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs		if (l->gen_mask & (1 << (gen)))                                \
192ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs			c++;                                                   \
1936ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		l++;                                                           \
1946ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	}                                                                      \
1956ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	if (c) {                                                               \
1966ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		p = drm_property_create(dev, DRM_MODE_PROP_ENUM, n, c);        \
1976ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		l = (list);                                                    \
1986ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		c = 0;                                                         \
1996ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		while (p && l->gen_mask) {                                     \
2006ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			if (l->gen_mask & (1 << (gen))) {                      \
2016ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs				drm_property_add_enum(p, c, l->type, l->name); \
2026ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs				c++;                                           \
203ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs			}                                                      \
2046ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			l++;                                                   \
2056ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		}                                                              \
2066ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	}                                                                      \
2076ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs} while(0)
2086ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
2096ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsint
2106ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsnouveau_display_init(struct drm_device *dev)
2116ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{
2126ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct drm_nouveau_private *dev_priv = dev->dev_private;
2136ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct nouveau_display_engine *disp = &dev_priv->engine.display;
2146ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	int ret;
2156ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
2166ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	ret = disp->init(dev);
2176ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	if (ret == 0) {
2186ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		drm_kms_helper_poll_enable(dev);
2196ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	}
2206ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
2216ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	return ret;
2226ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs}
2236ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
2246ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsvoid
2256ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsnouveau_display_fini(struct drm_device *dev)
2266ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{
2276ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct drm_nouveau_private *dev_priv = dev->dev_private;
228ebb945a94bba2ce8dff7b0942ff2b3f2a52a0a69Ben Skeggs	struct nouveau_display_engine *disp = &dev_priv->engine.display;
229ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs
230ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs	drm_kms_helper_poll_disable(dev);
231ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs	disp->fini(dev);
232ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs}
233ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs
234ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggsint
235ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggsnouveau_display_create(struct drm_device *dev)
236ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs{
237ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs	struct drm_nouveau_private *dev_priv = dev->dev_private;
238ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs	struct nouveau_display_engine *disp = &dev_priv->engine.display;
239ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs	int ret, gen;
240ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs
241ba59953d281747b1f7518a60f0ba8ff671cd0d65Ben Skeggs	drm_mode_config_init(dev);
2426ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	drm_mode_create_scaling_mode_property(dev);
2436ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	drm_mode_create_dvi_i_properties(dev);
2446ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
2456ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	if (dev_priv->card_type < NV_50)
2466ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		gen = 0;
2476ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	else
2486ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	if (dev_priv->card_type < NV_D0)
2496ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		gen = 1;
2506ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	else
2516ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		gen = 2;
2526ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
2536ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	PROP_ENUM(disp->dithering_mode, gen, "dithering mode", dither_mode);
2546ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	PROP_ENUM(disp->dithering_depth, gen, "dithering depth", dither_depth);
2556ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	PROP_ENUM(disp->underscan_property, gen, "underscan", underscan);
2566ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
2576ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	disp->underscan_hborder_property =
2586ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		drm_property_create(dev, DRM_MODE_PROP_RANGE,
2596ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs				    "underscan hborder", 2);
2606ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	disp->underscan_hborder_property->values[0] = 0;
2616ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	disp->underscan_hborder_property->values[1] = 128;
2626ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
263	disp->underscan_vborder_property =
264		drm_property_create(dev, DRM_MODE_PROP_RANGE,
265				    "underscan vborder", 2);
266	disp->underscan_vborder_property->values[0] = 0;
267	disp->underscan_vborder_property->values[1] = 128;
268
269	dev->mode_config.funcs = (void *)&nouveau_mode_config_funcs;
270	dev->mode_config.fb_base = pci_resource_start(dev->pdev, 1);
271
272	dev->mode_config.min_width = 0;
273	dev->mode_config.min_height = 0;
274	if (dev_priv->card_type < NV_10) {
275		dev->mode_config.max_width = 2048;
276		dev->mode_config.max_height = 2048;
277	} else
278	if (dev_priv->card_type < NV_50) {
279		dev->mode_config.max_width = 4096;
280		dev->mode_config.max_height = 4096;
281	} else {
282		dev->mode_config.max_width = 8192;
283		dev->mode_config.max_height = 8192;
284	}
285
286	drm_kms_helper_poll_init(dev);
287	drm_kms_helper_poll_disable(dev);
288
289	ret = disp->create(dev);
290	if (ret)
291		return ret;
292
293	if (dev->mode_config.num_crtc) {
294		ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
295		if (ret)
296			return ret;
297	}
298
299	return ret;
300}
301
302void
303nouveau_display_destroy(struct drm_device *dev)
304{
305	struct drm_nouveau_private *dev_priv = dev->dev_private;
306	struct nouveau_display_engine *disp = &dev_priv->engine.display;
307
308	drm_vblank_cleanup(dev);
309
310	disp->destroy(dev);
311
312	drm_kms_helper_poll_fini(dev);
313	drm_mode_config_cleanup(dev);
314}
315
316int
317nouveau_vblank_enable(struct drm_device *dev, int crtc)
318{
319	struct drm_nouveau_private *dev_priv = dev->dev_private;
320
321	if (dev_priv->card_type >= NV_50)
322		nv_mask(dev, NV50_PDISPLAY_INTR_EN_1, 0,
323			NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc));
324	else
325		NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0,
326			    NV_PCRTC_INTR_0_VBLANK);
327
328	return 0;
329}
330
331void
332nouveau_vblank_disable(struct drm_device *dev, int crtc)
333{
334	struct drm_nouveau_private *dev_priv = dev->dev_private;
335
336	if (dev_priv->card_type >= NV_50)
337		nv_mask(dev, NV50_PDISPLAY_INTR_EN_1,
338			NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc), 0);
339	else
340		NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0, 0);
341}
342
343static int
344nouveau_page_flip_reserve(struct nouveau_bo *old_bo,
345			  struct nouveau_bo *new_bo)
346{
347	int ret;
348
349	ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM);
350	if (ret)
351		return ret;
352
353	ret = ttm_bo_reserve(&new_bo->bo, false, false, false, 0);
354	if (ret)
355		goto fail;
356
357	ret = ttm_bo_reserve(&old_bo->bo, false, false, false, 0);
358	if (ret)
359		goto fail_unreserve;
360
361	return 0;
362
363fail_unreserve:
364	ttm_bo_unreserve(&new_bo->bo);
365fail:
366	nouveau_bo_unpin(new_bo);
367	return ret;
368}
369
370static void
371nouveau_page_flip_unreserve(struct nouveau_bo *old_bo,
372			    struct nouveau_bo *new_bo,
373			    struct nouveau_fence *fence)
374{
375	nouveau_bo_fence(new_bo, fence);
376	ttm_bo_unreserve(&new_bo->bo);
377
378	nouveau_bo_fence(old_bo, fence);
379	ttm_bo_unreserve(&old_bo->bo);
380
381	nouveau_bo_unpin(old_bo);
382}
383
384static int
385nouveau_page_flip_emit(struct nouveau_channel *chan,
386		       struct nouveau_bo *old_bo,
387		       struct nouveau_bo *new_bo,
388		       struct nouveau_page_flip_state *s,
389		       struct nouveau_fence **pfence)
390{
391	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
392	struct drm_device *dev = chan->dev;
393	unsigned long flags;
394	int ret;
395
396	/* Queue it to the pending list */
397	spin_lock_irqsave(&dev->event_lock, flags);
398	list_add_tail(&s->head, &chan->nvsw.flip);
399	spin_unlock_irqrestore(&dev->event_lock, flags);
400
401	/* Synchronize with the old framebuffer */
402	ret = nouveau_fence_sync(old_bo->bo.sync_obj, chan);
403	if (ret)
404		goto fail;
405
406	/* Emit the pageflip */
407	ret = RING_SPACE(chan, 2);
408	if (ret)
409		goto fail;
410
411	if (dev_priv->card_type < NV_C0)
412		BEGIN_RING(chan, NvSubSw, NV_SW_PAGE_FLIP, 1);
413	else
414		BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0500, 1);
415	OUT_RING  (chan, 0);
416	FIRE_RING (chan);
417
418	ret = nouveau_fence_new(chan, pfence, true);
419	if (ret)
420		goto fail;
421
422	return 0;
423fail:
424	spin_lock_irqsave(&dev->event_lock, flags);
425	list_del(&s->head);
426	spin_unlock_irqrestore(&dev->event_lock, flags);
427	return ret;
428}
429
430int
431nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
432		       struct drm_pending_vblank_event *event)
433{
434	struct drm_device *dev = crtc->dev;
435	struct drm_nouveau_private *dev_priv = dev->dev_private;
436	struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->fb)->nvbo;
437	struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo;
438	struct nouveau_page_flip_state *s;
439	struct nouveau_channel *chan;
440	struct nouveau_fence *fence;
441	int ret;
442
443	if (!dev_priv->channel)
444		return -ENODEV;
445
446	s = kzalloc(sizeof(*s), GFP_KERNEL);
447	if (!s)
448		return -ENOMEM;
449
450	/* Don't let the buffers go away while we flip */
451	ret = nouveau_page_flip_reserve(old_bo, new_bo);
452	if (ret)
453		goto fail_free;
454
455	/* Initialize a page flip struct */
456	*s = (struct nouveau_page_flip_state)
457		{ { }, event, nouveau_crtc(crtc)->index,
458		  fb->bits_per_pixel, fb->pitches[0], crtc->x, crtc->y,
459		  new_bo->bo.offset };
460
461	/* Choose the channel the flip will be handled in */
462	chan = nouveau_fence_channel(new_bo->bo.sync_obj);
463	if (!chan)
464		chan = nouveau_channel_get_unlocked(dev_priv->channel);
465	mutex_lock(&chan->mutex);
466
467	/* Emit a page flip */
468	if (dev_priv->card_type >= NV_50) {
469		ret = nv50_display_flip_next(crtc, fb, chan);
470		if (ret) {
471			nouveau_channel_put(&chan);
472			goto fail_unreserve;
473		}
474	}
475
476	ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence);
477	nouveau_channel_put(&chan);
478	if (ret)
479		goto fail_unreserve;
480
481	/* Update the crtc struct and cleanup */
482	crtc->fb = fb;
483
484	nouveau_page_flip_unreserve(old_bo, new_bo, fence);
485	nouveau_fence_unref(&fence);
486	return 0;
487
488fail_unreserve:
489	nouveau_page_flip_unreserve(old_bo, new_bo, NULL);
490fail_free:
491	kfree(s);
492	return ret;
493}
494
495int
496nouveau_finish_page_flip(struct nouveau_channel *chan,
497			 struct nouveau_page_flip_state *ps)
498{
499	struct drm_device *dev = chan->dev;
500	struct nouveau_page_flip_state *s;
501	unsigned long flags;
502
503	spin_lock_irqsave(&dev->event_lock, flags);
504
505	if (list_empty(&chan->nvsw.flip)) {
506		NV_ERROR(dev, "Unexpected pageflip in channel %d.\n", chan->id);
507		spin_unlock_irqrestore(&dev->event_lock, flags);
508		return -EINVAL;
509	}
510
511	s = list_first_entry(&chan->nvsw.flip,
512			     struct nouveau_page_flip_state, head);
513	if (s->event) {
514		struct drm_pending_vblank_event *e = s->event;
515		struct timeval now;
516
517		do_gettimeofday(&now);
518		e->event.sequence = 0;
519		e->event.tv_sec = now.tv_sec;
520		e->event.tv_usec = now.tv_usec;
521		list_add_tail(&e->base.link, &e->base.file_priv->event_list);
522		wake_up_interruptible(&e->base.file_priv->event_wait);
523	}
524
525	list_del(&s->head);
526	if (ps)
527		*ps = *s;
528	kfree(s);
529
530	spin_unlock_irqrestore(&dev->event_lock, flags);
531	return 0;
532}
533
534int
535nouveau_display_dumb_create(struct drm_file *file_priv, struct drm_device *dev,
536			    struct drm_mode_create_dumb *args)
537{
538	struct nouveau_bo *bo;
539	int ret;
540
541	args->pitch = roundup(args->width * (args->bpp / 8), 256);
542	args->size = args->pitch * args->height;
543	args->size = roundup(args->size, PAGE_SIZE);
544
545	ret = nouveau_gem_new(dev, args->size, 0, TTM_PL_FLAG_VRAM, 0, 0, &bo);
546	if (ret)
547		return ret;
548
549	ret = drm_gem_handle_create(file_priv, bo->gem, &args->handle);
550	drm_gem_object_unreference_unlocked(bo->gem);
551	return ret;
552}
553
554int
555nouveau_display_dumb_destroy(struct drm_file *file_priv, struct drm_device *dev,
556			     uint32_t handle)
557{
558	return drm_gem_handle_delete(file_priv, handle);
559}
560
561int
562nouveau_display_dumb_map_offset(struct drm_file *file_priv,
563				struct drm_device *dev,
564				uint32_t handle, uint64_t *poffset)
565{
566	struct drm_gem_object *gem;
567
568	gem = drm_gem_object_lookup(dev, file_priv, handle);
569	if (gem) {
570		struct nouveau_bo *bo = gem->driver_private;
571		*poffset = bo->bo.addr_space_offset;
572		drm_gem_object_unreference_unlocked(gem);
573		return 0;
574	}
575
576	return -ENOENT;
577}
578