1 /*        $NetBSD: video_subr.c,v 1.13 2012/02/12 16:34:11 matt Exp $ */
2 
3 /*-
4  * Copyright (c) 2000 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by UCHIYAMA Yasushi.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: video_subr.c,v 1.13 2012/02/12 16:34:11 matt Exp $");
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/malloc.h>
38 
39 #include <machine/bootinfo.h>
40 
41 #include <dev/hpc/video_subr.h>
42 
43 #define BPP2 ({                                                                           \
44           u_int8_t bitmap;                                                      \
45           bitmap = *(volatile u_int8_t*)addr;                                   \
46           *(volatile u_int8_t*)addr =                                           \
47                     (bitmap & ~(0x3 << ((3 - (x % 4)) * 2)));                   \
48 })
49 
50 #define BPP4 ({                                                                           \
51           u_int8_t bitmap;                                                      \
52           bitmap = *(volatile u_int8_t*)addr;                                   \
53           *(volatile u_int8_t*)addr =                                           \
54                     (bitmap & ~(0xf << ((1 - (x % 2)) * 4)));                   \
55 })
56 
57 #define BPP8 ({                                                                           \
58           *(volatile u_int8_t*)addr = 0xff;                                     \
59 })
60 
61 #define BRESENHAM(a, b, c, d, func) ({                                          \
62           u_int32_t fbaddr = vc->vc_fbvaddr;                                    \
63           u_int32_t fbwidth = vc->vc_fbwidth;                                   \
64           u_int32_t fbdepth = vc->vc_fbdepth;                                   \
65           len = a, step = b -1;                                                           \
66           if (step == 0)                                                                  \
67                     return;                                                               \
68           kstep = len == 0 ? 0 : 1;                                             \
69           for (i = k = 0, j = step / 2; i <= step; i++) {                       \
70                     x = xbase c;                                                          \
71                     y = ybase d;                                                          \
72                     addr = fbaddr + (((y * fbwidth + x) * fbdepth) >> 3);       \
73                     func;                                                                 \
74                     j -= len;                                                   \
75                     while (j < 0) {                                                       \
76                               j += step;                                                  \
77                               k += kstep;                                                 \
78                     }                                                                     \
79           }                                                                               \
80 })
81 
82 #define DRAWLINE(func) ({                                                       \
83           if (x < 0) {                                                                    \
84                     if (y < 0) {                                                          \
85                               if (_y < _x) {                                              \
86                                         BRESENHAM(_y, _x, -i, -k, func);        \
87                               } else {                                          \
88                                         BRESENHAM(_x, _y, -k, -i, func);        \
89                               }                                                           \
90                     } else {                                                    \
91                               if (_y < _x) {                                              \
92                                         BRESENHAM(_y, _x, -i, +k, func);        \
93                               } else {                                          \
94                                         BRESENHAM(_x, _y, -k, +i, func);        \
95                               }                                                           \
96                     }                                                                     \
97           } else {                                                              \
98                     if (y < 0) {                                                          \
99                               if (_y < _x) {                                              \
100                                         BRESENHAM(_y, _x, +i, -k, func);        \
101                               } else {                                          \
102                                         BRESENHAM(_x, _y, +k, -i, func);        \
103                               }                                                           \
104                     } else {                                                    \
105                               if (_y < _x) {                                              \
106                                         BRESENHAM(_y, _x, +i, +k, func);        \
107                               } else {                                          \
108                                         BRESENHAM(_x, _y, +k, +i, func);        \
109                               }                                                           \
110                     }                                                                     \
111           }                                                                               \
112 })
113 
114 #define LINEFUNC(b)                                                             \
115 static void                                                                               \
116 linebpp##b(struct video_chip *vc, int x0, int y0, int x1, int y1)     \
117 {                                                                                         \
118           u_int32_t addr;                                                                 \
119           int i, j, k, len, step, kstep;                                                  \
120           int x, _x, y, _y;                                                     \
121           int xbase, ybase;                                                     \
122           x = x1 - x0;                                                                    \
123           y = y1 - y0;                                                                    \
124           _x = abs(x);                                                                    \
125           _y = abs(y);                                                                    \
126           xbase = x0;                                                                     \
127           ybase = y0;                                                                     \
128           DRAWLINE(BPP##b);                                                     \
129 }
130 
131 #define DOTFUNC(b)                                                              \
132 static void                                                                               \
133 dotbpp##b(struct video_chip *vc, int x, int y)                                  \
134 {                                                                                         \
135           u_int32_t addr;                                                                 \
136           addr = vc->vc_fbvaddr + (((y * vc->vc_fbwidth + x) *                  \
137                                          vc->vc_fbdepth) >> 3);                           \
138           BPP##b;                                                                         \
139 }
140 
141 LINEFUNC(2)
142 LINEFUNC(4)
143 LINEFUNC(8)
144 DOTFUNC(2)
145 DOTFUNC(4)
146 DOTFUNC(8)
147 static void linebpp_unimpl(struct video_chip *, int, int, int, int);
148 static void dotbpp_unimpl(struct video_chip *, int, int);
149 
150 int
cmap_work_alloc(u_int8_t ** r,u_int8_t ** g,u_int8_t ** b,u_int32_t ** rgb,int cnt)151 cmap_work_alloc(u_int8_t **r, u_int8_t **g, u_int8_t **b, u_int32_t **rgb,
152     int cnt)
153 {
154           KASSERT(LEGAL_CLUT_INDEX(cnt - 1));
155 
156 #define   ALLOC_BUF(x, bit)                                                     \
157           if (x) {                                                              \
158                     *x = malloc(cnt * sizeof(u_int ## bit ## _t),               \
159                         M_DEVBUF, M_WAITOK);                                    \
160                     if (*x == 0)                                                          \
161                               goto errout;                                                \
162           }
163           ALLOC_BUF(r, 8);
164           ALLOC_BUF(g, 8);
165           ALLOC_BUF(b, 8);
166           ALLOC_BUF(rgb, 32);
167 #undef    ALLOCBUF
168 
169           return (0);
170 errout:
171           cmap_work_free(*r, *g, *b, *rgb);
172 
173           return (ENOMEM);
174 }
175 
176 void
cmap_work_free(u_int8_t * r,u_int8_t * g,u_int8_t * b,u_int32_t * rgb)177 cmap_work_free(u_int8_t *r, u_int8_t *g, u_int8_t *b, u_int32_t *rgb)
178 {
179           if (r)
180                     free(r, M_DEVBUF);
181           if (g)
182                     free(g, M_DEVBUF);
183           if (b)
184                     free(b, M_DEVBUF);
185           if (rgb)
186                     free(rgb, M_DEVBUF);
187 }
188 
189 void
rgb24_compose(u_int32_t * rgb24,u_int8_t * r,u_int8_t * g,u_int8_t * b,int cnt)190 rgb24_compose(u_int32_t *rgb24, u_int8_t *r, u_int8_t *g, u_int8_t *b, int cnt)
191 {
192           int i;
193           KASSERT(rgb24 && r && g && b && LEGAL_CLUT_INDEX(cnt - 1));
194 
195           for (i = 0; i < cnt; i++) {
196                     *rgb24++ = RGB24(r[i], g[i], b[i]);
197           }
198 }
199 
200 void
rgb24_decompose(u_int32_t * rgb24,u_int8_t * r,u_int8_t * g,u_int8_t * b,int cnt)201 rgb24_decompose(u_int32_t *rgb24, u_int8_t *r, u_int8_t *g, u_int8_t *b,
202     int cnt)
203 {
204           int i;
205           KASSERT(rgb24 && r && g && b && LEGAL_CLUT_INDEX(cnt - 1));
206 
207           for (i = 0; i < cnt; i++) {
208                     u_int32_t rgb = *rgb24++;
209                     *r++ = (rgb >> 16) & 0xff;
210                     *g++ = (rgb >> 8) & 0xff;
211                     *b++ = rgb & 0xff;
212           }
213 }
214 
215 /*
216  * Debug routines.
217  */
218 void
video_calibration_pattern(struct video_chip * vc)219 video_calibration_pattern(struct video_chip *vc)
220 {
221           int x, y;
222 
223           x = vc->vc_fbwidth - 40;
224           y = vc->vc_fbheight - 40;
225           video_line(vc, 40, 40, x , 40);
226           video_line(vc, x , 40, x , y );
227           video_line(vc, x , y , 40, y );
228           video_line(vc, 40, y , 40, 40);
229           video_line(vc, 40, 40, x , y );
230           video_line(vc, x,  40, 40, y );
231 }
232 
233 static void
linebpp_unimpl(struct video_chip * vc,int x0,int y0,int x1,int y1)234 linebpp_unimpl(struct video_chip *vc,
235                  int x0, int y0,
236                  int x1, int y1)
237 {
238 
239           return;
240 }
241 
242 static void
dotbpp_unimpl(struct video_chip * vc,int x,int y)243 dotbpp_unimpl(struct video_chip *vc, int x, int y)
244 {
245 
246           return;
247 }
248 
249 void
video_attach_drawfunc(struct video_chip * vc)250 video_attach_drawfunc(struct video_chip *vc)
251 {
252           switch (vc->vc_fbdepth) {
253           default:
254                     vc->vc_drawline = linebpp_unimpl;
255                     vc->vc_drawdot = dotbpp_unimpl;
256                     break;
257           case 8:
258                     vc->vc_drawline = linebpp8;
259                     vc->vc_drawdot = dotbpp8;
260                     break;
261           case 4:
262                     vc->vc_drawline = linebpp4;
263                     vc->vc_drawdot = dotbpp4;
264                     break;
265           case 2:
266                     vc->vc_drawline = linebpp2;
267                     vc->vc_drawdot = dotbpp2;
268                     break;
269           }
270 }
271 
272 void
video_line(struct video_chip * vc,int x0,int y0,int x1,int y1)273 video_line(struct video_chip *vc, int x0, int y0, int x1, int y1)
274 {
275           if (vc->vc_drawline)
276                     vc->vc_drawline(vc, x0, y0, x1, y1);
277 }
278 
279 void
video_dot(struct video_chip * vc,int x,int y)280 video_dot(struct video_chip *vc, int x, int y)
281 {
282           if (vc->vc_drawdot)
283                     vc->vc_drawdot(vc, x, y);
284 }
285 
286 int
video_reverse_color(void)287 video_reverse_color(void)
288 {
289           struct {
290                     int reverse, normal;
291           } ctype[] = {
292                     { BIFB_D2_M2L_3,    BIFB_D2_M2L_0       },
293                     { BIFB_D2_M2L_3x2,  BIFB_D2_M2L_0x2     },
294                     { BIFB_D8_FF,                 BIFB_D8_00          },
295                     { BIFB_D16_FFFF,    BIFB_D16_0000,      },
296                     { -1, -1 } /* terminator */
297           }, *ctypep;
298           u_int16_t fbtype;
299 
300           /* check reverse color */
301           fbtype = bootinfo->fb_type;
302           for (ctypep = ctype; ctypep->normal != -1 ;  ctypep++) {
303                     if (fbtype == ctypep->normal) {
304                               return (0);
305                     } else if (fbtype == ctypep->reverse) {
306                               return (1);
307                     }
308           }
309           printf(": WARNING unknown frame buffer type 0x%04x.\n", fbtype);
310           return (0);
311 }
312