rockbox/firmware/target/arm/sandisk/sansa-view/lcd-view.c

443 lines
9.9 KiB
C
Raw Normal View History

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Rockbox driver for Sansa View LCDs
*
* Copyright (c) 2009 Robert Keevil
*
* 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 <string.h>
#include "cpu.h"
#include "system.h"
#include "backlight-target.h"
#include "lcd.h"
#include "bitmaps/rockboxlogo.h"
/* Power and display status */
static bool power_on = false; /* Is the power turned on? */
static bool display_on SHAREDBSS_ATTR = false; /* Is the display turned on? */
static unsigned lcd_yuv_options SHAREDBSS_ATTR = 0;
static int lcd_type;
#define LCD_DATA_OUT_GPIO GPIOH_OUTPUT_VAL
#define LCD_DATA_OUT_PIN 4
#define LCD_CLOCK_GPIO GPIOH_OUTPUT_VAL
#define LCD_CLOCK_PIN 6
#define LCD_CS_GPIO GPIOH_OUTPUT_VAL
#define LCD_CS_PIN 7
#ifdef BOOTLOADER
static void lcd_init_gpio(void)
{
/* BOOT: 0x5CC8
OF: 0x88284 */
outl(inl(0x70000010) | 0xFC000000, 0x70000010);
outl(inl(0x70000014) | 0xC300000, 0x70000014);
GPIOE_ENABLE = 0;
GPIOM_ENABLE &= ~0x3;
GPIOF_ENABLE = 0;
GPIOJ_ENABLE &= ~0x1a;
GPIOB_ENABLE &= ~0x8;
GPIOH_OUTPUT_VAL |= 0x80;
GPIOH_OUTPUT_EN |= 0x80;
GPIOH_ENABLE |= 0x80;
GPIOH_OUTPUT_VAL |= 0x40;
GPIOH_OUTPUT_EN |= 0x40;
GPIOH_ENABLE |= 0x40;
GPIOH_OUTPUT_VAL |= 0x20;
GPIOH_OUTPUT_EN |= 0x20;
GPIOH_ENABLE |= 0x20;
GPIOH_OUTPUT_VAL |= 0x10;
GPIOH_OUTPUT_EN |= 0x10;
GPIOH_ENABLE |= 0x10;
GPIOD_OUTPUT_VAL |= 0x1; /* backlight on */
GPIOD_ENABLE |= 0x1;
GPIOB_OUTPUT_VAL |= 0x4;
GPIOB_ENABLE |= 0x4;
GPIOB_OUTPUT_EN |= 0x4;
DEV_INIT2 = 0x40000000;
GPIOG_ENABLE |= 0x8;
GPIOG_OUTPUT_EN &= ~0x8;
if (GPIOG_INPUT_VAL & 0x8)
lcd_type = 1;
else
lcd_type = 0;
}
#endif
static void lcd_send_msg(unsigned char count, unsigned int data)
{
/* BOOT: 0x645C
OF: 0x88E90 */
int i;
LCD_CLOCK_GPIO |= (1 << LCD_CLOCK_PIN);
LCD_CS_GPIO &= ~(1 << LCD_CS_PIN);
for (i = count - 1; i >= 0; i--)
{
if (data & (1 << i))
{
LCD_DATA_OUT_GPIO &= ~(1 << LCD_DATA_OUT_PIN);
} else {
LCD_DATA_OUT_GPIO |= (1 << LCD_DATA_OUT_PIN);
}
LCD_CLOCK_GPIO &= ~(1 << LCD_CLOCK_PIN);
udelay(1);
LCD_CLOCK_GPIO |= (1 << LCD_CLOCK_PIN);
udelay(2);
}
LCD_CS_GPIO |= (1 << LCD_CS_PIN);
LCD_CLOCK_GPIO |= (1 << LCD_CLOCK_PIN);
udelay(1);
}
/*
static void lcd_write_reg(unsigned int reg, unsigned int data)
{
// OF: 0x6278 - referenced from 0x62840
// So far this function is always called with shift = 0x0 ?
// If so can remove and simplify
unsigned int cmd;
unsigned int shift = 0;
cmd = shift << 0x2;
cmd |= 0x70;
cmd = cmd << 0x10;
cmd |= reg;
lcd_send_msg(0x18, cmd);
cmd = shift << 0x2;
cmd |= 0x72;
cmd = cmd << 0x10;
cmd |= data;
lcd_send_msg(0x18, cmd);
// lcd_send_msg(0x70, reg);
// lcd_send_msg(0x72, data);
}
*/
static void lcd_write_cmd(unsigned int cmd)
{
lcd_send_msg(0x18, (0x700000 | cmd));
}
static void lcd_write_info(unsigned int data)
{
lcd_send_msg(0x18, (0x720000 | data));
}
static void lcd_write_reg(unsigned int cmd, unsigned int data)
{
lcd_write_cmd(cmd);
lcd_write_info(data);
}
void lcd_reset(void)
{
/* BOOT: 0x623C
OF: 0x88BDC */
GPIOB_OUTPUT_VAL |= 0x4;
udelay(1000);
GPIOB_OUTPUT_VAL &= ~0x4;
udelay(10000);
GPIOB_OUTPUT_VAL |= 0x4;
udelay(50000);
}
/* Run the powerup sequence for the driver IC */
static void lcd_power_on(void)
{
lcd_reset();
/* OF: 0x5DC0 *
* r2: cmd *
* r3: data */
lcd_write_reg(0xE5, 0x8000);
lcd_write_reg(0x0, 0x1);
lcd_write_reg(0x1, 0x100);
lcd_write_reg(0x2, 0x700);
lcd_write_reg(0x3, 0x1230);
lcd_write_reg(0x4, 0x0);
lcd_write_reg(0x8, 0x408);
lcd_write_reg(0x9, 0x0);
lcd_write_reg(0xa, 0x0);
lcd_write_reg(0xd, 0x0);
lcd_write_reg(0xf, 0x2);
lcd_write_reg(0x10, 0x0);
lcd_write_reg(0x11, 0x0);
lcd_write_reg(0x12, 0x0);
lcd_write_reg(0x13, 0x0);
sleep(HZ/5);
lcd_write_reg(0x10, 0x17B0);
lcd_write_reg(0x11, 0x7);
sleep(HZ/20);
lcd_write_reg(0x12, 0x13c);
sleep(HZ/20);
/* BOOT: BNE 0x5fb2 */
if (lcd_type == 0)
{
lcd_write_reg(0x13, 0x1700);
lcd_write_reg(0x29, 0x10);
sleep(HZ/10);
lcd_write_reg(0x20, 0x0);
lcd_write_reg(0x21, 0x0);
lcd_write_reg(0x30, 0x7);
lcd_write_reg(0x31, 0x403);
lcd_write_reg(0x32, 0x400);
lcd_write_reg(0x35, 0x3);
lcd_write_reg(0x36, 0xF07);
lcd_write_reg(0x37, 0x606);
lcd_write_reg(0x38, 0x106);
lcd_write_reg(0x39, 0x7);
}
else
{
lcd_write_reg(0x13, 0x1800);
lcd_write_reg(0x29, 0x13);
sleep(HZ/10);
lcd_write_reg(0x20, 0x0);
lcd_write_reg(0x21, 0x0);
lcd_write_reg(0x30, 0x2);
lcd_write_reg(0x31, 0x606);
lcd_write_reg(0x32, 0x501);
lcd_write_reg(0x35, 0x206);
lcd_write_reg(0x36, 0x504);
lcd_write_reg(0x37, 0x707);
lcd_write_reg(0x38, 0x306);
lcd_write_reg(0x39, 0x9);
}
/* BOOT: 0x6066 */
lcd_write_reg(0x3c, 0x700);
lcd_write_reg(0x3d, 0x700);
lcd_write_reg(0x50, 0x0);
lcd_write_reg(0x51, 0xef); /* 239 - LCD_WIDTH */
lcd_write_reg(0x52, 0x0);
lcd_write_reg(0x53, 0x13f); /* 319 - LCD_HEIGHT */
/* BOOT: b 0x6114 */
lcd_write_reg(0x60, 0x2700);
lcd_write_reg(0x61, 0x1);
lcd_write_reg(0x6a, 0x0);
lcd_write_reg(0x80, 0x0);
lcd_write_reg(0x81, 0x0);
lcd_write_reg(0x82, 0x0);
lcd_write_reg(0x83, 0x0);
lcd_write_reg(0x84, 0x0);
lcd_write_reg(0x85, 0x0);
/* BOOT: 0x61A8 */
lcd_write_reg(0x90, 0x10);
lcd_write_reg(0x92, 0x0);
lcd_write_reg(0x93, 0x3);
lcd_write_reg(0x95, 0x110);
lcd_write_reg(0x97, 0x0);
lcd_write_reg(0x98, 0x0);
lcd_write_reg(0xc, 0x110);
lcd_write_reg(0x7, 0x173);
sleep(HZ/10);
power_on = true;
}
/* unknown 01 and 02 - sleep or enable on and off funcs? */
void unknown01(void)
{
/* BOOT: 0x62C4
OF: 0x88CA0 */
lcd_write_reg(0x10, 0x17B0);
udelay(100);
lcd_write_reg(0x7, 0x173);
}
void unknown02(void)
{
/* BOOT: 0x6308
OF: 0x88D0C */
lcd_write_reg(0x7, 0x160);
lcd_write_reg(0x10, 0x17B1);
}
void unknown03(bool r0)
{
/* BOOT: 0x6410
OF: 0x88E30 */
if (r0)
GPIOJ_ENABLE &= ~0x2;
else
{
GPIOJ_ENABLE |= 0x2;
GPIOJ_OUTPUT_EN |= 0x2;
GPIOJ_OUTPUT_VAL &= ~0x02;
}
}
/* Run the display on sequence for the driver IC */
static void lcd_display_on(void)
{
display_on = true;
}
#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
bool lcd_active(void)
{
return display_on;
}
/* Turn off visible display operations */
static void lcd_display_off(void)
{
display_on = false;
}
#endif
void lcd_init_device(void)
{
#ifdef BOOTLOADER /* Bother at all to do this again? */
/* Init GPIO ports */
lcd_init_gpio();
lcd_power_on();
lcd_display_on();
#else
power_on = true;
display_on = true;
lcd_set_invert_display(false);
lcd_set_flip(false);
#endif
}
#if defined(HAVE_LCD_ENABLE)
void lcd_enable(bool on)
{
(void)on;
}
#endif
#if defined(HAVE_LCD_SLEEP)
void lcd_sleep(void)
{
}
#endif
void lcd_update(void)
{
const fb_data *addr;
addr = FBADDR(LCD_WIDTH,LCD_HEIGHT);
lcd_write_reg(0x20, 0x0);
lcd_write_reg(0x21, 0x0);
int i,j;
for(i=0; i < LCD_HEIGHT; i++)
{
for(j=0; j < LCD_WIDTH; j++)
{
lcd_write_reg(0x22, *addr);
addr++;
}
}
}
/* Update a fraction of the display. */
void lcd_update_rect(int x, int y, int width, int height)
{
(void)x;
(void)y;
(void)width;
(void)height;
lcd_update();
}
/*** hardware configuration ***/
void lcd_set_contrast(int val)
{
(void)val;
}
void lcd_set_invert_display(bool yesno)
{
(void)yesno;
}
/* turn the display upside down (call lcd_update() afterwards) */
void lcd_set_flip(bool yesno)
{
(void)yesno;
}
/* Blitting functions */
void lcd_yuv_set_options(unsigned options)
{
lcd_yuv_options = options;
}
/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */
extern void lcd_write_yuv420_lines(fb_data *dst,
unsigned char const * const src[3],
int width,
int stride);
extern void lcd_write_yuv420_lines_odither(fb_data *dst,
unsigned char const * const src[3],
int width,
int stride,
int x_screen, /* To align dither pattern */
int y_screen);
void lcd_blit_yuv(unsigned char * const src[3],
int src_x, int src_y, int stride,
int x, int y, int width, int height)
{
(void)src;
(void)src_x;
(void)src_y;
(void)stride;
(void)x;
(void)y;
(void)width;
(void)height;
}