diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/drivers/lcd-h100-remote.c | 350 |
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. */ |
87 | static bool emireduce = false; | 87 | static bool emireduce = false; |
88 | static int byte_delay = 172; | 88 | static 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 |
127 | static inline void _byte_delay(void) | 127 | static 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 */ |
144 | static inline void _write_byte(unsigned data) | 146 | static 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. |
177 | static inline void _write_unrolled(unsigned data) | 228 | * Requires CLK low on entry */ |
229 | static 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) | |||
415 | static void remote_lcd_init(void) | 460 | static 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 */ |