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 <drm/drm_plane_helper.h> 27 #include <nouveau_bo.h> 28 29 #include <nvif/pushc37b.h> 30 31 #include <nvhw/class/clc57e.h> 32 33 static int 34 wndwc57e_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) 35 { 36 struct nvif_push *push = wndw->wndw.push; 37 int ret; 38 39 if ((ret = PUSH_WAIT(push, 17))) 40 return ret; 41 42 PUSH_MTHD(push, NVC57E, SET_PRESENT_CONTROL, 43 NVVAL(NVC57E, SET_PRESENT_CONTROL, MIN_PRESENT_INTERVAL, asyw->image.interval) | 44 NVVAL(NVC57E, SET_PRESENT_CONTROL, BEGIN_MODE, asyw->image.mode) | 45 NVDEF(NVC57E, SET_PRESENT_CONTROL, TIMESTAMP_MODE, DISABLE)); 46 47 PUSH_MTHD(push, NVC57E, SET_SIZE, 48 NVVAL(NVC57E, SET_SIZE, WIDTH, asyw->image.w) | 49 NVVAL(NVC57E, SET_SIZE, HEIGHT, asyw->image.h), 50 51 SET_STORAGE, 52 NVVAL(NVC57E, SET_STORAGE, BLOCK_HEIGHT, asyw->image.blockh) | 53 NVVAL(NVC57E, SET_STORAGE, MEMORY_LAYOUT, asyw->image.layout), 54 55 SET_PARAMS, 56 NVVAL(NVC57E, SET_PARAMS, FORMAT, asyw->image.format) | 57 NVDEF(NVC57E, SET_PARAMS, CLAMP_BEFORE_BLEND, DISABLE) | 58 NVDEF(NVC57E, SET_PARAMS, SWAP_UV, DISABLE) | 59 NVDEF(NVC57E, SET_PARAMS, FMT_ROUNDING_MODE, ROUND_TO_NEAREST), 60 61 SET_PLANAR_STORAGE(0), 62 NVVAL(NVC57E, SET_PLANAR_STORAGE, PITCH, asyw->image.blocks[0]) | 63 NVVAL(NVC57E, SET_PLANAR_STORAGE, PITCH, asyw->image.pitch[0] >> 6)); 64 65 PUSH_MTHD(push, NVC57E, SET_CONTEXT_DMA_ISO(0), asyw->image.handle, 1); 66 PUSH_MTHD(push, NVC57E, SET_OFFSET(0), asyw->image.offset[0] >> 8); 67 68 PUSH_MTHD(push, NVC57E, SET_POINT_IN(0), 69 NVVAL(NVC57E, SET_POINT_IN, X, asyw->state.src_x >> 16) | 70 NVVAL(NVC57E, SET_POINT_IN, Y, asyw->state.src_y >> 16)); 71 72 PUSH_MTHD(push, NVC57E, SET_SIZE_IN, 73 NVVAL(NVC57E, SET_SIZE_IN, WIDTH, asyw->state.src_w >> 16) | 74 NVVAL(NVC57E, SET_SIZE_IN, HEIGHT, asyw->state.src_h >> 16)); 75 76 PUSH_MTHD(push, NVC57E, SET_SIZE_OUT, 77 NVVAL(NVC57E, SET_SIZE_OUT, WIDTH, asyw->state.crtc_w) | 78 NVVAL(NVC57E, SET_SIZE_OUT, HEIGHT, asyw->state.crtc_h)); 79 return 0; 80 } 81 82 int 83 wndwc57e_csc_clr(struct nv50_wndw *wndw) 84 { 85 struct nvif_push *push = wndw->wndw.push; 86 const u32 identity[12] = { 87 0x00010000, 0x00000000, 0x00000000, 0x00000000, 88 0x00000000, 0x00010000, 0x00000000, 0x00000000, 89 0x00000000, 0x00000000, 0x00010000, 0x00000000, 90 }; 91 int ret; 92 93 if ((ret = PUSH_WAIT(push, 1 + ARRAY_SIZE(identity)))) 94 return ret; 95 96 PUSH_MTHD(push, NVC57E, SET_FMT_COEFFICIENT_C00, identity, ARRAY_SIZE(identity)); 97 return 0; 98 } 99 100 int 101 wndwc57e_csc_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) 102 { 103 struct nvif_push *push = wndw->wndw.push; 104 int ret; 105 106 if ((ret = PUSH_WAIT(push, 13))) 107 return ret; 108 109 PUSH_MTHD(push, NVC57E, SET_FMT_COEFFICIENT_C00, asyw->csc.matrix, 12); 110 return 0; 111 } 112 113 int 114 wndwc57e_ilut_clr(struct nv50_wndw *wndw) 115 { 116 struct nvif_push *push = wndw->wndw.push; 117 int ret; 118 119 if ((ret = PUSH_WAIT(push, 2))) 120 return ret; 121 122 PUSH_MTHD(push, NVC57E, SET_CONTEXT_DMA_ILUT, 0x00000000); 123 return 0; 124 } 125 126 int 127 wndwc57e_ilut_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) 128 { 129 struct nvif_push *push = wndw->wndw.push; 130 int ret; 131 132 if ((ret = PUSH_WAIT(push, 4))) 133 return ret; 134 135 PUSH_MTHD(push, NVC57E, SET_ILUT_CONTROL, 136 NVVAL(NVC57E, SET_ILUT_CONTROL, SIZE, asyw->xlut.i.size) | 137 NVVAL(NVC57E, SET_ILUT_CONTROL, MODE, asyw->xlut.i.mode) | 138 NVVAL(NVC57E, SET_ILUT_CONTROL, INTERPOLATE, asyw->xlut.i.output_mode), 139 140 SET_CONTEXT_DMA_ILUT, asyw->xlut.handle, 141 SET_OFFSET_ILUT, asyw->xlut.i.offset >> 8); 142 return 0; 143 } 144 145 static u16 146 fixedU0_16_FP16(u16 fixed) 147 { 148 int sign = 0, exp = 0, man = 0; 149 if (fixed) { 150 while (--exp && !(fixed & 0x8000)) 151 fixed <<= 1; 152 man = ((fixed << 1) & 0xffc0) >> 6; 153 exp += 15; 154 } 155 return (sign << 15) | (exp << 10) | man; 156 } 157 158 static void 159 wndwc57e_ilut_load(struct drm_color_lut *in, int size, void __iomem *mem) 160 { 161 memset_io(mem, 0x00, 0x20); /* VSS header. */ 162 mem += 0x20; 163 164 for (; size--; in++, mem += 0x08) { 165 u16 r = fixedU0_16_FP16(drm_color_lut_extract(in-> red, 16)); 166 u16 g = fixedU0_16_FP16(drm_color_lut_extract(in->green, 16)); 167 u16 b = fixedU0_16_FP16(drm_color_lut_extract(in-> blue, 16)); 168 writew(r, mem + 0); 169 writew(g, mem + 2); 170 writew(b, mem + 4); 171 } 172 173 /* INTERPOLATE modes require a "next" entry to interpolate with, 174 * so we replicate the last entry to deal with this for now. 175 */ 176 writew(readw(mem - 8), mem + 0); 177 writew(readw(mem - 6), mem + 2); 178 writew(readw(mem - 4), mem + 4); 179 } 180 181 void 182 wndwc57e_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, int size) 183 { 184 if (!size) 185 size = 1024; 186 187 if (size == 256) 188 asyw->xlut.i.mode = NVC57E_SET_ILUT_CONTROL_MODE_DIRECT8; 189 else 190 asyw->xlut.i.mode = NVC57E_SET_ILUT_CONTROL_MODE_DIRECT10; 191 192 asyw->xlut.i.size = 4 /* VSS header. */ + size + 1 /* Entries. */; 193 asyw->xlut.i.output_mode = NVC57E_SET_ILUT_CONTROL_INTERPOLATE_DISABLE; 194 asyw->xlut.i.load = wndwc57e_ilut_load; 195 } 196 197 /**************************************************************** 198 * Log2(block height) ----------------------------+ * 199 * Page Kind ----------------------------------+ | * 200 * Gob Height/Page Kind Generation ------+ | | * 201 * Sector layout -------+ | | | * 202 * Compression ------+ | | | | */ 203 const u64 wndwc57e_modifiers[] = { /* | | | | | */ 204 DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 2, 0x06, 0), 205 DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 2, 0x06, 1), 206 DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 2, 0x06, 2), 207 DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 2, 0x06, 3), 208 DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 2, 0x06, 4), 209 DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 2, 0x06, 5), 210 DRM_FORMAT_MOD_LINEAR, 211 DRM_FORMAT_MOD_INVALID 212 }; 213 214 static const struct nv50_wndw_func 215 wndwc57e = { 216 .acquire = wndwc37e_acquire, 217 .release = wndwc37e_release, 218 .sema_set = wndwc37e_sema_set, 219 .sema_clr = wndwc37e_sema_clr, 220 .ntfy_set = wndwc37e_ntfy_set, 221 .ntfy_clr = wndwc37e_ntfy_clr, 222 .ntfy_reset = corec37d_ntfy_init, 223 .ntfy_wait_begun = base507c_ntfy_wait_begun, 224 .ilut = wndwc57e_ilut, 225 .ilut_identity = true, 226 .ilut_size = 1024, 227 .xlut_set = wndwc57e_ilut_set, 228 .xlut_clr = wndwc57e_ilut_clr, 229 .csc = base907c_csc, 230 .csc_set = wndwc57e_csc_set, 231 .csc_clr = wndwc57e_csc_clr, 232 .image_set = wndwc57e_image_set, 233 .image_clr = wndwc37e_image_clr, 234 .blend_set = wndwc37e_blend_set, 235 .update = wndwc37e_update, 236 }; 237 238 int 239 wndwc57e_new(struct nouveau_drm *drm, enum drm_plane_type type, int index, 240 s32 oclass, struct nv50_wndw **pwndw) 241 { 242 return wndwc37e_new_(&wndwc57e, drm, type, index, oclass, 243 BIT(index >> 1), pwndw); 244 } 245