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