rockbox/firmware/target/arm/sandisk/sansa-view/lcd-view.c
Amaury Pouly 85390865b5 sansaview: fix lcd code
The lcd driver now works but is awfully slow. The trick is to put it in system
mode instead of RGB and setup 16bpp. The GRAM data can then be sent directly
with the SPI but since it's bit-banged and the CPU running at slow speed,
full screen refresh takes over a second, even with a slightly optmised version.
The OF uses a DMA mechanism with a proper LCD controller but the setup is much
more complicated and doesn't work at the moment.

Change-Id: I6c95d91de31bff97d0a5848b8e2078c21deb5895
2014-05-11 19:56:43 +02:00

340 lines
7.9 KiB
C

/***************************************************************************
* __________ __ ___.
* 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 "kernel.h"
#include "system.h"
#include "backlight-target.h"
#include "lcd.h"
static bool display_on SHAREDBSS_ATTR = true;
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
static void lcd_init_gpio(void)
{
DEV_INIT1 |= 0xfc000000;
DEV_INIT3 |= 0xc300000;
GPIOE_ENABLE = 0;
GPIOM_ENABLE &= ~0x3;
GPIOF_ENABLE = 0;
GPIOJ_ENABLE &= ~0x1a;
// reset low
GPIOB_ENABLE &= ~0x8;
// SPI chip select
GPIOH_OUTPUT_VAL |= 0x80;
GPIOH_OUTPUT_EN |= 0x80;
GPIOH_ENABLE |= 0x80;
// SPI clock
GPIOH_OUTPUT_VAL |= 0x40;
GPIOH_OUTPUT_EN |= 0x40;
GPIOH_ENABLE |= 0x40;
// unk
GPIOH_OUTPUT_VAL |= 0x20;
GPIOH_OUTPUT_EN |= 0x20;
GPIOH_ENABLE |= 0x20;
// SPI data
GPIOH_OUTPUT_VAL |= 0x10;
GPIOH_OUTPUT_EN |= 0x10;
GPIOH_ENABLE |= 0x10;
// LCD reset
GPIOB_OUTPUT_VAL |= 0x4;
GPIOB_ENABLE |= 0x4;
GPIOB_OUTPUT_EN |= 0x4;
DEV_INIT2 = 0x40000000;
// LCD type
GPIOG_ENABLE |= 0x8;
GPIOG_OUTPUT_EN &= ~0x8;
if(GPIOG_INPUT_VAL & 0x8)
lcd_type = 0;
else
lcd_type = 1;
}
static void lcd_send_msg(unsigned char count, unsigned int data)
{
GPIO_SET_BITWISE(LCD_CLOCK_GPIO, 1 << LCD_CLOCK_PIN);
GPIO_CLEAR_BITWISE(LCD_CS_GPIO, 1 << LCD_CS_PIN);
for(int i = count - 1; i >= 0; i--)
{
if(data & (1 << i))
GPIO_SET_BITWISE(LCD_DATA_OUT_GPIO, 1 << LCD_DATA_OUT_PIN);
else
GPIO_CLEAR_BITWISE(LCD_DATA_OUT_GPIO, 1 << LCD_DATA_OUT_PIN);
GPIO_CLEAR_BITWISE(LCD_CLOCK_GPIO, 1 << LCD_CLOCK_PIN);
udelay(1);
GPIO_SET_BITWISE(LCD_CLOCK_GPIO, 1 << LCD_CLOCK_PIN);
udelay(2);
}
GPIO_SET_BITWISE(LCD_CS_GPIO, 1 << LCD_CS_PIN);
}
static void lcd_send_cmd(unsigned int cmd)
{
lcd_send_msg(24, (0x700000 | cmd));
}
static void lcd_send_data(unsigned int data)
{
lcd_send_msg(24, (0x720000 | data));
}
static void lcd_write_reg(unsigned int cmd, unsigned int data)
{
lcd_send_cmd(cmd);
lcd_send_data(data);
}
void lcd_reset(void)
{
GPIO_SET_BITWISE(GPIOB_OUTPUT_VAL, 0x4);
udelay(1000);
GPIO_CLEAR_BITWISE(GPIOB_OUTPUT_VAL, 0x4);
udelay(10000);
GPIO_SET_BITWISE(GPIOB_OUTPUT_VAL, 0x4);
udelay(50000);
}
/* Run the powerup sequence for the driver IC */
static void lcd_power_on(void)
{
lcd_init_gpio();
lcd_reset();
lcd_write_reg(0xE5, 0x8000);
lcd_write_reg(0x0, 0x1);
lcd_write_reg(0x1, 0x100);
lcd_write_reg(0x2, 0x700);
lcd_write_reg(0x3, 0x5230);
lcd_write_reg(0x4, 0x0);
lcd_write_reg(0x8, 0x408); /* back porch = 8, front porch = 4 */
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);
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, 0x7);
}
lcd_write_reg(0x3c, 0x700);
lcd_write_reg(0x3d, 0x700);
lcd_write_reg(0x50, 0x0);
lcd_write_reg(0x51, 0xef);
lcd_write_reg(0x52, 0x0);
lcd_write_reg(0x53, 0x13f);
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);
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, 0x000); // SYSTEM mode
lcd_write_reg(0x7, 0x173);
sleep(HZ/10);
}
{
lcd_power_on();
lcd_write_reg(0x7, 0x160);
lcd_write_reg(0x10, 0x17B1);
}
void unknown03(bool r0)
{
if (r0)
GPIOJ_ENABLE &= ~0x2;
else
{
GPIOJ_ENABLE |= 0x2;
GPIOJ_OUTPUT_EN |= 0x2;
GPIOJ_OUTPUT_VAL &= ~0x02;
}
}
void lcd_init_device(void)
{
lcd_power_on();
}
#if defined(HAVE_LCD_ENABLE)
bool lcd_active(void)
{
return display_on;
}
void lcd_enable(bool on)
{
display_on = on;
if(on)
{
lcd_write_reg(0x10, 0x17B0);
udelay(100);
lcd_write_reg(0x7, 0x173);
}
else
{
lcd_write_reg(0x7, 0x160);
lcd_write_reg(0x10, 0x17B1);
}
}
#endif
static inline void lcd_send_frame_byte(unsigned char data)
{
for(int bit = 0; bit < 8; bit++)
{
if(data & 0x80)
GPIO_SET_BITWISE(LCD_DATA_OUT_GPIO, 1 << LCD_DATA_OUT_PIN);
else
GPIO_CLEAR_BITWISE(LCD_DATA_OUT_GPIO, 1 << LCD_DATA_OUT_PIN);
data <<= 1;
GPIO_CLEAR_BITWISE(LCD_CLOCK_GPIO, 1 << LCD_CLOCK_PIN);
GPIO_SET_BITWISE(LCD_CLOCK_GPIO, 1 << LCD_CLOCK_PIN);
}
}
static void lcd_send_frame(const fb_data *addr, int count)
{
GPIO_SET_BITWISE(LCD_CLOCK_GPIO, 1 << LCD_CLOCK_PIN);
GPIO_CLEAR_BITWISE(LCD_CS_GPIO, 1 << LCD_CS_PIN);
lcd_send_frame_byte(0x72);
while(count-- > 0)
{
lcd_send_frame_byte(*addr >> 8);
lcd_send_frame_byte(*addr++ & 0xff);
}
GPIO_SET_BITWISE(LCD_CS_GPIO, 1 << LCD_CS_PIN);
}
void lcd_update(void)
{
if(!display_on)
return;
lcd_write_reg(0x20, 0x0);
lcd_write_reg(0x21, 0x0);
lcd_send_cmd(0x22);
lcd_send_frame(FBADDR(0, 0), LCD_WIDTH * LCD_HEIGHT);
}
/* 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;
}