diff options
Diffstat (limited to 'firmware/drivers')
-rw-r--r-- | firmware/drivers/lcd-remote-1bit-v.c (renamed from firmware/drivers/lcd-h100-remote.c) | 636 |
1 files changed, 19 insertions, 617 deletions
diff --git a/firmware/drivers/lcd-h100-remote.c b/firmware/drivers/lcd-remote-1bit-v.c index e8d22213b8..c81ccc83c9 100644 --- a/firmware/drivers/lcd-h100-remote.c +++ b/firmware/drivers/lcd-remote-1bit-v.c | |||
@@ -32,36 +32,7 @@ | |||
32 | #include "rbunicode.h" | 32 | #include "rbunicode.h" |
33 | #include "bidi.h" | 33 | #include "bidi.h" |
34 | 34 | ||
35 | /*** definitions ***/ | 35 | #define SCROLLABLE_LINES (((LCD_REMOTE_HEIGHT+4)/5 < 32) ? (LCD_REMOTE_HEIGHT+4)/5 : 32) |
36 | |||
37 | #define LCD_REMOTE_CNTL_ADC_NORMAL 0xa0 | ||
38 | #define LCD_REMOTE_CNTL_ADC_REVERSE 0xa1 | ||
39 | #define LCD_REMOTE_CNTL_SHL_NORMAL 0xc0 | ||
40 | #define LCD_REMOTE_CNTL_SHL_REVERSE 0xc8 | ||
41 | #define LCD_REMOTE_CNTL_DISPLAY_ON_OFF 0xae | ||
42 | #define LCD_REMOTE_CNTL_ENTIRE_ON_OFF 0xa4 | ||
43 | #define LCD_REMOTE_CNTL_REVERSE_ON_OFF 0xa6 | ||
44 | #define LCD_REMOTE_CNTL_NOP 0xe3 | ||
45 | #define LCD_REMOTE_CNTL_POWER_CONTROL 0x2b | ||
46 | #define LCD_REMOTE_CNTL_SELECT_REGULATOR 0x20 | ||
47 | #define LCD_REMOTE_CNTL_SELECT_BIAS 0xa2 | ||
48 | #define LCD_REMOTE_CNTL_SELECT_VOLTAGE 0x81 | ||
49 | #define LCD_REMOTE_CNTL_INIT_LINE 0x40 | ||
50 | #define LCD_REMOTE_CNTL_SET_PAGE_ADDRESS 0xB0 | ||
51 | |||
52 | #define LCD_REMOTE_CNTL_HIGHCOL 0x10 /* Upper column address */ | ||
53 | #define LCD_REMOTE_CNTL_LOWCOL 0x00 /* Lower column address */ | ||
54 | |||
55 | #define CS_LO and_l(~0x00000004, &GPIO1_OUT) | ||
56 | #define CS_HI or_l(0x00000004, &GPIO1_OUT) | ||
57 | #define CLK_LO and_l(~0x10000000, &GPIO_OUT) | ||
58 | #define CLK_HI or_l(0x10000000, &GPIO_OUT) | ||
59 | #define DATA_LO and_l(~0x00040000, &GPIO1_OUT) | ||
60 | #define DATA_HI or_l(0x00040000, &GPIO1_OUT) | ||
61 | #define RS_LO and_l(~0x00010000, &GPIO_OUT) | ||
62 | #define RS_HI or_l(0x00010000, &GPIO_OUT) | ||
63 | |||
64 | #define SCROLLABLE_LINES 13 | ||
65 | 36 | ||
66 | /*** globals ***/ | 37 | /*** globals ***/ |
67 | 38 | ||
@@ -73,33 +44,6 @@ static int xmargin = 0; | |||
73 | static int ymargin = 0; | 44 | static int ymargin = 0; |
74 | static int curfont = FONT_SYSFIXED; | 45 | static int curfont = FONT_SYSFIXED; |
75 | 46 | ||
76 | #ifndef SIMULATOR | ||
77 | static int xoffset; /* needed for flip */ | ||
78 | |||
79 | /* timeout counter for deasserting /CS after access, <0 means not counting */ | ||
80 | static int cs_countdown IDATA_ATTR = 0; | ||
81 | #define CS_TIMEOUT (HZ/10) | ||
82 | |||
83 | #ifdef HAVE_REMOTE_LCD_TICKING | ||
84 | /* If set to true, will prevent "ticking" to headphones. */ | ||
85 | static bool emireduce = false; | ||
86 | static int byte_delay = 0; | ||
87 | #endif | ||
88 | |||
89 | /* remote hotplug */ | ||
90 | static struct event_queue remote_scroll_queue; | ||
91 | #define REMOTE_INIT_LCD 1 | ||
92 | #define REMOTE_DEINIT_LCD 2 | ||
93 | |||
94 | static bool remote_initialized = false; | ||
95 | static int _remote_type = REMOTETYPE_UNPLUGGED; | ||
96 | |||
97 | /* cached settings values */ | ||
98 | static bool cached_invert = false; | ||
99 | static bool cached_flip = false; | ||
100 | static int cached_contrast = DEFAULT_REMOTE_CONTRAST_SETTING; | ||
101 | #endif | ||
102 | |||
103 | /* scrolling */ | 47 | /* scrolling */ |
104 | static volatile int scrolling_lines=0; /* Bitpattern of which lines are scrolling */ | 48 | static volatile int scrolling_lines=0; /* Bitpattern of which lines are scrolling */ |
105 | static void scroll_thread(void); | 49 | static void scroll_thread(void); |
@@ -117,562 +61,10 @@ static const char scroll_tick_table[16] = { | |||
117 | 100, 80, 64, 50, 40, 32, 25, 20, 16, 12, 10, 8, 6, 5, 4, 3 | 61 | 100, 80, 64, 50, 40, 32, 25, 20, 16, 12, 10, 8, 6, 5, 4, 3 |
118 | }; | 62 | }; |
119 | 63 | ||
120 | /*** driver routines ***/ | 64 | /* remote hotplug */ |
121 | |||
122 | #ifndef SIMULATOR | ||
123 | |||
124 | #ifdef HAVE_REMOTE_LCD_TICKING | ||
125 | static inline void _byte_delay(int delay) | ||
126 | { | ||
127 | asm ( | ||
128 | "move.l %[dly], %%d0 \n" | ||
129 | "ble.s 2f \n" | ||
130 | "1: \n" | ||
131 | "subq.l #1, %%d0 \n" | ||
132 | "bne.s 1b \n" | ||
133 | "2: \n" | ||
134 | : /* outputs */ | ||
135 | : /* inputs */ | ||
136 | [dly]"d"(delay) | ||
137 | : /* clobbers */ | ||
138 | "d0" | ||
139 | ); | ||
140 | } | ||
141 | #endif /* HAVE_REMOTE_LCD_TICKING */ | ||
142 | |||
143 | /* Standard low-level byte writer. Requires CLK low on entry */ | ||
144 | static inline void _write_byte(unsigned data) | ||
145 | { | ||
146 | asm volatile ( | ||
147 | "move.l (%[gpo1]), %%d0 \n" /* Get current state of data line */ | ||
148 | "and.l %[dbit], %%d0 \n" | ||
149 | "beq.s 1f \n" /* and set it as previous-state bit */ | ||
150 | "bset #8, %[data] \n" | ||
151 | "1: \n" | ||
152 | "move.l %[data], %%d0 \n" /* Compute the 'bit derivative', i.e. a value */ | ||
153 | "lsr.l #1, %%d0 \n" /* with 1's where the data changes from the */ | ||
154 | "eor.l %%d0, %[data] \n" /* previous state, and 0's where it doesn't */ | ||
155 | "swap %[data] \n" /* Shift data to upper byte */ | ||
156 | "lsl.l #8, %[data] \n" | ||
157 | |||
158 | "lsl.l #1,%[data] \n" /* Shift out MSB */ | ||
159 | "bcc.s 1f \n" | ||
160 | "eor.l %[dbit], (%[gpo1]) \n" /* 1: flip DATA */ | ||
161 | "1: \n" | ||
162 | "eor.l %[cbit], (%[gpo0]) \n" /* Flip CLK */ | ||
163 | "eor.l %[cbit], (%[gpo0]) \n" /* Flip CLK */ | ||
164 | |||
165 | "lsl.l #1,%[data] \n" /* ..unrolled.. */ | ||
166 | "bcc.s 1f \n" | ||
167 | "eor.l %[dbit], (%[gpo1]) \n" | ||
168 | "1: \n" | ||
169 | "eor.l %[cbit], (%[gpo0]) \n" | ||
170 | "eor.l %[cbit], (%[gpo0]) \n" | ||
171 | |||
172 | "lsl.l #1,%[data] \n" | ||
173 | "bcc.s 1f \n" | ||
174 | "eor.l %[dbit], (%[gpo1]) \n" | ||
175 | "1: \n" | ||
176 | "eor.l %[cbit], (%[gpo0]) \n" | ||
177 | "eor.l %[cbit], (%[gpo0]) \n" | ||
178 | |||
179 | "lsl.l #1,%[data] \n" | ||
180 | "bcc.s 1f \n" | ||
181 | "eor.l %[dbit], (%[gpo1]) \n" | ||
182 | "1: \n" | ||
183 | "eor.l %[cbit], (%[gpo0]) \n" | ||
184 | "eor.l %[cbit], (%[gpo0]) \n" | ||
185 | |||
186 | "lsl.l #1,%[data] \n" | ||
187 | "bcc.s 1f \n" | ||
188 | "eor.l %[dbit], (%[gpo1]) \n" | ||
189 | "1: \n" | ||
190 | "eor.l %[cbit], (%[gpo0]) \n" | ||
191 | "eor.l %[cbit], (%[gpo0]) \n" | ||
192 | |||
193 | "lsl.l #1,%[data] \n" | ||
194 | "bcc.s 1f \n" | ||
195 | "eor.l %[dbit], (%[gpo1]) \n" | ||
196 | "1: \n" | ||
197 | "eor.l %[cbit], (%[gpo0]) \n" | ||
198 | "eor.l %[cbit], (%[gpo0]) \n" | ||
199 | |||
200 | "lsl.l #1,%[data] \n" | ||
201 | "bcc.s 1f \n" | ||
202 | "eor.l %[dbit], (%[gpo1]) \n" | ||
203 | "1: \n" | ||
204 | "eor.l %[cbit], (%[gpo0]) \n" | ||
205 | "eor.l %[cbit], (%[gpo0]) \n" | ||
206 | |||
207 | "lsl.l #1,%[data] \n" | ||
208 | "bcc.s 1f \n" | ||
209 | "eor.l %[dbit], (%[gpo1]) \n" | ||
210 | "1: \n" | ||
211 | "eor.l %[cbit], (%[gpo0]) \n" | ||
212 | "eor.l %[cbit], (%[gpo0]) \n" | ||
213 | : /* outputs */ | ||
214 | [data]"+d"(data) | ||
215 | : /* inputs */ | ||
216 | [gpo0]"a"(&GPIO_OUT), | ||
217 | [cbit]"d"(0x10000000), | ||
218 | [gpo1]"a"(&GPIO1_OUT), | ||
219 | [dbit]"d"(0x00040000) | ||
220 | : /* clobbers */ | ||
221 | "d0" | ||
222 | ); | ||
223 | } | ||
224 | |||
225 | /* Fast low-level byte writer. Don't use with high CPU clock. | ||
226 | * Requires CLK low on entry */ | ||
227 | static inline void _write_fast(unsigned data) | ||
228 | { | ||
229 | asm volatile ( | ||
230 | "move.w %%sr,%%d3 \n" /* Get current interrupt level */ | ||
231 | "move.w #0x2700,%%sr \n" /* Disable interrupts */ | ||
232 | |||
233 | "move.l (%[gpo1]), %%d0 \n" /* Get current state of data port */ | ||
234 | "move.l %%d0, %%d1 \n" | ||
235 | "and.l %[dbit], %%d1 \n" /* Check current state of data line */ | ||
236 | "beq.s 1f \n" /* and set it as previous-state bit */ | ||
237 | "bset #8, %[data] \n" | ||
238 | "1: \n" | ||
239 | "move.l %[data], %%d1 \n" /* Compute the 'bit derivative', i.e. a value */ | ||
240 | "lsr.l #1, %%d1 \n" /* with 1's where the data changes from the */ | ||
241 | "eor.l %%d1, %[data] \n" /* previous state, and 0's where it doesn't */ | ||
242 | "swap %[data] \n" /* Shift data to upper byte */ | ||
243 | "lsl.l #8, %[data] \n" | ||
244 | |||
245 | "move.l (%[gpo0]), %%d1 \n" /* Get current state of clock port */ | ||
246 | "move.l %[cbit], %%d2 \n" /* Precalculate opposite state of clock line */ | ||
247 | "eor.l %%d1, %%d2 \n" | ||
248 | |||
249 | "lsl.l #1,%[data] \n" /* Shift out MSB */ | ||
250 | "bcc.s 1f \n" | ||
251 | "eor.l %[dbit], %%d0 \n" /* 1: flip data bit */ | ||
252 | "move.l %%d0, (%[gpo1]) \n" /* and output new DATA state */ | ||
253 | "1: \n" | ||
254 | "move.l %%d2, (%[gpo0]) \n" /* Set CLK */ | ||
255 | "move.l %%d1, (%[gpo0]) \n" /* Reset CLK */ | ||
256 | |||
257 | "lsl.l #1,%[data] \n" /* ..unrolled.. */ | ||
258 | "bcc.s 1f \n" | ||
259 | "eor.l %[dbit], %%d0 \n" | ||
260 | "move.l %%d0, (%[gpo1]) \n" | ||
261 | "1: \n" | ||
262 | "move.l %%d2, (%[gpo0]) \n" | ||
263 | "move.l %%d1, (%[gpo0]) \n" | ||
264 | |||
265 | "lsl.l #1,%[data] \n" | ||
266 | "bcc.s 1f \n" | ||
267 | "eor.l %[dbit], %%d0 \n" | ||
268 | "move.l %%d0, (%[gpo1]) \n" | ||
269 | "1: \n" | ||
270 | "move.l %%d2, (%[gpo0]) \n" | ||
271 | "move.l %%d1, (%[gpo0]) \n" | ||
272 | |||
273 | "lsl.l #1,%[data] \n" | ||
274 | "bcc.s 1f \n" | ||
275 | "eor.l %[dbit], %%d0 \n" | ||
276 | "move.l %%d0, (%[gpo1]) \n" | ||
277 | "1: \n" | ||
278 | "move.l %%d2, (%[gpo0]) \n" | ||
279 | "move.l %%d1, (%[gpo0]) \n" | ||
280 | |||
281 | "lsl.l #1,%[data] \n" | ||
282 | "bcc.s 1f \n" | ||
283 | "eor.l %[dbit], %%d0 \n" | ||
284 | "move.l %%d0, (%[gpo1]) \n" | ||
285 | "1: \n" | ||
286 | "move.l %%d2, (%[gpo0]) \n" | ||
287 | "move.l %%d1, (%[gpo0]) \n" | ||
288 | |||
289 | "lsl.l #1,%[data] \n" | ||
290 | "bcc.s 1f \n" | ||
291 | "eor.l %[dbit], %%d0 \n" | ||
292 | "move.l %%d0, (%[gpo1]) \n" | ||
293 | "1: \n" | ||
294 | "move.l %%d2, (%[gpo0]) \n" | ||
295 | "move.l %%d1, (%[gpo0]) \n" | ||
296 | |||
297 | "lsl.l #1,%[data] \n" | ||
298 | "bcc.s 1f \n" | ||
299 | "eor.l %[dbit], %%d0 \n" | ||
300 | "move.l %%d0, (%[gpo1]) \n" | ||
301 | "1: \n" | ||
302 | "move.l %%d2, (%[gpo0]) \n" | ||
303 | "move.l %%d1, (%[gpo0]) \n" | ||
304 | |||
305 | "lsl.l #1,%[data] \n" | ||
306 | "bcc.s 1f \n" | ||
307 | "eor.l %[dbit], %%d0 \n" | ||
308 | "move.l %%d0, (%[gpo1]) \n" | ||
309 | "1: \n" | ||
310 | "move.l %%d2, (%[gpo0]) \n" | ||
311 | "move.l %%d1, (%[gpo0]) \n" | ||
312 | |||
313 | "move.w %%d3, %%sr \n" /* Restore interrupt level */ | ||
314 | : /* outputs */ | ||
315 | [data]"+d"(data) | ||
316 | : /* inputs */ | ||
317 | [gpo0]"a"(&GPIO_OUT), | ||
318 | [cbit]"i"(0x10000000), | ||
319 | [gpo1]"a"(&GPIO1_OUT), | ||
320 | [dbit]"d"(0x00040000) | ||
321 | : /* clobbers */ | ||
322 | "d0", "d1", "d2", "d3" | ||
323 | ); | ||
324 | } | ||
325 | |||
326 | void lcd_remote_write_command(int cmd) | ||
327 | { | ||
328 | cs_countdown = 0; | ||
329 | RS_LO; | ||
330 | CS_LO; | ||
331 | |||
332 | _write_byte(cmd); | ||
333 | #ifdef HAVE_REMOTE_LCD_TICKING | ||
334 | _byte_delay(byte_delay - 148); | ||
335 | #endif | ||
336 | |||
337 | cs_countdown = CS_TIMEOUT; | ||
338 | } | ||
339 | |||
340 | void lcd_remote_write_command_ex(int cmd, int data) | ||
341 | { | ||
342 | cs_countdown = 0; | ||
343 | RS_LO; | ||
344 | CS_LO; | ||
345 | |||
346 | _write_byte(cmd); | ||
347 | #ifdef HAVE_REMOTE_LCD_TICKING | ||
348 | _byte_delay(byte_delay - 148); | ||
349 | #endif | ||
350 | _write_byte(data); | ||
351 | #ifdef HAVE_REMOTE_LCD_TICKING | ||
352 | _byte_delay(byte_delay - 148); | ||
353 | #endif | ||
354 | |||
355 | cs_countdown = CS_TIMEOUT; | ||
356 | } | ||
357 | |||
358 | void lcd_remote_write_data(const unsigned char* p_bytes, int count) ICODE_ATTR; | ||
359 | void lcd_remote_write_data(const unsigned char* p_bytes, int count) | ||
360 | { | ||
361 | const unsigned char *p_end = p_bytes + count; | ||
362 | |||
363 | cs_countdown = 0; | ||
364 | RS_HI; | ||
365 | CS_LO; | ||
366 | |||
367 | /* This is safe as long as lcd_remote_write_data() isn't called from within | ||
368 | * an ISR. */ | ||
369 | if (cpu_frequency < 50000000) | ||
370 | { | ||
371 | while (p_bytes < p_end) | ||
372 | { | ||
373 | _write_fast(*p_bytes++); | ||
374 | #ifdef HAVE_REMOTE_LCD_TICKING | ||
375 | _byte_delay(byte_delay - 87); | ||
376 | #endif | ||
377 | } | ||
378 | } | ||
379 | else | ||
380 | { | ||
381 | while (p_bytes < p_end) | ||
382 | { | ||
383 | _write_byte(*p_bytes++); | ||
384 | #ifdef HAVE_REMOTE_LCD_TICKING | ||
385 | _byte_delay(byte_delay - 148); | ||
386 | #endif | ||
387 | } | ||
388 | } | ||
389 | |||
390 | cs_countdown = CS_TIMEOUT; | ||
391 | } | ||
392 | #endif /* !SIMULATOR */ | ||
393 | |||
394 | /*** hardware configuration ***/ | ||
395 | |||
396 | int lcd_remote_default_contrast(void) | ||
397 | { | ||
398 | return DEFAULT_REMOTE_CONTRAST_SETTING; | ||
399 | } | ||
400 | |||
401 | #ifndef SIMULATOR | 65 | #ifndef SIMULATOR |
402 | 66 | struct event_queue remote_scroll_queue; | |
403 | #ifdef HAVE_REMOTE_LCD_TICKING | ||
404 | void lcd_remote_emireduce(bool state) | ||
405 | { | ||
406 | emireduce = state; | ||
407 | } | ||
408 | #endif | ||
409 | |||
410 | void lcd_remote_powersave(bool on) | ||
411 | { | ||
412 | if (remote_initialized) | ||
413 | { | ||
414 | lcd_remote_write_command(LCD_REMOTE_CNTL_DISPLAY_ON_OFF | (on ? 0 : 1)); | ||
415 | lcd_remote_write_command(LCD_REMOTE_CNTL_ENTIRE_ON_OFF | (on ? 1 : 0)); | ||
416 | } | ||
417 | } | ||
418 | |||
419 | void lcd_remote_set_contrast(int val) | ||
420 | { | ||
421 | cached_contrast = val; | ||
422 | if (remote_initialized) | ||
423 | lcd_remote_write_command_ex(LCD_REMOTE_CNTL_SELECT_VOLTAGE, val); | ||
424 | } | ||
425 | |||
426 | void lcd_remote_set_invert_display(bool yesno) | ||
427 | { | ||
428 | cached_invert = yesno; | ||
429 | if (remote_initialized) | ||
430 | lcd_remote_write_command(LCD_REMOTE_CNTL_REVERSE_ON_OFF | (yesno?1:0)); | ||
431 | } | ||
432 | |||
433 | /* turn the display upside down (call lcd_remote_update() afterwards) */ | ||
434 | void lcd_remote_set_flip(bool yesno) | ||
435 | { | ||
436 | cached_flip = yesno; | ||
437 | if (yesno) | ||
438 | { | ||
439 | xoffset = 0; | ||
440 | if (remote_initialized) | ||
441 | { | ||
442 | lcd_remote_write_command(LCD_REMOTE_CNTL_ADC_NORMAL); | ||
443 | lcd_remote_write_command(LCD_REMOTE_CNTL_SHL_NORMAL); | ||
444 | } | ||
445 | } | ||
446 | else | ||
447 | { | ||
448 | xoffset = 132 - LCD_REMOTE_WIDTH; | ||
449 | if (remote_initialized) | ||
450 | { | ||
451 | lcd_remote_write_command(LCD_REMOTE_CNTL_ADC_REVERSE); | ||
452 | lcd_remote_write_command(LCD_REMOTE_CNTL_SHL_REVERSE); | ||
453 | } | ||
454 | } | ||
455 | } | ||
456 | |||
457 | /* The actual LCD init */ | ||
458 | static void remote_lcd_init(void) | ||
459 | { | ||
460 | CS_HI; | ||
461 | CLK_LO; | ||
462 | lcd_remote_write_command(LCD_REMOTE_CNTL_SELECT_BIAS | 0x0); | ||
463 | |||
464 | lcd_remote_write_command(LCD_REMOTE_CNTL_POWER_CONTROL | 0x5); | ||
465 | sleep(1); | ||
466 | lcd_remote_write_command(LCD_REMOTE_CNTL_POWER_CONTROL | 0x6); | ||
467 | sleep(1); | ||
468 | lcd_remote_write_command(LCD_REMOTE_CNTL_POWER_CONTROL | 0x7); | ||
469 | |||
470 | lcd_remote_write_command(LCD_REMOTE_CNTL_SELECT_REGULATOR | 0x4); // 0x4 Select regulator @ 5.0 (default); | ||
471 | |||
472 | sleep(1); | ||
473 | |||
474 | lcd_remote_write_command(LCD_REMOTE_CNTL_INIT_LINE | 0x0); // init line | ||
475 | lcd_remote_write_command(LCD_REMOTE_CNTL_SET_PAGE_ADDRESS | 0x0); // page address | ||
476 | lcd_remote_write_command_ex(0x10, 0x00); // Column MSB + LSB | ||
477 | |||
478 | lcd_remote_write_command(LCD_REMOTE_CNTL_DISPLAY_ON_OFF | 1); | ||
479 | |||
480 | remote_initialized = true; | ||
481 | |||
482 | lcd_remote_set_flip(cached_flip); | ||
483 | lcd_remote_set_contrast(cached_contrast); | ||
484 | lcd_remote_set_invert_display(cached_invert); | ||
485 | } | ||
486 | |||
487 | bool remote_detect(void) | ||
488 | { | ||
489 | return (GPIO_READ & 0x40000000)?false:true; | ||
490 | } | ||
491 | |||
492 | int remote_type(void) | ||
493 | { | ||
494 | return _remote_type; | ||
495 | } | ||
496 | |||
497 | /* Monitor remote hotswap */ | ||
498 | static void remote_tick(void) | ||
499 | { | ||
500 | static bool last_status = false; | ||
501 | static int countdown = 0; | ||
502 | static int init_delay = 0; | ||
503 | bool current_status; | ||
504 | int val; | ||
505 | int level; | ||
506 | |||
507 | current_status = remote_detect(); | ||
508 | /* Only report when the status has changed */ | ||
509 | if (current_status != last_status) | ||
510 | { | ||
511 | last_status = current_status; | ||
512 | countdown = current_status ? 20*HZ : 1; | ||
513 | } | ||
514 | else | ||
515 | { | ||
516 | /* Count down until it gets negative */ | ||
517 | if (countdown >= 0) | ||
518 | countdown--; | ||
519 | |||
520 | if (current_status) | ||
521 | { | ||
522 | if (!(countdown % 8)) | ||
523 | { | ||
524 | /* Determine which type of remote it is */ | ||
525 | level = set_irq_level(HIGHEST_IRQ_LEVEL); | ||
526 | val = adc_scan(ADC_REMOTEDETECT); | ||
527 | set_irq_level(level); | ||
528 | |||
529 | if (val < ADCVAL_H100_LCD_REMOTE_HOLD) | ||
530 | { | ||
531 | if (val < ADCVAL_H100_LCD_REMOTE) | ||
532 | if (val < ADCVAL_H300_LCD_REMOTE) | ||
533 | _remote_type = REMOTETYPE_H300_LCD; /* hold off */ | ||
534 | else | ||
535 | _remote_type = REMOTETYPE_H100_LCD; /* hold off */ | ||
536 | else | ||
537 | if (val < ADCVAL_H300_LCD_REMOTE_HOLD) | ||
538 | _remote_type = REMOTETYPE_H300_LCD; /* hold on */ | ||
539 | else | ||
540 | _remote_type = REMOTETYPE_H100_LCD; /* hold on */ | ||
541 | |||
542 | if (--init_delay <= 0) | ||
543 | { | ||
544 | queue_post(&remote_scroll_queue, REMOTE_INIT_LCD, 0); | ||
545 | init_delay = 6; | ||
546 | } | ||
547 | } | ||
548 | else | ||
549 | { | ||
550 | _remote_type = REMOTETYPE_H300_NONLCD; /* hold on or off */ | ||
551 | } | ||
552 | } | ||
553 | } | ||
554 | else | ||
555 | { | ||
556 | if (countdown == 0) | ||
557 | { | ||
558 | _remote_type = REMOTETYPE_UNPLUGGED; | ||
559 | |||
560 | queue_post(&remote_scroll_queue, REMOTE_DEINIT_LCD, 0); | ||
561 | } | ||
562 | } | ||
563 | } | ||
564 | |||
565 | /* handle chip select timeout */ | ||
566 | if (cs_countdown >= 0) | ||
567 | cs_countdown--; | ||
568 | if (cs_countdown == 0) | ||
569 | CS_HI; | ||
570 | } | ||
571 | #endif /* !SIMULATOR */ | ||
572 | |||
573 | /* LCD init */ | ||
574 | #ifdef SIMULATOR | ||
575 | |||
576 | void lcd_remote_init(void) | ||
577 | { | ||
578 | create_thread(scroll_thread, scroll_stack, | ||
579 | sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)); | ||
580 | } | ||
581 | #else /* !SIMULATOR */ | ||
582 | |||
583 | /* Initialise ports and kick off monitor */ | ||
584 | void lcd_remote_init(void) | ||
585 | { | ||
586 | #ifdef IRIVER_H300_SERIES | ||
587 | or_l(0x10010000, &GPIO_FUNCTION); /* GPIO16: RS | ||
588 | GPIO28: CLK */ | ||
589 | |||
590 | or_l(0x00040006, &GPIO1_FUNCTION); /* GPO33: Backlight | ||
591 | GPIO34: CS | ||
592 | GPIO50: Data */ | ||
593 | or_l(0x10010000, &GPIO_ENABLE); | ||
594 | or_l(0x00040006, &GPIO1_ENABLE); | ||
595 | #else | ||
596 | or_l(0x10010800, &GPIO_FUNCTION); /* GPIO11: Backlight | ||
597 | GPIO16: RS | ||
598 | GPIO28: CLK */ | ||
599 | |||
600 | or_l(0x00040004, &GPIO1_FUNCTION); /* GPIO34: CS | ||
601 | GPIO50: Data */ | ||
602 | or_l(0x10010800, &GPIO_ENABLE); | ||
603 | or_l(0x00040004, &GPIO1_ENABLE); | ||
604 | #endif | 67 | #endif |
605 | lcd_remote_clear_display(); | ||
606 | |||
607 | /* private queue */ | ||
608 | queue_init(&remote_scroll_queue, false); | ||
609 | tick_add_task(remote_tick); | ||
610 | create_thread(scroll_thread, scroll_stack, | ||
611 | sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)); | ||
612 | } | ||
613 | |||
614 | /*** update functions ***/ | ||
615 | |||
616 | /* Update the display. | ||
617 | This must be called after all other LCD functions that change the display. */ | ||
618 | void lcd_remote_update(void) ICODE_ATTR; | ||
619 | void lcd_remote_update(void) | ||
620 | { | ||
621 | int y; | ||
622 | |||
623 | if (!remote_initialized) | ||
624 | return; | ||
625 | |||
626 | #ifdef HAVE_REMOTE_LCD_TICKING | ||
627 | /* Adjust byte delay for emi reduction. */ | ||
628 | byte_delay = emireduce ? cpu_frequency / 197600 + 28: 0; | ||
629 | #endif | ||
630 | |||
631 | /* Copy display bitmap to hardware */ | ||
632 | for (y = 0; y < LCD_REMOTE_FBHEIGHT; y++) | ||
633 | { | ||
634 | lcd_remote_write_command(LCD_REMOTE_CNTL_SET_PAGE_ADDRESS | y); | ||
635 | lcd_remote_write_command(LCD_REMOTE_CNTL_HIGHCOL | ((xoffset >> 4) & 0xf)); | ||
636 | lcd_remote_write_command(LCD_REMOTE_CNTL_LOWCOL | (xoffset & 0xf)); | ||
637 | lcd_remote_write_data(lcd_remote_framebuffer[y], LCD_REMOTE_WIDTH); | ||
638 | } | ||
639 | } | ||
640 | |||
641 | /* Update a fraction of the display. */ | ||
642 | void lcd_remote_update_rect(int, int, int, int) ICODE_ATTR; | ||
643 | void lcd_remote_update_rect(int x, int y, int width, int height) | ||
644 | { | ||
645 | int ymax; | ||
646 | |||
647 | if (!remote_initialized) | ||
648 | return; | ||
649 | |||
650 | /* The Y coordinates have to work on even 8 pixel rows */ | ||
651 | ymax = (y + height-1) >> 3; | ||
652 | y >>= 3; | ||
653 | |||
654 | if(x + width > LCD_REMOTE_WIDTH) | ||
655 | width = LCD_REMOTE_WIDTH - x; | ||
656 | if (width <= 0) | ||
657 | return; /* nothing left to do, 0 is harmful to lcd_write_data() */ | ||
658 | if(ymax >= LCD_REMOTE_FBHEIGHT) | ||
659 | ymax = LCD_REMOTE_FBHEIGHT-1; | ||
660 | |||
661 | #ifdef HAVE_REMOTE_LCD_TICKING | ||
662 | /* Adjust byte delay for emi reduction */ | ||
663 | byte_delay = emireduce ? cpu_frequency / 197600 + 28: 0; | ||
664 | #endif | ||
665 | |||
666 | /* Copy specified rectange bitmap to hardware */ | ||
667 | for (; y <= ymax; y++) | ||
668 | { | ||
669 | lcd_remote_write_command(LCD_REMOTE_CNTL_SET_PAGE_ADDRESS | y); | ||
670 | lcd_remote_write_command(LCD_REMOTE_CNTL_HIGHCOL | (((x+xoffset) >> 4) & 0xf)); | ||
671 | lcd_remote_write_command(LCD_REMOTE_CNTL_LOWCOL | ((x+xoffset) & 0xf)); | ||
672 | lcd_remote_write_data(&lcd_remote_framebuffer[y][x], width); | ||
673 | } | ||
674 | } | ||
675 | #endif /* !SIMULATOR */ | ||
676 | 68 | ||
677 | /*** parameter handling ***/ | 69 | /*** parameter handling ***/ |
678 | 70 | ||
@@ -1335,12 +727,12 @@ void lcd_remote_puts_scroll(int x, int y, const unsigned char *string) | |||
1335 | 727 | ||
1336 | void lcd_remote_puts_scroll_style(int x, int y, const unsigned char *string, int style) | 728 | void lcd_remote_puts_scroll_style(int x, int y, const unsigned char *string, int style) |
1337 | { | 729 | { |
1338 | lcd_remote_puts_scroll_style_offset(x, y, string, style, 0); | 730 | lcd_remote_puts_scroll_style_offset(x, y, string, style, 0); |
1339 | } | 731 | } |
1340 | 732 | ||
1341 | void lcd_remote_puts_scroll_offset(int x, int y, const unsigned char *string, int offset) | 733 | void lcd_remote_puts_scroll_offset(int x, int y, const unsigned char *string, int offset) |
1342 | { | 734 | { |
1343 | lcd_remote_puts_scroll_style_offset(x, y, string, STYLE_DEFAULT, offset); | 735 | lcd_remote_puts_scroll_style_offset(x, y, string, STYLE_DEFAULT, offset); |
1344 | } | 736 | } |
1345 | 737 | ||
1346 | void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *string, | 738 | void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *string, |
@@ -1430,14 +822,12 @@ static void scroll_thread(void) | |||
1430 | switch (ev.id) | 822 | switch (ev.id) |
1431 | { | 823 | { |
1432 | case REMOTE_INIT_LCD: | 824 | case REMOTE_INIT_LCD: |
1433 | remote_lcd_init(); | 825 | lcd_remote_on(); |
1434 | lcd_remote_update(); | 826 | lcd_remote_update(); |
1435 | break; | 827 | break; |
1436 | 828 | ||
1437 | case REMOTE_DEINIT_LCD: | 829 | case REMOTE_DEINIT_LCD: |
1438 | CLK_LO; | 830 | lcd_remote_off(); |
1439 | CS_HI; | ||
1440 | remote_initialized = false; | ||
1441 | break; | 831 | break; |
1442 | } | 832 | } |
1443 | 833 | ||
@@ -1503,3 +893,15 @@ static void scroll_thread(void) | |||
1503 | } | 893 | } |
1504 | } | 894 | } |
1505 | 895 | ||
896 | /* LCD init */ | ||
897 | void lcd_remote_init(void) | ||
898 | { | ||
899 | #ifndef SIMULATOR | ||
900 | /* Call device specific init */ | ||
901 | lcd_remote_init_device(); | ||
902 | /* private queue */ | ||
903 | queue_init(&remote_scroll_queue, false); | ||
904 | #endif | ||
905 | create_thread(scroll_thread, scroll_stack, | ||
906 | sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)); | ||
907 | } | ||