home kinesia products products
Embedded Linux Information

  1. Building the 2.4.x Kernel Basics
  2. Network Configuration
  3. Developing Applications and Modules for uClinux 2.4.x
  4. Connection between Linux PC and 44B0X Target Board
  5. LCD Configuration
  6. Audio Configuration
  7. Sharp ARM 9 Root FS with FC
  8. Modifying SDL-1.2.11 to support USB mouse for ARM

LCD Configuration of uClinux 2.4.x for 44B0X

by Tong Lai Yu, Felix Lo, John Jiang, and Ken Liu August 2005

LCD pin mapping ( for the Brightek 44b0x board )

  
LCD & Controller
Wintek VM-X1216VE-6CL LCD and
Novatek NT7523 Controller
map to 44b0
( IDE )
IDE pin #44bb0 board pin
1S/PL     
2S8/16L     
3DB0 DATA017  
4DB1 DATA115  
5DB2 DATA213  
6DB3 DATA311  
7DB4 DATA49  
8DB5 DATA57  
9DB6 DATA65  
10DB7 DATA73  
11DB8 DATA84  
12DB9 DATA96  
13DB10 DATA108  
14DB11 DATA1110  
15DB12 DATA1212  
16DB13 DATA1313  
17DB14 DATA1416  
18DB15 DATA1518  
19VDD VDD39  
20VSS GND40   
21CSB nDATA_CS -- 19  
22RESET nRESET1   
23A0 ADDR0 -- 4  
24E/WRB(SCL) nWE21  
25R/W(RDB) nOE27   
26NCNC    
27LED_ANC     
28LED_BNC     
29C86H     
30NCNC     

Later, the connection was modified: A0 of LCD ( pin 23 ) was connected to Addr2 of 44B0X. Also, LED_A and LED_B ( pin 27, 28 ) of LCD have to be connected to 12.3V and GND respectively in order that the panel will be lit up.

We are using the 16-bit parallel mode of the LCD Controller. We must also set the 44B0X to 16-bit mode. The 44B0X schematics shows that we should use address bank 0x040000000 - 0x06000000 ( nGS2 ). The following piece of ASM code will accomplish these:

	AREA	asm1, CODE, READONLY
	
	ENTRY

START

	LDR	R0, =0x01c80000		;44B0X port to set mode
	LDR	R1, =0x11111290		;44B0X 16-bit mode
	STR	R1, [R0]		;set to 16-bit mode
	
	LDR	R2, =0x04000004		;44B0 port nGS2 write ( Adr2 to A0 of LCDC )
	LDR	R0, =0x04000000		;corresponding read port
	......

We then need to do the initialization of the LCDC ( NT7532, p.52, p.68 and Wintek p.10 ) as follows:
	.....		
	LDR	R1, =0x0002	;start of initialization, Wintek p.10
	STR	R1, [R0]
	LDR	R1, =0x0400
	STR	R1, [R2]
	
	LDR	R1, =0x0000
	STR	R1, [R0]
	LDR	R1, =0X7523
	STR	R1, [R2]
	
	LDR	R1, =0x0001
	STR	R1, [R0]
	LDR	R1, =0X0213
	STR	R1, [R2]
	
	LDR	R1, =0x0005
	STR	R1, [R0]
	LDR	R1, =0X0010
	STR	R1, [R2]
	
	LDR	R1, =0x000B
	STR	R1, [R0]
	LDR	R1, =0X0000
	STR	R1, [R2]
	
	LDR	R1, =0x0016
	STR	R1, [R0]
	LDR	R1, =0X7F00
	STR	R1, [R2]
	
	LDR	R1, =0x0017
	STR	R1, [R0]
	LDR	R1, =0X9F00
	STR	R1, [R2]
	
	LDR	R1, =0x0020
	STR	R1, [R0]
	LDR	R1, =0X0000
	STR	R1, [R2]
	
	LDR	R1, =0x0003
	STR	R1, [R0]
	LDR	R1, =0X8C08
	STR	R1, [R2]
	
	LDR	R1, =0x000c
	STR	R1, [R0]
	LDR	R1, =0X0000
	STR	R1, [R2]
	
	LDR	R1, =0x0004
	STR	R1, [R0]
	LDR	R1, =0X014B
	STR	R1, [R2]
	
	LDR	R1, =0x0007
	STR	R1, [R0]
	LDR	R1, =0X000B
	STR	R1, [R2]
	
	LDR	R1, =0X0000
	STR	R1, [R2]
	
	LDR	R1, =0X000B
	STR	R1, [R2]

