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 <drm/drm_connector.h> 23 #include <drm/drm_mode_config.h> 24 #include <drm/drm_vblank.h> 25 #include "nouveau_drv.h" 26 #include "nouveau_bios.h" 27 #include "nouveau_connector.h" 28 #include "head.h" 29 #include "core.h" 30 #include "crc.h" 31 32 void 33 head907d_or(struct nv50_head *head, struct nv50_head_atom *asyh) 34 { 35 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 36 u32 *push; 37 if ((push = evo_wait(core, 3))) { 38 evo_mthd(push, 0x0404 + (head->base.index * 0x300), 2); 39 evo_data(push, asyh->or.depth << 6 | 40 asyh->or.nvsync << 4 | 41 asyh->or.nhsync << 3 | 42 asyh->or.crc_raster); 43 evo_data(push, 0x31ec6000 | head->base.index << 25 | 44 asyh->mode.interlace); 45 evo_kick(push, core); 46 } 47 } 48 49 void 50 head907d_procamp(struct nv50_head *head, struct nv50_head_atom *asyh) 51 { 52 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 53 u32 *push; 54 if ((push = evo_wait(core, 2))) { 55 evo_mthd(push, 0x0498 + (head->base.index * 0x300), 1); 56 evo_data(push, asyh->procamp.sat.sin << 20 | 57 asyh->procamp.sat.cos << 8); 58 evo_kick(push, core); 59 } 60 } 61 62 static void 63 head907d_dither(struct nv50_head *head, struct nv50_head_atom *asyh) 64 { 65 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 66 u32 *push; 67 if ((push = evo_wait(core, 2))) { 68 evo_mthd(push, 0x0490 + (head->base.index * 0x0300), 1); 69 evo_data(push, asyh->dither.mode << 3 | 70 asyh->dither.bits << 1 | 71 asyh->dither.enable); 72 evo_kick(push, core); 73 } 74 } 75 76 void 77 head907d_ovly(struct nv50_head *head, struct nv50_head_atom *asyh) 78 { 79 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 80 u32 bounds = 0; 81 u32 *push; 82 83 if (asyh->ovly.cpp) { 84 switch (asyh->ovly.cpp) { 85 case 8: bounds |= 0x00000500; break; 86 case 4: bounds |= 0x00000300; break; 87 case 2: bounds |= 0x00000100; break; 88 default: 89 WARN_ON(1); 90 break; 91 } 92 bounds |= 0x00000001; 93 } else { 94 bounds |= 0x00000100; 95 } 96 97 if ((push = evo_wait(core, 2))) { 98 evo_mthd(push, 0x04d4 + head->base.index * 0x300, 1); 99 evo_data(push, bounds); 100 evo_kick(push, core); 101 } 102 } 103 104 static void 105 head907d_base(struct nv50_head *head, struct nv50_head_atom *asyh) 106 { 107 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 108 u32 bounds = 0; 109 u32 *push; 110 111 if (asyh->base.cpp) { 112 switch (asyh->base.cpp) { 113 case 8: bounds |= 0x00000500; break; 114 case 4: bounds |= 0x00000300; break; 115 case 2: bounds |= 0x00000100; break; 116 case 1: bounds |= 0x00000000; break; 117 default: 118 WARN_ON(1); 119 break; 120 } 121 bounds |= 0x00000001; 122 } 123 124 if ((push = evo_wait(core, 2))) { 125 evo_mthd(push, 0x04d0 + head->base.index * 0x300, 1); 126 evo_data(push, bounds); 127 evo_kick(push, core); 128 } 129 } 130 131 void 132 head907d_curs_clr(struct nv50_head *head) 133 { 134 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 135 u32 *push; 136 if ((push = evo_wait(core, 4))) { 137 evo_mthd(push, 0x0480 + head->base.index * 0x300, 1); 138 evo_data(push, 0x05000000); 139 evo_mthd(push, 0x048c + head->base.index * 0x300, 1); 140 evo_data(push, 0x00000000); 141 evo_kick(push, core); 142 } 143 } 144 145 void 146 head907d_curs_set(struct nv50_head *head, struct nv50_head_atom *asyh) 147 { 148 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 149 u32 *push; 150 if ((push = evo_wait(core, 5))) { 151 evo_mthd(push, 0x0480 + head->base.index * 0x300, 2); 152 evo_data(push, 0x80000000 | asyh->curs.layout << 26 | 153 asyh->curs.format << 24); 154 evo_data(push, asyh->curs.offset >> 8); 155 evo_mthd(push, 0x048c + head->base.index * 0x300, 1); 156 evo_data(push, asyh->curs.handle); 157 evo_kick(push, core); 158 } 159 } 160 161 void 162 head907d_core_clr(struct nv50_head *head) 163 { 164 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 165 u32 *push; 166 if ((push = evo_wait(core, 2))) { 167 evo_mthd(push, 0x0474 + head->base.index * 0x300, 1); 168 evo_data(push, 0x00000000); 169 evo_kick(push, core); 170 } 171 } 172 173 void 174 head907d_core_set(struct nv50_head *head, struct nv50_head_atom *asyh) 175 { 176 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 177 u32 *push; 178 if ((push = evo_wait(core, 9))) { 179 evo_mthd(push, 0x0460 + head->base.index * 0x300, 1); 180 evo_data(push, asyh->core.offset >> 8); 181 evo_mthd(push, 0x0468 + head->base.index * 0x300, 4); 182 evo_data(push, asyh->core.h << 16 | asyh->core.w); 183 evo_data(push, asyh->core.layout << 24 | 184 (asyh->core.pitch >> 8) << 8 | 185 asyh->core.blocks << 8 | 186 asyh->core.blockh); 187 evo_data(push, asyh->core.format << 8); 188 evo_data(push, asyh->core.handle); 189 evo_mthd(push, 0x04b0 + head->base.index * 0x300, 1); 190 evo_data(push, asyh->core.y << 16 | asyh->core.x); 191 evo_kick(push, core); 192 } 193 } 194 195 void 196 head907d_olut_clr(struct nv50_head *head) 197 { 198 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 199 u32 *push; 200 if ((push = evo_wait(core, 4))) { 201 evo_mthd(push, 0x0448 + (head->base.index * 0x300), 1); 202 evo_data(push, 0x00000000); 203 evo_mthd(push, 0x045c + (head->base.index * 0x300), 1); 204 evo_data(push, 0x00000000); 205 evo_kick(push, core); 206 } 207 } 208 209 void 210 head907d_olut_set(struct nv50_head *head, struct nv50_head_atom *asyh) 211 { 212 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 213 u32 *push; 214 if ((push = evo_wait(core, 5))) { 215 evo_mthd(push, 0x0448 + (head->base.index * 0x300), 2); 216 evo_data(push, 0x80000000 | asyh->olut.mode << 24); 217 evo_data(push, asyh->olut.offset >> 8); 218 evo_mthd(push, 0x045c + (head->base.index * 0x300), 1); 219 evo_data(push, asyh->olut.handle); 220 evo_kick(push, core); 221 } 222 } 223 224 void 225 head907d_olut_load(struct drm_color_lut *in, int size, void __iomem *mem) 226 { 227 for (; size--; in++, mem += 8) { 228 writew(drm_color_lut_extract(in-> red, 14) + 0x6000, mem + 0); 229 writew(drm_color_lut_extract(in->green, 14) + 0x6000, mem + 2); 230 writew(drm_color_lut_extract(in-> blue, 14) + 0x6000, mem + 4); 231 } 232 233 /* INTERPOLATE modes require a "next" entry to interpolate with, 234 * so we replicate the last entry to deal with this for now. 235 */ 236 writew(readw(mem - 8), mem + 0); 237 writew(readw(mem - 6), mem + 2); 238 writew(readw(mem - 4), mem + 4); 239 } 240 241 bool 242 head907d_olut(struct nv50_head *head, struct nv50_head_atom *asyh, int size) 243 { 244 if (size != 256 && size != 1024) 245 return false; 246 247 asyh->olut.mode = size == 1024 ? 4 : 7; 248 asyh->olut.load = head907d_olut_load; 249 return true; 250 } 251 252 void 253 head907d_mode(struct nv50_head *head, struct nv50_head_atom *asyh) 254 { 255 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 256 struct nv50_head_mode *m = &asyh->mode; 257 u32 *push; 258 if ((push = evo_wait(core, 14))) { 259 evo_mthd(push, 0x0410 + (head->base.index * 0x300), 6); 260 evo_data(push, 0x00000000); 261 evo_data(push, m->v.active << 16 | m->h.active ); 262 evo_data(push, m->v.synce << 16 | m->h.synce ); 263 evo_data(push, m->v.blanke << 16 | m->h.blanke ); 264 evo_data(push, m->v.blanks << 16 | m->h.blanks ); 265 evo_data(push, m->v.blank2e << 16 | m->v.blank2s); 266 evo_mthd(push, 0x042c + (head->base.index * 0x300), 2); 267 evo_data(push, 0x00000000); /* ??? */ 268 evo_data(push, 0xffffff00); 269 evo_mthd(push, 0x0450 + (head->base.index * 0x300), 3); 270 evo_data(push, m->clock * 1000); 271 evo_data(push, 0x00200000); /* ??? */ 272 evo_data(push, m->clock * 1000); 273 evo_kick(push, core); 274 } 275 } 276 277 void 278 head907d_view(struct nv50_head *head, struct nv50_head_atom *asyh) 279 { 280 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 281 u32 *push; 282 if ((push = evo_wait(core, 8))) { 283 evo_mthd(push, 0x0494 + (head->base.index * 0x300), 1); 284 evo_data(push, 0x00000000); 285 evo_mthd(push, 0x04b8 + (head->base.index * 0x300), 1); 286 evo_data(push, asyh->view.iH << 16 | asyh->view.iW); 287 evo_mthd(push, 0x04c0 + (head->base.index * 0x300), 3); 288 evo_data(push, asyh->view.oH << 16 | asyh->view.oW); 289 evo_data(push, asyh->view.oH << 16 | asyh->view.oW); 290 evo_data(push, asyh->view.oH << 16 | asyh->view.oW); 291 evo_kick(push, core); 292 } 293 } 294 295 const struct nv50_head_func 296 head907d = { 297 .view = head907d_view, 298 .mode = head907d_mode, 299 .olut = head907d_olut, 300 .olut_size = 1024, 301 .olut_set = head907d_olut_set, 302 .olut_clr = head907d_olut_clr, 303 .core_calc = head507d_core_calc, 304 .core_set = head907d_core_set, 305 .core_clr = head907d_core_clr, 306 .curs_layout = head507d_curs_layout, 307 .curs_format = head507d_curs_format, 308 .curs_set = head907d_curs_set, 309 .curs_clr = head907d_curs_clr, 310 .base = head907d_base, 311 .ovly = head907d_ovly, 312 .dither = head907d_dither, 313 .procamp = head907d_procamp, 314 .or = head907d_or, 315 }; 316