xref: /netbsd/sys/arch/hpcmips/dev/plumvideo.c (revision 6550d01e)
1 /*	$NetBSD: plumvideo.c,v 1.40 2009/03/18 10:22:28 cegger Exp $ */
2 
3 /*-
4  * Copyright (c) 1999-2002 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: plumvideo.c,v 1.40 2009/03/18 10:22:28 cegger Exp $");
34 
35 #undef PLUMVIDEODEBUG
36 
37 #include "plumohci.h" /* Plum2 OHCI shared memory allocated on V-RAM */
38 #include "bivideo.h"
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/device.h>
43 
44 #include <sys/ioctl.h>
45 #include <sys/buf.h>
46 #include <uvm/uvm_extern.h>
47 
48 #include <dev/cons.h> /* consdev */
49 
50 #include <mips/cache.h>
51 
52 #include <machine/bus.h>
53 #include <machine/intr.h>
54 #include <machine/config_hook.h>
55 
56 #include <hpcmips/tx/tx39var.h>
57 #include <hpcmips/dev/plumvar.h>
58 #include <hpcmips/dev/plumicuvar.h>
59 #include <hpcmips/dev/plumpowervar.h>
60 #include <hpcmips/dev/plumvideoreg.h>
61 
62 #include <machine/bootinfo.h>
63 
64 #include <dev/wscons/wsdisplayvar.h>
65 #include <dev/rasops/rasops.h>
66 #include <dev/hpc/video_subr.h>
67 
68 #include <dev/wscons/wsconsio.h>
69 #include <dev/hpc/hpcfbvar.h>
70 #include <dev/hpc/hpcfbio.h>
71 #if NBIVIDEO > 0
72 #include <dev/hpc/bivideovar.h>
73 #endif
74 
75 #ifdef PLUMVIDEODEBUG
76 int	plumvideo_debug = 1;
77 #define	DPRINTF(arg) if (plumvideo_debug) printf arg;
78 #define	DPRINTFN(n, arg) if (plumvideo_debug > (n)) printf arg;
79 #else
80 #define	DPRINTF(arg)
81 #define DPRINTFN(n, arg)
82 #endif
83 
84 struct plumvideo_softc {
85 	struct device sc_dev;
86 	tx_chipset_tag_t sc_tc;
87 	plum_chipset_tag_t sc_pc;
88 
89 	void *sc_powerhook;	/* power management hook */
90 	int sc_console;
91 
92 	int sc_backlight;
93 	int sc_brightness;
94 	int sc_max_brightness;
95 
96 	/* control register */
97 	bus_space_tag_t sc_regt;
98 	bus_space_handle_t sc_regh;
99 	/* frame buffer */
100 	bus_space_tag_t sc_fbiot;
101 	bus_space_handle_t sc_fbioh;
102 	/* clut buffer (8bpp only) */
103 	bus_space_tag_t sc_clutiot;
104 	bus_space_handle_t sc_clutioh;
105 	/* bitblt */
106 	bus_space_tag_t sc_bitbltt;
107 	bus_space_handle_t sc_bitblth;
108 
109 	struct video_chip sc_chip;
110 	struct hpcfb_fbconf sc_fbconf;
111 	struct hpcfb_dspconf sc_dspconf;
112 };
113 
114 int	plumvideo_match(struct device*, struct cfdata*, void*);
115 void	plumvideo_attach(struct device*, struct device*, void*);
116 
117 int	plumvideo_ioctl(void *, u_long, void *, int, struct lwp *);
118 paddr_t	plumvideo_mmap(void *, off_t, int);
119 
120 CFATTACH_DECL(plumvideo, sizeof(struct plumvideo_softc),
121     plumvideo_match, plumvideo_attach, NULL, NULL);
122 
123 struct hpcfb_accessops plumvideo_ha = {
124 	plumvideo_ioctl, plumvideo_mmap
125 };
126 
127 int	plumvideo_power(void *, int, long, void *);
128 
129 int	plumvideo_init(struct plumvideo_softc *, int *);
130 void	plumvideo_hpcfbinit(struct plumvideo_softc *, int);
131 
132 void	plumvideo_clut_default(struct plumvideo_softc *);
133 void	plumvideo_clut_set(struct plumvideo_softc *, u_int32_t *, int, int);
134 void	plumvideo_clut_get(struct plumvideo_softc *, u_int32_t *, int, int);
135 void	__plumvideo_clut_access(struct plumvideo_softc *, u_int32_t *, int, int,
136 	    void (*)(bus_space_tag_t, bus_space_handle_t, u_int32_t *, int, int));
137 static void _flush_cache(void) __attribute__((__unused__)); /* !!! */
138 static void plumvideo_init_backlight(struct plumvideo_softc *);
139 static void plumvideo_backlight(struct plumvideo_softc *, int);
140 static void plumvideo_brightness(struct plumvideo_softc *, int);
141 
142 #ifdef PLUMVIDEODEBUG
143 void	plumvideo_dump(struct plumvideo_softc*);
144 #endif
145 
146 #define ON	1
147 #define OFF	0
148 
149 int
150 plumvideo_match(struct device *parent, struct cfdata *cf, void *aux)
151 {
152 	/*
153 	 * VRAM area also uses as UHOSTC shared RAM.
154 	 */
155 	return (2); /* 1st attach group */
156 }
157 
158 void
159 plumvideo_attach(struct device *parent, struct device *self, void *aux)
160 {
161 	struct plum_attach_args *pa = aux;
162 	struct plumvideo_softc *sc = (void*)self;
163 	struct hpcfb_attach_args ha;
164 	int console, reverse_flag;
165 
166 	sc->sc_console = console = cn_tab ? 0 : 1;
167 	sc->sc_pc	= pa->pa_pc;
168 	sc->sc_regt	= pa->pa_regt;
169 	sc->sc_fbiot = sc->sc_clutiot = sc->sc_bitbltt  = pa->pa_iot;
170 
171 	printf(": ");
172 
173 	/* map register area */
174 	if (bus_space_map(sc->sc_regt, PLUM_VIDEO_REGBASE,
175 	    PLUM_VIDEO_REGSIZE, 0, &sc->sc_regh)) {
176 		printf("register map failed\n");
177 		return;
178 	}
179 
180 	/* initialize backlight and brightness values */
181 	plumvideo_init_backlight(sc);
182 
183 	/* power control */
184 	plumvideo_power(sc, 0, 0,
185 	    (void *)(console ? PWR_RESUME : PWR_SUSPEND));
186 	/* Add a hard power hook to power saving */
187 	sc->sc_powerhook = config_hook(CONFIG_HOOK_PMEVENT,
188 	    CONFIG_HOOK_PMEVENT_HARDPOWER,
189 	    CONFIG_HOOK_SHARE,
190 	    plumvideo_power, sc);
191 	if (sc->sc_powerhook == 0)
192 		printf("WARNING unable to establish hard power hook");
193 
194 	/*
195 	 *  Initialize LCD controller
196 	 *	map V-RAM area.
197 	 *	reinstall bootinfo structure.
198 	 *	some OHCI shared-buffer hack. XXX
199 	 */
200 	if (plumvideo_init(sc, &reverse_flag) != 0)
201 		return;
202 
203 	printf("\n");
204 
205 	/* Attach frame buffer device */
206 	plumvideo_hpcfbinit(sc, reverse_flag);
207 
208 #ifdef PLUMVIDEODEBUG
209 	if (plumvideo_debug > 0)
210 		plumvideo_dump(sc);
211 	/* attach debug draw routine (debugging use) */
212 	video_attach_drawfunc(&sc->sc_chip);
213 	tx_conf_register_video(sc->sc_pc->pc_tc, &sc->sc_chip);
214 #endif /* PLUMVIDEODEBUG */
215 
216 	if(console && hpcfb_cnattach(&sc->sc_fbconf) != 0) {
217 		panic("plumvideo_attach: can't init fb console");
218 	}
219 
220 	ha.ha_console = console;
221 	ha.ha_accessops = &plumvideo_ha;
222 	ha.ha_accessctx = sc;
223 	ha.ha_curfbconf = 0;
224 	ha.ha_nfbconf = 1;
225 	ha.ha_fbconflist = &sc->sc_fbconf;
226 	ha.ha_curdspconf = 0;
227 	ha.ha_ndspconf = 1;
228 	ha.ha_dspconflist = &sc->sc_dspconf;
229 
230 	config_found(self, &ha, hpcfbprint);
231 #if NBIVIDEO > 0
232 	/* bivideo is no longer need */
233 	bivideo_dont_attach = 1;
234 #endif /* NBIVIDEO > 0 */
235 }
236 
237 void
238 plumvideo_hpcfbinit(struct plumvideo_softc *sc, int reverse_flag)
239 {
240 	struct hpcfb_fbconf *fb = &sc->sc_fbconf;
241 	struct video_chip *chip = &sc->sc_chip;
242 	vaddr_t fbvaddr = (vaddr_t)sc->sc_fbioh;
243 	int height = chip->vc_fbheight;
244 	int width = chip->vc_fbwidth;
245 	int depth = chip->vc_fbdepth;
246 
247 	memset(fb, 0, sizeof(struct hpcfb_fbconf));
248 
249 	fb->hf_conf_index	= 0;	/* configuration index		*/
250 	fb->hf_nconfs		= 1;   	/* how many configurations	*/
251 	strncpy(fb->hf_name, "PLUM built-in video", HPCFB_MAXNAMELEN);
252 	/* frame buffer name		*/
253 	strncpy(fb->hf_conf_name, "LCD", HPCFB_MAXNAMELEN);
254 	/* configuration name		*/
255 	fb->hf_height		= height;
256 	fb->hf_width		= width;
257 	fb->hf_baseaddr		= (u_long)fbvaddr;
258 	fb->hf_offset		= (u_long)fbvaddr - mips_ptob(mips_btop(fbvaddr));
259 	/* frame buffer start offset   	*/
260 	fb->hf_bytes_per_line	= (width * depth) / NBBY;
261 	fb->hf_nplanes		= 1;
262 	fb->hf_bytes_per_plane	= height * fb->hf_bytes_per_line;
263 
264 	fb->hf_access_flags |= HPCFB_ACCESS_BYTE;
265 	fb->hf_access_flags |= HPCFB_ACCESS_WORD;
266 	fb->hf_access_flags |= HPCFB_ACCESS_DWORD;
267 	if (reverse_flag)
268 		fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
269 
270 	switch (depth) {
271 	default:
272 		panic("plumvideo_hpcfbinit: not supported color depth");
273 		/* NOTREACHED */
274 	case 16:
275 		fb->hf_class = HPCFB_CLASS_RGBCOLOR;
276 		fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
277 		fb->hf_pack_width = 16;
278 		fb->hf_pixels_per_pack = 1;
279 		fb->hf_pixel_width = 16;
280 
281 		fb->hf_class_data_length = sizeof(struct hf_rgb_tag);
282 		/* reserved for future use */
283 		fb->hf_u.hf_rgb.hf_flags = 0;
284 
285 		fb->hf_u.hf_rgb.hf_red_width = 5;
286 		fb->hf_u.hf_rgb.hf_red_shift = 11;
287 		fb->hf_u.hf_rgb.hf_green_width = 6;
288 		fb->hf_u.hf_rgb.hf_green_shift = 5;
289 		fb->hf_u.hf_rgb.hf_blue_width = 5;
290 		fb->hf_u.hf_rgb.hf_blue_shift = 0;
291 		fb->hf_u.hf_rgb.hf_alpha_width = 0;
292 		fb->hf_u.hf_rgb.hf_alpha_shift = 0;
293 		break;
294 
295 	case 8:
296 		fb->hf_class = HPCFB_CLASS_INDEXCOLOR;
297 		fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
298 		fb->hf_pack_width = 8;
299 		fb->hf_pixels_per_pack = 1;
300 		fb->hf_pixel_width = 8;
301 		fb->hf_class_data_length = sizeof(struct hf_indexed_tag);
302 		/* reserved for future use */
303 		fb->hf_u.hf_indexed.hf_flags = 0;
304 		break;
305 	}
306 }
307 
308 int
309 plumvideo_init(struct plumvideo_softc *sc, int *reverse)
310 {
311 	struct video_chip *chip = &sc->sc_chip;
312 	bus_space_tag_t regt = sc->sc_regt;
313 	bus_space_handle_t regh = sc->sc_regh;
314 	plumreg_t reg;
315 	size_t vram_size;
316 	int bpp, width, height, vram_pitch;
317 
318 	*reverse = video_reverse_color();
319 	chip->vc_v = sc->sc_pc->pc_tc;
320 #if notyet
321 	/* map BitBlt area */
322 	if (bus_space_map(sc->sc_bitbltt,
323 	    PLUM_VIDEO_BITBLT_IOBASE,
324 	    PLUM_VIDEO_BITBLT_IOSIZE, 0,
325 	    &sc->sc_bitblth)) {
326 		printf(": BitBlt map failed\n");
327 		return (1);
328 	}
329 #endif
330 	reg = plum_conf_read(regt, regh, PLUM_VIDEO_PLGMD_REG);
331 
332 	switch (reg & PLUM_VIDEO_PLGMD_GMODE_MASK) {
333 	case PLUM_VIDEO_PLGMD_16BPP:
334 #if NPLUMOHCI > 0 /* reserve V-RAM area for USB OHCI */
335 		/* FALLTHROUGH */
336 #else
337 		bpp = 16;
338 		break;
339 #endif
340 	default:
341 		bootinfo->fb_type = *reverse ? BIFB_D8_FF : BIFB_D8_00;
342 		reg &= ~PLUM_VIDEO_PLGMD_GMODE_MASK;
343 		plum_conf_write(regt, regh, PLUM_VIDEO_PLGMD_REG, reg);
344 		reg |= PLUM_VIDEO_PLGMD_8BPP;
345 		plum_conf_write(regt, regh, PLUM_VIDEO_PLGMD_REG, reg);
346 #if notyet
347 		/* change BitBlt color depth */
348 		plum_conf_write(sc->sc_bitbltt, sc->sc_bitblth, 0x8, 0);
349 #endif
350 		/* FALLTHROUGH */
351 	case PLUM_VIDEO_PLGMD_8BPP:
352 		bpp = 8;
353 		break;
354 	}
355 	chip->vc_fbdepth = bpp;
356 
357 	/*
358 	 * Get display size from WindowsCE setted.
359 	 */
360 	chip->vc_fbwidth = width = bootinfo->fb_width =
361 	    plum_conf_read(regt, regh, PLUM_VIDEO_PLHPX_REG) + 1;
362 	chip->vc_fbheight = height = bootinfo->fb_height =
363 	    plum_conf_read(regt, regh, PLUM_VIDEO_PLVT_REG) -
364 	    plum_conf_read(regt, regh, PLUM_VIDEO_PLVDS_REG);
365 
366 	/*
367 	 * set line byte length to bootinfo and LCD controller.
368 	 */
369 	vram_pitch = bootinfo->fb_line_bytes = (width * bpp) / NBBY;
370 	plum_conf_write(regt, regh, PLUM_VIDEO_PLPIT1_REG, vram_pitch);
371 	plum_conf_write(regt, regh, PLUM_VIDEO_PLPIT2_REG,
372 	    vram_pitch & PLUM_VIDEO_PLPIT2_MASK);
373 	plum_conf_write(regt, regh, PLUM_VIDEO_PLOFS_REG, vram_pitch);
374 
375 	/*
376 	 * boot messages and map CLUT(if any).
377 	 */
378 	printf("display mode: ");
379 	switch (bpp) {
380 	default:
381 		printf("disabled ");
382 		break;
383 	case 8:
384 		printf("8bpp ");
385 		/* map CLUT area */
386 		if (bus_space_map(sc->sc_clutiot,
387 		    PLUM_VIDEO_CLUT_LCD_IOBASE,
388 		    PLUM_VIDEO_CLUT_LCD_IOSIZE, 0,
389 		    &sc->sc_clutioh)) {
390 			printf(": CLUT map failed\n");
391 			return (1);
392 		}
393 		/* install default CLUT */
394 		plumvideo_clut_default(sc);
395 		break;
396 	case 16:
397 		printf("16bpp ");
398 		break;
399 	}
400 
401 	/*
402 	 * calcurate frame buffer size.
403 	 */
404 	reg = plum_conf_read(regt, regh, PLUM_VIDEO_PLGMD_REG);
405 	vram_size = (width * height * bpp) / NBBY;
406 	vram_size = mips_round_page(vram_size);
407 	chip->vc_fbsize = vram_size;
408 
409 	/*
410 	 * map V-RAM area.
411 	 */
412 	if (bus_space_map(sc->sc_fbiot, PLUM_VIDEO_VRAM_IOBASE,
413 	    vram_size, 0, &sc->sc_fbioh)) {
414 		printf(": V-RAM map failed\n");
415 		return (1);
416 	}
417 
418 	bootinfo->fb_addr = (unsigned char *)sc->sc_fbioh;
419 	chip->vc_fbvaddr = (vaddr_t)sc->sc_fbioh;
420 	chip->vc_fbpaddr = PLUM_VIDEO_VRAM_IOBASE_PHYSICAL;
421 
422 	return (0);
423 }
424 
425 int
426 plumvideo_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
427 {
428 	struct plumvideo_softc *sc = (struct plumvideo_softc *)v;
429 	struct hpcfb_fbconf *fbconf;
430 	struct hpcfb_dspconf *dspconf;
431 	struct wsdisplay_cmap *cmap;
432 	struct wsdisplay_param *dispparam;
433 	u_int8_t *r, *g, *b;
434 	u_int32_t *rgb;
435 	int idx, error;
436 	size_t cnt;
437 
438 	switch (cmd) {
439 	case WSDISPLAYIO_GETCMAP:
440 		cmap = (struct wsdisplay_cmap *)data;
441 		cnt = cmap->count;
442 		idx = cmap->index;
443 
444 		if (sc->sc_fbconf.hf_class != HPCFB_CLASS_INDEXCOLOR ||
445 		    sc->sc_fbconf.hf_pack_width != 8 ||
446 		    !LEGAL_CLUT_INDEX(idx) ||
447 		    !LEGAL_CLUT_INDEX(idx + cnt - 1)) {
448 			return (EINVAL);
449 		}
450 
451 		error = cmap_work_alloc(&r, &g, &b, &rgb, cnt);
452 		if (error)
453 			goto out;
454 		plumvideo_clut_get(sc, rgb, idx, cnt);
455 		rgb24_decompose(rgb, r, g, b, cnt);
456 
457 		error = copyout(r, cmap->red, cnt);
458 		if (error)
459 			goto out;
460 		error = copyout(g, cmap->green, cnt);
461 		if (error)
462 			goto out;
463 		error = copyout(b, cmap->blue, cnt);
464 
465 out:
466 		cmap_work_free(r, g, b, rgb);
467 		return error;
468 
469 	case WSDISPLAYIO_PUTCMAP:
470 		cmap = (struct wsdisplay_cmap *)data;
471 		cnt = cmap->count;
472 		idx = cmap->index;
473 
474 		if (sc->sc_fbconf.hf_class != HPCFB_CLASS_INDEXCOLOR ||
475 		    sc->sc_fbconf.hf_pack_width != 8 ||
476 		    !LEGAL_CLUT_INDEX(idx) ||
477 		    !LEGAL_CLUT_INDEX(idx + cnt - 1)) {
478 			return (EINVAL);
479 		}
480 
481 		error = cmap_work_alloc(&r, &g, &b, &rgb, cnt);
482 		if (error)
483 			goto out;
484 		error = copyin(cmap->red, r, cnt);
485 		if (error)
486 			goto out;
487 		error = copyin(cmap->green, g, cnt);
488 		if (error)
489 			goto out;
490 		error = copyin(cmap->blue, b, cnt);
491 		if (error)
492 			goto out;
493 		rgb24_compose(rgb, r, g, b, cnt);
494 		plumvideo_clut_set(sc, rgb, idx, cnt);
495 		goto out;
496 
497 	case WSDISPLAYIO_SVIDEO:
498 		if (*(int *)data == WSDISPLAYIO_VIDEO_OFF)
499 			plumvideo_backlight(sc, 0);
500 		else
501 			plumvideo_backlight(sc, 1);
502 		return 0;
503 
504 	case WSDISPLAYIO_GVIDEO:
505 		*(int *)data = sc->sc_backlight ?
506 			WSDISPLAYIO_VIDEO_ON : WSDISPLAYIO_VIDEO_OFF;
507 		return 0;
508 
509 	case WSDISPLAYIO_GETPARAM:
510 		dispparam = (struct wsdisplay_param *)data;
511 		switch (dispparam->param) {
512 		case WSDISPLAYIO_PARAM_BACKLIGHT:
513 			dispparam->min = 0;
514 			dispparam->max = 1;
515 			dispparam->curval = sc->sc_backlight;
516 			break;
517 		case WSDISPLAYIO_PARAM_BRIGHTNESS:
518 			if (sc->sc_max_brightness <= 0)
519 				return EINVAL;
520 			dispparam->min = 0;
521 			dispparam->max = sc->sc_max_brightness;
522 			dispparam->curval = sc->sc_brightness;
523 			break;
524 		default:
525 			return EINVAL;
526 		}
527 		return 0;
528 
529 	case WSDISPLAYIO_SETPARAM:
530 		dispparam = (struct wsdisplay_param * )data;
531 		switch (dispparam->param) {
532 		case WSDISPLAYIO_PARAM_BACKLIGHT:
533 			if (dispparam->curval < 0 || 1 < dispparam->curval)
534 				return EINVAL;
535 			plumvideo_backlight(sc, dispparam->curval);
536 			break;
537 		case WSDISPLAYIO_PARAM_BRIGHTNESS:
538 			if (sc->sc_max_brightness <= 0)
539 				return EINVAL;
540 			if (dispparam->curval < 0 ||
541 			    sc->sc_max_brightness < dispparam->curval)
542 				return EINVAL;
543 			plumvideo_brightness(sc, dispparam->curval);
544 			break;
545 		default:
546 			return EINVAL;
547 		}
548 		return 0;
549 
550 	case HPCFBIO_GCONF:
551 		fbconf = (struct hpcfb_fbconf *)data;
552 		if (fbconf->hf_conf_index != 0 &&
553 		    fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
554 			return (EINVAL);
555 		}
556 		*fbconf = sc->sc_fbconf;	/* structure assignment */
557 		return (0);
558 
559 	case HPCFBIO_SCONF:
560 		fbconf = (struct hpcfb_fbconf *)data;
561 		if (fbconf->hf_conf_index != 0 &&
562 		    fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
563 			return (EINVAL);
564 		}
565 		/*
566 		 * nothing to do because we have only one configuration
567 		 */
568 		return (0);
569 
570 	case HPCFBIO_GDSPCONF:
571 		dspconf = (struct hpcfb_dspconf *)data;
572 		if ((dspconf->hd_unit_index != 0 &&
573 		    dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
574 		    (dspconf->hd_conf_index != 0 &&
575 			dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
576 			return (EINVAL);
577 		}
578 		*dspconf = sc->sc_dspconf;	/* structure assignment */
579 		return (0);
580 
581 	case HPCFBIO_SDSPCONF:
582 		dspconf = (struct hpcfb_dspconf *)data;
583 		if ((dspconf->hd_unit_index != 0 &&
584 		    dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
585 		    (dspconf->hd_conf_index != 0 &&
586 			dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
587 			return (EINVAL);
588 		}
589 		/*
590 		 * nothing to do
591 		 * because we have only one unit and one configuration
592 		 */
593 		return (0);
594 
595 	case HPCFBIO_GOP:
596 	case HPCFBIO_SOP:
597 		/* XXX not implemented yet */
598 		return (EINVAL);
599 	}
600 
601 	return (EPASSTHROUGH);
602 }
603 
604 paddr_t
605 plumvideo_mmap(void *ctx, off_t offset, int prot)
606 {
607 	struct plumvideo_softc *sc = (struct plumvideo_softc *)ctx;
608 
609 	if (offset < 0 || (sc->sc_fbconf.hf_bytes_per_plane +
610 	    sc->sc_fbconf.hf_offset) <  offset) {
611 		return (-1);
612 	}
613 
614 	return (mips_btop(PLUM_VIDEO_VRAM_IOBASE_PHYSICAL + offset));
615 }
616 
617 static void __plumvideo_clut_get(bus_space_tag_t, bus_space_handle_t,
618     u_int32_t *, int, int);
619 static void __plumvideo_clut_get(bus_space_tag_t iot, bus_space_handle_t ioh,
620     u_int32_t *rgb, int beg, int cnt)
621 {
622 	int i;
623 
624 	for (i = 0, beg *= 4; i < cnt; i++, beg += 4) {
625 		*rgb++ = bus_space_read_4(iot, ioh, beg) &
626 		    0x00ffffff;
627 	}
628 }
629 
630 void
631 plumvideo_clut_get(struct plumvideo_softc *sc, u_int32_t *rgb, int beg,
632     int cnt)
633 {
634 	KASSERT(rgb);
635 	KASSERT(LEGAL_CLUT_INDEX(beg));
636 	KASSERT(LEGAL_CLUT_INDEX(beg + cnt - 1));
637 	__plumvideo_clut_access(sc, rgb, beg, cnt, __plumvideo_clut_get);
638 }
639 
640 static void __plumvideo_clut_set(bus_space_tag_t, bus_space_handle_t,
641     u_int32_t *, int, int);
642 static void __plumvideo_clut_set(bus_space_tag_t iot, bus_space_handle_t ioh,
643     u_int32_t *rgb, int beg, int cnt)
644 {
645 	int i;
646 
647 	for (i = 0, beg *= 4; i < cnt; i++, beg +=4) {
648 		bus_space_write_4(iot, ioh, beg,
649 		    *rgb++ & 0x00ffffff);
650 	}
651 }
652 
653 void
654 plumvideo_clut_set(struct plumvideo_softc *sc, u_int32_t *rgb, int beg,
655     int cnt)
656 {
657 	KASSERT(rgb);
658 	KASSERT(LEGAL_CLUT_INDEX(beg));
659 	KASSERT(LEGAL_CLUT_INDEX(beg + cnt - 1));
660 	__plumvideo_clut_access(sc, rgb, beg, cnt, __plumvideo_clut_set);
661 }
662 
663 static void __plumvideo_clut_default(bus_space_tag_t, bus_space_handle_t,
664     u_int32_t *, int, int);
665 static void __plumvideo_clut_default(bus_space_tag_t iot, bus_space_handle_t ioh,
666     u_int32_t *rgb, int beg, int cnt)
667 {
668 	static const u_int8_t compo6[6] = { 0, 51, 102, 153, 204, 255 };
669 	static const u_int32_t ansi_color[16] = {
670 		0x000000, 0xff0000, 0x00ff00, 0xffff00,
671 		0x0000ff, 0xff00ff, 0x00ffff, 0xffffff,
672 		0x000000, 0x800000, 0x008000, 0x808000,
673 		0x000080, 0x800080, 0x008080, 0x808080,
674 	};
675 	int i, r, g, b;
676 
677 	/* ANSI escape sequence */
678 	for (i = 0; i < 16; i++) {
679 		bus_space_write_4(iot, ioh, i << 2, ansi_color[i]);
680 	}
681 	/* 16 - 31, gray scale */
682 	for ( ; i < 32; i++) {
683 		int j = (i - 16) * 17;
684 		bus_space_write_4(iot, ioh, i << 2, RGB24(j, j, j));
685 	}
686 	/* 32 - 247, RGB color */
687 	for (r = 0; r < 6; r++) {
688 		for (g = 0; g < 6; g++) {
689 			for (b = 0; b < 6; b++) {
690 				bus_space_write_4(iot, ioh, i << 2,
691 				    RGB24(compo6[r],
692 					compo6[g],
693 					compo6[b]));
694 				i++;
695 			}
696 		}
697 	}
698 	/* 248 - 245, just white */
699 	for ( ; i < 256; i++) {
700 		bus_space_write_4(iot, ioh, i << 2, 0xffffff);
701 	}
702 }
703 
704 void
705 plumvideo_clut_default(struct plumvideo_softc *sc)
706 {
707 	__plumvideo_clut_access(sc, NULL, 0, 256, __plumvideo_clut_default);
708 }
709 
710 void
711 __plumvideo_clut_access(struct plumvideo_softc *sc, u_int32_t *rgb, int beg,
712     int cnt, void (*palette_func)(bus_space_tag_t, bus_space_handle_t,
713     u_int32_t *, int, int))
714 {
715 	bus_space_tag_t regt = sc->sc_regt;
716 	bus_space_handle_t regh = sc->sc_regh;
717 	plumreg_t val, gmode;
718 
719 	/* display off */
720 	val = bus_space_read_4(regt, regh, PLUM_VIDEO_PLGMD_REG);
721 	gmode = val & PLUM_VIDEO_PLGMD_GMODE_MASK;
722 	val &= ~PLUM_VIDEO_PLGMD_GMODE_MASK;
723 	bus_space_write_4(regt, regh, PLUM_VIDEO_PLGMD_REG, val);
724 
725 	/* palette access disable */
726 	val &= ~PLUM_VIDEO_PLGMD_PALETTE_ENABLE;
727 	bus_space_write_4(regt, regh, PLUM_VIDEO_PLGMD_REG, val);
728 
729 	/* change palette mode to CPU */
730 	val &= ~PLUM_VIDEO_PLGMD_MODE_DISPLAY;
731 	bus_space_write_4(regt, regh, PLUM_VIDEO_PLGMD_REG, val);
732 
733 	/* palette access */
734 	(*palette_func) (sc->sc_clutiot, sc->sc_clutioh, rgb, beg, cnt);
735 
736 	/* change palette mode to Display */
737 	val |= PLUM_VIDEO_PLGMD_MODE_DISPLAY;
738 	bus_space_write_4(regt, regh, PLUM_VIDEO_PLGMD_REG, val);
739 
740 	/* palette access enable */
741 	val |= PLUM_VIDEO_PLGMD_PALETTE_ENABLE;
742 	bus_space_write_4(regt, regh, PLUM_VIDEO_PLGMD_REG, val);
743 
744 	/* display on */
745 	val |= gmode;
746 	bus_space_write_4(regt, regh, PLUM_VIDEO_PLGMD_REG, val);
747 }
748 
749 /* !!! */
750 static void
751 _flush_cache(void)
752 {
753 	mips_dcache_wbinv_all();
754 	mips_icache_sync_all();
755 }
756 
757 int
758 plumvideo_power(void *ctx, int type, long id, void *msg)
759 {
760 	struct plumvideo_softc *sc = ctx;
761 	int why = (int)msg;
762 
763 	switch (why) {
764 	case PWR_RESUME:
765 		if (!sc->sc_console)
766 			return (0); /* serial console */
767 
768 		DPRINTF(("%s: ON\n", sc->sc_dev.dv_xname));
769 		/* power on */
770 		plumvideo_backlight(sc, 1);
771 		break;
772 	case PWR_SUSPEND:
773 		/* FALLTHROUGH */
774 	case PWR_STANDBY:
775 		DPRINTF(("%s: OFF\n", sc->sc_dev.dv_xname));
776 		/* power off */
777 		plumvideo_backlight(sc, 0);
778 		break;
779 	}
780 
781 	return (0);
782 }
783 
784 static void
785 plumvideo_init_backlight(struct plumvideo_softc *sc)
786 {
787 	int val;
788 
789 	val = -1;
790 	if (config_hook_call(CONFIG_HOOK_GET,
791 	    CONFIG_HOOK_POWER_LCDLIGHT, &val) != -1) {
792 		/* we can get real backlight state */
793 		sc->sc_backlight = val;
794 	}
795 
796 	val = -1;
797 	if (config_hook_call(CONFIG_HOOK_GET,
798 	    CONFIG_HOOK_BRIGHTNESS_MAX, &val) != -1) {
799 		/* we can get real brightness max */
800 		sc->sc_max_brightness = val;
801 
802 		val = -1;
803 		if (config_hook_call(CONFIG_HOOK_GET,
804 		    CONFIG_HOOK_BRIGHTNESS, &val) != -1) {
805 			/* we can get real brightness */
806 			sc->sc_brightness = val;
807 		} else {
808 			sc->sc_brightness = sc->sc_max_brightness;
809 		}
810 	}
811 }
812 
813 static void
814 plumvideo_backlight(struct plumvideo_softc *sc, int on)
815 {
816 	plum_chipset_tag_t pc = sc->sc_pc;
817 	bus_space_tag_t regt = sc->sc_regt;
818 	bus_space_handle_t regh = sc->sc_regh;
819 
820 	sc->sc_backlight = on;
821 	if (on) {
822 		/* LCD on */
823 		plum_power_establish(pc, PLUM_PWR_LCD);
824 		/* backlight on */
825 		plum_power_establish(pc, PLUM_PWR_BKL);
826 		plum_conf_write(regt, regh, PLUM_VIDEO_PLLUM_REG,
827 				PLUM_VIDEO_PLLUM_MAX);
828 	} else {
829 		/* backlight off */
830 		plum_conf_write(regt, regh, PLUM_VIDEO_PLLUM_REG,
831 				PLUM_VIDEO_PLLUM_MIN);
832 		plum_power_disestablish(pc, PLUM_PWR_BKL);
833 		/* LCD off */
834 		plum_power_disestablish(pc, PLUM_PWR_LCD);
835 	}
836 	/* call machine dependent backlight control */
837 	config_hook_call(CONFIG_HOOK_SET,
838 			 CONFIG_HOOK_POWER_LCDLIGHT, (void *)on);
839 }
840 
841 static void
842 plumvideo_brightness(struct plumvideo_softc *sc, int val)
843 {
844 
845 	sc->sc_brightness = val;
846 	/* call machine dependent brightness control */
847 	if (sc->sc_backlight)
848 		config_hook_call(CONFIG_HOOK_SET,
849 				 CONFIG_HOOK_BRIGHTNESS, &val);
850 }
851 
852 #ifdef PLUMVIDEODEBUG
853 void
854 plumvideo_dump(struct plumvideo_softc *sc)
855 {
856 	bus_space_tag_t regt = sc->sc_regt;
857 	bus_space_handle_t regh = sc->sc_regh;
858 
859 	plumreg_t reg;
860 	int i;
861 
862 	for (i = 0; i < 0x160; i += 4) {
863 		reg = plum_conf_read(regt, regh, i);
864 		printf("0x%03x %08x", i, reg);
865 		dbg_bit_print(reg);
866 	}
867 }
868 #endif /* PLUMVIDEODEBUG */
869