Home | History | Annotate | Line # | Download | only in dispnv50
      1 /*	$NetBSD: nouveau_dispnv50_headc57d.c,v 1.4 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_headc57d.c,v 1.4 2021/12/19 10:49:47 riastradh Exp $");
     26 
     27 #include "head.h"
     28 #include "atom.h"
     29 #include "core.h"
     30 
     31 static void
     32 headc57d_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, 0xfc000001 |
     52 			       asyh->or.depth << 4 |
     53 			       asyh->or.nvsync << 3 |
     54 			       asyh->or.nhsync << 2);
     55 		evo_kick(push, core);
     56 	}
     57 }
     58 
     59 static void
     60 headc57d_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 #if 0
     67 		evo_data(push, 0x80000000 |
     68 			       asyh->procamp.sat.sin << 16 |
     69 			       asyh->procamp.sat.cos << 4);
     70 #else
     71 		evo_data(push, 0);
     72 #endif
     73 		evo_kick(push, core);
     74 	}
     75 }
     76 
     77 static void
     78 headc57d_olut_clr(struct nv50_head *head)
     79 {
     80 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
     81 	u32 *push;
     82 	if ((push = evo_wait(core, 2))) {
     83 		evo_mthd(push, 0x2288 + (head->base.index * 0x400), 1);
     84 		evo_data(push, 0x00000000);
     85 		evo_kick(push, core);
     86 	}
     87 }
     88 
     89 static void
     90 headc57d_olut_set(struct nv50_head *head, struct nv50_head_atom *asyh)
     91 {
     92 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
     93 	u32 *push;
     94 	if ((push = evo_wait(core, 4))) {
     95 		evo_mthd(push, 0x2280 + (head->base.index * 0x400), 4);
     96 		evo_data(push, asyh->olut.size << 8 |
     97 			       asyh->olut.mode << 2 |
     98 			       asyh->olut.output_mode);
     99 		evo_data(push, 0xffffffff); /* FP_NORM_SCALE. */
    100 		evo_data(push, asyh->olut.handle);
    101 		evo_data(push, asyh->olut.offset >> 8);
    102 		evo_kick(push, core);
    103 	}
    104 }
    105 
    106 #ifdef __NetBSD__
    107 #define	__iomem		__lut_iomem
    108 #define	readw(p)	atomic_load_relaxed((const __iomem uint16_t *)(p))
    109 #define	writew(v,p)	atomic_store_relaxed((__iomem uint16_t *)(p), (v))
    110 #endif
    111 
    112 static void
    113 headc57d_olut_load_8(struct drm_color_lut *in, int size, void __iomem *mem)
    114 {
    115 	memset_io(mem, 0x00, 0x20); /* VSS header. */
    116 	mem += 0x20;
    117 
    118 	while (size--) {
    119 		u16 r = drm_color_lut_extract(in->  red + 0, 16);
    120 		u16 g = drm_color_lut_extract(in->green + 0, 16);
    121 		u16 b = drm_color_lut_extract(in-> blue + 0, 16);
    122 		u16 ri = 0, gi = 0, bi = 0, i;
    123 
    124 		if (in++, size) {
    125 			ri = (drm_color_lut_extract(in->  red, 16) - r) / 4;
    126 			gi = (drm_color_lut_extract(in->green, 16) - g) / 4;
    127 			bi = (drm_color_lut_extract(in-> blue, 16) - b) / 4;
    128 		}
    129 
    130 		for (i = 0; i < 4; i++, mem += 8) {
    131 			writew(r + ri * i, mem + 0);
    132 			writew(g + gi * i, mem + 2);
    133 			writew(b + bi * i, mem + 4);
    134 		}
    135 	}
    136 
    137 	/* INTERPOLATE modes require a "next" entry to interpolate with,
    138 	 * so we replicate the last entry to deal with this for now.
    139 	 */
    140 	writew(readw(mem - 8), mem + 0);
    141 	writew(readw(mem - 6), mem + 2);
    142 	writew(readw(mem - 4), mem + 4);
    143 }
    144 
    145 static void
    146 headc57d_olut_load(struct drm_color_lut *in, int size, void __iomem *mem)
    147 {
    148 	memset_io(mem, 0x00, 0x20); /* VSS header. */
    149 	mem += 0x20;
    150 
    151 	for (; size--; in++, mem += 0x08) {
    152 		writew(drm_color_lut_extract(in->  red, 16), mem + 0);
    153 		writew(drm_color_lut_extract(in->green, 16), mem + 2);
    154 		writew(drm_color_lut_extract(in-> blue, 16), mem + 4);
    155 	}
    156 
    157 	/* INTERPOLATE modes require a "next" entry to interpolate with,
    158 	 * so we replicate the last entry to deal with this for now.
    159 	 */
    160 	writew(readw(mem - 8), mem + 0);
    161 	writew(readw(mem - 6), mem + 2);
    162 	writew(readw(mem - 4), mem + 4);
    163 }
    164 
    165 static bool
    166 headc57d_olut(struct nv50_head *head, struct nv50_head_atom *asyh, int size)
    167 {
    168 	if (size != 0 && size != 256 && size != 1024)
    169 		return false;
    170 
    171 	asyh->olut.mode = 2; /* DIRECT10 */
    172 	asyh->olut.size = 4 /* VSS header. */ + 1024 + 1 /* Entries. */;
    173 	asyh->olut.output_mode = 1; /* INTERPOLATE_ENABLE. */
    174 	if (size == 256)
    175 		asyh->olut.load = headc57d_olut_load_8;
    176 	else
    177 		asyh->olut.load = headc57d_olut_load;
    178 	return true;
    179 }
    180 
    181 static void
    182 headc57d_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
    183 {
    184 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
    185 	struct nv50_head_mode *m = &asyh->mode;
    186 	u32 *push;
    187 	if ((push = evo_wait(core, 12))) {
    188 		evo_mthd(push, 0x2064 + (head->base.index * 0x400), 5);
    189 		evo_data(push, (m->v.active  << 16) | m->h.active );
    190 		evo_data(push, (m->v.synce   << 16) | m->h.synce  );
    191 		evo_data(push, (m->v.blanke  << 16) | m->h.blanke );
    192 		evo_data(push, (m->v.blanks  << 16) | m->h.blanks );
    193 		evo_data(push, (m->v.blank2e << 16) | m->v.blank2s);
    194 		evo_mthd(push, 0x200c + (head->base.index * 0x400), 1);
    195 		evo_data(push, m->clock * 1000);
    196 		evo_mthd(push, 0x2028 + (head->base.index * 0x400), 1);
    197 		evo_data(push, m->clock * 1000);
    198 		/*XXX: HEAD_USAGE_BOUNDS, doesn't belong here. */
    199 		evo_mthd(push, 0x2030 + (head->base.index * 0x400), 1);
    200 		evo_data(push, 0x00001014);
    201 		evo_kick(push, core);
    202 	}
    203 }
    204 
    205 const struct nv50_head_func
    206 headc57d = {
    207 	.view = headc37d_view,
    208 	.mode = headc57d_mode,
    209 	.olut = headc57d_olut,
    210 	.olut_identity = true,
    211 	.olut_size = 1024,
    212 	.olut_set = headc57d_olut_set,
    213 	.olut_clr = headc57d_olut_clr,
    214 	.curs_layout = head917d_curs_layout,
    215 	.curs_format = headc37d_curs_format,
    216 	.curs_set = headc37d_curs_set,
    217 	.curs_clr = headc37d_curs_clr,
    218 	.dither = headc37d_dither,
    219 	.procamp = headc57d_procamp,
    220 	.or = headc57d_or,
    221 };
    222