1 /* $NetBSD: nouveau_dispnv50_wndwc57e.c,v 1.3 2021/12/19 10:49:47 riastradh Exp $ */ 2 3 /* 4 * Copyright 2018 Red Hat Inc. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 #include <sys/cdefs.h> 25 __KERNEL_RCSID(0, "$NetBSD: nouveau_dispnv50_wndwc57e.c,v 1.3 2021/12/19 10:49:47 riastradh Exp $"); 26 27 #include "wndw.h" 28 #include "atom.h" 29 30 #include <drm/drm_atomic_helper.h> 31 #include <drm/drm_plane_helper.h> 32 #include <nouveau_bo.h> 33 34 #include <nvif/clc37e.h> 35 36 static void 37 wndwc57e_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) 38 { 39 u32 *push; 40 41 if (!(push = evo_wait(&wndw->wndw, 17))) 42 return; 43 44 evo_mthd(push, 0x0308, 1); 45 evo_data(push, asyw->image.mode << 4 | asyw->image.interval); 46 evo_mthd(push, 0x0224, 4); 47 evo_data(push, asyw->image.h << 16 | asyw->image.w); 48 evo_data(push, asyw->image.layout << 4 | asyw->image.blockh); 49 evo_data(push, asyw->image.colorspace << 8 | 50 asyw->image.format); 51 evo_data(push, asyw->image.blocks[0] | (asyw->image.pitch[0] >> 6)); 52 evo_mthd(push, 0x0240, 1); 53 evo_data(push, asyw->image.handle[0]); 54 evo_mthd(push, 0x0260, 1); 55 evo_data(push, asyw->image.offset[0] >> 8); 56 evo_mthd(push, 0x0290, 1); 57 evo_data(push, (asyw->state.src_y >> 16) << 16 | 58 (asyw->state.src_x >> 16)); 59 evo_mthd(push, 0x0298, 1); 60 evo_data(push, (asyw->state.src_h >> 16) << 16 | 61 (asyw->state.src_w >> 16)); 62 evo_mthd(push, 0x02a4, 1); 63 evo_data(push, asyw->state.crtc_h << 16 | 64 asyw->state.crtc_w); 65 evo_kick(push, &wndw->wndw); 66 } 67 68 static void 69 wndwc57e_csc_clr(struct nv50_wndw *wndw) 70 { 71 u32 *push; 72 if ((push = evo_wait(&wndw->wndw, 13))) { 73 evo_mthd(push, 0x0400, 12); 74 evo_data(push, 0x00010000); 75 evo_data(push, 0x00000000); 76 evo_data(push, 0x00000000); 77 evo_data(push, 0x00000000); 78 evo_data(push, 0x00000000); 79 evo_data(push, 0x00010000); 80 evo_data(push, 0x00000000); 81 evo_data(push, 0x00000000); 82 evo_data(push, 0x00000000); 83 evo_data(push, 0x00000000); 84 evo_data(push, 0x00010000); 85 evo_data(push, 0x00000000); 86 evo_kick(push, &wndw->wndw); 87 } 88 } 89 90 static void 91 wndwc57e_csc_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) 92 { 93 u32 *push, i; 94 if ((push = evo_wait(&wndw->wndw, 13))) { 95 evo_mthd(push, 0x0400, 12); 96 for (i = 0; i < 12; i++) 97 evo_data(push, asyw->csc.matrix[i]); 98 evo_kick(push, &wndw->wndw); 99 } 100 } 101 102 static void 103 wndwc57e_ilut_clr(struct nv50_wndw *wndw) 104 { 105 u32 *push; 106 if ((push = evo_wait(&wndw->wndw, 2))) { 107 evo_mthd(push, 0x0444, 1); 108 evo_data(push, 0x00000000); 109 evo_kick(push, &wndw->wndw); 110 } 111 } 112 113 static void 114 wndwc57e_ilut_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) 115 { 116 u32 *push; 117 if ((push = evo_wait(&wndw->wndw, 4))) { 118 evo_mthd(push, 0x0440, 3); 119 evo_data(push, asyw->xlut.i.size << 8 | 120 asyw->xlut.i.mode << 2 | 121 asyw->xlut.i.output_mode); 122 evo_data(push, asyw->xlut.handle); 123 evo_data(push, asyw->xlut.i.offset >> 8); 124 evo_kick(push, &wndw->wndw); 125 } 126 } 127 128 static u16 129 fixedU0_16_FP16(u16 fixed) 130 { 131 int sign = 0, exp = 0, man = 0; 132 if (fixed) { 133 while (--exp && !(fixed & 0x8000)) 134 fixed <<= 1; 135 man = ((fixed << 1) & 0xffc0) >> 6; 136 exp += 15; 137 } 138 return (sign << 15) | (exp << 10) | man; 139 } 140 141 #ifdef __NetBSD__ 142 #define __iomem __lut_iomem 143 #define readw(p) atomic_load_relaxed((const __iomem uint16_t *)(p)) 144 #define writew(v,p) atomic_store_relaxed((__iomem uint16_t *)(p), (v)) 145 #endif 146 147 static void 148 wndwc57e_ilut_load(struct drm_color_lut *in, int size, void __iomem *mem) 149 { 150 memset_io(mem, 0x00, 0x20); /* VSS header. */ 151 mem += 0x20; 152 153 for (; size--; in++, mem += 0x08) { 154 u16 r = fixedU0_16_FP16(drm_color_lut_extract(in-> red, 16)); 155 u16 g = fixedU0_16_FP16(drm_color_lut_extract(in->green, 16)); 156 u16 b = fixedU0_16_FP16(drm_color_lut_extract(in-> blue, 16)); 157 writew(r, mem + 0); 158 writew(g, mem + 2); 159 writew(b, mem + 4); 160 } 161 162 /* INTERPOLATE modes require a "next" entry to interpolate with, 163 * so we replicate the last entry to deal with this for now. 164 */ 165 writew(readw(mem - 8), mem + 0); 166 writew(readw(mem - 6), mem + 2); 167 writew(readw(mem - 4), mem + 4); 168 } 169 170 static bool 171 wndwc57e_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, int size) 172 { 173 if (size = size ? size : 1024, size != 256 && size != 1024) 174 return false; 175 176 if (size == 256) { 177 asyw->xlut.i.mode = 1; /* DIRECT8. */ 178 } else { 179 asyw->xlut.i.mode = 2; /* DIRECT10. */ 180 } 181 asyw->xlut.i.size = 4 /* VSS header. */ + size + 1 /* Entries. */; 182 asyw->xlut.i.output_mode = 0; /* INTERPOLATE_DISABLE. */ 183 asyw->xlut.i.load = wndwc57e_ilut_load; 184 return true; 185 } 186 187 static const struct nv50_wndw_func 188 wndwc57e = { 189 .acquire = wndwc37e_acquire, 190 .release = wndwc37e_release, 191 .sema_set = wndwc37e_sema_set, 192 .sema_clr = wndwc37e_sema_clr, 193 .ntfy_set = wndwc37e_ntfy_set, 194 .ntfy_clr = wndwc37e_ntfy_clr, 195 .ntfy_reset = corec37d_ntfy_init, 196 .ntfy_wait_begun = base507c_ntfy_wait_begun, 197 .ilut = wndwc57e_ilut, 198 .ilut_identity = true, 199 .ilut_size = 1024, 200 .xlut_set = wndwc57e_ilut_set, 201 .xlut_clr = wndwc57e_ilut_clr, 202 .csc = base907c_csc, 203 .csc_set = wndwc57e_csc_set, 204 .csc_clr = wndwc57e_csc_clr, 205 .image_set = wndwc57e_image_set, 206 .image_clr = wndwc37e_image_clr, 207 .blend_set = wndwc37e_blend_set, 208 .update = wndwc37e_update, 209 }; 210 211 int 212 wndwc57e_new(struct nouveau_drm *drm, enum drm_plane_type type, int index, 213 s32 oclass, struct nv50_wndw **pwndw) 214 { 215 return wndwc37e_new_(&wndwc57e, drm, type, index, oclass, 216 BIT(index >> 1), pwndw); 217 } 218