18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2013 Ilia Mirkin 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation 78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 128c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 158c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 168c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 178c2ecf20Sopenharmony_ci * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 188c2ecf20Sopenharmony_ci * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 198c2ecf20Sopenharmony_ci * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 208c2ecf20Sopenharmony_ci * SOFTWARE. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Implementation based on the pre-KMS implementation in xf86-video-nouveau, 238c2ecf20Sopenharmony_ci * written by Arthur Huillet. 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <drm/drm_crtc.h> 278c2ecf20Sopenharmony_ci#include <drm/drm_fourcc.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include "nouveau_drv.h" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include "nouveau_bo.h" 328c2ecf20Sopenharmony_ci#include "nouveau_connector.h" 338c2ecf20Sopenharmony_ci#include "nouveau_display.h" 348c2ecf20Sopenharmony_ci#include "nouveau_gem.h" 358c2ecf20Sopenharmony_ci#include "nvreg.h" 368c2ecf20Sopenharmony_ci#include "disp.h" 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistruct nouveau_plane { 398c2ecf20Sopenharmony_ci struct drm_plane base; 408c2ecf20Sopenharmony_ci bool flip; 418c2ecf20Sopenharmony_ci struct nouveau_bo *cur; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci struct { 448c2ecf20Sopenharmony_ci struct drm_property *colorkey; 458c2ecf20Sopenharmony_ci struct drm_property *contrast; 468c2ecf20Sopenharmony_ci struct drm_property *brightness; 478c2ecf20Sopenharmony_ci struct drm_property *hue; 488c2ecf20Sopenharmony_ci struct drm_property *saturation; 498c2ecf20Sopenharmony_ci } props; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci int colorkey; 528c2ecf20Sopenharmony_ci int contrast; 538c2ecf20Sopenharmony_ci int brightness; 548c2ecf20Sopenharmony_ci int hue; 558c2ecf20Sopenharmony_ci int saturation; 568c2ecf20Sopenharmony_ci enum drm_color_encoding color_encoding; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci void (*set_params)(struct nouveau_plane *); 598c2ecf20Sopenharmony_ci}; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic uint32_t formats[] = { 628c2ecf20Sopenharmony_ci DRM_FORMAT_YUYV, 638c2ecf20Sopenharmony_ci DRM_FORMAT_UYVY, 648c2ecf20Sopenharmony_ci DRM_FORMAT_NV12, 658c2ecf20Sopenharmony_ci DRM_FORMAT_NV21, 668c2ecf20Sopenharmony_ci}; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* Sine can be approximated with 698c2ecf20Sopenharmony_ci * http://en.wikipedia.org/wiki/Bhaskara_I's_sine_approximation_formula 708c2ecf20Sopenharmony_ci * sin(x degrees) ~= 4 x (180 - x) / (40500 - x (180 - x) ) 718c2ecf20Sopenharmony_ci * Note that this only works for the range [0, 180]. 728c2ecf20Sopenharmony_ci * Also note that sin(x) == -sin(x - 180) 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_cistatic inline int 758c2ecf20Sopenharmony_cisin_mul(int degrees, int factor) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci if (degrees > 180) { 788c2ecf20Sopenharmony_ci degrees -= 180; 798c2ecf20Sopenharmony_ci factor *= -1; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci return factor * 4 * degrees * (180 - degrees) / 828c2ecf20Sopenharmony_ci (40500 - degrees * (180 - degrees)); 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/* cos(x) = sin(x + 90) */ 868c2ecf20Sopenharmony_cistatic inline int 878c2ecf20Sopenharmony_cicos_mul(int degrees, int factor) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci return sin_mul((degrees + 90) % 360, factor); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic int 938c2ecf20Sopenharmony_civerify_scaling(const struct drm_framebuffer *fb, uint8_t shift, 948c2ecf20Sopenharmony_ci uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h, 958c2ecf20Sopenharmony_ci uint32_t crtc_w, uint32_t crtc_h) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci if (crtc_w < (src_w >> shift) || crtc_h < (src_h >> shift)) { 988c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("Unsuitable framebuffer scaling: %dx%d -> %dx%d\n", 998c2ecf20Sopenharmony_ci src_w, src_h, crtc_w, crtc_h); 1008c2ecf20Sopenharmony_ci return -ERANGE; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci if (src_x != 0 || src_y != 0) { 1048c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("Unsuitable framebuffer offset: %d,%d\n", 1058c2ecf20Sopenharmony_ci src_x, src_y); 1068c2ecf20Sopenharmony_ci return -ERANGE; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci return 0; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic int 1138c2ecf20Sopenharmony_cinv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, 1148c2ecf20Sopenharmony_ci struct drm_framebuffer *fb, int crtc_x, int crtc_y, 1158c2ecf20Sopenharmony_ci unsigned int crtc_w, unsigned int crtc_h, 1168c2ecf20Sopenharmony_ci uint32_t src_x, uint32_t src_y, 1178c2ecf20Sopenharmony_ci uint32_t src_w, uint32_t src_h, 1188c2ecf20Sopenharmony_ci struct drm_modeset_acquire_ctx *ctx) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci struct nouveau_drm *drm = nouveau_drm(plane->dev); 1218c2ecf20Sopenharmony_ci struct nvif_object *dev = &drm->client.device.object; 1228c2ecf20Sopenharmony_ci struct nouveau_plane *nv_plane = 1238c2ecf20Sopenharmony_ci container_of(plane, struct nouveau_plane, base); 1248c2ecf20Sopenharmony_ci struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); 1258c2ecf20Sopenharmony_ci struct nouveau_bo *cur = nv_plane->cur; 1268c2ecf20Sopenharmony_ci struct nouveau_bo *nvbo; 1278c2ecf20Sopenharmony_ci bool flip = nv_plane->flip; 1288c2ecf20Sopenharmony_ci int soff = NV_PCRTC0_SIZE * nv_crtc->index; 1298c2ecf20Sopenharmony_ci int soff2 = NV_PCRTC0_SIZE * !nv_crtc->index; 1308c2ecf20Sopenharmony_ci unsigned shift = drm->client.device.info.chipset >= 0x30 ? 1 : 3; 1318c2ecf20Sopenharmony_ci unsigned format = 0; 1328c2ecf20Sopenharmony_ci int ret; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* Source parameters given in 16.16 fixed point, ignore fractional. */ 1358c2ecf20Sopenharmony_ci src_x >>= 16; 1368c2ecf20Sopenharmony_ci src_y >>= 16; 1378c2ecf20Sopenharmony_ci src_w >>= 16; 1388c2ecf20Sopenharmony_ci src_h >>= 16; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci ret = verify_scaling(fb, shift, 0, 0, src_w, src_h, crtc_w, crtc_h); 1418c2ecf20Sopenharmony_ci if (ret) 1428c2ecf20Sopenharmony_ci return ret; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci nvbo = nouveau_gem_object(fb->obj[0]); 1458c2ecf20Sopenharmony_ci ret = nouveau_bo_pin(nvbo, NOUVEAU_GEM_DOMAIN_VRAM, false); 1468c2ecf20Sopenharmony_ci if (ret) 1478c2ecf20Sopenharmony_ci return ret; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci nv_plane->cur = nvbo; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci nvif_mask(dev, NV_PCRTC_ENGINE_CTRL + soff, NV_CRTC_FSEL_OVERLAY, NV_CRTC_FSEL_OVERLAY); 1528c2ecf20Sopenharmony_ci nvif_mask(dev, NV_PCRTC_ENGINE_CTRL + soff2, NV_CRTC_FSEL_OVERLAY, 0); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_BASE(flip), 0); 1558c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_OFFSET_BUFF(flip), nvbo->offset); 1568c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_SIZE_IN(flip), src_h << 16 | src_w); 1578c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_POINT_IN(flip), src_y << 16 | src_x); 1588c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_DS_DX(flip), (src_w << 20) / crtc_w); 1598c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_DT_DY(flip), (src_h << 20) / crtc_h); 1608c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_POINT_OUT(flip), crtc_y << 16 | crtc_x); 1618c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_SIZE_OUT(flip), crtc_h << 16 | crtc_w); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if (fb->format->format == DRM_FORMAT_YUYV || 1648c2ecf20Sopenharmony_ci fb->format->format == DRM_FORMAT_NV12) 1658c2ecf20Sopenharmony_ci format |= NV_PVIDEO_FORMAT_COLOR_LE_CR8YB8CB8YA8; 1668c2ecf20Sopenharmony_ci if (fb->format->format == DRM_FORMAT_NV12 || 1678c2ecf20Sopenharmony_ci fb->format->format == DRM_FORMAT_NV21) 1688c2ecf20Sopenharmony_ci format |= NV_PVIDEO_FORMAT_PLANAR; 1698c2ecf20Sopenharmony_ci if (nv_plane->color_encoding == DRM_COLOR_YCBCR_BT709) 1708c2ecf20Sopenharmony_ci format |= NV_PVIDEO_FORMAT_MATRIX_ITURBT709; 1718c2ecf20Sopenharmony_ci if (nv_plane->colorkey & (1 << 24)) 1728c2ecf20Sopenharmony_ci format |= NV_PVIDEO_FORMAT_DISPLAY_COLOR_KEY; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (format & NV_PVIDEO_FORMAT_PLANAR) { 1758c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_UVPLANE_BASE(flip), 0); 1768c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_UVPLANE_OFFSET_BUFF(flip), 1778c2ecf20Sopenharmony_ci nvbo->offset + fb->offsets[1]); 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_FORMAT(flip), format | fb->pitches[0]); 1808c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_STOP, 0); 1818c2ecf20Sopenharmony_ci /* TODO: wait for vblank? */ 1828c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_BUFFER, flip ? 0x10 : 0x1); 1838c2ecf20Sopenharmony_ci nv_plane->flip = !flip; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (cur) 1868c2ecf20Sopenharmony_ci nouveau_bo_unpin(cur); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci return 0; 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic int 1928c2ecf20Sopenharmony_cinv10_disable_plane(struct drm_plane *plane, 1938c2ecf20Sopenharmony_ci struct drm_modeset_acquire_ctx *ctx) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci struct nvif_object *dev = &nouveau_drm(plane->dev)->client.device.object; 1968c2ecf20Sopenharmony_ci struct nouveau_plane *nv_plane = 1978c2ecf20Sopenharmony_ci container_of(plane, struct nouveau_plane, base); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_STOP, 1); 2008c2ecf20Sopenharmony_ci if (nv_plane->cur) { 2018c2ecf20Sopenharmony_ci nouveau_bo_unpin(nv_plane->cur); 2028c2ecf20Sopenharmony_ci nv_plane->cur = NULL; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci return 0; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic void 2098c2ecf20Sopenharmony_cinv_destroy_plane(struct drm_plane *plane) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci drm_plane_force_disable(plane); 2128c2ecf20Sopenharmony_ci drm_plane_cleanup(plane); 2138c2ecf20Sopenharmony_ci kfree(plane); 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic void 2178c2ecf20Sopenharmony_cinv10_set_params(struct nouveau_plane *plane) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci struct nvif_object *dev = &nouveau_drm(plane->base.dev)->client.device.object; 2208c2ecf20Sopenharmony_ci u32 luma = (plane->brightness - 512) << 16 | plane->contrast; 2218c2ecf20Sopenharmony_ci u32 chroma = ((sin_mul(plane->hue, plane->saturation) & 0xffff) << 16) | 2228c2ecf20Sopenharmony_ci (cos_mul(plane->hue, plane->saturation) & 0xffff); 2238c2ecf20Sopenharmony_ci u32 format = 0; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_LUMINANCE(0), luma); 2268c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_LUMINANCE(1), luma); 2278c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_CHROMINANCE(0), chroma); 2288c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_CHROMINANCE(1), chroma); 2298c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_COLOR_KEY, plane->colorkey & 0xffffff); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (plane->cur) { 2328c2ecf20Sopenharmony_ci if (plane->color_encoding == DRM_COLOR_YCBCR_BT709) 2338c2ecf20Sopenharmony_ci format |= NV_PVIDEO_FORMAT_MATRIX_ITURBT709; 2348c2ecf20Sopenharmony_ci if (plane->colorkey & (1 << 24)) 2358c2ecf20Sopenharmony_ci format |= NV_PVIDEO_FORMAT_DISPLAY_COLOR_KEY; 2368c2ecf20Sopenharmony_ci nvif_mask(dev, NV_PVIDEO_FORMAT(plane->flip), 2378c2ecf20Sopenharmony_ci NV_PVIDEO_FORMAT_MATRIX_ITURBT709 | 2388c2ecf20Sopenharmony_ci NV_PVIDEO_FORMAT_DISPLAY_COLOR_KEY, 2398c2ecf20Sopenharmony_ci format); 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic int 2448c2ecf20Sopenharmony_cinv_set_property(struct drm_plane *plane, 2458c2ecf20Sopenharmony_ci struct drm_property *property, 2468c2ecf20Sopenharmony_ci uint64_t value) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci struct nouveau_plane *nv_plane = 2498c2ecf20Sopenharmony_ci container_of(plane, struct nouveau_plane, base); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (property == nv_plane->props.colorkey) 2528c2ecf20Sopenharmony_ci nv_plane->colorkey = value; 2538c2ecf20Sopenharmony_ci else if (property == nv_plane->props.contrast) 2548c2ecf20Sopenharmony_ci nv_plane->contrast = value; 2558c2ecf20Sopenharmony_ci else if (property == nv_plane->props.brightness) 2568c2ecf20Sopenharmony_ci nv_plane->brightness = value; 2578c2ecf20Sopenharmony_ci else if (property == nv_plane->props.hue) 2588c2ecf20Sopenharmony_ci nv_plane->hue = value; 2598c2ecf20Sopenharmony_ci else if (property == nv_plane->props.saturation) 2608c2ecf20Sopenharmony_ci nv_plane->saturation = value; 2618c2ecf20Sopenharmony_ci else if (property == nv_plane->base.color_encoding_property) 2628c2ecf20Sopenharmony_ci nv_plane->color_encoding = value; 2638c2ecf20Sopenharmony_ci else 2648c2ecf20Sopenharmony_ci return -EINVAL; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (nv_plane->set_params) 2678c2ecf20Sopenharmony_ci nv_plane->set_params(nv_plane); 2688c2ecf20Sopenharmony_ci return 0; 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic const struct drm_plane_funcs nv10_plane_funcs = { 2728c2ecf20Sopenharmony_ci .update_plane = nv10_update_plane, 2738c2ecf20Sopenharmony_ci .disable_plane = nv10_disable_plane, 2748c2ecf20Sopenharmony_ci .set_property = nv_set_property, 2758c2ecf20Sopenharmony_ci .destroy = nv_destroy_plane, 2768c2ecf20Sopenharmony_ci}; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic void 2798c2ecf20Sopenharmony_cinv10_overlay_init(struct drm_device *device) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci struct nouveau_drm *drm = nouveau_drm(device); 2828c2ecf20Sopenharmony_ci struct nouveau_plane *plane = kzalloc(sizeof(struct nouveau_plane), GFP_KERNEL); 2838c2ecf20Sopenharmony_ci unsigned int num_formats = ARRAY_SIZE(formats); 2848c2ecf20Sopenharmony_ci int ret; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci if (!plane) 2878c2ecf20Sopenharmony_ci return; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci switch (drm->client.device.info.chipset) { 2908c2ecf20Sopenharmony_ci case 0x10: 2918c2ecf20Sopenharmony_ci case 0x11: 2928c2ecf20Sopenharmony_ci case 0x15: 2938c2ecf20Sopenharmony_ci case 0x1a: 2948c2ecf20Sopenharmony_ci case 0x20: 2958c2ecf20Sopenharmony_ci num_formats = 2; 2968c2ecf20Sopenharmony_ci break; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci ret = drm_plane_init(device, &plane->base, 3 /* both crtc's */, 3008c2ecf20Sopenharmony_ci &nv10_plane_funcs, 3018c2ecf20Sopenharmony_ci formats, num_formats, false); 3028c2ecf20Sopenharmony_ci if (ret) 3038c2ecf20Sopenharmony_ci goto err; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci /* Set up the plane properties */ 3068c2ecf20Sopenharmony_ci plane->props.colorkey = drm_property_create_range( 3078c2ecf20Sopenharmony_ci device, 0, "colorkey", 0, 0x01ffffff); 3088c2ecf20Sopenharmony_ci plane->props.contrast = drm_property_create_range( 3098c2ecf20Sopenharmony_ci device, 0, "contrast", 0, 8192 - 1); 3108c2ecf20Sopenharmony_ci plane->props.brightness = drm_property_create_range( 3118c2ecf20Sopenharmony_ci device, 0, "brightness", 0, 1024); 3128c2ecf20Sopenharmony_ci plane->props.hue = drm_property_create_range( 3138c2ecf20Sopenharmony_ci device, 0, "hue", 0, 359); 3148c2ecf20Sopenharmony_ci plane->props.saturation = drm_property_create_range( 3158c2ecf20Sopenharmony_ci device, 0, "saturation", 0, 8192 - 1); 3168c2ecf20Sopenharmony_ci if (!plane->props.colorkey || 3178c2ecf20Sopenharmony_ci !plane->props.contrast || 3188c2ecf20Sopenharmony_ci !plane->props.brightness || 3198c2ecf20Sopenharmony_ci !plane->props.hue || 3208c2ecf20Sopenharmony_ci !plane->props.saturation) 3218c2ecf20Sopenharmony_ci goto cleanup; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci plane->colorkey = 0; 3248c2ecf20Sopenharmony_ci drm_object_attach_property(&plane->base.base, 3258c2ecf20Sopenharmony_ci plane->props.colorkey, plane->colorkey); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci plane->contrast = 0x1000; 3288c2ecf20Sopenharmony_ci drm_object_attach_property(&plane->base.base, 3298c2ecf20Sopenharmony_ci plane->props.contrast, plane->contrast); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci plane->brightness = 512; 3328c2ecf20Sopenharmony_ci drm_object_attach_property(&plane->base.base, 3338c2ecf20Sopenharmony_ci plane->props.brightness, plane->brightness); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci plane->hue = 0; 3368c2ecf20Sopenharmony_ci drm_object_attach_property(&plane->base.base, 3378c2ecf20Sopenharmony_ci plane->props.hue, plane->hue); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci plane->saturation = 0x1000; 3408c2ecf20Sopenharmony_ci drm_object_attach_property(&plane->base.base, 3418c2ecf20Sopenharmony_ci plane->props.saturation, plane->saturation); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci plane->color_encoding = DRM_COLOR_YCBCR_BT601; 3448c2ecf20Sopenharmony_ci drm_plane_create_color_properties(&plane->base, 3458c2ecf20Sopenharmony_ci BIT(DRM_COLOR_YCBCR_BT601) | 3468c2ecf20Sopenharmony_ci BIT(DRM_COLOR_YCBCR_BT709), 3478c2ecf20Sopenharmony_ci BIT(DRM_COLOR_YCBCR_LIMITED_RANGE), 3488c2ecf20Sopenharmony_ci DRM_COLOR_YCBCR_BT601, 3498c2ecf20Sopenharmony_ci DRM_COLOR_YCBCR_LIMITED_RANGE); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci plane->set_params = nv10_set_params; 3528c2ecf20Sopenharmony_ci nv10_set_params(plane); 3538c2ecf20Sopenharmony_ci drm_plane_force_disable(&plane->base); 3548c2ecf20Sopenharmony_ci return; 3558c2ecf20Sopenharmony_cicleanup: 3568c2ecf20Sopenharmony_ci drm_plane_cleanup(&plane->base); 3578c2ecf20Sopenharmony_cierr: 3588c2ecf20Sopenharmony_ci kfree(plane); 3598c2ecf20Sopenharmony_ci NV_ERROR(drm, "Failed to create plane\n"); 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic int 3638c2ecf20Sopenharmony_cinv04_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, 3648c2ecf20Sopenharmony_ci struct drm_framebuffer *fb, int crtc_x, int crtc_y, 3658c2ecf20Sopenharmony_ci unsigned int crtc_w, unsigned int crtc_h, 3668c2ecf20Sopenharmony_ci uint32_t src_x, uint32_t src_y, 3678c2ecf20Sopenharmony_ci uint32_t src_w, uint32_t src_h, 3688c2ecf20Sopenharmony_ci struct drm_modeset_acquire_ctx *ctx) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci struct nvif_object *dev = &nouveau_drm(plane->dev)->client.device.object; 3718c2ecf20Sopenharmony_ci struct nouveau_plane *nv_plane = 3728c2ecf20Sopenharmony_ci container_of(plane, struct nouveau_plane, base); 3738c2ecf20Sopenharmony_ci struct nouveau_bo *cur = nv_plane->cur; 3748c2ecf20Sopenharmony_ci struct nouveau_bo *nvbo; 3758c2ecf20Sopenharmony_ci uint32_t overlay = 1; 3768c2ecf20Sopenharmony_ci int brightness = (nv_plane->brightness - 512) * 62 / 512; 3778c2ecf20Sopenharmony_ci int ret, i; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci /* Source parameters given in 16.16 fixed point, ignore fractional. */ 3808c2ecf20Sopenharmony_ci src_x >>= 16; 3818c2ecf20Sopenharmony_ci src_y >>= 16; 3828c2ecf20Sopenharmony_ci src_w >>= 16; 3838c2ecf20Sopenharmony_ci src_h >>= 16; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci ret = verify_scaling(fb, 0, src_x, src_y, src_w, src_h, crtc_w, crtc_h); 3868c2ecf20Sopenharmony_ci if (ret) 3878c2ecf20Sopenharmony_ci return ret; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci nvbo = nouveau_gem_object(fb->obj[0]); 3908c2ecf20Sopenharmony_ci ret = nouveau_bo_pin(nvbo, NOUVEAU_GEM_DOMAIN_VRAM, false); 3918c2ecf20Sopenharmony_ci if (ret) 3928c2ecf20Sopenharmony_ci return ret; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci nv_plane->cur = nvbo; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_OE_STATE, 0); 3978c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_SU_STATE, 0); 3988c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_RM_STATE, 0); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 4018c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_BUFF0_START_ADDRESS + 4 * i, 4028c2ecf20Sopenharmony_ci nvbo->offset); 4038c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_BUFF0_PITCH_LENGTH + 4 * i, 4048c2ecf20Sopenharmony_ci fb->pitches[0]); 4058c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_BUFF0_OFFSET + 4 * i, 0); 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_WINDOW_START, crtc_y << 16 | crtc_x); 4088c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_WINDOW_SIZE, crtc_h << 16 | crtc_w); 4098c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_STEP_SIZE, 4108c2ecf20Sopenharmony_ci (uint32_t)(((src_h - 1) << 11) / (crtc_h - 1)) << 16 | (uint32_t)(((src_w - 1) << 11) / (crtc_w - 1))); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci /* It should be possible to convert hue/contrast to this */ 4138c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_RED_CSC_OFFSET, 0x69 - brightness); 4148c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_GREEN_CSC_OFFSET, 0x3e + brightness); 4158c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_BLUE_CSC_OFFSET, 0x89 - brightness); 4168c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_CSC_ADJUST, 0); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_CONTROL_Y, 0x001); /* (BLUR_ON, LINE_HALF) */ 4198c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_CONTROL_X, 0x111); /* (WEIGHT_HEAVY, SHARPENING_ON, SMOOTHING_ON) */ 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_FIFO_BURST_LENGTH, 0x03); 4228c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_FIFO_THRES_SIZE, 0x38); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_KEY, nv_plane->colorkey); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (nv_plane->colorkey & (1 << 24)) 4278c2ecf20Sopenharmony_ci overlay |= 0x10; 4288c2ecf20Sopenharmony_ci if (fb->format->format == DRM_FORMAT_YUYV) 4298c2ecf20Sopenharmony_ci overlay |= 0x100; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_OVERLAY, overlay); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_SU_STATE, nvif_rd32(dev, NV_PVIDEO_SU_STATE) ^ (1 << 16)); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci if (cur) 4368c2ecf20Sopenharmony_ci nouveau_bo_unpin(cur); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci return 0; 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_cistatic int 4428c2ecf20Sopenharmony_cinv04_disable_plane(struct drm_plane *plane, 4438c2ecf20Sopenharmony_ci struct drm_modeset_acquire_ctx *ctx) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci struct nvif_object *dev = &nouveau_drm(plane->dev)->client.device.object; 4468c2ecf20Sopenharmony_ci struct nouveau_plane *nv_plane = 4478c2ecf20Sopenharmony_ci container_of(plane, struct nouveau_plane, base); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci nvif_mask(dev, NV_PVIDEO_OVERLAY, 1, 0); 4508c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_OE_STATE, 0); 4518c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_SU_STATE, 0); 4528c2ecf20Sopenharmony_ci nvif_wr32(dev, NV_PVIDEO_RM_STATE, 0); 4538c2ecf20Sopenharmony_ci if (nv_plane->cur) { 4548c2ecf20Sopenharmony_ci nouveau_bo_unpin(nv_plane->cur); 4558c2ecf20Sopenharmony_ci nv_plane->cur = NULL; 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci return 0; 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic const struct drm_plane_funcs nv04_plane_funcs = { 4628c2ecf20Sopenharmony_ci .update_plane = nv04_update_plane, 4638c2ecf20Sopenharmony_ci .disable_plane = nv04_disable_plane, 4648c2ecf20Sopenharmony_ci .set_property = nv_set_property, 4658c2ecf20Sopenharmony_ci .destroy = nv_destroy_plane, 4668c2ecf20Sopenharmony_ci}; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cistatic void 4698c2ecf20Sopenharmony_cinv04_overlay_init(struct drm_device *device) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci struct nouveau_drm *drm = nouveau_drm(device); 4728c2ecf20Sopenharmony_ci struct nouveau_plane *plane = kzalloc(sizeof(struct nouveau_plane), GFP_KERNEL); 4738c2ecf20Sopenharmony_ci int ret; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci if (!plane) 4768c2ecf20Sopenharmony_ci return; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci ret = drm_plane_init(device, &plane->base, 1 /* single crtc */, 4798c2ecf20Sopenharmony_ci &nv04_plane_funcs, 4808c2ecf20Sopenharmony_ci formats, 2, false); 4818c2ecf20Sopenharmony_ci if (ret) 4828c2ecf20Sopenharmony_ci goto err; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci /* Set up the plane properties */ 4858c2ecf20Sopenharmony_ci plane->props.colorkey = drm_property_create_range( 4868c2ecf20Sopenharmony_ci device, 0, "colorkey", 0, 0x01ffffff); 4878c2ecf20Sopenharmony_ci plane->props.brightness = drm_property_create_range( 4888c2ecf20Sopenharmony_ci device, 0, "brightness", 0, 1024); 4898c2ecf20Sopenharmony_ci if (!plane->props.colorkey || 4908c2ecf20Sopenharmony_ci !plane->props.brightness) 4918c2ecf20Sopenharmony_ci goto cleanup; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci plane->colorkey = 0; 4948c2ecf20Sopenharmony_ci drm_object_attach_property(&plane->base.base, 4958c2ecf20Sopenharmony_ci plane->props.colorkey, plane->colorkey); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci plane->brightness = 512; 4988c2ecf20Sopenharmony_ci drm_object_attach_property(&plane->base.base, 4998c2ecf20Sopenharmony_ci plane->props.brightness, plane->brightness); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci drm_plane_force_disable(&plane->base); 5028c2ecf20Sopenharmony_ci return; 5038c2ecf20Sopenharmony_cicleanup: 5048c2ecf20Sopenharmony_ci drm_plane_cleanup(&plane->base); 5058c2ecf20Sopenharmony_cierr: 5068c2ecf20Sopenharmony_ci kfree(plane); 5078c2ecf20Sopenharmony_ci NV_ERROR(drm, "Failed to create plane\n"); 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_civoid 5118c2ecf20Sopenharmony_cinouveau_overlay_init(struct drm_device *device) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci struct nvif_device *dev = &nouveau_drm(device)->client.device; 5148c2ecf20Sopenharmony_ci if (dev->info.chipset < 0x10) 5158c2ecf20Sopenharmony_ci nv04_overlay_init(device); 5168c2ecf20Sopenharmony_ci else if (dev->info.chipset <= 0x40) 5178c2ecf20Sopenharmony_ci nv10_overlay_init(device); 5188c2ecf20Sopenharmony_ci} 519