2acf8db3e1
Prevent startup screen flash by properly using AVR LCM functions. Power off LCD when not needed to improve battery runtime. Change-Id: I76e3c5c0208774f189fbc6f7d7b3c9e22c062285
342 lines
9 KiB
C
342 lines
9 KiB
C
/***************************************************************************
|
|
* __________ __ ___.
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
* \/ \/ \/ \/ \/
|
|
* $Id: $
|
|
*
|
|
* Copyright (C) 2011 by Tomasz Moń
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
* KIND, either express or implied.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include <sys/types.h>
|
|
#include "config.h"
|
|
#include "cpu.h"
|
|
#include "string.h"
|
|
#include "kernel.h"
|
|
#include "system.h"
|
|
#include "system-target.h"
|
|
#include "lcd.h"
|
|
#include "lcd-target.h"
|
|
#include "avr-sansaconnect.h"
|
|
#include "backlight-target.h"
|
|
|
|
/* See lcd-memframe.c */
|
|
extern void lcd_set_active(bool active);
|
|
|
|
static bool lcd_powered;
|
|
|
|
void lcd_sleep(void)
|
|
{
|
|
if (lcd_powered)
|
|
{
|
|
lcd_set_active(false);
|
|
|
|
avr_hid_lcm_power_off();
|
|
mdelay(100);
|
|
|
|
/* Disable OSD window */
|
|
bitclr16(&IO_OSD_OSDWINMD0, 0x01);
|
|
/* disable video encoder */
|
|
bitclr16(&IO_VID_ENC_VMOD, VENC_VMOD_VENC);
|
|
mdelay(66);
|
|
|
|
/* disable video encoder and OSD clocks */
|
|
bitclr16(&IO_CLK_MOD1, CLK_MOD1_VENC | CLK_MOD1_OSD);
|
|
|
|
lcd_powered = false;
|
|
}
|
|
}
|
|
|
|
void lcd_awake(void)
|
|
{
|
|
if (!lcd_powered)
|
|
{
|
|
/* Enable Video Encoder and OSD clocks */
|
|
bitset16(&IO_CLK_MOD1, CLK_MOD1_VENC | CLK_MOD1_OSD);
|
|
/* Enable OSD window */
|
|
bitset16(&IO_OSD_OSDWINMD0, 0x01);
|
|
/* Enable video encoder */
|
|
bitset16(&IO_VID_ENC_VMOD, VENC_VMOD_VENC);
|
|
|
|
avr_hid_lcm_power_on();
|
|
lcd_set_active(true);
|
|
avr_hid_lcm_wake();
|
|
|
|
lcd_powered = true;
|
|
send_event(LCD_EVENT_ACTIVATION, NULL);
|
|
}
|
|
}
|
|
|
|
void lcd_shutdown(void)
|
|
{
|
|
backlight_hw_off();
|
|
lcd_sleep();
|
|
}
|
|
|
|
void lcd_enable(bool enable)
|
|
{
|
|
if (lcd_active() == enable)
|
|
return;
|
|
|
|
lcd_set_active(enable);
|
|
|
|
if (enable)
|
|
{
|
|
/* Enable Video Encoder and OSD clocks */
|
|
bitset16(&IO_CLK_MOD1, CLK_MOD1_VENC | CLK_MOD1_OSD);
|
|
/* Enable OSD window */
|
|
bitset16(&IO_OSD_OSDWINMD0, 0x01);
|
|
/* Enable video encoder */
|
|
bitset16(&IO_VID_ENC_VMOD, VENC_VMOD_VENC);
|
|
|
|
avr_hid_lcm_wake();
|
|
mdelay(30);
|
|
|
|
send_event(LCD_EVENT_ACTIVATION, NULL);
|
|
}
|
|
else
|
|
{
|
|
mdelay(30);
|
|
avr_hid_lcm_sleep();
|
|
mdelay(10);
|
|
|
|
/* Disable OSD window */
|
|
bitclr16(&IO_OSD_OSDWINMD0, 0x01);
|
|
/* disable video encoder */
|
|
bitclr16(&IO_VID_ENC_VMOD, VENC_VMOD_VENC);
|
|
mdelay(66);
|
|
|
|
/* disable video encoder and OSD clocks */
|
|
bitclr16(&IO_CLK_MOD1, CLK_MOD1_VENC | CLK_MOD1_OSD);
|
|
}
|
|
}
|
|
|
|
void lcd_init_device(void)
|
|
{
|
|
unsigned int addr;
|
|
|
|
/* Disable Video Encoder clock */
|
|
bitclr16(&IO_CLK_MOD1, CLK_MOD1_VENC);
|
|
|
|
/* configure GIO39, GIO34 as outputs */
|
|
IO_GIO_DIR2 &= ~((1 << 7) /* GIO39 */ | (1 << 2) /* GIO34 */);
|
|
|
|
IO_GIO_FSEL3 = (IO_GIO_FSEL3 & ~(0x300F)) |
|
|
(0x1000) /* GIO39 - FIELD_VENC */ |
|
|
(0x4); /* GIO34 - PWM1 (brightness control) */
|
|
|
|
/* OSD Clock = VENC Clock /2,
|
|
CCD clock PCLK,
|
|
VENC Clock from PLLA */
|
|
IO_CLK_SEL1 = 0x3;
|
|
|
|
/* Set VENC Clock Division to 11
|
|
OF bootloader sets division to 8, vmlinux sets it to 11 */
|
|
IO_CLK_DIV3 = (IO_CLK_DIV3 & ~(0x1F00)) | 0xB00;
|
|
|
|
/* Enable OSD clock */
|
|
bitset16(&IO_CLK_MOD1, CLK_MOD1_OSD);
|
|
|
|
/* magic values based on OF bootloader initialization */
|
|
/* Set DAC to powerdown mode (bit 2 to 1 in VMOD) */
|
|
IO_VID_ENC_VMOD = 0x2014; /* OF sets 0x2010 */
|
|
IO_VID_ENC_VDPRO = 0x80;
|
|
IO_VID_ENC_HSPLS = 0x4;
|
|
IO_VID_ENC_HINT = 0x4B0;
|
|
IO_VID_ENC_HSTART = 0x88;
|
|
IO_VID_ENC_HVALID = 0x3C0;
|
|
IO_VID_ENC_HSDLY = 0;
|
|
IO_VID_ENC_VSPLS = 0x2;
|
|
IO_VID_ENC_VINT = 0x152;
|
|
IO_VID_ENC_VSTART = 0x6;
|
|
IO_VID_ENC_VVALID = 0x140;
|
|
IO_VID_ENC_VSDLY = 0;
|
|
IO_VID_ENC_DCLKCTL = 0x3;
|
|
IO_VID_ENC_DCLKPTN0 = 0xC;
|
|
IO_VID_ENC_VDCTL = 0x6000;
|
|
IO_VID_ENC_SYNCTL = 0x2;
|
|
IO_VID_ENC_LCDOUT = 0x101;
|
|
IO_VID_ENC_VMOD = 0x2015; /* OF sets 0x2011 */
|
|
|
|
/* Copy Rockbox frame buffer to the second framebuffer */
|
|
lcd_set_active(true);
|
|
lcd_update();
|
|
|
|
/* set framebuffer address - OF sets RAM start address to 0x1000000 */
|
|
addr = ((int)FRAME-CONFIG_SDRAM_START)/32;
|
|
|
|
IO_OSD_OSDWINADH = addr >> 16;
|
|
IO_OSD_OSDWIN0ADL = addr & 0xFFFF;
|
|
|
|
IO_OSD_BASEPX = 0x44;
|
|
IO_OSD_BASEPY = 0x6;
|
|
IO_OSD_OSDWIN0XP = 0;
|
|
IO_OSD_OSDWIN0YP = 0;
|
|
IO_OSD_OSDWIN0XL = LCD_WIDTH*2; /* OF bootloader sets 480 */
|
|
IO_OSD_OSDWIN0YL = LCD_HEIGHT; /* OF bootloader sets 320 */
|
|
IO_OSD_OSDWIN0OFST = 0xF;
|
|
IO_OSD_OSDWINMD0 = 0x25FB;/* OF bootloader sets 25C3,
|
|
vmlinux changes this to 0x25FB */
|
|
IO_OSD_VIDWINMD = 0; /* disable video windows (OF sets 0x03) */
|
|
|
|
IO_OSD_OSDWINMD1 = 0; /* disable OSD window 1 */
|
|
|
|
/* Enable Video Encoder and OSD clocks */
|
|
bitset16(&IO_CLK_MOD1, CLK_MOD1_VENC | CLK_MOD1_OSD);
|
|
|
|
/* Enable Video Encoder - RGB666, custom timing */
|
|
IO_VID_ENC_VMOD = 0x2015;
|
|
|
|
lcd_powered = true;
|
|
avr_hid_lcm_wake();
|
|
}
|
|
|
|
#ifdef LCD_USE_DMA
|
|
static void dma_lcd_copy_buffer_rect(int x, int y, int width, int height)
|
|
{
|
|
char *dst, *src;
|
|
|
|
/* Image buffer A is 4KW, every pixel is one Word */
|
|
/* lines is maximum number of lines we can transfer in single run */
|
|
int lines = 4096/width;
|
|
if (lines > height)
|
|
lines = height;
|
|
|
|
/* Set source and destination addresses */
|
|
dst = (char*)(FRAME + LCD_WIDTH*y + x);
|
|
src = (char*)(FBADDR(x,y));
|
|
|
|
/* Flush cache to memory */
|
|
commit_dcache();
|
|
|
|
/* Addresses are relative to start of SDRAM */
|
|
src -= CONFIG_SDRAM_START;
|
|
dst -= CONFIG_SDRAM_START;
|
|
|
|
/* Enable Image Buffer clock */
|
|
bitset16(&IO_CLK_MOD1, CLK_MOD1_IMGBUF);
|
|
|
|
/* Use Image Buffer A for DMA */
|
|
COP_BUF_MUX0 = (COP_BUF_MUX0 & 0xFFF0) | 0x0003;
|
|
|
|
/* Setup buffer offsets and transfer width/height */
|
|
COP_BUF_LOFST = width;
|
|
COP_DMA_XNUM = width;
|
|
COP_DMA_YNUM = lines;
|
|
|
|
/* DMA: No byte SWAP, no transformation, data bus shift down 0 bit */
|
|
COP_IMG_MODE &= 0xC0;
|
|
|
|
/* Set the start address of buffer */
|
|
COP_BUF_ADDR = 0x0000;
|
|
|
|
/* Setup SDRAM stride */
|
|
COP_SDEM_LOFST = LCD_WIDTH;
|
|
|
|
do {
|
|
int addr;
|
|
|
|
addr = (int)src;
|
|
addr >>= 1; /* Addresses are in 16-bit words */
|
|
|
|
/* Setup the registers to initiate the read from SDRAM */
|
|
COP_SDEM_ADDRH = addr >> 16;
|
|
COP_SDEM_ADDRL = addr & 0xFFFF;
|
|
|
|
/* Set direction and start */
|
|
COP_DMA_CTRL = 0x0001;
|
|
COP_DMA_CTRL |= 0x0002;
|
|
|
|
/* Wait for read to finish */
|
|
while (COP_DMA_CTRL & 0x02) {};
|
|
|
|
addr = (int)dst;
|
|
addr >>= 1;
|
|
|
|
COP_SDEM_ADDRH = addr >> 16;
|
|
COP_SDEM_ADDRL = addr & 0xFFFF;
|
|
|
|
/* Set direction and start transfer */
|
|
COP_DMA_CTRL = 0x0000;
|
|
COP_DMA_CTRL |= 0x0002;
|
|
|
|
/* Wait for the transfer to complete */
|
|
while (COP_DMA_CTRL & 0x02) {};
|
|
|
|
/* Decrease height, update pointers */
|
|
src += (LCD_WIDTH << 1)*lines;
|
|
dst += (LCD_WIDTH << 1)*lines;
|
|
|
|
height -= lines;
|
|
if (height < lines)
|
|
{
|
|
lines = height;
|
|
COP_DMA_YNUM = height;
|
|
}
|
|
} while (height > 0);
|
|
|
|
/* Disable Image Buffer clock */
|
|
bitclr16(&IO_CLK_MOD1, CLK_MOD1_IMGBUF);
|
|
}
|
|
|
|
/* Update a fraction of the display. */
|
|
void lcd_update_rect(int x, int y, int width, int height)
|
|
__attribute__ ((section(".icode")));
|
|
void lcd_update_rect(int x, int y, int width, int height)
|
|
{
|
|
if (!lcd_active())
|
|
return;
|
|
|
|
if ((width | height) < 0)
|
|
return; /* Nothing left to do */
|
|
|
|
if (x + width > LCD_WIDTH)
|
|
width = LCD_WIDTH - x; /* Clip right */
|
|
if (x < 0)
|
|
width += x, x = 0; /* Clip left */
|
|
|
|
if (y + height > LCD_HEIGHT)
|
|
height = LCD_HEIGHT - y; /* Clip bottom */
|
|
if (y < 0)
|
|
height += y, y = 0; /* Clip top */
|
|
|
|
dma_lcd_copy_buffer_rect(x, y, width, height);
|
|
}
|
|
|
|
/* Update the display.
|
|
This must be called after all other LCD functions that change the display. */
|
|
void lcd_update(void) __attribute__ ((section(".icode")));
|
|
void lcd_update(void)
|
|
{
|
|
if (!lcd_active())
|
|
return;
|
|
|
|
lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT);
|
|
}
|
|
#endif
|
|
|
|
void lcd_set_contrast(int val) {
|
|
(void) val;
|
|
// TODO:
|
|
}
|
|
|
|
void lcd_set_invert_display(bool yesno) {
|
|
(void) yesno;
|
|
// TODO:
|
|
}
|
|
|
|
void lcd_set_flip(bool yesno) {
|
|
(void) yesno;
|
|
// TODO:
|
|
}
|