1/* $NetBSD: nouveau_dispnv50_headc37d.c,v 1.2 2021/12/18 23:45:32 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_headc37d.c,v 1.2 2021/12/18 23:45:32 riastradh Exp $"); 26 27#include "head.h" 28#include "atom.h" 29#include "core.h" 30 31static void 32headc37d_or(struct nv50_head *head, struct nv50_head_atom *asyh) 33{ 34 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 35 u32 *push; 36 if ((push = evo_wait(core, 2))) { 37 /*XXX: This is a dirty hack until OR depth handling is 38 * improved later for deep colour etc. 39 */ 40 switch (asyh->or.depth) { 41 case 6: asyh->or.depth = 5; break; 42 case 5: asyh->or.depth = 4; break; 43 case 2: asyh->or.depth = 1; break; 44 case 0: asyh->or.depth = 4; break; 45 default: 46 WARN_ON(1); 47 break; 48 } 49 50 evo_mthd(push, 0x2004 + (head->base.index * 0x400), 1); 51 evo_data(push, 0x00000001 | 52 asyh->or.depth << 4 | 53 asyh->or.nvsync << 3 | 54 asyh->or.nhsync << 2); 55 evo_kick(push, core); 56 } 57} 58 59static void 60headc37d_procamp(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, 0x2000 + (head->base.index * 0x400), 1); 66 evo_data(push, 0x80000000 | 67 asyh->procamp.sat.sin << 16 | 68 asyh->procamp.sat.cos << 4); 69 evo_kick(push, core); 70 } 71} 72 73void 74headc37d_dither(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 *push; 78 if ((push = evo_wait(core, 2))) { 79 evo_mthd(push, 0x2018 + (head->base.index * 0x0400), 1); 80 evo_data(push, asyh->dither.mode << 8 | 81 asyh->dither.bits << 4 | 82 asyh->dither.enable); 83 evo_kick(push, core); 84 } 85} 86 87void 88headc37d_curs_clr(struct nv50_head *head) 89{ 90 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 91 u32 *push; 92 if ((push = evo_wait(core, 4))) { 93 evo_mthd(push, 0x209c + head->base.index * 0x400, 1); 94 evo_data(push, 0x000000cf); 95 evo_mthd(push, 0x2088 + head->base.index * 0x400, 1); 96 evo_data(push, 0x00000000); 97 evo_kick(push, core); 98 } 99} 100 101void 102headc37d_curs_set(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 *push; 106 if ((push = evo_wait(core, 7))) { 107 evo_mthd(push, 0x209c + head->base.index * 0x400, 2); 108 evo_data(push, 0x80000000 | 109 asyh->curs.layout << 8 | 110 asyh->curs.format << 0); 111 evo_data(push, 0x000072ff); 112 evo_mthd(push, 0x2088 + head->base.index * 0x400, 1); 113 evo_data(push, asyh->curs.handle); 114 evo_mthd(push, 0x2090 + head->base.index * 0x400, 1); 115 evo_data(push, asyh->curs.offset >> 8); 116 evo_kick(push, core); 117 } 118} 119 120int 121headc37d_curs_format(struct nv50_head *head, struct nv50_wndw_atom *asyw, 122 struct nv50_head_atom *asyh) 123{ 124 asyh->curs.format = asyw->image.format; 125 return 0; 126} 127 128static void 129headc37d_olut_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, 2))) { 134 evo_mthd(push, 0x20ac + (head->base.index * 0x400), 1); 135 evo_data(push, 0x00000000); 136 evo_kick(push, core); 137 } 138} 139 140static void 141headc37d_olut_set(struct nv50_head *head, struct nv50_head_atom *asyh) 142{ 143 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 144 u32 *push; 145 if ((push = evo_wait(core, 4))) { 146 evo_mthd(push, 0x20a4 + (head->base.index * 0x400), 3); 147 evo_data(push, asyh->olut.output_mode << 8 | 148 asyh->olut.range << 4 | 149 asyh->olut.size); 150 evo_data(push, asyh->olut.offset >> 8); 151 evo_data(push, asyh->olut.handle); 152 evo_kick(push, core); 153 } 154} 155 156static bool 157headc37d_olut(struct nv50_head *head, struct nv50_head_atom *asyh, int size) 158{ 159 if (size != 256 && size != 1024) 160 return false; 161 162 asyh->olut.mode = 2; 163 asyh->olut.size = size == 1024 ? 2 : 0; 164 asyh->olut.range = 0; 165 asyh->olut.output_mode = 1; 166 asyh->olut.load = head907d_olut_load; 167 return true; 168} 169 170static void 171headc37d_mode(struct nv50_head *head, struct nv50_head_atom *asyh) 172{ 173 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 174 struct nv50_head_mode *m = &asyh->mode; 175 u32 *push; 176 if ((push = evo_wait(core, 12))) { 177 evo_mthd(push, 0x2064 + (head->base.index * 0x400), 5); 178 evo_data(push, (m->v.active << 16) | m->h.active ); 179 evo_data(push, (m->v.synce << 16) | m->h.synce ); 180 evo_data(push, (m->v.blanke << 16) | m->h.blanke ); 181 evo_data(push, (m->v.blanks << 16) | m->h.blanks ); 182 evo_data(push, (m->v.blank2e << 16) | m->v.blank2s); 183 evo_mthd(push, 0x200c + (head->base.index * 0x400), 1); 184 evo_data(push, m->clock * 1000); 185 evo_mthd(push, 0x2028 + (head->base.index * 0x400), 1); 186 evo_data(push, m->clock * 1000); 187 /*XXX: HEAD_USAGE_BOUNDS, doesn't belong here. */ 188 evo_mthd(push, 0x2030 + (head->base.index * 0x400), 1); 189 evo_data(push, 0x00000124); 190 evo_kick(push, core); 191 } 192} 193 194void 195headc37d_view(struct nv50_head *head, struct nv50_head_atom *asyh) 196{ 197 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 198 u32 *push; 199 if ((push = evo_wait(core, 4))) { 200 evo_mthd(push, 0x204c + (head->base.index * 0x400), 1); 201 evo_data(push, (asyh->view.iH << 16) | asyh->view.iW); 202 evo_mthd(push, 0x2058 + (head->base.index * 0x400), 1); 203 evo_data(push, (asyh->view.oH << 16) | asyh->view.oW); 204 evo_kick(push, core); 205 } 206} 207 208const struct nv50_head_func 209headc37d = { 210 .view = headc37d_view, 211 .mode = headc37d_mode, 212 .olut = headc37d_olut, 213 .olut_size = 1024, 214 .olut_set = headc37d_olut_set, 215 .olut_clr = headc37d_olut_clr, 216 .curs_layout = head917d_curs_layout, 217 .curs_format = headc37d_curs_format, 218 .curs_set = headc37d_curs_set, 219 .curs_clr = headc37d_curs_clr, 220 .dither = headc37d_dither, 221 .procamp = headc37d_procamp, 222 .or = headc37d_or, 223}; 224