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