> Date: Sat, 6 Aug 2016 04:26:27 -0400
> From: Ian Sutton <[email protected]>

Hi Ian,

> amdisplay(4) drives the LCD controller in am335x SoCs (beaglebone black
> for us). Patch is unfinished but is further along than imxdisplay(4).
> (imx6q's display subsystem is enormously complicated and poorly
> documented; I intend to finish both but am working on this one for now).

Right.  I had a quick look at the documentation there and quickly
decided it wasn't an immediate priority.

Note that on many platforms (including i.MX6) u-boot already sets up a
framebuffer.  So if we'd know framebuffer address and the layout of
the framebuffer it would be trivial to attach a rasops-based
wsdisplay(4) to that.  There is a "simple-framebuffer" device tree
binding for passing that information; see

  Documentation/devicetree/bindings/display/simple-framebuffer.txt

in the Linux tree.  Unofrtunately u-boot only adds the appropriate
nodes to the tree on the Allwinner and Raspberry Pi platforms.  I
don't think it would be too difficult to add it for other platforms
though.

Of course this wouldn't allow you to change resolution and color
depth.  But it would be enough to run X with the wsfb driver.

> Interestingly, the am335x SoC does not have a HDMI/DP/etc transmitter on
> silicon -- the BBB has its LCDC pins wired to a TDA19988 HDMI
> transmitter which is additionally backwired to one of the am335x's i2c
> ports:
> 
> "nxp,tda998x" at iic0 addr 0x70 not configured
> 
> Without a TDA19988 driver we are unable to probe for an attached
> display's EDID bits thus unable to tailor timing/videomode parameters
> on a per-display basis.
> 
> I am working on such a driver but would like to ask developers if it
> would be worth it, or if there is more important armv7 work to be done
> elsewhere.

If it interests you, go for it.  But I think that for most of our
users a simple framebuffer as I sketched above would be good enough.
So for me, this doesn't have a very high priority.


