bivideo.c revision 1.1 1 /* $NetBSD: bivideo.c,v 1.1 2001/02/22 18:37:54 uch Exp $ */
2
3 /*-
4 * Copyright (c) 1999
5 * Shin Takemura and PocketBSD Project. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the PocketBSD project
18 * and its contributors.
19 * 4. Neither the name of the project nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 */
36 #define FBDEBUG
37 static const char _copyright[] __attribute__ ((unused)) =
38 "Copyright (c) 1999 Shin Takemura. All rights reserved.";
39 static const char _rcsid[] __attribute__ ((unused)) =
40 "$Id: bivideo.c,v 1.1 2001/02/22 18:37:54 uch Exp $";
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/device.h>
46 #include <sys/conf.h>
47 #include <sys/malloc.h>
48 #include <sys/buf.h>
49 #include <sys/ioctl.h>
50 #include <sys/reboot.h>
51
52 #include <uvm/uvm_extern.h>
53
54 #include <machine/bus.h>
55 #include <machine/autoconf.h>
56 #include <machine/bootinfo.h>
57 #include <machine/platid.h>
58 #include <machine/platid_mask.h>
59 #include <machine/config_hook.h>
60
61 #include <dev/wscons/wsconsio.h>
62 #include <dev/wscons/wsdisplayvar.h>
63
64 #include <dev/rasops/rasops.h>
65
66 #include <dev/hpc/hpcfbvar.h>
67 #include <dev/hpc/hpcfbio.h>
68 #include <dev/hpc/bivideovar.h>
69 #include <dev/hpc/hpccmapvar.h>
70
71 #define VPRINTF(arg) do { if (bootverbose) printf arg; } while(0);
72
73 /*
74 * global variables
75 */
76 int bivideo_dont_attach = 0;
77
78 /*
79 * function prototypes
80 */
81 int bivideomatch __P((struct device *, struct cfdata *, void *));
82 void bivideoattach __P((struct device *, struct device *, void *));
83 int bivideo_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
84 paddr_t bivideo_mmap __P((void *, off_t, int));
85
86 struct bivideo_softc {
87 struct device sc_dev;
88 struct hpcfb_fbconf sc_fbconf;
89 struct hpcfb_dspconf sc_dspconf;
90 void *sc_powerhook; /* power management hook */
91 int sc_powerstate;
92 #define PWRSTAT_SUSPEND (1<<0)
93 #define PWRSTAT_LCD (1<<1)
94 #define PWRSTAT_BACKLIGHT (1<<2)
95 #define PWRSTAT_ALL (0xffffffff)
96 };
97 static int bivideo_init __P((struct hpcfb_fbconf *fb));
98 static void bivideo_power __P((int, void *));
99 static void bivideo_update_powerstate __P((struct bivideo_softc *, int));
100
101
102 /*
103 * static variables
104 */
105 struct cfattach bivideo_ca = {
106 sizeof(struct bivideo_softc), bivideomatch, bivideoattach,
107 };
108 struct hpcfb_accessops bivideo_ha = {
109 bivideo_ioctl, bivideo_mmap
110 };
111
112 static int console_flag = 0;
113 static int attach_flag = 0;
114
115 /*
116 * function bodies
117 */
118 int
119 bivideomatch(parent, match, aux)
120 struct device *parent;
121 struct cfdata *match;
122 void *aux;
123 {
124 struct mainbus_attach_args *ma = aux;
125
126 if (bivideo_dont_attach ||
127 strcmp(ma->ma_name, match->cf_driver->cd_name))
128 return 0;
129
130 return (1);
131 }
132
133 void
134 bivideoattach(parent, self, aux)
135 struct device *parent, *self;
136 void *aux;
137 {
138 struct bivideo_softc *sc = (struct bivideo_softc *)self;
139 struct hpcfb_attach_args ha;
140
141 if (attach_flag) {
142 panic("%s(%d): bivideo attached twice", __FILE__, __LINE__);
143 }
144 attach_flag = 1;
145
146 printf(": ");
147 if (bivideo_init(&sc->sc_fbconf) != 0) {
148 /* just return so that hpcfb will not be attached */
149 return;
150 }
151
152 printf("pseudo video controller");
153 if (console_flag) {
154 printf(", console");
155 }
156 printf("\n");
157 printf("%s: framebuffer address: 0x%08lx\n",
158 sc->sc_dev.dv_xname, (u_long)bootinfo->fb_addr);
159
160 /* Add a suspend hook to power saving */
161 sc->sc_powerstate = 0;
162 sc->sc_powerhook = powerhook_establish(bivideo_power, sc);
163 if (sc->sc_powerhook == NULL)
164 printf("%s: WARNING: unable to establish power hook\n",
165 sc->sc_dev.dv_xname);
166
167 ha.ha_console = console_flag;
168 ha.ha_accessops = &bivideo_ha;
169 ha.ha_accessctx = sc;
170 ha.ha_curfbconf = 0;
171 ha.ha_nfbconf = 1;
172 ha.ha_fbconflist = &sc->sc_fbconf;
173 ha.ha_curdspconf = 0;
174 ha.ha_ndspconf = 1;
175 ha.ha_dspconflist = &sc->sc_dspconf;
176
177 config_found(self, &ha, hpcfbprint);
178 }
179
180 int
181 bivideo_getcnfb(fb)
182 struct hpcfb_fbconf *fb;
183 {
184 console_flag = 1;
185
186 return bivideo_init(fb);
187 }
188
189 static int
190 bivideo_init(fb)
191 struct hpcfb_fbconf *fb;
192 {
193 /*
194 * get fb settings from bootinfo
195 */
196 if (bootinfo == NULL ||
197 bootinfo->fb_addr == 0 ||
198 bootinfo->fb_line_bytes == 0 ||
199 bootinfo->fb_width == 0 ||
200 bootinfo->fb_height == 0) {
201 printf("no frame buffer infomation.\n");
202 return (-1);
203 }
204
205 /* zero fill */
206 bzero(fb, sizeof(*fb));
207
208 fb->hf_conf_index = 0; /* configuration index */
209 fb->hf_nconfs = 1; /* how many configurations */
210 strcpy(fb->hf_name, "built-in video");
211 /* frame buffer name */
212 strcpy(fb->hf_conf_name, "default");
213 /* configuration name */
214 fb->hf_height = bootinfo->fb_height;
215 fb->hf_width = bootinfo->fb_width;
216 fb->hf_baseaddr = (u_long)bootinfo->fb_addr;
217 fb->hf_offset = (u_long)bootinfo->fb_addr -
218 mips_ptob(mips_btop(bootinfo->fb_addr));
219 /* frame buffer start offset */
220 fb->hf_bytes_per_line = bootinfo->fb_line_bytes;
221 fb->hf_nplanes = 1;
222 fb->hf_bytes_per_plane = bootinfo->fb_height *
223 bootinfo->fb_line_bytes;
224
225 fb->hf_access_flags |= HPCFB_ACCESS_BYTE;
226 fb->hf_access_flags |= HPCFB_ACCESS_WORD;
227 fb->hf_access_flags |= HPCFB_ACCESS_DWORD;
228
229 switch (bootinfo->fb_type) {
230 /*
231 * gray scale
232 */
233 case BIFB_D2_M2L_3:
234 case BIFB_D2_M2L_3x2:
235 fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
236 /* fall through */
237 case BIFB_D2_M2L_0:
238 case BIFB_D2_M2L_0x2:
239 fb->hf_class = HPCFB_CLASS_GRAYSCALE;
240 fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
241 fb->hf_pack_width = 8;
242 fb->hf_pixels_per_pack = 4;
243 fb->hf_pixel_width = 2;
244 fb->hf_class_data_length = sizeof(struct hf_gray_tag);
245 fb->hf_u.hf_gray.hf_flags = 0; /* reserved for future use */
246 break;
247
248 case BIFB_D4_M2L_F:
249 case BIFB_D4_M2L_Fx2:
250 fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
251 /* fall through */
252 case BIFB_D4_M2L_0:
253 case BIFB_D4_M2L_0x2:
254 fb->hf_class = HPCFB_CLASS_GRAYSCALE;
255 fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
256 fb->hf_pack_width = 8;
257 fb->hf_pixels_per_pack = 2;
258 fb->hf_pixel_width = 4;
259 fb->hf_class_data_length = sizeof(struct hf_gray_tag);
260 fb->hf_u.hf_gray.hf_flags = 0; /* reserved for future use */
261 break;
262
263 /*
264 * indexed color
265 */
266 case BIFB_D8_FF:
267 fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
268 /* fall through */
269 case BIFB_D8_00:
270 fb->hf_class = HPCFB_CLASS_INDEXCOLOR;
271 fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
272 fb->hf_pack_width = 8;
273 fb->hf_pixels_per_pack = 1;
274 fb->hf_pixel_width = 8;
275 fb->hf_class_data_length = sizeof(struct hf_indexed_tag);
276 fb->hf_u.hf_indexed.hf_flags = 0; /* reserved for future use */
277 break;
278
279 /*
280 * RGB color
281 */
282 case BIFB_D16_FFFF:
283 fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
284 /* fall through */
285 case BIFB_D16_0000:
286 fb->hf_class = HPCFB_CLASS_RGBCOLOR;
287 fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
288 #if BYTE_ORDER == LITTLE_ENDIAN
289 fb->hf_swap_flags = HPCFB_SWAP_BYTE;
290 #endif
291 fb->hf_pack_width = 16;
292 fb->hf_pixels_per_pack = 1;
293 fb->hf_pixel_width = 16;
294
295 fb->hf_class_data_length = sizeof(struct hf_rgb_tag);
296 fb->hf_u.hf_rgb.hf_flags = 0; /* reserved for future use */
297
298 fb->hf_u.hf_rgb.hf_red_width = 5;
299 fb->hf_u.hf_rgb.hf_red_shift = 11;
300 fb->hf_u.hf_rgb.hf_green_width = 6;
301 fb->hf_u.hf_rgb.hf_green_shift = 5;
302 fb->hf_u.hf_rgb.hf_blue_width = 5;
303 fb->hf_u.hf_rgb.hf_blue_shift = 0;
304 fb->hf_u.hf_rgb.hf_alpha_width = 0;
305 fb->hf_u.hf_rgb.hf_alpha_shift = 0;
306 break;
307
308 default:
309 printf("unsupported type %d.\n", bootinfo->fb_type);
310 return (-1);
311 break;
312 }
313
314 return (0); /* no error */
315 }
316
317 static void
318 bivideo_power(why, arg)
319 int why;
320 void *arg;
321 {
322 struct bivideo_softc *sc = arg;
323
324 switch (why) {
325 case PWR_SUSPEND:
326 case PWR_STANDBY:
327 sc->sc_powerstate |= PWRSTAT_SUSPEND;
328 bivideo_update_powerstate(sc, PWRSTAT_ALL);
329 break;
330 case PWR_RESUME:
331 sc->sc_powerstate &= ~PWRSTAT_SUSPEND;
332 bivideo_update_powerstate(sc, PWRSTAT_ALL);
333 break;
334 }
335 }
336
337 static void
338 bivideo_update_powerstate(sc, updates)
339 struct bivideo_softc *sc;
340 int updates;
341 {
342 if (updates & PWRSTAT_LCD)
343 config_hook_call(CONFIG_HOOK_POWERCONTROL,
344 CONFIG_HOOK_POWERCONTROL_LCD,
345 (void*)!(sc->sc_powerstate & PWRSTAT_SUSPEND));
346
347 if (updates & PWRSTAT_BACKLIGHT)
348 config_hook_call(CONFIG_HOOK_POWERCONTROL,
349 CONFIG_HOOK_POWERCONTROL_LCDLIGHT,
350 (void*)(!(sc->sc_powerstate & PWRSTAT_SUSPEND) &&
351 (sc->sc_powerstate & PWRSTAT_BACKLIGHT)));
352 }
353
354 int
355 bivideo_ioctl(v, cmd, data, flag, p)
356 void *v;
357 u_long cmd;
358 caddr_t data;
359 int flag;
360 struct proc *p;
361 {
362 struct bivideo_softc *sc = (struct bivideo_softc *)v;
363 struct hpcfb_fbconf *fbconf;
364 struct hpcfb_dspconf *dspconf;
365 struct wsdisplay_cmap *cmap;
366 struct wsdisplay_param *dispparam;
367
368 switch (cmd) {
369 case WSDISPLAYIO_GETCMAP:
370 cmap = (struct wsdisplay_cmap*)data;
371
372 if (sc->sc_fbconf.hf_class != HPCFB_CLASS_INDEXCOLOR ||
373 sc->sc_fbconf.hf_pack_width != 8 ||
374 256 <= cmap->index ||
375 256 < (cmap->index + cmap->count))
376 return (EINVAL);
377
378 if (!uvm_useracc(cmap->red, cmap->count, B_WRITE) ||
379 !uvm_useracc(cmap->green, cmap->count, B_WRITE) ||
380 !uvm_useracc(cmap->blue, cmap->count, B_WRITE))
381 return (EFAULT);
382
383 copyout(&bivideo_cmap_r[cmap->index], cmap->red, cmap->count);
384 copyout(&bivideo_cmap_g[cmap->index], cmap->green,cmap->count);
385 copyout(&bivideo_cmap_b[cmap->index], cmap->blue, cmap->count);
386
387 return (0);
388
389 case WSDISPLAYIO_PUTCMAP:
390 /*
391 * This driver can't set color map.
392 */
393 return (EINVAL);
394
395 case WSDISPLAYIO_GETPARAM:
396 dispparam = (struct wsdisplay_param*)data;
397 switch (dispparam->param) {
398 case WSDISPLAYIO_PARAM_BACKLIGHT:
399 dispparam->min = 0;
400 dispparam->max = 1;
401 dispparam->curval =
402 (sc->sc_powerstate & PWRSTAT_BACKLIGHT) ? 1 : 0;
403 VPRINTF(("bivideo_ioctl: GETPARAM:BACKLIGHT:%d\n",
404 dispparam->curval));
405 break;
406 case WSDISPLAYIO_PARAM_CONTRAST:
407 VPRINTF(("bivideo_ioctl: GETPARAM:CONTRAST\n"));
408 return (EINVAL);
409 case WSDISPLAYIO_PARAM_BRIGHTNESS:
410 VPRINTF(("bivideo_ioctl: GETPARAM:BRIGHTNESS\n"));
411 return (EINVAL);
412 default:
413 return (EINVAL);
414 }
415 return (0);
416
417 case WSDISPLAYIO_SETPARAM:
418 dispparam = (struct wsdisplay_param*)data;
419 switch (dispparam->param) {
420 case WSDISPLAYIO_PARAM_BACKLIGHT:
421 if (dispparam->curval < 0 ||
422 1 < dispparam->curval)
423 return (EINVAL);
424 if (dispparam->curval == 0)
425 sc->sc_powerstate &= ~PWRSTAT_BACKLIGHT;
426 else
427 sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
428 bivideo_update_powerstate(sc, PWRSTAT_BACKLIGHT);
429 VPRINTF(("bivideo_ioctl: SETPARAM:BACKLIGHT:%d\n",
430 (sc->sc_powerstate & PWRSTAT_BACKLIGHT)?1:0));
431 break;
432 case WSDISPLAYIO_PARAM_CONTRAST:
433 VPRINTF(("bivideo_ioctl: SETPARAM:CONTRAST\n"));
434 return (EINVAL);
435 case WSDISPLAYIO_PARAM_BRIGHTNESS:
436 VPRINTF(("mq200_ioctl: SETPARAM:BRIGHTNESS\n"));
437 return (EINVAL);
438 default:
439 return (EINVAL);
440 }
441 return (0);
442
443 case HPCFBIO_GCONF:
444 fbconf = (struct hpcfb_fbconf *)data;
445 if (fbconf->hf_conf_index != 0 &&
446 fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
447 return (EINVAL);
448 }
449 *fbconf = sc->sc_fbconf; /* structure assignment */
450 return (0);
451 case HPCFBIO_SCONF:
452 fbconf = (struct hpcfb_fbconf *)data;
453 if (fbconf->hf_conf_index != 0 &&
454 fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
455 return (EINVAL);
456 }
457 /*
458 * nothing to do because we have only one configration
459 */
460 return (0);
461 case HPCFBIO_GDSPCONF:
462 dspconf = (struct hpcfb_dspconf *)data;
463 if ((dspconf->hd_unit_index != 0 &&
464 dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
465 (dspconf->hd_conf_index != 0 &&
466 dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
467 return (EINVAL);
468 }
469 *dspconf = sc->sc_dspconf; /* structure assignment */
470 return (0);
471 case HPCFBIO_SDSPCONF:
472 dspconf = (struct hpcfb_dspconf *)data;
473 if ((dspconf->hd_unit_index != 0 &&
474 dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
475 (dspconf->hd_conf_index != 0 &&
476 dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
477 return (EINVAL);
478 }
479 /*
480 * nothing to do
481 * because we have only one unit and one configration
482 */
483 return (0);
484 case HPCFBIO_GOP:
485 case HPCFBIO_SOP:
486 /*
487 * curently not implemented...
488 */
489 return (EINVAL);
490 }
491
492 return (ENOTTY);
493 }
494
495 paddr_t
496 bivideo_mmap(ctx, offset, prot)
497 void *ctx;
498 off_t offset;
499 int prot;
500 {
501 struct bivideo_softc *sc = (struct bivideo_softc *)ctx;
502
503 if (offset < 0 ||
504 (sc->sc_fbconf.hf_bytes_per_plane +
505 sc->sc_fbconf.hf_offset) < offset)
506 return -1;
507
508 return mips_btop((u_long)bootinfo->fb_addr + offset);
509 }
510