We can now read-write to the LCD ( Novatek p.68 )
	LDR	r1, =0x0000	;set IR ( index register, 7 bits ) to 0
	STR	r1, [r0]	;write to LCD port
	ldr	r3, [r2]	;read from LCD port, we should get 0x7532
	ldr	r3, [r2]
	ldr	r3, [r2]
	ldr	r3, [r2]
	
;write data to LCD	
	LDR	r1, =0x0021	
	str	r1, [r0]	;points IR to 0x21, i.e. use R21
	
	ldr	r1, =0x0100
	str	r1, [r0]	
	BL	write_data_to_lcd
	
	LDR	r1, =0x0021
	str	r1, [r0]
	ldr	r1, =0x0200
	str	r1, [r0]	
	BL	write_data_to_lcd
	
	LDR	r1, =0x0021
	str	r1, [r0]
	ldr	r1, =0x0300
	str	r1, [r0]	
	BL	write_data_to_lcd
	
	LDR	r1, =0x0021
	str	r1, [r0]
	ldr	r1, =0x0400
	str	r1, [r0]	
	BL	write_data_to_lcd
	b	.
	
write_data_to_lcd               
	LDR	r1, =0x0022     
	str	r1, [r0]        
	mov	r3, #0          
lcd_loop	                
	ldr	r1, =0x3f3f     
	str	r1, [r2]        
	ADD	r3, r3, #1      
	CMP	r3, #0x83       
	blt	lcd_loop	                                
	MOV	pc, lr          
	
	END 

A crucial trick in bringing this to work to to first read the LCD status. Make sure that you get the value 0x7523 before you proceed further. If you get something like 0x2323, most likely your 44B0X mode has not been set to 16-bit.

The corresponding C-code is :
//lcd.c

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <linux/stddef.h>
#include <linux/sched.h>
#include <linux/config.h>
#include <linux/init.h>
#include <linux/string.h>
#include <asm/uaccess.h>

#define ADDR_INDEX 0x04000000
#define ADDR_DATA  0x04000004

#define ADDR_ARM_BOARD_DATA_BITS     0x01c80000
#define VALUE_ARM_BOARD_DATA_BITS_32 0x11110292
#define VALUE_ARM_BOARD_DATA_BITS_16 0x11110092

#define OUTL(addr,data) *(volatile unsigned long int *)(addr)=(data)
#define OUTW(addr,data) *(volatile unsigned short int*)(addr)=(data)
#define OUT_INDEX(data) OUTW(ADDR_INDEX,data)
#define OUT_DATA(data)  OUTW(ADDR_DATA,data)
#define INW(addr) *(volatile unsigned short int *)(addr)
#define INL(addr) *(volatile unsigned long  int *)(addr)

//define s3c44b0 bank num
#define BANK0 0
#define BANK1 1
#define BANK2 2
#define BANK3 3
#define BANK4 4
#define BANK5 5
#define BANK6 6
#define BANK7 7

//define s3c44b0 memory data bus width
#define BIT8  8
#define BIT16 16
#define BIT32 32

const int major = 29;
const char *name = "fb0";

unsigned long int s3c44b0_mem_ctrl;

int lcd_open(struct inode* inode,struct file* file);
int lcd_close(struct inode* inode,struct file* file);
int lcd_read(struct inode * inode,struct file* file,char* buf,int count);
int lcd_write(struct inode* inode,struct file* file,const char* buf,int count);

char buf[240][320];

struct file_operations lcd_fb =
{
     .read    = lcd_read,
     .write   = lcd_write,
     .open    = lcd_open,
     .release = lcd_close
};

inline void get_s3c44b0_mem_ctrl()
{
     s3c44b0_mem_ctrl = INL(0x01C80000);
}

