1 /* $NetBSD: arcvideo.c,v 1.13 2009/01/07 23:14:40 bjh21 Exp $ */
3 * Copyright (c) 1998, 2000 Ben Harris
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * arcvideo.c - Archimedes video system driver.
33 * The Arc video system is rather closely tied into the heart of the
34 * machine, being partly controlled by the MEMC. Similarly, this
35 * driver will probably end up with its tentacles throughout the
36 * kernel, though in theory it should be possible to leave it out.
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: arcvideo.c,v 1.13 2009/01/07 23:14:40 bjh21 Exp $");
42 #include <sys/param.h>
43 #include <sys/device.h>
44 #include <sys/errno.h>
45 #include <sys/reboot.h> /* For bootverbose */
46 #include <sys/systm.h>
48 #include <uvm/uvm_extern.h>
50 #include <dev/wscons/wsconsio.h>
51 #include <dev/wscons/wscons_raster.h>
52 #include <dev/wscons/wsdisplayvar.h>
53 #include <dev/rasops/rasops.h>
55 #include <machine/boot.h>
56 #include <machine/bus.h>
57 #include <machine/intr.h>
58 #include <machine/irq.h>
59 #include <machine/machdep.h>
60 #include <machine/memcreg.h>
62 #include <arch/acorn26/iobus/iocreg.h>
63 #include <arch/acorn26/iobus/iocvar.h>
64 #include <arch/acorn26/vidc/vidcreg.h>
65 #include <arch/acorn26/vidc/arcvideovar.h>
67 static int arcvideo_match(device_t parent
, cfdata_t cf
, void *aux
);
68 static void arcvideo_attach(device_t parent
, device_t self
, void *aux
);
70 static int arcvideo_setmode(device_t self
, struct arcvideo_mode
*mode
);
71 static void arcvideo_await_vsync(device_t self
);
73 static int arcvideo_intr(void *cookie
);
74 static int arcvideo_ioctl(void *cookie
, void *vs
, u_long cmd
, void *data
,
75 int flag
, struct lwp
*l
);
76 static paddr_t
arcvideo_mmap(void *cookie
, void *vs
, off_t off
, int prot
);
77 static int arcvideo_alloc_screen(void *cookie
, const struct wsscreen_descr
*scr
,
78 void **scookiep
, int *curxp
, int *curyp
,
80 static void arcvideo_free_screen(void *cookie
, void *scookie
);
81 static int arcvideo_show_screen(void *cookie
, void *scookie
, int waitok
,
82 void (*cb
)(void *, int, int),
84 static int arcvideo_load_font(void *cookie
, void *scookie
,
85 struct wsdisplay_font
*);
86 static void arccons_8bpp_hack(struct rasops_info
*ri
);
88 struct arcvideo_softc
{
90 paddr_t sc_screenmem_base
;
91 struct arcvideo_mode sc_current_mode
;
92 u_int32_t sc_vidc_ctl
;
93 struct irq_handler
*sc_irq
;
94 struct evcnt sc_intrcnt
;
96 #define AV_VIDEO_ON 0x01
99 CFATTACH_DECL_NEW(arcvideo
, sizeof(struct arcvideo_softc
),
100 arcvideo_match
, arcvideo_attach
, NULL
, NULL
);
102 device_t the_arcvideo
;
104 static struct rasops_info arccons_ri
;
106 static struct wsscreen_descr arcscreen
;
108 static struct wsdisplay_accessops arcvideo_accessops
= {
109 arcvideo_ioctl
, arcvideo_mmap
, arcvideo_alloc_screen
,
110 arcvideo_free_screen
, arcvideo_show_screen
, arcvideo_load_font
113 static int arcvideo_isconsole
= 0;
116 arcvideo_match(device_t parent
, cfdata_t cf
, void *aux
)
119 /* A system can't sensibly have more than one VIDC. */
120 if (the_arcvideo
== NULL
)
126 arcvideo_attach(device_t parent
, device_t self
, void *aux
)
128 struct wsemuldisplaydev_attach_args da
;
129 struct wsscreen_list scrdata
;
130 const struct wsscreen_descr
*screenp
;
131 struct arcvideo_softc
*sc
= device_private(self
);
133 sc
->sc_dev
= the_arcvideo
= self
;
134 if (!arcvideo_isconsole
) {
135 aprint_error(": Not console -- I can't cope with this!\n");
139 sc
->sc_flags
= AV_VIDEO_ON
;
140 /* Detect monitor type? */
144 evcnt_attach_dynamic(&sc
->sc_intrcnt
, EVCNT_TYPE_INTR
, NULL
,
145 device_xname(sc
->sc_dev
), "vsync intr");
146 sc
->sc_irq
= irq_establish(IOC_IRQ_IR
, IPL_TTY
, arcvideo_intr
, self
,
148 aprint_verbose(": VSYNC interrupts at %s", irq_string(sc
->sc_irq
));
149 irq_disable(sc
->sc_irq
);
153 scrdata
.nscreens
= 1;
154 scrdata
.screens
= &screenp
;
155 screenp
= &arcscreen
;
157 da
.console
= arcvideo_isconsole
;
158 da
.scrdata
= &scrdata
;
159 da
.accessops
= &arcvideo_accessops
;
160 da
.accesscookie
= sc
;
162 config_found(self
, &da
, wsemuldisplaydevprint
);
167 arcvideo_setmode(device_t self
, struct arcvideo_mode
*mode
)
169 struct arcvideo_softc
*sc
= device_private(self
);
170 u_int32_t newctl
, ctlmask
;
171 u_int32_t newhswr
, newhbsr
, newhdsr
, newhder
, newhber
, newhcr
, newhir
;
172 u_int32_t newvswr
, newvbsr
, newvdsr
, newvder
, newvber
, newvcr
;
176 /* XXX: should this be abstracted a little to allow for
178 switch (mode
->timings
.pixelrate
) {
180 newctl
|= VIDC_CTL_DOTCLOCK_8MHZ
;
183 newctl
|= VIDC_CTL_DOTCLOCK_12MHZ
;
186 newctl
|= VIDC_CTL_DOTCLOCK_16MHZ
;
189 newctl
|= VIDC_CTL_DOTCLOCK_24MHZ
;
197 newctl
|= VIDC_CTL_BPP_ONE
;
200 newctl
|= VIDC_CTL_BPP_TWO
;
203 newctl
|= VIDC_CTL_BPP_FOUR
;
206 newctl
|= VIDC_CTL_BPP_EIGHT
;
212 /* XXX: should work this out from pixelrate, bpp and MCLK rate. */
213 newctl
|= VIDC_CTL_DMARQ_37
;
215 ctlmask
= ~(VIDC_CTL_DOTCLOCK_MASK
217 | VIDC_CTL_DMARQ_MASK
);
219 newhswr
= (mode
->timings
.hsw
- 2) / 2 << 14;
220 newhbsr
= (mode
->timings
.hbs
- 1) / 2 << 14;
223 newhdsr
= (mode
->timings
.hds
- 5) / 2 << 14;
224 newhder
= (mode
->timings
.hde
- 5) / 2 << 14;
227 newhdsr
= (mode
->timings
.hds
- 7) / 2 << 14;
228 newhder
= (mode
->timings
.hde
- 7) / 2 << 14;
231 newhdsr
= (mode
->timings
.hds
- 11) / 2 << 14;
232 newhder
= (mode
->timings
.hde
- 11) / 2 << 14;
235 newhdsr
= (mode
->timings
.hds
- 19) / 2 << 14;
236 newhder
= (mode
->timings
.hde
- 19) / 2 << 14;
239 newhber
= (mode
->timings
.hbe
- 1) / 2 << 14;
240 newhcr
= (mode
->timings
.hc
- 2) / 2 << 14;
241 newhir
= mode
->timings
.hc
/ 4 << 14;
242 newvswr
= (mode
->timings
.vsw
- 1) << 14;
243 newvbsr
= (mode
->timings
.vbs
- 1) << 14;
244 newvdsr
= (mode
->timings
.vds
- 1) << 14;
245 newvder
= (mode
->timings
.vde
- 1) << 14;
246 newvber
= (mode
->timings
.vbe
- 1) << 14;
247 newvcr
= (mode
->timings
.vc
- 1) << 14;
248 arcvideo_await_vsync(self
);
249 spltty(); /* XXX audio? */
250 newctl
|= sc
->sc_vidc_ctl
& ctlmask
;
251 VIDC_WRITE(VIDC_CONTROL
| newctl
);
252 sc
->sc_vidc_ctl
= newctl
;
253 VIDC_WRITE(VIDC_VCR
| newvcr
);
254 VIDC_WRITE(VIDC_VSWR
| newvswr
);
255 VIDC_WRITE(VIDC_VBSR
| newvbsr
);
256 VIDC_WRITE(VIDC_VDSR
| newvdsr
);
257 VIDC_WRITE(VIDC_VDER
| newvder
);
258 VIDC_WRITE(VIDC_VBER
| newvber
);
259 VIDC_WRITE(VIDC_HCR
| newhcr
);
260 VIDC_WRITE(VIDC_HIR
| newhir
);
261 VIDC_WRITE(VIDC_HSWR
| newhswr
);
262 VIDC_WRITE(VIDC_HBSR
| newhbsr
);
263 VIDC_WRITE(VIDC_HDSR
| newhdsr
);
264 VIDC_WRITE(VIDC_HDER
| newhder
);
265 VIDC_WRITE(VIDC_HBER
| newhber
);
270 arcvideo_await_vsync(device_t self
)
273 panic("arcvideo_await_vsync not implemented");
278 arcvideo_intr(void *cookie
)
280 /* struct arcvideo_softc *sc = cookie; */
286 * In the standard RISC OS 8-bit palette (which we use), the bits go
287 * BGgRbrTt, feeding RrTt, GgTt and BbTt to the DACs. The top four of
288 * these bits are fixed in hardware.
290 * The following table is the closest match I can get to the colours
291 * at the top of rasops.c.
294 static u_int8_t rasops_cmap_8bpp
[] = {
295 0x00, 0x10, 0x40, 0x50, 0x80, 0x90, 0xc0, 0xfc,
296 0xd0, 0x17, 0x63, 0x77, 0x8b, 0x9f, 0xeb, 0xff,
306 struct rasops_info
*ri
= &arccons_ri
;
308 /* Force the screen to be at a known location */
309 if (bootconfig
.screenbase
!= 0)
311 MEMC_WRITE(MEMC_SET_PTR(MEMC_VSTART
, 0));
312 MEMC_WRITE(MEMC_SET_PTR(MEMC_VINIT
, 0));
313 MEMC_WRITE(MEMC_SET_PTR(MEMC_VEND
, 0x00080000));
315 /* TODO: We should really set up the VIDC ourselves here. */
317 /* Set up arccons_ri */
318 memset(ri
, 0, sizeof(*ri
));
319 ri
->ri_depth
= bootconfig
.bpp
;
320 ri
->ri_bits
= (u_char
*)(MEMC_PHYS_BASE
);
321 ri
->ri_width
= bootconfig
.xpixels
;
322 ri
->ri_height
= bootconfig
.ypixels
;
323 ri
->ri_stride
= ((bootconfig
.xpixels
* bootconfig
.bpp
+ 31) >> 5) << 2;
324 ri
->ri_flg
= RI_CENTER
| (clear
? RI_CLEAR
: 0);
326 if (rasops_init(ri
, 1000, 1000) < 0)
327 panic("rasops_init failed");
329 /* Register video memory with UVM now we know how much we're using. */
330 uvm_page_physload(0, atop(MEMC_DMA_MAX
),
331 atop(round_page(ri
->ri_height
* ri
->ri_stride
)),
332 atop(MEMC_DMA_MAX
), VM_FREELIST_LOW
);
334 if (ri
->ri_depth
== 8)
335 arccons_8bpp_hack(&arccons_ri
);
336 else if (ri
->ri_depth
== 4)
337 for (i
= 0; i
< 1 << ri
->ri_depth
; i
++)
338 VIDC_WRITE(VIDC_PALETTE_LCOL(i
) |
339 VIDC_PALETTE_ENTRY(rasops_cmap
[3*i
+ 0] >> 4,
340 rasops_cmap
[3*i
+ 1] >> 4,
341 rasops_cmap
[3*i
+ 2] >> 4, 0));
343 /* Take rcons stuff and put it in arcscreen */
344 /* XXX shouldn't this kind of thing be done by rcons_init? */
345 arcscreen
.name
= "arccons";
346 arcscreen
.ncols
= ri
->ri_cols
;
347 arcscreen
.nrows
= ri
->ri_rows
;
348 arcscreen
.textops
= &ri
->ri_ops
;
349 arcscreen
.fontwidth
= ri
->ri_font
->fontwidth
;
350 arcscreen
.fontheight
= ri
->ri_font
->fontheight
;
351 arcscreen
.capabilities
= ri
->ri_caps
;
353 /* work out cursor row */
357 /* +/-1 is to round up */
358 crow
= (bootconfig
.cpixelrow
- ri
->ri_yorigin
- 1) /
359 ri
->ri_font
->fontheight
+ 1;
360 if (crow
< 0) crow
= 0;
361 if (crow
> ri
->ri_rows
) crow
= ri
->ri_rows
;
363 if ((arccons_ri
.ri_ops
.allocattr
)(&arccons_ri
, 0, 0, 0, &defattr
) !=
365 panic("allocattr failed");
366 wsdisplay_cnattach(&arcscreen
, &arccons_ri
, 0, crow
, defattr
);
368 /* That should be all */
369 arcvideo_isconsole
= 1;
373 * The following is a gross hack because the rasops code has no way
374 * for us to specify the devcmap if we don't want the default. I think
375 * it assumes that all 8-bit displays are PseudoColor.
379 arccons_8bpp_hack(struct rasops_info
*ri
)
383 for (i
= 0; i
< 16; i
++) {
384 c
= rasops_cmap_8bpp
[i
];
385 ri
->ri_devcmap
[i
] = c
| (c
<<8) | (c
<<16) | (c
<<24);
390 /* wsdisplay access functions */
393 arcvideo_ioctl(void *cookie
, void *vs
, u_long cmd
, void *data
, int flag
,
396 struct arcvideo_softc
*sc
= cookie
;
399 case WSDISPLAYIO_GTYPE
:
400 *(u_int
*)data
= WSDISPLAY_TYPE_VIDC
;
402 case WSDISPLAYIO_GVIDEO
:
403 if (sc
->sc_flags
& AV_VIDEO_ON
)
404 *(u_int
*)data
= WSDISPLAYIO_VIDEO_ON
;
406 *(u_int
*)data
= WSDISPLAYIO_VIDEO_OFF
;
408 case WSDISPLAYIO_SVIDEO
:
409 switch (*(u_int
*)data
) {
410 case WSDISPLAYIO_VIDEO_OFF
:
411 sc
->sc_flags
&= ~AV_VIDEO_ON
;
412 update_memc(MEMC_CTL_VIDEODMA
| MEMC_CTL_RFRSH_MASK
,
413 MEMC_CTL_RFRSH_CONTIN
);
415 case WSDISPLAYIO_VIDEO_ON
:
416 sc
->sc_flags
|= AV_VIDEO_ON
;
417 update_memc(MEMC_CTL_VIDEODMA
| MEMC_CTL_RFRSH_MASK
,
419 MEMC_CTL_RFRSH_FLYBACK
);
427 arcvideo_mmap(void *cookie
, void *vs
, off_t off
, int prot
)
434 arcvideo_alloc_screen(void *cookie
, const struct wsscreen_descr
*scr
,
435 void **scookiep
, int *curxp
, int *curyp
, long *defattrp
)
442 arcvideo_free_screen(void *cookie
, void *scookie
)
445 panic("arcvideo_free_screen not implemented");
449 arcvideo_show_screen(void *cookie
, void *scookie
, int waitok
,
450 void (*cb
)(void *cbarg
, int error
, int waitok
), void *cbarg
)
453 /* Do nothing, since there can only be one screen. */
458 arcvideo_load_font(void *cookie
, void *emulcookie
, struct wsdisplay_font
*font
)