diff options
Diffstat (limited to 'firmware/target/arm/tcc780x/cowond2/lcd-cowond2.c')
-rw-r--r-- | firmware/target/arm/tcc780x/cowond2/lcd-cowond2.c | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/firmware/target/arm/tcc780x/cowond2/lcd-cowond2.c b/firmware/target/arm/tcc780x/cowond2/lcd-cowond2.c new file mode 100644 index 0000000000..181c58669e --- /dev/null +++ b/firmware/target/arm/tcc780x/cowond2/lcd-cowond2.c | |||
@@ -0,0 +1,346 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2008 by Rob Purchase | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #include "config.h" | ||
20 | |||
21 | #include "hwcompat.h" | ||
22 | #include "kernel.h" | ||
23 | #include "lcd.h" | ||
24 | #include "system.h" | ||
25 | #include "cpu.h" | ||
26 | #include "i2c.h" | ||
27 | |||
28 | /* GPIO A pins for LCD panel SDI interface */ | ||
29 | |||
30 | #define LTV250QV_CS (1<<24) | ||
31 | #define LTV250QV_SCL (1<<25) | ||
32 | #define LTV250QV_SDI (1<<26) | ||
33 | |||
34 | /* LCD Controller registers */ | ||
35 | |||
36 | #define LCDC_CTRL (*(volatile unsigned long *)0xF0000000) | ||
37 | #define LCDC_CLKDIV (*(volatile unsigned long *)0xF0000008) | ||
38 | #define LCDC_HTIME1 (*(volatile unsigned long *)0xF000000C) | ||
39 | #define LCDC_HTIME2 (*(volatile unsigned long *)0xF0000010) | ||
40 | #define LCDC_VTIME1 (*(volatile unsigned long *)0xF0000014) | ||
41 | #define LCDC_VTIME2 (*(volatile unsigned long *)0xF0000018) | ||
42 | #define LCDC_VTIME3 (*(volatile unsigned long *)0xF000001C) | ||
43 | #define LCDC_VTIME4 (*(volatile unsigned long *)0xF0000020) | ||
44 | #define LCDC_DS (*(volatile unsigned long *)0xF000005C) | ||
45 | #define LCDC_I1CTRL (*(volatile unsigned long *)0xF000008C) | ||
46 | #define LCDC_I1POS (*(volatile unsigned long *)0xF0000090) | ||
47 | #define LCDC_I1SIZE (*(volatile unsigned long *)0xF0000094) | ||
48 | #define LCDC_I1BASE (*(volatile unsigned long *)0xF0000098) | ||
49 | #define LCDC_I1OFF (*(volatile unsigned long *)0xF00000A8) | ||
50 | #define LCDC_I1SCALE (*(volatile unsigned long *)0xF00000AC) | ||
51 | |||
52 | /* Power and display status */ | ||
53 | static bool display_on = false; /* Is the display turned on? */ | ||
54 | |||
55 | |||
56 | int lcd_default_contrast(void) | ||
57 | { | ||
58 | return 0x1f; | ||
59 | } | ||
60 | |||
61 | void lcd_set_contrast(int val) | ||
62 | { | ||
63 | /* iirc there is an ltv250qv command to do this */ | ||
64 | #warning function not implemented | ||
65 | (void)val; | ||
66 | } | ||
67 | |||
68 | |||
69 | /* LTV250QV panel functions */ | ||
70 | |||
71 | static void ltv250qv_write(unsigned int command) | ||
72 | { | ||
73 | int i; | ||
74 | |||
75 | GPIOA_CLEAR = LTV250QV_CS; | ||
76 | |||
77 | for (i = 23; i >= 0; i--) | ||
78 | { | ||
79 | GPIOA_CLEAR = LTV250QV_SCL; | ||
80 | |||
81 | if ((command>>i) & 1) | ||
82 | GPIOA_SET = LTV250QV_SDI; | ||
83 | else | ||
84 | GPIOA_CLEAR = LTV250QV_SDI; | ||
85 | |||
86 | GPIOA_SET = LTV250QV_SCL; | ||
87 | } | ||
88 | |||
89 | GPIOA_SET = LTV250QV_CS; | ||
90 | } | ||
91 | |||
92 | static void lcd_write_reg(unsigned char reg, unsigned short val) | ||
93 | { | ||
94 | ltv250qv_write(0x740000 | reg); | ||
95 | ltv250qv_write(0x760000 | val); | ||
96 | } | ||
97 | |||
98 | |||
99 | /* TODO: The existing pcf50606 drivers are target-specific, so the following | ||
100 | lonely function exists until a D2 driver exists. */ | ||
101 | |||
102 | void pcf50606_write_reg(unsigned char reg, unsigned char val) | ||
103 | { | ||
104 | unsigned char data[] = { reg, val }; | ||
105 | i2c_write(0x10, data, 2); | ||
106 | } | ||
107 | |||
108 | |||
109 | /* | ||
110 | TEMP: Rough millisecond delay routine used by the LCD panel init sequence. | ||
111 | PCK_TCT must first have been initialised to 2Mhz by calling clock_init(). | ||
112 | */ | ||
113 | static void sleep_ms(unsigned int ms) | ||
114 | { | ||
115 | /* disable timer */ | ||
116 | TCFG1 = 0; | ||
117 | |||
118 | /* set Timer1 reference value based on 125kHz tick */ | ||
119 | TREF1 = ms * 125; | ||
120 | |||
121 | /* single count, zero the counter, divider = 16 [2^(3+1)], enable */ | ||
122 | TCFG1 = (1<<9) | (1<<8) | (3<<4) | 1; | ||
123 | |||
124 | /* wait until Timer1 ref reached */ | ||
125 | while (!(TIREQ & TF1)) {}; | ||
126 | } | ||
127 | |||
128 | |||
129 | static void lcd_display_on(void) | ||
130 | { | ||
131 | /* power on sequence as per the D2 firmware */ | ||
132 | GPIOA_SET = (1<<16); | ||
133 | |||
134 | sleep_ms(10); | ||
135 | |||
136 | lcd_write_reg(1, 0x1D); | ||
137 | lcd_write_reg(2, 0x0); | ||
138 | lcd_write_reg(3, 0x0); | ||
139 | lcd_write_reg(4, 0x0); | ||
140 | lcd_write_reg(5, 0x40A3); | ||
141 | lcd_write_reg(6, 0x0); | ||
142 | lcd_write_reg(7, 0x0); | ||
143 | lcd_write_reg(8, 0x0); | ||
144 | lcd_write_reg(9, 0x0); | ||
145 | lcd_write_reg(10, 0x0); | ||
146 | lcd_write_reg(16, 0x0); | ||
147 | lcd_write_reg(17, 0x0); | ||
148 | lcd_write_reg(18, 0x0); | ||
149 | lcd_write_reg(19, 0x0); | ||
150 | lcd_write_reg(20, 0x0); | ||
151 | lcd_write_reg(21, 0x0); | ||
152 | lcd_write_reg(22, 0x0); | ||
153 | lcd_write_reg(23, 0x0); | ||
154 | lcd_write_reg(24, 0x0); | ||
155 | lcd_write_reg(25, 0x0); | ||
156 | sleep_ms(10); | ||
157 | |||
158 | lcd_write_reg(9, 0x4055); | ||
159 | lcd_write_reg(10, 0x0); | ||
160 | sleep_ms(40); | ||
161 | |||
162 | lcd_write_reg(10, 0x2000); | ||
163 | sleep_ms(40); | ||
164 | |||
165 | lcd_write_reg(1, 0xC01D); | ||
166 | lcd_write_reg(2, 0x204); | ||
167 | lcd_write_reg(3, 0xE100); | ||
168 | lcd_write_reg(4, 0x1000); | ||
169 | lcd_write_reg(5, 0x5033); | ||
170 | lcd_write_reg(6, 0x4); | ||
171 | lcd_write_reg(7, 0x30); | ||
172 | lcd_write_reg(8, 0x41C); | ||
173 | lcd_write_reg(16, 0x207); | ||
174 | lcd_write_reg(17, 0x702); | ||
175 | lcd_write_reg(18, 0xB05); | ||
176 | lcd_write_reg(19, 0xB05); | ||
177 | lcd_write_reg(20, 0x707); | ||
178 | lcd_write_reg(21, 0x507); | ||
179 | lcd_write_reg(22, 0x103); | ||
180 | lcd_write_reg(23, 0x406); | ||
181 | lcd_write_reg(24, 0x2); | ||
182 | lcd_write_reg(25, 0x0); | ||
183 | sleep_ms(60); | ||
184 | |||
185 | lcd_write_reg(9, 0xA55); | ||
186 | lcd_write_reg(10, 0x111F); | ||
187 | sleep_ms(10); | ||
188 | |||
189 | pcf50606_write_reg(0x35, 0xe9); /* PWMC1 - backlight power (intensity) */ | ||
190 | pcf50606_write_reg(0x38, 0x3); /* GPOC1 - ? */ | ||
191 | |||
192 | /* tell that we're on now */ | ||
193 | display_on = true; | ||
194 | } | ||
195 | |||
196 | static void lcd_display_off(void) | ||
197 | { | ||
198 | /* block drawing operations and changing of first */ | ||
199 | display_on = false; | ||
200 | |||
201 | /* LQV shutdown sequence */ | ||
202 | lcd_write_reg(9, 0x55); | ||
203 | lcd_write_reg(10, 0x1417); | ||
204 | lcd_write_reg(5, 0x4003); | ||
205 | sleep_ms(10); | ||
206 | |||
207 | lcd_write_reg(9, 0x0); | ||
208 | sleep_ms(10); | ||
209 | |||
210 | /* kill power to LCD panel (unconfirmed) */ | ||
211 | GPIOA_CLEAR = (1<<16); | ||
212 | |||
213 | /* also kill the backlight, otherwise LCD fade is visible on screen */ | ||
214 | GPIOA_CLEAR = (1<<6); | ||
215 | } | ||
216 | |||
217 | |||
218 | void lcd_enable(bool on) | ||
219 | { | ||
220 | if (on == display_on) | ||
221 | return; | ||
222 | |||
223 | if (on) | ||
224 | { | ||
225 | lcd_display_on(); /* Turn on display */ | ||
226 | lcd_update(); /* Resync display */ | ||
227 | } | ||
228 | else | ||
229 | { | ||
230 | lcd_display_off(); /* Turn off display */ | ||
231 | } | ||
232 | } | ||
233 | |||
234 | bool lcd_enabled(void) | ||
235 | { | ||
236 | return display_on; | ||
237 | } | ||
238 | |||
239 | |||
240 | void lcd_init_device(void) | ||
241 | { | ||
242 | BCLKCTR |= 4; /* enable LCD bus clock */ | ||
243 | |||
244 | /* set PCK_LCD to 108Mhz */ | ||
245 | PCLK_LCD &= ~PCK_EN; | ||
246 | PCLK_LCD = PCK_EN | (CKSEL_PLL1<<24) | 1; /* source = PLL1, divided by 2 */ | ||
247 | |||
248 | /* reset the LCD controller */ | ||
249 | SWRESET |= 4; | ||
250 | SWRESET &= ~4; | ||
251 | |||
252 | /* set port configuration */ | ||
253 | PORTCFG1 &= ~0xC0000000; | ||
254 | PORTCFG1 &= ~0x3FC0; | ||
255 | PORTCFG2 &= ~0x100; | ||
256 | |||
257 | /* set physical display size */ | ||
258 | LCDC_DS = (LCD_HEIGHT<<16) | LCD_WIDTH; | ||
259 | |||
260 | LCDC_HTIME1 = (0x2d<<16) | 0x3bf; | ||
261 | LCDC_HTIME2 = (1<<16) | 1; | ||
262 | LCDC_VTIME1 = LCDC_VTIME3 = (0<<16) | 239; | ||
263 | LCDC_VTIME2 = LCDC_VTIME4 = (1<<16) | 3; | ||
264 | |||
265 | LCDC_I1BASE = (unsigned int)lcd_framebuffer; /* dirty, dirty hack */ | ||
266 | LCDC_I1SIZE = (LCD_HEIGHT<<16) | LCD_WIDTH; /* image 1 size */ | ||
267 | //LCDC_I1POS = (0<<16) | 0; /* position */ | ||
268 | //LCDC_I1OFF = 0; /* address offset */ | ||
269 | //LCDC_I1SCALE = 0; /* scaling */ | ||
270 | LCDC_I1CTRL = 5; /* 565bpp (7 = 888bpp) */ | ||
271 | //LCDC_CTRL &= ~(1<<28); | ||
272 | |||
273 | LCDC_CLKDIV = (LCDC_CLKDIV &~ 0xFF00FF) | (1<<16) | 2; /* and this means? */ | ||
274 | |||
275 | /* set and clear various flags - not investigated yet */ | ||
276 | //LCDC_CTRL &~ 0x090006AA; /* clear bits 1,3,5,7,9,10,24,27 */ | ||
277 | LCDC_CTRL |= 0x02800144; /* set bits 2,6,8,25,23 */ | ||
278 | LCDC_CTRL = (LCDC_CTRL &~ 0xF0000) | 0x20000; | ||
279 | //LCDC_CTRL = (LCDC_CTRL &~ 0x700000) | 0x700000; | ||
280 | |||
281 | /* enable LCD controller */ | ||
282 | LCDC_CTRL |= 1; | ||
283 | } | ||
284 | |||
285 | |||
286 | /*** Update functions ***/ | ||
287 | |||
288 | |||
289 | /* Update the display. | ||
290 | This must be called after all other LCD functions that change the display. */ | ||
291 | void lcd_update(void) ICODE_ATTR; | ||
292 | void lcd_update(void) | ||
293 | { | ||
294 | #warning function not implemented | ||
295 | /* currently lcd_framebuffer is accessed directly by the hardware */ | ||
296 | } | ||
297 | |||
298 | /* Update a fraction of the display. */ | ||
299 | void lcd_update_rect(int, int, int, int) ICODE_ATTR; | ||
300 | void lcd_update_rect(int x, int y, int width, int height) | ||
301 | { | ||
302 | #warning function not implemented | ||
303 | (void)x; | ||
304 | (void)y; | ||
305 | (void)width; | ||
306 | (void)height; | ||
307 | } | ||
308 | |||
309 | void lcd_set_flip(bool yesno) | ||
310 | { | ||
311 | #warning function not implemented | ||
312 | (void)yesno; | ||
313 | } | ||
314 | |||
315 | void lcd_set_invert_display(bool yesno) | ||
316 | { | ||
317 | #warning function not implemented | ||
318 | (void)yesno; | ||
319 | } | ||
320 | |||
321 | void lcd_blit(const fb_data* data, int bx, int y, int bwidth, | ||
322 | int height, int stride) | ||
323 | { | ||
324 | #warning function not implemented | ||
325 | (void)data; | ||
326 | (void)bx; | ||
327 | (void)y; | ||
328 | (void)bwidth; | ||
329 | (void)height; | ||
330 | (void)stride; | ||
331 | } | ||
332 | |||
333 | void lcd_yuv_blit(unsigned char * const src[3], | ||
334 | int src_x, int src_y, int stride, | ||
335 | int x, int y, int width, int height) | ||
336 | { | ||
337 | #warning function not implemented | ||
338 | (void)src; | ||
339 | (void)src_x; | ||
340 | (void)src_y; | ||
341 | (void)stride; | ||
342 | (void)x; | ||
343 | (void)y; | ||
344 | (void)width; | ||
345 | (void)height; | ||
346 | } | ||