summaryrefslogtreecommitdiff
path: root/firmware/target
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target')
-rw-r--r--firmware/target/coldfire/iaudio/m3/lcd-as-m3.S516
-rw-r--r--firmware/target/coldfire/iaudio/m3/lcd-m3.c305
2 files changed, 547 insertions, 274 deletions
diff --git a/firmware/target/coldfire/iaudio/m3/lcd-as-m3.S b/firmware/target/coldfire/iaudio/m3/lcd-as-m3.S
new file mode 100644
index 0000000000..5f77e01e86
--- /dev/null
+++ b/firmware/target/coldfire/iaudio/m3/lcd-as-m3.S
@@ -0,0 +1,516 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2008 by Jens Arnold
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
20#define CLOCK_MASK 0x20000000
21#define DATA_MASK 0x04000000
22#define GPIO_OUT_ADDR 0x80000004
23
24#define CS_MASK 0x00010000
25#define RS_MASK 0x00001000
26#define GPIO1_OUT_ADDR 0x800000b4
27
28 .extern cpu_frequency /* Global variable from system.c */
29
30 .section .icode,"ax",@progbits
31
32 /* Output 8 bits to the LCD. Instruction order is devised to maximize the
33 * delay between changing the data line and the CLK L->H transition, which
34 * makes the LCD controller sample DATA.
35 *
36 * Custom calling convention:
37 * %a0 - GPIO_OUT_ADDR
38 * %d3 - data byte
39 * %d6 - DATA_MASK
40 * %d7 - CLOCK_MASK
41 * Clobbers:
42 * %d0..%d3
43 */
44.write_byte:
45 move.w %sr, %d2
46 move.w #0x2700, %sr
47
48 move.l (%a0), %d0 /* Get current state of data port */
49 move.l %d0, %d1
50 and.l %d6, %d1 /* Check current state of data line */
51 beq.s 1f /* and set it as previous-state bit */
52 bset #8, %d3
531:
54 move.l %d3, %d1 /* Compute the 'bit derivative', i.e. a value */
55 lsr.l #1, %d1 /* with 1's where the data changes from the */
56 eor.l %d1, %d3 /* previous state, and 0's where it doesn't */
57 swap %d3 /* Shift data to upper byte */
58 lsl.l #8, %d3
59
60 eor.l %d7, %d0 /* precalculate opposite state of clock line */
61
62 lsl.l #1,%d3 /* Shift out MSB */
63 bcc.s 1f
64 eor.l %d6, %d0 /* 1: Flip data bit */
651:
66 move.l %d0, %d1
67 move.l %d0, (%a0) /* Output new state and set CLK = 0*/
68 eor.l %d7, %d1
69 bra.w .wr_bit7
70
71
72 /* Output 16 bits to the LCD. Instruction order is devised to maximize the
73 * delay between changing the data line and the CLK L->H transition, which
74 * makes the LCD controller sample DATA.
75 *
76 * Custom calling convention:
77 * %a0 - GPIO_OUT_ADDR
78 * %d3 - data word
79 * %d6 - DATA_MASK
80 * %d7 - CLOCK_MASK
81 * Clobbers:
82 * %d0..%d3
83 */
84.write_word:
85 move.w %sr, %d2
86 move.w #0x2700, %sr
87
88 move.l (%a0), %d0 /* Get current state of data port */
89 move.l %d0, %d1
90 and.l %d6, %d1 /* Check current state of data line */
91 beq.s 1f /* and set it as previous-state bit */
92 bset #16, %d3
931:
94 move.l %d3, %d1 /* Compute the 'bit derivative', i.e. a value */
95 lsr.l #1, %d1 /* with 1's where the data changes from the */
96 eor.l %d1, %d3 /* previous state, and 0's where it doesn't */
97 swap %d3 /* Shift data to upper word */
98
99 eor.l %d7, %d0 /* precalculate opposite state of clock line */
100
101 lsl.l #1,%d3 /* Shift out MSB */
102 bcc.s 1f
103 eor.l %d6, %d0 /* 1: Flip data bit */
1041:
105 move.l %d0, %d1
106 move.l %d0, (%a0) /* Output new state and set CLK = 0*/
107 eor.l %d7, %d1
108 nop
109
110.macro bit_out
111 lsl.l #1,%d3
112 bcc.s 1f
113 eor.l %d6, %d0
1141:
115 move.l %d1, (%a0) /* Set CLK = 1 (delayed) */
116 move.l %d0, %d1
117 move.l %d0, (%a0)
118 eor.l %d7, %d1
119.endm
120 bit_out
121 nop
122 bit_out
123 nop
124 bit_out
125 nop
126 bit_out
127 nop
128 bit_out
129 nop
130 bit_out
131 nop
132 bit_out
133 nop
134 bit_out
135 nop
136
137.wr_bit7:
138 bit_out
139 nop
140 bit_out
141 nop
142 bit_out
143 nop
144 bit_out
145 nop
146 bit_out
147 nop
148 bit_out
149 nop
150 bit_out
151 nop
152
153 nop
154 move.l %d1, (%a0) /* Set CLK = 1 (delayed) */
155 move.w %d2, %sr
156 rts
157
158
159 /* Output 16 bits to the LCD as fast as possible. Use only at < 60MHz.
160 *
161 * Custom calling convention:
162 * %a0 - GPIO_OUT_ADDR
163 * %d3 - data word
164 * %d6 - DATA_MASK
165 * %d7 - CLOCK_MASK
166 * Clobbers:
167 * %d0..%d3
168 */
169.write_word_fast:
170 move.w %sr, %d2 /* Get current interrupt level */
171 move.w #0x2700, %sr /* Disable interrupts */
172
173 move.l (%a0), %d0 /* Get current state of data port */
174 move.l %d0, %d1
175 and.l %d6, %d1 /* Check current state of data line */
176 beq.s 1f /* and set it as previous-state bit */
177 bset #16, %d3
1781:
179 move.l %d3, %d1 /* Compute the 'bit derivative', i.e. a value */
180 lsr.l #1, %d1 /* with 1's where the data changes from the */
181 eor.l %d1, %d3 /* previous state, and 0's where it doesn't */
182 swap %d3 /* Shift data to upper byte */
183
184 move.l %d0, %d1 /* precalculate opposite state of clock line */
185 eor.l %d7, %d1
186
187.macro bit_out_fast
188 lsl.l #1,%d3 /* Shift out MSB */
189 bcc.s 1f
190 eor.l %d6, %d0 /* 1: Flip data bit */
191 eor.l %d6, %d1 /* for both clock states */
1921:
193 move.l %d1, (%a0) /* Output new state and set CLK = 0*/
194 move.l %d0, (%a0) /* set CLK = 1 */
195.endm
196 bit_out_fast
197 bit_out_fast
198 bit_out_fast
199 bit_out_fast
200 bit_out_fast
201 bit_out_fast
202 bit_out_fast
203 bit_out_fast
204 bit_out_fast
205 bit_out_fast
206 bit_out_fast
207 bit_out_fast
208 bit_out_fast
209 bit_out_fast
210 bit_out_fast
211 bit_out_fast
212
213 move.w %d2, %sr /* Restore interrupt level */
214 rts
215
216
217 .global lcd_write_command
218 .type lcd_write_command, @function
219
220lcd_write_command:
221 lea.l (-4*4, %sp), %sp
222 movem.l %d2-%d3/%d6-%d7, (%sp)
223
224 move.l (4*4+4, %sp), %d3 /* cmd */
225
226 lea.l GPIO_OUT_ADDR, %a0
227 lea.l GPIO1_OUT_ADDR, %a1
228 move.l #DATA_MASK, %d6
229 move.l #CLOCK_MASK, %d7
230
231 move.l #~(RS_MASK+CS_MASK), %d0
232 and.l %d0, (%a1)
233
234 bsr.w .write_byte
235
236 move.l #CS_MASK, %d0
237 or.l %d0, (%a1)
238
239 movem.l (%sp), %d2-%d3/%d6-%d7
240 lea.l (4*4, %sp), %sp
241 rts
242
243
244 .global lcd_write_command_e
245 .type lcd_write_command_e, @function
246
247lcd_write_command_e:
248 lea.l (-4*4, %sp), %sp
249 movem.l %d2-%d3/%d6-%d7, (%sp)
250
251 movem.l (4*4+4, %sp), %d2-%d3 /* cmd, data */
252
253 lea.l GPIO_OUT_ADDR, %a0
254 lea.l GPIO1_OUT_ADDR, %a1
255 move.l #DATA_MASK, %d6
256 move.l #CLOCK_MASK, %d7
257
258 move.l #~(RS_MASK+CS_MASK), %d0
259 and.l %d0, (%a1)
260
261 lsl.l #8, %d2
262 or.l %d2, %d3
263 bsr.w .write_word
264
265 move.l #CS_MASK, %d0
266 or.l %d0, (%a1)
267
268 movem.l (%sp), %d2-%d3/%d6-%d7
269 lea.l (4*4, %sp), %sp
270 rts
271
272
273 .global lcd_write_data
274 .type lcd_write_data, @function
275
276lcd_write_data:
277 lea.l (-7*4, %sp), %sp
278 movem.l %d2-%d4/%d6-%d7/%a2-%a3, (%sp)
279
280 move.l (7*4+4, %sp), %a2 /* p_words */
281 move.l (7*4+8, %sp), %d4 /* count */
282
283 lea.l GPIO_OUT_ADDR, %a0
284 lea.l GPIO1_OUT_ADDR, %a1
285 move.l #DATA_MASK, %d6
286 move.l #CLOCK_MASK, %d7
287
288 lea.l .write_word, %a3
289 move.l cpu_frequency, %d0
290 cmp.l #60000000, %d0
291 bhi.b 1f
292 lea.l .write_word_fast, %a3
2931:
294
295 move.l #RS_MASK, %d0
296 or.l %d0, (%a1)
297 move.l #~CS_MASK, %d0
298 and.l %d0, (%a1)
299
300.wd_loop:
301 clr.l %d3
302 move.w (%a2)+, %d3
303 jsr (%a3)
304 subq.l #1, %d4
305 bne.s .wd_loop
306
307 move.l #CS_MASK, %d0
308 or.l %d0, (%a1)
309
310 movem.l (%sp), %d2-%d4/%d6-%d7/%a2-%a3
311 lea.l (7*4, %sp), %sp
312 rts
313
314
315/*** The following functions are only needed for main LCDs ***/
316
317
318 .global lcd_mono_data
319 .type lcd_mono_data, @function
320
321lcd_mono_data:
322 lea.l (-7*4, %sp), %sp
323 movem.l %d2-%d4/%d6-%d7/%a2-%a3, (%sp)
324
325 move.l (7*4+4, %sp), %a2 /* p_bytes */
326 move.l (7*4+8, %sp), %d4 /* count */
327
328 lea.l GPIO_OUT_ADDR, %a0
329 lea.l GPIO1_OUT_ADDR, %a1
330 move.l #DATA_MASK, %d6
331 move.l #CLOCK_MASK, %d7
332
333 lea.l .write_word, %a3
334 move.l cpu_frequency, %d0
335 cmp.l #60000000, %d0
336 bhi.b 1f
337 lea.l .write_word_fast, %a3
3381:
339
340 move.l #RS_MASK, %d0
341 or.l %d0, (%a1)
342 move.l #~CS_MASK, %d0
343 and.l %d0, (%a1)
344
345.md_loop:
346 clr.l %d3
347 move.b (%a2)+, %d3
348 move.l %d3, %d2
349 lsl.l #8, %d2
350 or.l %d2, %d3
351 jsr (%a3)
352 subq.l #1, %d4
353 bne.s .md_loop
354
355 move.l #CS_MASK, %d0
356 or.l %d0, (%a1)
357
358 movem.l (%sp), %d2-%d4/%d6-%d7/%a2-%a3
359 lea.l (7*4, %sp), %sp
360 rts
361
362
363 .global lcd_grey_data
364 .type lcd_grey_data,@function
365
366lcd_grey_data:
367 lea.l (-9*4, %sp), %sp
368 movem.l %d2-%d7/%a2-%a4, (%sp)
369
370 movem.l (9*4+4, %sp), %a2-%a4 /* values, phases, length */
371 add.l %a4, %a4
372 lea.l (%a3, %a4.l*4), %a4 /* end address */
373
374 lea.l GPIO_OUT_ADDR, %a0
375 lea.l GPIO1_OUT_ADDR, %a1
376 move.l #DATA_MASK, %d6
377 move.l #CLOCK_MASK, %d7
378
379 move.l #RS_MASK, %d0
380 or.l %d0, (%a1)
381 move.l #~CS_MASK, %d0
382 and.l %d0, (%a1)
383
384 clr.l %d5
385 move.l (%a3), %d4 /* fetch 4 pixel phases */
386 bclr.l #31, %d4 /* Z = !(p0 & 0x80); p0 &= ~0x80; */
387 seq.b %d5 /* %d5 = ........................00000000 */
388 lsl.l #1, %d5 /* %d5 = .......................00000000. */
389 bclr.l #23, %d4 /* Z = !(p1 & 0x80); p1 &= ~0x80; */
390 seq.b %d5 /* %d5 = .......................011111111 */
391 lsl.l #1, %d5 /* %d5 = ......................011111111. */
392 bclr.l #15, %d4 /* Z = !(p2 & 0x80); p2 &= ~0x80; */
393 seq.b %d5 /* %d5 = ......................0122222222 */
394 lsl.l #1, %d5 /* %d5 = .....................0122222222. */
395 bclr.l #7, %d4 /* Z = !(p3 & 0x80); p3 &= ~0x80; */
396 seq.b %d5 /* %d5 = .....................01233333333 */
397 lsl.l #1, %d5 /* %d5 = ....................01233333333. */
398 add.l (%a2)+, %d4 /* add 4 pixel values to the phases */
399 move.l %d4, (%a3)+ /* store new phases, advance pointer */
400
401 move.l (%a3), %d4 /* fetch 4 pixel phases */
402 bclr.l #31, %d4 /* Z = !(p0 & 0x80); p0 &= ~0x80; */
403 seq.b %d5 /* %d5 = ....................012344444444 */
404 lsl.l #1, %d5 /* %d5 = ...................012344444444. */
405 bclr.l #23, %d4 /* Z = !(p1 & 0x80); p1 &= ~0x80; */
406 seq.b %d5 /* %d5 = ...................0123455555555 */
407 lsl.l #1, %d5 /* %d5 = ..................0123455555555. */
408 bclr.l #15, %d4 /* Z = !(p2 & 0x80); p2 &= ~0x80; */
409 seq.b %d5 /* %d5 = ..................01234566666666 */
410 lsl.l #1, %d5 /* %d5 = .................01234566666666. */
411 bclr.l #7, %d4 /* Z = !(p3 & 0x80); p3 &= ~0x80; */
412 seq.b %d5 /* %d5 = .................012345677777777 */
413 lsr.l #7, %d5 /* %d5 = ........................01234567 */
414 add.l (%a2)+, %d4 /* add 4 pixel values to the phases */
415 move.l %d4, (%a3)+ /* store new phases, advance pointer */
416
417 move.l %d5, %d3
418 lsl.l #8, %d3
419 or.l %d5, %d3
420
421 cmp.l %a3, %a4
422 bls.w .gd_last
423
424.gd_loop:
425 move.w %sr, %d2
426 move.w #0x2700, %sr
427
428 move.l (%a0), %d0 /* Get current state of data port */
429 move.l %d0, %d1
430 and.l %d6, %d1 /* Check current state of data line */
431 beq.s 1f /* and set it as previous-state bit */
432 bset #16, %d3
4331:
434 move.l %d3, %d1 /* Compute the 'bit derivative', i.e. a value */
435 lsr.l #1, %d1 /* with 1's where the data changes from the */
436 eor.l %d1, %d3 /* previous state, and 0's where it doesn't */
437 swap %d3 /* Shift data to upper word */
438
439 eor.l %d7, %d0 /* precalculate opposite state of clock line */
440
441 lsl.l #1,%d3 /* Shift out MSB */
442 bcc.s 1f
443 eor.l %d6, %d0 /* 1: Flip data bit */
4441:
445 move.l %d0, %d1
446 move.l %d0, (%a0) /* Output new state and set CLK = 0*/
447 eor.l %d7, %d1
448
449 move.l (%a3), %d4 /* fetch 4 pixel phases */
450 bit_out
451 bclr.l #31, %d4 /* Z = !(p0 & 0x80); p0 &= ~0x80; */
452 seq.b %d5 /* %d5 = ........................00000000 */
453 lsl.l #1, %d5 /* %d5 = .......................00000000. */
454 bit_out
455 bclr.l #23, %d4 /* Z = !(p1 & 0x80); p1 &= ~0x80; */
456 seq.b %d5 /* %d5 = .......................011111111 */
457 lsl.l #1, %d5 /* %d5 = ......................011111111. */
458 bit_out
459 bclr.l #15, %d4 /* Z = !(p2 & 0x80); p2 &= ~0x80; */
460 seq.b %d5 /* %d5 = ......................0122222222 */
461 lsl.l #1, %d5 /* %d5 = .....................0122222222. */
462 bit_out
463 bclr.l #7, %d4 /* Z = !(p3 & 0x80); p3 &= ~0x80; */
464 seq.b %d5 /* %d5 = .....................01233333333 */
465 lsl.l #1, %d5 /* %d5 = ....................01233333333. */
466 bit_out
467 add.l (%a2)+, %d4 /* add 4 pixel values to the phases */
468 bit_out
469 move.l %d4, (%a3)+ /* store new phases, advance pointer */
470
471 bit_out
472 move.l (%a3), %d4 /* fetch 4 pixel phases */
473 bit_out
474 bclr.l #31, %d4 /* Z = !(p0 & 0x80); p0 &= ~0x80; */
475 seq.b %d5 /* %d5 = ....................012344444444 */
476 lsl.l #1, %d5 /* %d5 = ...................012344444444. */
477 bit_out
478 bclr.l #23, %d4 /* Z = !(p1 & 0x80); p1 &= ~0x80; */
479 seq.b %d5 /* %d5 = ...................0123455555555 */
480 lsl.l #1, %d5 /* %d5 = ..................0123455555555. */
481 bit_out
482 bclr.l #15, %d4 /* Z = !(p2 & 0x80); p2 &= ~0x80; */
483 seq.b %d5 /* %d5 = ..................01234566666666 */
484 lsl.l #1, %d5 /* %d5 = .................01234566666666. */
485 bit_out
486 bclr.l #7, %d4 /* Z = !(p3 & 0x80); p3 &= ~0x80; */
487 seq.b %d5 /* %d5 = .................012345677777777 */
488 lsr.l #7, %d5 /* %d5 = ........................01234567 */
489 bit_out
490 add.l (%a2)+, %d4 /* add 4 pixel values to the phases */
491 bit_out
492 move.l %d4, (%a3)+ /* store new phases, advance pointer */
493
494 bit_out
495 nop
496 bit_out
497 move.l %d5, %d3
498 lsl.l #8, %d3
499 or.l %d5, %d3
500
501 nop
502 move.l %d1, (%a0) /* Set CLK = 1 (delayed) */
503 move.w %d2, %sr
504
505 cmp.l %a3, %a4
506 bhi.w .gd_loop
507
508.gd_last:
509 bsr.w .write_word
510
511 move.l #CS_MASK, %d0
512 or.l %d0, (%a1)
513
514 movem.l (%sp), %d2-%d7/%a2-%a4
515 lea.l (9*4, %sp), %sp
516 rts
diff --git a/firmware/target/coldfire/iaudio/m3/lcd-m3.c b/firmware/target/coldfire/iaudio/m3/lcd-m3.c
index ae72832a82..81f19bd73f 100644
--- a/firmware/target/coldfire/iaudio/m3/lcd-m3.c
+++ b/firmware/target/coldfire/iaudio/m3/lcd-m3.c
@@ -61,263 +61,6 @@ static int cached_contrast = DEFAULT_CONTRAST_SETTING;
61bool initialized = false; 61bool initialized = false;
62 62
63 63
64/* Standard low-level byte writer. Requires CLK high on entry */
65static inline void _write_byte(unsigned data)
66{
67 asm volatile (
68 "move.l (%[gpo0]), %%d0 \n" /* Get current state of data line */
69 "and.l %[dbit], %%d0 \n"
70 "beq.s 1f \n" /* and set it as previous-state bit */
71 "bset #8, %[data] \n"
72 "1: \n"
73 "move.l %[data], %%d0 \n" /* Compute the 'bit derivative', i.e. a value */
74 "lsr.l #1, %%d0 \n" /* with 1's where the data changes from the */
75 "eor.l %%d0, %[data] \n" /* previous state, and 0's where it doesn't */
76 "swap %[data] \n" /* Shift data to upper byte */
77 "lsl.l #8, %[data] \n"
78
79 "move.l %[cbit], %%d1 \n" /* Prepare mask for flipping CLK */
80 "or.l %[dbit], %%d1 \n" /* and DATA at once */
81
82 "lsl.l #1,%[data] \n" /* Shift out MSB */
83 "bcc.s 1f \n"
84 "eor.l %%d1, (%[gpo0]) \n" /* 1: Flip both CLK and DATA */
85 ".word 0x51fa \n" /* (trapf.w - shadow next insn) */
86 "1: \n"
87 "eor.l %[cbit], (%[gpo0]) \n" /* else flip CLK only */
88 "eor.l %[cbit], (%[gpo0]) \n" /* Flip CLK again */
89
90 "lsl.l #1,%[data] \n" /* ..unrolled.. */
91 "bcc.s 1f \n"
92 "eor.l %%d1, (%[gpo0]) \n"
93 ".word 0x51fa \n"
94 "1: \n"
95 "eor.l %[cbit], (%[gpo0]) \n"
96 "eor.l %[cbit], (%[gpo0]) \n"
97
98 "lsl.l #1,%[data] \n"
99 "bcc.s 1f \n"
100 "eor.l %%d1, (%[gpo0]) \n"
101 ".word 0x51fa \n"
102 "1: \n"
103 "eor.l %[cbit], (%[gpo0]) \n"
104 "eor.l %[cbit], (%[gpo0]) \n"
105
106 "lsl.l #1,%[data] \n"
107 "bcc.s 1f \n"
108 "eor.l %%d1, (%[gpo0]) \n"
109 ".word 0x51fa \n"
110 "1: \n"
111 "eor.l %[cbit], (%[gpo0]) \n"
112 "eor.l %[cbit], (%[gpo0]) \n"
113
114 "lsl.l #1,%[data] \n"
115 "bcc.s 1f \n"
116 "eor.l %%d1, (%[gpo0]) \n"
117 ".word 0x51fa \n"
118 "1: \n"
119 "eor.l %[cbit], (%[gpo0]) \n"
120 "eor.l %[cbit], (%[gpo0]) \n"
121
122 "lsl.l #1,%[data] \n"
123 "bcc.s 1f \n"
124 "eor.l %%d1, (%[gpo0]) \n"
125 ".word 0x51fa \n"
126 "1: \n"
127 "eor.l %[cbit], (%[gpo0]) \n"
128 "eor.l %[cbit], (%[gpo0]) \n"
129
130 "lsl.l #1,%[data] \n"
131 "bcc.s 1f \n"
132 "eor.l %%d1, (%[gpo0]) \n"
133 ".word 0x51fa \n"
134 "1: \n"
135 "eor.l %[cbit], (%[gpo0]) \n"
136 "eor.l %[cbit], (%[gpo0]) \n"
137
138 "lsl.l #1,%[data] \n"
139 "bcc.s 1f \n"
140 "eor.l %%d1, (%[gpo0]) \n"
141 ".word 0x51fa \n"
142 "1: \n"
143 "eor.l %[cbit], (%[gpo0]) \n"
144 "eor.l %[cbit], (%[gpo0]) \n"
145 : /* outputs */
146 [data]"+d"(data)
147 : /* inputs */
148 [gpo0]"a"(&GPIO_OUT),
149 [cbit]"d"(0x20000000),
150 [dbit]"d"(0x04000000)
151 : /* clobbers */
152 "d0", "d1"
153 );
154}
155
156/* Fast low-level byte writer. Don't use with high CPU clock.
157 * Requires CLK high on entry */
158static inline void _write_fast(unsigned data)
159{
160 asm volatile (
161 "move.w %%sr,%%d3 \n" /* Get current interrupt level */
162 "move.w #0x2700,%%sr \n" /* Disable interrupts */
163
164 "move.l (%[gpo0]), %%d0 \n" /* Get current state of data port */
165 "move.l %%d0, %%d1 \n"
166 "and.l %[dbit], %%d1 \n" /* Check current state of data line */
167 "beq.s 1f \n" /* and set it as previous-state bit */
168 "bset #8, %[data] \n"
169 "1: \n"
170 "move.l %[data], %%d1 \n" /* Compute the 'bit derivative', i.e. a value */
171 "lsr.l #1, %%d1 \n" /* with 1's where the data changes from the */
172 "eor.l %%d1, %[data] \n" /* previous state, and 0's where it doesn't */
173 "swap %[data] \n" /* Shift data to upper byte */
174 "lsl.l #8, %[data] \n"
175
176 "move.l %%d0, %%d1 \n" /* precalculate opposite state of clock line */
177 "eor.l %[cbit], %%d1 \n"
178
179 "lsl.l #1,%[data] \n" /* Shift out MSB */
180 "bcc.s 1f \n"
181 "eor.l %[dbit], %%d0 \n" /* 1: Flip data bit */
182 "eor.l %[dbit], %%d1 \n" /* for both clock states */
183 "1: \n"
184 "move.l %%d1, (%[gpo0]) \n" /* Output new state and set CLK */
185 "move.l %%d0, (%[gpo0]) \n" /* reset CLK */
186
187 "lsl.l #1,%[data] \n" /* ..unrolled.. */
188 "bcc.s 1f \n"
189 "eor.l %[dbit], %%d0 \n"
190 "eor.l %[dbit], %%d1 \n"
191 "1: \n"
192 "move.l %%d1, (%[gpo0]) \n"
193 "move.l %%d0, (%[gpo0]) \n"
194
195 "lsl.l #1,%[data] \n"
196 "bcc.s 1f \n"
197 "eor.l %[dbit], %%d0 \n"
198 "eor.l %[dbit], %%d1 \n"
199 "1: \n"
200 "move.l %%d1, (%[gpo0]) \n"
201 "move.l %%d0, (%[gpo0]) \n"
202
203 "lsl.l #1,%[data] \n"
204 "bcc.s 1f \n"
205 "eor.l %[dbit], %%d0 \n"
206 "eor.l %[dbit], %%d1 \n"
207 "1: \n"
208 "move.l %%d1, (%[gpo0]) \n"
209 "move.l %%d0, (%[gpo0]) \n"
210
211 "lsl.l #1,%[data] \n"
212 "bcc.s 1f \n"
213 "eor.l %[dbit], %%d0 \n"
214 "eor.l %[dbit], %%d1 \n"
215 "1: \n"
216 "move.l %%d1, (%[gpo0]) \n"
217 "move.l %%d0, (%[gpo0]) \n"
218
219 "lsl.l #1,%[data] \n"
220 "bcc.s 1f \n"
221 "eor.l %[dbit], %%d0 \n"
222 "eor.l %[dbit], %%d1 \n"
223 "1: \n"
224 "move.l %%d1, (%[gpo0]) \n"
225 "move.l %%d0, (%[gpo0]) \n"
226
227 "lsl.l #1,%[data] \n"
228 "bcc.s 1f \n"
229 "eor.l %[dbit], %%d0 \n"
230 "eor.l %[dbit], %%d1 \n"
231 "1: \n"
232 "move.l %%d1, (%[gpo0]) \n"
233 "move.l %%d0, (%[gpo0]) \n"
234
235 "lsl.l #1,%[data] \n"
236 "bcc.s 1f \n"
237 "eor.l %[dbit], %%d0 \n"
238 "eor.l %[dbit], %%d1 \n"
239 "1: \n"
240 "move.l %%d1, (%[gpo0]) \n"
241 "move.l %%d0, (%[gpo0]) \n"
242
243 "move.w %%d3, %%sr \n" /* Restore interrupt level */
244 : /* outputs */
245 [data]"+d"(data)
246 : /* inputs */
247 [gpo0]"a"(&GPIO_OUT),
248 [cbit]"d"(0x20000000),
249 [dbit]"d"(0x04000000)
250 : /* clobbers */
251 "d0", "d1", "d2", "d3"
252 );
253}
254
255void lcd_write_command(int cmd)
256{
257 RS_LO;
258 CS_LO;
259 _write_byte(cmd);
260 CS_HI;
261}
262
263void lcd_write_command_e(int cmd, int data)
264{
265 RS_LO;
266 CS_LO;
267 _write_byte(cmd);
268 _write_byte(data);
269 CS_HI;
270}
271
272void lcd_write_data(const fb_data *p_words, int count)
273{
274 const unsigned char *p_bytes = (const unsigned char *)p_words;
275 const unsigned char *p_end = (const unsigned char *)(p_words + count);
276
277 RS_HI;
278 CS_LO;
279 if (cpu_frequency < 50000000)
280 {
281 while (p_bytes < p_end)
282 _write_fast(*p_bytes++);
283 }
284 else
285 {
286 while (p_bytes < p_end)
287 _write_byte(*p_bytes++);
288 }
289 CS_HI;
290}
291
292static void lcd_mono_data(const unsigned char *p_words, int count)
293{
294 unsigned data;
295 const unsigned char *p_bytes = p_words;
296 const unsigned char *p_end = p_words + count;
297
298 RS_HI;
299 CS_LO;
300 if (cpu_frequency < 50000000)
301 {
302 while (p_bytes < p_end)
303 {
304 data = *p_bytes++;
305 _write_fast(data);
306 _write_fast(data);
307 }
308 }
309 else
310 {
311 while (p_bytes < p_end)
312 {
313 data = *p_bytes++;
314 _write_byte(data);
315 _write_byte(data);
316 }
317 }
318 CS_HI;
319}
320
321int lcd_default_contrast(void) 64int lcd_default_contrast(void)
322{ 65{
323 return DEFAULT_CONTRAST_SETTING; 66 return DEFAULT_CONTRAST_SETTING;
@@ -457,6 +200,9 @@ void lcd_init_device(void)
457#endif 200#endif
458} 201}
459 202
203/* Helper function. */
204void lcd_mono_data(const unsigned char *data, int count);
205
460/* Performance function that works with an external buffer 206/* Performance function that works with an external buffer
461 note that by and bheight are in 8-pixel units! */ 207 note that by and bheight are in 8-pixel units! */
462void lcd_blit_mono(const unsigned char *data, int x, int by, int width, 208void lcd_blit_mono(const unsigned char *data, int x, int by, int width,
@@ -477,36 +223,44 @@ void lcd_blit_mono(const unsigned char *data, int x, int by, int width,
477 } 223 }
478} 224}
479 225
480/* TODO: implement grey blit function */ 226/* Helper function for lcd_grey_phase_blit(). */
227void lcd_grey_data(unsigned char *values, unsigned char *phases, int count);
481 228
482/* Performance function that works with an external buffer 229/* Performance function that works with an external buffer
483 note that by and bheight are in 8-pixel units! */ 230 note that by and bheight are in 8-pixel units! */
484void lcd_blit_grey_phase(unsigned char *values, unsigned char *phases, 231void lcd_blit_grey_phase(unsigned char *values, unsigned char *phases,
485 int x, int by, int width, int bheight, int stride) 232 int x, int by, int width, int bheight, int stride)
486{ 233{
487 (void)values; 234 if (initialized)
488 (void)phases; 235 {
489 (void)x; 236 stride <<= 3; /* 8 pixels per block */
490 (void)by; 237 while (bheight--)
491 (void)width; 238 {
492 (void)bheight; 239 lcd_write_command(LCD_SET_PAGE | ((by > 5 ? by + 2 : by) & 0xf));
493 (void)stride; 240 lcd_write_command_e(LCD_SET_COLUMN | ((x >> 4) & 0xf), x & 0xf);
241
242 lcd_grey_data(values, phases, width);
243 values += stride;
244 phases += stride;
245 by++;
246 }
247 }
494} 248}
495 249
496/* Update the display. 250/* Update the display.
497 This must be called after all other LCD functions that change the display. */ 251 This must be called after all other LCD functions that change the display. */
498void lcd_update(void) ICODE_ATTR;
499void lcd_update(void) 252void lcd_update(void)
500{ 253{
501 int y; 254 int y;
502 if (initialized) 255 if (initialized)
503 { 256 {
504 for(y = 0;y < LCD_FBHEIGHT;y++) { 257 for(y = 0;y < LCD_FBHEIGHT;y++)
258 {
505 /* Copy display bitmap to hardware. 259 /* Copy display bitmap to hardware.
506 The COM48-COM63 lines are not connected so we have to skip 260 The COM48-COM63 lines are not connected so we have to skip
507 them. Further, the column address doesn't wrap, so we 261 them. Further, the column address doesn't wrap, so we
508 have to update one page at a time. */ 262 have to update one page at a time. */
509 lcd_write_command(LCD_SET_PAGE | (y>5?y+2:y)); 263 lcd_write_command(LCD_SET_PAGE | (y > 5 ? y + 2 : y));
510 lcd_write_command_e(LCD_SET_COLUMN | 0, 0); 264 lcd_write_command_e(LCD_SET_COLUMN | 0, 0);
511 lcd_write_data(lcd_framebuffer[y], LCD_WIDTH); 265 lcd_write_data(lcd_framebuffer[y], LCD_WIDTH);
512 } 266 }
@@ -514,7 +268,6 @@ void lcd_update(void)
514} 268}
515 269
516/* Update a fraction of the display. */ 270/* Update a fraction of the display. */
517void lcd_update_rect(int, int, int, int) ICODE_ATTR;
518void lcd_update_rect(int x, int y, int width, int height) 271void lcd_update_rect(int x, int y, int width, int height)
519{ 272{
520 if (initialized) 273 if (initialized)
@@ -536,7 +289,7 @@ void lcd_update_rect(int x, int y, int width, int height)
536 COM48-COM63 are not connected, so we need to skip those */ 289 COM48-COM63 are not connected, so we need to skip those */
537 for (; y <= ymax; y++) 290 for (; y <= ymax; y++)
538 { 291 {
539 lcd_write_command(LCD_SET_PAGE | ((y > 5?y + 2:y) & 0xf)); 292 lcd_write_command(LCD_SET_PAGE | ((y > 5 ? y + 2 : y) & 0xf));
540 lcd_write_command_e(LCD_SET_COLUMN | ((x >> 4) & 0xf), x & 0xf); 293 lcd_write_command_e(LCD_SET_COLUMN | ((x >> 4) & 0xf), x & 0xf);
541 294
542 lcd_write_data(&lcd_framebuffer[y][x], width); 295 lcd_write_data(&lcd_framebuffer[y][x], width);
@@ -547,19 +300,23 @@ void lcd_update_rect(int x, int y, int width, int height)
547void lcd_set_invert_display(bool yesno) 300void lcd_set_invert_display(bool yesno)
548{ 301{
549 cached_invert = yesno; 302 cached_invert = yesno;
550 if(initialized) 303 if (initialized)
551 lcd_write_command(LCD_REVERSE | yesno); 304 lcd_write_command(LCD_REVERSE | yesno);
552} 305}
553 306
554void lcd_set_flip(bool yesno) 307void lcd_set_flip(bool yesno)
555{ 308{
556 cached_flip = yesno; 309 cached_flip = yesno;
557 if(initialized) { 310 if (initialized)
558 if(yesno) { 311 {
312 if(yesno)
313 {
559 lcd_write_command(LCD_SELECT_ADC | 0); 314 lcd_write_command(LCD_SELECT_ADC | 0);
560 lcd_write_command(LCD_SELECT_SHL | 0); 315 lcd_write_command(LCD_SELECT_SHL | 0);
561 lcd_write_command_e(LCD_SET_COM0, 16); 316 lcd_write_command_e(LCD_SET_COM0, 16);
562 } else { 317 }
318 else
319 {
563 lcd_write_command(LCD_SELECT_ADC | 1); 320 lcd_write_command(LCD_SELECT_ADC | 1);
564 lcd_write_command(LCD_SELECT_SHL | 8); 321 lcd_write_command(LCD_SELECT_SHL | 8);
565 lcd_write_command_e(LCD_SET_COM0, 0); 322 lcd_write_command_e(LCD_SET_COM0, 0);