Index: sys/arch/armv7/conf/GENERIC =================================================================== RCS file: /cvs/src/sys/arch/armv7/conf/GENERIC,v retrieving revision 1.71 diff -u -p -p -u -r1.71 GENERIC --- sys/arch/armv7/conf/GENERIC 23 Jan 2017 22:43:17 -0000 1.71 +++ sys/arch/armv7/conf/GENERIC 3 Apr 2017 05:24:32 -0000 @@ -81,6 +81,9 @@ sdmmc* at ommmc? # SD/MMC bus omehci* at fdt? # EHCI usb* at omehci? +nxptda* at iic? # TDA19988 HDMI PHY +amdisplay* at fdt? # AM335x LCD controller +wsdisplay* at amdisplay? # Sunxi A1x/A20 SoC sxiintc* at fdt? # A1x interrupt controller 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 -p -u -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 3 Apr 2017 05:24:33 -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 @@ -38,6 +39,10 @@ #define PRCM_AM335X_CM_WKUP 0x0400 #define PRCM_AM335X_GPIO0_CLKCTRL 0x0408 #define PRCM_AM335X_TIMER0_CLKCTRL 0x0410 +#define PRCM_AM335X_DISP_IDLEST 0x0448 +#define PRCM_AM335X_DISP_CLKSEL 0x0454 +#define PRCM_AM335X_DISP_CLKMODE 0x0498 +#define PRCM_AM335X_DISP_M2 0x04a4 #define PRCM_AM335X_I2C0_CLKCTRL 0x04b8 #define PRCM_AM335X_CM_DPLL 0x0500 #define PRCM_AM335X_CLKSEL_TIMER2_CLK 0x0508 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 3 Apr 2017 05:24:33 -0000 @@ -0,0 +1,628 @@ +/* + * Copyright (c) 2016 Ian Sutton + * + * 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#ifdef LCD_DEBUG +int lcd_dbg_thresh = 20; +#define DPRINTF(n,s) do { if ((n) <= lcd_dbg_thresh) printf s; } while (0) +#else +#define DPRINTF(n,s) do {} while (0) +#endif + +#define str(X) #X +#define DEVNAME(_s) ((_s)->sc_dev.dv_xname) +#define PALETTE_BPP 0x4000 + +#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; + + int sc_flags; +#define LCD_RESET_PENDING (1 << 0) +#define LCD_MODE_COMPAT (1 << 1) +#define LCD_MODE_ALLOC (1 << 2) + + struct edid_info *sc_edid; + struct videomode *sc_active_mode; + int sc_active_depth; + + bus_dmamap_t sc_fb0_dma; + bus_dma_segment_t sc_fb0_dma_segs[1]; + void *sc_fb0; + int sc_fb_dma_nsegs; + bus_size_t sc_fb_size; + + struct rasops_info *sc_ro; +}; + +struct wsscreen_descr amdisplay_stdscreen = { + "std", 100, 100, + NULL, + 0, 0 +}; + +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_detach(struct device *, int); +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); + +int amdisplay_setup_dma(struct amdisplay_softc *); +void amdisplay_conf_crt_timings(struct amdisplay_softc *); + +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, amdisplay_detach +}; + +struct cfdriver amdisplay_cd = { + NULL, "amdisplay", DV_DULL +}; + +void +preg(uint32_t reg, char *rn, struct amdisplay_softc *sc) +{ + uint32_t read; + + read = HREAD4(sc, reg); + DPRINTF(16, ("%s: %s: 0x%08x\n", DEVNAME(sc), rn, read)); +} + +void +dumpregs(struct amdisplay_softc *sc) +{ + preg(LCD_PID, str(AMDISPLAY_PID), sc); + preg(LCD_CTRL, str(AMDISPLAY_CTRL), sc); + preg(LCD_RASTER_CTRL, str(AMDISPLAY_RASTER_CTRL), sc); + preg(LCD_RASTER_TIMING_0, str(AMDISPLAY_RASTER_TIMING_0), sc); + preg(LCD_RASTER_TIMING_1, str(AMDISPLAY_RASTER_TIMING_1), sc); + preg(LCD_RASTER_TIMING_2, str(AMDISPLAY_RASTER_TIMING_2), sc); + preg(LCD_RASTER_SUBPANEL, str(AMDISPLAY_RASTER_SUBPANEL), sc); + preg(LCD_RASTER_SUBPANEL_2, str(AMDISPLAY_RASTER_SUBPANEL_2), sc); + preg(LCD_LCDDMA_CTRL, str(AMDISPLAY_LCDDMA_CTRL), sc); + + /* accessing these regs is liable to occur during CPU lock out period */ + #if 0 + preg(LCD_LCDDMA_FB0_BASE, str(AMDISPLAY_LCDDMA_FB0_BASE), sc); + preg(LCD_LCDDMA_FB0_CEILING, str(AMDISPLAY_LCDDMA_FB0_CEILING), sc); + preg(LCD_LCDDMA_FB1_BASE, str(AMDISPLAY_LCDDMA_FB1_BASE), sc); + preg(LCD_LCDDMA_FB1_CEILING, str(AMDISPLAY_LCDDMA_FB1_CEILING), sc); + #endif + + preg(LCD_SYSCONFIG, str(AMDISPLAY_SYSCONFIG), sc); + preg(LCD_IRQSTATUS_RAW, str(AMDISPLAY_IRQSTATUS_RAW), sc); + preg(LCD_IRQSTATUS, str(AMDISPLAY_IRQSTATUS), sc); + preg(LCD_IRQENABLE_SET, str(AMDISPLAY_IRQENABLE_SET), sc); + preg(LCD_IRQENABLE_CLEAR, str(AMDISPLAY_IRQENABLE_CLEAR), sc); + preg(LCD_CLKC_ENABLE, str(AMDISPLAY_CLKC_ENABLE), sc); + preg(LCD_CLKC_RESET, str(AMDISPLAY_CLKC_RESET), sc); +} + +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; + struct edid_info edid; + + uint32_t irq, reg; + uint8_t *edid_buf; + int stride, i = 0; + + 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__); + + /* enable clock module */ + prcm_enablemodule(PRCM_LCDC); + + /* force ourselves out of standby/idle states */ + reg = HREAD4(sc, LCD_SYSCONFIG); + reg &= ~(LCD_SYSCONFIG_STANDBYMODE | LCD_SYSCONFIG_IDLEMODE); + reg |= (0x2 << LCD_SYSCONFIG_STANDBYMODE_SHAMT) + | (0x2 << LCD_SYSCONFIG_IDLEMODE_SHAMT); + HWRITE4(sc, LCD_SYSCONFIG, reg); + + irq = faa->fa_intr[0]; + sc->sc_ih = arm_intr_establish(irq, IPL_BIO, amdisplay_intr, sc, DEVNAME(sc)); + + printf("\n"); + + /* read/parse EDID bits from TDA19988 HDMI PHY */ + edid_buf = malloc(EDID_LENGTH, M_DEVBUF, M_WAITOK | M_ZERO); + sc->sc_active_mode = malloc(sizeof(struct videomode), M_DEVBUF, + M_WAITOK | M_ZERO); + sc->sc_flags |= LCD_MODE_ALLOC; + + if (nxptda_get_edid(edid_buf, EDID_LENGTH) + || edid_parse(edid_buf, &edid)) { + printf("%s: no display attached.\n", DEVNAME(sc)); + free(edid_buf, M_DEVBUF, EDID_LENGTH); + amdisplay_detach(self, 0); + return; + } + + sc->sc_edid = &edid; + + /* check to make sure default VGA mode is supported */ + for (; i < edid.edid_nmodes - 1; i++) + if (!strcmp(edid.edid_modes[i].name, "640x480x60")) + sc->sc_flags |= LCD_MODE_COMPAT; + i = 0; + + if (!ISSET(sc->sc_flags, LCD_MODE_COMPAT)) { + printf("%s: no suitable video modes found\n", DEVNAME(sc)); + free(edid_buf, M_DEVBUF, EDID_LENGTH); + amdisplay_detach(self, 0); + return; + } + + /* set VGA videomode */ + for (; i < videomode_count; i++) + if (!strcmp("640x480x60", videomode_list[i].name)) + memcpy(sc->sc_active_mode, &videomode_list[i], sizeof(struct videomode)); + + sc->sc_active_mode->flags |= VID_HSKEW; + sc->sc_active_depth = 16; + + /* configure DMA framebuffer */ + if (amdisplay_setup_dma(sc)) { + printf("%s: couldn't allocate DMA framebuffer\n", DEVNAME(sc)); + free(edid_buf, M_DEVBUF, EDID_LENGTH); + amdisplay_detach(self, 0); + return; + } + + /* setup rasops */ + stride = sc->sc_active_mode->hdisplay * sc->sc_active_depth; + + sc->sc_ro = malloc(sizeof(struct rasops_info), M_DEVBUF, M_ZERO | M_WAITOK); + sc->sc_ro->ri_depth = sc->sc_active_depth; + sc->sc_ro->ri_width = sc->sc_active_mode->hdisplay; + sc->sc_ro->ri_height = sc->sc_active_mode->vdisplay; + sc->sc_ro->ri_stride = stride; + sc->sc_ro->ri_bits = sc->sc_fb0; + sc->sc_ro->ri_rnum = 5; + sc->sc_ro->ri_gnum = 6; + sc->sc_ro->ri_bnum = 5; + sc->sc_ro->ri_rpos = 0; + sc->sc_ro->ri_gpos = 5; + sc->sc_ro->ri_bpos = 11; + + if (rasops_init(sc->sc_ro, 100, 100)) { + printf("%s: no rasops\n", DEVNAME(sc)); + amdisplay_detach(self, 0); + return; + } + + /* ensure controller is off */ + HCLR4(sc, LCD_RASTER_CTRL, LCD_RASTER_CTRL_LCDEN); + delay(100); + + /* set clock divisor needed for 640x480 VGA timings */ + reg = HREAD4(sc, LCD_CTRL); + reg &= ~LCD_CTRL_CLKDIV; + reg |= (0x2 << LCD_CTRL_CLKDIV_SHAMT); + + /* select raster mode & reset-on-underflow, write */ + reg |= LCD_CTRL_MODESEL; + HWRITE4(sc, LCD_CTRL, reg); + + /* set stn565 + active matrix + pallete loading only mode, delay */ + reg = HREAD4(sc, LCD_RASTER_CTRL); + reg &= 0xF8000C7C; + reg |= (LCD_RASTER_CTRL_LCDTFT) + | (0x02 << LCD_RASTER_CTRL_PALMODE_SHAMT) + | (0xFF << LCD_RASTER_CTRL_REQDLY_SHAMT); + HWRITE4(sc, LCD_RASTER_CTRL, reg); + + /* set timing values */ + amdisplay_conf_crt_timings(sc); + + /* configure HDMI transmitter (TDA19988) with our mode details */ + nxptda_set_videomode(sc->sc_active_mode); + + /* latch pins/pads according to fdt node */ + pinctrl_byphandle(LCD_FDT_PHANDLE); + + /* write bpp empty palette into framebuffer */ + memset((void *)sc->sc_fb0, 0, 0x20); + *(unsigned int *)sc->sc_fb0 = PALETTE_BPP; + sc->sc_fb0 += 0x20; + + /* configure DMA transfer settings */ + reg = HREAD4(sc, LCD_LCDDMA_CTRL); + reg &= ~(LCD_LCDDMA_CTRL_DMA_MASTER_PRIO + | LCD_LCDDMA_CTRL_TH_FIFO_READY + | LCD_LCDDMA_CTRL_BURST_SIZE + | LCD_LCDDMA_CTRL_BYTE_SWAP + | LCD_LCDDMA_CTRL_BIGENDIAN + | LCD_LCDDMA_CTRL_FRAME_MODE); + reg |= (0x4 << LCD_LCDDMA_CTRL_BURST_SIZE_SHAMT); + HWRITE4(sc, LCD_LCDDMA_CTRL, reg); + + /* set framebuffer location + bounds */ + HWRITE4(sc, LCD_LCDDMA_FB0, sc->sc_fb0_dma_segs[0].ds_addr); + HWRITE4(sc, LCD_LCDDMA_FB0_CEIL, (sc->sc_fb0_dma_segs[0].ds_addr + + sc->sc_fb_size) - 0); + + /* enable all intrs. */ + reg = 0; + reg |= (LCD_IRQ_EOF1 | LCD_IRQ_EOF0 | LCD_IRQ_PL | LCD_IRQ_FUF | + LCD_IRQ_ACB | LCD_IRQ_SYNC | LCD_IRQ_RR_DONE | LCD_IRQ_DONE); + + HWRITE4(sc, LCD_IRQENABLE_SET, reg); + + /* enable dma & core clocks */ + HSET4(sc, LCD_CLKC_ENABLE, LCD_CLKC_ENABLE_DMA_CLK_EN + | LCD_CLKC_ENABLE_CORE_CLK_EN + | LCD_CLKC_ENABLE_LIDD_CLK_EN); + + /* perform controller clock reset */ + HSET4(sc, LCD_CLKC_RESET, LCD_CLKC_RESET_MAIN_RST); + delay(100); + HCLR4(sc, LCD_CLKC_RESET, LCD_CLKC_RESET_MAIN_RST); + + /* attach console */ + wsaa.console = 0; + wsaa.scrdata = &amdisplay_screenlist; + wsaa.accessops = &amdisplay_accessops; + wsaa.accesscookie = sc; + wsaa.defaultscreens = 0; + +// wsdisplay_cnattach(&amdisplay_stdscreen, sc->sc_ro, sc->sc_ro->ri_ccol, +// sc->sc_ro->ri_crow, 0); +// config_found(self, &wsaa, wsemuldisplaydevprint); + + /* enable controller */ + HSET4(sc, LCD_RASTER_CTRL, LCD_RASTER_CTRL_LCDEN); + + dumpregs(sc); +} + +int +amdisplay_detach(struct device *self, int flags) +{ + struct amdisplay_softc *sc = (struct amdisplay_softc *)self; + + if (sc->sc_ro) + free(sc->sc_ro, M_DEVBUF, sizeof(struct rasops_info)); + + if (sc->sc_edid) + free(sc->sc_edid, M_DEVBUF, sizeof(struct edid_info)); + + if (ISSET(sc->sc_flags, LCD_MODE_ALLOC)) + free(sc->sc_active_mode, M_DEVBUF, sizeof(struct videomode)); + + if (!sc->sc_fb0) + return 0; + + bus_dmamap_sync(sc->sc_dmat, sc->sc_fb0_dma, 0, sc->sc_fb_size, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + + bus_dmamap_unload(sc->sc_dmat, sc->sc_fb0_dma); + bus_dmamem_unmap(sc->sc_dmat, (caddr_t)(sc->sc_fb0), sc->sc_fb_size); + bus_dmamem_free(sc->sc_dmat, sc->sc_fb0_dma_segs, sc->sc_fb_dma_nsegs); + bus_dmamap_destroy(sc->sc_dmat, sc->sc_fb0_dma); + + return 0; +} + +int +amdisplay_intr(void *arg) +{ + struct amdisplay_softc *sc = arg; + uint32_t reg, write_through; + + reg = HREAD4(sc, LCD_IRQSTATUS); + HWRITE4(sc, LCD_IRQSTATUS, reg); + + /* make sure we didn't just cache the ack */ + write_through = HREAD4(sc, LCD_IRQSTATUS); + + DPRINTF(25, ("%s: intr 0x%08x\n", DEVNAME(sc), reg)); + + if (ISSET(reg, LCD_IRQ_PL)) { + DPRINTF(10, ("%s: palette loaded, irq: 0x%08x\n", + DEVNAME(sc), reg)); + HCLR4(sc, LCD_RASTER_CTRL, LCD_RASTER_CTRL_LCDEN); + delay(100); + memset(sc->sc_fb0, 0, sc->sc_fb_size); + HCLR4(sc, LCD_RASTER_CTRL, LCD_RASTER_CTRL_PALMODE); + HSET4(sc, LCD_RASTER_CTRL, 0x2 << LCD_RASTER_CTRL_PALMODE_SHAMT); + HSET4(sc, LCD_RASTER_CTRL, LCD_RASTER_CTRL_LCDEN); + } if (ISSET(reg, LCD_IRQ_FUF)) { + DPRINTF(15, ("%s: FIFO underflow\n", DEVNAME(sc))); + } if (ISSET(reg, LCD_IRQ_SYNC)) { + sc->sc_flags |= LCD_RESET_PENDING; + DPRINTF(18, ("%s: sync lost\n", DEVNAME(sc))); + } if (ISSET(reg, LCD_IRQ_RR_DONE)) { /* use ping-pong here XXX */ + DPRINTF(21, ("%s: frame done\n", DEVNAME(sc))); + HWRITE4(sc, LCD_LCDDMA_FB0, sc->sc_fb0_dma_segs[0].ds_addr); + HWRITE4(sc, LCD_LCDDMA_FB0_CEIL, (sc->sc_fb0_dma_segs[0].ds_addr + + sc->sc_fb_size) - 1); + } if (ISSET(reg, LCD_IRQ_EOF0)) { + DPRINTF(21, ("%s: framebuffer 0 done\n", DEVNAME(sc))); + } if (ISSET(reg, LCD_IRQ_EOF1)) { + DPRINTF(21, ("%s: framebuffer 1 done\n", DEVNAME(sc))); + } if (ISSET(reg, LCD_IRQ_DONE)) { + if (ISSET(sc->sc_flags, LCD_RESET_PENDING)) { + HWRITE4(sc, LCD_IRQSTATUS, 0xFFFFFFFF); /* XXX */ + HSET4(sc, LCD_CLKC_RESET, LCD_CLKC_RESET_MAIN_RST); + delay(10); + HCLR4(sc, LCD_CLKC_RESET, LCD_CLKC_RESET_MAIN_RST); + HSET4(sc, LCD_RASTER_CTRL, LCD_RASTER_CTRL_LCDEN); + sc->sc_flags &= ~LCD_RESET_PENDING; + } + DPRINTF(15, ("%s: last frame done\n", DEVNAME(sc))); + } if (ISSET(reg, LCD_IRQ_ACB)) { + DPRINTF(15, ("%s: AC bias event\n", DEVNAME(sc))); + } + + HWRITE4(sc, LCD_IRQ_END, 0); + reg = HREAD4(sc, LCD_IRQ_END); + + return 0; +} + +int +amdisplay_setup_dma(struct amdisplay_softc *sc) +{ + bus_size_t bsize; + + bsize = (sc->sc_active_mode->hdisplay * sc->sc_active_mode->vdisplay + * sc->sc_active_depth) >> 3; + sc->sc_fb_size = bsize; + sc->sc_fb_dma_nsegs = 1; + + if (bus_dmamap_create(sc->sc_dmat, sc->sc_fb_size, sc->sc_fb_dma_nsegs, + sc->sc_fb_size, 0, BUS_DMA_NOWAIT, &(sc->sc_fb0_dma))) + return -1; + + if (bus_dmamem_alloc(sc->sc_dmat, sc->sc_fb_size, 4, 0, + sc->sc_fb0_dma_segs, 1, &(sc->sc_fb_dma_nsegs), + BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) + return -2; + + if (bus_dmamem_map(sc->sc_dmat, sc->sc_fb0_dma_segs, sc->sc_fb_dma_nsegs, + sc->sc_fb_size, (caddr_t *)&(sc->sc_fb0), + BUS_DMA_NOWAIT | BUS_DMA_COHERENT | BUS_DMA_NOCACHE)) + return -3; + + if (bus_dmamap_load(sc->sc_dmat, sc->sc_fb0_dma, sc->sc_fb0, bsize, NULL, + BUS_DMA_NOWAIT)) + return -4; + + memset(sc->sc_fb0, 0, bsize); + + bus_dmamap_sync(sc->sc_dmat, sc->sc_fb0_dma, 0, bsize, + BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); + + return 0; +} + +void +amdisplay_conf_crt_timings(struct amdisplay_softc *sc) +{ + uint32_t timing0, timing1, timing2; + uint32_t hbp, hfp, hsw, vbp, vfp, vsw, width, height; + struct videomode *m = sc->sc_active_mode; + + timing0 = 0; + timing1 = 0; + timing2 = 0; + + hbp = (m->htotal - m->hsync_end) - 1; + hfp = (m->hsync_start - m->hdisplay) - 1; + hsw = (m->hsync_end - m->hsync_start) - 1; + + vbp = (m->vtotal - m->vsync_end); + vfp = (m->vsync_start - m->vdisplay); + vsw = (m->vsync_end - m->vsync_start) - 1; + + height = m->vdisplay - 1; + width = m->hdisplay - 1; + + /* Horizontal back porch */ + timing0 |= (hbp & 0xff) << LCD_RASTER_TIMING_0_HBP_SHAMT; + timing2 |= ((hbp >> 8) & 3) << LCD_RASTER_TIMING_2_HPB_HIGHBITS_SHAMT; + /* Horizontal front porch */ + timing0 |= (hfp & 0xff) << LCD_RASTER_TIMING_0_HFP_SHAMT; + timing2 |= ((hfp >> 8) & 3) << 0; + /* Horizontal sync width */ + timing0 |= (hsw & 0x3f) << LCD_RASTER_TIMING_0_HSW_SHAMT; + timing2 |= ((hsw >> 6) & 0xf) << LCD_RASTER_TIMING_2_HSW_HIGHBITS_SHAMT; + + /* Vertical back porch, front porch, sync width */ + timing1 |= (vbp & 0xff) << LCD_RASTER_TIMING_1_VBP_SHAMT; + timing1 |= (vfp & 0xff) << LCD_RASTER_TIMING_1_VFP_SHAMT; + timing1 |= (vsw & 0x3f) << LCD_RASTER_TIMING_1_VSW_SHAMT; + + /* Pixels per line */ + timing0 |= ((width >> 10) & 1) + << LCD_RASTER_TIMING_0_PPLMSB_SHAMT; + timing0 |= ((width >> 4) & 0x3f) + << LCD_RASTER_TIMING_0_PPLLSB_SHAMT; + + /* Lines per panel */ + timing1 |= (height & 0x3ff); + timing2 |= ((height >> 10 ) & 1) + << LCD_RASTER_TIMING_2_LPP_B10_SHAMT; + + /* waveform settings */ + timing2 |= LCD_RASTER_TIMING_2_PHSVS_ON_OFF; + timing2 |= (0xff << LCD_RASTER_TIMING_2_ACBI_SHAMT); + + if (!ISSET(m->flags, VID_NHSYNC)) + timing2 |= LCD_RASTER_TIMING_2_IHS; + if (!ISSET(m->flags, VID_NVSYNC)) + timing2 |= LCD_RASTER_TIMING_2_IVS; + + HWRITE4(sc, LCD_RASTER_TIMING_0, timing0); + HWRITE4(sc, LCD_RASTER_TIMING_1, timing1); + HWRITE4(sc, LCD_RASTER_TIMING_2, timing2); +} + +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->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->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->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->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->sc_ro; + + return rasops_list_font(ri, font); +} + +void +amdisplay_burner(void *sconf, u_int on, u_int flags) +{ +} + Index: sys/arch/armv7/omap/amdisplayreg.h =================================================================== RCS file: sys/arch/armv7/omap/amdisplayreg.h diff -N sys/arch/armv7/omap/amdisplayreg.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/arch/armv7/omap/amdisplayreg.h 3 Apr 2017 05:24:33 -0000 @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2016 Ian Sutton + * + * 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. + */ + +/* AM335x LCDC register offsets */ +#define LCD_PID 0x00 +#define LCD_CTRL 0x04 +#define LCD_CTRL_CLKDIV (0xFF << 8) +#define LCD_CTRL_AUTO_UFLOW_RESTART (1 << 1) +#define LCD_CTRL_MODESEL (1 << 0) +#define LCD_CTRL_CLKDIV_SHAMT 8 +#define LCD_RASTER_CTRL 0x28 +#define LCD_RASTER_CTRL_TFT24UNPACKED (1 << 26) +#define LCD_RASTER_CTRL_TFT24 (1 << 25) +#define LCD_RASTER_CTRL_STN565 (1 << 24) +#define LCD_RASTER_CTRL_TFTMAP (1 << 23) +#define LCD_RASTER_CTRL_NIBMODE (1 << 22) +#define LCD_RASTER_CTRL_PALMODE (3 << 20) +#define LCD_RASTER_CTRL_REQDLY (0xFF << 12) +#define LCD_RASTER_CTRL_LCDTFT (1 << 7) +#define LCD_RASTER_CTRL_LCDEN (1 << 0) +#define LCD_RASTER_CTRL_PALMODE_SHAMT 20 +#define LCD_RASTER_CTRL_REQDLY_SHAMT 12 +#define LCD_RASTER_TIMING_0 0x2C +#define LCD_RASTER_TIMING_0_HBP (0xFF << 24) +#define LCD_RASTER_TIMING_0_HFP (0xFF << 16) +#define LCD_RASTER_TIMING_0_HSW (0x3F << 10) +#define LCD_RASTER_TIMING_0_PPLLSB (0x3 << 4) +#define LCD_RASTER_TIMING_0_PPLMSB (0x1 << 3) +#define LCD_RASTER_TIMING_0_HBP_SHAMT 24 +#define LCD_RASTER_TIMING_0_HFP_SHAMT 16 +#define LCD_RASTER_TIMING_0_HSW_SHAMT 10 +#define LCD_RASTER_TIMING_0_PPLLSB_SHAMT 4 +#define LCD_RASTER_TIMING_0_PPLMSB_SHAMT 3 +#define LCD_RASTER_TIMING_1 0x30 +#define LCD_RASTER_TIMING_1_VBP (0xFF << 24) +#define LCD_RASTER_TIMING_1_VFP (0xFF << 16) +#define LCD_RASTER_TIMING_1_VSW (0x3C << 10) +#define LCD_RASTER_TIMING_1_LPP (0x3FF << 0) +#define LCD_RASTER_TIMING_1_VBP_SHAMT 24 +#define LCD_RASTER_TIMING_1_VFP_SHAMT 16 +#define LCD_RASTER_TIMING_1_VSW_SHAMT 10 +#define LCD_RASTER_TIMING_2 0x34 +#define LCD_RASTER_TIMING_2_HSW_HIGHBITS (0xF << 27) +#define LCD_RASTER_TIMING_2_LPP_B10 (0x1 << 26) +#define LCD_RASTER_TIMING_2_PHSVS_ON_OFF (0x1 << 25) +#define LCD_RASTER_TIMING_2_PHSVS_RF (0x1 << 24) +#define LCD_RASTER_TIMING_2_IEO (0x1 << 23) +#define LCD_RASTER_TIMING_2_IPC (0x1 << 22) +#define LCD_RASTER_TIMING_2_IHS (0x1 << 21) +#define LCD_RASTER_TIMING_2_IVS (0x1 << 20) +#define LCD_RASTER_TIMING_2_ACBI (0xF << 16) +#define LCD_RASTER_TIMING_2_ACB (0xFF << 8) +#define LCD_RASTER_TIMING_2_HBP_HIGHBITS (0x3 << 4) +#define LCD_RASTER_TIMING_2_HFP_HIGHBITS (0x3 << 0) +#define LCD_RASTER_TIMING_2_HSW_HIGHBITS_SHAMT 27 +#define LCD_RASTER_TIMING_2_LPP_B10_SHAMT 26 +#define LCD_RASTER_TIMING_2_ACBI_SHAMT 16 +#define LCD_RASTER_TIMING_2_ACB_SHAMT 8 +#define LCD_RASTER_TIMING_2_HPB_HIGHBITS_SHAMT 4 +#define LCD_RASTER_SUBPANEL 0x38 +#define LCD_RASTER_SUBPANEL_SPEN (0x1 << 31) +#define LCD_RASTER_SUBPANEL_HOLS (0x1 << 29) +#define LCD_RASTER_SUBPANEL_LPPT (0x2FF << 16) +#define LCD_RASTER_SUBPANEL_DPDLSB (0xFFFF << 0) +#define LCD_RASTER_SUBPANEL_LPPT_SHAMT +#define LCD_RASTER_SUBPANEL_2 0x3C +#define LCD_RASTER_SUBPANEL2_LPPT_B10 (0x1 << 8) +#define LCD_RASTER_SUBPANEL2_DPDMSB (0xFF << 0) +#define LCD_LCDDMA_CTRL 0x40 +#define LCD_LCDDMA_CTRL_DMA_MASTER_PRIO (0x7 << 0x10) +#define LCD_LCDDMA_CTRL_TH_FIFO_READY (0x7 << 0x08) +#define LCD_LCDDMA_CTRL_BURST_SIZE (0x7 << 0x04) +#define LCD_LCDDMA_CTRL_BYTE_SWAP (0x1 << 0x03) +#define LCD_LCDDMA_CTRL_BIGENDIAN (0x1 << 0x01) +#define LCD_LCDDMA_CTRL_FRAME_MODE (0x1 << 0x00) +#define LCD_LCDDMA_CTRL_DMA_MASTER_PRIO_SHAMT 0xFF +#define LCD_LCDDMA_CTRL_TH_FIFO_READY_SHAMT 0x08 +#define LCD_LCDDMA_CTRL_BURST_SIZE_SHAMT 0x04 +#define LCD_LCDDMA_FB0 0x44 +#define LCD_LCDDMA_FB0_BASE 0xFFFC +#define LCD_LCDDMA_FB0_BASE_SHAMT 0 +#define LCD_LCDDMA_FB0_CEIL 0x48 +#define LCD_LCDDMA_FB0_CEILING 0xFFFC +#define LCD_LCDDMA_FB0_CEILING_SHAMT 0 +#define LCD_LCDDMA_FB1 0x4C +#define LCD_LCDDMA_FB1_BASE 0xFFFC +#define LCD_LCDDMA_FB1_BASE_SHAMT 0 +#define LCD_LCDDMA_FB1_CEIL 0x50 +#define LCD_LCDDMA_FB1_CEILING 0xFFFC +#define LCD_LCDDMA_FB1_CEILING_SHAMT 0 +#define LCD_SYSCONFIG 0x54 +#define LCD_SYSCONFIG_STANDBYMODE (2 << 4) +#define LCD_SYSCONFIG_IDLEMODE (2 << 2) +#define LCD_SYSCONFIG_STANDBYMODE_SHAMT 4 +#define LCD_SYSCONFIG_IDLEMODE_SHAMT 2 +#define LCD_IRQSTATUS_RAW 0x58 +#define LCD_IRQSTATUS 0x5C +#define LCD_IRQENABLE_SET 0x60 +#define LCD_IRQENABLE_CLEAR 0x64 +#define LCD_IRQ_END 0x68 +#define LCD_CLKC_ENABLE 0x6C +#define LCD_CLKC_ENABLE_DMA_CLK_EN (1 << 2) +#define LCD_CLKC_ENABLE_LIDD_CLK_EN (1 << 1) +#define LCD_CLKC_ENABLE_CORE_CLK_EN (1 << 0) +#define LCD_CLKC_RESET 0x70 +#define LCD_CLKC_RESET_MAIN_RST (1 << 3) +#define LCD_CLKC_RESET_DMA_RST (1 << 2) +#define LCD_CLKC_RESET_LIDD_RST (1 << 1) +#define LCD_CLKC_RESET_CORE_RST (1 << 0) + +/* AM335x LCDC intr. masks */ +#define LCD_IRQ_EOF1 (1 << 9) +#define LCD_IRQ_EOF0 (1 << 8) +#define LCD_IRQ_PL (1 << 6) +#define LCD_IRQ_FUF (1 << 5) +#define LCD_IRQ_ACB (1 << 3) +#define LCD_IRQ_SYNC (1 << 2) +#define LCD_IRQ_RR_DONE (1 << 1) +#define LCD_IRQ_DONE (1 << 0) + +/* EDID reading */ +#define EDID_LENGTH 0x80 + +/* phandle for pin muxing */ +#define LCD_FDT_PHANDLE 0x2f Index: sys/arch/armv7/omap/files.omap =================================================================== RCS file: /cvs/src/sys/arch/armv7/omap/files.omap,v retrieving revision 1.19 diff -u -p -p -u -r1.19 files.omap --- sys/arch/armv7/omap/files.omap 3 Oct 2016 01:59:20 -0000 1.19 +++ sys/arch/armv7/omap/files.omap 3 Apr 2017 05:24:33 -0000 @@ -86,6 +86,10 @@ device omdisplay: wsemuldisplaydev, raso attach omdisplay at omap file arch/armv7/omap/omdisplay.c omdisplay +device amdisplay: wsemuldisplaydev, rasops16 +attach amdisplay at fdt +file arch/armv7/omap/amdisplay.c amdisplay + # MCSPI - spi device mcspi attach mcspi at omap @@ -95,3 +99,9 @@ file arch/armv7/omap/mcspi.c mcspi device oaudio: audio attach oaudio at omap # configure after Atlas Driver file arch/armv7/omap/beagle_audio.c oaudio + +# TDA19988 HDMI PHY +device nxptda +attach nxptda at i2c +file arch/armv7/omap/nxptda.c nxptda + Index: sys/arch/armv7/omap/nxptda.c =================================================================== RCS file: sys/arch/armv7/omap/nxptda.c diff -N sys/arch/armv7/omap/nxptda.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/arch/armv7/omap/nxptda.c 3 Apr 2017 05:24:34 -0000 @@ -0,0 +1,778 @@ +/* + * Copyright (c) 2016 Ian Sutton + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 2015 Oleksandr Tymoshenko + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +/* TDA19988 registers */ +#define MKREG(page, addr) (((page) << 8) | (addr)) + +#define REGPAGE(reg) (((reg) >> 8) & 0xff) +#define REGADDR(reg) ((reg) & 0xff) + +#define TDA_VERSION MKREG(0x00, 0x00) +#define TDA_MAIN_CNTRL0 MKREG(0x00, 0x01) +#define MAIN_CNTRL0_SR (1 << 0) +#define TDA_VERSION_MSB MKREG(0x00, 0x02) +#define TDA_SOFTRESET MKREG(0x00, 0x0a) +#define SOFTRESET_I2C (1 << 1) +#define SOFTRESET_AUDIO (1 << 0) +#define TDA_DDC_CTRL MKREG(0x00, 0x0b) +#define DDC_ENABLE 0 +#define TDA_CCLK MKREG(0x00, 0x0c) +#define CCLK_ENABLE 1 +#define TDA_INT_FLAGS_2 MKREG(0x00, 0x11) +#define INT_FLAGS_2_EDID_BLK_RD (1 << 1) + +#define TDA_VIP_CNTRL_0 MKREG(0x00, 0x20) +#define TDA_VIP_CNTRL_1 MKREG(0x00, 0x21) +#define TDA_VIP_CNTRL_2 MKREG(0x00, 0x22) +#define TDA_VIP_CNTRL_3 MKREG(0x00, 0x23) +#define VIP_CNTRL_3_SYNC_HS (2 << 4) +#define VIP_CNTRL_3_V_TGL (1 << 2) +#define VIP_CNTRL_3_H_TGL (1 << 1) + +#define TDA_VIP_CNTRL_4 MKREG(0x00, 0x24) +#define VIP_CNTRL_4_BLANKIT_NDE (0 << 2) +#define VIP_CNTRL_4_BLANKIT_HS_VS (1 << 2) +#define VIP_CNTRL_4_BLANKIT_NHS_VS (2 << 2) +#define VIP_CNTRL_4_BLANKIT_HE_VE (3 << 2) +#define VIP_CNTRL_4_BLC_NONE (0 << 0) +#define VIP_CNTRL_4_BLC_RGB444 (1 << 0) +#define VIP_CNTRL_4_BLC_YUV444 (2 << 0) +#define VIP_CNTRL_4_BLC_YUV422 (3 << 0) +#define TDA_VIP_CNTRL_5 MKREG(0x00, 0x25) +#define VIP_CNTRL_5_SP_CNT(n) (((n) & 3) << 1) +#define TDA_MUX_VP_VIP_OUT MKREG(0x00, 0x27) +#define TDA_MAT_CONTRL MKREG(0x00, 0x80) +#define MAT_CONTRL_MAT_BP (1 << 2) +#define TDA_VIDFORMAT MKREG(0x00, 0xa0) +#define TDA_REFPIX_MSB MKREG(0x00, 0xa1) +#define TDA_REFPIX_LSB MKREG(0x00, 0xa2) +#define TDA_REFLINE_MSB MKREG(0x00, 0xa3) +#define TDA_REFLINE_LSB MKREG(0x00, 0xa4) +#define TDA_NPIX_MSB MKREG(0x00, 0xa5) +#define TDA_NPIX_LSB MKREG(0x00, 0xa6) +#define TDA_NLINE_MSB MKREG(0x00, 0xa7) +#define TDA_NLINE_LSB MKREG(0x00, 0xa8) +#define TDA_VS_LINE_STRT_1_MSB MKREG(0x00, 0xa9) +#define TDA_VS_LINE_STRT_1_LSB MKREG(0x00, 0xaa) +#define TDA_VS_PIX_STRT_1_MSB MKREG(0x00, 0xab) +#define TDA_VS_PIX_STRT_1_LSB MKREG(0x00, 0xac) +#define TDA_VS_LINE_END_1_MSB MKREG(0x00, 0xad) +#define TDA_VS_LINE_END_1_LSB MKREG(0x00, 0xae) +#define TDA_VS_PIX_END_1_MSB MKREG(0x00, 0xaf) +#define TDA_VS_PIX_END_1_LSB MKREG(0x00, 0xb0) +#define TDA_VS_LINE_STRT_2_MSB MKREG(0x00, 0xb1) +#define TDA_VS_LINE_STRT_2_LSB MKREG(0x00, 0xb2) +#define TDA_VS_PIX_STRT_2_MSB MKREG(0x00, 0xb3) +#define TDA_VS_PIX_STRT_2_LSB MKREG(0x00, 0xb4) +#define TDA_VS_LINE_END_2_MSB MKREG(0x00, 0xb5) +#define TDA_VS_LINE_END_2_LSB MKREG(0x00, 0xb6) +#define TDA_VS_PIX_END_2_MSB MKREG(0x00, 0xb7) +#define TDA_VS_PIX_END_2_LSB MKREG(0x00, 0xb8) +#define TDA_HS_PIX_START_MSB MKREG(0x00, 0xb9) +#define TDA_HS_PIX_START_LSB MKREG(0x00, 0xba) +#define TDA_HS_PIX_STOP_MSB MKREG(0x00, 0xbb) +#define TDA_HS_PIX_STOP_LSB MKREG(0x00, 0xbc) +#define TDA_VWIN_START_1_MSB MKREG(0x00, 0xbd) +#define TDA_VWIN_START_1_LSB MKREG(0x00, 0xbe) +#define TDA_VWIN_END_1_MSB MKREG(0x00, 0xbf) +#define TDA_VWIN_END_1_LSB MKREG(0x00, 0xc0) +#define TDA_VWIN_START_2_MSB MKREG(0x00, 0xc1) +#define TDA_VWIN_START_2_LSB MKREG(0x00, 0xc2) +#define TDA_VWIN_END_2_MSB MKREG(0x00, 0xc3) +#define TDA_VWIN_END_2_LSB MKREG(0x00, 0xc4) +#define TDA_DE_START_MSB MKREG(0x00, 0xc5) +#define TDA_DE_START_LSB MKREG(0x00, 0xc6) +#define TDA_DE_STOP_MSB MKREG(0x00, 0xc7) +#define TDA_DE_STOP_LSB MKREG(0x00, 0xc8) + +#define TDA_TBG_CNTRL_0 MKREG(0x00, 0xca) +#define TBG_CNTRL_0_SYNC_ONCE (1 << 7) +#define TBG_CNTRL_0_SYNC_MTHD (1 << 6) + +#define TDA_TBG_CNTRL_1 MKREG(0x00, 0xcb) +#define TBG_CNTRL_1_DWIN_DIS (1 << 6) +#define TBG_CNTRL_1_TGL_EN (1 << 2) +#define TBG_CNTRL_1_V_TGL (1 << 1) +#define TBG_CNTRL_1_H_TGL (1 << 0) + +#define TDA_HVF_CNTRL_0 MKREG(0x00, 0xe4) +#define HVF_CNTRL_0_PREFIL_NONE (0 << 2) +#define HVF_CNTRL_0_INTPOL_BYPASS (0 << 0) +#define TDA_HVF_CNTRL_1 MKREG(0x00, 0xe5) +#define HVF_CNTRL_1_VQR(x) (((x) & 3) << 2) +#define HVF_CNTRL_1_VQR_FULL HVF_CNTRL_1_VQR(0) +#define TDA_ENABLE_SPACE MKREG(0x00, 0xd6) +#define TDA_RPT_CNTRL MKREG(0x00, 0xf0) + +#define TDA_PLL_SERIAL_1 MKREG(0x02, 0x00) +#define PLL_SERIAL_1_SRL_MAN_IP (1 << 6) +#define TDA_PLL_SERIAL_2 MKREG(0x02, 0x01) +#define PLL_SERIAL_2_SRL_PR(x) (((x) & 0xf) << 4) +#define PLL_SERIAL_2_SRL_NOSC(x) (((x) & 0x3) << 0) +#define TDA_PLL_SERIAL_3 MKREG(0x02, 0x02) +#define PLL_SERIAL_3_SRL_PXIN_SEL (1 << 4) +#define PLL_SERIAL_3_SRL_DE (1 << 2) +#define PLL_SERIAL_3_SRL_CCIR (1 << 0) +#define TDA_SERIALIZER MKREG(0x02, 0x03) +#define TDA_BUFFER_OUT MKREG(0x02, 0x04) +#define TDA_PLL_SCG1 MKREG(0x02, 0x05) +#define TDA_PLL_SCG2 MKREG(0x02, 0x06) +#define TDA_PLL_SCGN1 MKREG(0x02, 0x07) +#define TDA_PLL_SCGN2 MKREG(0x02, 0x08) +#define TDA_PLL_SCGR1 MKREG(0x02, 0x09) +#define TDA_PLL_SCGR2 MKREG(0x02, 0x0a) + +#define TDA_SEL_CLK MKREG(0x02, 0x11) +#define SEL_CLK_ENA_SC_CLK (1 << 3) +#define SEL_CLK_SEL_VRF_CLK(x) (((x) & 3) << 1) +#define SEL_CLK_SEL_CLK1 (1 << 0) +#define TDA_ANA_GENERAL MKREG(0x02, 0x12) + +#define TDA_EDID_DATA0 MKREG(0x09, 0x00) +#define TDA_EDID_CTRL MKREG(0x09, 0xfa) +#define TDA_DDC_ADDR MKREG(0x09, 0xfb) +#define TDA_DDC_OFFS MKREG(0x09, 0xfc) +#define TDA_DDC_SEGM_ADDR MKREG(0x09, 0xfd) +#define TDA_DDC_SEGM MKREG(0x09, 0xfe) + +#define TDA_IF_VSP MKREG(0x10, 0x20) +#define TDA_IF_AVI MKREG(0x10, 0x40) +#define TDA_IF_SPD MKREG(0x10, 0x60) +#define TDA_IF_AUD MKREG(0x10, 0x80) +#define TDA_IF_MPS MKREG(0x10, 0xa0) + +#define TDA_ENC_CNTRL MKREG(0x11, 0x0d) +#define ENC_CNTRL_DVI_MODE (0 << 2) +#define ENC_CNTRL_HDMI_MODE (1 << 2) +#define TDA_DIP_IF_FLAGS MKREG(0x11, 0x0f) +#define DIP_IF_FLAGS_IF5 (1 << 5) +#define DIP_IF_FLAGS_IF4 (1 << 4) +#define DIP_IF_FLAGS_IF3 (1 << 3) +#define DIP_IF_FLAGS_IF2 (1 << 2) /* AVI IF on page 10h */ +#define DIP_IF_FLAGS_IF1 (1 << 1) + +#define TDA_TX3 MKREG(0x12, 0x9a) +#define TDA_TX4 MKREG(0x12, 0x9b) +#define TX4_PD_RAM (1 << 1) +#define TDA_HDCP_TX33 MKREG(0x12, 0xb8) +#define HDCP_TX33_HDMI (1 << 1) + +#define TDA_CURPAGE_ADDR 0xff + +#define TDA_CEC_ENAMODS 0xff +#define ENAMODS_RXSENS (1 << 2) +#define ENAMODS_HDMI (1 << 1) +#define TDA_CEC_FRO_IM_CLK_CTRL 0xfb +#define CEC_FRO_IM_CLK_CTRL_GHOST_DIS (1 << 7) +#define CEC_FRO_IM_CLK_CTRL_IMCLK_SEL (1 << 1) + +/* EDID reading */ +#define EDID_LENGTH 0x80 +#define MAX_READ_ATTEMPTS 100 + +/* EDID fields */ +#define EDID_MODES0 35 +#define EDID_MODES1 36 +#define EDID_TIMING_START 38 +#define EDID_TIMING_END 54 +#define EDID_TIMING_X(v) (((v) + 31) * 8) +#define EDID_FREQ(v) (((v) & 0x3f) + 60) +#define EDID_RATIO(v) (((v) >> 6) & 0x3) +#define EDID_RATIO_10x16 0 +#define EDID_RATIO_3x4 1 +#define EDID_RATIO_4x5 2 +#define EDID_RATIO_9x16 3 + +/* NXP TDA19988 slave addrs. */ +#define TDA_HDMI 0x70 +#define TDA_CEC 0x34 + +/* debug/etc macros */ +#define DEVNAME(s) ((s)->sc_dev.dv_xname) +//#ifdef I2CDEBUG +#ifdef NXPTDA_DEBUG +int nxptda_debug = 20; +#define DPRINTF(n,s) do { if ((n) <= nxptda_debug) printf s; } while (0) +#else +#define DPRINTF(n,s) do {} while (0) +#endif + +struct nxptda_softc { + struct device sc_dev; + i2c_tag_t sc_tag; + i2c_addr_t sc_addr; + + uint8_t sc_curpage; + uint8_t sc_edid[EDID_LENGTH]; +}; + +int nxptda_match(struct device *, void *, void *); +void nxptda_attach(struct device *, struct device *, void *); + +int nxptda_cec_read(struct nxptda_softc *, uint8_t, uint8_t *); +int nxptda_cec_write(struct nxptda_softc *, uint8_t, uint8_t); +int nxptda_read(struct nxptda_softc *, uint16_t, uint8_t *); +int nxptda_write(struct nxptda_softc *, uint16_t, uint8_t); +int nxptda_write2(struct nxptda_softc *, uint16_t, uint16_t); +int nxptda_set(struct nxptda_softc *, uint16_t, uint8_t); +int nxptda_clear(struct nxptda_softc *, uint16_t, uint8_t); +int nxptda_set_page(struct nxptda_softc *, uint8_t); +int nxptda_read_edid(struct nxptda_softc *); +int nxptda_reset(struct nxptda_softc *); +int nxptda_init_encoder(struct nxptda_softc *, struct videomode *); + +int nxptda_get_edid(uint8_t *, int); +int nxptda_set_videomode(struct videomode *); + +struct cfattach nxptda_ca = { + sizeof(struct nxptda_softc), nxptda_match, nxptda_attach +}; + +struct cfdriver nxptda_cd = { + NULL, "nxptda", DV_DULL +}; + +int +nxptda_match(struct device *parent, void *match, void *aux) +{ + struct i2c_attach_args *ia = aux; + + if (strcmp(ia->ia_name, "nxp,tda998x") == 0) + return 1; + + return 0; +} + +void +nxptda_attach(struct device *parent, struct device *self, void *aux) +{ + struct nxptda_softc *sc = (struct nxptda_softc *)self; + struct i2c_attach_args *ia = aux; + uint8_t data = 0; + uint16_t version = 0; + int res = 0, node = *(int *)(ia->ia_cookie); + + sc->sc_tag = ia->ia_tag; + sc->sc_addr = ia->ia_addr; + sc->sc_curpage = 0xff; + + if (!node) { + printf(": not configured\n"); + return; + } else if ((pinctrl_byname(node, "default") == -1)) { + printf(": not configured\n"); + return; + } + + iic_acquire_bus(sc->sc_tag, 0); + + DPRINTF(3,("\n")); + + /* enable HDMI core */ + nxptda_cec_write(sc, TDA_CEC_ENAMODS, ENAMODS_RXSENS | ENAMODS_HDMI); + delay(1000); + + if (!(nxptda_reset(sc))) + DPRINTF(3,("%s: software reset OK\n", DEVNAME(sc))); + else + DPRINTF(3,("%s: software reset failed!\n", DEVNAME(sc))); + + /* PLL registers common configuration */ + nxptda_write(sc, TDA_PLL_SERIAL_1, 0x00); + nxptda_write(sc, TDA_PLL_SERIAL_2, PLL_SERIAL_2_SRL_NOSC(1)); + nxptda_write(sc, TDA_PLL_SERIAL_3, 0x00); + nxptda_write(sc, TDA_SERIALIZER, 0x00); + nxptda_write(sc, TDA_BUFFER_OUT, 0x00); + nxptda_write(sc, TDA_PLL_SCG1, 0x00); + nxptda_write(sc, TDA_SEL_CLK, SEL_CLK_SEL_CLK1 | SEL_CLK_ENA_SC_CLK); + nxptda_write(sc, TDA_PLL_SCGN1, 0xfa); + nxptda_write(sc, TDA_PLL_SCGN2, 0x00); + nxptda_write(sc, TDA_PLL_SCGR1, 0x5b); + nxptda_write(sc, TDA_PLL_SCGR2, 0x00); + nxptda_write(sc, TDA_PLL_SCG2, 0x10); + + /* Write the default value MUX register */ + nxptda_write(sc, TDA_MUX_VP_VIP_OUT, 0x24); + + res |= nxptda_read(sc, TDA_VERSION, &data); + version |= data; + res |= nxptda_read(sc, TDA_VERSION_MSB, &data); + version |= (data << 8); + version &= ~0x30; + + if (!res) { + DPRINTF(3,("%s: ", DEVNAME(sc))); + printf(": rev 0x%04x\n", version); + } else { + DPRINTF(3,("%s: ", DEVNAME(sc))); + printf(": failed to enable HDMI core, exiting...\n"); + iic_release_bus(sc->sc_tag, 0); + return; + } + + nxptda_write(sc, TDA_DDC_CTRL, DDC_ENABLE); + nxptda_write(sc, TDA_TX3, 39); + + nxptda_cec_write(sc, TDA_CEC_FRO_IM_CLK_CTRL, + CEC_FRO_IM_CLK_CTRL_GHOST_DIS | CEC_FRO_IM_CLK_CTRL_IMCLK_SEL); + + if (nxptda_read_edid(sc)) { + DPRINTF(3,("%s: failed to read EDID bits, exiting!\n", DEVNAME(sc))); + return; + } + + /* Default values for RGB 4:4:4 mapping */ + nxptda_write(sc, TDA_VIP_CNTRL_0, 0x23); + nxptda_write(sc, TDA_VIP_CNTRL_1, 0x01); + nxptda_write(sc, TDA_VIP_CNTRL_2, 0x45); + + iic_release_bus(sc->sc_tag, 0); +} + +int +nxptda_cec_read(struct nxptda_softc *sc, uint8_t addr, uint8_t *buf) +{ + int ret = 0; + + if ((ret |= iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, TDA_CEC, &addr, 1, + NULL, 0, 0))) { + DPRINTF(3,("%s: (CEC) failed to read addr 0x%02x, errno %d\n", DEVNAME(sc), + addr, ret)); + return ret; + } + + DPRINTF(3,("%s: (CEC) read 0x%02x from 0x%02x\n", DEVNAME(sc), *buf, addr)); + + return ret; +} + +int +nxptda_cec_write(struct nxptda_softc *sc, uint8_t addr, uint8_t val) +{ + int ret = 0; + uint8_t sendbuf[] = { addr, val }; + + if ((ret |= iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, TDA_CEC, &sendbuf, 2, + NULL, 0, 0))) { + DPRINTF(3,("%s: (CEC) failed to write 0x%02x to 0x%02x, errno %d\n", + DEVNAME(sc), val, addr, ret)); + return ret; + } + + DPRINTF(3,("%s: (CEC) wrote 0x%02x to 0x%02x\n", DEVNAME(sc), val, addr)); + + return ret; +} + +int +nxptda_read(struct nxptda_softc *sc, uint16_t reg, uint8_t *buf) +{ + int ret = 0; + + nxptda_set_page(sc, REGPAGE(reg)); + + if ((ret = iic_smbus_read_byte(sc->sc_tag, TDA_HDMI, REGADDR(reg), buf, 0))) { + DPRINTF(3,("%s: failed to read addr 0x%02x on page 0x%02x, errno %d\n", + DEVNAME(sc), REGADDR(reg), REGPAGE(reg), ret)); + return ret; + } + + DPRINTF(3,("%s: read 0x%02x from 0x%02x on page 0x%02x\n", DEVNAME(sc), *buf, + REGADDR(reg), REGPAGE(reg))); + + return ret; +} + +int +nxptda_write(struct nxptda_softc *sc, uint16_t reg, uint8_t val) +{ + int ret = 0; + uint8_t sendbuf[] = { REGADDR(reg), val }; + + nxptda_set_page(sc, REGPAGE(reg)); + + if ((ret = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, TDA_HDMI, &sendbuf, 2, + NULL, 0, 0))) { + DPRINTF(3,("%s: failed to write 0x%02x to 0x%02x on page 0x%02x, errno %d\n", + DEVNAME(sc), val, REGADDR(reg), REGPAGE(reg), ret)); + return ret; + } + + DPRINTF(3,("%s: wrote 0x%02x to 0x%02x on page 0x%02x\n", DEVNAME(sc), val, + REGADDR(reg), REGPAGE(reg))); + + return ret; +} + +int +nxptda_write2(struct nxptda_softc *sc, uint16_t reg, uint16_t val) +{ + int ret = 0; + uint8_t sendbuf[] = { REGADDR(reg), val >> 8, val & 0xff }; + + nxptda_set_page(sc, REGPAGE(reg)); + + if ((ret = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, TDA_HDMI, &sendbuf, 3, + NULL, 0, 0))) { + DPRINTF(3,("%s: failed to write 0x%04x to 0x%02x on page 0x%02x, errno %d\n", + DEVNAME(sc), val, REGADDR(reg), REGPAGE(reg), ret)); + return ret; + } + + DPRINTF(3,("%s: wrote 0x%04x to 0x%02x on page 0x%02x\n", DEVNAME(sc), val, + REGADDR(reg), REGPAGE(reg))); + + return ret; + +} + +int +nxptda_set(struct nxptda_softc *sc, uint16_t reg, uint8_t bits) +{ + int ret = 0; + uint8_t buf; + + ret |= nxptda_read(sc, reg, &buf); + buf |= bits; + ret |= nxptda_write(sc, reg, buf); + + return ret; +} + +int +nxptda_clear(struct nxptda_softc *sc, uint16_t reg, uint8_t bits) +{ + int ret = 0; + uint8_t buf; + + ret |= nxptda_read(sc, reg, &buf); + buf &= ~bits; + ret |= nxptda_write(sc, reg, buf); + + return ret; +} + +int +nxptda_set_page(struct nxptda_softc *sc, uint8_t page) +{ + int ret = 0; + uint8_t sendbuf[] = { TDA_CURPAGE_ADDR, page }; + + if (sc->sc_curpage == page) + return ret; + + if ((ret = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, TDA_HDMI, &sendbuf, + sizeof(sendbuf), NULL, 0, 0))) { + DPRINTF(3,("%s: failed to set memory page 0x%02x, errno %d\n", DEVNAME(sc), + page, ret)); + return ret; + } + + sc->sc_curpage = page; + DPRINTF(3,("%s: set page to 0x%02x\n", DEVNAME(sc), page)); + + return ret; +} + +int +nxptda_read_edid(struct nxptda_softc *sc) +{ + int i = 0, ret = 0; + uint8_t reg; + + nxptda_set(sc, TDA_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD); + + /* Block 0 */ + nxptda_write(sc, TDA_DDC_ADDR, 0xa0); + nxptda_write(sc, TDA_DDC_OFFS, 0x00); + nxptda_write(sc, TDA_DDC_SEGM_ADDR, 0x60); + nxptda_write(sc, TDA_DDC_SEGM, 0x00); + + nxptda_write(sc, TDA_EDID_CTRL, 1); + nxptda_write(sc, TDA_EDID_CTRL, 0); + + for (; i < MAX_READ_ATTEMPTS; i++) { + nxptda_read(sc, TDA_INT_FLAGS_2, ®); + if (reg & INT_FLAGS_2_EDID_BLK_RD) { + DPRINTF(3,("%s: EDID-ready IRQ fired\n", DEVNAME(sc))); + break; + } + } + + if (i == MAX_READ_ATTEMPTS) { + printf("%s: no display detected\n", DEVNAME(sc)); + ret = ENXIO; + return ret; + } + + nxptda_set_page(sc, 0x09); + + reg = 0x00; + DPRINTF(3,("%s: ------------- EDID -------------", DEVNAME(sc))); + for (i = 0; i < EDID_LENGTH; i++) { + iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, TDA_HDMI, ®, 1, + &sc->sc_edid[i], 1, 0); + if (!(i % 16)) + DPRINTF(3,("\n%s: ", DEVNAME(sc))); + DPRINTF(3,("%02x", sc->sc_edid[i])); + reg++; + } + DPRINTF(3,("\n%s: --------------------------------\n", DEVNAME(sc))); + + nxptda_clear(sc, TDA_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD); + nxptda_set(sc, TDA_TX4, TX4_PD_RAM); + + return ret; +} + +int +nxptda_reset(struct nxptda_softc *sc) +{ + int ret = 0; + + /* reset core */ + ret |= nxptda_set(sc, TDA_SOFTRESET, 3); + delay(100); + ret |= nxptda_clear(sc, TDA_SOFTRESET, 3); + delay(100); + + /* reset transmitter */ + ret |= nxptda_set(sc, TDA_MAIN_CNTRL0, MAIN_CNTRL0_SR); + ret |= nxptda_clear(sc, TDA_MAIN_CNTRL0, MAIN_CNTRL0_SR); + + return ret; +} + +int +nxptda_init_encoder(struct nxptda_softc *sc, struct videomode *mode) +{ + int ret = 0; + + uint16_t ref_pix, ref_line, n_pix, n_line; + uint16_t hs_pix_start, hs_pix_stop; + uint16_t vs1_pix_start, vs1_pix_stop; + uint16_t vs1_line_start, vs1_line_end; + uint16_t vs2_pix_start, vs2_pix_stop; + uint16_t vs2_line_start, vs2_line_end; + uint16_t vwin1_line_start, vwin1_line_end; + uint16_t vwin2_line_start, vwin2_line_end; + uint16_t de_start, de_stop; + uint8_t reg, div; + + n_pix = mode->htotal; + n_line = mode->vtotal; + + hs_pix_stop = mode->hsync_end - mode->hdisplay; + hs_pix_start = mode->hsync_start - mode->hdisplay; + + de_stop = mode->htotal; + de_start = mode->htotal - mode->hdisplay; + ref_pix = hs_pix_start + 3; + + if (mode->flags & VID_HSKEW) + ref_pix += mode->hsync_end - mode->hsync_start; + + if ((mode->flags & VID_INTERLACE) == 0) { + ref_line = 1 + mode->vsync_start - mode->vdisplay; + vwin1_line_start = mode->vtotal - mode->vdisplay - 1; + vwin1_line_end = vwin1_line_start + mode->vdisplay; + + vs1_pix_start = vs1_pix_stop = hs_pix_start; + vs1_line_start = mode->vsync_start - mode->vdisplay; + vs1_line_end = vs1_line_start + mode->vsync_end - mode->vsync_start; + + vwin2_line_start = vwin2_line_end = 0; + vs2_pix_start = vs2_pix_stop = 0; + vs2_line_start = vs2_line_end = 0; + } else { + ref_line = 1 + (mode->vsync_start - mode->vdisplay)/2; + vwin1_line_start = (mode->vtotal - mode->vdisplay)/2; + vwin1_line_end = vwin1_line_start + mode->vdisplay/2; + + vs1_pix_start = vs1_pix_stop = hs_pix_start; + vs1_line_start = (mode->vsync_start - mode->vdisplay)/2; + vs1_line_end = vs1_line_start + (mode->vsync_end - mode->vsync_start)/2; + + vwin2_line_start = vwin1_line_start + mode->vtotal/2; + vwin2_line_end = vwin2_line_start + mode->vdisplay/2; + + vs2_pix_start = vs2_pix_stop = hs_pix_start + mode->htotal/2; + vs2_line_start = vs1_line_start + mode->vtotal/2 ; + vs2_line_end = vs2_line_start + (mode->vsync_end - mode->vsync_start)/2; + } + + div = 148500 / mode->dot_clock; + if (div != 0) { + div--; + if (div > 3) + div = 3; + } + + /* set HDMI HDCP mode off */ + nxptda_set(sc, TDA_TBG_CNTRL_1, TBG_CNTRL_1_DWIN_DIS); + nxptda_clear(sc, TDA_HDCP_TX33, HDCP_TX33_HDMI); + nxptda_write(sc, TDA_ENC_CNTRL, ENC_CNTRL_DVI_MODE); + + /* no pre-filter or interpolator */ + nxptda_write(sc, TDA_HVF_CNTRL_0, + HVF_CNTRL_0_INTPOL_BYPASS | HVF_CNTRL_0_PREFIL_NONE); + nxptda_write(sc, TDA_VIP_CNTRL_5, VIP_CNTRL_5_SP_CNT(0)); + nxptda_write(sc, TDA_VIP_CNTRL_4, + VIP_CNTRL_4_BLANKIT_NDE | VIP_CNTRL_4_BLC_NONE); + + nxptda_clear(sc, TDA_PLL_SERIAL_3, PLL_SERIAL_3_SRL_CCIR); + nxptda_clear(sc, TDA_PLL_SERIAL_1, PLL_SERIAL_1_SRL_MAN_IP); + nxptda_clear(sc, TDA_PLL_SERIAL_3, PLL_SERIAL_3_SRL_DE); + nxptda_write(sc, TDA_SERIALIZER, 0); + nxptda_write(sc, TDA_HVF_CNTRL_1, HVF_CNTRL_1_VQR_FULL); + + nxptda_write(sc, TDA_RPT_CNTRL, 0); + nxptda_write(sc, TDA_SEL_CLK, SEL_CLK_SEL_VRF_CLK(0) | + SEL_CLK_SEL_CLK1 | SEL_CLK_ENA_SC_CLK); + + nxptda_write(sc, TDA_PLL_SERIAL_2, PLL_SERIAL_2_SRL_NOSC(div) | + PLL_SERIAL_2_SRL_PR(0)); + + nxptda_set(sc, TDA_MAT_CONTRL, MAT_CONTRL_MAT_BP); + + nxptda_write(sc, TDA_ANA_GENERAL, 0x09); + + nxptda_clear(sc, TDA_TBG_CNTRL_0, TBG_CNTRL_0_SYNC_MTHD); + + /* + * Sync on rising HSYNC/VSYNC + */ + reg = VIP_CNTRL_3_SYNC_HS; + if (mode->flags & VID_NHSYNC) + reg |= VIP_CNTRL_3_H_TGL; + if (mode->flags & VID_NVSYNC) + reg |= VIP_CNTRL_3_V_TGL; + nxptda_write(sc, TDA_VIP_CNTRL_3, reg); + + reg = TBG_CNTRL_1_TGL_EN; + if (mode->flags & VID_NHSYNC) + reg |= TBG_CNTRL_1_H_TGL; + if (mode->flags & VID_NVSYNC) + reg |= TBG_CNTRL_1_V_TGL; + nxptda_write(sc, TDA_TBG_CNTRL_1, reg); + + /* Program timing */ + nxptda_write(sc, TDA_VIDFORMAT, 0x00); + + nxptda_write2(sc, TDA_REFPIX_MSB, ref_pix); + nxptda_write2(sc, TDA_REFLINE_MSB, ref_line); + nxptda_write2(sc, TDA_NPIX_MSB, n_pix); + nxptda_write2(sc, TDA_NLINE_MSB, n_line); + + nxptda_write2(sc, TDA_VS_LINE_STRT_1_MSB, vs1_line_start); + nxptda_write2(sc, TDA_VS_PIX_STRT_1_MSB, vs1_pix_start); + nxptda_write2(sc, TDA_VS_LINE_END_1_MSB, vs1_line_end); + nxptda_write2(sc, TDA_VS_PIX_END_1_MSB, vs1_pix_stop); + nxptda_write2(sc, TDA_VS_LINE_STRT_2_MSB, vs2_line_start); + nxptda_write2(sc, TDA_VS_PIX_STRT_2_MSB, vs2_pix_start); + nxptda_write2(sc, TDA_VS_LINE_END_2_MSB, vs2_line_end); + nxptda_write2(sc, TDA_VS_PIX_END_2_MSB, vs2_pix_stop); + nxptda_write2(sc, TDA_HS_PIX_START_MSB, hs_pix_start); + nxptda_write2(sc, TDA_HS_PIX_STOP_MSB, hs_pix_stop); + nxptda_write2(sc, TDA_VWIN_START_1_MSB, vwin1_line_start); + nxptda_write2(sc, TDA_VWIN_END_1_MSB, vwin1_line_end); + nxptda_write2(sc, TDA_VWIN_START_2_MSB, vwin2_line_start); + nxptda_write2(sc, TDA_VWIN_END_2_MSB, vwin2_line_end); + nxptda_write2(sc, TDA_DE_START_MSB, de_start); + nxptda_write2(sc, TDA_DE_STOP_MSB, de_stop); + + nxptda_write(sc, TDA_ENABLE_SPACE, 0x00); + + /* must be last register set */ + nxptda_clear(sc, TDA_TBG_CNTRL_0, TBG_CNTRL_0_SYNC_ONCE); + + return ret; +} + +int +nxptda_get_edid(uint8_t *buf, int buflen) +{ + int ret = 0, i; + struct nxptda_softc *sc = nxptda_cd.cd_devs[0]; + + if (buflen < EDID_LENGTH || sc->sc_edid == NULL) + return -1; + + for (i = 0; i < EDID_LENGTH; i++) + buf[i] = sc->sc_edid[i]; + + return ret; +} + +int +nxptda_set_videomode(struct videomode *mode) +{ + int ret = 0; + struct nxptda_softc *sc = nxptda_cd.cd_devs[0]; + + ret = nxptda_init_encoder(sc, mode); + + return ret; +} Index: sys/arch/armv7/omap/nxptdavar.h =================================================================== RCS file: sys/arch/armv7/omap/nxptdavar.h diff -N sys/arch/armv7/omap/nxptdavar.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/arch/armv7/omap/nxptdavar.h 3 Apr 2017 05:24:34 -0000 @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2016 Ian Sutton + * + * 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. + */ + +int nxptda_get_edid(uint8_t *, int); +int nxptda_set_videomode(struct videomode *); 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 -p -u -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 3 Apr 2017 05:24:34 -0000 @@ -75,7 +75,9 @@ uint32_t prcm_fmask_mask[PRCM_REG_MAX]; uint32_t prcm_imask_addr[PRCM_REG_MAX]; uint32_t prcm_fmask_addr[PRCM_REG_MAX]; -#define SYS_CLK 13 /* SYS_CLK speed in MHz */ +#define SYS_CLK 13 /* SYS_CLK speed in MHz */ +#define PRCM_AM335X_MASTER_OSC 24000 /* KHz */ + struct prcm_softc { struct device sc_dev; @@ -97,6 +99,7 @@ int prcm_setup_dpll5(struct prcm_softc * uint32_t prcm_v3_bit(int mod); uint32_t prcm_am335x_clkctrl(int mod); +void prcm_am335x_setup(struct prcm_softc *); void prcm_am335x_enablemodule(struct prcm_softc *, int); void prcm_am335x_setclock(struct prcm_softc *, int, int); @@ -132,7 +135,7 @@ prcm_attach(struct device *parent, struc sc->sc_dev.dv_xname); if (fdt_is_compatible(node, "ti,am33xx")) { - sc->sc_setup = NULL; + sc->sc_setup = prcm_am335x_setup; sc->sc_enablemodule = prcm_am335x_enablemodule; sc->sc_setclock = prcm_am335x_setclock; } else if (fdt_is_compatible(node, "ti,omap3")) { @@ -336,6 +339,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__); } @@ -350,6 +355,37 @@ prcm_enablemodule(int mod) panic("%s: not initialised!", __func__); sc->sc_enablemodule(sc, mod); +} + +void +prcm_am335x_setup(struct prcm_softc *sc) +{ + uint32_t oreg; + + /* Set display PLL for standard VGA resolution (640x480) */ + oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE); + oreg &= ~0x7; + oreg |= 0x4; + bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE, oreg); + while(!(bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_IDLEST + & 0x10))); + + oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKSEL); + oreg &= 0xFFF80000; + oreg |= 0x2F; + oreg |= (0x3EF << 8); + bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKSEL, oreg); + + oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_M2); + oreg &= ~(0x1F); + oreg |= 0xA; + bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_M2, oreg); + + oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE); + oreg |= 0x7; + bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE, oreg); + while(!(bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_IDLEST + & 0x10))); } void 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 -p -u -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 3 Apr 2017 05:24:34 -0000 @@ -54,6 +54,7 @@ enum PRCM_MODULES { PRCM_I2C1, PRCM_I2C2, PRCM_I2C3, + PRCM_LCDC, }; #define PRCM_REG_MAX 6 Index: share/man/man4/man4.armv7/amdisplay.4 =================================================================== RCS file: share/man/man4/man4.armv7/amdisplay.4 diff -N share/man/man4/man4.armv7/amdisplay.4 --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ share/man/man4/man4.armv7/amdisplay.4 3 Apr 2017 05:24:42 -0000 @@ -0,0 +1,73 @@ +.\" Copyright (c) 2017 Ian Sutton $ +.\" +.\" 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. +.\" +.Dd $Mdocdate: April 2 2017 $ +.Dt AMDISPLAY 4 armv7 +.Os +.Sh NAME +.Nm amdisplay , +.Nm nxptda +.Nd Texas Instruments am335x LCD display driver +.Sh SYNOPSIS +.Nm "amdisplay* at simplebus0" +.Nm "nxptda* at iic*" +.Nm "wsdisplay* at amdisplay*" +.Sh DESCRIPTION +The +.Nm +driver supports the LCD controller integrated in Texas Instruments' line of +AM335x SoCs. +The LCDC reads a framebuffer from memory via DMA and scans it out +at the proper frequency to suit a display (along with the nessecary +hsync/vsync/etc signals) to a PHY transmitter. +The BeagleBone Black uses +NXP/Freescale's TDA19988 HDMI transmitter which is additionally supported by the +.Nm nxptda +driver. +.Sh SEE ALSO +.Xr intro 4 , +.Xr wsdisplay 4 , +.Xr wsfb 4 +.Sh HISTORY +The +.Nm +driver does not appear in +.Ox 6.1 +currently. +.Sh AUTHORS +.An -nosplit +The +.Nm +driver was written by +.An Ian Sutton Aq Mt ian@ce.gl . +The +.Nm nxptda +driver was written by +.An Oleksandr Tymoshenko Aq Mt gonzo@freebsd.org +and later ported to OpenBSD. +.Sh CAVEATS +On the BeagleBone Black, the LCDC and onboard eMMC NAND chip share the same set +of pads such that only one can be wired and used at a time. +If you wish to boot from or use the onboard storage, you must disable +.Nm +via +.Xr config 8 +in your kernel. +.Pp +Display must be attached at boot time, otherwise +.Nm +will fail to configure. +Hotplugging is not supported. +.Sh BUGS +Only VGA mode (640x480) at 16 bit color depth is currently supported.