int set_s3c44b0_bus_width(unsigned char bank,unsigned char bits)
{
     unsigned long int new_mem_ctrl;
     
     switch(bank)
     {
     case BANK1:
	  break;
     case BANK2:
	  new_mem_ctrl = s3c44b0_mem_ctrl & (~(0x1 << 8));
	  new_mem_ctrl = new_mem_ctrl & (~(0x1 << 9));
	  if(bits == BIT8)
	       break;
	  else if(bits == BIT16)
	       new_mem_ctrl |= (0x01 << 8);
	  else if(bits == BIT32)
	       new_mem_ctrl |= (0x01 << 9);
	  else
	       return -1;
	  break;
     case BANK3:
     case BANK4:
     case BANK5:
     case BANK6:
     case BANK7:
	  break;
     default:
	  printk("<1>john:s3c44b0 bank error\n");
	  return -1;
     }

     printk("<1>s3c44b0 new memory control value is:%x\n",new_mem_ctrl);
     OUTL(ADDR_ARM_BOARD_DATA_BITS,new_mem_ctrl);

     return 0;
};

inline void set_s3c44b0_bus_width_to_raw()
{
          OUTL(ADDR_ARM_BOARD_DATA_BITS,s3c44b0_mem_ctrl);
}

void lcd_init()
{

     DECLARE_WAIT_QUEUE_HEAD(wait_on_interrupt);

     get_s3c44b0_mem_ctrl();
     printk("<1>john:old s3c44bo mem ctrl is:%x\n",s3c44b0_mem_ctrl);

     OUT_INDEX(0x02);
     OUT_DATA(0x0400);

     OUT_INDEX(0x00);
     OUT_DATA(0x7523);

     interruptible_sleep_on_timeout(&wait_on_interrupt,1);

     OUT_INDEX(0x00);
     printk("<1>john:read start oscillation:%x\n",INW(0x04000004));

     OUT_INDEX(0x01);
     OUT_DATA(0x0213);

     OUT_INDEX(0x05);
     OUT_DATA(0x0010);

     OUT_INDEX(0x0B);
     OUT_DATA(0x0000);

     OUT_INDEX(0x16);
     OUT_DATA(0x8300);

     OUT_INDEX(0x17);
     OUT_DATA(0xAF00);

     OUT_INDEX(0x20);
     OUT_DATA(0x0000);

     OUT_INDEX(0x03);
     OUT_DATA(0x8C08);

     OUT_INDEX(0x0C);
     OUT_DATA(0x0000);

     OUT_INDEX(0x04);
     OUT_DATA(0x014B);
  
     OUT_INDEX(0x07);
     OUT_DATA(0x0003);
}

static int __init my_init(void)
{
     lcd_init();

     register_chrdev(major,name,&lcd_fb);  

     return 0;
}

static void __exit my_cleanup(void)
{
     if(!MOD_IN_USE)
	  unregister_chrdev(major,name);
}


int lcd_open(struct inode* inode,struct file* file)
{
     MOD_INC_USE_COUNT;
     return 0;
}

int lcd_close(struct inode* inode,struct file* file)
{
     MOD_DEC_USE_COUNT;

     return 0;
}

int lcd_read(struct inode * inode,struct file* file,char* buf,int count)
{
     return 0;
}

int lcd_write(struct inode* inode,struct file* file,const char* buf,int count)
{
    int row_cur,col_cur;
    unsigned  short tmp;
    int i = 0;

    row_cur = 0x4F;
    while(row_cur<0x7F)
    {
	 col_cur = 0x10;

	 OUTL(0x01c80000,0x11110292); //set s3c44b0 to 32 bits
	 OUTW(0x04000000,0x21);
	 OUTW(0x04000002,(col_cur<<8)|row_cur);

	 OUTW(0x04000000,0x22);

	 while(col_cur<0x48F)
	 {
	      OUTW(0x04000002,0x0000);
	      col_cur++;
	 }
	 row_cur++;
    }

    row_cur = 0x4F;
    while(row_cur<0x7F)
    {
	 col_cur = 0x10;

	 OUTL(0x01c80000,0x11110292); //set s3c44b0 to 32 bits
	 OUTW(0x04000000,0x21);
	 OUTW(0x04000002,(col_cur<<8)|row_cur);

	 OUTW(0x04000000,0x22);

	 while(col_cur<0x48F)
	 {
	      OUTW(0x04000002,0x0000);
	      col_cur++;
	 }
	 row_cur++;
    }

   row_cur = 0x4F;
   col_cur = 0x10;
   while(row_cur < 0x7F)
   {
	col_cur = 0x6F;

	while(col_cur < 0x8F)
	{
	     i = (col_cur<<8 | row_cur);

	     OUTW(0x04000000,0x21);
	     OUTW(0x04000002,i);

	     OUTW(0x04000000,0x22);
     
	     if((tmp = INW(0x04000002)) != 0 && tmp != 0x4b4b)
	     {
		  printk("<1>row=%x col=%x pixel=%x\n",row_cur,col_cur,tmp);
	     }
	     col_cur++;
	}

	row_cur++;
   }

    return 0;
}

