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