summaryrefslogtreecommitdiff
path: root/firmware/drivers
diff options
context:
space:
mode:
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;
73static int ymargin = 0; 44static int ymargin = 0;
74static int curfont = FONT_SYSFIXED; 45static int curfont = FONT_SYSFIXED;
75 46
76#ifndef SIMULATOR
77static int xoffset; /* needed for flip */
78
79/* timeout counter for deasserting /CS after access, <0 means not counting */
80static 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. */
85static bool emireduce = false;
86static int byte_delay = 0;
87#endif
88
89/* remote hotplug */
90static struct event_queue remote_scroll_queue;
91#define REMOTE_INIT_LCD 1
92#define REMOTE_DEINIT_LCD 2
93
94static bool remote_initialized = false;
95static int _remote_type = REMOTETYPE_UNPLUGGED;
96
97/* cached settings values */
98static bool cached_invert = false;
99static bool cached_flip = false;
100static int cached_contrast = DEFAULT_REMOTE_CONTRAST_SETTING;
101#endif
102
103/* scrolling */ 47/* scrolling */
104static volatile int scrolling_lines=0; /* Bitpattern of which lines are scrolling */ 48static volatile int scrolling_lines=0; /* Bitpattern of which lines are scrolling */
105static void scroll_thread(void); 49static 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
125static 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 */
144static 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 */
227static 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
326void 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
340void 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
358void lcd_remote_write_data(const unsigned char* p_bytes, int count) ICODE_ATTR;
359void 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
396int lcd_remote_default_contrast(void)
397{
398 return DEFAULT_REMOTE_CONTRAST_SETTING;
399}
400
401#ifndef SIMULATOR 65#ifndef SIMULATOR
402 66struct event_queue remote_scroll_queue;
403#ifdef HAVE_REMOTE_LCD_TICKING
404void lcd_remote_emireduce(bool state)
405{
406 emireduce = state;
407}
408#endif
409
410void 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
419void 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
426void 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) */
434void 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 */
458static 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
487bool remote_detect(void)
488{
489 return (GPIO_READ & 0x40000000)?false:true;
490}
491
492int remote_type(void)
493{
494 return _remote_type;
495}
496
497/* Monitor remote hotswap */
498static 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
576void 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 */
584void 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. */
618void lcd_remote_update(void) ICODE_ATTR;
619void 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. */
642void lcd_remote_update_rect(int, int, int, int) ICODE_ATTR;
643void 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
1336void lcd_remote_puts_scroll_style(int x, int y, const unsigned char *string, int style) 728void 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
1341void lcd_remote_puts_scroll_offset(int x, int y, const unsigned char *string, int offset) 733void 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
1346void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *string, 738void 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 */
897void 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}