Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / arch / acorn26 / vidc / arcvideo.c
blobb870c6483aa7d018b1c6e1c38901084ab1c70370
1 /* $NetBSD: arcvideo.c,v 1.13 2009/01/07 23:14:40 bjh21 Exp $ */
2 /*-
3 * Copyright (c) 1998, 2000 Ben Harris
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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);
69 #if 0
70 static int arcvideo_setmode(device_t self, struct arcvideo_mode *mode);
71 static void arcvideo_await_vsync(device_t self);
72 #endif
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,
79 long *defattrp);
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),
83 void *cbarg);
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 {
89 device_t sc_dev;
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;
95 int sc_flags;
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;
115 static int
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)
121 return 1;
122 return 0;
125 static void
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");
136 return;
139 sc->sc_flags = AV_VIDEO_ON;
140 /* Detect monitor type? */
141 /* Reset VIDC */
143 /* Find IRQ */
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,
147 &sc->sc_intrcnt);
148 aprint_verbose(": VSYNC interrupts at %s", irq_string(sc->sc_irq));
149 irq_disable(sc->sc_irq);
151 aprint_normal("\n");
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);
165 #if 0
166 static int
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;
174 newctl = 0;
175 /* Dot clock */
176 /* XXX: should this be abstracted a little to allow for
177 variable VIDCLKs? */
178 switch (mode->timings.pixelrate) {
179 case 8000000:
180 newctl |= VIDC_CTL_DOTCLOCK_8MHZ;
181 break;
182 case 12000000:
183 newctl |= VIDC_CTL_DOTCLOCK_12MHZ;
184 break;
185 case 16000000:
186 newctl |= VIDC_CTL_DOTCLOCK_16MHZ;
187 break;
188 case 24000000:
189 newctl |= VIDC_CTL_DOTCLOCK_24MHZ;
190 break;
191 default:
192 return ENXIO;
194 /* Bits per pixel */
195 switch (mode->bpp) {
196 case 1:
197 newctl |= VIDC_CTL_BPP_ONE;
198 break;
199 case 2:
200 newctl |= VIDC_CTL_BPP_TWO;
201 break;
202 case 4:
203 newctl |= VIDC_CTL_BPP_FOUR;
204 break;
205 case 8:
206 newctl |= VIDC_CTL_BPP_EIGHT;
207 break;
208 default:
209 return EINVAL;
211 /* DMA timings */
212 /* XXX: should work this out from pixelrate, bpp and MCLK rate. */
213 newctl |= VIDC_CTL_DMARQ_37;
215 ctlmask = ~(VIDC_CTL_DOTCLOCK_MASK
216 | VIDC_CTL_BPP_MASK
217 | VIDC_CTL_DMARQ_MASK);
219 newhswr = (mode->timings.hsw - 2) / 2 << 14;
220 newhbsr = (mode->timings.hbs - 1) / 2 << 14;
221 switch (mode->bpp) {
222 case 8:
223 newhdsr = (mode->timings.hds - 5) / 2 << 14;
224 newhder = (mode->timings.hde - 5) / 2 << 14;
225 break;
226 case 4:
227 newhdsr = (mode->timings.hds - 7) / 2 << 14;
228 newhder = (mode->timings.hde - 7) / 2 << 14;
229 break;
230 case 2:
231 newhdsr = (mode->timings.hds - 11) / 2 << 14;
232 newhder = (mode->timings.hde - 11) / 2 << 14;
233 break;
234 case 1:
235 newhdsr = (mode->timings.hds - 19) / 2 << 14;
236 newhder = (mode->timings.hde - 19) / 2 << 14;
237 break;
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);
266 return 0;
269 static void
270 arcvideo_await_vsync(device_t self)
273 panic("arcvideo_await_vsync not implemented");
275 #endif
277 static int
278 arcvideo_intr(void *cookie)
280 /* struct arcvideo_softc *sc = cookie; */
282 return IRQ_HANDLED;
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,
299 void
300 arccons_init(void)
302 long defattr;
303 int clear = 0;
304 int crow;
305 int i;
306 struct rasops_info *ri = &arccons_ri;
308 /* Force the screen to be at a known location */
309 if (bootconfig.screenbase != 0)
310 clear = 1;
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 */
354 if (clear)
355 crow = 0;
356 else
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.
378 static void
379 arccons_8bpp_hack(struct rasops_info *ri)
381 int i, c;
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 */
392 static int
393 arcvideo_ioctl(void *cookie, void *vs, u_long cmd, void *data, int flag,
394 struct lwp *l)
396 struct arcvideo_softc *sc = cookie;
398 switch (cmd) {
399 case WSDISPLAYIO_GTYPE:
400 *(u_int *)data = WSDISPLAY_TYPE_VIDC;
401 return 0;
402 case WSDISPLAYIO_GVIDEO:
403 if (sc->sc_flags & AV_VIDEO_ON)
404 *(u_int *)data = WSDISPLAYIO_VIDEO_ON;
405 else
406 *(u_int *)data = WSDISPLAYIO_VIDEO_OFF;
407 return 0;
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);
414 return 0;
415 case WSDISPLAYIO_VIDEO_ON:
416 sc->sc_flags |= AV_VIDEO_ON;
417 update_memc(MEMC_CTL_VIDEODMA | MEMC_CTL_RFRSH_MASK,
418 MEMC_CTL_VIDEODMA |
419 MEMC_CTL_RFRSH_FLYBACK);
420 return 0;
423 return EPASSTHROUGH;
426 static paddr_t
427 arcvideo_mmap(void *cookie, void *vs, off_t off, int prot)
430 return ENODEV;
433 static int
434 arcvideo_alloc_screen(void *cookie, const struct wsscreen_descr *scr,
435 void **scookiep, int *curxp, int *curyp, long *defattrp)
438 return ENODEV;
441 static void
442 arcvideo_free_screen(void *cookie, void *scookie)
445 panic("arcvideo_free_screen not implemented");
448 static int
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. */
454 return 0;
457 static int
458 arcvideo_load_font(void *cookie, void *emulcookie, struct wsdisplay_font *font)
461 return EPASSTHROUGH;