2006-08-03 20:18:31 +00:00
|
|
|
/***************************************************************************
|
|
|
|
* __________ __ ___.
|
|
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
|
|
* \/ \/ \/ \/ \/
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
* Copyright (C) 2006 by Barry Wardell
|
|
|
|
*
|
2008-06-28 18:10:04 +00:00
|
|
|
* 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.
|
2006-08-03 20:18:31 +00:00
|
|
|
*
|
|
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
|
|
* KIND, either express or implied.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
#include "config.h"
|
|
|
|
#include "cpu.h"
|
|
|
|
#include "lcd.h"
|
|
|
|
#include "kernel.h"
|
|
|
|
#include "system.h"
|
|
|
|
|
2006-08-23 09:14:28 +00:00
|
|
|
/* register defines for TL1771 */
|
|
|
|
#define R_START_OSC 0x00
|
|
|
|
#define R_DEVICE_CODE_READ 0x00
|
|
|
|
#define R_DRV_OUTPUT_CONTROL 0x01
|
|
|
|
#define R_DRV_AC_CONTROL 0x02
|
|
|
|
#define R_ENTRY_MODE 0x03
|
|
|
|
#define R_DISP_CONTROL1 0x07
|
|
|
|
#define R_DISP_CONTROL2 0x08
|
|
|
|
#define R_FRAME_CYCLE_CONTROL 0x0b
|
|
|
|
#define R_POWER_CONTROL1 0x10
|
|
|
|
#define R_POWER_CONTROL2 0x11
|
|
|
|
#define R_POWER_CONTROL3 0x12
|
|
|
|
#define R_POWER_CONTROL4 0x13
|
|
|
|
#define R_POWER_CONTROL5 0x14
|
|
|
|
#define R_RAM_ADDR_SET 0x21
|
|
|
|
#define R_WRITE_DATA_2_GRAM 0x22
|
|
|
|
#define R_GAMMA_FINE_ADJ_POS1 0x30
|
|
|
|
#define R_GAMMA_FINE_ADJ_POS2 0x31
|
|
|
|
#define R_GAMMA_FINE_ADJ_POS3 0x32
|
|
|
|
#define R_GAMMA_GRAD_ADJ_POS 0x33
|
|
|
|
#define R_GAMMA_FINE_ADJ_NEG1 0x34
|
|
|
|
#define R_GAMMA_FINE_ADJ_NEG2 0x35
|
|
|
|
#define R_GAMMA_FINE_ADJ_NEG3 0x36
|
|
|
|
#define R_GAMMA_GRAD_ADJ_NEG 0x37
|
|
|
|
#define R_POWER_CONTROL6 0x38
|
|
|
|
#define R_GATE_SCAN_START_POS 0x40
|
|
|
|
#define R_1ST_SCR_DRV_POS 0x42
|
|
|
|
#define R_2ND_SCR_DRV_POS 0x43
|
2006-09-04 23:10:27 +00:00
|
|
|
#define R_HORIZ_RAM_ADDR_POS 0x44
|
|
|
|
#define R_VERT_RAM_ADDR_POS 0x45
|
2006-08-23 09:14:28 +00:00
|
|
|
|
2006-08-31 01:27:54 +00:00
|
|
|
static inline void lcd_wait_write(void)
|
2006-08-20 10:18:47 +00:00
|
|
|
{
|
2007-10-12 00:28:57 +00:00
|
|
|
while (LCD2_PORT & LCD2_BUSY_MASK);
|
2006-08-03 20:18:31 +00:00
|
|
|
}
|
2006-08-20 10:18:47 +00:00
|
|
|
|
|
|
|
/* Send command */
|
2007-10-12 00:28:57 +00:00
|
|
|
static inline void lcd_send_cmd(unsigned v)
|
2006-08-03 20:18:31 +00:00
|
|
|
{
|
2006-08-20 10:18:47 +00:00
|
|
|
lcd_wait_write();
|
2007-10-12 00:28:57 +00:00
|
|
|
LCD2_PORT = LCD2_CMD_MASK;
|
|
|
|
LCD2_PORT = LCD2_CMD_MASK | v;
|
2006-08-03 20:18:31 +00:00
|
|
|
}
|
|
|
|
|
2006-08-20 10:18:47 +00:00
|
|
|
/* Send 16-bit data */
|
2007-10-12 00:28:57 +00:00
|
|
|
static inline void lcd_send_data(unsigned v)
|
2006-08-03 20:18:31 +00:00
|
|
|
{
|
2006-08-20 10:18:47 +00:00
|
|
|
lcd_wait_write();
|
2007-10-12 00:28:57 +00:00
|
|
|
LCD2_PORT = LCD2_DATA_MASK | (v >> 8); /* Send MSB first */
|
|
|
|
LCD2_PORT = LCD2_DATA_MASK | (v & 0xff);
|
2006-08-03 20:18:31 +00:00
|
|
|
}
|
|
|
|
|
2007-10-12 17:09:33 +00:00
|
|
|
/* Write value to register */
|
|
|
|
static void lcd_write_reg(int reg, int val)
|
|
|
|
{
|
|
|
|
lcd_send_cmd(reg);
|
|
|
|
lcd_send_data(val);
|
|
|
|
}
|
|
|
|
|
2006-08-03 20:18:31 +00:00
|
|
|
|
2006-08-20 10:18:47 +00:00
|
|
|
/*** hardware configuration ***/
|
2006-08-03 20:18:31 +00:00
|
|
|
|
|
|
|
void lcd_set_contrast(int val)
|
|
|
|
{
|
2006-08-20 10:18:47 +00:00
|
|
|
/* TODO: Implement lcd_set_contrast() */
|
|
|
|
(void)val;
|
2006-08-03 20:18:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void lcd_set_invert_display(bool yesno)
|
|
|
|
{
|
2006-08-20 10:18:47 +00:00
|
|
|
/* TODO: Implement lcd_set_invert_display() */
|
|
|
|
(void)yesno;
|
2006-08-03 20:18:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* turn the display upside down (call lcd_update() afterwards) */
|
|
|
|
void lcd_set_flip(bool yesno)
|
|
|
|
{
|
2006-08-20 10:18:47 +00:00
|
|
|
/* TODO: Implement lcd_set_flip() */
|
|
|
|
(void)yesno;
|
2006-08-03 20:18:31 +00:00
|
|
|
}
|
|
|
|
|
2006-08-20 10:18:47 +00:00
|
|
|
/* LCD init */
|
2006-08-03 20:18:31 +00:00
|
|
|
void lcd_init_device(void)
|
2006-08-20 10:18:47 +00:00
|
|
|
{
|
2009-03-02 22:42:13 +00:00
|
|
|
#ifndef BOOTLOADER
|
|
|
|
/* The OF won't boot if this is done in the bootloader - ideally we should
|
|
|
|
tweak the lcd controller speed settings but this will do for now */
|
2007-07-26 15:33:25 +00:00
|
|
|
CLCD_CLOCK_SRC |= 0xc0000000; /* Set LCD interface clock to PLL */
|
2009-03-02 22:42:13 +00:00
|
|
|
#endif
|
2006-08-20 10:18:47 +00:00
|
|
|
/* H10 LCD is initialised by the bootloader */
|
2006-08-03 20:18:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*** update functions ***/
|
|
|
|
|
|
|
|
/* Update a fraction of the display. */
|
2008-04-02 22:45:23 +00:00
|
|
|
void lcd_update_rect(int x0, int y0, int width, int height)
|
2006-08-03 20:18:31 +00:00
|
|
|
{
|
2008-04-02 22:45:23 +00:00
|
|
|
int x1, y1;
|
|
|
|
int newx,newwidth;
|
|
|
|
unsigned long *addr;
|
2006-08-20 10:18:47 +00:00
|
|
|
|
2008-04-02 22:45:23 +00:00
|
|
|
/* Ensure x and width are both even - so we can read 32-bit aligned
|
|
|
|
data from lcd_framebuffer */
|
|
|
|
newx=x0&~1;
|
|
|
|
newwidth=width&~1;
|
|
|
|
if (newx+newwidth < x0+width) { newwidth+=2; }
|
|
|
|
x0=newx; width=newwidth;
|
|
|
|
|
|
|
|
/* calculate the drawing region */
|
|
|
|
y1 = (y0 + height) - 1; /* max vert */
|
|
|
|
x1 = (x0 + width) - 1; /* max horiz */
|
|
|
|
|
|
|
|
|
|
|
|
/* swap max horiz < start horiz */
|
|
|
|
if (y1 < y0) {
|
|
|
|
int t;
|
|
|
|
t = y0;
|
|
|
|
y0 = y1;
|
|
|
|
y1 = t;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* swap max vert < start vert */
|
|
|
|
if (x1 < x0) {
|
|
|
|
int t;
|
|
|
|
t = x0;
|
|
|
|
x0 = x1;
|
|
|
|
x1 = t;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* max horiz << 8 | start horiz */
|
|
|
|
lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (x1 << 8) | x0);
|
|
|
|
|
|
|
|
/* max vert << 8 | start vert */
|
|
|
|
lcd_write_reg(R_VERT_RAM_ADDR_POS, (y1 << 8) | y0);
|
|
|
|
|
|
|
|
/* start vert << 8 | start horiz */
|
|
|
|
lcd_write_reg(R_RAM_ADDR_SET, (y0 << 8) | x0);
|
|
|
|
|
|
|
|
/* start drawing */
|
2006-08-20 10:18:47 +00:00
|
|
|
lcd_send_cmd(R_WRITE_DATA_2_GRAM);
|
|
|
|
|
2012-02-22 10:18:05 +00:00
|
|
|
addr = (unsigned long*)FBADDR(x0,y0);
|
2008-03-25 19:57:23 +00:00
|
|
|
|
2008-04-02 22:45:23 +00:00
|
|
|
while (height > 0) {
|
|
|
|
int c, r;
|
|
|
|
int h, pixels_to_write;
|
|
|
|
|
|
|
|
pixels_to_write = (width * height) * 2;
|
|
|
|
h = height;
|
|
|
|
|
|
|
|
/* calculate how much we can do in one go */
|
|
|
|
if (pixels_to_write > 0x10000) {
|
|
|
|
h = (0x10000/2) / width;
|
|
|
|
pixels_to_write = (width * h) * 2;
|
2008-03-25 19:57:23 +00:00
|
|
|
}
|
2008-04-02 22:45:23 +00:00
|
|
|
|
|
|
|
LCD2_BLOCK_CTRL = 0x10000080;
|
|
|
|
LCD2_BLOCK_CONFIG = 0xc0010000 | (pixels_to_write - 1);
|
|
|
|
LCD2_BLOCK_CTRL = 0x34000000;
|
|
|
|
|
|
|
|
/* for each row */
|
|
|
|
for (r = 0; r < h; r++) {
|
|
|
|
/* for each column */
|
|
|
|
for (c = 0; c < width; c += 2) {
|
|
|
|
while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_TXOK));
|
|
|
|
|
|
|
|
/* output 2 pixels */
|
|
|
|
LCD2_BLOCK_DATA = *addr++;
|
|
|
|
}
|
|
|
|
addr += (LCD_WIDTH - width)/2;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_READY));
|
|
|
|
LCD2_BLOCK_CONFIG = 0;
|
|
|
|
|
|
|
|
height -= h;
|
2006-08-20 10:18:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update the display.
|
|
|
|
This must be called after all other LCD functions that change the display. */
|
|
|
|
void lcd_update(void)
|
|
|
|
{
|
|
|
|
lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT);
|
2006-08-03 20:18:31 +00:00
|
|
|
}
|