summaryrefslogtreecommitdiff
path: root/firmware/target/coldfire/iaudio/m3/lcd-m3.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/coldfire/iaudio/m3/lcd-m3.c')
-rw-r--r--firmware/target/coldfire/iaudio/m3/lcd-m3.c305
1 files changed, 31 insertions, 274 deletions
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);