1 /* $NetBSD: fb_elb.c,v 1.8 2007/03/04 05:59:46 christos Exp $ */
4 * Copyright (c) 2003 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Juergen Hannken-Illjes.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: fb_elb.c,v 1.8 2007/03/04 05:59:46 christos Exp $");
35 #include <sys/param.h>
37 #include <sys/device.h>
38 #include <sys/ioctl.h>
39 #include <sys/malloc.h>
40 #include <sys/systm.h>
42 #include <dev/wscons/wsconsio.h>
43 #include <dev/wscons/wsdisplayvar.h>
44 #include <dev/rasops/rasops.h>
46 #include <machine/explora.h>
47 #include <machine/bus.h>
49 #include <evbppc/explora/dev/elbvar.h>
51 #define FB_NPORTS 65536
55 bus_space_tag_t fb_iot
;
56 bus_space_handle_t fb_ioh
;
57 struct rasops_info fb_ri
;
66 static int fb_elb_probe(struct device
*, struct cfdata
*, void *);
67 static void fb_elb_attach(struct device
*, struct device
*, void *);
68 void fb_cnattach(bus_space_tag_t
, bus_addr_t
, void *);
69 static void fb_init(struct fb_dev
*, int);
70 static int fb_ioctl(void *, void *, u_long
, void *, int, struct lwp
*);
71 static paddr_t
fb_mmap(void *, void *, off_t
, int);
72 static int fb_alloc_screen(void *, const struct wsscreen_descr
*, void **,
73 int *, int *, long *);
74 static void fb_free_screen(void *, void *);
75 static int fb_show_screen(void *, void *, int, void (*)(void *, int, int),
78 static void fb_eraserows(void *, int, int, long);
79 static void fb_erasecols(void *, int, int, int, long);
80 static void fb_copyrows(void *, int, int, int);
81 static void fb_copycols(void *, int, int, int, int);
83 static void s3_init(struct fb_dev
*, int *, int *);
84 static void s3_copy(struct fb_dev
*, int, int, int, int, int, int, int);
85 static void s3_fill(struct fb_dev
*, int, int, int, int, int, int);
87 static struct fb_dev console_dev
;
89 static struct wsdisplay_accessops accessops
= {
98 static struct wsscreen_descr stdscreen
= {
106 static const struct wsscreen_descr
*scrlist
[] = {
110 static struct wsscreen_list screenlist
= {
111 sizeof(scrlist
)/sizeof(scrlist
[0]), scrlist
114 CFATTACH_DECL(fb_elb
, sizeof(struct fb_elb_softc
),
115 fb_elb_probe
, fb_elb_attach
, NULL
, NULL
);
118 fb_elb_probe(struct device
*parent
, struct cfdata
*cf
, void *aux
)
120 struct elb_attach_args
*oaa
= aux
;
122 if (strcmp(oaa
->elb_name
, cf
->cf_name
) != 0)
129 fb_elb_attach(struct device
*parent
, struct device
*self
, void *aux
)
131 struct fb_elb_softc
*sc
= (void *)self
;
132 struct elb_attach_args
*eaa
= aux
;
133 struct wsemuldisplaydev_attach_args waa
;
134 struct rasops_info
*ri
;
135 bus_space_handle_t ioh
;
138 is_console
= ((void *)eaa
->elb_base
== console_dev
.fb_vram
);
141 sc
->sc_fb
= &console_dev
;
143 sc
->sc_fb
= malloc(sizeof(struct fb_dev
), M_DEVBUF
, M_WAITOK
);
144 memset(sc
->sc_fb
, 0, sizeof(struct fb_dev
));
147 sc
->sc_fb
->fb_iot
= eaa
->elb_bt
;
148 bus_space_map(sc
->sc_fb
->fb_iot
, eaa
->elb_base
, SIZE_FB
,
149 BUS_SPACE_MAP_LINEAR
, &ioh
);
150 sc
->sc_fb
->fb_vram
= bus_space_vaddr(sc
->sc_fb
->fb_iot
, ioh
);
151 bus_space_map(sc
->sc_fb
->fb_iot
, eaa
->elb_base2
, FB_NPORTS
,
152 0, &sc
->sc_fb
->fb_ioh
);
154 fb_init(sc
->sc_fb
, !is_console
);
156 ri
= &sc
->sc_fb
->fb_ri
;
158 printf(": %d x %d\n", ri
->ri_rows
, ri
->ri_cols
);
160 waa
.console
= is_console
;
161 waa
.scrdata
= &screenlist
;
162 waa
.accessops
= &accessops
;
163 waa
.accesscookie
= sc
;
165 config_found(self
, &waa
, wsemuldisplaydevprint
);
169 fb_init(struct fb_dev
*fb
, int full
)
171 struct rasops_info
*ri
= &fb
->fb_ri
;
174 s3_init(fb
, &ri
->ri_width
, &ri
->ri_height
);
176 ri
->ri_stride
= ri
->ri_width
;
177 ri
->ri_bits
= fb
->fb_vram
;
178 ri
->ri_flg
= RI_CENTER
;
180 rasops_init(ri
, 500, 500);
182 ri
->ri_origbits
= fb
->fb_vram
; /*XXX*/
183 rasops_reconfig(ri
, 500, 500);
186 /* Replace the copy/erase ops. */
188 ri
->ri_ops
.eraserows
= fb_eraserows
;
189 ri
->ri_ops
.erasecols
= fb_erasecols
;
190 ri
->ri_ops
.copyrows
= fb_copyrows
;
191 ri
->ri_ops
.copycols
= fb_copycols
;
193 stdscreen
.nrows
= ri
->ri_rows
;
194 stdscreen
.ncols
= ri
->ri_cols
;
195 stdscreen
.textops
= &ri
->ri_ops
;
196 stdscreen
.capabilities
= ri
->ri_caps
;
200 fb_ioctl(void *v
, void *vs
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
202 struct fb_elb_softc
*sc
= v
;
203 struct rasops_info
*ri
= &sc
->sc_fb
->fb_ri
;
204 struct wsdisplay_fbinfo
*wdf
;
207 case WSDISPLAYIO_GTYPE
:
208 *(int *)data
= WSDISPLAY_TYPE_UNKNOWN
; /* XXX */
211 case WSDISPLAYIO_GINFO
:
213 wdf
->height
= ri
->ri_height
;
214 wdf
->width
= ri
->ri_width
;
215 wdf
->depth
= ri
->ri_depth
;
216 wdf
->cmsize
= 16; /*XXX*/
219 case WSDISPLAYIO_SVIDEO
:
220 case WSDISPLAYIO_GETCMAP
:
221 case WSDISPLAYIO_PUTCMAP
:
225 return(EPASSTHROUGH
);
229 fb_mmap(void *v
, void *vs
, off_t offset
, int prot
)
231 struct fb_elb_softc
*sc
= v
;
233 if (offset
< 0 || offset
>= SIZE_FB
)
236 return bus_space_mmap(sc
->sc_fb
->fb_iot
, BASE_FB
, offset
, prot
,
237 BUS_SPACE_MAP_LINEAR
);
241 fb_alloc_screen(void *v
, const struct wsscreen_descr
*scrdesc
, void **cookiep
,
242 int *ccolp
, int *crowp
, long *attrp
)
244 struct fb_elb_softc
*sc
= v
;
245 struct rasops_info
*ri
= &sc
->sc_fb
->fb_ri
;
247 if (sc
->sc_nscreens
> 0)
252 (*ri
->ri_ops
.allocattr
)(ri
, 0, 0, 0, attrp
);
259 fb_free_screen(void *v
, void *cookie
)
261 struct fb_elb_softc
*sc
= v
;
263 if (sc
->sc_fb
== &console_dev
)
264 panic("fb_free_screen: freeing console");
270 fb_show_screen(void *v
, void *cookie
, int waitok
, void (*cb
)(void *, int, int),
277 fb_cnattach(bus_space_tag_t iot
, bus_addr_t iobase
, void *vram
)
279 struct rasops_info
*ri
= &console_dev
.fb_ri
;
282 console_dev
.fb_iot
= iot
;
283 console_dev
.fb_ioh
= iobase
;
284 console_dev
.fb_vram
= vram
;
286 fb_init(&console_dev
, 1);
288 (*ri
->ri_ops
.allocattr
)(ri
, 0, 0, 0, &defattr
);
290 wsdisplay_cnattach(&stdscreen
, ri
, 0, 0, defattr
);
294 fb_eraserows(void *v
, int row
, int nrows
, long attr
)
296 struct rasops_info
*ri
= v
;
297 struct fb_dev
*fb
= ri
->ri_hw
;
299 row
*= ri
->ri_font
->fontheight
;
300 nrows
*= ri
->ri_font
->fontheight
;
302 s3_fill(fb
, 0, row
, ri
->ri_stride
, nrows
, (attr
>> 16)&0x0f, 0x0f);
306 fb_erasecols(void *v
, int row
, int startcol
, int ncols
, long attr
)
308 struct rasops_info
*ri
= v
;
309 struct fb_dev
*fb
= ri
->ri_hw
;
311 row
*= ri
->ri_font
->fontheight
;
312 startcol
*= ri
->ri_font
->fontwidth
;
313 ncols
*= ri
->ri_font
->fontwidth
;
315 s3_fill(fb
, startcol
, row
, ncols
, ri
->ri_font
->fontheight
,
316 (attr
>> 16)&0x0f, 0x0f);
320 fb_copyrows(void *v
, int srcrow
, int dstrow
, int nrows
)
322 struct rasops_info
*ri
= v
;
323 struct fb_dev
*fb
= ri
->ri_hw
;
325 srcrow
*= ri
->ri_font
->fontheight
;
326 dstrow
*= ri
->ri_font
->fontheight
;
327 nrows
*= ri
->ri_font
->fontheight
;
329 s3_copy(fb
, 0, srcrow
, 0, dstrow
, ri
->ri_stride
, nrows
, 0x0f);
333 fb_copycols(void *v
, int row
, int srccol
, int dstcol
, int ncols
)
335 struct rasops_info
*ri
= v
;
336 struct fb_dev
*fb
= ri
->ri_hw
;
338 row
*= ri
->ri_font
->fontheight
;
339 srccol
*= ri
->ri_font
->fontwidth
;
340 dstcol
*= ri
->ri_font
->fontwidth
;
341 ncols
*= ri
->ri_font
->fontwidth
;
343 s3_copy(fb
, srccol
, row
, dstcol
, row
,
344 ncols
, ri
->ri_font
->fontheight
, 0x0f);
348 * S3 support routines
351 #define S3_CRTC_INDEX 0x83d4
352 #define S3_CRTC_DATA 0x83d5
354 #define S3_DAC_RD_INDEX 0x83c7
355 #define S3_DAC_WR_INDEX 0x83c8
356 #define S3_DAC_DATA 0x83c9
358 #define S3_CUR_Y 0x82e8
359 #define S3_CUR_X 0x86e8
360 #define S3_DESTY_AXSTP 0x8ae8
361 #define S3_DESTX_DIASTP 0x8ee8
362 #define S3_MAJ_AXIS_PCNT 0x96e8
363 #define S3_GP_STAT 0x9ae8
364 #define S3_CMD 0x9ae8
365 #define S3_BKGD_COLOR 0xa2e8
366 #define S3_FRGD_COLOR 0xa6e8
367 #define S3_WRT_MASK 0xaae8
368 #define S3_RD_MASK 0xaee8
369 #define S3_BKGD_MIX 0xb6e8
370 #define S3_FRGD_MIX 0xbae8
371 #define S3_MULTIFUNC_CNTL 0xbee8
373 #define S3_GP_STAT_FIFO_1 0x0080
374 #define S3_GP_STAT_BSY 0x0200
376 #define S3_CMD_BITBLT 0xc001
377 #define S3_CMD_RECT 0x4001
378 #define S3_INC_Y 0x0080
379 #define S3_INC_X 0x0020
380 #define S3_DRAW 0x0010
381 #define S3_MULTI 0x0002
383 #define S3_CSRC_BKGDCOL 0x0000
384 #define S3_CSRC_FRGDCOL 0x0020
385 #define S3_CSRC_DISPMEM 0x0060
386 #define S3_MIX_NEW 0x0007
388 #define CMAP_SIZE 256
390 static u_int8_t default_cmap
[] = {
392 /* blue */ 0, 0, 192,
393 /* green */ 0, 192, 0,
394 /* cyan */ 0, 192, 192,
396 /* magenta */ 192, 0, 192,
397 /* brown */ 192, 192, 0,
398 /* lightgrey */ 212, 208, 200,
399 /* darkgrey */ 200, 192, 188,
400 /* lightblue */ 0, 0, 255,
401 /* lightgreen */ 0, 255, 0,
402 /* lightcyan */ 0, 255, 255,
403 /* lightred */ 255, 0, 0,
404 /* lightmagenta */ 255, 0, 255,
405 /* yellow */ 255, 255, 0,
406 /* white */ 255, 255, 255,
410 s3_init(struct fb_dev
*fb
, int *width
, int *height
)
413 bus_space_tag_t iot
= fb
->fb_iot
;
414 bus_space_handle_t ioh
= fb
->fb_ioh
;
416 /* Initialize colormap */
418 bus_space_write_1(iot
, ioh
, S3_DAC_WR_INDEX
, 0);
420 for (i
= j
= 0; i
< CMAP_SIZE
*3; i
++) {
421 bus_space_write_1(iot
, ioh
, S3_DAC_DATA
, default_cmap
[j
] >> 2);
422 j
= (j
+1) % sizeof(default_cmap
)/sizeof(default_cmap
[0]);
425 /* Retrieve frame buffer geometry */
427 bus_space_write_1(iot
, ioh
, S3_CRTC_INDEX
, 1);
428 w
= bus_space_read_1(iot
, ioh
, S3_CRTC_DATA
);
430 bus_space_write_1(iot
, ioh
, S3_CRTC_INDEX
, 18);
431 h
= bus_space_read_1(iot
, ioh
, S3_CRTC_DATA
);
433 bus_space_write_1(iot
, ioh
, S3_CRTC_INDEX
, 7);
434 i
= bus_space_read_1(iot
, ioh
, S3_CRTC_DATA
);
436 h
+= (i
<< 7) & 0x100;
437 h
+= (i
<< 3) & 0x200;
444 s3_copy(struct fb_dev
*fb
, int src_x
, int src_y
, int dest_x
, int dest_y
,
445 int width
, int height
, int mask
)
447 bus_space_tag_t iot
= fb
->fb_iot
;
448 bus_space_handle_t ioh
= fb
->fb_ioh
;
449 u_int16_t cmd
= S3_CMD_BITBLT
| S3_DRAW
;
465 while (bus_space_read_2(iot
, ioh
, S3_GP_STAT
) & S3_GP_STAT_FIFO_1
)
468 bus_space_write_2(iot
, ioh
, S3_FRGD_MIX
, S3_CSRC_DISPMEM
| S3_MIX_NEW
);
469 bus_space_write_2(iot
, ioh
, S3_WRT_MASK
, mask
);
470 bus_space_write_2(iot
, ioh
, S3_CUR_X
, src_x
);
471 bus_space_write_2(iot
, ioh
, S3_CUR_Y
, src_y
);
472 bus_space_write_2(iot
, ioh
, S3_DESTX_DIASTP
, dest_x
);
473 bus_space_write_2(iot
, ioh
, S3_DESTY_AXSTP
, dest_y
);
474 bus_space_write_2(iot
, ioh
, S3_MULTIFUNC_CNTL
, height
-1);
475 bus_space_write_2(iot
, ioh
, S3_MAJ_AXIS_PCNT
, width
-1);
476 bus_space_write_2(iot
, ioh
, S3_CMD
, cmd
);
478 while (bus_space_read_2(iot
, ioh
, S3_GP_STAT
) & S3_GP_STAT_BSY
)
483 s3_fill(struct fb_dev
*fb
, int x
, int y
, int width
, int height
,
486 bus_space_tag_t iot
= fb
->fb_iot
;
487 bus_space_handle_t ioh
= fb
->fb_ioh
;
488 u_int16_t cmd
= S3_CMD_RECT
| S3_INC_X
| S3_INC_Y
| S3_DRAW
;
490 while (bus_space_read_2(iot
, ioh
, S3_GP_STAT
) & S3_GP_STAT_FIFO_1
)
493 bus_space_write_2(iot
, ioh
, S3_FRGD_MIX
, S3_CSRC_FRGDCOL
| S3_MIX_NEW
);
494 bus_space_write_2(iot
, ioh
, S3_FRGD_COLOR
, color
);
495 bus_space_write_2(iot
, ioh
, S3_WRT_MASK
, mask
);
496 bus_space_write_2(iot
, ioh
, S3_CUR_X
, x
);
497 bus_space_write_2(iot
, ioh
, S3_CUR_Y
, y
);
498 bus_space_write_2(iot
, ioh
, S3_MULTIFUNC_CNTL
, height
-1);
499 bus_space_write_2(iot
, ioh
, S3_MAJ_AXIS_PCNT
, width
-1);
500 bus_space_write_2(iot
, ioh
, S3_CMD
, cmd
);
502 while (bus_space_read_2(iot
, ioh
, S3_GP_STAT
) & S3_GP_STAT_BSY
)