module_init(my_init);
module_exit(my_cleanup);
EXPORT_NO_SYMBOLS;


//demo.c #include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <unistd.h> #define OUTW(addr,data) *(volatile unsigned short int*)addr=(short int)(data) #define OUTL(addr,data) *(volatile unsigned long int*)addr=(short int)(data) #define INW(addr) *(volatile unsigned short int*)addr int main() { int fd; char *data="232323423423"; int i = 0; char input[20]; int pos = 0; unsigned short int tmp = 0; int res; int times=0; int row,col; int row_cur,col_cur; int count = 0; unsigned color[] = {0x0000,0xF800,0x07E0,0xFFFF}; unsigned color_cur = 0; printf("mem ctrl is:%x\n",*(volatile unsigned long *)0x01c80000); printf("draw background........................\n"); row_cur = 0x00; while(row_cur<0x83) { col_cur = 0x00; // OUTL(0x01c80000,0x11110292); //set s3c44b0 to 32 bits while(col_cur<0xAF) { OUTW(0x04000000,0x22); OUTW(0x04000004,0x07E0); //green // OUTW(0x04000004,0xF800); //red // OUTW(0x04000004,0x0000); col_cur++; } row_cur++; } //DRAW LINE row_cur = 0x10; while(row_cur < 0x12) { col_cur = 0x30; while(col_cur < 0x80) { OUTW(0x04000000,0x21);; OUTW(0x04000004,(col_cur<<8)|row_cur); OUTW(0x04000000,0x22); OUTW(0x04000004,0xF800);//red col_cur++; } row_cur++; } printf("draw image...................\n"); while(1) { row_cur = 0x20; while(row_cur < 0x60) { col_cur= 0x30; while(col_cur < 0x80) { OUTW(0x04000000,0x21); OUTW(0x04000004,(col_cur<<8)|row_cur); OUTW(0x04000000,0x22); OUTW(0x04000004,color[color_cur]); //red col_cur++; } row_cur++; } color_cur++; color_cur %= sizeof(color)/sizeof(color[0]); sleep(1); } printf("write data ok!\n"); printf("application over!\n"); return 0; }

Notes:
software flow:

  1. Set ARM memory controller data bus width. We can set the width during the initialization of the bootloader. Details can be found in /linux-2.4.x/init/main.c We add in the function asmlinkage void __init start_kernel ( void ) the following piece of code *(volatile unsigned long *) 0x01c80000 = 0x11110292; where 0x01c80000 is the address of memory controller special register of s3c44b0x ( see SC3C44B0X.pdf, p.163-164)
  2. In init_module, set register values according to document LCD WM-1216VE-(-).pdf p. 9-10. We first set the value of INDEX which points to a register ( Rxx ); we then set the value of the register.
  3. Write the application demo.c. We can directly write to the LCD screen lines and figures. When sending information to the screen, we first set the coordinates and then send the data ( see LCD WM-1216VE-().pdf and T7532_0.3.pdf, p.52-69 )
  4. In demo add functions open, close, write, read, iocrtl.
  5. Rewrite demo. Display geometrical shapes using framebuffer.

NT7523 LCD Framebuffer Driver for S3C44B0X

Hints and Notes

It is very important that the driver should set the memory address bus of the S3C44B0X to 32bits. Otherwise, data access will have error.

The screen size of the LCD is 176 x 132. The LCD's DRAM address (0,0) has mapped with pixel address (0,0), so it is more easy to understand.

The framebuffer driver should reserve a (176x132x16 / 8) bytes memory for framebuffer. The interface of the LCD controller doesn't support DMA, so we need to reserve memory for buffer from the SDRAM. Moreover, the LCD controller doesn't support memory map so we need to update display by a special call.

The framebuffer has a method call nt7523_redraw. It is used to copy the content from board's SDRAM to LCD's DRAM. The programmer can use the framebuffer's ioctl call.

Eg.
	//nt7523.h
        #define FBIO_SCREEN_UPDATE 0x8000
	int fbfd = 0;
	char * param;

        fbfd = open("/dev/fb0", O_RDWR);
        if (!fbfd) {
                printf("Error: cannot open framebuffer device.\n");
        } else {
              ioctl(fbfd, FBIO_SCREEN_UPDATE, ¶m);
        }

        close(fbfd);

