kernel/syscons: First hacky steps to make syscons work with {i915,radeon}kms.
[dragonfly.git] / sys / dev / misc / syscons / sckmsrndr.c
1 /*-
2  * Copyright (c) 2014 Imre Vadász <imre@vdsz.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer as
10  *    the first lines of this file unmodified.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "opt_syscons.h"
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <sys/thread.h>
33 #include <sys/thread2.h>
34
35 #include <machine/console.h>
36
37 #include <dev/drm/include/linux/fb.h>
38
39 #include "syscons.h"
40
41 #include <bus/isa/isareg.h>
42
43 static vr_draw_t                kms_draw;
44 static vr_draw_cursor_t         kms_cursor;
45 static vr_blink_cursor_t        kms_blink;
46 static vr_draw_mouse_t          kms_mouse;
47
48 static void                     kms_nop(scr_stat *scp, ...);
49
50 static sc_rndr_sw_t kmsrndrsw = {
51         (vr_draw_border_t *)kms_nop,
52         kms_draw,
53         (vr_set_cursor_t *)kms_nop,
54         kms_cursor,
55         kms_blink,
56 #ifndef SC_NO_CUTPASTE
57         kms_mouse,
58 #else
59         (vr_draw_mouse_t *)kms_nop;
60 #endif
61 };
62 RENDERER(kms, V_INFO_MM_TEXT, kmsrndrsw, kms_set);
63
64 #ifndef SC_NO_MODE_CHANGE
65 static sc_rndr_sw_t grrndrsw = {
66         (vr_draw_border_t *)kms_nop,
67         (vr_draw_t *)kms_nop,
68         (vr_set_cursor_t *)kms_nop,
69         (vr_draw_cursor_t *)kms_nop,
70         (vr_blink_cursor_t *)kms_nop,
71         (vr_draw_mouse_t *)kms_nop,
72 };
73 RENDERER(kms, V_INFO_MM_OTHER, grrndrsw, kms_set);
74 #endif /* SC_NO_MODE_CHANGE */
75
76 RENDERER_MODULE(kms, kms_set);
77
78 static uint32_t colormap[16] = {
79         0x00000000,     /* BLACK */
80         0x000000aa,     /* BLUE */
81         0x0000aa00,     /* GREEN */
82         0x0000aaaa,     /* CYAN */
83         0x00aa0000,     /* RED */
84         0x00aa00aa,     /* MAGENTA */
85         0x00aa5500,     /* BROWN */
86         0x00aaaaaa,     /* WHITE */
87         0x00555555,     /* HIGHLIGHT BLACK */
88         0x005555ff,     /* HIGHLIGHT BLUE */
89         0x0055ff55,     /* HIGHLIGHT GREEN */
90         0x0055ffff,     /* HIGHLIGHT CYAN */
91         0x00ff5555,     /* HIGHLIGHT RED */
92         0x00ff55ff,     /* HIGHLIGHT MAGENTA */
93         0x00ffff55,     /* HIGHLIGHT BROWN */
94         0x00ffffff,     /* HIGHLIGHT WHITE */
95 };
96
97 #ifndef SC_NO_CUTPASTE
98 static u_short mouse_and_mask[16] = {
99         0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80,
100         0xfe00, 0x1e00, 0x1f00, 0x0f00, 0x0f00, 0x0000, 0x0000, 0x0000
101 };
102 static u_short mouse_or_mask[16] = {
103         0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x6800,
104         0x0c00, 0x0c00, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000
105 };
106 #endif
107
108 static void
109 kms_nop(scr_stat *scp, ...)
110 {
111 }
112
113 /* KMS renderer */
114
115 static void
116 kms_draw(scr_stat *scp, int from, int count, int flip)
117 {
118         sc_softc_t *sc = scp->sc;
119         u_char *char_data;
120         int a, i, j;
121         uint32_t fg, bg;
122         vm_offset_t draw_pos, p;
123         int pos, line_width, pixel_size;
124
125         line_width = sc->fbi->stride;
126         pixel_size = 4;
127
128         draw_pos = sc->fbi->vaddr +
129             8 * pixel_size * (from % scp->xsize) +
130             scp->font_size * line_width * (from / scp->xsize);
131
132         if (from + count > scp->xsize * scp->ysize)
133                 count = scp->xsize * scp->ysize - from;
134
135         for (i = from; count-- > 0; i++) {
136                 p = draw_pos;
137                 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, i) *
138                     scp->font_size]);
139
140                 a = sc_vtb_geta(&scp->vtb, i);
141                 if (flip) {
142                         fg = colormap[((a & 0xf000) >> 4) >> 8];
143                         bg = colormap[(a & 0x0f00) >> 8];
144                 } else {
145                         fg = colormap[(a & 0x0f00) >> 8];
146                         bg = colormap[((a & 0xf000) >> 4) >> 8];
147                 }
148
149                 for (j = 0; j < scp->font_size; j++, char_data++) {
150                         for (pos = 7; pos >= 0; pos--, p += pixel_size)
151                                 writel(p, *char_data & (1 << pos) ? fg : bg);
152                         p += line_width - 8 * pixel_size;
153                 }
154                 draw_pos += 8 * pixel_size;
155                 if ((i % scp->xsize) == scp->xsize - 1) {
156                         draw_pos += (scp->font_size - 1) * line_width +
157                             scp->xpad * pixel_size;
158                 }
159         }
160 }
161
162 static void
163 draw_kmscursor(scr_stat *scp, int at, int on, int flip)
164 {
165         sc_softc_t *sc = scp->sc;
166         int line_width, pixel_size, height;
167         int a, i, pos;
168         uint32_t fg, bg;
169         unsigned char *char_data;
170         vm_offset_t draw_pos;
171
172         line_width = sc->fbi->stride;
173         pixel_size = 4;
174
175         draw_pos = sc->fbi->vaddr +
176             8 * pixel_size * (at % scp->xsize) +
177             scp->font_size * line_width * (at / scp->xsize) +
178             (scp->font_size - scp->cursor_base - 1) * line_width;
179
180         a = sc_vtb_geta(&scp->vtb, at);
181         if (flip) {
182                 fg = colormap[((on) ? (a & 0x0f00) :
183                     ((a & 0xf000) >> 4)) >> 8];
184                 bg = colormap[((on) ? ((a & 0xf000) >> 4) :
185                     (a & 0x0f00)) >> 8];
186         } else {
187                 fg = colormap[((on) ? ((a & 0xf000) >> 4) :
188                     (a & 0x0f00)) >> 8];
189                 bg = colormap[((on) ? (a & 0x0f00) :
190                     ((a & 0xf000) >> 4)) >> 8];
191         }
192
193         char_data = &(scp->font[sc_vtb_getc(&scp->vtb, at) * scp->font_size +
194             scp->font_size - scp->cursor_base - 1]);
195         height = imin(scp->cursor_height, scp->font_size);
196
197         for (i = 0; i < height; i++, char_data--) {
198                 for (pos = 7; pos >= 0; pos--, draw_pos += pixel_size)
199                         writel(draw_pos, *char_data & (1 << pos) ? fg : bg);
200                 draw_pos -= line_width + 8 * pixel_size;
201         }
202 }
203
204 static int pxlblinkrate = 0;
205
206 static void
207 kms_cursor(scr_stat *scp, int at, int blink, int on, int flip)
208 {
209         if (scp->cursor_height <= 0)    /* the text cursor is disabled */
210                 return;
211
212         if (on) {
213                 if (!blink) {
214                         scp->status |= VR_CURSOR_ON;
215                         draw_kmscursor(scp, at, on, flip);
216                 } else if (++pxlblinkrate & 4) {
217                         pxlblinkrate = 0;
218                         scp->status ^= VR_CURSOR_ON;
219                         draw_kmscursor(scp, at,
220                             scp->status & VR_CURSOR_ON, flip);
221                 }
222         } else {
223                 if (scp->status & VR_CURSOR_ON)
224                         draw_kmscursor(scp, at, on, flip);
225                 scp->status &= ~VR_CURSOR_ON;
226         }
227         if (blink)
228                 scp->status |= VR_CURSOR_BLINK;
229         else
230                 scp->status &= ~VR_CURSOR_BLINK;
231 }
232
233 static void
234 kms_blink(scr_stat *scp, int at, int flip)
235 {
236         if (!(scp->status & VR_CURSOR_BLINK))
237                 return;
238         if (!(++pxlblinkrate & 4))
239                 return;
240         pxlblinkrate = 0;
241         scp->status ^= VR_CURSOR_ON;
242         draw_kmscursor(scp, at, scp->status & VR_CURSOR_ON, flip);
243 }
244
245 #ifndef SC_NO_CUTPASTE
246
247 static void
248 draw_kmsmouse(scr_stat *scp, int x, int y)
249 {
250         sc_softc_t *sc = scp->sc;
251         int line_width, pixel_size;
252         int xend, yend;
253         int i, j;
254         vm_offset_t draw_pos;
255
256         line_width = sc->fbi->stride;
257         pixel_size = 4;
258
259         xend = imin(x + 8, 8 * (scp->xoff + scp->xsize));
260         yend = imin(y + 16, scp->font_size * (scp->yoff + scp->ysize));
261
262         draw_pos = sc->fbi->vaddr + y * line_width + x * pixel_size;
263
264         for (i = 0; i < (yend - y); i++) {
265                 for (j = (xend - x - 1); j >= 0; j--) {
266                         if (mouse_or_mask[i] & 1 << (15 - j))
267                                 writel(draw_pos + pixel_size * j, colormap[15]);
268                         else if (mouse_and_mask[i] & 1 << (15 - j))
269                                 writel(draw_pos + pixel_size * j, colormap[0]);
270                 }
271
272                 draw_pos += line_width;
273         }
274 }
275
276 static void
277 remove_kmsmouse(scr_stat *scp, int x, int y)
278 {
279         int col, row;
280         int pos;
281         int i;
282
283         /* erase the mouse cursor image */
284         col = x/8 - scp->xoff;
285         row = y/scp->font_size - scp->yoff;
286         pos = row*scp->xsize + col;
287         i = (col < scp->xsize - 1) ? 2 : 1;
288         (*scp->rndr->draw)(scp, pos, i, FALSE);
289         if (row < scp->ysize - 1)
290                 (*scp->rndr->draw)(scp, pos + scp->xsize, i, FALSE);
291 }
292
293 static void
294 kms_mouse(scr_stat *scp, int x, int y, int on)
295 {
296         if (on)
297                 draw_kmsmouse(scp, x, y);
298         else
299                 remove_kmsmouse(scp, x, y);
300 }
301
302 #endif /* SC_NO_CUTPASTE */