/**************************************************************************** * arch/arm/src//lpc17xx/lpc17_lcd.c * * Copyright (C) 2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * 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 "up_arch.h" #include "chip/lpc17_syscon.h" #include "lpc17_gpio.h" #include "lpc17_lcd.h" /**************************************************************************** * Pre-Processor Definitions ****************************************************************************/ #define LPC17_LCD_CLK_PER_LINE (CONFIG_LPC17_LCD_HWIDTH + CONFIG_LPC17_LCD_HPULSE + CONFIG_LPC17_LCD_HFRONTPORCH + CONFIG_LPC17_LCD_HBACKPORCH) #define LPC17_LCD_LINES_PER_FRAME (CONFIG_LPC17_LCD_VHEIGHT + CONFIG_LPC17_LCD_VPULSE + CONFIG_LPC17_LCD_VFRONTPORCH + CONFIG_LPC17_LCD_VBACKPORCH) #define LPC17_LCD_PIXEL_CLOCK (LPC17_LCD_CLK_PER_LINE * LPC17_LCD_LINES_PER_FRAME * CONFIG_LPC17_LCD_REFRESH_FREQ) /* Framebuffer characteristics in bytes */ #if defined(CONFIG_LPC17_LCD_BPP1) # define LPC17_STRIDE ((CONFIG_LPC17_LCD_HWIDTH * 1 + 7) / 8) #elif defined(CONFIG_LPC17_LCD_BPP2) # define LPC17_STRIDE ((CONFIG_LPC17_LCD_HWIDTH * 2 + 7) / 8) #elif defined(CONFIG_LPC17_LCD_BPP4) # define LPC17_STRIDE ((CONFIG_LPC17_LCD_HWIDTH * 4 + 7) / 8) #elif defined(CONFIG_LPC17_LCD_BPP8) # define LPC17_STRIDE ((CONFIG_LPC17_LCD_HWIDTH * 8 + 7) / 8) #elif defined(CONFIG_LPC17_LCD_BPP16) # define LPC17_STRIDE ((CONFIG_LPC17_LCD_HWIDTH * 16 + 7) / 8) #elif defined(CONFIG_LPC17_LCD_BPP24) # define LPC17_STRIDE ((CONFIG_LPC17_LCD_HWIDTH * 32 + 7) / 8) #elif defined(CONFIG_LPC17_LCD_BPP16_565) # define LPC17_STRIDE ((CONFIG_LPC17_LCD_HWIDTH * 16 + 7) / 8) #else /* defined(CONFIG_LPC17_LCD_BPP12_444) */ # define LPC17_STRIDE ((CONFIG_LPC17_LCD_HWIDTH * 16 + 7) / 8) #endif #define LPC17_FBSIZE (LPC17_STRIDE * CONFIG_LPC17_LCD_VHEIGHT) /* Delays */ #define LPC17_LCD_PWRDIS_DELAY 10000 #define LPC17_LCD_PWREN_DELAY 10000 /**************************************************************************** * Private Types ****************************************************************************/ /**************************************************************************** * Private Function Prototypes ****************************************************************************/ /* Get information about the video controller configuration and the * configuration of each color plane. */ static int lpc17_getvideoinfo(FAR struct fb_vtable_s *vtable, FAR struct fb_videoinfo_s *vinfo); static int lpc17_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 lpc17_getcmap(FAR struct fb_vtable_s *vtable, FAR struct fb_cmap_s *cmap); static int lpc17_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 lpc17_getcursor(FAR struct fb_vtable_s *vtable, FAR struct fb_cursorattrib_s *attrib); static int lpc17_setcursor(FAR struct fb_vtable_s *vtable, FAR struct fb_setcursor_s *setttings); #endif /**************************************************************************** * Private Data ****************************************************************************/ /* This structure describes the simulated video controller */ static const struct fb_videoinfo_s g_videoinfo = { .fmt = LPC17_COLOR_FMT, .xres = CONFIG_LPC17_LCD_HWIDTH, .yres = CONFIG_LPC17_LCD_VHEIGHT, .nplanes = 1, }; /* This structure describes the single, simulated color plane */ static const struct fb_planeinfo_s g_planeinfo = { .fbmem = (FAR void *)CONFIG_LPC17_LCD_VRAMBASE, .fblen = LPC17_FBSIZE, .stride = LPC17_STRIDE, .bpp = LPC17_BPP, }; /* Current cursor position */ #ifdef CONFIG_FB_HWCURSOR static struct fb_cursorpos_s g_cpos; /* Current cursor size */ #ifdef CONFIG_FB_HWCURSORSIZE static struct fb_cursorsize_s g_csize; #endif #endif /* The framebuffer object -- There is no private state information in this simple * framebuffer simulation. */ struct fb_vtable_s g_fbobject = { .getvideoinfo = lpc17_getvideoinfo, .getplaneinfo = lpc17_getplaneinfo, #ifdef CONFIG_FB_CMAP .getcmap = lpc17_getcmap, .putcmap = lpc17_putcmap, #endif #ifdef CONFIG_FB_HWCURSOR .getcursor = lpc17_getcursor, .setcursor = lpc17_setcursor, #endif }; /**************************************************************************** * Public Data ****************************************************************************/ /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: lpc17_getvideoinfo ****************************************************************************/ static int lpc17_getvideoinfo(FAR struct fb_vtable_s *vtable, FAR struct fb_videoinfo_s *vinfo) { dbg("vtable=%p vinfo=%p\n", vtable, vinfo); if (vtable && vinfo) { memcpy(vinfo, &g_videoinfo, sizeof(struct fb_videoinfo_s)); return OK; } dbg("Returning EINVAL\n"); return -EINVAL; } /**************************************************************************** * Name: lpc17_getplaneinfo ****************************************************************************/ static int lpc17_getplaneinfo(FAR struct fb_vtable_s *vtable, int planeno, FAR struct fb_planeinfo_s *pinfo) { dbg("vtable=%p planeno=%d pinfo=%p\n", vtable, planeno, pinfo); if (vtable && planeno == 0 && pinfo) { memcpy(pinfo, &g_planeinfo, sizeof(struct fb_planeinfo_s)); return OK; } dbg("Returning EINVAL\n"); return -EINVAL; } /**************************************************************************** * Name: lpc17_getcmap ****************************************************************************/ #ifdef CONFIG_FB_CMAP static int lpc17_getcmap(FAR struct fb_vtable_s *vtable, FAR struct fb_cmap_s *cmap) { uint32_t *pal; uint32_t rgb; int last; int i; dbg("vtable=%p cmap=%p first=%d len=%d\n", vtable, cmap, cmap->first, cmap->len); DEBUGASSERT(vtable && cmap && cmap->first < 256 && (cmap->first + cmap->len) < 256); pal = (uint32_t *)LPC17_LCD_PAL(cmap->first >> 1); last = cmap->first + cmap->len; /* Handle the case where the first color starts on an odd boundary */ i = cmap->first; if ((i & 1) != 0) { rgb = *pal++; i++; /* Save the odd palette value */ cmap->red[i] = (rgb & LCD_PAL_R1_MASK) >> LCD_PAL_R1_SHIFT; cmap->green[i] = (rgb & LCD_PAL_G1_MASK) >> LCD_PAL_G1_SHIFT; cmap->blue[i] = (rgb & LCD_PAL_B1_MASK) >> LCD_PAL_B1_SHIFT; #ifdef CONFIG_FB_TRANSPARENCY cmap->transp[i] = 0; #endif } /* Handle even colors */ for (; i < last; i += 2) { rgb = *pal++; /* Save the even palette value */ cmap->red[i] = (rgb & LCD_PAL_R0_MASK) >> LCD_PAL_R0_SHIFT; cmap->green[i] = (rgb & LCD_PAL_G0_MASK) >> LCD_PAL_G0_SHIFT; cmap->blue[i] = (rgb & LCD_PAL_B0_MASK) >> LCD_PAL_B0_SHIFT; #ifdef CONFIG_FB_TRANSPARENCY cmap->transp[i] = 0; #endif /* Handle the case where the len ends on an odd boudary */ if ((i + 1) < last) { /* Save the even palette value */ cmap->red[i+1] = (rgb & LCD_PAL_R1_MASK) >> LCD_PAL_R1_SHIFT; cmap->green[i+1] = (rgb & LCD_PAL_G1_MASK) >> LCD_PAL_G1_SHIFT; cmap->blue[i+1] = (rgb & LCD_PAL_B1_MASK) >> LCD_PAL_B1_SHIFT; #ifdef CONFIG_FB_TRANSPARENCY cmap->transp[i+1] = 0; #endif } } return OK; } #endif /**************************************************************************** * Name: lpc17_putcmap ****************************************************************************/ #ifdef CONFIG_FB_CMAP static int lpc17_putcmap(FAR struct fb_vtable_s *vtable, FAR const struct fb_cmap_s *cmap) { uint32_t *pal; uint32_t rgb0; uint32_t rgb1; int last; int i; dbg("vtable=%p cmap=%p first=%d len=%d\n", vtable, cmap, cmap->first, cmap->len); DEBUGASSERT(vtable && cmap); pal = (uint32_t *)LPC17_LCD_PAL(cmap->first >> 1); last = cmap->first + cmap->len; /* Handle the case where the first color starts on an odd boundary */ i = cmap->first; if ((i & 1) != 0) { rgb0 = *pal; rgb0 &= (LCD_PAL_R0_MASK | LCD_PAL_G0_MASK | LCD_PAL_B0_MASK | LCD_PAL_I0); rgb1 |= ((uint32_t)cmap->red[i] << LCD_PAL_R0_SHIFT | (uint32_t)cmap->green[i] << LCD_PAL_G0_SHIFT | (uint32_t)cmap->blue[i] << LCD_PAL_B0_SHIFT); /* Save the new palette value */ *pal++ = (rgb0 | rgb1); i++; } /* Handle even colors */ for (; i < last; i += 2) { uint32_t rgb0 = ((uint32_t)cmap->red[i] << LCD_PAL_R0_SHIFT | (uint32_t)cmap->green[i] << LCD_PAL_G0_SHIFT | (uint32_t)cmap->blue[i] << LCD_PAL_B0_SHIFT); /* Handle the case where the len ends on an odd boudary */ if ((i + 1) >= last) { rgb1 = *pal; rgb1 &= (LCD_PAL_R1_MASK | LCD_PAL_G1_MASK | LCD_PAL_B1_MASK | LCD_PAL_I1); } else { rgb1 = ((uint32_t)cmap->red[i+1] << LCD_PAL_R1_SHIFT | (uint32_t)cmap->green[i+1] << LCD_PAL_G1_SHIFT | (uint32_t)cmap->blue[i+1] << LCD_PAL_B1_SHIFT); } /* Save the new pallete value */ *pal++ = (rgb0 | rgb1); } return OK; } #endif /**************************************************************************** * Name: lpc17_getcursor ****************************************************************************/ #ifdef CONFIG_FB_HWCURSOR static int lpc17_getcursor(FAR struct fb_vtable_s *vtable, FAR struct fb_cursorattrib_s *attrib) { dbg("vtable=%p attrib=%p\n", vtable, attrib); if (vtable && attrib) { #ifdef CONFIG_FB_HWCURSORIMAGE attrib->fmt = LPC17_COLOR_FMT; #endif dbg("pos: (x=%d, y=%d)\n", g_cpos.x, g_cpos.y); attrib->pos = g_cpos; #ifdef CONFIG_FB_HWCURSORSIZE attrib->mxsize.h = CONFIG_LPC17_LCD_VHEIGHT; attrib->mxsize.w = CONFIG_LPC17_LCD_HWIDTH; dbg("size: (h=%d, w=%d)\n", g_csize.h, g_csize.w); attrib->size = g_csize; #endif return OK; } dbg("Returning EINVAL\n"); return -EINVAL; } #endif /**************************************************************************** * Name: lpc17_setcursor ****************************************************************************/ #ifdef CONFIG_FB_HWCURSOR static int lpc17_setcursor(FAR struct fb_vtable_s *vtable, FAR struct fb_setcursor_s *setttings) { dbg("vtable=%p setttings=%p\n", vtable, setttings); if (vtable && setttings) { dbg("flags: %02x\n", settings->flags); if ((flags & FB_CUR_SETPOSITION) != 0) { g_cpos = settings->pos; dbg("pos: (h:%d, w:%d)\n", g_cpos.x, g_cpos.y); } #ifdef CONFIG_FB_HWCURSORSIZE if ((flags & FB_CUR_SETSIZE) != 0) { g_csize = settings->size; dbg("size: (h:%d, w:%d)\n", g_csize.h, g_csize.w); } #endif #ifdef CONFIG_FB_HWCURSORIMAGE if ((flags & FB_CUR_SETIMAGE) != 0) { dbg("image: (h:%d, w:%d) @ %p\n", settings->img.height, settings->img.width, settings->img.image); } #endif return OK; } dbg("Returning EINVAL\n"); return -EINVAL; } #endif /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: lpc17_fbinitialize * * Description: * Initialize the framebuffer video hardware * ****************************************************************************/ int up_fbinitialize(void) { uint32_t regval; int i; /* Disable LCD controller */ regval = getreg32(LPC17_LCD_CTRL); regval &= ~LCD_CTRL_LCDPWR; putreg32(regval, LPC17_LCD_CTRL); for (i = LPC17_LCD_PWRDIS_DELAY; i; i--); regval &= ~LCD_CTRL_LCDEN; putreg32(regval, LPC17_LCD_CTRL); /* Configure pins */ /* Video data */ lpc17_configgpio(GPIO_LCD_VD0); lpc17_configgpio(GPIO_LCD_VD1); lpc17_configgpio(GPIO_LCD_VD2); lpc17_configgpio(GPIO_LCD_VD3); lpc17_configgpio(GPIO_LCD_VD4); lpc17_configgpio(GPIO_LCD_VD5); lpc17_configgpio(GPIO_LCD_VD6); lpc17_configgpio(GPIO_LCD_VD7); lpc17_configgpio(GPIO_LCD_VD8); lpc17_configgpio(GPIO_LCD_VD9); lpc17_configgpio(GPIO_LCD_VD10); lpc17_configgpio(GPIO_LCD_VD11); lpc17_configgpio(GPIO_LCD_VD12); lpc17_configgpio(GPIO_LCD_VD13); lpc17_configgpio(GPIO_LCD_VD14); lpc17_configgpio(GPIO_LCD_VD15); #if LPC17_BPP > 16 lpc17_configgpio(GPIO_LCD_VD16); lpc17_configgpio(GPIO_LCD_VD17); lpc17_configgpio(GPIO_LCD_VD18); lpc17_configgpio(GPIO_LCD_VD19); lpc17_configgpio(GPIO_LCD_VD20); lpc17_configgpio(GPIO_LCD_VD21); lpc17_configgpio(GPIO_LCD_VD22); lpc17_configgpio(GPIO_LCD_VD23); #endif /* Other pins */ lpc17_configgpio(GPIO_LCD_DCLK); lpc17_configgpio(GPIO_LCD_LP); lpc17_configgpio(GPIO_LCD_FP); lpc17_configgpio(GPIO_LCD_ENABM); lpc17_configgpio(GPIO_LCD_PWR); /* Turn on LCD clock */ regval = getreg32(LPC17_SYSCON_PCONP); regval |= SYSCON_PCONP_PCLCD; putreg32(regval, LPC17_SYSCON_PCONP); /* Disable the cursor */ regval = getreg32(LPC17_LCD_CRSR_CRTL); regval &= ~LCD_CRSR_CTRL_CRSON; putreg32(regval, LPC17_LCD_CRSR_CRTL); /* Disable GLCD controller */ putreg32(0, LPC17_LCD_CTRL); /* Set the bits per pixel */ regval = getreg32(LPC17_LCD_CTRL); regval &= ~LCD_CTRL_LCDBPP_MASK; #if defined(CONFIG_LPC17_LCD_BPP1) regval |= LCD_CTRL_LCDBPP_1; /* 1 bpp */ #elif defined(CONFIG_LPC17_LCD_BPP2) regval |= LCD_CTRL_LCDBPP_2; /* 2 bpp */ #elif defined(CONFIG_LPC17_LCD_BPP4) regval |= LCD_CTRL_LCDBPP_4; /* 4 bpp */ #elif defined(CONFIG_LPC17_LCD_BPP8) regval |= LCD_CTRL_LCDBPP_8; /* 8 bpp */ #elif defined(CONFIG_LPC17_LCD_BPP16) regval |= LCD_CTRL_LCDBPP_16; /* 16 bpp */ #elif defined(CONFIG_LPC17_LCD_BPP24) regval |= LCD_CTRL_LCDBPP_24; /* 24-bit TFT panel only */ #elif defined(CONFIG_LPC17_LCD_BPP16_565) regval |= LCD_CTRL_LCDBPP_565; /* 16 bpp, 5:6:5 mode */ #else /* defined(CONFIG_LPC17_LCD_BPP12_444) */ regval |= LCD_CTRL_LCDBPP_444; /* 12 bpp, 4:4:4 mode */ #endif putreg32(regval, LPC17_LCD_CTRL); /* TFT panel */ #if CONFIG_LPC17_LCD_TFTPANEL regval |= LCD_CTRL_LCDTFT; putreg32(regval, LPC17_LCD_CTRL); #endif /* Single panel */ regval &= ~LCD_CTRL_LCDDUAL; putreg32(regval, LPC17_LCD_CTRL); /* Normal RGB output */ regval &= ~LCD_CTRL_BGR; putreg32(regval, LPC17_LCD_CTRL); /* Little endian byte order */ regval &= ~LCD_CTRL_BEBO; putreg32(regval, LPC17_LCD_CTRL); /* Little endian pixel order */ regval &= ~LCD_CTRL_BEPO; putreg32(regval, LPC17_LCD_CTRL); /* Disable power */ regval &= ~LCD_CTRL_LCDPWR; putreg32(regval, LPC17_LCD_CTRL); /* Initialize pixel clock (assuming clock source is CCLK) */ putreg32(LPC17_CCLK / LPC17_LCD_PIXEL_CLOCK, LPC17_SYSCON_LCDCFG); /* Bypass internal pixel clock divider */ regval = getreg32(LPC17_LCD_POL); regval |= LCD_POL_BCD; putreg32(regval, LPC17_LCD_POL); /* Select the CCLK for the LCD block clock source */ regval &= ~LCD_POL_CLKSEL; putreg32(regval, LPC17_LCD_POL); /* LCDFP pin is active LOW and inactive HIGH */ regval |= LCD_POL_IVS; putreg32(regval, LPC17_LCD_POL); /* LCDLP pin is active LOW and inactive HIGH */ regval |= LCD_POL_IHS; putreg32(regval, LPC17_LCD_POL); /* Data is driven out into the LCD on the falling edge */ regval &= ~LCD_POL_IPC; putreg32(regval, LPC17_LCD_POL); /* Active high */ regval &= ~LCD_POL_IOE; putreg32(regval, LPC17_LCD_POL); regval &= ~LCD_POL_CPL_MASK; regval |= (CONFIG_LPC17_LCD_HWIDTH-1) << LCD_POL_CPL_SHIFT; putreg32(regval, LPC17_LCD_POL); /* Initialize horizontal timing */ putreg32(0, LPC17_LCD_TIMH); regval = (((CONFIG_LPC17_LCD_HWIDTH/16) - 1) << LCD_TIMH_PPL_SHIFT | (CONFIG_LPC17_LCD_HPULSE - 1) << LCD_TIMH_HSW_SHIFT | (CONFIG_LPC17_LCD_HFRONTPORCH - 1) << LCD_TIMH_HFP_SHIFT | (CONFIG_LPC17_LCD_HBACKPORCH - 1) << LCD_TIMH_HBP_SHIFT); putreg32(regval, LPC17_LCD_TIMH); /* Initialize vertical timing */ putreg32(0, LPC17_LCD_TIMV); regval = ((CONFIG_LPC17_LCD_VHEIGHT - 1) << LCD_TIMV_LPP_SHIFT | (CONFIG_LPC17_LCD_VPULSE - 1) << LCD_TIMV_VSW_SHIFT | (CONFIG_LPC17_LCD_VFRONTPORCH) << LCD_TIMV_VFP_SHIFT | (CONFIG_LPC17_LCD_VBACKPORCH) << LCD_TIMV_VBP_SHIFT); /* Frame base address doubleword aligned */ putreg32(CONFIG_LPC17_LCD_VRAMBASE & ~7, LPC17_LCD_UPBASE); putreg32(CONFIG_LPC17_LCD_VRAMBASE & ~7, LPC17_LCD_LPBASE); /* Clear the display */ lpc17_lcdclear(CONFIG_LPC17_LCD_BACKCOLOR); for (i = LPC17_LCD_PWREN_DELAY; i; i--); /* Enable LCD */ regval = getreg32(LPC17_LCD_CTRL); regval |= LCD_CTRL_LCDEN; putreg32(regval, LPC17_LCD_CTRL); for (i = LPC17_LCD_PWREN_DELAY; i; i--); regval |= LCD_CTRL_LCDPWR; putreg32(regval, LPC17_LCD_CTRL); return OK; } /**************************************************************************** * Name: lpc17_fbgetvplane * * Description: * Return a a reference to the framebuffer object for the specified video * plane. * * Input parameters: * None * * Returned value: * Reference to the framebuffer object (NULL on failure) * ***************************************************************************/ FAR struct fb_vtable_s *up_fbgetvplane(int vplane) { if (vplane == 0) { return &g_fbobject; } else { return NULL; } } /**************************************************************************** * Name: lpc17_fbinitialize * * Description: * Unitialize the framebuffer support * ****************************************************************************/ void fb_uninitialize(void) { return OK; } /************************************************************************************ * Name: lpc17_lcdclear * * Description: * This is a non-standard LCD interface just for the LPC17xx. Clearing the display * in the normal way by writing a sequences of runs that covers the entire display * can be slow. Here the dispaly is cleared by simply setting all VRAM memory to * the specified color. * ************************************************************************************/ void lpc17_lcdclear(nxgl_mxpixel_t color) { #if LPC17_BPP > 16 uint32_t *dest; #else uint16_t *dest; #endif int i; dest = (uint32_t *) CONFIG_LPC17_LCD_VRAMBASE; for (i = 0; (CONFIG_LPC17_LCD_HWIDTH * CONFIG_LPC17_LCD_VHEIGHT) > i; i++) { *dest++ = color; } }