Because of this special call, the framebuffer program doesn't know that it needs to call this frame update method. Therefore, I have written a simple program which loop infinitely to update the screen. You can run it as a background proccess by

> nt7523d &

If the programmer has written a high level GUI program, he can call this method without running the background process when the program has finished painting.

Utility

I have written a tool to control the register inside the LCD's control. The usage is as following

nt7523u [r/w] [register] [data]

The numerical value is in 10 base.
r: read
w: write
Eg.
> nt7523u r 0
It should show
7523

The tool has another function that it can test the color of the LCD display. Please terminate the looping process because it will overwrite the color at the LCD's DRAM.

>nt7523u [RED/BLUE/GREEN/WHITE]
The whole screen should change the color according to the command.
Kernel Configuration
  1. Add a choice into the Linux Kernal Configuration (make Menuconfig)
    i) vi linux-2.4.x/drivers/video/Config.in
    ii) Add a new entry as below
    .
    .
    if [ "$CONFIG_CPU_S3C44B0X" = "y" ]; then
    tristate ' NT7523 LCD controller frame buffer support for S3C44B0X ' CONFIG_FB_NT7523
    fi
    .
    .
    (Note: search S3C44B0X, you can find the location)
  2. Modify Makefile for video (NT7523)
    i) vi linux-2.4.x/drivers/video/Makefile
    and add a new line for compilation
    obj-$(CONFIG_FB_NT7523) += nt7523fb.o
  3. Modify linux-2.4.x/drivers/video/fbmem.c
    i) Add a new driver
    .
    .
    extern int s3c44b0xfb_init(void);
    extern int s3c44b0xfb_setup(char*);
    extern int nt7523fb_init(void);    //Add this
    extern int nt7523fb_setup(char*);  //Add this
    .
    .
    #ifdef CONFIG_FB_S3C44B0X
            { "s3c44b0xfb", s3c44b0xfb_init, s3c44b0xfb_setup },
    #endif
    //Add following lines
    #ifdef CONFIG_FB_NT7523
            { "nt7523fb", nt7523fb_init, nt7523fb_setup },
    #endif
    .
    .
    
