summaryrefslogtreecommitdiff
path: root/firmware/drivers
diff options
context:
space:
mode:
authorJens Arnold <amiconn@rockbox.org>2006-08-22 05:25:04 +0000
committerJens Arnold <amiconn@rockbox.org>2006-08-22 05:25:04 +0000
commitacc153f1c5ebf6060b11c895298056f30caf10af (patch)
tree7a1f00885bb4f4ad3adb6ce1f2469b19cc50eb44 /firmware/drivers
parent4746e6765fa5bb7da5d2a43b198c6b46e51d5d52 (diff)
downloadrockbox-acc153f1c5ebf6060b11c895298056f30caf10af.tar.gz
rockbox-acc153f1c5ebf6060b11c895298056f30caf10af.zip
Irivers: Faster remote LCD update. Maximum speedup (without ticking reduction): +32% @11MHz, 2.5 times @45MHz, +45% @124MHz. The speedup is data dependent, the worst case (every pixel having the opposite value from the previous one, in LCD data order) would see no speedup (except @45MHz), but it's a highly unlikely case.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@10684 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/drivers')
-rw-r--r--firmware/drivers/lcd-h100-remote.c350
1 files changed, 198 insertions, 152 deletions
diff --git a/firmware/drivers/lcd-h100-remote.c b/firmware/drivers/lcd-h100-remote.c
index 8c1176bad8..bf4445462d 100644
--- a/firmware/drivers/lcd-h100-remote.c
+++ b/firmware/drivers/lcd-h100-remote.c
@@ -85,7 +85,7 @@ static int cs_countdown IDATA_ATTR = 0;
85#ifdef HAVE_REMOTE_LCD_TICKING 85#ifdef HAVE_REMOTE_LCD_TICKING
86/* If set to true, will prevent "ticking" to headphones. */ 86/* If set to true, will prevent "ticking" to headphones. */
87static bool emireduce = false; 87static bool emireduce = false;
88static int byte_delay = 172; 88static int byte_delay = 0;
89#endif 89#endif
90 90
91/* remote hotplug */ 91/* remote hotplug */
@@ -124,153 +124,204 @@ static const char scroll_tick_table[16] = {
124#ifndef SIMULATOR 124#ifndef SIMULATOR
125 125
126#ifdef HAVE_REMOTE_LCD_TICKING 126#ifdef HAVE_REMOTE_LCD_TICKING
127static inline void _byte_delay(void) 127static inline void _byte_delay(int delay)
128{ 128{
129 asm ( 129 asm (
130 "move.l %[dly],%%d0 \n" 130 "move.l %[dly], %%d0 \n"
131 "ble.s 2f \n"
131 "1: \n" 132 "1: \n"
132 "subq.l #1,%%d0 \n" 133 "subq.l #1, %%d0 \n"
133 "bhi.s 1b \n" 134 "bne.s 1b \n"
135 "2: \n"
134 : /* outputs */ 136 : /* outputs */
135 : /* inputs */ 137 : /* inputs */
136 [dly]"d"(byte_delay) 138 [dly]"d"(delay)
137 : /* clobbers */ 139 : /* clobbers */
138 "d0" 140 "d0"
139 ); 141 );
140} 142}
141#endif /* HAVE_REMOTE_LCD_TICKING */ 143#endif /* HAVE_REMOTE_LCD_TICKING */
142 144
143/* Standard low-level byte writer */ 145/* Standard low-level byte writer. Requires CLK low on entry */
144static inline void _write_byte(unsigned data) 146static inline void _write_byte(unsigned data)
145{ 147{
146 asm volatile ( 148 asm volatile (
147 "moveq.l #8,%%d1 \n" /* bit counter */ 149 "move.l (%[gpo1]), %%d0 \n" /* Get current state of data line */
148 150 "and.l %[dbit], %%d0 \n"
149 "2: \n" 151 "beq.s 1f \n" /* and set it as previous-state bit */
150 "lsl.l #1,%[data] \n" /* data <<= 1, MSB of data set? */ 152 "bset #8, %[data] \n"
151 "bcc.s 1f \n" 153 "1: \n"
152 "or.l %[dhi],(%[gpi1]) \n" /* set data bit */ 154 "move.l %[data], %%d0 \n" /* Compute the 'bit derivative', i.e. a value */
153 ".word 0x51fa \n" /* trapf.w - shadow next insn */ 155 "lsr.l #1, %%d0 \n" /* with 1's where the data changes from the */
154 "1: \n" 156 "eor.l %%d0, %[data] \n" /* previous state, and 0's where it doesn't */
155 "and.l %[dlo],(%[gpi1]) \n" /* reset data bit */ 157 "swap %[data] \n" /* Shift data to upper byte */
156 "eor.l %[cbit],(%[gpio]) \n" /* set clock bit */ 158 "lsl.l #8, %[data] \n"
157 "eor.l %[cbit],(%[gpio]) \n" /* reset clock bit */ 159
158 160 "lsl.l #1,%[data] \n" /* Shift out MSB */
159 "subq.l #1,%%d1 \n" 161 "bcc.s 1f \n"
160 "bne.s 2b \n" 162 "eor.l %[dbit], (%[gpo1]) \n" /* 1: flip DATA */
161 163 "1: \n"
162 "or.l %[dhi],(%[gpi1]) \n" /* set data bit */ 164 "eor.l %[cbit], (%[gpo0]) \n" /* Flip CLK */
165 "eor.l %[cbit], (%[gpo0]) \n" /* Flip CLK */
166
167 "lsl.l #1,%[data] \n" /* ..unrolled.. */
168 "bcc.s 1f \n"
169 "eor.l %[dbit], (%[gpo1]) \n"
170 "1: \n"
171 "eor.l %[cbit], (%[gpo0]) \n"
172 "eor.l %[cbit], (%[gpo0]) \n"
173
174 "lsl.l #1,%[data] \n"
175 "bcc.s 1f \n"
176 "eor.l %[dbit], (%[gpo1]) \n"
177 "1: \n"
178 "eor.l %[cbit], (%[gpo0]) \n"
179 "eor.l %[cbit], (%[gpo0]) \n"
180
181 "lsl.l #1,%[data] \n"
182 "bcc.s 1f \n"
183 "eor.l %[dbit], (%[gpo1]) \n"
184 "1: \n"
185 "eor.l %[cbit], (%[gpo0]) \n"
186 "eor.l %[cbit], (%[gpo0]) \n"
187
188 "lsl.l #1,%[data] \n"
189 "bcc.s 1f \n"
190 "eor.l %[dbit], (%[gpo1]) \n"
191 "1: \n"
192 "eor.l %[cbit], (%[gpo0]) \n"
193 "eor.l %[cbit], (%[gpo0]) \n"
194
195 "lsl.l #1,%[data] \n"
196 "bcc.s 1f \n"
197 "eor.l %[dbit], (%[gpo1]) \n"
198 "1: \n"
199 "eor.l %[cbit], (%[gpo0]) \n"
200 "eor.l %[cbit], (%[gpo0]) \n"
201
202 "lsl.l #1,%[data] \n"
203 "bcc.s 1f \n"
204 "eor.l %[dbit], (%[gpo1]) \n"
205 "1: \n"
206 "eor.l %[cbit], (%[gpo0]) \n"
207 "eor.l %[cbit], (%[gpo0]) \n"
208
209 "lsl.l #1,%[data] \n"
210 "bcc.s 1f \n"
211 "eor.l %[dbit], (%[gpo1]) \n"
212 "1: \n"
213 "eor.l %[cbit], (%[gpo0]) \n"
214 "eor.l %[cbit], (%[gpo0]) \n"
163 : /* outputs */ 215 : /* outputs */
216 [data]"+d"(data)
164 : /* inputs */ 217 : /* inputs */
165 [data]"d"(data << 24), 218 [gpo0]"a"(&GPIO_OUT),
166 [gpio]"a"(&GPIO_OUT),
167 [cbit]"d"(0x10000000), 219 [cbit]"d"(0x10000000),
168 [gpi1]"a"(&GPIO1_OUT), 220 [gpo1]"a"(&GPIO1_OUT),
169 [dhi] "d"(0x00040000), 221 [dbit]"d"(0x00040000)
170 [dlo] "d"(~0x00040000)
171 : /* clobbers */ 222 : /* clobbers */
172 "d1" 223 "d0"
173 ); 224 );
174} 225}
175 226
176/* Unrolled fast low-level byte writer. Don't use with high CPU clock. */ 227/* Fast low-level byte writer. Don't use with high CPU clock.
177static inline void _write_unrolled(unsigned data) 228 * Requires CLK low on entry */
229static inline void _write_fast(unsigned data)
178{ 230{
179 asm volatile ( 231 asm volatile (
180 "move.w %%sr,%%d4 \n" /* get current interrupt level */ 232 "move.w %%sr,%%d3 \n" /* Get current interrupt level */
181 "move.w #0x2700,%%sr \n" /* disable interrupts */ 233 "move.w #0x2700,%%sr \n" /* Disable interrupts */
182 234
183 "move.l #0x00040000,%%d1\n" /* precalculate port values */ 235 "move.l (%[gpo1]), %%d0 \n" /* Get current state of data port */
184 "move.l %%d1,%%d0 \n" /* for setting and resetting */ 236 "move.l %%d0, %%d1 \n"
185 "or.l (%[gpi1]),%%d1 \n" /* the data bit */ 237 "and.l %[dbit], %%d1 \n" /* Check current state of data line */
186 "eor.l %%d1,%%d0 \n" 238 "beq.s 1f \n" /* and set it as previous-state bit */
187 239 "bset #8, %[data] \n"
188 "move.l #0x10000000,%%d3\n" /* precalculate port values */ 240 "1: \n"
189 "move.l %%d3,%%d2 \n" /* for setting and resetting */ 241 "move.l %[data], %%d1 \n" /* Compute the 'bit derivative', i.e. a value */
190 "or.l (%[gpio]),%%d3 \n" /* the clock bit */ 242 "lsr.l #1, %%d1 \n" /* with 1's where the data changes from the */
191 "eor.l %%d3,%%d2 \n" 243 "eor.l %%d1, %[data] \n" /* previous state, and 0's where it doesn't */
192 244 "swap %[data] \n" /* Shift data to upper byte */
193 "lsl.l #1,%[data] \n" /* data <<= 1, MSB of data set? */ 245 "lsl.l #8, %[data] \n"
194 "bcc.s 1f \n" 246
195 "move.l %%d1,(%[gpi1]) \n" /* set data bit */ 247 "move.l (%[gpo0]), %%d1 \n" /* Get current state of clock port */
196 ".word 0x51fa \n" /* trapf.w - shadow next insn */ 248 "move.l %[cbit], %%d2 \n" /* Precalculate opposite state of clock line */
197 "1: \n" 249 "eor.l %%d1, %%d2 \n"
198 "move.l %%d0,(%[gpi1]) \n" /* reset data bit */ 250
199 "move.l %%d3,(%[gpio]) \n" /* set clock bit */ 251 "lsl.l #1,%[data] \n" /* Shift out MSB */
200 "move.l %%d2,(%[gpio]) \n" /* reset clock bit */ 252 "bcc.s 1f \n"
201 253 "eor.l %[dbit], %%d0 \n" /* 1: flip data bit */
202 "lsl.l #1,%[data] \n" 254 "move.l %%d0, (%[gpo1]) \n" /* and output new DATA state */
203 "bcc.s 1f \n" 255 "1: \n"
204 "move.l %%d1,(%[gpi1]) \n" 256 "move.l %%d2, (%[gpo0]) \n" /* Set CLK */
205 ".word 0x51fa \n" 257 "move.l %%d1, (%[gpo0]) \n" /* Reset CLK */
206 "1: \n" 258
207 "move.l %%d0,(%[gpi1]) \n" 259 "lsl.l #1,%[data] \n" /* ..unrolled.. */
208 "move.l %%d3,(%[gpio]) \n" 260 "bcc.s 1f \n"
209 "move.l %%d2,(%[gpio]) \n" 261 "eor.l %[dbit], %%d0 \n"
210 262 "move.l %%d0, (%[gpo1]) \n"
211 "lsl.l #1,%[data] \n" 263 "1: \n"
212 "bcc.s 1f \n" 264 "move.l %%d2, (%[gpo0]) \n"
213 "move.l %%d1,(%[gpi1]) \n" 265 "move.l %%d1, (%[gpo0]) \n"
214 ".word 0x51fa \n" 266
215 "1: \n" 267 "lsl.l #1,%[data] \n"
216 "move.l %%d0,(%[gpi1]) \n" 268 "bcc.s 1f \n"
217 "move.l %%d3,(%[gpio]) \n" 269 "eor.l %[dbit], %%d0 \n"
218 "move.l %%d2,(%[gpio]) \n" 270 "move.l %%d0, (%[gpo1]) \n"
219 271 "1: \n"
220 "lsl.l #1,%[data] \n" 272 "move.l %%d2, (%[gpo0]) \n"
221 "bcc.s 1f \n" 273 "move.l %%d1, (%[gpo0]) \n"
222 "move.l %%d1,(%[gpi1]) \n" 274
223 ".word 0x51fa \n" 275 "lsl.l #1,%[data] \n"
224 "1: \n" 276 "bcc.s 1f \n"
225 "move.l %%d0,(%[gpi1]) \n" 277 "eor.l %[dbit], %%d0 \n"
226 "move.l %%d3,(%[gpio]) \n" 278 "move.l %%d0, (%[gpo1]) \n"
227 "move.l %%d2,(%[gpio]) \n" 279 "1: \n"
228 280 "move.l %%d2, (%[gpo0]) \n"
229 "lsl.l #1,%[data] \n" 281 "move.l %%d1, (%[gpo0]) \n"
230 "bcc.s 1f \n" 282
231 "move.l %%d1,(%[gpi1]) \n" 283 "lsl.l #1,%[data] \n"
232 ".word 0x51fa \n" 284 "bcc.s 1f \n"
233 "1: \n" 285 "eor.l %[dbit], %%d0 \n"
234 "move.l %%d0,(%[gpi1]) \n" 286 "move.l %%d0, (%[gpo1]) \n"
235 "move.l %%d3,(%[gpio]) \n" 287 "1: \n"
236 "move.l %%d2,(%[gpio]) \n" 288 "move.l %%d2, (%[gpo0]) \n"
237 289 "move.l %%d1, (%[gpo0]) \n"
238 "lsl.l #1,%[data] \n" 290
239 "bcc.s 1f \n" 291 "lsl.l #1,%[data] \n"
240 "move.l %%d1,(%[gpi1]) \n" 292 "bcc.s 1f \n"
241 ".word 0x51fa \n" 293 "eor.l %[dbit], %%d0 \n"
242 "1: \n" 294 "move.l %%d0, (%[gpo1]) \n"
243 "move.l %%d0,(%[gpi1]) \n" 295 "1: \n"
244 "move.l %%d3,(%[gpio]) \n" 296 "move.l %%d2, (%[gpo0]) \n"
245 "move.l %%d2,(%[gpio]) \n" 297 "move.l %%d1, (%[gpo0]) \n"
246 298
247 "lsl.l #1,%[data] \n" 299 "lsl.l #1,%[data] \n"
248 "bcc.s 1f \n" 300 "bcc.s 1f \n"
249 "move.l %%d1,(%[gpi1]) \n" 301 "eor.l %[dbit], %%d0 \n"
250 ".word 0x51fa \n" 302 "move.l %%d0, (%[gpo1]) \n"
251 "1: \n" 303 "1: \n"
252 "move.l %%d0,(%[gpi1]) \n" 304 "move.l %%d2, (%[gpo0]) \n"
253 "move.l %%d3,(%[gpio]) \n" 305 "move.l %%d1, (%[gpo0]) \n"
254 "move.l %%d2,(%[gpio]) \n" 306
255 307 "lsl.l #1,%[data] \n"
256 "lsl.l #1,%[data] \n" 308 "bcc.s 1f \n"
257 "bcc.s 1f \n" 309 "eor.l %[dbit], %%d0 \n"
258 "move.l %%d1,(%[gpi1]) \n" 310 "move.l %%d0, (%[gpo1]) \n"
259 ".word 0x51fa \n" 311 "1: \n"
260 "1: \n" 312 "move.l %%d2, (%[gpo0]) \n"
261 "move.l %%d0,(%[gpi1]) \n" 313 "move.l %%d1, (%[gpo0]) \n"
262 "move.l %%d3,(%[gpio]) \n" 314
263 "move.l %%d2,(%[gpio]) \n" 315 "move.w %%d3, %%sr \n" /* Restore interrupt level */
264
265 "move.l %%d1,(%[gpi1]) \n" /* set data bit */
266 "move.w %%d4,%%sr \n" /* reenable interrupts */
267 : /* outputs */ 316 : /* outputs */
317 [data]"+d"(data)
268 : /* inputs */ 318 : /* inputs */
269 [data]"d"(data << 24), 319 [gpo0]"a"(&GPIO_OUT),
270 [gpio]"a"(&GPIO_OUT), 320 [cbit]"i"(0x10000000),
271 [gpi1]"a"(&GPIO1_OUT) 321 [gpo1]"a"(&GPIO1_OUT),
322 [dbit]"d"(0x00040000)
272 : /* clobbers */ 323 : /* clobbers */
273 "d0", "d1", "d2", "d3", "d4" 324 "d0", "d1", "d2", "d3"
274 ); 325 );
275} 326}
276 327
@@ -282,8 +333,7 @@ void lcd_remote_write_command(int cmd)
282 333
283 _write_byte(cmd); 334 _write_byte(cmd);
284#ifdef HAVE_REMOTE_LCD_TICKING 335#ifdef HAVE_REMOTE_LCD_TICKING
285 if (emireduce) 336 _byte_delay(byte_delay - 148);
286 _byte_delay();
287#endif 337#endif
288 338
289 cs_countdown = CS_TIMEOUT; 339 cs_countdown = CS_TIMEOUT;
@@ -295,20 +345,14 @@ void lcd_remote_write_command_ex(int cmd, int data)
295 RS_LO; 345 RS_LO;
296 CS_LO; 346 CS_LO;
297 347
348 _write_byte(cmd);
298#ifdef HAVE_REMOTE_LCD_TICKING 349#ifdef HAVE_REMOTE_LCD_TICKING
299 if (emireduce) 350 _byte_delay(byte_delay - 148);
300 { 351#endif
301 _write_byte(cmd); 352 _write_byte(data);
302 _byte_delay(); 353#ifdef HAVE_REMOTE_LCD_TICKING
303 _write_byte(data); 354 _byte_delay(byte_delay - 148);
304 _byte_delay();
305 }
306 else
307#endif 355#endif
308 {
309 _write_byte(cmd);
310 _write_byte(data);
311 }
312 356
313 cs_countdown = CS_TIMEOUT; 357 cs_countdown = CS_TIMEOUT;
314} 358}
@@ -323,25 +367,26 @@ void lcd_remote_write_data(const unsigned char* p_bytes, int count)
323 CS_LO; 367 CS_LO;
324 368
325 /* This is safe as long as lcd_remote_write_data() isn't called from within 369 /* This is safe as long as lcd_remote_write_data() isn't called from within
326 * an ISR. */ 370 * an ISR. */
327 if (cpu_frequency < 20000000) 371 if (cpu_frequency < 50000000)
328 { 372 {
329 while (p_bytes < p_end) 373 while (p_bytes < p_end)
330 _write_unrolled(*p_bytes++); 374 {
375 _write_fast(*p_bytes++);
376#ifdef HAVE_REMOTE_LCD_TICKING
377 _byte_delay(byte_delay - 87);
378#endif
379 }
331 } 380 }
332 else 381 else
333 { 382 {
383 while (p_bytes < p_end)
384 {
385 _write_byte(*p_bytes++);
334#ifdef HAVE_REMOTE_LCD_TICKING 386#ifdef HAVE_REMOTE_LCD_TICKING
335 if (emireduce) 387 _byte_delay(byte_delay - 148);
336 while (p_bytes < p_end)
337 {
338 _write_byte(*p_bytes++);
339 _byte_delay();
340 }
341 else
342#endif 388#endif
343 while (p_bytes < p_end) 389 }
344 _write_byte(*p_bytes++);
345 } 390 }
346 391
347 cs_countdown = CS_TIMEOUT; 392 cs_countdown = CS_TIMEOUT;
@@ -415,6 +460,7 @@ void lcd_remote_set_flip(bool yesno)
415static void remote_lcd_init(void) 460static void remote_lcd_init(void)
416{ 461{
417 CS_HI; 462 CS_HI;
463 CLK_LO;
418 lcd_remote_write_command(LCD_REMOTE_CNTL_SELECT_BIAS | 0x0); 464 lcd_remote_write_command(LCD_REMOTE_CNTL_SELECT_BIAS | 0x0);
419 465
420 lcd_remote_write_command(LCD_REMOTE_CNTL_POWER_CONTROL | 0x5); 466 lcd_remote_write_command(LCD_REMOTE_CNTL_POWER_CONTROL | 0x5);
@@ -574,8 +620,8 @@ void lcd_remote_update(void)
574 return; 620 return;
575 621
576#ifdef HAVE_REMOTE_LCD_TICKING 622#ifdef HAVE_REMOTE_LCD_TICKING
577 /* adjust byte delay for emi reduction */ 623 /* Adjust byte delay for emi reduction. */
578 byte_delay = (cpu_frequency >> 18) - 30; 624 byte_delay = emireduce ? cpu_frequency / 197600 + 28: 0;
579#endif 625#endif
580 626
581 /* Copy display bitmap to hardware */ 627 /* Copy display bitmap to hardware */
@@ -609,8 +655,8 @@ void lcd_remote_update_rect(int x, int y, int width, int height)
609 ymax = LCD_REMOTE_HEIGHT/8-1; 655 ymax = LCD_REMOTE_HEIGHT/8-1;
610 656
611#ifdef HAVE_REMOTE_LCD_TICKING 657#ifdef HAVE_REMOTE_LCD_TICKING
612 /* adjust byte delay for emi reduction */ 658 /* Adjust byte delay for emi reduction */
613 byte_delay = (cpu_frequency >> 18) - 30; 659 byte_delay = emireduce ? cpu_frequency / 197600 + 28: 0;
614#endif 660#endif
615 661
616 /* Copy specified rectange bitmap to hardware */ 662 /* Copy specified rectange bitmap to hardware */