b37e6bc8c1
Change all lcd drivers to using a pointer to the static framebuffer instead of directly accessing the static array. This will let us later do fun things like dynamic framebuffer sizes (RaaA) or ability to use different buffers for different layers (dynamic skin backdrops!) Change-Id: I0a4d58a9d7b55e6c932131b929e5d4c9f9414b06
351 lines
10 KiB
C
351 lines
10 KiB
C
/***************************************************************************
|
|
* __________ __ ___.
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
* \/ \/ \/ \/ \/
|
|
* $Id$
|
|
*
|
|
* Copyright (C) 2005 by Richard S. La Charité III
|
|
*
|
|
* 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 "config.h"
|
|
#include "system.h"
|
|
#include "file.h"
|
|
#include "lcd-remote.h"
|
|
#include "adc.h"
|
|
#include "scroll_engine.h"
|
|
|
|
/*** definitions ***/
|
|
|
|
#define LCD_REMOTE_CNTL_ADC_NORMAL 0xa0
|
|
#define LCD_REMOTE_CNTL_ADC_REVERSE 0xa1
|
|
#define LCD_REMOTE_CNTL_SHL_NORMAL 0xc0
|
|
#define LCD_REMOTE_CNTL_SHL_REVERSE 0xc8
|
|
#define LCD_REMOTE_CNTL_DISPLAY_ON_OFF 0xae
|
|
#define LCD_REMOTE_CNTL_ENTIRE_ON_OFF 0xa4
|
|
#define LCD_REMOTE_CNTL_REVERSE_ON_OFF 0xa6
|
|
#define LCD_REMOTE_CNTL_NOP 0xe3
|
|
#define LCD_REMOTE_CNTL_POWER_CONTROL 0x2b
|
|
#define LCD_REMOTE_CNTL_SELECT_REGULATOR 0x20
|
|
#define LCD_REMOTE_CNTL_SELECT_BIAS 0xa2
|
|
#define LCD_REMOTE_CNTL_SELECT_VOLTAGE 0x81
|
|
#define LCD_REMOTE_CNTL_INIT_LINE 0x40
|
|
#define LCD_REMOTE_CNTL_SET_PAGE_ADDRESS 0xB0
|
|
|
|
#define LCD_REMOTE_CNTL_HIGHCOL 0x10 /* Upper column address */
|
|
#define LCD_REMOTE_CNTL_LOWCOL 0x00 /* Lower column address */
|
|
|
|
#define CS_LO and_l(~0x00000004, &GPIO1_OUT)
|
|
#define CS_HI or_l(0x00000004, &GPIO1_OUT)
|
|
#define CLK_LO and_l(~0x10000000, &GPIO_OUT)
|
|
#define CLK_HI or_l(0x10000000, &GPIO_OUT)
|
|
#define DATA_LO and_l(~0x00040000, &GPIO1_OUT)
|
|
#define DATA_HI or_l(0x00040000, &GPIO1_OUT)
|
|
#define RS_LO and_l(~0x00010000, &GPIO_OUT)
|
|
#define RS_HI or_l(0x00010000, &GPIO_OUT)
|
|
|
|
static int xoffset; /* needed for flip */
|
|
|
|
/* timeout counter for deasserting /CS after access, <0 means not counting */
|
|
int remote_cs_countdown IDATA_ATTR = 0;
|
|
#define CS_TIMEOUT (HZ/10)
|
|
|
|
#ifdef HAVE_REMOTE_LCD_TICKING
|
|
/* If set to true, will prevent "ticking" to headphones. */
|
|
static bool emireduce = false;
|
|
int remote_byte_delay = 0; /* used in lcd-remote-as-iriver.S */
|
|
#endif
|
|
|
|
bool remote_initialized = false;
|
|
static int _remote_type = REMOTETYPE_UNPLUGGED;
|
|
|
|
/* cached settings values */
|
|
static bool cached_invert = false;
|
|
static bool cached_flip = false;
|
|
static int cached_contrast = DEFAULT_REMOTE_CONTRAST_SETTING;
|
|
|
|
|
|
/*** hardware configuration ***/
|
|
|
|
int lcd_remote_default_contrast(void)
|
|
{
|
|
return DEFAULT_REMOTE_CONTRAST_SETTING;
|
|
}
|
|
|
|
#ifdef HAVE_REMOTE_LCD_TICKING
|
|
void lcd_remote_emireduce(bool state)
|
|
{
|
|
emireduce = state;
|
|
}
|
|
#endif
|
|
|
|
#if 0 // FIXME
|
|
void lcd_remote_powersave(bool on)
|
|
{
|
|
if (remote_initialized)
|
|
{
|
|
lcd_remote_write_command(LCD_REMOTE_CNTL_DISPLAY_ON_OFF | (on ? 0 : 1));
|
|
lcd_remote_write_command(LCD_REMOTE_CNTL_ENTIRE_ON_OFF | (on ? 1 : 0));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void lcd_remote_set_contrast(int val)
|
|
{
|
|
cached_contrast = val;
|
|
if (remote_initialized)
|
|
lcd_remote_write_command_ex(LCD_REMOTE_CNTL_SELECT_VOLTAGE, val);
|
|
}
|
|
|
|
void lcd_remote_set_invert_display(bool yesno)
|
|
{
|
|
cached_invert = yesno;
|
|
if (remote_initialized)
|
|
lcd_remote_write_command(LCD_REMOTE_CNTL_REVERSE_ON_OFF | (yesno?1:0));
|
|
}
|
|
|
|
/* turn the display upside down (call lcd_remote_update() afterwards) */
|
|
void lcd_remote_set_flip(bool yesno)
|
|
{
|
|
cached_flip = yesno;
|
|
if (yesno)
|
|
{
|
|
xoffset = 0;
|
|
if (remote_initialized)
|
|
{
|
|
lcd_remote_write_command(LCD_REMOTE_CNTL_ADC_NORMAL);
|
|
lcd_remote_write_command(LCD_REMOTE_CNTL_SHL_NORMAL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
xoffset = 132 - LCD_REMOTE_WIDTH;
|
|
if (remote_initialized)
|
|
{
|
|
lcd_remote_write_command(LCD_REMOTE_CNTL_ADC_REVERSE);
|
|
lcd_remote_write_command(LCD_REMOTE_CNTL_SHL_REVERSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool remote_detect(void)
|
|
{
|
|
return (GPIO_READ & 0x40000000)?false:true;
|
|
}
|
|
|
|
int remote_type(void)
|
|
{
|
|
return _remote_type;
|
|
}
|
|
|
|
void lcd_remote_on(void)
|
|
{
|
|
CS_HI;
|
|
CLK_LO;
|
|
lcd_remote_write_command(LCD_REMOTE_CNTL_SELECT_BIAS | 0x0);
|
|
|
|
lcd_remote_write_command(LCD_REMOTE_CNTL_POWER_CONTROL | 0x5);
|
|
sleep(1);
|
|
lcd_remote_write_command(LCD_REMOTE_CNTL_POWER_CONTROL | 0x6);
|
|
sleep(1);
|
|
lcd_remote_write_command(LCD_REMOTE_CNTL_POWER_CONTROL | 0x7);
|
|
|
|
lcd_remote_write_command(LCD_REMOTE_CNTL_SELECT_REGULATOR | 0x4); // 0x4 Select regulator @ 5.0 (default);
|
|
|
|
sleep(1);
|
|
|
|
lcd_remote_write_command(LCD_REMOTE_CNTL_INIT_LINE | 0x0); // init line
|
|
lcd_remote_write_command(LCD_REMOTE_CNTL_SET_PAGE_ADDRESS | 0x0); // page address
|
|
lcd_remote_write_command_ex(0x10, 0x00); // Column MSB + LSB
|
|
|
|
lcd_remote_write_command(LCD_REMOTE_CNTL_DISPLAY_ON_OFF | 1);
|
|
|
|
remote_initialized = true;
|
|
|
|
lcd_remote_set_flip(cached_flip);
|
|
lcd_remote_set_contrast(cached_contrast);
|
|
lcd_remote_set_invert_display(cached_invert);
|
|
}
|
|
|
|
void lcd_remote_off(void)
|
|
{
|
|
remote_initialized = false;
|
|
CLK_LO;
|
|
CS_HI;
|
|
}
|
|
|
|
#ifndef BOOTLOADER
|
|
/* Monitor remote hotswap */
|
|
static void remote_tick(void)
|
|
{
|
|
static bool last_status = false;
|
|
static int countdown = 0;
|
|
static int init_delay = 0;
|
|
bool current_status;
|
|
int val;
|
|
int level;
|
|
|
|
current_status = remote_detect();
|
|
/* Only report when the status has changed */
|
|
if (current_status != last_status)
|
|
{
|
|
last_status = current_status;
|
|
countdown = current_status ? 20*HZ : 1;
|
|
}
|
|
else
|
|
{
|
|
/* Count down until it gets negative */
|
|
if (countdown >= 0)
|
|
countdown--;
|
|
|
|
if (current_status)
|
|
{
|
|
if (!(countdown % 8))
|
|
{
|
|
/* Determine which type of remote it is */
|
|
level = disable_irq_save();
|
|
val = adc_scan(ADC_REMOTEDETECT);
|
|
restore_irq(level);
|
|
|
|
if (val < ADCVAL_H100_LCD_REMOTE_HOLD)
|
|
{
|
|
if (val < ADCVAL_H100_LCD_REMOTE)
|
|
if (val < ADCVAL_H300_LCD_REMOTE)
|
|
_remote_type = REMOTETYPE_H300_LCD; /* hold off */
|
|
else
|
|
_remote_type = REMOTETYPE_H100_LCD; /* hold off */
|
|
else
|
|
if (val < ADCVAL_H300_LCD_REMOTE_HOLD)
|
|
_remote_type = REMOTETYPE_H300_LCD; /* hold on */
|
|
else
|
|
_remote_type = REMOTETYPE_H100_LCD; /* hold on */
|
|
|
|
if (--init_delay <= 0)
|
|
{
|
|
queue_broadcast(SYS_REMOTE_PLUGGED, 0);
|
|
init_delay = 6;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_remote_type = REMOTETYPE_H300_NONLCD; /* hold on or off */
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (countdown == 0)
|
|
{
|
|
_remote_type = REMOTETYPE_UNPLUGGED;
|
|
|
|
queue_broadcast(SYS_REMOTE_UNPLUGGED, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* handle chip select timeout */
|
|
if (remote_cs_countdown >= 0)
|
|
remote_cs_countdown--;
|
|
if (remote_cs_countdown == 0)
|
|
CS_HI;
|
|
}
|
|
#endif
|
|
|
|
void lcd_remote_init_device(void)
|
|
{
|
|
#ifdef IRIVER_H300_SERIES
|
|
or_l(0x10010000, &GPIO_FUNCTION); /* GPIO16: RS
|
|
GPIO28: CLK */
|
|
|
|
or_l(0x00040006, &GPIO1_FUNCTION); /* GPO33: Backlight
|
|
GPIO34: CS
|
|
GPIO50: Data */
|
|
or_l(0x10010000, &GPIO_ENABLE);
|
|
or_l(0x00040006, &GPIO1_ENABLE);
|
|
#else
|
|
or_l(0x10010800, &GPIO_FUNCTION); /* GPIO11: Backlight
|
|
GPIO16: RS
|
|
GPIO28: CLK */
|
|
|
|
or_l(0x00040004, &GPIO1_FUNCTION); /* GPIO34: CS
|
|
GPIO50: Data */
|
|
or_l(0x10010800, &GPIO_ENABLE);
|
|
or_l(0x00040004, &GPIO1_ENABLE);
|
|
#endif
|
|
|
|
lcd_remote_clear_display();
|
|
if (remote_detect())
|
|
lcd_remote_on();
|
|
#ifndef BOOTLOADER
|
|
tick_add_task(remote_tick);
|
|
#endif
|
|
}
|
|
|
|
/* Update the display.
|
|
This must be called after all other LCD functions that change the display. */
|
|
void lcd_remote_update(void)
|
|
{
|
|
int y;
|
|
|
|
if (!remote_initialized)
|
|
return;
|
|
|
|
#ifdef HAVE_REMOTE_LCD_TICKING
|
|
/* Adjust byte delay for emi reduction. */
|
|
remote_byte_delay = emireduce ? cpu_frequency / 206200 - 85: 0;
|
|
#endif
|
|
|
|
/* Copy display bitmap to hardware */
|
|
for (y = 0; y < LCD_REMOTE_FBHEIGHT; y++)
|
|
{
|
|
lcd_remote_write_command(LCD_REMOTE_CNTL_SET_PAGE_ADDRESS | y);
|
|
lcd_remote_write_command(LCD_REMOTE_CNTL_HIGHCOL | ((xoffset >> 4) & 0xf));
|
|
lcd_remote_write_command(LCD_REMOTE_CNTL_LOWCOL | (xoffset & 0xf));
|
|
lcd_remote_write_data(FBREMOTEADDR(0, y), LCD_REMOTE_WIDTH);
|
|
}
|
|
}
|
|
|
|
/* Update a fraction of the display. */
|
|
void lcd_remote_update_rect(int x, int y, int width, int height)
|
|
{
|
|
int ymax;
|
|
|
|
if (!remote_initialized)
|
|
return;
|
|
|
|
/* The Y coordinates have to work on even 8 pixel rows */
|
|
ymax = (y + height-1) >> 3;
|
|
y >>= 3;
|
|
|
|
if(x + width > LCD_REMOTE_WIDTH)
|
|
width = LCD_REMOTE_WIDTH - x;
|
|
if (width <= 0)
|
|
return; /* nothing left to do, 0 is harmful to lcd_write_data() */
|
|
if(ymax >= LCD_REMOTE_FBHEIGHT)
|
|
ymax = LCD_REMOTE_FBHEIGHT-1;
|
|
|
|
#ifdef HAVE_REMOTE_LCD_TICKING
|
|
/* Adjust byte delay for emi reduction */
|
|
remote_byte_delay = emireduce ? cpu_frequency / 206200 - 85: 0;
|
|
#endif
|
|
|
|
/* Copy specified rectange bitmap to hardware */
|
|
for (; y <= ymax; y++)
|
|
{
|
|
lcd_remote_write_command(LCD_REMOTE_CNTL_SET_PAGE_ADDRESS | y);
|
|
lcd_remote_write_command(LCD_REMOTE_CNTL_HIGHCOL | (((x+xoffset) >> 4) & 0xf));
|
|
lcd_remote_write_command(LCD_REMOTE_CNTL_LOWCOL | ((x+xoffset) & 0xf));
|
|
lcd_remote_write_data(FBREMOTEADDR(x,y), width);
|
|
}
|
|
}
|