]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/arm/broadcom/bcm2835/bcm2835_fb.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / arm / broadcom / bcm2835 / bcm2835_fb.c
1 /*-
2  * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/bio.h>
33 #include <sys/bus.h>
34 #include <sys/conf.h>
35 #include <sys/endian.h>
36 #include <sys/kernel.h>
37 #include <sys/kthread.h>
38 #include <sys/lock.h>
39 #include <sys/malloc.h>
40 #include <sys/module.h>
41 #include <sys/mutex.h>
42 #include <sys/queue.h>
43 #include <sys/resource.h>
44 #include <sys/rman.h>
45 #include <sys/time.h>
46 #include <sys/timetc.h>
47 #include <sys/fbio.h>
48 #include <sys/consio.h>
49
50 #include <sys/kdb.h>
51
52 #include <machine/bus.h>
53 #include <machine/cpu.h>
54 #include <machine/cpufunc.h>
55 #include <machine/resource.h>
56 #include <machine/frame.h>
57 #include <machine/intr.h>
58
59 #include <dev/fdt/fdt_common.h>
60 #include <dev/ofw/ofw_bus.h>
61 #include <dev/ofw/ofw_bus_subr.h>
62
63 #include <dev/fb/fbreg.h>
64 #include <dev/syscons/syscons.h>
65
66 #include <arm/broadcom/bcm2835/bcm2835_mbox.h>
67 #include <arm/broadcom/bcm2835/bcm2835_vcbus.h>
68
69 #include "mbox_if.h"
70
71 #define BCMFB_FONT_HEIGHT       16
72
73 struct argb {
74         uint8_t         a;
75         uint8_t         r;
76         uint8_t         g;
77         uint8_t         b;
78 };
79
80 static struct argb bcmfb_palette[16] = {
81         {0x00, 0x00, 0x00, 0x00},
82         {0x00, 0x00, 0x00, 0xaa},
83         {0x00, 0x00, 0xaa, 0x00},
84         {0x00, 0x00, 0xaa, 0xaa},
85         {0x00, 0xaa, 0x00, 0x00},
86         {0x00, 0xaa, 0x00, 0xaa},
87         {0x00, 0xaa, 0x55, 0x00},
88         {0x00, 0xaa, 0xaa, 0xaa},
89         {0x00, 0x55, 0x55, 0x55},
90         {0x00, 0x55, 0x55, 0xff},
91         {0x00, 0x55, 0xff, 0x55},
92         {0x00, 0x55, 0xff, 0xff},
93         {0x00, 0xff, 0x55, 0x55},
94         {0x00, 0xff, 0x55, 0xff},
95         {0x00, 0xff, 0xff, 0x55},
96         {0x00, 0xff, 0xff, 0xff}
97 };
98
99 /* mouse pointer from dev/syscons/scgfbrndr.c */
100 static u_char mouse_pointer[16] = {
101         0x00, 0x40, 0x60, 0x70, 0x78, 0x7c, 0x7e, 0x68,
102         0x0c, 0x0c, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00
103 };
104
105 #define FB_WIDTH                640
106 #define FB_HEIGHT               480
107 #define FB_DEPTH                24
108
109 struct bcm_fb_config {
110         uint32_t        xres;
111         uint32_t        yres;
112         uint32_t        vxres;
113         uint32_t        vyres;
114         uint32_t        pitch;
115         uint32_t        bpp;
116         uint32_t        xoffset;
117         uint32_t        yoffset;
118         /* Filled by videocore */
119         uint32_t        base;
120         uint32_t        screen_size;
121 };
122
123 struct bcmsc_softc {
124         device_t                dev;
125         struct cdev *           cdev;
126         struct mtx              mtx;
127         bus_dma_tag_t           dma_tag;
128         bus_dmamap_t            dma_map;
129         struct bcm_fb_config*   fb_config;
130         bus_addr_t              fb_config_phys;
131         struct intr_config_hook init_hook;
132
133 };
134
135 struct video_adapter_softc {
136         /* Videoadpater part */
137         video_adapter_t va;
138         int             console;
139
140         intptr_t        fb_addr;
141         intptr_t        fb_paddr;
142         unsigned int    fb_size;
143
144         unsigned int    height;
145         unsigned int    width;
146         unsigned int    depth;
147         unsigned int    stride;
148
149         unsigned int    xmargin;
150         unsigned int    ymargin;
151
152         unsigned char   *font;
153         int             initialized;
154 };
155
156 static struct bcmsc_softc *bcmsc_softc;
157 static struct video_adapter_softc va_softc;
158
159 #define bcm_fb_lock(_sc)        mtx_lock(&(_sc)->mtx)
160 #define bcm_fb_unlock(_sc)      mtx_unlock(&(_sc)->mtx)
161 #define bcm_fb_lock_assert(sc)  mtx_assert(&(_sc)->mtx, MA_OWNED)
162
163 static int bcm_fb_probe(device_t);
164 static int bcm_fb_attach(device_t);
165 static void bcm_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err);
166 static void bcmfb_update_margins(video_adapter_t *adp);
167 static int bcmfb_configure(int);
168
169 static void
170 bcm_fb_init(void *arg)
171 {
172         struct bcmsc_softc *sc = arg;
173         struct video_adapter_softc *va_sc = &va_softc;
174         int err;
175         volatile struct bcm_fb_config*  fb_config = sc->fb_config;
176         phandle_t node;
177         pcell_t cell;
178         device_t mbox;
179
180         node = ofw_bus_get_node(sc->dev);
181
182         fb_config->xres = 0;
183         fb_config->yres = 0;
184         fb_config->bpp = 0;
185
186         if ((OF_getprop(node, "broadcom,width", &cell, sizeof(cell))) > 0)
187                 fb_config->xres = (int)fdt32_to_cpu(cell);
188         if (fb_config->xres == 0)
189                 fb_config->xres = FB_WIDTH;
190
191         if ((OF_getprop(node, "broadcom,height", &cell, sizeof(cell))) > 0)
192                 fb_config->yres = (uint32_t)fdt32_to_cpu(cell);
193         if (fb_config->yres == 0)
194                 fb_config->yres = FB_HEIGHT;
195
196         if ((OF_getprop(node, "broadcom,depth", &cell, sizeof(cell))) > 0)
197                 fb_config->bpp = (uint32_t)fdt32_to_cpu(cell);
198         if (fb_config->bpp == 0)
199                 fb_config->bpp = FB_DEPTH;
200
201         fb_config->vxres = 0;
202         fb_config->vyres = 0;
203         fb_config->xoffset = 0;
204         fb_config->yoffset = 0;
205         fb_config->base = 0;
206         fb_config->pitch = 0;
207         fb_config->screen_size = 0;
208
209         bus_dmamap_sync(sc->dma_tag, sc->dma_map,
210                 BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
211
212         mbox = devclass_get_device(devclass_find("mbox"), 0);
213         if (mbox) {
214                 MBOX_WRITE(mbox, BCM2835_MBOX_CHAN_FB, sc->fb_config_phys);
215                 MBOX_READ(mbox, BCM2835_MBOX_CHAN_FB, &err);
216         }
217         bus_dmamap_sync(sc->dma_tag, sc->dma_map,
218                 BUS_DMASYNC_POSTREAD);
219
220         if (fb_config->base != 0) {
221                 device_printf(sc->dev, "%dx%d(%dx%d@%d,%d) %dbpp\n", 
222                         fb_config->xres, fb_config->yres,
223                         fb_config->vxres, fb_config->vyres,
224                         fb_config->xoffset, fb_config->yoffset,
225                         fb_config->bpp);
226
227
228                 device_printf(sc->dev, "pitch %d, base 0x%08x, screen_size %d\n", 
229                         fb_config->pitch, fb_config->base,
230                         fb_config->screen_size);
231
232                 va_sc->fb_addr = (intptr_t)pmap_mapdev(fb_config->base, fb_config->screen_size);
233                 va_sc->fb_paddr = fb_config->base;
234                 va_sc->fb_size = fb_config->screen_size;
235                 va_sc->depth = fb_config->bpp;
236                 va_sc->stride = fb_config->pitch;
237
238                 va_sc->width = fb_config->xres;
239                 va_sc->height = fb_config->yres;
240                 bcmfb_update_margins(&va_sc->va);
241         }
242         else {
243                 device_printf(sc->dev, "Failed to set framebuffer info\n");
244                 return;
245         }
246
247         config_intrhook_disestablish(&sc->init_hook);
248 }
249
250 static int
251 bcm_fb_probe(device_t dev)
252 {
253         int error = 0;
254
255         if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-fb"))
256                 return (ENXIO);
257
258         device_set_desc(dev, "BCM2835 framebuffer device");
259
260         error = sc_probe_unit(device_get_unit(dev), 
261             device_get_flags(dev) | SC_AUTODETECT_KBD);
262         if (error != 0)
263                 return (error);
264
265
266         return (BUS_PROBE_DEFAULT);
267 }
268
269 static int
270 bcm_fb_attach(device_t dev)
271 {
272         struct bcmsc_softc *sc = device_get_softc(dev);
273         int dma_size = sizeof(struct bcm_fb_config);
274         int err;
275
276         if (bcmsc_softc)
277                 return (ENXIO);
278
279         bcmsc_softc = sc;
280
281         sc->dev = dev;
282         mtx_init(&sc->mtx, "bcm2835fb", "fb", MTX_DEF);
283
284         err = bus_dma_tag_create(
285             bus_get_dma_tag(sc->dev),
286             PAGE_SIZE, 0,               /* alignment, boundary */
287             BUS_SPACE_MAXADDR_32BIT,    /* lowaddr */
288             BUS_SPACE_MAXADDR,          /* highaddr */
289             NULL, NULL,                 /* filter, filterarg */
290             dma_size, 1,                /* maxsize, nsegments */
291             dma_size, 0,                /* maxsegsize, flags */
292             NULL, NULL,                 /* lockfunc, lockarg */
293             &sc->dma_tag);
294
295         err = bus_dmamem_alloc(sc->dma_tag, (void **)&sc->fb_config,
296             0, &sc->dma_map);
297         if (err) {
298                 device_printf(dev, "cannot allocate framebuffer\n");
299                 goto fail;
300         }
301
302         err = bus_dmamap_load(sc->dma_tag, sc->dma_map, sc->fb_config,
303             dma_size, bcm_fb_dmamap_cb, &sc->fb_config_phys, BUS_DMA_NOWAIT);
304
305         if (err) {
306                 device_printf(dev, "cannot load DMA map\n");
307                 goto fail;
308         }
309
310         err = (sc_attach_unit(device_get_unit(dev),
311             device_get_flags(dev) | SC_AUTODETECT_KBD));
312
313         if (err) {
314                 device_printf(dev, "failed to attach syscons\n");
315                 goto fail;
316         }
317
318         /* 
319          * We have to wait until interrupts are enabled. 
320          * Mailbox relies on it to get data from VideoCore
321          */
322         sc->init_hook.ich_func = bcm_fb_init;
323         sc->init_hook.ich_arg = sc;
324
325         if (config_intrhook_establish(&sc->init_hook) != 0) {
326                 device_printf(dev, "failed to establish intrhook\n");
327                 return (ENOMEM);
328         }
329
330         return (0);
331
332 fail:
333         return (ENXIO);
334 }
335
336
337 static void
338 bcm_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
339 {
340         bus_addr_t *addr;
341
342         if (err)
343                 return;
344
345         addr = (bus_addr_t*)arg;
346         *addr = PHYS_TO_VCBUS(segs[0].ds_addr);
347 }
348
349 static device_method_t bcm_fb_methods[] = {
350         /* Device interface */
351         DEVMETHOD(device_probe,         bcm_fb_probe),
352         DEVMETHOD(device_attach,        bcm_fb_attach),
353
354         { 0, 0 }
355 };
356
357 static devclass_t bcm_fb_devclass;
358
359 static driver_t bcm_fb_driver = {
360         "fb",
361         bcm_fb_methods,
362         sizeof(struct bcmsc_softc),
363 };
364
365 DRIVER_MODULE(bcm2835fb, fdtbus, bcm_fb_driver, bcm_fb_devclass, 0, 0);
366
367 /*
368  * Video driver routines and glue.
369  */
370 static vi_probe_t               bcmfb_probe;
371 static vi_init_t                bcmfb_init;
372 static vi_get_info_t            bcmfb_get_info;
373 static vi_query_mode_t          bcmfb_query_mode;
374 static vi_set_mode_t            bcmfb_set_mode;
375 static vi_save_font_t           bcmfb_save_font;
376 static vi_load_font_t           bcmfb_load_font;
377 static vi_show_font_t           bcmfb_show_font;
378 static vi_save_palette_t        bcmfb_save_palette;
379 static vi_load_palette_t        bcmfb_load_palette;
380 static vi_set_border_t          bcmfb_set_border;
381 static vi_save_state_t          bcmfb_save_state;
382 static vi_load_state_t          bcmfb_load_state;
383 static vi_set_win_org_t         bcmfb_set_win_org;
384 static vi_read_hw_cursor_t      bcmfb_read_hw_cursor;
385 static vi_set_hw_cursor_t       bcmfb_set_hw_cursor;
386 static vi_set_hw_cursor_shape_t bcmfb_set_hw_cursor_shape;
387 static vi_blank_display_t       bcmfb_blank_display;
388 static vi_mmap_t                bcmfb_mmap;
389 static vi_ioctl_t               bcmfb_ioctl;
390 static vi_clear_t               bcmfb_clear;
391 static vi_fill_rect_t           bcmfb_fill_rect;
392 static vi_bitblt_t              bcmfb_bitblt;
393 static vi_diag_t                bcmfb_diag;
394 static vi_save_cursor_palette_t bcmfb_save_cursor_palette;
395 static vi_load_cursor_palette_t bcmfb_load_cursor_palette;
396 static vi_copy_t                bcmfb_copy;
397 static vi_putp_t                bcmfb_putp;
398 static vi_putc_t                bcmfb_putc;
399 static vi_puts_t                bcmfb_puts;
400 static vi_putm_t                bcmfb_putm;
401
402 static video_switch_t bcmfbvidsw = {
403         .probe                  = bcmfb_probe,
404         .init                   = bcmfb_init,
405         .get_info               = bcmfb_get_info,
406         .query_mode             = bcmfb_query_mode,
407         .set_mode               = bcmfb_set_mode,
408         .save_font              = bcmfb_save_font,
409         .load_font              = bcmfb_load_font,
410         .show_font              = bcmfb_show_font,
411         .save_palette           = bcmfb_save_palette,
412         .load_palette           = bcmfb_load_palette,
413         .set_border             = bcmfb_set_border,
414         .save_state             = bcmfb_save_state,
415         .load_state             = bcmfb_load_state,
416         .set_win_org            = bcmfb_set_win_org,
417         .read_hw_cursor         = bcmfb_read_hw_cursor,
418         .set_hw_cursor          = bcmfb_set_hw_cursor,
419         .set_hw_cursor_shape    = bcmfb_set_hw_cursor_shape,
420         .blank_display          = bcmfb_blank_display,
421         .mmap                   = bcmfb_mmap,
422         .ioctl                  = bcmfb_ioctl,
423         .clear                  = bcmfb_clear,
424         .fill_rect              = bcmfb_fill_rect,
425         .bitblt                 = bcmfb_bitblt,
426         .diag                   = bcmfb_diag,
427         .save_cursor_palette    = bcmfb_save_cursor_palette,
428         .load_cursor_palette    = bcmfb_load_cursor_palette,
429         .copy                   = bcmfb_copy,
430         .putp                   = bcmfb_putp,
431         .putc                   = bcmfb_putc,
432         .puts                   = bcmfb_puts,
433         .putm                   = bcmfb_putm,
434 };
435
436 VIDEO_DRIVER(bcmfb, bcmfbvidsw, bcmfb_configure);
437
438 static vr_init_t bcmrend_init;
439 static vr_clear_t bcmrend_clear;
440 static vr_draw_border_t bcmrend_draw_border;
441 static vr_draw_t bcmrend_draw;
442 static vr_set_cursor_t bcmrend_set_cursor;
443 static vr_draw_cursor_t bcmrend_draw_cursor;
444 static vr_blink_cursor_t bcmrend_blink_cursor;
445 static vr_set_mouse_t bcmrend_set_mouse;
446 static vr_draw_mouse_t bcmrend_draw_mouse;
447
448 /*
449  * We use our own renderer; this is because we must emulate a hardware
450  * cursor.
451  */
452 static sc_rndr_sw_t bcmrend = {
453         bcmrend_init,
454         bcmrend_clear,
455         bcmrend_draw_border,
456         bcmrend_draw,
457         bcmrend_set_cursor,
458         bcmrend_draw_cursor,
459         bcmrend_blink_cursor,
460         bcmrend_set_mouse,
461         bcmrend_draw_mouse
462 };
463
464 RENDERER(bcmfb, 0, bcmrend, gfb_set);
465 RENDERER_MODULE(bcmfb, gfb_set);
466
467 static void
468 bcmrend_init(scr_stat* scp)
469 {
470 }
471
472 static void
473 bcmrend_clear(scr_stat* scp, int c, int attr)
474 {
475 }
476
477 static void
478 bcmrend_draw_border(scr_stat* scp, int color)
479 {
480 }
481
482 static void
483 bcmrend_draw(scr_stat* scp, int from, int count, int flip)
484 {
485         video_adapter_t* adp = scp->sc->adp;
486         int i, c, a;
487
488         if (!flip) {
489                 /* Normal printing */
490                 vidd_puts(adp, from, (uint16_t*)sc_vtb_pointer(&scp->vtb, from), count);
491         } else {        
492                 /* This is for selections and such: invert the color attribute */
493                 for (i = count; i-- > 0; ++from) {
494                         c = sc_vtb_getc(&scp->vtb, from);
495                         a = sc_vtb_geta(&scp->vtb, from) >> 8;
496                         vidd_putc(adp, from, c, (a >> 4) | ((a & 0xf) << 4));
497                 }
498         }
499 }
500
501 static void
502 bcmrend_set_cursor(scr_stat* scp, int base, int height, int blink)
503 {
504 }
505
506 static void
507 bcmrend_draw_cursor(scr_stat* scp, int off, int blink, int on, int flip)
508 {
509         video_adapter_t* adp = scp->sc->adp;
510         struct video_adapter_softc *sc;
511         int row, col;
512         uint8_t *addr;
513         int i, j, bytes;
514
515         sc = (struct video_adapter_softc *)adp;
516
517         if (scp->curs_attr.height <= 0)
518                 return;
519
520         if (sc->fb_addr == 0)
521                 return;
522
523         if (off >= adp->va_info.vi_width * adp->va_info.vi_height)
524                 return;
525
526         /* calculate the coordinates in the video buffer */
527         row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight;
528         col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth;
529
530         addr = (uint8_t *)sc->fb_addr
531             + (row + sc->ymargin)*(sc->stride)
532             + (sc->depth/8) * (col + sc->xmargin);
533
534         bytes = sc->depth/8;
535
536         /* our cursor consists of simply inverting the char under it */
537         for (i = 0; i < adp->va_info.vi_cheight; i++) {
538                 for (j = 0; j < adp->va_info.vi_cwidth; j++) {
539                         switch (sc->depth) {
540                         case 32:
541                         case 24:
542                                 addr[bytes*j + 2] ^= 0xff;
543                                 /* FALLTHROUGH */
544                         case 16:
545                                 addr[bytes*j + 1] ^= 0xff;
546                                 addr[bytes*j] ^= 0xff;
547                                 break;
548                         default:
549                                 break;
550                         }
551                 }
552
553                 addr += sc->stride;
554         }
555 }
556
557 static void
558 bcmrend_blink_cursor(scr_stat* scp, int at, int flip)
559 {
560 }
561
562 static void
563 bcmrend_set_mouse(scr_stat* scp)
564 {
565 }
566
567 static void
568 bcmrend_draw_mouse(scr_stat* scp, int x, int y, int on)
569 {
570         vidd_putm(scp->sc->adp, x, y, mouse_pointer, 0xffffffff, 16, 8);
571 }
572
573 static uint16_t bcmfb_static_window[ROW*COL];
574 extern u_char dflt_font_16[];
575
576 /*
577  * Update videoadapter settings after changing resolution
578  */
579 static void
580 bcmfb_update_margins(video_adapter_t *adp)
581 {
582         struct video_adapter_softc *sc;
583         video_info_t *vi;
584
585         sc = (struct video_adapter_softc *)adp;
586         vi = &adp->va_info;
587
588         sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2;
589         sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight))/2;
590 }
591
592 static int
593 bcmfb_configure(int flags)
594 {
595         struct video_adapter_softc *va_sc;
596
597         va_sc = &va_softc;
598         phandle_t display, root;
599         pcell_t cell;
600
601         if (va_sc->initialized)
602                 return (0);
603
604         va_sc->width = 0;
605         va_sc->height = 0;
606
607         /*
608          * It seems there is no way to let syscons framework know
609          * that framebuffer resolution has changed. So just try
610          * to fetch data from FDT and go with defaults if failed
611          */
612         root = OF_finddevice("/");
613         if ((root != 0) && 
614             (display = fdt_find_compatible(root, "broadcom,bcm2835-fb", 1))) {
615                 if ((OF_getprop(display, "broadcom,width", 
616                     &cell, sizeof(cell))) > 0)
617                         va_sc->width = (int)fdt32_to_cpu(cell);
618
619                 if ((OF_getprop(display, "broadcom,height", 
620                     &cell, sizeof(cell))) > 0)
621                         va_sc->height = (int)fdt32_to_cpu(cell);
622         }
623
624         if (va_sc->width == 0)
625                 va_sc->width = FB_WIDTH;
626         if (va_sc->height == 0)
627                 va_sc->height = FB_HEIGHT;
628
629         bcmfb_init(0, &va_sc->va, 0);
630
631         va_sc->initialized = 1;
632
633         return (0);
634 }
635
636 static int
637 bcmfb_probe(int unit, video_adapter_t **adp, void *arg, int flags)
638 {
639
640         return (0);
641 }
642
643 static int
644 bcmfb_init(int unit, video_adapter_t *adp, int flags)
645 {
646         struct video_adapter_softc *sc;
647         video_info_t *vi;
648
649         sc = (struct video_adapter_softc *)adp;
650         vi = &adp->va_info;
651
652         vid_init_struct(adp, "bcmfb", -1, unit);
653
654         sc->font = dflt_font_16;
655         vi->vi_cheight = BCMFB_FONT_HEIGHT;
656         vi->vi_cwidth = 8;
657
658         vi->vi_width = sc->width/8;
659         vi->vi_height = sc->height/vi->vi_cheight;
660
661         /*
662          * Clamp width/height to syscons maximums
663          */
664         if (vi->vi_width > COL)
665                 vi->vi_width = COL;
666         if (vi->vi_height > ROW)
667                 vi->vi_height = ROW;
668
669         sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2;
670         sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight))/2;
671
672
673         adp->va_window = (vm_offset_t) bcmfb_static_window;
674         adp->va_flags |= V_ADP_FONT /* | V_ADP_COLOR | V_ADP_MODECHANGE */;
675
676         vid_register(&sc->va);
677
678         return (0);
679 }
680
681 static int
682 bcmfb_get_info(video_adapter_t *adp, int mode, video_info_t *info)
683 {
684         bcopy(&adp->va_info, info, sizeof(*info));
685         return (0);
686 }
687
688 static int
689 bcmfb_query_mode(video_adapter_t *adp, video_info_t *info)
690 {
691         return (0);
692 }
693
694 static int
695 bcmfb_set_mode(video_adapter_t *adp, int mode)
696 {
697         return (0);
698 }
699
700 static int
701 bcmfb_save_font(video_adapter_t *adp, int page, int size, int width,
702     u_char *data, int c, int count)
703 {
704         return (0);
705 }
706
707 static int
708 bcmfb_load_font(video_adapter_t *adp, int page, int size, int width,
709     u_char *data, int c, int count)
710 {
711         struct video_adapter_softc *sc = (struct video_adapter_softc *)adp;
712
713         sc->font = data;
714
715         return (0);
716 }
717
718 static int
719 bcmfb_show_font(video_adapter_t *adp, int page)
720 {
721         return (0);
722 }
723
724 static int
725 bcmfb_save_palette(video_adapter_t *adp, u_char *palette)
726 {
727         return (0);
728 }
729
730 static int
731 bcmfb_load_palette(video_adapter_t *adp, u_char *palette)
732 {
733         return (0);
734 }
735
736 static int
737 bcmfb_set_border(video_adapter_t *adp, int border)
738 {
739         return (bcmfb_blank_display(adp, border));
740 }
741
742 static int
743 bcmfb_save_state(video_adapter_t *adp, void *p, size_t size)
744 {
745         return (0);
746 }
747
748 static int
749 bcmfb_load_state(video_adapter_t *adp, void *p)
750 {
751         return (0);
752 }
753
754 static int
755 bcmfb_set_win_org(video_adapter_t *adp, off_t offset)
756 {
757         return (0);
758 }
759
760 static int
761 bcmfb_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
762 {
763         *col = *row = 0;
764
765         return (0);
766 }
767
768 static int
769 bcmfb_set_hw_cursor(video_adapter_t *adp, int col, int row)
770 {
771         return (0);
772 }
773
774 static int
775 bcmfb_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
776     int celsize, int blink)
777 {
778         return (0);
779 }
780
781 static int
782 bcmfb_blank_display(video_adapter_t *adp, int mode)
783 {
784
785         struct video_adapter_softc *sc;
786
787         sc = (struct video_adapter_softc *)adp;
788         if (sc && sc->fb_addr)
789                 memset((void*)sc->fb_addr, 0, sc->fb_size);
790
791         return (0);
792 }
793
794 static int
795 bcmfb_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr,
796     int prot, vm_memattr_t *memattr)
797 {
798         struct video_adapter_softc *sc;
799
800         sc = (struct video_adapter_softc *)adp;
801
802         /*
803          * This might be a legacy VGA mem request: if so, just point it at the
804          * framebuffer, since it shouldn't be touched
805          */
806         if (offset < sc->stride*sc->height) {
807                 *paddr = sc->fb_paddr + offset;
808                 return (0);
809         }
810
811         return (EINVAL);
812 }
813
814 static int
815 bcmfb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t data)
816 {
817         struct video_adapter_softc *sc;
818         struct fbtype *fb;
819
820         sc = (struct video_adapter_softc *)adp;
821
822         switch (cmd) {
823         case FBIOGTYPE:
824                 fb = (struct fbtype *)data;
825                 fb->fb_type = FBTYPE_PCIMISC;
826                 fb->fb_height = sc->height;
827                 fb->fb_width = sc->width;
828                 fb->fb_depth = sc->depth;
829                 if (sc->depth <= 1 || sc->depth > 8)
830                         fb->fb_cmsize = 0;
831                 else
832                         fb->fb_cmsize = 1 << sc->depth;
833                 fb->fb_size = sc->fb_size;
834                 break;
835         default:
836                 return (fb_commonioctl(adp, cmd, data));
837         }
838
839         return (0);
840 }
841
842 static int
843 bcmfb_clear(video_adapter_t *adp)
844 {
845
846         return (bcmfb_blank_display(adp, 0));
847 }
848
849 static int
850 bcmfb_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
851 {
852
853         return (0);
854 }
855
856 static int
857 bcmfb_bitblt(video_adapter_t *adp, ...)
858 {
859
860         return (0);
861 }
862
863 static int
864 bcmfb_diag(video_adapter_t *adp, int level)
865 {
866
867         return (0);
868 }
869
870 static int
871 bcmfb_save_cursor_palette(video_adapter_t *adp, u_char *palette)
872 {
873
874         return (0);
875 }
876
877 static int
878 bcmfb_load_cursor_palette(video_adapter_t *adp, u_char *palette)
879 {
880
881         return (0);
882 }
883
884 static int
885 bcmfb_copy(video_adapter_t *adp, vm_offset_t src, vm_offset_t dst, int n)
886 {
887
888         return (0);
889 }
890
891 static int
892 bcmfb_putp(video_adapter_t *adp, vm_offset_t off, uint32_t p, uint32_t a,
893     int size, int bpp, int bit_ltor, int byte_ltor)
894 {
895
896         return (0);
897 }
898
899 static int
900 bcmfb_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a)
901 {
902         struct video_adapter_softc *sc;
903         int row;
904         int col;
905         int i, j, k;
906         uint8_t *addr;
907         u_char *p;
908         uint8_t fg, bg, color;
909         uint16_t rgb;
910
911         sc = (struct video_adapter_softc *)adp;
912
913         if (sc->fb_addr == 0)
914                 return (0);
915
916         row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight;
917         col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth;
918         p = sc->font + c*BCMFB_FONT_HEIGHT;
919         addr = (uint8_t *)sc->fb_addr
920             + (row + sc->ymargin)*(sc->stride)
921             + (sc->depth/8) * (col + sc->xmargin);
922
923         fg = a & 0xf ;
924         bg = (a >> 4) & 0xf;
925
926         for (i = 0; i < BCMFB_FONT_HEIGHT; i++) {
927                 for (j = 0, k = 7; j < 8; j++, k--) {
928                         if ((p[i] & (1 << k)) == 0)
929                                 color = bg;
930                         else
931                                 color = fg;
932
933                         switch (sc->depth) {
934                         case 32:
935                                 addr[4*j+0] = bcmfb_palette[color].r;
936                                 addr[4*j+1] = bcmfb_palette[color].g;
937                                 addr[4*j+2] = bcmfb_palette[color].b;
938                                 addr[4*j+3] = bcmfb_palette[color].a;
939                                 break;
940                         case 24:
941                                 addr[3*j] = bcmfb_palette[color].r;
942                                 addr[3*j+1] = bcmfb_palette[color].g;
943                                 addr[3*j+2] = bcmfb_palette[color].b;
944                                 break;
945                         case 16:
946                                 rgb = (bcmfb_palette[color].r >> 3) << 11;
947                                 rgb |= (bcmfb_palette[color].g >> 2) << 5;
948                                 rgb |= (bcmfb_palette[color].b >> 3);
949                                 addr[2*j] = rgb & 0xff;
950                                 addr[2*j + 1] = (rgb >> 8) & 0xff;
951                         default:
952                                 /* Not supported yet */
953                                 break;
954                         }
955                 }
956
957                 addr += (sc->stride);
958         }
959
960         return (0);
961 }
962
963 static int
964 bcmfb_puts(video_adapter_t *adp, vm_offset_t off, u_int16_t *s, int len)
965 {
966         int i;
967
968         for (i = 0; i < len; i++) 
969                 bcmfb_putc(adp, off + i, s[i] & 0xff, (s[i] & 0xff00) >> 8);
970
971         return (0);
972 }
973
974 static int
975 bcmfb_putm(video_adapter_t *adp, int x, int y, uint8_t *pixel_image,
976     uint32_t pixel_mask, int size, int width)
977 {
978
979         return (0);
980 }
981
982 /*
983  * Define a stub keyboard driver in case one hasn't been
984  * compiled into the kernel
985  */
986 #include <sys/kbio.h>
987 #include <dev/kbd/kbdreg.h>
988
989 static int dummy_kbd_configure(int flags);
990
991 keyboard_switch_t bcmdummysw;
992
993 static int
994 dummy_kbd_configure(int flags)
995 {
996
997         return (0);
998 }
999 KEYBOARD_DRIVER(bcmdummy, bcmdummysw, dummy_kbd_configure);