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