The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/mips/ingenic/jz4780_lcd.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca>
    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 ``AS IS'' AND ANY EXPRESS OR
   15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   19  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   21  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   22  * 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  * $FreeBSD: releng/12.0/sys/mips/ingenic/jz4780_lcd.c 338318 2018-08-25 19:38:08Z alc $
   27  */
   28 
   29 /*
   30  * Ingenic JZ4780 LCD Controller
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD: releng/12.0/sys/mips/ingenic/jz4780_lcd.c 338318 2018-08-25 19:38:08Z alc $");
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/bus.h>
   39 #include <sys/rman.h>
   40 #include <sys/condvar.h>
   41 #include <sys/kernel.h>
   42 #include <sys/module.h>
   43 #include <sys/fbio.h>
   44 #include <vm/vm.h>
   45 #include <vm/vm_extern.h>
   46 #include <vm/vm_kern.h>
   47 #include <vm/pmap.h>
   48 
   49 #include <machine/bus.h>
   50 
   51 #include <dev/ofw/ofw_bus.h>
   52 #include <dev/ofw/ofw_bus_subr.h>
   53 
   54 #include <dev/videomode/videomode.h>
   55 #include <dev/videomode/edidvar.h>
   56 
   57 #include <dev/extres/clk/clk.h>
   58 
   59 #include <mips/ingenic/jz4780_lcd.h>
   60 
   61 #include "fb_if.h"
   62 #include "hdmi_if.h"
   63 
   64 #define FB_DEFAULT_W    800
   65 #define FB_DEFAULT_H    600
   66 #define FB_DEFAULT_REF  60
   67 #define FB_BPP          32
   68 #define FB_ALIGN        (16 * 4)
   69 #define FB_MAX_BW       (1920 * 1080 * 60)
   70 #define FB_MAX_W        2048
   71 #define FB_MAX_H        2048
   72 #define FB_DIVIDE(x, y) (((x) + ((y) / 2)) / (y))
   73 
   74 #define PCFG_MAGIC      0xc7ff2100
   75 
   76 #define DOT_CLOCK_TO_HZ(c)      ((c) * 1000)
   77 
   78 #ifndef VM_MEMATTR_WRITE_COMBINING
   79 #define VM_MEMATTR_WRITE_COMBINING VM_MEMATTR_UNCACHEABLE
   80 #endif
   81 
   82 struct jzlcd_softc {
   83         device_t                dev;
   84         device_t                fbdev;
   85         struct resource         *res[1];
   86 
   87         /* Clocks */
   88         clk_t                   clk;
   89         clk_t                   clk_pix;
   90 
   91         /* Framebuffer */
   92         struct fb_info          info;
   93         size_t                  fbsize;
   94         bus_addr_t              paddr;
   95         vm_offset_t             vaddr;
   96 
   97         /* HDMI */
   98         eventhandler_tag        hdmi_evh;
   99 
  100         /* Frame descriptor DMA */
  101         bus_dma_tag_t           fdesc_tag;
  102         bus_dmamap_t            fdesc_map;
  103         bus_addr_t              fdesc_paddr;
  104         struct lcd_frame_descriptor     *fdesc;
  105 };
  106 
  107 static struct resource_spec jzlcd_spec[] = {
  108         { SYS_RES_MEMORY,       0,      RF_ACTIVE },
  109         { -1, 0 }
  110 };
  111 
  112 #define LCD_READ(sc, reg)               bus_read_4((sc)->res[0], (reg))
  113 #define LCD_WRITE(sc, reg, val)         bus_write_4((sc)->res[0], (reg), (val))
  114 
  115 static int
  116 jzlcd_allocfb(struct jzlcd_softc *sc)
  117 {
  118         sc->vaddr = kmem_alloc_contig(sc->fbsize, M_NOWAIT | M_ZERO, 0, ~0,
  119             FB_ALIGN, 0, VM_MEMATTR_WRITE_COMBINING);
  120         if (sc->vaddr == 0) {
  121                 device_printf(sc->dev, "failed to allocate FB memory\n");
  122                 return (ENOMEM);
  123         }
  124         sc->paddr = pmap_kextract(sc->vaddr);
  125 
  126         return (0);
  127 }
  128 
  129 static void
  130 jzlcd_freefb(struct jzlcd_softc *sc)
  131 {
  132         kmem_free(sc->vaddr, sc->fbsize);
  133 }
  134 
  135 static void
  136 jzlcd_start(struct jzlcd_softc *sc)
  137 {
  138         uint32_t ctrl;
  139 
  140         /* Clear status registers */
  141         LCD_WRITE(sc, LCDSTATE, 0);
  142         LCD_WRITE(sc, LCDOSDS, 0);
  143         /* Enable the controller */
  144         ctrl = LCD_READ(sc, LCDCTRL);
  145         ctrl |= LCDCTRL_ENA;
  146         ctrl &= ~LCDCTRL_DIS;
  147         LCD_WRITE(sc, LCDCTRL, ctrl);
  148 }
  149 
  150 static void
  151 jzlcd_stop(struct jzlcd_softc *sc)
  152 {
  153         uint32_t ctrl;
  154 
  155         ctrl = LCD_READ(sc, LCDCTRL);
  156         if ((ctrl & LCDCTRL_ENA) != 0) {
  157                 /* Disable the controller and wait for it to stop */
  158                 ctrl |= LCDCTRL_DIS;
  159                 LCD_WRITE(sc, LCDCTRL, ctrl);
  160                 while ((LCD_READ(sc, LCDSTATE) & LCDSTATE_LDD) == 0)
  161                         DELAY(100);
  162         }
  163         /* Clear all status except for disable */
  164         LCD_WRITE(sc, LCDSTATE, LCD_READ(sc, LCDSTATE) & ~LCDSTATE_LDD);
  165 }
  166 
  167 static void
  168 jzlcd_setup_descriptor(struct jzlcd_softc *sc, const struct videomode *mode,
  169     u_int desno)
  170 {
  171         struct lcd_frame_descriptor *fdesc;
  172         int line_sz;
  173 
  174         /* Frame size is specified in # words */
  175         line_sz = (mode->hdisplay * FB_BPP) >> 3;
  176         line_sz = ((line_sz + 3) & ~3) / 4;
  177 
  178         fdesc = sc->fdesc + desno;
  179 
  180         if (desno == 0)
  181                 fdesc->next = sc->fdesc_paddr +
  182                     sizeof(struct lcd_frame_descriptor);
  183         else
  184                 fdesc->next = sc->fdesc_paddr;
  185         fdesc->physaddr = sc->paddr;
  186         fdesc->id = desno;
  187         fdesc->cmd = LCDCMD_FRM_EN | (line_sz * mode->vdisplay);
  188         fdesc->offs = 0;
  189         fdesc->pw = 0;
  190         fdesc->cnum_pos = LCDPOS_BPP01_18_24 |
  191             LCDPOS_PREMULTI01 |
  192             (desno == 0 ? LCDPOS_COEF_BLE01_1 : LCDPOS_COEF_SLE01);
  193         fdesc->dessize = LCDDESSIZE_ALPHA |
  194             ((mode->vdisplay - 1) << LCDDESSIZE_HEIGHT_SHIFT) |
  195             ((mode->hdisplay - 1) << LCDDESSIZE_WIDTH_SHIFT);
  196 }
  197 
  198 static int
  199 jzlcd_set_videomode(struct jzlcd_softc *sc, const struct videomode *mode)
  200 {
  201         u_int hbp, hfp, hsw, vbp, vfp, vsw;
  202         u_int hds, hde, ht, vds, vde, vt;
  203         uint32_t ctrl;
  204         int error;
  205 
  206         hbp = mode->htotal - mode->hsync_end;
  207         hfp = mode->hsync_start - mode->hdisplay;
  208         hsw = mode->hsync_end - mode->hsync_start;
  209         vbp = mode->vtotal - mode->vsync_end;
  210         vfp = mode->vsync_start - mode->vdisplay;
  211         vsw = mode->vsync_end - mode->vsync_start;
  212 
  213         hds = hsw + hbp;
  214         hde = hds + mode->hdisplay;
  215         ht = hde + hfp;
  216 
  217         vds = vsw + vbp;
  218         vde = vds + mode->vdisplay;
  219         vt = vde + vfp;
  220 
  221         /* Setup timings */
  222         LCD_WRITE(sc, LCDVAT,
  223             (ht << LCDVAT_HT_SHIFT) | (vt << LCDVAT_VT_SHIFT));
  224         LCD_WRITE(sc, LCDDAH,
  225             (hds << LCDDAH_HDS_SHIFT) | (hde << LCDDAH_HDE_SHIFT));
  226         LCD_WRITE(sc, LCDDAV,
  227             (vds << LCDDAV_VDS_SHIFT) | (vde << LCDDAV_VDE_SHIFT));
  228         LCD_WRITE(sc, LCDHSYNC, hsw);
  229         LCD_WRITE(sc, LCDVSYNC, vsw);
  230 
  231         /* Set configuration */
  232         LCD_WRITE(sc, LCDCFG, LCDCFG_NEWDES | LCDCFG_RECOVER | LCDCFG_24 |
  233             LCDCFG_PSM | LCDCFG_CLSM | LCDCFG_SPLM | LCDCFG_REVM | LCDCFG_PCP);
  234         ctrl = LCD_READ(sc, LCDCTRL);
  235         ctrl &= ~LCDCTRL_BST;
  236         ctrl |= LCDCTRL_BST_64 | LCDCTRL_OFUM;
  237         LCD_WRITE(sc, LCDCTRL, ctrl);
  238         LCD_WRITE(sc, LCDPCFG, PCFG_MAGIC);
  239         LCD_WRITE(sc, LCDRGBC, LCDRGBC_RGBFMT);
  240 
  241         /* Update registers */
  242         LCD_WRITE(sc, LCDSTATE, 0);
  243 
  244         /* Setup frame descriptors */
  245         jzlcd_setup_descriptor(sc, mode, 0);
  246         jzlcd_setup_descriptor(sc, mode, 1);
  247         bus_dmamap_sync(sc->fdesc_tag, sc->fdesc_map, BUS_DMASYNC_PREWRITE);
  248 
  249         /* Setup DMA channels */
  250         LCD_WRITE(sc, LCDDA0, sc->fdesc_paddr
  251             + sizeof(struct lcd_frame_descriptor));
  252         LCD_WRITE(sc, LCDDA1, sc->fdesc_paddr);
  253 
  254         /* Set display clock */
  255         error = clk_set_freq(sc->clk_pix, DOT_CLOCK_TO_HZ(mode->dot_clock), 0);
  256         if (error != 0) {
  257                 device_printf(sc->dev, "failed to set pixel clock to %u Hz\n",
  258                     DOT_CLOCK_TO_HZ(mode->dot_clock));
  259                 return (error);
  260         }
  261 
  262         return (0);
  263 }
  264 
  265 static int
  266 jzlcd_configure(struct jzlcd_softc *sc, const struct videomode *mode)
  267 {
  268         size_t fbsize;
  269         int error;
  270 
  271         fbsize = round_page(mode->hdisplay * mode->vdisplay * (FB_BPP / NBBY));
  272 
  273         /* Detach the old FB device */
  274         if (sc->fbdev != NULL) {
  275                 device_delete_child(sc->dev, sc->fbdev);
  276                 sc->fbdev = NULL;
  277         }
  278 
  279         /* If the FB size has changed, free the old FB memory */
  280         if (sc->fbsize > 0 && sc->fbsize != fbsize) {
  281                 jzlcd_freefb(sc);
  282                 sc->vaddr = 0;
  283         }
  284 
  285         /* Allocate the FB if necessary */
  286         sc->fbsize = fbsize;
  287         if (sc->vaddr == 0) {
  288                 error = jzlcd_allocfb(sc);
  289                 if (error != 0) {
  290                         device_printf(sc->dev, "failed to allocate FB memory\n");
  291                         return (ENXIO);
  292                 }
  293         }
  294 
  295         /* Setup video mode */
  296         error = jzlcd_set_videomode(sc, mode);
  297         if (error != 0)
  298                 return (error);
  299 
  300         /* Attach framebuffer device */
  301         sc->info.fb_name = device_get_nameunit(sc->dev);
  302         sc->info.fb_vbase = (intptr_t)sc->vaddr;
  303         sc->info.fb_pbase = sc->paddr;
  304         sc->info.fb_size = sc->fbsize;
  305         sc->info.fb_bpp = sc->info.fb_depth = FB_BPP;
  306         sc->info.fb_stride = mode->hdisplay * (FB_BPP / NBBY);
  307         sc->info.fb_width = mode->hdisplay;
  308         sc->info.fb_height = mode->vdisplay;
  309 #ifdef VM_MEMATTR_WRITE_COMBINING
  310         sc->info.fb_flags = FB_FLAG_MEMATTR;
  311         sc->info.fb_memattr = VM_MEMATTR_WRITE_COMBINING;
  312 #endif
  313         sc->fbdev = device_add_child(sc->dev, "fbd", device_get_unit(sc->dev));
  314         if (sc->fbdev == NULL) {
  315                 device_printf(sc->dev, "failed to add fbd child\n");
  316                 return (ENOENT);
  317         }
  318 
  319         error = device_probe_and_attach(sc->fbdev);
  320         if (error != 0) {
  321                 device_printf(sc->dev, "failed to attach fbd device\n");
  322                 return (error);
  323         }
  324 
  325         return (0);
  326 }
  327 
  328 static int
  329 jzlcd_get_bandwidth(const struct videomode *mode)
  330 {
  331         int refresh;
  332 
  333         refresh = FB_DIVIDE(FB_DIVIDE(DOT_CLOCK_TO_HZ(mode->dot_clock),
  334             mode->htotal), mode->vtotal);
  335 
  336         return mode->hdisplay * mode->vdisplay * refresh;
  337 }
  338 
  339 static int
  340 jzlcd_mode_supported(const struct videomode *mode)
  341 {
  342         /* Width and height must be less than 2048 */
  343         if (mode->hdisplay > FB_MAX_W || mode->vdisplay > FB_MAX_H)
  344                 return (0);
  345 
  346         /* Bandwidth check */
  347         if (jzlcd_get_bandwidth(mode) > FB_MAX_BW)
  348                 return (0);
  349 
  350         /* Interlace modes not yet supported by the driver */
  351         if ((mode->flags & VID_INTERLACE) != 0)
  352                 return (0);
  353 
  354         return (1);
  355 }
  356 
  357 static const struct videomode *
  358 jzlcd_find_mode(struct edid_info *ei)
  359 {
  360         const struct videomode *best;
  361         int n, bw, best_bw;
  362 
  363         /* If the preferred mode is OK, just use it */
  364         if (jzlcd_mode_supported(ei->edid_preferred_mode) != 0)
  365                 return ei->edid_preferred_mode;
  366 
  367         /* Pick the mode with the highest bandwidth requirements */
  368         best = NULL;
  369         best_bw = 0;
  370         for (n = 0; n < ei->edid_nmodes; n++) {
  371                 if (jzlcd_mode_supported(&ei->edid_modes[n]) == 0)
  372                         continue;
  373                 bw = jzlcd_get_bandwidth(&ei->edid_modes[n]);
  374                 if (bw > FB_MAX_BW)
  375                         continue;
  376                 if (best == NULL || bw > best_bw) {
  377                         best = &ei->edid_modes[n];
  378                         best_bw = bw;
  379                 }
  380         }
  381 
  382         return best;
  383 }
  384 
  385 static void
  386 jzlcd_hdmi_event(void *arg, device_t hdmi_dev)
  387 {
  388         const struct videomode *mode;
  389         struct videomode hdmi_mode;
  390         struct jzlcd_softc *sc;
  391         struct edid_info ei;
  392         uint8_t *edid;
  393         uint32_t edid_len;
  394         int error;
  395 
  396         sc = arg;
  397         edid = NULL;
  398         edid_len = 0;
  399         mode = NULL;
  400 
  401         error = HDMI_GET_EDID(hdmi_dev, &edid, &edid_len);
  402         if (error != 0) {
  403                 device_printf(sc->dev, "failed to get EDID: %d\n", error);
  404         } else {
  405                 error = edid_parse(edid, &ei);
  406                 if (error != 0) {
  407                         device_printf(sc->dev, "failed to parse EDID: %d\n",
  408                             error);
  409                 } else {
  410                         if (bootverbose)
  411                                 edid_print(&ei);
  412 
  413                         mode = jzlcd_find_mode(&ei);
  414                 }
  415         }
  416 
  417         /* If a suitable mode could not be found, try the default */
  418         if (mode == NULL)
  419                 mode = pick_mode_by_ref(FB_DEFAULT_W, FB_DEFAULT_H,
  420                     FB_DEFAULT_REF);
  421 
  422         if (mode == NULL) {
  423                 device_printf(sc->dev, "failed to find usable video mode\n");
  424                 return;
  425         }
  426 
  427         if (bootverbose)
  428                 device_printf(sc->dev, "using %dx%d\n",
  429                     mode->hdisplay, mode->vdisplay);
  430 
  431         /* Stop the controller */
  432         jzlcd_stop(sc);
  433 
  434         /* Configure LCD controller */
  435         error = jzlcd_configure(sc, mode);
  436         if (error != 0) {
  437                 device_printf(sc->dev, "failed to configure FB: %d\n", error);
  438                 return;
  439         }
  440 
  441         /* Enable HDMI TX */
  442         hdmi_mode = *mode;
  443         HDMI_SET_VIDEOMODE(hdmi_dev, &hdmi_mode);
  444 
  445         /* Start the controller! */
  446         jzlcd_start(sc);
  447 }
  448 
  449 static void
  450 jzlcd_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
  451 {
  452         if (error != 0)
  453                 return;
  454         *(bus_addr_t *)arg = segs[0].ds_addr;
  455 }
  456 
  457 static int
  458 jzlcd_probe(device_t dev)
  459 {
  460         if (!ofw_bus_status_okay(dev))
  461                 return (ENXIO);
  462 
  463         if (!ofw_bus_is_compatible(dev, "ingenic,jz4780-lcd"))
  464                 return (ENXIO);
  465 
  466         device_set_desc(dev, "Ingenic JZ4780 LCD Controller");
  467         return (BUS_PROBE_DEFAULT);
  468 }
  469 
  470 static int
  471 jzlcd_attach(device_t dev)
  472 {
  473         struct jzlcd_softc *sc;
  474         int error;
  475 
  476         sc = device_get_softc(dev);
  477 
  478         sc->dev = dev;
  479 
  480         if (bus_alloc_resources(dev, jzlcd_spec, sc->res)) {
  481                 device_printf(dev, "cannot allocate resources for device\n");
  482                 goto failed;
  483         }
  484 
  485         if (clk_get_by_ofw_name(dev, 0, "lcd_clk", &sc->clk) != 0 ||
  486             clk_get_by_ofw_name(dev, 0, "lcd_pixclk", &sc->clk_pix) != 0) {
  487                 device_printf(dev, "cannot get clocks\n");
  488                 goto failed;
  489         }
  490         if (clk_enable(sc->clk) != 0 || clk_enable(sc->clk_pix) != 0) {
  491                 device_printf(dev, "cannot enable clocks\n");
  492                 goto failed;
  493         }
  494 
  495         error = bus_dma_tag_create(
  496             bus_get_dma_tag(dev),
  497             sizeof(struct lcd_frame_descriptor), 0,
  498             BUS_SPACE_MAXADDR_32BIT,
  499             BUS_SPACE_MAXADDR,
  500             NULL, NULL,
  501             sizeof(struct lcd_frame_descriptor) * 2, 1,
  502             sizeof(struct lcd_frame_descriptor) * 2,
  503             0,
  504             NULL, NULL,
  505             &sc->fdesc_tag);
  506         if (error != 0) {
  507                 device_printf(dev, "cannot create bus dma tag\n");
  508                 goto failed;
  509         }
  510 
  511         error = bus_dmamem_alloc(sc->fdesc_tag, (void **)&sc->fdesc,
  512             BUS_DMA_NOCACHE | BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->fdesc_map);
  513         if (error != 0) {
  514                 device_printf(dev, "cannot allocate dma descriptor\n");
  515                 goto dmaalloc_failed;
  516         }
  517 
  518         error = bus_dmamap_load(sc->fdesc_tag, sc->fdesc_map, sc->fdesc,
  519             sizeof(struct lcd_frame_descriptor) * 2, jzlcd_dmamap_cb,
  520             &sc->fdesc_paddr, 0);
  521         if (error != 0) {
  522                 device_printf(dev, "cannot load dma map\n");
  523                 goto dmaload_failed;
  524         }
  525 
  526         sc->hdmi_evh = EVENTHANDLER_REGISTER(hdmi_event,
  527             jzlcd_hdmi_event, sc, 0);
  528 
  529         return (0);
  530 
  531 dmaload_failed:
  532         bus_dmamem_free(sc->fdesc_tag, sc->fdesc, sc->fdesc_map);
  533 dmaalloc_failed:
  534         bus_dma_tag_destroy(sc->fdesc_tag);
  535 failed:
  536         if (sc->clk_pix != NULL)
  537                 clk_release(sc->clk);
  538         if (sc->clk != NULL)
  539                 clk_release(sc->clk);
  540         if (sc->res != NULL)
  541                 bus_release_resources(dev, jzlcd_spec, sc->res);
  542 
  543         return (ENXIO);
  544 }
  545 
  546 static struct fb_info *
  547 jzlcd_fb_getinfo(device_t dev)
  548 {
  549         struct jzlcd_softc *sc;
  550 
  551         sc = device_get_softc(dev);
  552 
  553         return (&sc->info);
  554 }
  555 
  556 static device_method_t jzlcd_methods[] = {
  557         /* Device interface */
  558         DEVMETHOD(device_probe,         jzlcd_probe),
  559         DEVMETHOD(device_attach,        jzlcd_attach),
  560 
  561         /* FB interface */
  562         DEVMETHOD(fb_getinfo,           jzlcd_fb_getinfo),
  563 
  564         DEVMETHOD_END
  565 };
  566 
  567 static driver_t jzlcd_driver = {
  568         "fb",
  569         jzlcd_methods,
  570         sizeof(struct jzlcd_softc),
  571 };
  572 
  573 static devclass_t jzlcd_devclass;
  574 
  575 DRIVER_MODULE(fb, simplebus, jzlcd_driver, jzlcd_devclass, 0, 0);

Cache object: f8c789d3324969731b155d64a27736e4


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.