diff --git a/arch/arm/src/am335x/Kconfig b/arch/arm/src/am335x/Kconfig index dea00146f61..b7ee6fa19bb 100644 --- a/arch/arm/src/am335x/Kconfig +++ b/arch/arm/src/am335x/Kconfig @@ -94,16 +94,18 @@ config AM335X_GPIO bool "GPIO" default n +config AM335X_LCDC + bool "LCD controller" + default n + depends on VIDEO && EXPERIMENTAL + select VIDEO_EDID + config AM335X_TSC bool "Touchscreen Controller" default n -config AM335X_LCDC - bool "LCD Controller" - default n - config AM335X_CPSW - bool "Ethernet subsustem" + bool "Ethernet subsystem" default n config AM335X_PWMSS @@ -248,4 +250,121 @@ config AM335X_DDR_MAPSIZE plus the size of the available heap. NOTE that RAM_SIZE may not include all of SDRAM up to the end of mapped region. +menu "LCD Configuration" + depends on AM335X_LCDC + +config AM335X_LCDC_VRAMBASE + hex "Video RAM base address" + default 0xa0010000 + ---help--- + Base address of the video RAM frame buffer. The default is + (AM335X_EXTDRAM_CS0 + 0x00010000) + +config AM335X_LCDC_USE_CLKIN + bool "Use optional input clock" + default n + +config AM335X_LCDC_CLKIN_FREQUENCY + int "Input clock frequency" + default 0 + depends on AM335X_LCDC_USE_CLKIN + +config AM335X_LCDC_REFRESH_FREQ + int "LCD refesh rate (Hz)" + default 50 + ---help--- + LCD refesh rate (Hz) + +choice + prompt "Bits per pixel" + default AM335X_LCDC_BPP16_565 + +config AM335X_LCDC_BPP1 + bool "1 BPP" + +config AM335X_LCDC_BPP2 + bool "2 BPP" + +config AM335X_LCDC_BPP4 + bool "4 BPP" + +config AM335X_LCDC_BPP8 + bool "8 BPP" + +config AM335X_LCDC_BPP12_444 + bool "12 bpp, 4:4:4 mode" + +config AM335X_LCDC_BPP16_565 + bool "16 BPP, 5:6:5 mode" + +config AM335X_LCDC_BPP24 + bool "24 BPP, 8:8:8 mode (packed)" + +config AM335X_LCDC_BPP32 + bool "32 BPP, 8:8:8 mode (unpacked)" + +endchoice + +config AM335X_LCDC_BGR + bool "Blue-Green-Red color order" + default n + depends on !AM335X_LCDC_MONOCHROME + ---help--- + This option selects BGR color order vs. default RGB + +config AM335X_LCDC_BACKCOLOR + hex "Initial background color" + default 0x0 + ---help--- + Initial background color + +config AM335X_LCDC_ACBIAS + int "AC bias pin frequency" + default 255 + range 0 255 + +config AM335X_LCDC_ACBIAS_PINT + int "AC bias pin transitions per interrupt" + default 0 + range 0 15 + +choice + prompt "DMA burst size" + default AM335X_LCDC_DMA_BURST16 + +config AM335X_LCDC_DMA_BURST1 + bool "1" + +config AM335X_LCDC_DMA_BURST2 + bool "2" + +config AM335X_LCDC_DMA_BURST4 + bool "4" + +config AM335X_LCDC_DMA_BURST8 + bool "8" + +config AM335X_LCDC_DMA_BURST16 + bool "16" + +endchoice + +config AM335X_LCDC_FDD + int "Palette loading delay" + default 128 + range 0 255 + +config AM335X_LCDC_SYNC_EDGE + bool "HSYNC/VSYNC rise or fall" + default n + +config AM335X_LCDC_SYNC_CTRL + bool "Hsync/Vsync pixel clock control on/off" + default y + +config AM335X_LCDC_PIXCLK_INVERT + bool "Invert pixel clock" + default y + +endmenu # LCD Configuration endif # ARCH_CHIP_AM335X diff --git a/arch/arm/src/am335x/Make.defs b/arch/arm/src/am335x/Make.defs index 65cff8e6982..7aea218c536 100644 --- a/arch/arm/src/am335x/Make.defs +++ b/arch/arm/src/am335x/Make.defs @@ -133,4 +133,8 @@ endif ifeq ($(CONFIG_AM335X_GPIO_IRQ),y) CHIP_CSRCS += am335x_gpioirq.c -endif \ No newline at end of file +endif + +ifeq ($(CONFIG_AM335X_LCDC),y) +CHIP_CSRCS += am335x_lcdc.c am335x_edid.c +endif diff --git a/arch/arm/src/am335x/am335x_edid.c b/arch/arm/src/am335x/am335x_edid.c new file mode 100644 index 00000000000..bc93a7b06b9 --- /dev/null +++ b/arch/arm/src/am335x/am335x_edid.c @@ -0,0 +1,402 @@ +/**************************************************************************** + * arch/arm/src/am335x/am335x_wdog.c + * + * Copyright (C) 2019 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * The LCD driver derives from the LPC54xx LCD driver but also includes + * information from the FreeBSD AM335x LCD driver which was released under + * a two-clause BSD license: + * + * Copyright 2013 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. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include + +#include "am335x_lcdc.h" + +/**************************************************************************** + * Pre-processor definitions Functions + ****************************************************************************/ + +#define MODE_HBP(mode) ((mode)->htotal - (mode)->hsync_end) +#define MODE_HFP(mode) ((mode)->hsync_start - (mode)->hdisplay) +#define MODE_HSW(mode) ((mode)->hsync_end - (mode)->hsync_start) +#define MODE_VBP(mode) ((mode)->vtotal - (mode)->vsync_end) +#define MODE_VFP(mode) ((mode)->vsync_start - (mode)->vdisplay) +#define MODE_VSW(mode) ((mode)->vsync_end - (mode)->vsync_start) + +#define MAX_PIXEL_CLOCK 126000 +#define MAX_BANDWIDTH (1280*1024*60) + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: am335x_lcd_edid + * + * Description: + * Return the vertical refresh rate for this video mode. + * + ****************************************************************************/ + +static uint32_t + am335x_videomode_vrefresh(FAR const struct edid_videomode_s *videomode) +{ + uint32_t refresh; + + /* Calculate vertical refresh rate */ + + refresh = (videomode->dotclock * 1000 / videomode->htotal); + refresh = (refresh + videomode->vtotal / 2) / videomode->vtotal; + + if (videomode->flags & VID_INTERLACE) + { + refresh *= 2; + } + + if (videomode->flags & VID_DBLSCAN) + { + refresh /= 2; + } + + return refresh; +} + +/**************************************************************************** + * Name: am335x_videomode_valid + * + * Description: + * Return true if the provided video mode is valid. + * + ****************************************************************************/ + +static bool + am335x_videomode_valid(FAR const struct edid_videomode_s *videomode, + FAR const struct am335x_fbinfo_s *fbinfo) +{ + size_t fbstride; + size_t fbsize; + uint32_t hbp; + uint32_t hfp; + uint32_t hsw; + uint32_t vbp; + uint32_t vfp; + uint32_t vsw; + uint32_t vrefresh; + + if (videomode->dotclock > MAX_PIXEL_CLOCK) + { + return false; + } + + if (videomode->hdisplay & 0xf) + { + return false; + } + + if (videomode->vdisplay > 2048) + { + return false; + } + + /* Check ranges for timing parameters */ + + hbp = MODE_HBP(videomode) - 1; + hfp = MODE_HFP(videomode) - 1; + hsw = MODE_HSW(videomode) - 1; + vbp = MODE_VBP(videomode); + vfp = MODE_VFP(videomode); + vsw = MODE_VSW(videomode) - 1; + + if (hbp > 0x3ff) + { + return false; + } + + if (hfp > 0x3ff) + { + return false; + } + + if (hsw > 0x3ff) + { + return false; + } + + if (vbp > 0xff) + { + return false; + } + + if (vfp > 0xff) + { + return false; + } + + if (vsw > 0x3f) + { + return false; + } + + vrefresh = am335x_videomode_vrefresh(videomode); + if (videomode->vdisplay * videomode->hdisplay * vrefresh > MAX_BANDWIDTH) + { + return false; + } + + /* Finally, make sure that the framebuffer buffer region is large enough + * to support this video mode. + */ + + fbstride = (videomode->hdisplay * AM335X_BPP + 7) >> 3; + fbsize = videomode->vdisplay * fbstride; + + if (fbsize > fbinfo->fbsize) + { + return false; + } + + return true; +} + +/**************************************************************************** + * Name: am335x_lcd_pickmode + * + * Description: + * If there is access to Extended Display Identification Data (EDIDI), + * then the board-specific logic may read the EDID data and use this + * function to select an appropriate video mode. + * + * edid_parse() should be used to convert the raw EDID data into the + * digested form of struct edid_info. + * + * The returned video mode may be used to both (1) configure HDMI and (2) + * initialize the AM335x LCD controller. + * + ****************************************************************************/ + +static const struct edid_videomode_s * + am335x_lcd_pickmode(FAR struct edid_info_s *ei, + FAR const struct am335x_fbinfo_s *fbinfo) +{ + FAR const struct edid_videomode_s *videomode; + int n; + + /* Get standard VGA as default */ + + videomode = NULL; + + /* Pick a video mode -- First check if we can support the preferred mode. */ + + if (ei->edid_preferred_mode != NULL) + { + if (am335x_videomode_valid(ei->edid_preferred_mode, fbinfo)) + { + videomode = ei->edid_preferred_mode; + return videomode; + } + } + + /* Sort video modes by refresh rate, aspect ratio (*), then resolution. + * Preferred mode or largest mode is first in the list and other modes + * are sorted on closest match to that mode. + */ + + edid_sort_modes(ei->edid_modes, &ei->edid_preferred_mode, ei->edid_nmodes); + + /* Pick the first valid mode in the list */ + + for (n = 0; n < ei->edid_nmodes; n++) + { + if (am335x_videomode_valid(&ei->edid_modes[n], fbinfo)) + { + videomode = &ei->edid_modes[n]; + break; + } + } + + return videomode; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: am335x_lcd_videomode + * + * Description: + * If the video mod is known, then the board-specific logic may read the + * use this function to convert the video mode data to an instance of + * struct am335x_panel_info_s which then may be used to initialize the + * the LCD/ + * + * Input Parameters: + * videomode - A reference to the desired video mode. + * panel - A user provided location to receive the panel data. + * + * Returned value: + * None. Always succeeds. + * + ****************************************************************************/ + +void am335x_lcd_videomode(FAR const struct edid_videomode_s *videomode, + FAR struct am335x_panel_info_s *panel) +{ + lcdinfo("Detected videomode: %dx%d @ %dKHz\n", + videomode->hdisplay, videomode->vdisplay, + am335x_videomode_vrefresh(videomode)); + + panel->width = videomode->hdisplay; + panel->height = videomode->vdisplay; + panel->hfp = videomode->hsync_start - videomode->hdisplay; + panel->hbp = videomode->htotal - videomode->hsync_end; + panel->hsw = videomode->hsync_end - videomode->hsync_start; + panel->vfp = videomode->vsync_start - videomode->vdisplay; + panel->vbp = videomode->vtotal - videomode->vsync_end; + panel->vsw = videomode->vsync_end - videomode->vsync_start; + panel->pixelclk_active = true; + + /* Logic for HSYNC should be reversed */ + + panel->hsync_active = ((videomode->flags & VID_NHSYNC) != 0); + panel->vsync_active = ((videomode->flags & VID_NVSYNC) == 0); + panel->pixclk = videomode->dotclock * 1000; + + /* Set other values to the default */ + +#ifdef CONFIG_AM335X_LCDC_SYNC_EDGE + panel->sync_edge = true; +#else + panel->sync_edge = false; +#endif + +#ifdef CONFIG_AM335X_LCDC_SYNC_CTRL + panel->sync_ctrl = true; +#else + panel->sync_ctrl = false; +#endif + +#ifdef CONFIG_AM335X_LCDC_PIXCLK_INVERT + panel->pixelclk_active = true; +#else + panel->pixelclk_active = false; +#endif + + panel->acbias = CONFIG_AM335X_LCDC_ACBIAS; + panel->acbias_pint = CONFIG_AM335X_LCDC_ACBIAS_PINT; + panel->dma_burstsz = AM335X_LCD_DMA_BURSTSZ; + panel->bpp = AM335X_BPP; /* REVISIT */ + panel->fdd = CONFIG_AM335X_LCDC_FDD; +} + +/**************************************************************************** + * Name: am335x_lcd_edid + * + * Description: + * If there is access to Extended Display Identification Data (EDID), + * then the board-specific logic may read the EDID data and use this + * function to initialize an instance of struct am335x_panel_info_s. + * + * The returned video mode may optionally be returned to configure HDMI. + * + * Input Parameters: + * edid - A reference to the raw EDID data. + * len - The length of the EDID data in bytes + * panel - A user provided location to receive the panel data. + * selected - A user provided location to receive the selected video mode. + * fbinfo - Provides information about the pre-allocate framebuffer + * memory. + * + * Returned value: + * None. Always succeeds. The logic will fallback to VGA mode if no + * EDID data is provided or if there is no valid video mode in the EDID + * data. + * + ****************************************************************************/ + +void am335x_lcd_edid(FAR const uint8_t *edid, size_t edid_len, + FAR struct am335x_panel_info_s *panel, + FAR struct edid_videomode_s *selected, + FAR const struct am335x_fbinfo_s *fbinfo) +{ + FAR const struct edid_videomode_s *videomode = NULL; + struct edid_info_s ei; + + /* Do we have EDID data? */ + + if (edid != NULL && edid_len > 0) + { + /* Parse the EDID data */ + + if (edid_parse(edid, &ei) == 0) + { + videomode = am335x_lcd_pickmode(&ei, fbinfo); + } + else + { + lcderr("ERROR: Failed to parse EDID\n"); + } + } + + /* Use standard VGA as fallback */ + + if (videomode == NULL) + { + videomode = edid_mode_lookup("640x480x60"); + DEBUGASSERT(videomode != NULL); + } + + /* Initialize the LCD using the selected video mode */ + + am335x_lcd_videomode(videomode, panel); + + /* Return the selected video mode */ + + if (selected != NULL) + { + memcpy(selected, videomode, sizeof(struct edid_videomode_s)); + } +} diff --git a/arch/arm/src/am335x/am335x_lcdc.c b/arch/arm/src/am335x/am335x_lcdc.c new file mode 100644 index 00000000000..bc9a17f90a6 --- /dev/null +++ b/arch/arm/src/am335x/am335x_lcdc.c @@ -0,0 +1,821 @@ +/**************************************************************************** + * arch/arm/src/am225x/am335x_lcd.c + * + * Copyright (C) 2019 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * This driver derives from the LPC54xx LCD driver but also includes + * information from the FreeBSD AM335x LCD driver which was released under + * a two-clause BSD license: + * + * Copyright 2013 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. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "up_arch.h" +#include "am335x_pinmux.h" +#include "am335x_config.h" +#include "am335x_gpio.h" +#include "am335x_lcdc.h" + +#include + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Get information about the video controller configuration and the + * configuration of each color plane. + */ + +static int am335x_getvideoinfo(FAR struct fb_vtable_s *vtable, + FAR struct fb_videoinfo_s *vinfo); +static int am335x_getplaneinfo(FAR struct fb_vtable_s *vtable, int planeno, + FAR struct fb_planeinfo_s *pinfo); + +/* The following is provided only if the video hardware supports RGB color + * mapping + */ + +#ifdef CONFIG_FB_CMAP +static int am335x_getcmap(FAR struct fb_vtable_s *vtable, + FAR struct fb_cmap_s *cmap); +static int am335x_putcmap(FAR struct fb_vtable_s *vtable, + FAR const struct fb_cmap_s *cmap); +#endif + +/* The following is provided only if the video hardware supports a hardware + * cursor + */ + +#ifdef CONFIG_FB_HWCURSOR +static int am335x_getcursor(FAR struct fb_vtable_s *vtable, + FAR struct fb_cursorattrib_s *attrib); +static int am335x_setcursor(FAR struct fb_vtable_s *vtable, + FAR struct fb_setcursor_s *settings); +#endif + +/* Miscellaneous internal functions */ + +static int am335x_lcd_interrupt(int irq, void *context, void *arg); +static uint32_t am335x_lcd_divisor(uint32_t reference, uint32_t freq); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* The framebuffer object -- There is no private state information in this + * framebuffer driver. + */ + +struct fb_vtable_s g_fbinterface = +{ + .getvideoinfo = am335x_getvideoinfo, + .getplaneinfo = am335x_getplaneinfo, +#ifdef CONFIG_FB_CMAP + .getcmap = am335x_getcmap, + .putcmap = am335x_putcmap, +#endif +#ifdef CONFIG_FB_HWCURSOR + .getcursor = am335x_getcursor, + .setcursor = am335x_setcursor, +#endif +}; + +struct am335x_lcd_dev_s +{ + /* Saved panel configuration */ + + struct am335x_panel_info_s panel; + + sem_t exclsem; /* Assure mutually exclusive access */ + nxgl_coord_t stride; /* Width of framebuffer in bytes */ + size_t fbsize; /* Size of the framebuffer allocation */ + FAR void *fbmem; /* Allocated framebuffer memory (virtual) */ + FAR void *fbphys; /* Allocated framebuffer memory (physical) */ +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Since there is only a single LCD controller, its state structure can be + * allocated in .bss. + */ + +static struct am335x_lcd_dev_s g_lcddev; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: am335x_getvideoinfo + ****************************************************************************/ + +static int am335x_getvideoinfo(FAR struct fb_vtable_s *vtable, + FAR struct fb_videoinfo_s *vinfo) +{ + struct am335x_lcd_dev_s *priv = &g_lcddev; + + lcdinfo("vtable=%p vinfo=%p\n", vtable, vinfo); + if (vtable && vinfo) + { + vinfo->fmt = AM335X_COLOR_FMT; /* REVISIT */ + vinfo->xres = priv->panel.width; + vinfo->yres = priv->panel.height; + vinfo->nplanes = 1; +#ifdef CONFIG_FB_OVERLAY + vinfo->noverlays = 0; +#endif + return OK; + } + + lcderr("ERROR: Returning EINVAL\n"); + return -EINVAL; +} + +/**************************************************************************** + * Name: am335x_getplaneinfo + ****************************************************************************/ + +static int am335x_getplaneinfo(FAR struct fb_vtable_s *vtable, int planeno, + FAR struct fb_planeinfo_s *pinfo) +{ + struct am335x_lcd_dev_s *priv = &g_lcddev; + + lcdinfo("vtable=%p planeno=%d pinfo=%p\n", vtable, planeno, pinfo); + + if (vtable != NULL && planeno == 0 && pinfo != NULL) + { +#ifdef CONFIG_BUILD_KERNEL + pinfo->fbmem = priv->fbphys; +#else + pinfo->fbmem = priv->fbmem; +#endif + pinfo->fblen = priv->fbsize; + pinfo->stride = priv->stride; + pinfo->display = 0; + pinfo->bpp = priv->panel.bpp; + return OK; + } + + lcderr("ERROR: Returning EINVAL\n"); + return -EINVAL; +} + +/**************************************************************************** + * Name: am335x_getcmap + ****************************************************************************/ + +#ifdef CONFIG_FB_CMAP +static int am335x_getcmap(FAR struct fb_vtable_s *vtable, + FAR struct fb_cmap_s *cmap) +{ + return -ENOSYS; +} +#endif + +/**************************************************************************** + * Name: am335x_putcmap + ****************************************************************************/ + +#ifdef CONFIG_FB_CMAP +static int am335x_putcmap(FAR struct fb_vtable_s *vtable, + FAR const struct fb_cmap_s *cmap) +{ + return -ENOSYS; +} +#endif + +/**************************************************************************** + * Name: am335x_getcursor + ****************************************************************************/ + +#ifdef CONFIG_FB_HWCURSOR +static int am335x_getcursor(FAR struct fb_vtable_s *vtable, + FAR struct fb_cursorattrib_s *attrib) +{ + lcdinfo("vtable=%p attrib=%p\n", vtable, attrib); + return -ENOSYS; +} +#endif + +/**************************************************************************** + * Name: am335x_setcursor + ****************************************************************************/ + +#ifdef CONFIG_FB_HWCURSOR +static int am335x_setcursor(FAR struct fb_vtable_s *vtable, + FAR struct fb_setcursor_s *settings) +{ + lcdinfo("vtable=%p settings=%p\n", vtable, settings); + return -ENOSYS; +} +#endif + +/**************************************************************************** + * Name: am335x_lcd_interrupt + ****************************************************************************/ + +static int am335x_lcd_interrupt(int irq, void *context, void *arg) +{ + struct am335x_lcd_dev_s *priv = (struct am335x_lcd_dev_s *)arg; + uint32_t regval; + + regval = getreg32(AM335X_LCD_IRQ_STAT); + putreg32(AM335X_LCD_IRQ_STAT, regval); + + /* Read value back to make sure it reached the hardware */ + + regval = getreg32(AM335X_LCD_IRQ_STAT); + if ((regval & LCD_IRQ_SYNC) != 0 || (regval & LCD_IRQ_PL) != 0) + { + regval = getreg32(AM335X_LCD_RASTER_CTRL); + regval &= ~LCD_RASTER_CTRL_LCD_EN; + putreg32(AM335X_LCD_RASTER_CTRL, regval); + + regval = getreg32(AM335X_LCD_RASTER_CTRL); + regval |= LCD_RASTER_CTRL_LCD_EN; + putreg32(AM335X_LCD_RASTER_CTRL, regval); + goto done; + } + + if ((regval & LCD_IRQ_EOF0) != 0) + { + putreg32(AM335X_LCD_DMA_FB0_BASE, priv->fbphys); + putreg32(AM335X_LCD_DMA_FB0_CEIL, + priv->fbphys + priv->fbsize - 1); + regval &= ~LCD_IRQ_EOF0; + } + + if ((regval & LCD_IRQ_EOF1) != 0) + { + putreg32(AM335X_LCD_DMA_FB1_BASE, priv->fbphys); + putreg32(AM335X_LCD_DMA_FB1_CEIL, + priv->fbphys + priv->fbsize - 1); + regval &= ~LCD_IRQ_EOF1; + } + + if ((regval & LCD_IRQ_FUF) != 0) + { + /* TODO: Handle FUF */ + + regval &= ~LCD_IRQ_FUF; + } + + if ((regval & LCD_IRQ_ACB) != 0) + { + /* TODO: Handle ACB */ + + regval &= ~LCD_IRQ_ACB; + } + +done: + putreg32(AM335X_LCD_END_INT, 0); + + /* Read value back to make sure it reached the hardware */ + + regval = getreg32(AM335X_LCD_END_INT); + return OK; +} + +/**************************************************************************** + * Name: am335x_lcd_divisor + ****************************************************************************/ + +static uint32_t am335x_lcd_divisor(uint32_t reference, uint32_t freq) +{ + uint32_t div; + uint32_t delta; + uint32_t mindelta; + int i; + + mindelta = freq; + div = 255; + + /* Raster mode case: divisors are in range from 2 to 255 */ + + for (i = 2; i < 255; i++) + { + delta = reference / i - freq; + if (delta < 0) + { + delta = -delta; + } + + if (delta < mindelta) + { + div = i; + mindelta = delta; + } + } + + return div; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: am335x_lcd_initialize + * + * Description: + * Initialize the AM335x for use the display described by the provided + * instance of struct am335x_panel_info_s. + * + * This function must be called by board specific logic to initialize the + * LCD. Normally the calling sequence is as follows: + * + * 1a. Graphics application starts and initializes the NX server via + * boardctl(BOARDIOC_NX_START). This calls the graphics + * initialization function nxmu_start() which, in turn, will call + * up_fbinitialize(). Or, + * 1b. The framebuffer character driver is initialized and calls + * up_fbinitialize(). + * 2. The function up_fbinitialize() must reside in board specific logic + * under configs/. It must create the instance of struct + * am335x_panel_info_s and call this function with that instance. + * + * For a directly connected LCD, either (1) the struct am335x_panel_info_s + * may be initialized with constant data or (2) the desired video mode can + * obtained via lookup from edid_mode_lookup() and the struct + * am335x_panel_info_s can be created with am335x_lcd_videomode(). + * + * If there is access to Extended Display Identification Data (EDID), then + * the board-specific logic may read the EDID data and use + * am335x_lcd_edid() to use the EDID data to initialize the struct + * am335x_panel_info_s instance. + * + * Input Parameters: + * panel - Provides information about the connect LCD panel. + * fbinfo - Provides information about the pre-allocate framebuffer + * memory. + * + * Returned value: + * Zero (OK) is returned on success; a negated errno value is returned in + * the the case of a failure. + * + ****************************************************************************/ + +int am335x_lcd_initialize(FAR const struct am335x_panel_info_s *panel, + FAR const struct am335x_fbinfo_s *fbinfo) +{ + struct am335x_lcd_dev_s *priv = &g_lcddev; + uint32_t regval; + uint32_t reffreq; + uint32_t timing0; + uint32_t timing1; + uint32_t timing2; + uint32_t logburst; + uint32_t hbp; + uint32_t hfp; + uint32_t hsw; + uint32_t vbp; + uint32_t vfp; + uint32_t vsw; + uint32_t width; + uint32_t height; + int div; + int ret; + + DEBUGASSERT(panel != NULL && fbinfo != NULL); + + /* Configure LCD pins */ + + lcdinfo("Configuring pins\n"); + +#if !defined(CONFIG_AM335X_LCDC_BPP16_565) && !defined(CONFIG_AM335X_LCDC_BPP12_444) + am335x_gpio_config(GPIO_LCD_DATA0); + am335x_gpio_config(GPIO_LCD_DATA1); + am335x_gpio_config(GPIO_LCD_DATA2); +#endif +#ifndef CONFIG_AM335X_LCDC_BPP12_444 + am335x_gpio_config(GPIO_LCD_DATA3); +#endif + am335x_gpio_config(GPIO_LCD_DATA4); + am335x_gpio_config(GPIO_LCD_DATA5); + am335x_gpio_config(GPIO_LCD_DATA6); + am335x_gpio_config(GPIO_LCD_DATA7); + +#if AM335X_BPP > 8 /* Or STN 8-BPP Dual panel */ +#if !defined(CONFIG_AM335X_LCDC_BPP16_565) && !defined(CONFIG_AM335X_LCDC_BPP12_444) + am335x_gpio_config(GPIO_LCD_DATA8); + am335x_gpio_config(GPIO_LCD_DATA9); +#endif +#ifndef CONFIG_AM335X_LCDC_BPP12_444 + am335x_gpio_config(GPIO_LCD_DATA10); + am335x_gpio_config(GPIO_LCD_DATA11); +#endif + am335x_gpio_config(GPIO_LCD_DATA12); + am335x_gpio_config(GPIO_LCD_DATA13); + am335x_gpio_config(GPIO_LCD_DATA14); + am335x_gpio_config(GPIO_LCD_DATA15); +#endif + +#if AM335X_BPP > 16 || defined(CONFIG_AM335X_LCDC_TFTPANEL) +#if !defined(CONFIG_AM335X_LCDC_BPP16_565) && !defined(CONFIG_AM335X_LCDC_BPP12_444) + am335x_gpio_config(GPIO_LCD_DATA16); + am335x_gpio_config(GPIO_LCD_DATA17); + am335x_gpio_config(GPIO_LCD_DATA18); +#endif +#ifndef CONFIG_AM335X_LCDC_BPP12_444 + am335x_gpio_config(GPIO_LCD_DATA19); +#endif + am335x_gpio_config(GPIO_LCD_DATA20); + am335x_gpio_config(GPIO_LCD_DATA21); + am335x_gpio_config(GPIO_LCD_DATA22); + am335x_gpio_config(GPIO_LCD_DATA23); +#endif + + /* Other pins */ + + am335x_gpio_config(GPIO_LCD_HSYNC); + am335x_gpio_config(GPIO_LCD_VSYNC); + am335x_gpio_config(GPIO_LCD_AC_BIAS_EN); + am335x_gpio_config(GPIO_LCD_MEMORY_CLK_1); + am335x_gpio_config(GPIO_LCD_MEMORY_CLK_2); + + /* Initialize the device state singleton */ + + sem_init(&priv->exclsem, 0, 1); + memcpy(&priv->panel, panel, sizeof(struct am335x_panel_info_s)); + + /* Save framebuffer information */ + + priv->fbmem = fbinfo->fbmem; + priv->fbphys = fbinfo->fbphys; + priv->stride = (priv->panel.width * priv->panel.bpp + 7) >> 3; + priv->fbsize = priv->stride * priv->panel.height; + DEBUGASSERT(priv->fbsize <= fbinfo->fbsize); + + /* Attach the LCD interrupt */ + + ret = irq_attach(AM335X_IRQ_LCDC, am335x_lcd_interrupt, priv); + if (ret < 0) + { + lcderr("ERROR: Failed to attach LCDC interrupt."); + } + + /* Enable clocking to the LCD peripheral */ + /* REVISIT: Need to (1) set the initial pixel clock and (2) set + * LCDC related bits in PRCM to enable clocking to the LCDC. + * Reference: http://fxr.watson.org/fxr/source/arm/ti/am335x/am335x_prcm.c#L819 + */ + + lcdinfo("Enable clocking to the LCD controller\n"); +#if 0 /* FIXEME */ + ti_prcm_clk_enable(LCDC_CLK); +#endif +#warning Missing logic + + /* Adjust clock to get double of requested pixel clock frequency + * HDMI/DVI displays are very sensitive to error in frequency value. + * Reference: http://fxr.watson.org/fxr/source/arm/ti/am335x/am335x_prcm.c#L718 + */ + +#warning Missing logic +#if 0 /* FIXEME */ + if (ti_prcm_clk_set_source_freq(LCDC_CLK, priv->panel.pixclk * 2)) +#endif + { + lcderr("ERROR: Can't set source frequency\n"); + return -ENXIO; + } + + /* Read back the actual reference clock frequency */ + /* Reference: http://fxr.watson.org/fxr/source/arm/ti/am335x/am335x_prcm.c#L701 */ + +#warning Missing logic +#if 0 /* FIXEME */ + if (ti_prcm_clk_get_source_freq(LCDC_CLK, &reffreq)) +#endif + { + lcderr("ERROR: Can't get reference frequency\n"); + return -ENXIO; + } + + /* Panel initialization */ + + /* Put the LCD framebuffer memory in a known state */ + + am335x_lcdclear(CONFIG_AM335X_LCDC_BACKCOLOR); + + /* Only raster mode is supported */ + + regval = LCD_CTRL_MODE_RASTER; + div = am335x_lcd_divisor(reffreq, priv->panel.pixclk); + regval |= (div << LCD_CTRL_CLKDIV_SHIFT); + putreg32(AM335X_LCD_CTRL, regval); + + /* Set timing */ + + timing0 = timing1 = timing2 = 0; + + hbp = priv->panel.hbp - 1; + hfp = priv->panel.hfp - 1; + hsw = priv->panel.hsw - 1; + + vbp = priv->panel.vbp; + vfp = priv->panel.vfp; + vsw = priv->panel.vsw - 1; + + height = priv->panel.height - 1; + width = priv->panel.width - 1; + + /* Horizontal back porch */ + + timing0 |= (hbp & 0xff) << LCD_RASTER_TIMING_0_HBP_SHIFT; + timing2 |= ((hbp >> 8) & 3) << LCD_RASTER_TIMING_2_HBP_HBITS_SHIFT; + + /* Horizontal front porch */ + + timing0 |= (hfp & 0xff) << LCD_RASTER_TIMING_0_HFP_SHIFT; + timing2 |= ((hfp >> 8) & 3) << LCD_RASTER_TIMING_2_HFP_HBITS_SHIFT; + + /* Horizontal sync width */ + + timing0 |= (hsw & 0x3f) << LCD_RASTER_TIMING_0_HSW_SHIFT; + timing2 |= ((hsw >> 6) & 0xf) << LCD_RASTER_TIMING_2_HSW_HBITS_SHIFT; + + /* Vertical back porch, front porch, sync width */ + + timing1 |= (vbp & 0xff) << LCD_RASTER_TIMING_1_VBP_SHIFT; + timing1 |= (vfp & 0xff) << LCD_RASTER_TIMING_1_VFP_SHIFT; + timing1 |= (vsw & 0x3f) << LCD_RASTER_TIMING_1_VSW_SHIFT; + + /* Pixels per line */ + + timing0 |= ((width >> 10) & 1) << LCD_RASTER_TIMING_0_PPLLSB_SHIFT; + timing0 |= ((width >> 4) & 0x3f) << LCD_RASTER_TIMING_0_PPLLSB_SHIFT; + + /* Lines per panel */ + + timing1 |= (height & 0x3ff) << LCD_RASTER_TIMING_1_LPP_SHIFT; + timing2 |= ((height >> 10) & 1) << LCD_RASTER_TIMING_2_LPP_B10_SHIFT; + + /* Clock signal settings */ + + if (priv->panel.sync_ctrl) + { + timing2 |= LCD_RASTER_TIMING_2_PHSVS_ON; + } + + if (priv->panel.sync_edge) + { + timing2 |= LCD_RASTER_TIMING_2_PHSVS_RF; + } + + if (!priv->panel.hsync_active) + { + timing2 |= LCD_RASTER_TIMING_2_IHS; + } + + if (!priv->panel.vsync_active) + { + timing2 |= LCD_RASTER_TIMING_2_IVS; + } + + if (!priv->panel.pixelclk_active) + { + timing2 |= LCD_RASTER_TIMING_2_IPC; + } + + /* AC bias */ + + timing2 |= (priv->panel.acbias << LCD_RASTER_TIMING_2_ACB_SHIFT); + timing2 |= (priv->panel.acbias_pint << LCD_RASTER_TIMING_2_ACBI_SHIFT); + + putreg32(AM335X_LCD_RASTER_TIMING_0, timing0); + putreg32(AM335X_LCD_RASTER_TIMING_1, timing1); + putreg32(AM335X_LCD_RASTER_TIMING_2, timing2); + + /* DMA settings */ + + regval = LCD_DMA_CTRL_FRAME_MODE; + + /* Find power of 2 for current burst size */ + + switch (priv->panel.dma_burstsz) + { + case 1: + logburst = 0; + break; + + case 2: + logburst = 1; + break; + + case 4: + logburst = 2; + break; + + case 8: + logburst = 3; + break; + + case 16: + default: + logburst = 4; + break; + } + + regval |= (logburst << LCD_DMA_CTRL_BURST_SIZE_SHIFT); + + /* XXX: FIFO TH */ + + regval |= (0 << LCD_DMA_CTRL_TH_FIFO_RDY_SHIFT); + putreg32(AM335X_LCD_DMA_CTRL, regval); + + putreg32(AM335X_LCD_DMA_FB0_BASE, priv->fbphys); + putreg32(AM335X_LCD_DMA_FB0_BASE, priv->fbphys + priv->fbsize - 1); + putreg32(AM335X_LCD_DMA_FB1_BASE, priv->fbphys); + putreg32(AM335X_LCD_DMA_FB1_CEIL, priv->fbphys + priv->fbsize - 1); + + /* Enable LCD */ + + regval = LCD_RASTER_CTRL_LCD_TFT; + regval |= (priv->panel.fdd << LCD_RASTER_CTRL_REQDLY_SHIFT); + regval |= LCD_RASTER_CTRL_DATA; + + if (priv->panel.bpp >= 24) + { + regval |= LCD_RASTER_CTRL_TFT24; + } + + if (priv->panel.bpp == 32) + { + regval |= LCD_RASTER_CTRL_TFT24_UNPACKED; + } + + putreg32(AM335X_LCD_RASTER_CTRL, regval); + + putreg32(AM335X_LCD_CLKC_ENABLE, + LCD_CLKC_ENABLE_CORE | LCD_CLKC_ENABLE_LIDD | + LCD_CLKC_ENABLE_DMA); + + putreg32(AM335X_LCD_CLKC_RESET, LCD_CLKC_RESET_MAIN); + up_udelay(100); + putreg32(AM335X_LCD_CLKC_RESET, 0); + + regval = LCD_IRQ_DONE | LCD_IRQ_RR_DONE | LCD_IRQ_SYNC | LCD_IRQ_ACB | + LCD_IRQ_PL | LCD_IRQ_FUF | LCD_IRQ_EOF0 | LCD_IRQ_EOF1; + putreg32(AM335X_LCD_IRQ_EN_SET, regval); + + regval = getreg32(AM335X_LCD_RASTER_CTRL); + regval |= LCD_RASTER_CTRL_LCD_EN; + putreg32(AM335X_LCD_RASTER_CTRL, regval); + + putreg32(AM335X_LCD_SYSC, LCD_SYSC_IDLE_SMART | LCD_SYSC_STANDBY_SMART); + +#ifdef CONFIG_AM335X_LCDC_BACKLIGHT + /* Turn on the back light + * REVISIT: Current assumes a discrete ON/OFF control. Needs additional + * support for backlight level control. + */ + + am335x_backlight(true); +#endif + + /* Enable interrupts at the interrupt controller */ + + up_enable_irq(AM335X_IRQ_LCDC); + return OK; +} + +/**************************************************************************** + * Name: up_fbgetvplane + * + * Description: + * Return a a reference to the framebuffer object for the specified video + * plane of the specified plane. Many OSDs support multiple planes of video. + * + * Input Parameters: + * display - In the case of hardware with multiple displays, this + * specifies the display. Normally this is zero. + * vplane - Identifies the plane being queried. + * + * Returned Value: + * A non-NULL pointer to the frame buffer access structure is returned on + * success; NULL is returned on any failure. + * + ****************************************************************************/ + +FAR struct fb_vtable_s *up_fbgetvplane(int display, int vplane) +{ + lcdinfo("vplane: %d\n", vplane); + if (vplane == 0) + { + return &g_fbinterface; + } + else + { + return NULL; + } +} + +/**************************************************************************** + * Name: up_fbuninitialize + * + * Description: + * Uninitialize the framebuffer support for the specified display. + * + * Input Parameters: + * display - In the case of hardware with multiple displays, this + * specifies the display. Normally this is zero. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void up_fbuninitialize(int display) +{ +#ifdef CONFIG_AM335X_LCDC_BACKLIGHT + /* Turn off the back light */ + + am335x_backlight(false); +#endif + + /* Disable the LCD controller */ +#warning Missing Logic + + /* Disable clocking to the LCD peripheral */ +#warning Missing Logic +} + +/**************************************************************************** + * Name: am335x_lcdclear + * + * Description: + * This is a non-standard LCD interface just for the AM335x. Clearing + * the display in the normal way by writing a sequences of runs that + * covers the entire display can be slow. Here the display is cleared by + * simply setting all VRAM memory to the specified color. + * + ****************************************************************************/ + +void am335x_lcdclear(nxgl_mxpixel_t color) +{ + struct am335x_lcd_dev_s *priv = &g_lcddev; +#if AM335X_BPP > 16 + uint32_t *dest = (uint32_t *)priv->fbmem; + int incr = sizeof(uint32_t); +#else + uint16_t *dest = (uint16_t *)priv->fbmem; + int incr = sizeof(uint16_t); +#endif + int i; + + lcdinfo("Clearing display: color=%04x VRAM=%p size=%lu\n", + color, priv->fbmem, (unsigned long)priv->fbsize); + + for (i = 0; i < priv->fbsize; i += incr) + { + *dest++ = color; + } +} diff --git a/arch/arm/src/am335x/am335x_lcdc.h b/arch/arm/src/am335x/am335x_lcdc.h new file mode 100644 index 00000000000..6f001d5d3a8 --- /dev/null +++ b/arch/arm/src/am335x/am335x_lcdc.h @@ -0,0 +1,314 @@ +/**************************************************************************** + * arch/arm/src/am335x/am335x_lcdc.h + * + * Copyright (C) 2019 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * The LCD driver derives from the LPC54xx LCD driver but also includes + * information from the FreeBSD AM335x LCD driver which was released under + * a two-clause BSD license: + * + * Copyright 2013 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. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT OWNER 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. + * + ****************************************************************************/ + +/* The LPC54 LCD driver uses the common framebuffer interfaces declared in + * include/nuttx/video/fb.h. + */ + +#ifndef __ARCH_ARM_SRC_AM335X_AM335X_LCDC_H +#define __ARCH_ARM_SRC_AM335X_AM335X_LCDC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include + +#include "hardware/am335x_lcd.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* Background color */ + +#ifndef CONFIG_AM335X_LCDC_BACKCOLOR +# warning "Assuming background color == 16" +# define CONFIG_AM335X_LCDC_BACKCOLOR 0 /* Initial background color */ +#endif + +/* Default characteristics (may be overridden via struct am335x_panel_info_s */ + +/* Bits per pixel / color format */ + +#undef AM335X_COLOR_FMT +#if defined(CONFIG_AM335X_LCDC_BPP1) +# define AM335X_BPP 1 +# define AM335X_COLOR_FMT FB_FMT_Y1 +#elif defined(CONFIG_AM335X_LCDC_BPP2) +# define AM335X_BPP 2 +# define AM335X_COLOR_FMT FB_FMT_Y2 +#elif defined(CONFIG_AM335X_LCDC_BPP4) +# define AM335X_BPP 4 +# define AM335X_COLOR_FMT FB_FMT_Y4 +#elif defined(CONFIG_AM335X_LCDC_BPP8) +# define AM335X_BPP 8 +# define AM335X_COLOR_FMT FB_FMT_Y8 +#elif defined(CONFIG_AM335X_LCDC_BPP12_444) +# define AM335X_BPP 1 12 +# define AM335X_COLOR_FMT FB_FMT_RGB12_444 +#elif defined(CONFIG_AM335X_LCDC_BPP16_565) +# define AM335X_BPP 16 +# define AM335X_COLOR_FMT FB_FMT_RGB16_565 +#elif defined(CONFIG_AM335X_LCDC_BPP24) +# define AM335X_BPP 24 RGB */ +# define AM335X_COLOR_FMT FB_FMT_RGB24 +#else +# warning "Assuming 16 BPP 5:6:5" +# define AM335X_BPP 16 +# define CONFIG_AM335X_LCDC_BPP16_565 1 +# define AM335X_COLOR_FMT FB_FMT_RGB16_565 +#endif + +#ifndef CONFIG_AM335X_LCDC_ACBIAS +# warning "Assuming AC bias == 255" +# define CONFIG_AM335X_LCDC_ACBIAS 255 +#endif + +#ifndef CONFIG_AM335X_LCDC_ACBIAS_PINT +# warning "Assuming AC bias per interrupt == 0" +# define CONFIG_AM335X_LCDC_ACBIAS_PINT 0 +#endif + +#if defined(CONFIG_AM335X_LCDC_DMA_BURST1) +# define AM335X_LCD_DMA_BURSTSZ 1 +#elif defined(CONFIG_AM335X_LCDC_DMA_BURST2) +# define AM335X_LCD_DMA_BURSTSZ 2 +#elif defined(CONFIG_AM335X_LCDC_DMA_BURST4) +# define AM335X_LCD_DMA_BURSTSZ 4 +#elif defined(CONFIG_AM335X_LCDC_DMA_BURST8) +# define AM335X_LCD_DMA_BURSTSZ 8 +#elif defined(CONFIG_AM335X_LCDC_DMA_BURST16) +# define AM335X_LCD_DMA_BURSTSZ 16 +#else +# warning "Assuming DMA burst size == 16" +# define CONFIG_AM335X_LCDC_DMA_BURST16 1 +# define AM335X_LCD_DMA_BURSTSZ 16 +#endif + +#ifndef CONFIG_AM335X_LCDC_FDD +# warning "Assuming FDD == 128" +# define CONFIG_AM335X_LCDC_FDD 128 +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Describes the LCD panel configuration */ + +struct am335x_panel_info_s +{ + bool hsync_active; /* HSync active */ + bool vsync_active; /* Invert VSync */ + bool sync_edge; /* HSYNC/VSYNC rise or fall */ + bool sync_ctrl; /* Hsync/Vsync pixel clock control on/off */ + bool pixelclk_active; /* Invert pixel clock */ + + uint32_t width; /* Display width (pixels) */ + uint32_t height; /* Display height (lines) */ + uint32_t hfp; /* Horizontal front porch (pixels) */ + uint32_t hbp; /* Horizontal back porch (pixels) */ + uint32_t hsw; /* HSync width */ + uint32_t vfp; /* Vertical front porch (lines) */ + uint32_t vbp; /* Vertical back porch (lines) */ + uint32_t vsw; /* VSync width */ + uint32_t pixclk; /* Pixel clock */ + + uint32_t acbias; /* AC bias pin frequency */ + uint32_t acbias_pint; /* AC bias pins transitions per interrupt */ + uint32_t dma_burstsz; /* DMA burst size */ + uint32_t bpp; /* Bits per pixel */ + uint32_t fdd; /* Palette loading delay */ +}; + +/* A special memory region is set aside for the framebuffer. This region + * must be set aside in the linker script and assigned a virtual address + * during initialization. The framebuffer memory region must be non- + * cached. + */ + +struct am335x_fbinfo_s +{ + FAR void *fbmem; /* Virtual address of the framebuffer */ + FAR void *fbphys; /* Physical address of the framebuffer */ + size_t fbsize; /* Size of the framebuffer region */ +}; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: am335x_lcd_initialize + * + * Description: + * Initialize the AM335x for use the display described by the provided + * instance of struct am335x_panel_info_s. + * + * This function must be called by board specific logic to initialize the + * LCD. Normally the calling sequence is as follows: + * + * 1a. Graphics application starts and initializes the NX server via + * boardctl(BOARDIOC_NX_START). This calls the graphics + * initialization function nxmu_start() which, in turn, will call + * up_fbinitialize(). Or, + * 1b. The framebuffer character driver is initialized and calls + * up_fbinitialize(). + * 2. The function up_fbinitialize() must reside in board specific logic + * under configs/. It must create the instance of struct + * am335x_panel_info_s and call this function with that instance. + * + * For a directly connected LCD, either (1) the struct am335x_panel_info_s + * may be initialized with constant data or (2) the desired video mode can + * obtained via lookup from edid_mode_lookup() and the struct + * am335x_panel_info_s can be created with am335x_lcd_videomode(). + * + * If there is access to Extended Display Identification Data (EDID), then + * the board-specific logic may read the EDID data and use + * am335x_lcd_edid() to use the EDID data to initialize the struct + * am335x_panel_info_s instance. + * + * Input Parameters: + * panel - Provides information about the connect LCD panel. + * fbinfo - Provides information about the pre-allocate framebuffer + * memory. + * + * Returned value: + * Zero (OK) is returned on success; a negated errno value is returned in + * the the case of a failure. + * + ****************************************************************************/ + +int am335x_lcd_initialize(FAR const struct am335x_panel_info_s *panel, + FAR const struct am335x_fbinfo_s *fbinfo); + +/**************************************************************************** + * Name: am335x_lcdclear + * + * Description: + * This is a non-standard LCD interface just for the AM335x. Clearing + * the display in the normal way by writing a sequences of runs that + * covers the entire display can be slow. Here the display is cleared by + * simply setting all VRAM memory to the specified color. + * + ****************************************************************************/ + +void am335x_lcdclear(nxgl_mxpixel_t color); + +/**************************************************************************** + * Name: am335x_lcd_videomode + * + * Description: + * If the video mod is known, then the board-specific logic may read the + * use this function to convert the video mode data to an instance of + * struct am335x_panel_info_s which then may be used to initialize the + * the LCD/ + * + * Input Parameters: + * videomode - A reference to the desired video mode. + * panel - A user provided location to receive the panel data. + * + * Returned value: + * None. Always succeeds. + * + ****************************************************************************/ + +struct edid_videomode_s; /* Forward reference */ + +void am335x_lcd_videomode(FAR const struct edid_videomode_s *videomode, + FAR struct am335x_panel_info_s *panel); + +/**************************************************************************** + * Name: am335x_lcd_edid + * + * Description: + * If there is access to Extended Display Identification Data (EDID), + * then the board-specific logic may read the EDID data and use this + * function to initialize an instance of struct am335x_panel_info_s. + * + * The returned video mode may optionally be returned to configure HDMI. + * + * Input Parameters: + * edid - A reference to the raw EDID data. + * len - The length of the EDID data in bytes + * panel - A user provided location to receive the panel data. + * selected - A user provided location to receive the selected video mode. + * fbinfo - Provides information about the pre-allocate framebuffer + * memory. + * + * Returned value: + * None. Always succeeds. The logic will fallback to VGA mode if no + * EDID data is provided or if there is no valid video mode in the EDID + * data. + * + ****************************************************************************/ + +void am335x_lcd_edid(FAR const uint8_t *edid, size_t edid_len, + FAR struct am335x_panel_info_s *panel, + FAR struct edid_videomode_s *selected, + FAR const struct am335x_fbinfo_s *fbinfo); + +/**************************************************************************** + * Name: am335x_backlight + * + * Description: + * If CONFIG_AM335X_LCDC_BACKLIGHT is defined, then the board-specific + * logic must provide this interface to turn the backlight on and off. + * + * REVISIT: Current assumes a discrete ON/OFF control. Needs additional + * support for backlight level control. + * + ****************************************************************************/ + +#ifdef CONFIG_AM335X_LCDC_BACKLIGHT +void am335x_backlight(bool blon); +#endif + +#endif /* __ARCH_ARM_SRC_AM335X_AM335X_LCDC_H */ diff --git a/arch/arm/src/am335x/hardware/am335x_lcd.h b/arch/arm/src/am335x/hardware/am335x_lcd.h index 5bab468140f..a3ef1736a05 100644 --- a/arch/arm/src/am335x/hardware/am335x_lcd.h +++ b/arch/arm/src/am335x/hardware/am335x_lcd.h @@ -175,8 +175,8 @@ #define LCD_RASTER_CTRL_REQDLY_MASK (255 << LCD_RASTER_CTRL_REQDLY_SHIFT) #define LCD_RASTER_CTRL_PALMODE_SHIFT (20) /* Bits 20-21: Palette Loading Mode */ #define LCD_RASTER_CTRL_PALMODE_MASK (3 << LCD_RASTER_CTRL_PALMODE_SHIFT) -# define LCD_RASTER_CTRL_PALLET_DATA (0 << LCD_RASTER_CTRL_PALMODE_SHIFT) /* Palette and data loading */ -# define LCD_RASTER_CTRL_PALLET (1 << LCD_RASTER_CTRL_PALMODE_SHIFT) /* Palette loading only */ +# define LCD_RASTER_CTRL_PALETTE_DATA (0 << LCD_RASTER_CTRL_PALMODE_SHIFT) /* Palette and data loading */ +# define LCD_RASTER_CTRL_PALETTE (1 << LCD_RASTER_CTRL_PALMODE_SHIFT) /* Palette loading only */ # define LCD_RASTER_CTRL_DATA (2 << LCD_RASTER_CTRL_PALMODE_SHIFT) /* Data loading only For Raw Data (12/16/24 bpp) framebuffers, no palette lookup is employed */ #define LCD_RASTER_CTRL_NIB_MODE (1 << 22) /* Bit 22: Nibble Mode */ #define LCD_RASTER_CTRL_TFT_MAP (1 << 23) /* Bit 23: TFT Mode Alternate Signal Mapping for Palettized framebuffer */