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 "head.h" 23 #include "core.h" 24 25 void 26 head507d_procamp(struct nv50_head *head, struct nv50_head_atom *asyh) 27 { 28 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 29 u32 *push; 30 if ((push = evo_wait(core, 2))) { 31 evo_mthd(push, 0x08a8 + (head->base.index * 0x400), 1); 32 evo_data(push, asyh->procamp.sat.sin << 20 | 33 asyh->procamp.sat.cos << 8); 34 evo_kick(push, core); 35 } 36 } 37 38 void 39 head507d_dither(struct nv50_head *head, struct nv50_head_atom *asyh) 40 { 41 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 42 u32 *push; 43 if ((push = evo_wait(core, 2))) { 44 evo_mthd(push, 0x08a0 + (head->base.index * 0x0400), 1); 45 evo_data(push, asyh->dither.mode << 3 | 46 asyh->dither.bits << 1 | 47 asyh->dither.enable); 48 evo_kick(push, core); 49 } 50 } 51 52 void 53 head507d_ovly(struct nv50_head *head, struct nv50_head_atom *asyh) 54 { 55 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 56 u32 bounds = 0; 57 u32 *push; 58 59 if (asyh->ovly.cpp) { 60 switch (asyh->ovly.cpp) { 61 case 4: bounds |= 0x00000300; break; 62 case 2: bounds |= 0x00000100; break; 63 default: 64 WARN_ON(1); 65 break; 66 } 67 bounds |= 0x00000001; 68 } else { 69 bounds |= 0x00000100; 70 } 71 72 if ((push = evo_wait(core, 2))) { 73 evo_mthd(push, 0x0904 + head->base.index * 0x400, 1); 74 evo_data(push, bounds); 75 evo_kick(push, core); 76 } 77 } 78 79 void 80 head507d_base(struct nv50_head *head, struct nv50_head_atom *asyh) 81 { 82 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 83 u32 bounds = 0; 84 u32 *push; 85 86 if (asyh->base.cpp) { 87 switch (asyh->base.cpp) { 88 case 8: bounds |= 0x00000500; break; 89 case 4: bounds |= 0x00000300; break; 90 case 2: bounds |= 0x00000100; break; 91 case 1: bounds |= 0x00000000; break; 92 default: 93 WARN_ON(1); 94 break; 95 } 96 bounds |= 0x00000001; 97 } 98 99 if ((push = evo_wait(core, 2))) { 100 evo_mthd(push, 0x0900 + head->base.index * 0x400, 1); 101 evo_data(push, bounds); 102 evo_kick(push, core); 103 } 104 } 105 106 static void 107 head507d_curs_clr(struct nv50_head *head) 108 { 109 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 110 u32 *push; 111 if ((push = evo_wait(core, 2))) { 112 evo_mthd(push, 0x0880 + head->base.index * 0x400, 1); 113 evo_data(push, 0x05000000); 114 evo_kick(push, core); 115 } 116 } 117 118 static void 119 head507d_curs_set(struct nv50_head *head, struct nv50_head_atom *asyh) 120 { 121 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 122 u32 *push; 123 if ((push = evo_wait(core, 3))) { 124 evo_mthd(push, 0x0880 + head->base.index * 0x400, 2); 125 evo_data(push, 0x80000000 | asyh->curs.layout << 26 | 126 asyh->curs.format << 24); 127 evo_data(push, asyh->curs.offset >> 8); 128 evo_kick(push, core); 129 } 130 } 131 132 int 133 head507d_curs_format(struct nv50_head *head, struct nv50_wndw_atom *asyw, 134 struct nv50_head_atom *asyh) 135 { 136 switch (asyw->image.format) { 137 case 0xcf: asyh->curs.format = 1; break; 138 default: 139 WARN_ON(1); 140 return -EINVAL; 141 } 142 return 0; 143 } 144 145 int 146 head507d_curs_layout(struct nv50_head *head, struct nv50_wndw_atom *asyw, 147 struct nv50_head_atom *asyh) 148 { 149 switch (asyw->image.w) { 150 case 32: asyh->curs.layout = 0; break; 151 case 64: asyh->curs.layout = 1; break; 152 default: 153 return -EINVAL; 154 } 155 return 0; 156 } 157 158 void 159 head507d_core_clr(struct nv50_head *head) 160 { 161 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 162 u32 *push; 163 if ((push = evo_wait(core, 2))) { 164 evo_mthd(push, 0x0874 + head->base.index * 0x400, 1); 165 evo_data(push, 0x00000000); 166 evo_kick(push, core); 167 } 168 } 169 170 static void 171 head507d_core_set(struct nv50_head *head, struct nv50_head_atom *asyh) 172 { 173 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 174 u32 *push; 175 if ((push = evo_wait(core, 9))) { 176 evo_mthd(push, 0x0860 + head->base.index * 0x400, 1); 177 evo_data(push, asyh->core.offset >> 8); 178 evo_mthd(push, 0x0868 + head->base.index * 0x400, 4); 179 evo_data(push, asyh->core.h << 16 | asyh->core.w); 180 evo_data(push, asyh->core.layout << 20 | 181 (asyh->core.pitch >> 8) << 8 | 182 asyh->core.blocks << 8 | 183 asyh->core.blockh); 184 evo_data(push, asyh->core.kind << 16 | 185 asyh->core.format << 8); 186 evo_data(push, asyh->core.handle); 187 evo_mthd(push, 0x08c0 + head->base.index * 0x400, 1); 188 evo_data(push, asyh->core.y << 16 | asyh->core.x); 189 evo_kick(push, core); 190 191 /* EVO will complain with INVALID_STATE if we have an 192 * active cursor and (re)specify HeadSetContextDmaIso 193 * without also updating HeadSetOffsetCursor. 194 */ 195 asyh->set.curs = asyh->curs.visible; 196 asyh->set.olut = asyh->olut.handle != 0; 197 } 198 } 199 200 void 201 head507d_core_calc(struct nv50_head *head, struct nv50_head_atom *asyh) 202 { 203 struct nv50_disp *disp = nv50_disp(head->base.base.dev); 204 if ((asyh->core.visible = (asyh->base.cpp != 0))) { 205 asyh->core.x = asyh->base.x; 206 asyh->core.y = asyh->base.y; 207 asyh->core.w = asyh->base.w; 208 asyh->core.h = asyh->base.h; 209 } else 210 if ((asyh->core.visible = (asyh->ovly.cpp != 0)) || 211 (asyh->core.visible = asyh->curs.visible)) { 212 /*XXX: We need to either find some way of having the 213 * primary base layer appear black, while still 214 * being able to display the other layers, or we 215 * need to allocate a dummy black surface here. 216 */ 217 asyh->core.x = 0; 218 asyh->core.y = 0; 219 asyh->core.w = asyh->state.mode.hdisplay; 220 asyh->core.h = asyh->state.mode.vdisplay; 221 } 222 asyh->core.handle = disp->core->chan.vram.handle; 223 asyh->core.offset = 0; 224 asyh->core.format = 0xcf; 225 asyh->core.kind = 0; 226 asyh->core.layout = 1; 227 asyh->core.blockh = 0; 228 asyh->core.blocks = 0; 229 asyh->core.pitch = ALIGN(asyh->core.w, 64) * 4; 230 } 231 232 static void 233 head507d_olut_clr(struct nv50_head *head) 234 { 235 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 236 u32 *push; 237 if ((push = evo_wait(core, 2))) { 238 evo_mthd(push, 0x0840 + (head->base.index * 0x400), 1); 239 evo_data(push, 0x00000000); 240 evo_kick(push, core); 241 } 242 } 243 244 static void 245 head507d_olut_set(struct nv50_head *head, struct nv50_head_atom *asyh) 246 { 247 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 248 u32 *push; 249 if ((push = evo_wait(core, 3))) { 250 evo_mthd(push, 0x0840 + (head->base.index * 0x400), 2); 251 evo_data(push, 0x80000000 | asyh->olut.mode << 30); 252 evo_data(push, asyh->olut.offset >> 8); 253 evo_kick(push, core); 254 } 255 } 256 257 static void 258 head507d_olut_load(struct drm_color_lut *in, int size, void __iomem *mem) 259 { 260 for (; size--; in++, mem += 8) { 261 writew(drm_color_lut_extract(in-> red, 11) << 3, mem + 0); 262 writew(drm_color_lut_extract(in->green, 11) << 3, mem + 2); 263 writew(drm_color_lut_extract(in-> blue, 11) << 3, mem + 4); 264 } 265 266 /* INTERPOLATE modes require a "next" entry to interpolate with, 267 * so we replicate the last entry to deal with this for now. 268 */ 269 writew(readw(mem - 8), mem + 0); 270 writew(readw(mem - 6), mem + 2); 271 writew(readw(mem - 4), mem + 4); 272 } 273 274 bool 275 head507d_olut(struct nv50_head *head, struct nv50_head_atom *asyh, int size) 276 { 277 if (size != 256) 278 return false; 279 280 if (asyh->base.cpp == 1) 281 asyh->olut.mode = 0; 282 else 283 asyh->olut.mode = 1; 284 285 asyh->olut.load = head507d_olut_load; 286 return true; 287 } 288 289 void 290 head507d_mode(struct nv50_head *head, struct nv50_head_atom *asyh) 291 { 292 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 293 struct nv50_head_mode *m = &asyh->mode; 294 u32 *push; 295 if ((push = evo_wait(core, 13))) { 296 evo_mthd(push, 0x0804 + (head->base.index * 0x400), 2); 297 evo_data(push, 0x00800000 | m->clock); 298 evo_data(push, m->interlace ? 0x00000002 : 0x00000000); 299 evo_mthd(push, 0x0810 + (head->base.index * 0x400), 7); 300 evo_data(push, 0x00000000); 301 evo_data(push, m->v.active << 16 | m->h.active ); 302 evo_data(push, m->v.synce << 16 | m->h.synce ); 303 evo_data(push, m->v.blanke << 16 | m->h.blanke ); 304 evo_data(push, m->v.blanks << 16 | m->h.blanks ); 305 evo_data(push, m->v.blank2e << 16 | m->v.blank2s); 306 evo_data(push, asyh->mode.v.blankus); 307 evo_mthd(push, 0x082c + (head->base.index * 0x400), 1); 308 evo_data(push, 0x00000000); 309 evo_kick(push, core); 310 } 311 } 312 313 void 314 head507d_view(struct nv50_head *head, struct nv50_head_atom *asyh) 315 { 316 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 317 u32 *push; 318 if ((push = evo_wait(core, 7))) { 319 evo_mthd(push, 0x08a4 + (head->base.index * 0x400), 1); 320 evo_data(push, 0x00000000); 321 evo_mthd(push, 0x08c8 + (head->base.index * 0x400), 1); 322 evo_data(push, asyh->view.iH << 16 | asyh->view.iW); 323 evo_mthd(push, 0x08d8 + (head->base.index * 0x400), 2); 324 evo_data(push, asyh->view.oH << 16 | asyh->view.oW); 325 evo_data(push, asyh->view.oH << 16 | asyh->view.oW); 326 evo_kick(push, core); 327 } 328 } 329 330 const struct nv50_head_func 331 head507d = { 332 .view = head507d_view, 333 .mode = head507d_mode, 334 .olut = head507d_olut, 335 .olut_size = 256, 336 .olut_set = head507d_olut_set, 337 .olut_clr = head507d_olut_clr, 338 .core_calc = head507d_core_calc, 339 .core_set = head507d_core_set, 340 .core_clr = head507d_core_clr, 341 .curs_layout = head507d_curs_layout, 342 .curs_format = head507d_curs_format, 343 .curs_set = head507d_curs_set, 344 .curs_clr = head507d_curs_clr, 345 .base = head507d_base, 346 .ovly = head507d_ovly, 347 .dither = head507d_dither, 348 .procamp = head507d_procamp, 349 }; 350