diff options
author | Linus Nielsen Feltzing <linus@haxx.se> | 2006-07-31 23:00:13 +0000 |
---|---|---|
committer | Linus Nielsen Feltzing <linus@haxx.se> | 2006-07-31 23:00:13 +0000 |
commit | c255073fb8d7d6e9433010d2a29c6e648db15d10 (patch) | |
tree | fcceab95ea13555ed717f0bfe2320a443cff922d /firmware/target/coldfire/iaudio | |
parent | 8630f072e9b544cb9b58291fe3a60daccc899d46 (diff) | |
download | rockbox-c255073fb8d7d6e9433010d2a29c6e648db15d10.tar.gz rockbox-c255073fb8d7d6e9433010d2a29c6e648db15d10.zip |
Patch #5740 by Mike Sevakis - X5 LCD performance enhancements
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@10390 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/coldfire/iaudio')
-rwxr-xr-x | firmware/target/coldfire/iaudio/x5/lcd-x5.c | 502 |
1 files changed, 326 insertions, 176 deletions
diff --git a/firmware/target/coldfire/iaudio/x5/lcd-x5.c b/firmware/target/coldfire/iaudio/x5/lcd-x5.c index c06521ef54..2e3e785d73 100755 --- a/firmware/target/coldfire/iaudio/x5/lcd-x5.c +++ b/firmware/target/coldfire/iaudio/x5/lcd-x5.c | |||
@@ -30,72 +30,59 @@ | |||
30 | #include "font.h" | 30 | #include "font.h" |
31 | #include "bidi.h" | 31 | #include "bidi.h" |
32 | 32 | ||
33 | static bool display_on=false; /* is the display turned on? */ | 33 | /* Is the display turned on? */ |
34 | static bool display_on = false; | ||
34 | 35 | ||
36 | /* Amount of vertical offset. Used for offset correction when flipped. */ | ||
37 | static int y_offset = 0; | ||
38 | |||
39 | /* Amount of roll offset (0-127). */ | ||
40 | static int roll_offset = 0; | ||
41 | |||
42 | /* A15(0x8000) && CS1->CS, A1(0x0002)->RS */ | ||
35 | #define LCD_CMD *(volatile unsigned short *)0xf0008000 | 43 | #define LCD_CMD *(volatile unsigned short *)0xf0008000 |
36 | #define LCD_DATA *(volatile unsigned short *)0xf0008002 | 44 | #define LCD_DATA *(volatile unsigned short *)0xf0008002 |
37 | 45 | ||
38 | /* register defines for the Renesas HD66773R */ | 46 | /* register defines for the Renesas HD66773R */ |
47 | #define R_START_OSC 0x00 | ||
48 | #define R_DEVICE_CODE_READ 0x00 | ||
49 | #define R_DRV_OUTPUT_CONTROL 0x01 | ||
50 | #define R_DRV_AC_CONTROL 0x02 | ||
51 | #define R_POWER_CONTROL1 0x03 | ||
52 | #define R_POWER_CONTROL2 0x04 | ||
53 | #define R_ENTRY_MODE 0x05 | ||
54 | #define R_COMPARE_REG 0x06 | ||
55 | #define R_DISP_CONTROL 0x07 | ||
56 | #define R_FRAME_CYCLE_CONTROL 0x0b | ||
57 | #define R_POWER_CONTROL3 0x0c | ||
58 | #define R_POWER_CONTROL4 0x0d | ||
59 | #define R_POWER_CONTROL5 0x0e | ||
60 | #define R_GATE_SCAN_START_POS 0x0f | ||
61 | #define R_VERT_SCROLL_CONTROL 0x11 | ||
62 | #define R_1ST_SCR_DRV_POS 0x14 | ||
63 | #define R_2ND_SCR_DRV_POS 0x15 | ||
39 | #define R_HORIZ_RAM_ADDR_POS 0x16 | 64 | #define R_HORIZ_RAM_ADDR_POS 0x16 |
40 | #define R_VERT_RAM_ADDR_POS 0x17 | 65 | #define R_VERT_RAM_ADDR_POS 0x17 |
66 | #define R_RAM_WRITE_DATA_MASK 0x20 | ||
41 | #define R_RAM_ADDR_SET 0x21 | 67 | #define R_RAM_ADDR_SET 0x21 |
42 | #define R_WRITE_DATA_2_GRAM 0x22 | 68 | #define R_WRITE_DATA_2_GRAM 0x22 |
43 | 69 | #define R_RAM_READ_DATA 0x22 | |
44 | /***************************************************** | 70 | #define R_GAMMA_FINE_ADJ_POS1 0x30 |
45 | The table below was generated by the following script: | 71 | #define R_GAMMA_FINE_ADJ_POS2 0x31 |
46 | 72 | #define R_GAMMA_FINE_ADJ_POS3 0x32 | |
47 | #!/usr/bin/perl | 73 | #define R_GAMMA_GRAD_ADJ_POS 0x33 |
48 | 74 | #define R_GAMMA_FINE_ADJ_NEG1 0x34 | |
49 | # high byte table | 75 | #define R_GAMMA_FINE_ADJ_NEG2 0x35 |
50 | print "short high8to9[] = {\n"; | 76 | #define R_GAMMA_FINE_ADJ_NEG3 0x36 |
51 | $str = " "; | 77 | #define R_GAMMA_GRAD_ADJ_NEG 0x37 |
52 | for my $m (0 .. 255) { | 78 | #define R_GAMMA_AMP_ADJ_POS 0x3a |
53 | # RRRRRGGG => RRRRR0GGG | 79 | #define R_GAMMA_AMP_ADJ_NEG 0x3b |
54 | my $v = (($m & 0xF8) << 1) | ($m & 0x07); | ||
55 | if(length($str) > 75) { | ||
56 | print "$str\n"; | ||
57 | $str=" "; | ||
58 | } | ||
59 | $str .= sprintf("0x%03x, ", $v); | ||
60 | } | ||
61 | print "$str\n};\n"; | ||
62 | |||
63 | *****************************************************/ | ||
64 | |||
65 | /* Lookup table for 16->18bit conversion, high byte. The low byte is just | ||
66 | shifted. */ | ||
67 | const short high8to9[] ICONST_ATTR = { | ||
68 | 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, 0x010, 0x011, 0x012, | ||
69 | 0x013, 0x014, 0x015, 0x016, 0x017, 0x020, 0x021, 0x022, 0x023, 0x024, 0x025, | ||
70 | 0x026, 0x027, 0x030, 0x031, 0x032, 0x033, 0x034, 0x035, 0x036, 0x037, 0x040, | ||
71 | 0x041, 0x042, 0x043, 0x044, 0x045, 0x046, 0x047, 0x050, 0x051, 0x052, 0x053, | ||
72 | 0x054, 0x055, 0x056, 0x057, 0x060, 0x061, 0x062, 0x063, 0x064, 0x065, 0x066, | ||
73 | 0x067, 0x070, 0x071, 0x072, 0x073, 0x074, 0x075, 0x076, 0x077, 0x080, 0x081, | ||
74 | 0x082, 0x083, 0x084, 0x085, 0x086, 0x087, 0x090, 0x091, 0x092, 0x093, 0x094, | ||
75 | 0x095, 0x096, 0x097, 0x0a0, 0x0a1, 0x0a2, 0x0a3, 0x0a4, 0x0a5, 0x0a6, 0x0a7, | ||
76 | 0x0b0, 0x0b1, 0x0b2, 0x0b3, 0x0b4, 0x0b5, 0x0b6, 0x0b7, 0x0c0, 0x0c1, 0x0c2, | ||
77 | 0x0c3, 0x0c4, 0x0c5, 0x0c6, 0x0c7, 0x0d0, 0x0d1, 0x0d2, 0x0d3, 0x0d4, 0x0d5, | ||
78 | 0x0d6, 0x0d7, 0x0e0, 0x0e1, 0x0e2, 0x0e3, 0x0e4, 0x0e5, 0x0e6, 0x0e7, 0x0f0, | ||
79 | 0x0f1, 0x0f2, 0x0f3, 0x0f4, 0x0f5, 0x0f6, 0x0f7, 0x100, 0x101, 0x102, 0x103, | ||
80 | 0x104, 0x105, 0x106, 0x107, 0x110, 0x111, 0x112, 0x113, 0x114, 0x115, 0x116, | ||
81 | 0x117, 0x120, 0x121, 0x122, 0x123, 0x124, 0x125, 0x126, 0x127, 0x130, 0x131, | ||
82 | 0x132, 0x133, 0x134, 0x135, 0x136, 0x137, 0x140, 0x141, 0x142, 0x143, 0x144, | ||
83 | 0x145, 0x146, 0x147, 0x150, 0x151, 0x152, 0x153, 0x154, 0x155, 0x156, 0x157, | ||
84 | 0x160, 0x161, 0x162, 0x163, 0x164, 0x165, 0x166, 0x167, 0x170, 0x171, 0x172, | ||
85 | 0x173, 0x174, 0x175, 0x176, 0x177, 0x180, 0x181, 0x182, 0x183, 0x184, 0x185, | ||
86 | 0x186, 0x187, 0x190, 0x191, 0x192, 0x193, 0x194, 0x195, 0x196, 0x197, 0x1a0, | ||
87 | 0x1a1, 0x1a2, 0x1a3, 0x1a4, 0x1a5, 0x1a6, 0x1a7, 0x1b0, 0x1b1, 0x1b2, 0x1b3, | ||
88 | 0x1b4, 0x1b5, 0x1b6, 0x1b7, 0x1c0, 0x1c1, 0x1c2, 0x1c3, 0x1c4, 0x1c5, 0x1c6, | ||
89 | 0x1c7, 0x1d0, 0x1d1, 0x1d2, 0x1d3, 0x1d4, 0x1d5, 0x1d6, 0x1d7, 0x1e0, 0x1e1, | ||
90 | 0x1e2, 0x1e3, 0x1e4, 0x1e5, 0x1e6, 0x1e7, 0x1f0, 0x1f1, 0x1f2, 0x1f3, 0x1f4, | ||
91 | 0x1f5, 0x1f6, 0x1f7, | ||
92 | }; | ||
93 | 80 | ||
94 | /* called very frequently - inline! */ | 81 | /* called very frequently - inline! */ |
95 | inline void lcd_write_reg(int reg, int val) | 82 | inline void lcd_write_reg(int reg, int val) |
96 | { | 83 | { |
97 | LCD_CMD = (reg >> 8) << 1; | 84 | LCD_CMD = 0x0000; /* MSB is ~always~ 0 */ |
98 | LCD_CMD = (reg & 0xff) << 1; | 85 | LCD_CMD = reg << 1; |
99 | LCD_DATA = (val >> 8) << 1; | 86 | LCD_DATA = (val >> 8) << 1; |
100 | LCD_DATA = (val & 0xff) << 1; | 87 | LCD_DATA = (val & 0xff) << 1; |
101 | } | 88 | } |
@@ -103,38 +90,29 @@ inline void lcd_write_reg(int reg, int val) | |||
103 | /* called very frequently - inline! */ | 90 | /* called very frequently - inline! */ |
104 | inline void lcd_begin_write_gram(void) | 91 | inline void lcd_begin_write_gram(void) |
105 | { | 92 | { |
106 | LCD_CMD = (R_WRITE_DATA_2_GRAM >> 8) << 1; | 93 | LCD_CMD = 0x0000; |
107 | LCD_CMD = (R_WRITE_DATA_2_GRAM & 0xff) << 1; | 94 | LCD_CMD = R_WRITE_DATA_2_GRAM << 1; |
108 | } | 95 | } |
109 | 96 | ||
110 | /* called very frequently - inline! */ | 97 | static inline void lcd_write_one(unsigned short px) |
111 | inline void lcd_write_data(const unsigned short* p_bytes, int count) ICODE_ATTR; | ||
112 | inline void lcd_write_data(const unsigned short* p_bytes, int count) | ||
113 | { | 98 | { |
114 | unsigned int tmp; | 99 | unsigned short pxsr = px >> 8; |
115 | unsigned int *ptr = (unsigned int *)p_bytes; | 100 | LCD_DATA = pxsr + (pxsr & 0x1F8); |
116 | bool extra; | 101 | LCD_DATA = px << 1; |
117 | |||
118 | /* if there's on odd number of pixels, remmber this and output the | ||
119 | trailing pixel after the loop */ | ||
120 | extra = (count&1)?true:false; | ||
121 | |||
122 | count >>= 1; | ||
123 | while(count--) { | ||
124 | tmp = *ptr++; | ||
125 | LCD_DATA = high8to9[tmp >> 24]; | ||
126 | LCD_DATA = tmp>>15; | ||
127 | LCD_DATA = high8to9[(tmp >> 8)&255]; | ||
128 | LCD_DATA = tmp<<1; | ||
129 | } | ||
130 | if(extra) { | ||
131 | /* the final "spare" pixel */ | ||
132 | unsigned short read = *(unsigned short *)ptr; | ||
133 | LCD_DATA = high8to9[read >> 8]; | ||
134 | LCD_DATA = read<<1; | ||
135 | } | ||
136 | } | 102 | } |
137 | 103 | ||
104 | /* Write two pixels to gram from a long */ | ||
105 | /* called very frequently - inline! */ | ||
106 | static inline void lcd_write_two(unsigned long px2) | ||
107 | { | ||
108 | unsigned short px2sr = px2 >> 24; | ||
109 | LCD_DATA = px2sr + (px2sr & 0x1F8); | ||
110 | LCD_DATA = px2 >> 15; | ||
111 | px2sr = px2 >> 8; | ||
112 | LCD_DATA = px2sr + (px2sr & 0x1F8); | ||
113 | LCD_DATA = px2 << 1; | ||
114 | } | ||
115 | |||
138 | /*** hardware configuration ***/ | 116 | /*** hardware configuration ***/ |
139 | 117 | ||
140 | int lcd_default_contrast(void) | 118 | int lcd_default_contrast(void) |
@@ -152,18 +130,26 @@ void lcd_set_contrast(int val) | |||
152 | else if (val > 30) | 130 | else if (val > 30) |
153 | val = 30; | 131 | val = 30; |
154 | 132 | ||
155 | lcd_write_reg(0x0e, 0x2018 + (val << 8)); | 133 | lcd_write_reg(R_POWER_CONTROL5, 0x2018 + (val << 8)); |
156 | } | 134 | } |
157 | 135 | ||
158 | void lcd_set_invert_display(bool yesno) | 136 | void lcd_set_invert_display(bool yesno) |
159 | { | 137 | { |
160 | (void)yesno; | 138 | /* PT1-0=00, VLE2-1=00, SPT=0, GON=1, DTE=1, REV=x, D1-0=11 */ |
139 | lcd_write_reg(R_DISP_CONTROL, yesno ? 0x0033 : 0x0037); | ||
161 | } | 140 | } |
162 | 141 | ||
163 | /* turn the display upside down (call lcd_update() afterwards) */ | 142 | /* turn the display upside down (call lcd_update() afterwards) */ |
164 | void lcd_set_flip(bool yesno) | 143 | void lcd_set_flip(bool yesno) |
165 | { | 144 | { |
166 | (void)yesno; | 145 | y_offset = yesno ? 4 : 0; |
146 | /* SCN4-0=000x0 (G160) */ | ||
147 | lcd_write_reg(R_GATE_SCAN_START_POS, yesno ? 0x0000 : 0x0002); | ||
148 | /* SM=0, GS=x, SS=x, NL4-0=10011 (G1-G160)*/ | ||
149 | lcd_write_reg(R_DRV_OUTPUT_CONTROL, yesno ? 0x0013 : 0x0313); | ||
150 | /* Vertical stripe */ | ||
151 | /* HEA7-0=0xxx, HSA7-0=0xxx */ | ||
152 | lcd_write_reg(R_HORIZ_RAM_ADDR_POS, 0x7f00 + (y_offset << 8) + y_offset); | ||
167 | } | 153 | } |
168 | 154 | ||
169 | /* Rolls up the lcd display by the specified amount of lines. | 155 | /* Rolls up the lcd display by the specified amount of lines. |
@@ -172,19 +158,22 @@ void lcd_set_flip(bool yesno) | |||
172 | * remapping only and all operations on the lcd are affected. | 158 | * remapping only and all operations on the lcd are affected. |
173 | * -> | 159 | * -> |
174 | * @param int lines - The number of lines that are rolled. | 160 | * @param int lines - The number of lines that are rolled. |
175 | * The value must be 0 <= pixels < LCD_HEIGHT. */ | 161 | * The value must be 0 <= pixels < LCD_HEIGHT. |
162 | * Call lcd_update() afterwards */ | ||
176 | void lcd_roll(int lines) | 163 | void lcd_roll(int lines) |
177 | { | 164 | { |
178 | (void)lines; | 165 | /* Just allow any value mod LCD_HEIGHT-1. Assumes LCD_HEIGHT == 128. */ |
166 | if (lines < 0) | ||
167 | lines = -lines & 127; | ||
168 | else | ||
169 | lines = (128 - (lines & 127)) & 127; | ||
170 | |||
171 | roll_offset = lines; | ||
179 | } | 172 | } |
180 | 173 | ||
181 | /* LCD init | 174 | /* LCD init */ |
182 | * These settings are taken from the original X5 firmware | ||
183 | */ | ||
184 | void lcd_init_device(void) | 175 | void lcd_init_device(void) |
185 | { | 176 | { |
186 | display_on=true; | ||
187 | |||
188 | /* LCD Reset */ | 177 | /* LCD Reset */ |
189 | and_l(~0x00000010, &GPIO1_OUT); | 178 | and_l(~0x00000010, &GPIO1_OUT); |
190 | or_l(0x00000010, &GPIO1_ENABLE); | 179 | or_l(0x00000010, &GPIO1_ENABLE); |
@@ -194,60 +183,105 @@ void lcd_init_device(void) | |||
194 | 183 | ||
195 | sleep(HZ/100); | 184 | sleep(HZ/100); |
196 | 185 | ||
197 | lcd_write_reg(0, 0x0001); | 186 | /** Power ON Sequence **/ |
198 | 187 | /* Per datasheet Rev.1.10, Jun.21.2003, p. 99 */ | |
199 | sleep(HZ/50); | ||
200 | |||
201 | lcd_write_reg(0x0d, 0x0401); | ||
202 | lcd_write_reg(0x0e, 0x321e); | ||
203 | lcd_write_reg(0x01, 0x0313); | ||
204 | lcd_write_reg(0x02, 0x0700); | ||
205 | lcd_write_reg(0x05, 0x9038); | ||
206 | lcd_write_reg(0x06, 0x0000); | ||
207 | lcd_write_reg(0x0b, 0x4000); | ||
208 | |||
209 | sleep(HZ/100); | ||
210 | |||
211 | lcd_write_reg(0x21,0x0000); | ||
212 | lcd_write_reg(0x30,0x0003); | ||
213 | lcd_write_reg(0x31,0x0400); | ||
214 | lcd_write_reg(0x32,0x0407); | ||
215 | lcd_write_reg(0x33,0x0305); | ||
216 | lcd_write_reg(0x34,0x0003); | ||
217 | lcd_write_reg(0x35,0x0704); | ||
218 | lcd_write_reg(0x36,0x0407); | ||
219 | lcd_write_reg(0x37,0x0503); | ||
220 | lcd_write_reg(0x0f,0x0002); | ||
221 | lcd_write_reg(0x11,0x0000); | ||
222 | lcd_write_reg(0x14,0x9f00); | ||
223 | lcd_write_reg(0x15,0x5c00); | ||
224 | lcd_write_reg(0x16,0x7f00); | ||
225 | lcd_write_reg(0x17,0x9f00); | ||
226 | lcd_write_reg(0x3a,0x1409); | ||
227 | lcd_write_reg(0x3b,0x0602); | ||
228 | |||
229 | lcd_write_reg(0x0c,0x0001); | ||
230 | 188 | ||
189 | lcd_write_reg(R_START_OSC, 0x0001); /* Start Oscillation */ | ||
190 | /* 10ms or more for oscillation circuit to stabilize */ | ||
191 | sleep(HZ/50); | ||
192 | /* Instruction (1) for power setting; VC2-0, VRH3-0, CAD, | ||
193 | VRL3-0, VCM4-0, VDV4-0 */ | ||
194 | /* VC2-0=001 */ | ||
195 | lcd_write_reg(R_POWER_CONTROL3, 0x0001); | ||
196 | /* VRL3-0=0100, PON=0, VRH3-0=0001 */ | ||
197 | lcd_write_reg(R_POWER_CONTROL4, 0x0401); | ||
198 | /* CAD=1 */ | ||
199 | lcd_write_reg(R_POWER_CONTROL2, 0x8000); | ||
200 | /* VCOMG=0, VDV4-0=10011 (19), VCM4-0=11000 */ | ||
201 | lcd_write_reg(R_POWER_CONTROL5, 0x1318); | ||
202 | /* Instruction (2) for power setting; BT2-0, DC2-0, AP2-0 */ | ||
203 | /* BT2-0=000, DC2-0=001, AP2-0=011, SLP=0, STB=0 */ | ||
204 | lcd_write_reg(R_POWER_CONTROL1, 0x002c); | ||
205 | /* Instruction (3) for power setting; VCOMG = "1" */ | ||
206 | /* VCOMG=1, VDV4-0=10011 (19), VCM4-0=11000 */ | ||
207 | lcd_write_reg(R_POWER_CONTROL5, 0x3318); | ||
208 | |||
209 | /* 40ms or more; time for step-up circuits 1,2 to stabilize */ | ||
231 | sleep(HZ/25); | 210 | sleep(HZ/25); |
232 | |||
233 | lcd_write_reg(0x03,0x002c); | ||
234 | lcd_write_reg(0x04,0x8000); | ||
235 | 211 | ||
236 | sleep(HZ/25); | 212 | /* Instruction (4) for power setting; PON = "1" */ |
237 | 213 | /* VRL3-0=0100, PON=1, VRH3-0=0001 */ | |
238 | lcd_write_reg(0x0e,0x3318); | 214 | lcd_write_reg(R_POWER_CONTROL4, 0x0411); |
239 | 215 | ||
216 | /* 40ms or more; time for step-up circuit 4 to stabilize */ | ||
240 | sleep(HZ/25); | 217 | sleep(HZ/25); |
241 | |||
242 | lcd_write_reg(0x0d,0x0411); | ||
243 | 218 | ||
244 | sleep(HZ/100); | 219 | /* Instructions for other mode settings (in register order). */ |
245 | 220 | /* SM=0, GS=1, SS=1, NL4-0=10011 (G1-G160)*/ | |
246 | lcd_write_reg(0x07,0x0006); | 221 | lcd_write_reg(R_DRV_OUTPUT_CONTROL, 0x313); |
247 | lcd_write_reg(0x07,0x036); | 222 | /* FLD1-0=01 (1 field), B/C=1, EOR=1 (C-pat), NW5-0=000000 (1 row) */ |
248 | lcd_write_reg(0x07,0x037); | 223 | lcd_write_reg(R_DRV_AC_CONTROL, 0x0700); |
249 | lcd_write_reg(0x07,0x0037); | 224 | /* DIT=1, BGR=1, HWM=0, I/D1-0=11, AM=1, LG2-0=000 */ |
250 | return; | 225 | lcd_write_reg(R_ENTRY_MODE, 0x9038); |
226 | /* CP15-0=0000000000000000 */ | ||
227 | lcd_write_reg(R_COMPARE_REG, 0x0000); | ||
228 | /* NO1-0=01, SDT1-0=00, EQ1-0=00, DIV1-0=00, RTN3-00000 */ | ||
229 | lcd_write_reg(R_FRAME_CYCLE_CONTROL, 0x4000); | ||
230 | /* SCN4-0=00010 (G160) */ | ||
231 | lcd_write_reg(R_GATE_SCAN_START_POS, 0x0002); | ||
232 | /* VL7-0=0x00 */ | ||
233 | lcd_write_reg(R_VERT_SCROLL_CONTROL, 0x0000); | ||
234 | /* SE17-10(End)=0x9f (159), SS17-10(Start)=0x00 */ | ||
235 | lcd_write_reg(R_1ST_SCR_DRV_POS, 0x9f00); | ||
236 | /* SE27-20(End)=0x5c (92), SS27-20(Start)=0x00 */ | ||
237 | lcd_write_reg(R_2ND_SCR_DRV_POS, 0x5c00); | ||
238 | /* HEA7-0=0x7f, HSA7-0=0x00 */ | ||
239 | lcd_write_reg(R_HORIZ_RAM_ADDR_POS, 0x7f00); /* Vertical stripe */ | ||
240 | /* PKP12-10=0x0, PKP02-00=0x0 */ | ||
241 | lcd_write_reg(R_GAMMA_FINE_ADJ_POS1, 0x0003); | ||
242 | /* PKP32-30=0x4, PKP22-20=0x0 */ | ||
243 | lcd_write_reg(R_GAMMA_FINE_ADJ_POS2, 0x0400); | ||
244 | /* PKP52-50=0x4, PKP42-40=0x7 */ | ||
245 | lcd_write_reg(R_GAMMA_FINE_ADJ_POS3, 0x0407); | ||
246 | /* PRP12-10=0x3, PRP02-00=0x5 */ | ||
247 | lcd_write_reg(R_GAMMA_GRAD_ADJ_POS, 0x0305); | ||
248 | /* PKN12-10=0x0, PKN02-00=0x3 */ | ||
249 | lcd_write_reg(R_GAMMA_FINE_ADJ_NEG1, 0x0003); | ||
250 | /* PKN32-30=0x7, PKN22-20=0x4 */ | ||
251 | lcd_write_reg(R_GAMMA_FINE_ADJ_NEG2, 0x0704); | ||
252 | /* PKN52-50=0x4, PRN42-40=0x7 */ | ||
253 | lcd_write_reg(R_GAMMA_FINE_ADJ_NEG3, 0x0407); | ||
254 | /* PRN12-10=0x5, PRN02-00=0x3 */ | ||
255 | lcd_write_reg(R_GAMMA_GRAD_ADJ_NEG, 0x0503); | ||
256 | /* VRP14-10=0x14, VRP03-00=0x09 */ | ||
257 | lcd_write_reg(R_GAMMA_AMP_ADJ_POS, 0x1409); | ||
258 | /* VRN14-00=0x06, VRN03-00=0x02 */ | ||
259 | lcd_write_reg(R_GAMMA_AMP_ADJ_NEG, 0x0602); | ||
260 | |||
261 | /* 100ms or more; time for step-up circuits to stabilize */ | ||
262 | sleep(HZ/10); | ||
263 | |||
264 | /** Display ON Sequence **/ | ||
265 | /* Per datasheet Rev.1.10, Jun.21.2003, p. 97 */ | ||
266 | |||
267 | /* PT1-0=00, VLE2-1=00, SPT=0, GON=0, DTE=0, REV=1, D1-0=01 */ | ||
268 | lcd_write_reg(R_DISP_CONTROL, 0x0005); | ||
269 | |||
270 | sleep(HZ/25); /* Wait 2 frames or more */ | ||
271 | |||
272 | /* PT1-0=00, VLE2-1=00, SPT=0, GON=1, DTE=0, REV=1, D1-0=01 */ | ||
273 | lcd_write_reg(R_DISP_CONTROL, 0x0025); | ||
274 | /* PT1-0=00, VLE2-1=00, SPT=0, GON=1, DTE=0, REV=1, D1-0=11 */ | ||
275 | lcd_write_reg(R_DISP_CONTROL, 0x0027); | ||
276 | |||
277 | sleep(HZ/25); /* Wait 2 frames or more */ | ||
278 | |||
279 | /* PT1-0=00, VLE2-1=00, SPT=0, GON=1, DTE=1, REV=1, D1-0=11 */ | ||
280 | lcd_write_reg(R_DISP_CONTROL, 0x0037); | ||
281 | |||
282 | display_on = true; | ||
283 | y_offset = 0; | ||
284 | roll_offset = 0; | ||
251 | } | 285 | } |
252 | 286 | ||
253 | void lcd_enable(bool on) | 287 | void lcd_enable(bool on) |
@@ -274,51 +308,167 @@ void lcd_blit(const fb_data* data, int x, int by, int width, | |||
274 | 308 | ||
275 | 309 | ||
276 | /* Update the display. | 310 | /* Update the display. |
277 | This must be called after all other LCD functions that change the display. */ | 311 | This must be called after all other LCD functions that change the |
312 | lcd frame buffer. */ | ||
278 | void lcd_update(void) ICODE_ATTR; | 313 | void lcd_update(void) ICODE_ATTR; |
279 | void lcd_update(void) | 314 | void lcd_update(void) |
280 | { | 315 | { |
281 | if(display_on){ | 316 | /* Optimized for full-screen write. */ |
282 | 317 | const unsigned long *ptr, *ptr_end; | |
283 | /* Copy display bitmap to hardware */ | 318 | |
284 | lcd_write_reg(R_RAM_ADDR_SET, 0x0000); | 319 | if (!display_on) |
285 | lcd_begin_write_gram(); | 320 | return; |
286 | lcd_write_data((unsigned short *)lcd_framebuffer, LCD_WIDTH*LCD_HEIGHT); | 321 | |
287 | } | 322 | /* Set start position and window */ |
288 | } | 323 | /* Just add roll offset to start address. CP will roll back around. */ |
324 | lcd_write_reg(R_RAM_ADDR_SET, y_offset + roll_offset); /* X == 0 */ | ||
325 | lcd_write_reg(R_VERT_RAM_ADDR_POS, (LCD_WIDTH-1) << 8); | ||
326 | |||
327 | lcd_begin_write_gram(); | ||
328 | |||
329 | ptr = (unsigned long *)lcd_framebuffer; | ||
330 | ptr_end = ptr + (LCD_WIDTH*LCD_HEIGHT >> 1); | ||
331 | |||
332 | do | ||
333 | { | ||
334 | /* 16 words per turns out to be about optimal according to | ||
335 | test_fps. */ | ||
336 | lcd_write_two(*ptr++); | ||
337 | #ifndef BOOTLOADER | ||
338 | lcd_write_two(*ptr++); | ||
339 | lcd_write_two(*ptr++); | ||
340 | lcd_write_two(*ptr++); | ||
341 | lcd_write_two(*ptr++); | ||
342 | lcd_write_two(*ptr++); | ||
343 | lcd_write_two(*ptr++); | ||
344 | lcd_write_two(*ptr++); | ||
345 | #endif | ||
346 | } | ||
347 | while (ptr < ptr_end); | ||
348 | } /* lcd_update */ | ||
289 | 349 | ||
290 | /* Update a fraction of the display. */ | 350 | /* Update a fraction of the display. */ |
291 | void lcd_update_rect(int, int, int, int) ICODE_ATTR; | 351 | void lcd_update_rect(int, int, int, int) ICODE_ATTR; |
292 | void lcd_update_rect(int x, int y, int width, int height) | 352 | void lcd_update_rect(int x, int y, int width, int height) |
293 | { | 353 | { |
294 | if(display_on) { | 354 | int y_end; |
295 | int ymax = y + height; | 355 | int odd_lead, odd_trail; |
296 | 356 | int duff; | |
297 | if(x + width > LCD_WIDTH) | 357 | const unsigned long *ptr, *duff_end; |
298 | width = LCD_WIDTH - x; | 358 | int stride; /* Actually end of currline -> start of next */ |
299 | if (width <= 0) | 359 | |
300 | return; /* nothing left to do, 0 is harmful to lcd_write_data() */ | 360 | if (!display_on) |
301 | if(ymax >= LCD_HEIGHT) | 361 | return; |
302 | ymax = LCD_HEIGHT-1; | 362 | |
303 | 363 | if (x + width > LCD_WIDTH) | |
304 | /* set update window */ | 364 | width = LCD_WIDTH - x; /* Clip right */ |
305 | 365 | if (x < 0) | |
306 | /* horiz ram addr */ | 366 | width += x, x = 0; /* Clip left */ |
307 | lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (ymax<<8) | y); | 367 | if (width <= 0) |
308 | 368 | return; /* nothing left to do */ | |
309 | /* vert ram addr */ | 369 | |
310 | lcd_write_reg(R_VERT_RAM_ADDR_POS,((x+width-1)<<8) | x); | 370 | y_end = y + height; |
311 | lcd_write_reg(R_RAM_ADDR_SET, (x<<8) | y); | 371 | if (y_end > LCD_HEIGHT) |
312 | lcd_begin_write_gram(); | 372 | y_end = LCD_HEIGHT; /* Clip bottom */ |
313 | 373 | if (y < 0) | |
314 | /* Copy specified rectangle bitmap to hardware */ | 374 | y = 0; /* Clip top */ |
315 | for (; y <= ymax; y++) | 375 | if (y >= y_end) |
316 | { | 376 | return; /* nothing left to do */ |
317 | lcd_write_data ((unsigned short *)&lcd_framebuffer[y][x], width); | 377 | |
318 | } | 378 | ptr = (unsigned long *)&lcd_framebuffer[y][x]; |
319 | 379 | ||
320 | /* reset update window */ | 380 | /* Set start position and window */ |
321 | lcd_write_reg(R_HORIZ_RAM_ADDR_POS, 0x7f00); | 381 | lcd_write_reg(R_RAM_ADDR_SET, (x << 8) | |
322 | lcd_write_reg(R_VERT_RAM_ADDR_POS, 0x9f00); | 382 | (((y + roll_offset) & 127) + y_offset)); |
383 | lcd_write_reg(R_VERT_RAM_ADDR_POS, ((x + width - 1) << 8) | x); | ||
384 | |||
385 | lcd_begin_write_gram(); | ||
386 | |||
387 | /* Aligning source reads to long boundaries helps 2% - 3% with IRAM | ||
388 | buffer. DK with DRAM. */ | ||
389 | |||
390 | /* special case widths 1 and 2. */ | ||
391 | switch (width) | ||
392 | { | ||
393 | case 1: | ||
394 | odd_lead = 1; /* odd_lead case writes pixels */ | ||
395 | odd_trail = 0; | ||
396 | duff = 0; /* Squelch compiler warning. */ | ||
397 | duff_end = ptr; | ||
398 | break; | ||
399 | case 2: /* Just read as long */ | ||
400 | odd_lead = 0; | ||
401 | odd_trail = 0; | ||
402 | duff = 1; | ||
403 | duff_end = ptr + 1; | ||
404 | break; | ||
405 | default: | ||
406 | odd_lead = x & 1; | ||
407 | |||
408 | if (odd_lead) | ||
409 | { | ||
410 | duff = width - 1; | ||
411 | odd_trail = duff & 1; | ||
412 | duff >>= 1; | ||
413 | } | ||
414 | else | ||
415 | { | ||
416 | duff = width >> 1; | ||
417 | odd_trail = width & 1; | ||
418 | } | ||
419 | |||
420 | duff_end = ptr + duff; | ||
421 | #ifndef BOOTLOADER | ||
422 | duff &= 7; | ||
423 | #endif | ||
424 | } /* end switch */ | ||
425 | |||
426 | stride = LCD_WIDTH - width + odd_trail; /* See odd_trail below */ | ||
427 | |||
428 | do | ||
429 | { | ||
430 | if (odd_lead) | ||
431 | { | ||
432 | /* Write odd start pixel. */ | ||
433 | lcd_write_one(*(unsigned short *)ptr); | ||
434 | ptr = (unsigned long *)((short *)ptr + 1); | ||
435 | } | ||
436 | |||
437 | if (ptr < duff_end) | ||
438 | { | ||
439 | #ifdef BOOTLOADER | ||
440 | do | ||
441 | lcd_write_two(*ptr); | ||
442 | while (++ptr < duff_end); | ||
443 | #else | ||
444 | switch (duff) | ||
445 | { | ||
446 | do | ||
447 | { | ||
448 | case 0: lcd_write_two(*ptr++); | ||
449 | case 7: lcd_write_two(*ptr++); | ||
450 | case 6: lcd_write_two(*ptr++); | ||
451 | case 5: lcd_write_two(*ptr++); | ||
452 | case 4: lcd_write_two(*ptr++); | ||
453 | case 3: lcd_write_two(*ptr++); | ||
454 | case 2: lcd_write_two(*ptr++); | ||
455 | case 1: lcd_write_two(*ptr++); | ||
456 | } | ||
457 | while (ptr < duff_end); | ||
458 | } /* end switch */ | ||
459 | #endif /* BOOTLOADER */ | ||
460 | |||
461 | duff_end += LCD_WIDTH/2; | ||
462 | } | ||
463 | |||
464 | if (odd_trail) | ||
465 | { | ||
466 | /* Finish remaining odd pixel. */ | ||
467 | lcd_write_one(*(unsigned short *)ptr); | ||
468 | /* Stride increased by one pixel. */ | ||
469 | } | ||
470 | |||
471 | ptr = (unsigned long *)((short *)ptr + stride); | ||
323 | } | 472 | } |
473 | while (++y < y_end); | ||
324 | } | 474 | } |