fernly/lcd.c
Sean Cross 516c74096d fernly: fix gcc warnings
Several GCC warnings were getting generated on various compilers.  This
patch solves those warnings.

For various platforms, a uint32_t is not the same as an unsigned int. On
these platforms, printf("%x", (uint32_t)0) generates a warning.  Use the
<inttypes.h> formats (i.e. PRIx32) as formatters to silence these warnings.

There was also a security warning picked up by certain compilers when
calling printf(msg) in fernly-usb-loader.  This has been fixed.

Finally, lcd.c was refactored to fold the unused lcd_dat_slot() function
into the lcd_cmd_slot() function as a brand-new unified lcd_slot().

Signed-off-by: Sean Cross <xobs@kosagi.com>
2015-04-07 18:17:26 +08:00

294 lines
7.4 KiB
C

#include <string.h>
#include "bionic.h"
#include "memio.h"
#include "printf.h"
#include "fernvale-lcd.h"
#include "fernvale-gpio.h"
#include "fernvale-clockgate.h"
#include "lcd.h"
static pixel_t *fb = (pixel_t *)0x40000;
static const uint32_t fb_height = 320;
static const uint32_t fb_width = 240;
static const uint32_t fb_bpp = 2;
#define LCD_FORMAT (0 \
| LCD_AUTOCOPY_CTRL_FORMAT_PAD_MSB \
| LCD_AUTOCOPY_CTRL_FORMAT_RGB565 \
| LCD_AUTOCOPY_CTRL_FORMAT_IFACE_9BIT \
)
#define lcd_cmd(_cmd_) writew(_cmd_, LCD_PAR0_CMD_PORT_REG)
#define lcd_dat(_dat_) writew(_dat_, LCD_PAR0_DAT_PORT_REG)
/* Note these don't flush the DMA, you have to do this yourself
* explicitly later on.
* [slot] is the order to execute.
*/
enum lcd_slot_type {
SLOT_DATA = 0,
SLOT_CMD = 0x800000,
};
static void lcd_slot(enum lcd_slot_type type, uint16_t cmd, uint8_t slot)
{
writel(cmd | type, LCD_CMD_LIST_ADDR + (slot * 4));
}
static void lcd_setup_gpio(void)
{
/* LPCE0, LPTE0, LPRSTB */
writel(readl(GPIO_CTRL_MODE5) & ~(GPIO_CTRL_MODE5_IO40_MASK |
GPIO_CTRL_MODE5_IO46_MASK |
GPIO_CTRL_MODE5_IO45_MASK),
GPIO_CTRL_MODE5);
writel(readl(GPIO_CTRL_MODE5) | (GPIO_CTRL_MODE5_IO40_LPCE0B |
GPIO_CTRL_MODE5_IO45_LPTE0 |
GPIO_CTRL_MODE5_IO46_LPRSTB),
GPIO_CTRL_MODE5);
/* NLD0-4, LWRB, LRDB, LPA0 */
writel(readl(GPIO_CTRL_MODE4) & ~(GPIO_CTRL_MODE4_IO32_MASK |
GPIO_CTRL_MODE4_IO33_MASK |
GPIO_CTRL_MODE4_IO34_MASK |
GPIO_CTRL_MODE4_IO35_MASK |
GPIO_CTRL_MODE4_IO36_MASK |
GPIO_CTRL_MODE4_IO37_MASK |
GPIO_CTRL_MODE4_IO38_MASK |
GPIO_CTRL_MODE4_IO39_MASK),
GPIO_CTRL_MODE4);
writel(readl(GPIO_CTRL_MODE4) | (GPIO_CTRL_MODE4_IO32_NLD4 |
GPIO_CTRL_MODE4_IO33_NLD3 |
GPIO_CTRL_MODE4_IO34_NLD2 |
GPIO_CTRL_MODE4_IO35_NLD1 |
GPIO_CTRL_MODE4_IO36_NLD0 |
GPIO_CTRL_MODE4_IO37_LWRB |
GPIO_CTRL_MODE4_IO38_LRDB |
GPIO_CTRL_MODE4_IO39_LPA0),
GPIO_CTRL_MODE4);
/* NLD5-8 */
writel(readl(GPIO_CTRL_MODE3) & ~(GPIO_CTRL_MODE3_IO28_MASK |
GPIO_CTRL_MODE3_IO29_MASK |
GPIO_CTRL_MODE3_IO30_MASK |
GPIO_CTRL_MODE3_IO31_MASK),
GPIO_CTRL_MODE3);
writel(readl(GPIO_CTRL_MODE3) | (GPIO_CTRL_MODE3_IO28_NLD8 |
GPIO_CTRL_MODE3_IO29_NLD7 |
GPIO_CTRL_MODE3_IO30_NLD6 |
GPIO_CTRL_MODE3_IO31_NLD5),
GPIO_CTRL_MODE3);
}
static int lcd_setup(void)
{
lcd_setup_gpio();
/* Power up the LCD block */
writel(CLKGATE_CTL0_LCD, CLKGATE_SYS_CTL0_CLR);
_msleep(1);
/* execute setup command
* we're on CS0
* our internal bus period is 166 MHz, or 6.25ns
* write cycle = 66ns = 11 cycles - 1 = 10
* write c22write su (tcs) = 15ns = 3 cycles
* write ce2write hold (tdht) = 10ns = 2 cycles - 1 = 1
* read latency = 450 ns = 72 cycles, crop at 63 cycles
* read ce2read su (trdl - trcs) = 45-45 = 0 ns = 0 cycles
* read th = 90ns = 15 cycles (not quite clear, but best guess)
*/
writel( (10 << LCD_PAR_CFG_WR_WAIT_CYC_BIT) |
(3 << LCD_PAR_CFG_WR_TSU_BIT) |
(1 << LCD_PAR_CFG_WR_TH_BIT) |
/* this might need to be shorter?? */
(63 << LCD_PAR_CFG_RD_LATENCY_CYC_BIT) |
(0 << LCD_PAR_CFG_RD_TSU_BIT) |
(15 << LCD_PAR_CFG_RD_TH_BIT),
LCD_PAR0_CFG_REG);
/* 9 bit width, tchw is 0 for this chipset
* (back2back writes allowed)
*/
writel( (0 << LCD_PAR_W2W_WAIT0_BIT) |
(LCD_PAR_BUS_WIDTH_9BIT << LCD_PAR_BUS_WIDTH0_BIT),
LCD_PAR_DATA_WIDTH_REG);
/* Set up tear control */
//writel(LCD_TEARING_MODE_HSYNC | LCD_TEARING_ENABLE, LCD_TEARING_REG);
//writel(0x0003000f, LCD_TEARING_LCD_SIZE_REG);
//writel(4, LCD_TEARING_SYNC_CNT_REG);
//writel(0x10000 | LCD_GMC_CTRL_ENABLE | 4, LCD_GMC_CTRL_REG);
//writel(15, LCD_FREERUN_RATE_REG);
//writel(20 << LCD_FREERUN_DBI_THRESH_HIGH_SHIFT, LCD_FREERUN_DBI_THRESH_REG);
//writel(20 << LCD_FREERUN_GMC_THRESH_HIGH_SHIFT, LCD_FREERUN_GMC_THRESH_REG);
/* Point freerunning DMA engine at parallel LCD registers */
writew((uint16_t)LCD_PAR0_CMD_PORT_REG, LCD_AUTOCOPY_CMD_ADDR_REG);
writew((uint16_t)LCD_PAR0_DAT_PORT_REG, LCD_AUTOCOPY_DATA_ADDR_REG);
return 0;
}
static void lcd_panel_setup(void)
{
writew(LCD_RESET_CLEAR, LCD_RESET_REG);
_usleep(20000);
writew(LCD_RESET_SET, LCD_RESET_REG);
_msleep(20);
writew(LCD_RESET_CLEAR, LCD_RESET_REG);
_msleep(150);
lcd_cmd(0x11); //Exit Sleep
_msleep(50); // Delay 50ms
lcd_cmd(0xC0); //Power control
lcd_dat(0x26);
lcd_cmd(0xC1); //Power control
lcd_dat(0x11); //SAP[2:0];BT[3:0]
lcd_cmd(0xC5); //VCM control
lcd_dat(0x35);
lcd_dat(0x3E);
lcd_cmd(0xc7);
lcd_dat(0xbe);
lcd_cmd(0x36); // Memory Access Control
lcd_dat(0x48);
lcd_cmd(0x3a); // pixel format set
lcd_dat(0x55); // 16bpp
lcd_cmd(0xB1); // Frame Rate Control
lcd_dat(0x00);
lcd_dat(0x1b);
//--------------ddram ---------------------
lcd_cmd(0x2a); // column set
lcd_dat(0x00);
lcd_dat(0x00);
lcd_dat(0x00);
lcd_dat(0xEF);
lcd_cmd(0x2b); // page address set
lcd_dat(0x00);
lcd_dat(0x00);
lcd_dat(0x01);
lcd_dat(0x3F);
lcd_cmd(0x34); // tearing effect off
//lcd_cmd(0x35); // tearing effect on
//lcd_cmd(0xb4); // display inversion
//lcd_dat(0x00,0x00);
lcd_cmd(0xb7); //entry mode set
lcd_dat(0x07);
//-----------------display---------------------
lcd_cmd(0xb6); // display function control
lcd_dat(0x0a);
lcd_dat(0x82);
lcd_dat(0x27);
lcd_dat(0x00);
lcd_cmd(0x11); //sleep out
_msleep(100);
lcd_cmd(0x29); // display on
_msleep(100);
/* Memory Write -- prep for the first pixel to be written */
lcd_cmd(0x2c);
}
/* Fill pre-frame command buffer. These commands are sent out before
* pixel data, whenever RUN is enabled.
*/
static void lcd_fill_cmd_buffer(void)
{
int ncommands = 0;
/* Memory write */
lcd_slot(SLOT_CMD, 0x2c, ncommands++);
/* Count the number of cmmands and add it to AUTOCOPY_CTRL */
writel((readl(LCD_AUTOCOPY_CTRL_REG)
& ~LCD_AUTOCOPY_CTRL_CMD_COUNT_MASK)
| ((ncommands - 1) << LCD_AUTOCOPY_CTRL_CMD_COUNT_SHIFT),
LCD_AUTOCOPY_CTRL_REG);
}
static int lcd_dma_setup(void)
{
/* Set up AUTOCOPY (i.e. freerunning mode) */
writel(LCD_FORMAT | (0x1f << LCD_AUTOCOPY_CTRL_PERIOD_SHIFT),
LCD_AUTOCOPY_CTRL_REG);
writel((fb_height << 16) | (fb_width), LCD_AUTOCOPY_SIZE_REG);
writel(0, LCD_AUTOCOPY_OFFSET_REG);
writel((uint32_t)fb, LCD_LAYER0_SRC_ADDR_REG);
writel(LCD_LAYER_CTRL_CLRDPT_RGB565, LCD_LAYER0_CTRL_REG);
writel((fb_height << 16) | (fb_width), LCD_LAYER0_SIZE_REG);
writel(fb_width * fb_bpp, LCD_LAYER0_PITCH_REG);
writel(0, LCD_LAYER0_MEM_OFFSET_REG);
writel(0, LCD_LAYER0_OFFSET_REG);
writel(0, LCD_LAYER0_SRC_KEY_REG);
writel(rgb(0, 255, 255), LCD_AUTOCOPY_BG_COLOR_REG);
writel(readl(LCD_AUTOCOPY_CTRL_REG) | LCD_AUTOCOPY_CTRL_EN0,
LCD_AUTOCOPY_CTRL_REG);
/* Enable AUTOCOPY_CTRL command transfer */
writel(readl(LCD_AUTOCOPY_CTRL_REG)
| LCD_AUTOCOPY_CTRL_ENC
| LCD_AUTOCOPY_CTRL_SEND_RESIDUE,
LCD_AUTOCOPY_CTRL_REG);
return 0;
}
int lcd_init(void)
{
lcd_setup();
lcd_panel_setup();
lcd_dma_setup();
return 0;
}
int lcd_run(void)
{
writew(0, LCD_RUN_REG);
/* Must refill the command buffer before sending another frame */
lcd_fill_cmd_buffer();
writew(LCD_RUN_BIT, LCD_RUN_REG);
return 0;
}
int lcd_stop(void)
{
writew(1, LCD_RUN_REG);
writew(0, LCD_RUN_REG);
return 0;
}
pixel_t *lcd_fb(void)
{
return fb;
}
uint32_t lcd_width(void)
{
return fb_width;
}
uint32_t lcd_height(void)
{
return fb_height;
}
uint32_t lcd_bpp(void)
{
return fb_bpp;
}
void lcd_addpixel(pixel_t px)
{
lcd_dat(px >> 8);
lcd_dat(px & 0xff);
}