1 /* 2 * Copyright 2018 Red Hat Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 */ 22 #include "wndw.h" 23 #include "atom.h" 24 25 #include <drm/drm_atomic_helper.h> 26 #include <nouveau_bo.h> 27 28 #include <nvif/pushc37b.h> 29 30 #include <nvhw/class/clc57e.h> 31 32 static int 33 wndwc57e_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) 34 { 35 struct nvif_push *push = &wndw->wndw.push; 36 int ret; 37 38 if ((ret = PUSH_WAIT(push, 17))) 39 return ret; 40 41 PUSH_MTHD(push, NVC57E, SET_PRESENT_CONTROL, 42 NVVAL(NVC57E, SET_PRESENT_CONTROL, MIN_PRESENT_INTERVAL, asyw->image.interval) | 43 NVVAL(NVC57E, SET_PRESENT_CONTROL, BEGIN_MODE, asyw->image.mode) | 44 NVDEF(NVC57E, SET_PRESENT_CONTROL, TIMESTAMP_MODE, DISABLE)); 45 46 PUSH_MTHD(push, NVC57E, SET_SIZE, 47 NVVAL(NVC57E, SET_SIZE, WIDTH, asyw->image.w) | 48 NVVAL(NVC57E, SET_SIZE, HEIGHT, asyw->image.h), 49 50 SET_STORAGE, 51 NVVAL(NVC57E, SET_STORAGE, BLOCK_HEIGHT, asyw->image.blockh) | 52 NVVAL(NVC57E, SET_STORAGE, MEMORY_LAYOUT, asyw->image.layout), 53 54 SET_PARAMS, 55 NVVAL(NVC57E, SET_PARAMS, FORMAT, asyw->image.format) | 56 NVDEF(NVC57E, SET_PARAMS, CLAMP_BEFORE_BLEND, DISABLE) | 57 NVDEF(NVC57E, SET_PARAMS, SWAP_UV, DISABLE) | 58 NVDEF(NVC57E, SET_PARAMS, FMT_ROUNDING_MODE, ROUND_TO_NEAREST), 59 60 SET_PLANAR_STORAGE(0), 61 NVVAL(NVC57E, SET_PLANAR_STORAGE, PITCH, asyw->image.blocks[0]) | 62 NVVAL(NVC57E, SET_PLANAR_STORAGE, PITCH, asyw->image.pitch[0] >> 6)); 63 64 PUSH_MTHD(push, NVC57E, SET_CONTEXT_DMA_ISO(0), asyw->image.handle, 1); 65 PUSH_MTHD(push, NVC57E, SET_OFFSET(0), asyw->image.offset[0] >> 8); 66 67 PUSH_MTHD(push, NVC57E, SET_POINT_IN(0), 68 NVVAL(NVC57E, SET_POINT_IN, X, asyw->state.src_x >> 16) | 69 NVVAL(NVC57E, SET_POINT_IN, Y, asyw->state.src_y >> 16)); 70 71 PUSH_MTHD(push, NVC57E, SET_SIZE_IN, 72 NVVAL(NVC57E, SET_SIZE_IN, WIDTH, asyw->state.src_w >> 16) | 73 NVVAL(NVC57E, SET_SIZE_IN, HEIGHT, asyw->state.src_h >> 16)); 74 75 PUSH_MTHD(push, NVC57E, SET_SIZE_OUT, 76 NVVAL(NVC57E, SET_SIZE_OUT, WIDTH, asyw->state.crtc_w) | 77 NVVAL(NVC57E, SET_SIZE_OUT, HEIGHT, asyw->state.crtc_h)); 78 return 0; 79 } 80 81 int 82 wndwc57e_csc_clr(struct nv50_wndw *wndw) 83 { 84 struct nvif_push *push = &wndw->wndw.push; 85 const u32 identity[12] = { 86 0x00010000, 0x00000000, 0x00000000, 0x00000000, 87 0x00000000, 0x00010000, 0x00000000, 0x00000000, 88 0x00000000, 0x00000000, 0x00010000, 0x00000000, 89 }; 90 int ret; 91 92 if ((ret = PUSH_WAIT(push, 1 + ARRAY_SIZE(identity)))) 93 return ret; 94 95 PUSH_MTHD(push, NVC57E, SET_FMT_COEFFICIENT_C00, identity, ARRAY_SIZE(identity)); 96 return 0; 97 } 98 99 int 100 wndwc57e_csc_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) 101 { 102 struct nvif_push *push = &wndw->wndw.push; 103 int ret; 104 105 if ((ret = PUSH_WAIT(push, 13))) 106 return ret; 107 108 PUSH_MTHD(push, NVC57E, SET_FMT_COEFFICIENT_C00, asyw->csc.matrix, 12); 109 return 0; 110 } 111 112 int 113 wndwc57e_ilut_clr(struct nv50_wndw *wndw) 114 { 115 struct nvif_push *push = &wndw->wndw.push; 116 int ret; 117 118 if ((ret = PUSH_WAIT(push, 2))) 119 return ret; 120 121 PUSH_MTHD(push, NVC57E, SET_CONTEXT_DMA_ILUT, 0x00000000); 122 return 0; 123 } 124 125 int 126 wndwc57e_ilut_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) 127 { 128 struct nvif_push *push = &wndw->wndw.push; 129 int ret; 130 131 if ((ret = PUSH_WAIT(push, 4))) 132 return ret; 133 134 PUSH_MTHD(push, NVC57E, SET_ILUT_CONTROL, 135 NVVAL(NVC57E, SET_ILUT_CONTROL, SIZE, asyw->xlut.i.size) | 136 NVVAL(NVC57E, SET_ILUT_CONTROL, MODE, asyw->xlut.i.mode) | 137 NVVAL(NVC57E, SET_ILUT_CONTROL, INTERPOLATE, asyw->xlut.i.output_mode), 138 139 SET_CONTEXT_DMA_ILUT, asyw->xlut.handle, 140 SET_OFFSET_ILUT, asyw->xlut.i.offset >> 8); 141 return 0; 142 } 143 144 static u16 145 fixedU0_16_FP16(u16 fixed) 146 { 147 int sign = 0, exp = 0, man = 0; 148 if (fixed) { 149 while (--exp && !(fixed & 0x8000)) 150 fixed <<= 1; 151 man = ((fixed << 1) & 0xffc0) >> 6; 152 exp += 15; 153 } 154 return (sign << 15) | (exp << 10) | man; 155 } 156 157 static void 158 wndwc57e_ilut_load(struct drm_color_lut *in, int size, void __iomem *mem) 159 { 160 memset_io(mem, 0x00, 0x20); /* VSS header. */ 161 mem += 0x20; 162 163 for (; size--; in++, mem += 0x08) { 164 u16 r = fixedU0_16_FP16(drm_color_lut_extract(in-> red, 16)); 165 u16 g = fixedU0_16_FP16(drm_color_lut_extract(in->green, 16)); 166 u16 b = fixedU0_16_FP16(drm_color_lut_extract(in-> blue, 16)); 167 writew(r, mem + 0); 168 writew(g, mem + 2); 169 writew(b, mem + 4); 170 } 171 172 /* INTERPOLATE modes require a "next" entry to interpolate with, 173 * so we replicate the last entry to deal with this for now. 174 */ 175 writew(readw(mem - 8), mem + 0); 176 writew(readw(mem - 6), mem + 2); 177 writew(readw(mem - 4), mem + 4); 178 } 179 180 void 181 wndwc57e_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, int size) 182 { 183 if (!size) 184 size = 1024; 185 186 if (size == 256) 187 asyw->xlut.i.mode = NVC57E_SET_ILUT_CONTROL_MODE_DIRECT8; 188 else 189 asyw->xlut.i.mode = NVC57E_SET_ILUT_CONTROL_MODE_DIRECT10; 190 191 asyw->xlut.i.size = 4 /* VSS header. */ + size + 1 /* Entries. */; 192 asyw->xlut.i.output_mode = NVC57E_SET_ILUT_CONTROL_INTERPOLATE_DISABLE; 193 asyw->xlut.i.load = wndwc57e_ilut_load; 194 } 195 196 /**************************************************************** 197 * Log2(block height) ----------------------------+ * 198 * Page Kind ----------------------------------+ | * 199 * Gob Height/Page Kind Generation ------+ | | * 200 * Sector layout -------+ | | | * 201 * Compression ------+ | | | | */ 202 const u64 wndwc57e_modifiers[] = { /* | | | | | */ 203 DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 2, 0x06, 0), 204 DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 2, 0x06, 1), 205 DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 2, 0x06, 2), 206 DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 2, 0x06, 3), 207 DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 2, 0x06, 4), 208 DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 2, 0x06, 5), 209 DRM_FORMAT_MOD_LINEAR, 210 DRM_FORMAT_MOD_INVALID 211 }; 212 213 static const struct nv50_wndw_func 214 wndwc57e = { 215 .acquire = wndwc37e_acquire, 216 .release = wndwc37e_release, 217 .sema_set = wndwc37e_sema_set, 218 .sema_clr = wndwc37e_sema_clr, 219 .ntfy_set = wndwc37e_ntfy_set, 220 .ntfy_clr = wndwc37e_ntfy_clr, 221 .ntfy_reset = corec37d_ntfy_init, 222 .ntfy_wait_begun = base507c_ntfy_wait_begun, 223 .ilut = wndwc57e_ilut, 224 .ilut_identity = true, 225 .ilut_size = 1024, 226 .xlut_set = wndwc57e_ilut_set, 227 .xlut_clr = wndwc57e_ilut_clr, 228 .csc = base907c_csc, 229 .csc_set = wndwc57e_csc_set, 230 .csc_clr = wndwc57e_csc_clr, 231 .image_set = wndwc57e_image_set, 232 .image_clr = wndwc37e_image_clr, 233 .blend_set = wndwc37e_blend_set, 234 .update = wndwc37e_update, 235 }; 236 237 int 238 wndwc57e_new(struct nouveau_drm *drm, enum drm_plane_type type, int index, 239 s32 oclass, struct nv50_wndw **pwndw) 240 { 241 return wndwc37e_new_(&wndwc57e, drm, type, index, oclass, 242 BIT(index >> 1), pwndw); 243 } 244