Howto write the NT7523 framebuffer driver
  1. cp linux-2.4.x/drivers/video/s3c44b0xfb.c linux-2.4.x/drivers/video/nt7523fb.c
    cp linux-2.4.x/drivers/video/s3c44b0xfb.h linux-2.4.x/drivers/video/nt7523fb.h
  2. vi linux-2.4.x/drivers/video/nt7523fb.h
    Make change as following
    .
    .
    #ifndef NT7523FB_H
    #define NT7523FB_H
    .
    .
    #define CMAP_SIZE       30
    #define SCR_XSIZE       176
    #define SCR_YSIZE       132
    #define LCD_XSIZE       176
    #define LCD_YSIZE       132
    #define LCD_DEPTH       16
    #define LCD_BUF_SIZE    ((SCR_XSIZE*SCR_YSIZE*2)) /* 2bytes per pixel*/
    #define FBIO_SCREEN_UPDATE      0x8000
    #define ADDR_INDEX 0x04000000
    #define ADDR_DATA  0x04000004
    #define OUTL(addr,data) *(volatile unsigned long int *)(addr)=(data)
    #define OUTW(addr,data) *(volatile unsigned short int*)(addr)=(data)
    #define OUT_INDEX(data) OUTW(ADDR_INDEX,data)
    #define OUT_DATA(data)  OUTW(ADDR_DATA,data)
    #define IN_DATA() *(volatile unsigned short int *)(ADDR_DATA)
    #define INW(addr) *(volatile unsigned short int *)(addr)
    #define INL(addr) *(volatile unsigned long  int *)(addr)
    
  3. vi linux-2.4.x/drivers/video/nt7523fb.c
    Make change as following

    a) Search #ifdef MODULE
    .
    .
    #ifdef MODULE
    module_init(nt7523fb_init);
    module_exit(nt7523fb_exit);
    #endif
    .
    .
    
    b) change method call name

    s3c44b0xfb_exit(void) --> nt7523fb_exit(void)
    s3c44b0xfb_setup(char *options) --> nt7523fb_setup(char *options)
    s3c44b0xfb_init(void) --> nt7523fb_init(void)

    c) include the header
    #include "nt7523fb.h" d) 32bit memory address control for S3C44BOX

    inline void setup_s3c44b0x_mem_ctrl()
    {
            unsigned int data = inl(S3C44B0X_BWSCON);
            outl( (data&0xFFFFFCFF)|S3C44B0X_BWSCON_DW2_32, S3C44B0X_BWSCON);
    }
    
    e) User defined part
    static int
    s3c44b0fb_set_var(struct fb_var_screeninfo *var, int con,
                       struct fb_info *info)
    {
    .
    .
            var->transp.msb_right   = 0;
            var->transp.offset      = 0;
            var->transp.length      = 0;
            var->red.msb_right      = 0;
            var->red.offset         = 11;
            var->red.length         = 5;
            var->green.msb_right    = 0;
            var->green.offset       = 5;
            var->green.length       = 6;
            var->blue.msb_right     = 0;
            var->blue.offset        = 0;
            var->blue.length        = 5;
    
            switch (var->bits_per_pixel) {
    #ifdef FBCON_HAS_CFB16
            case 16:
                    cfb->fb.fix.visual      = FB_VISUAL_PSEUDOCOLOR;//FB_VISUAL_TRUECOLOR;
                    display->dispsw         = &fbcon_cfb16;
                    display->dispsw_data    = NULL;
                    break;
    #endif
            default:
                    return -EINVAL;
            }
    
    f) Copy Data from memory buffer to LCD's DRAM
    static int nt7523_redraw() {
            //Full screen redraw
            int count=0;
            int SIZE = LCD_XSIZE * LCD_YSIZE;
            unsigned short int *buf = (unsigned short int *)(cfb->fb.screen_base);
            OUT_INDEX(0x21);
            OUT_DATA(0x0);
    
            OUT_INDEX(0x22);
            while(count
    
    g) IO Control
    static int nt7523fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
                            u_long arg, int con, struct fb_info *info)
    {
    .
    .
            switch (cmd){
            case FBIO_SCREEN_UPDATE:
                    nt7523_redraw();
                    break;
    .
    .
    }
    
    h) Method mapping
    static struct fb_ops s3c44b0fb_ops = {
            owner:          THIS_MODULE,
            fb_set_var:     s3c44b0fb_set_var,
            fb_set_cmap:    s3c44b0fb_set_cmap,
            fb_get_fix:     gen_get_fix,
            fb_get_var:     gen_get_var,
            fb_get_cmap:    gen_get_cmap,
            fb_ioctl:       nt7523fb_ioctl,
    };
    
    i) Initialization
    
    int __init nt7523fb_init(void)
    {
    .
    .
    .
            cfb->fb.disp            = (struct display *)(cfb + 1);
    
            fb_alloc_cmap(&cfb->fb.cmap, CMAP_SIZE, 0);
    
            /*
             * Power up the LCD
             */
            setup_s3c44b0x_mem_ctrl();
    
            //Start Oscilation
            OUT_INDEX(0x0000);
            OUT_DATA(0x7523);
    
            //interruptible_sleep_on_timeout(&wait_on_interrupt,1);
            mdelay(15); //10ms
            //LCD Driving Waveform control
            OUT_INDEX(0x0002);
            OUT_DATA(0x0400);
            mdelay(1);
    
            OUT_INDEX(0x00);
            printk("<1>john:read start oscillation:%x\n",INW(ADDR_DATA));
            //Driver Output Control
            OUT_INDEX(0x0001);
            OUT_DATA(0x0215);
            //Entry Mode
            OUT_INDEX(0x0005);
            OUT_DATA(0x0028);
            //Frame Cycle Control
            OUT_INDEX(0x000B);
            OUT_DATA(0x0000);
            //Horizontal RAM Address Position
            OUT_INDEX(0x0016);
            OUT_DATA(0x8300);
            //Vertical RAM Address Position
            OUT_INDEX(0x0017);
            OUT_DATA(0xAF00); //Don't change it
            //RAM Write Data Mask
            OUT_INDEX(0x0020);
            OUT_DATA(0x0000);
            //Power Control 1
            OUT_INDEX(0x0003);
            OUT_DATA(0x8c08);
            //Power Control 2
            OUT_INDEX(0x000c);
            OUT_DATA(0x0000);
            //Contrast Control
            OUT_INDEX(0x0004);
            OUT_DATA(0x0168);
            //Display Control
            OUT_INDEX(0x0007);
            OUT_DATA(0x0003);