> Index: sys/arch/armv7/conf/GENERIC
> ===================================================================
> RCS file: /cvs/src/sys/arch/armv7/conf/GENERIC,v
> retrieving revision 1.31
> diff -u -p -r1.31 GENERIC
> --- sys/arch/armv7/conf/GENERIC       12 Jul 2016 19:17:49 -0000      1.31
> +++ sys/arch/armv7/conf/GENERIC       6 Aug 2016 07:59:48 -0000
> @@ -76,6 +76,8 @@ cpsw*               at fdt?
>  com*         at fdt?                 # onboard uarts
>  ommmc*               at fdt?                 # SD/MMC card controller
>  sdmmc*               at ommmc?               # SD/MMC bus
> +amdisplay*   at fdt?                 # LCD controller
> +wsdisplay*   at amdisplay? console ?
>  
>  ehci*                at omap?                # EHCI (shim)
>  usb*         at ehci?
> Index: sys/arch/armv7/omap/am335x_prcmreg.h
> ===================================================================
> RCS file: /cvs/src/sys/arch/armv7/omap/am335x_prcmreg.h,v
> retrieving revision 1.4
> diff -u -p -r1.4 am335x_prcmreg.h
> --- sys/arch/armv7/omap/am335x_prcmreg.h      18 Mar 2014 07:34:17 -0000      
> 1.4
> +++ sys/arch/armv7/omap/am335x_prcmreg.h      6 Aug 2016 07:59:48 -0000
> @@ -20,6 +20,7 @@
>  #define AM335X_CLKCTRL_MODULEMODE_MASK               0x00000003
>  
>  #define PRCM_AM335X_CM_PER           0x0000
> +#define PRCM_AM335X_LCDC_CLKCTRL     0x0018
>  #define PRCM_AM335X_USB0_CLKCTRL     0x001c
>  #define PRCM_AM335X_TPTC0_CLKCTRL    0x0024
>  #define PRCM_AM335X_MMC0_CLKCTRL     0x003c
> Index: sys/arch/armv7/omap/amdisplay.c
> ===================================================================
> RCS file: sys/arch/armv7/omap/amdisplay.c
> diff -N sys/arch/armv7/omap/amdisplay.c
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ sys/arch/armv7/omap/amdisplay.c   6 Aug 2016 07:59:48 -0000
> @@ -0,0 +1,371 @@
> +/*
> + * Copyright (c) 2016 Ian Sutton <[email protected]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/param.h>
> +#include <sys/systm.h>
> +
> +#include <dev/cons.h>
> +#include <dev/wscons/wsconsio.h>
> +#include <dev/wscons/wsdisplayvar.h>
> +#include <dev/wscons/wscons_callbacks.h>
> +#include <dev/rasops/rasops.h>
> +
> +#include <dev/ofw/openfirm.h>
> +#include <dev/ofw/fdt.h>
> +#include <machine/fdt.h>
> +
> +#include <armv7/omap/prcmvar.h>
> +
> +/* register offsets */
> +#define AMDISPLAY_PID                        0x00
> +#define AMDISPLAY_CTRL                       0x04
> +#define   AMDISPLAY_CTRL_CLKDIV_MASK (0xFF << 8)
> +#define   AMDISPLAY_CTRL_MODESEL_MASK        (1 << 0)
> +#define AMDISPLAY_RASTER_CTRL                0x28
> +#define   AMDISPLAY_RASTER_CTRL_TFT24UNPACKED_MASK   (1 << 26)
> +#define   AMDISPLAY_RASTER_CTRL_TFT24_MASK           (1 << 25)
> +#define   AMDISPLAY_RASTER_CTRL_LCDTFT_MASK          (1 << 7)
> +#define   AMDISPLAY_RASTER_CTRL_LCDEN_MASK           (1 << 0)
> +#define AMDISPLAY_RASTER_TIMING_0    0x2C
> +#define AMDISPLAY_RASTER_TIMING_1    0x30
> +#define AMDISPLAY_RASTER_TIMING_2    0x34
> +#define AMDISPLAY_RASTER_SUBPANEL    0x38
> +#define AMDISPLAY_RASTER_SUBPANEL_2  0x3C
> +#define AMDISPLAY_LCDDMA_CTRL                0x40
> +#define AMDISPLAY_LCDDMA_FB0_BASE    0x44
> +#define AMDISPLAY_LCDDMA_FB0_CEILING 0x48
> +#define AMDISPLAY_LCDDMA_FB1_BASE    0x4C
> +#define AMDISPLAY_LCDDMA_FB1_CEILING 0x50
> +#define AMDISPLAY_SYSCONFIG          0x54
> +#define   AMDISPLAY_SYSCONFIG_STANDBYMODE_MASK               (3 << 4)
> +#define   AMDISPLAY_SYSCONFIG_IDLEMODE_MASK          (3 << 2)
> +#define   AMDISPLAY_SYSCONFIG_STANDBYMODE_SHAMT              4
> +#define   AMDISPLAY_SYSCONFIG_IDLEMODE_SHAMT         2
> +#define AMDISPLAY_IRQSTATUS_RAW              0x58
> +#define AMDISPLAY_IRQSTATUS          0x5C
> +#define AMDISPLAY_IRQENABLE_SET              0x60
> +#define AMDISPLAY_IRQENABLE_CLEAR    0x64
> +#define AMDISPLAY_CLKC_ENABLE                0x6C
> +#define AMDISPLAY_CLKC_RESET         0x70
> +
> +/* intr. masks */
> +#define AMDISPLAY_IRQ_EOF1   (1 << 9)
> +#define AMDISPLAY_IRQ_EOF0   (1 << 8)
> +#define AMDISPLAY_IRQ_PL     (1 << 6)
> +#define AMDISPLAY_IRQ_FUF    (1 << 5)
> +#define AMDISPLAY_IRQ_ACB    (1 << 3)
> +#define AMDISPLAY_IRQ_SYNC   (1 << 2)
> +#define AMDISPLAY_IRQ_RR_DONE        (1 << 1)
> +#define AMDISPLAY_IRQ_DONE   (1 << 0)
> +
> +#define DEVNAME(_s) ((_s)->sc_dev.dv_xname)
> +
> +#define HREAD4(sc, reg)                                                      
> \
> +     (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
> +#define HWRITE4(sc, reg, val)                                                
> \
> +     bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
> +#define HSET4(sc, reg, bits)                                         \
> +     HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
> +#define HCLR4(sc, reg, bits)                                         \
> +     HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
> +
> +struct amdisplay_softc {
> +     struct device           sc_dev;
> +     bus_space_tag_t         sc_iot;
> +     bus_space_handle_t      sc_ioh;
> +     bus_dma_tag_t           sc_dmat;
> +     void                    *sc_ih;
> +
> +     struct amdisplay_panel_data     *sc_active;
> +     bus_dmamap_t            sc_fb_dma;
> +     bus_dma_segment_t       sc_fb_dma_segs[1];
> +     int                     sc_fb_dma_nsegs;
> +     size_t                  sc_fb_size;
> +     caddr_t                 sc_fb;
> +     int                     depth;
> +     struct rasops_info      ro;
> +};
> +
> +struct amdisplay_panel_data {
> +     int width;
> +     int height;
> +     int horiz_sync_width;
> +     int horiz_front_porch;
> +     int horiz_back_porch;
> +     int vert_sync_width;
> +     int vert_front_porch;
> +     int vert_back_porch;
> +     int panel_flags;
> +     int sync;
> +     int depth;
> +#define PANEL_SYNC_H_ACTIVE_HIGH 1
> +#define PANEL_SYNC_V_ACTIVE_HIGH 2
> +     int linebytes;
> +};
> +
> +/* we use this dummy device and hope it applies as the am335x has no on-chip
> + * method of determining peripheral display capabilities. the beaglebone 
> black
> + * has the LCDC pins hardwired to a TDA19988 which sits between LCDC & HDMI
> + * connector and is also wired to an i2c port over which it sends EDID
> + * information needed to properly configure display geometry on a per-panel
> + * basis XXX */
> +struct amdisplay_panel_data dummy = {
> +     1280,
> +     720,
> +     44, 88, 148,
> +     5, 4, 36,
> +     0,
> +     0,
> +     24,
> +     2560
> +};
> +
> +struct wsscreen_descr amdisplay_stdscreen = {
> +     "std"
> +};
> +
> +const struct wsscreen_descr *amdisplay_scrlist[] = {
> +     &amdisplay_stdscreen,
> +};
> +
> +struct wsscreen_list amdisplay_screenlist = {
> +     nitems(amdisplay_scrlist), amdisplay_scrlist
> +};
> +
> +int  amdisplay_match(struct device *, void *, void *);
> +void amdisplay_attach(struct device *, struct device *, void *);
> +int  amdisplay_activate(struct device *, int);
> +int  amdisplay_intr(void *);
> +
> +int  amdisplay_ioctl(void *, u_long, caddr_t, int, struct proc *);
> +int  amdisplay_alloc_screen(void *, const struct wsscreen_descr *,
> +     void **, int *, int *, long *);
> +void amdisplay_free_screen(void *, void *);
> +int  amdisplay_show_screen(void *, void *, int,
> +     void (*)(void *, int, int), void *);
> +void amdisplay_doswitch(void *, void *);
> +int  amdisplay_load_font(void *, void *, struct wsdisplay_font *);
> +int  amdisplay_list_font(void *, struct wsdisplay_font *);
> +int  amdisplay_getchar(void *, int, int, struct wsdisplay_charcell *);
> +void amdisplay_burner(void *, u_int, u_int);
> +paddr_t amdisplay_mmap(void *, off_t, int);
> +
> +void amdisplay_setup_rasops(struct amdisplay_softc *);
> +int  amdisplay_setup_dma(struct amdisplay_softc *, struct 
> amdisplay_panel_data *);
> +
> +struct wsdisplay_accessops amdisplay_accessops = {
> +     .ioctl = amdisplay_ioctl,
> +     .mmap = amdisplay_mmap,
> +     .alloc_screen = amdisplay_alloc_screen,
> +     .free_screen = amdisplay_free_screen,
> +     .show_screen = amdisplay_show_screen,
> +     .getchar = amdisplay_getchar,
> +     .load_font = amdisplay_load_font,
> +     .list_font = amdisplay_list_font,
> +     .burn_screen = amdisplay_burner
> +};
> +
> +struct cfattach amdisplay_ca = {
> +     sizeof(struct amdisplay_softc), amdisplay_match, amdisplay_attach
> +};
> +
> +struct cfdriver amdisplay_cd = {
> +     NULL, "amdisplay", DV_DULL
> +};
> +
> +int
> +amdisplay_match(struct device *parent, void *v, void *aux)
> +{
> +     struct fdt_attach_args *faa = aux;
> +     return OF_is_compatible(faa->fa_node, "ti,am33xx-tilcdc");
> +}
> +
> +void
> +amdisplay_attach(struct device *parent, struct device *self, void *args)
> +{
> +     struct   amdisplay_softc        *sc = (struct amdisplay_softc *) self;
> +     struct   fdt_attach_args        *faa = args;
> +     struct   wsemuldisplaydev_attach_args wsaa;
> +     
> +     uint32_t irq, reg;
> +
> +     sc->sc_iot  = faa->fa_iot;
> +     sc->sc_dmat = faa->fa_dmat;
> +     if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
> +         faa->fa_reg[0].size, 0, &sc->sc_ioh))
> +             panic("%s: bus_space_map failed!", __func__);
> +
> +     irq = faa->fa_intr[0];
> +
> +     prcm_enablemodule(PRCM_LCDC);
> +
> +     /* force ourselves out of standby/idle states */
> +     reg = HREAD4(sc, AMDISPLAY_SYSCONFIG);
> +     reg &= ~(AMDISPLAY_SYSCONFIG_STANDBYMODE_MASK | 
> AMDISPLAY_SYSCONFIG_IDLEMODE_MASK);
> +     reg |= (1 << AMDISPLAY_SYSCONFIG_STANDBYMODE_SHAMT);
> +     reg |= (1 << AMDISPLAY_SYSCONFIG_IDLEMODE_SHAMT);
> +     HWRITE4(sc, AMDISPLAY_SYSCONFIG, reg);
> +
> +     sc->sc_ih = arm_intr_establish(irq, IPL_BIO, amdisplay_intr, sc, 
> DEVNAME(sc));
> +
> +     printf("\n");
> +
> +     /* allocate DMA-able memory for framebuffer */
> +     if (amdisplay_setup_dma(sc, &dummy)) {
> +         printf("%s: could not create framebuffer!\n", DEVNAME(sc));
> +         return;
> +     }
> +
> +     amdisplay_setup_rasops(sc);
> +
> +     /* set raster mode */
> +     HSET4(sc, AMDISPLAY_CTRL, AMDISPLAY_CTRL_MODESEL_MASK);
> +
> +     /* enable all intrs. */
> +     reg = 0;
> +     reg |= (AMDISPLAY_IRQ_EOF1 | AMDISPLAY_IRQ_EOF0 | AMDISPLAY_IRQ_PL |
> +         AMDISPLAY_IRQ_FUF | AMDISPLAY_IRQ_ACB | AMDISPLAY_IRQ_SYNC |
> +         AMDISPLAY_IRQ_RR_DONE | AMDISPLAY_IRQ_DONE);
> +     HWRITE4(sc, AMDISPLAY_IRQENABLE_SET, reg);
> +
> +     wsaa.console = 0;
> +     wsaa.scrdata = &amdisplay_screenlist;
> +     wsaa.accessops = &amdisplay_accessops;
> +     wsaa.accesscookie = sc;
> +     wsaa.defaultscreens = 0;
> +
> +     printf("%s: %dx%d\n", sc->sc_dev.dv_xname, sc->ro.ri_width, 
> sc->ro.ri_height);
> +
> +     //config_found(self, &wsaa, wsemuldisplaydevprint);
> +}
> +
> +void
> +amdisplay_setup_rasops(struct amdisplay_softc *sc)
> +{
> +     sc->ro.ri_depth  = sc->sc_active->depth;
> +     sc->ro.ri_width  = sc->sc_active->width;
> +     sc->ro.ri_height = sc->sc_active->height;
> +     sc->ro.ri_stride = sc->sc_active->width * sc->sc_active->depth;
> +     sc->ro.ri_bits   = (void *) sc->sc_fb;
> +
> +     rasops_init(&(sc->ro), 100, 100);
> +}
> +
> +int
> +amdisplay_setup_dma(struct amdisplay_softc *sc, struct amdisplay_panel_data 
> *p)
> +{
> +     size_t fb_size;
> +     int dma_flags     = (cold ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
> +
> +     //fb_size = p->width * p->height * p->depth;
> +     fb_size = roundup(p->height * p->linebytes, 16);
> +     if(bus_dmamap_create(sc->sc_dmat, fb_size, 1, fb_size, 0, dma_flags,
> +         &(sc->sc_fb_dma)))
> +             return -1;
> +
> +     if(bus_dmamem_alloc(sc->sc_dmat, fb_size, 0x100000, 0, 
> sc->sc_fb_dma_segs,
> +         1, &(sc->sc_fb_dma_nsegs), dma_flags)) /* XXX check alignment */
> +             return -1;
> +
> +     sc->sc_fb = NULL;
> +     if(bus_dmamem_map(sc->sc_dmat, sc->sc_fb_dma_segs, sc->sc_fb_dma_nsegs,
> +         fb_size, &(sc->sc_fb), dma_flags))
> +             return -1;
> +
> +     sc->sc_active = p;
> +     return 0;
> +}
> +
> +int
> +amdisplay_intr(void *arg)
> +{
> +     return 0;
> +}
> +
> +int
> +amdisplay_ioctl(void *sconf, u_long cmd, caddr_t data, int flat, struct proc 
> *p)
> +{
> +     return -1;
> +}
> +
> +paddr_t
> +amdisplay_mmap(void *sconf, off_t off, int prot)
> +{
> +     return -1;
> +}
> +
> +int
> +amdisplay_alloc_screen(void *sconf, const struct wsscreen_descr *type,
> +     void **cookiep, int *curxp, int *curyp, long *attrp)
> +{
> +     struct amdisplay_softc *sc = sconf;
> +     struct rasops_info *ri = &(sc->ro);
> +
> +     return rasops_alloc_screen(ri, cookiep, curxp, curyp, attrp);
> +}
> +
> +void
> +amdisplay_free_screen(void *sconf, void *cookie)
> +{
> +     struct amdisplay_softc *sc = sconf;
> +     struct rasops_info *ri = &(sc->ro);
> +
> +     return rasops_free_screen(ri, cookie);
> +}
> +
> +int
> +amdisplay_show_screen(void *sconf, void *cookie, int waitok,
> +     void (*cb)(void *, int, int), void *cbarg)
> +{
> +     return (0);
> +}
> +
> +void
> +amdisplay_doswitch(void *v, void *dummy)
> +{
> +}
> +
> +int
> +amdisplay_getchar(void *sconf, int row, int col, struct wsdisplay_charcell 
> *cell)
> +{
> +     struct amdisplay_softc *sc = sconf;
> +     struct rasops_info *ri = &(sc->ro);
> +
> +     return rasops_getchar(ri, row, col, cell);
> +}
> +
> +int
> +amdisplay_load_font(void *sconf, void *cookie, struct wsdisplay_font *font)
> +{
> +     struct amdisplay_softc *sc = sconf;
> +     struct rasops_info *ri = &(sc->ro);
> +
> +     return rasops_load_font(ri, cookie, font);
> +}
> +
> +int
> +amdisplay_list_font(void *sconf, struct wsdisplay_font *font)
> +{
> +     struct amdisplay_softc *sc = sconf;
> +     struct rasops_info *ri = &(sc->ro);
> +
> +     return rasops_list_font(ri, font);
> +}
> +
> +void
> +amdisplay_burner(void *sconf, u_int on, u_int flags)
> +{
> +}
> Index: sys/arch/armv7/omap/files.omap
> ===================================================================
> RCS file: /cvs/src/sys/arch/armv7/omap/files.omap,v
> retrieving revision 1.13
> diff -u -p -r1.13 files.omap
> --- sys/arch/armv7/omap/files.omap    26 Jun 2016 09:06:35 -0000      1.13
> +++ sys/arch/armv7/omap/files.omap    6 Aug 2016 07:59:48 -0000
> @@ -81,6 +81,11 @@ device omdisplay: wsemuldisplaydev, raso
>  attach omdisplay at omap
>  file arch/armv7/omap/omdisplay.c             omdisplay
>  
> +# am335x LCD frame buffer
> +device amdisplay: wsemuldisplaydev, rasops16
> +attach amdisplay at fdt
> +file arch/armv7/omap/amdisplay.c             amdisplay
> +
>  # MCSPI - spi 
>  device mcspi 
>  attach mcspi at omap
> Index: sys/arch/armv7/omap/prcm.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/armv7/omap/prcm.c,v
> retrieving revision 1.11
> diff -u -p -r1.11 prcm.c
> --- sys/arch/armv7/omap/prcm.c        18 Jul 2016 15:03:01 -0000      1.11
> +++ sys/arch/armv7/omap/prcm.c        6 Aug 2016 07:59:48 -0000
> @@ -336,6 +336,8 @@ prcm_am335x_clkctrl(int mod)
>               return PRCM_AM335X_I2C1_CLKCTRL;
>       case PRCM_I2C2:
>               return PRCM_AM335X_I2C2_CLKCTRL;
> +     case PRCM_LCDC:
> +             return PRCM_AM335X_LCDC_CLKCTRL;
>       default:
>               panic("%s: module not found\n", __func__);
>       }
> Index: sys/arch/armv7/omap/prcmvar.h
> ===================================================================
> RCS file: /cvs/src/sys/arch/armv7/omap/prcmvar.h,v
> retrieving revision 1.6
> diff -u -p -r1.6 prcmvar.h
> --- sys/arch/armv7/omap/prcmvar.h     18 Jul 2016 15:03:01 -0000      1.6
> +++ sys/arch/armv7/omap/prcmvar.h     6 Aug 2016 07:59:48 -0000
> @@ -54,6 +54,7 @@ enum PRCM_MODULES {
>       PRCM_I2C1,
>       PRCM_I2C2,
>       PRCM_I2C3,
> +     PRCM_LCDC,
>  };
>  
>  #define PRCM_REG_MAX 6
> 
> 

Reply via email to