diff options
-rwxr-xr-x | firmware/target/coldfire/iaudio/x5/lcd-remote-x5.c | 242 |
1 files changed, 218 insertions, 24 deletions
diff --git a/firmware/target/coldfire/iaudio/x5/lcd-remote-x5.c b/firmware/target/coldfire/iaudio/x5/lcd-remote-x5.c index 586104fc0a..d707e95ca6 100755 --- a/firmware/target/coldfire/iaudio/x5/lcd-remote-x5.c +++ b/firmware/target/coldfire/iaudio/x5/lcd-remote-x5.c | |||
@@ -60,44 +60,236 @@ static int cached_contrast = LCD_REMOTE_DEFAULT_CONTRAST; | |||
60 | 60 | ||
61 | bool remote_initialized = false; | 61 | bool remote_initialized = false; |
62 | 62 | ||
63 | static void remote_write(unsigned char byte, bool is_command) | 63 | /* Standard low-level byte writer. Requires CLK high on entry */ |
64 | static inline void _write_byte(unsigned data) | ||
64 | { | 65 | { |
65 | int i; | 66 | asm volatile ( |
66 | 67 | "move.l (%[gpo0]), %%d0 \n" /* Get current state of data line */ | |
67 | CS_LO; | 68 | "and.l %[dbit], %%d0 \n" |
68 | if (is_command) | 69 | "beq.s 1f \n" /* and set it as previous-state bit */ |
69 | RS_LO; | 70 | "bset #8, %[data] \n" |
70 | else | 71 | "1: \n" |
71 | RS_HI; | 72 | "move.l %[data], %%d0 \n" /* Compute the 'bit derivative', i.e. a value */ |
72 | 73 | "lsr.l #1, %%d0 \n" /* with 1's where the data changes from the */ | |
73 | for (i = 0x80; i; i >>= 1) | 74 | "eor.l %%d0, %[data] \n" /* previous state, and 0's where it doesn't */ |
74 | { | 75 | "swap %[data] \n" /* Shift data to upper byte */ |
75 | CLK_LO; | 76 | "lsl.l #8, %[data] \n" |
76 | if (i & byte) | 77 | |
77 | DATA_HI; | 78 | "move.l %[cbit], %%d1 \n" /* Prepare mask for flipping CLK */ |
78 | else | 79 | "or.l %[dbit], %%d1 \n" /* and DATA at once */ |
79 | DATA_LO; | ||
80 | CLK_HI; | ||
81 | } | ||
82 | 80 | ||
83 | CS_HI; | 81 | "lsl.l #1,%[data] \n" /* Shift out MSB */ |
82 | "bcc.s 1f \n" | ||
83 | "eor.l %%d1, (%[gpo0]) \n" /* 1: Flip both CLK and DATA */ | ||
84 | ".word 0x51fa \n" /* (trapf.w - shadow next insn) */ | ||
85 | "1: \n" | ||
86 | "eor.l %[cbit], (%[gpo0]) \n" /* else flip CLK only */ | ||
87 | "eor.l %[cbit], (%[gpo0]) \n" /* Flip CLK again */ | ||
88 | |||
89 | "lsl.l #1,%[data] \n" /* ..unrolled.. */ | ||
90 | "bcc.s 1f \n" | ||
91 | "eor.l %%d1, (%[gpo0]) \n" | ||
92 | ".word 0x51fa \n" | ||
93 | "1: \n" | ||
94 | "eor.l %[cbit], (%[gpo0]) \n" | ||
95 | "eor.l %[cbit], (%[gpo0]) \n" | ||
96 | |||
97 | "lsl.l #1,%[data] \n" | ||
98 | "bcc.s 1f \n" | ||
99 | "eor.l %%d1, (%[gpo0]) \n" | ||
100 | ".word 0x51fa \n" | ||
101 | "1: \n" | ||
102 | "eor.l %[cbit], (%[gpo0]) \n" | ||
103 | "eor.l %[cbit], (%[gpo0]) \n" | ||
104 | |||
105 | "lsl.l #1,%[data] \n" | ||
106 | "bcc.s 1f \n" | ||
107 | "eor.l %%d1, (%[gpo0]) \n" | ||
108 | ".word 0x51fa \n" | ||
109 | "1: \n" | ||
110 | "eor.l %[cbit], (%[gpo0]) \n" | ||
111 | "eor.l %[cbit], (%[gpo0]) \n" | ||
112 | |||
113 | "lsl.l #1,%[data] \n" | ||
114 | "bcc.s 1f \n" | ||
115 | "eor.l %%d1, (%[gpo0]) \n" | ||
116 | ".word 0x51fa \n" | ||
117 | "1: \n" | ||
118 | "eor.l %[cbit], (%[gpo0]) \n" | ||
119 | "eor.l %[cbit], (%[gpo0]) \n" | ||
120 | |||
121 | "lsl.l #1,%[data] \n" | ||
122 | "bcc.s 1f \n" | ||
123 | "eor.l %%d1, (%[gpo0]) \n" | ||
124 | ".word 0x51fa \n" | ||
125 | "1: \n" | ||
126 | "eor.l %[cbit], (%[gpo0]) \n" | ||
127 | "eor.l %[cbit], (%[gpo0]) \n" | ||
128 | |||
129 | "lsl.l #1,%[data] \n" | ||
130 | "bcc.s 1f \n" | ||
131 | "eor.l %%d1, (%[gpo0]) \n" | ||
132 | ".word 0x51fa \n" | ||
133 | "1: \n" | ||
134 | "eor.l %[cbit], (%[gpo0]) \n" | ||
135 | "eor.l %[cbit], (%[gpo0]) \n" | ||
136 | |||
137 | "lsl.l #1,%[data] \n" | ||
138 | "bcc.s 1f \n" | ||
139 | "eor.l %%d1, (%[gpo0]) \n" | ||
140 | ".word 0x51fa \n" | ||
141 | "1: \n" | ||
142 | "eor.l %[cbit], (%[gpo0]) \n" | ||
143 | "eor.l %[cbit], (%[gpo0]) \n" | ||
144 | : /* outputs */ | ||
145 | [data]"+d"(data) | ||
146 | : /* inputs */ | ||
147 | [gpo0]"a"(&GPIO_OUT), | ||
148 | [cbit]"d"(0x00004000), | ||
149 | [dbit]"d"(0x00002000) | ||
150 | : /* clobbers */ | ||
151 | "d0", "d1" | ||
152 | ); | ||
153 | } | ||
154 | |||
155 | /* Fast low-level byte writer. Don't use with high CPU clock. | ||
156 | * Requires CLK high on entry */ | ||
157 | static inline void _write_fast(unsigned data) | ||
158 | { | ||
159 | asm volatile ( | ||
160 | "move.w %%sr,%%d3 \n" /* Get current interrupt level */ | ||
161 | "move.w #0x2700,%%sr \n" /* Disable interrupts */ | ||
162 | |||
163 | "move.l (%[gpo0]), %%d0 \n" /* Get current state of data port */ | ||
164 | "move.l %%d0, %%d1 \n" | ||
165 | "and.l %[dbit], %%d1 \n" /* Check current state of data line */ | ||
166 | "beq.s 1f \n" /* and set it as previous-state bit */ | ||
167 | "bset #8, %[data] \n" | ||
168 | "1: \n" | ||
169 | "move.l %[data], %%d1 \n" /* Compute the 'bit derivative', i.e. a value */ | ||
170 | "lsr.l #1, %%d1 \n" /* with 1's where the data changes from the */ | ||
171 | "eor.l %%d1, %[data] \n" /* previous state, and 0's where it doesn't */ | ||
172 | "swap %[data] \n" /* Shift data to upper byte */ | ||
173 | "lsl.l #8, %[data] \n" | ||
174 | |||
175 | "lsl.l #1,%[data] \n" /* Shift out MSB */ | ||
176 | "bcc.s 1f \n" | ||
177 | "eor.l %[dbit], %%d0 \n" /* 1: Flip data bit */ | ||
178 | "1: \n" | ||
179 | "eor.l %[cbit], %%d0 \n" /* Flip clock bit */ | ||
180 | "move.l %%d0, (%[gpo0]) \n" /* Output new state */ | ||
181 | "eor.l %[cbit], %%d0 \n" /* Flip clock bit */ | ||
182 | "move.l %%d0, (%[gpo0]) \n" /* Output new state */ | ||
183 | |||
184 | "lsl.l #1,%[data] \n" /* ..unrolled.. */ | ||
185 | "bcc.s 1f \n" | ||
186 | "eor.l %[dbit], %%d0 \n" | ||
187 | "1: \n" | ||
188 | "eor.l %[cbit], %%d0 \n" | ||
189 | "move.l %%d0, (%[gpo0]) \n" | ||
190 | "eor.l %[cbit], %%d0 \n" | ||
191 | "move.l %%d0, (%[gpo0]) \n" | ||
192 | |||
193 | "lsl.l #1,%[data] \n" | ||
194 | "bcc.s 1f \n" | ||
195 | "eor.l %[dbit], %%d0 \n" | ||
196 | "1: \n" | ||
197 | "eor.l %[cbit], %%d0 \n" | ||
198 | "move.l %%d0, (%[gpo0]) \n" | ||
199 | "eor.l %[cbit], %%d0 \n" | ||
200 | "move.l %%d0, (%[gpo0]) \n" | ||
201 | |||
202 | "lsl.l #1,%[data] \n" | ||
203 | "bcc.s 1f \n" | ||
204 | "eor.l %[dbit], %%d0 \n" | ||
205 | "1: \n" | ||
206 | "eor.l %[cbit], %%d0 \n" | ||
207 | "move.l %%d0, (%[gpo0]) \n" | ||
208 | "eor.l %[cbit], %%d0 \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 | "1: \n" | ||
215 | "eor.l %[cbit], %%d0 \n" | ||
216 | "move.l %%d0, (%[gpo0]) \n" | ||
217 | "eor.l %[cbit], %%d0 \n" | ||
218 | "move.l %%d0, (%[gpo0]) \n" | ||
219 | |||
220 | "lsl.l #1,%[data] \n" | ||
221 | "bcc.s 1f \n" | ||
222 | "eor.l %[dbit], %%d0 \n" | ||
223 | "1: \n" | ||
224 | "eor.l %[cbit], %%d0 \n" | ||
225 | "move.l %%d0, (%[gpo0]) \n" | ||
226 | "eor.l %[cbit], %%d0 \n" | ||
227 | "move.l %%d0, (%[gpo0]) \n" | ||
228 | |||
229 | "lsl.l #1,%[data] \n" | ||
230 | "bcc.s 1f \n" | ||
231 | "eor.l %[dbit], %%d0 \n" | ||
232 | "1: \n" | ||
233 | "eor.l %[cbit], %%d0 \n" | ||
234 | "move.l %%d0, (%[gpo0]) \n" | ||
235 | "eor.l %[cbit], %%d0 \n" | ||
236 | "move.l %%d0, (%[gpo0]) \n" | ||
237 | |||
238 | "lsl.l #1,%[data] \n" | ||
239 | "bcc.s 1f \n" | ||
240 | "eor.l %[dbit], %%d0 \n" | ||
241 | "1: \n" | ||
242 | "eor.l %[cbit], %%d0 \n" | ||
243 | "move.l %%d0, (%[gpo0]) \n" | ||
244 | "eor.l %[cbit], %%d0 \n" | ||
245 | "move.l %%d0, (%[gpo0]) \n" | ||
246 | |||
247 | "move.w %%d3, %%sr \n" /* Restore interrupt level */ | ||
248 | : /* outputs */ | ||
249 | [data]"+d"(data) | ||
250 | : /* inputs */ | ||
251 | [gpo0]"a"(&GPIO_OUT), | ||
252 | [cbit]"d"(0x00004000), | ||
253 | [dbit]"d"(0x00002000) | ||
254 | : /* clobbers */ | ||
255 | "d0", "d1", "d2", "d3" | ||
256 | ); | ||
84 | } | 257 | } |
85 | 258 | ||
86 | void lcd_remote_write_command(int cmd) | 259 | void lcd_remote_write_command(int cmd) |
87 | { | 260 | { |
88 | remote_write(cmd, true); | 261 | RS_LO; |
262 | CS_LO; | ||
263 | _write_byte(cmd); | ||
264 | CS_HI; | ||
89 | } | 265 | } |
90 | 266 | ||
91 | void lcd_remote_write_command_ex(int cmd, int data) | 267 | void lcd_remote_write_command_ex(int cmd, int data) |
92 | { | 268 | { |
93 | remote_write(cmd, true); | 269 | RS_LO; |
94 | remote_write(data, true); | 270 | CS_LO; |
271 | _write_byte(cmd); | ||
272 | _write_byte(data); | ||
273 | CS_HI; | ||
95 | } | 274 | } |
96 | 275 | ||
97 | void lcd_remote_write_data(const unsigned char* p_bytes, int count) | 276 | void lcd_remote_write_data(const unsigned char* p_bytes, int count) |
98 | { | 277 | { |
99 | while(count--) | 278 | const unsigned char *p_end = p_bytes + count; |
100 | remote_write(*p_bytes++, false); | 279 | |
280 | RS_HI; | ||
281 | CS_LO; | ||
282 | if (cpu_frequency < 50000000) | ||
283 | { | ||
284 | while (p_bytes < p_end) | ||
285 | _write_fast(*p_bytes++); | ||
286 | } | ||
287 | else | ||
288 | { | ||
289 | while (p_bytes < p_end) | ||
290 | _write_byte(*p_bytes++); | ||
291 | } | ||
292 | CS_HI; | ||
101 | } | 293 | } |
102 | 294 | ||
103 | int lcd_remote_default_contrast(void) | 295 | int lcd_remote_default_contrast(void) |
@@ -144,6 +336,8 @@ void lcd_remote_init_device(void) | |||
144 | 336 | ||
145 | void lcd_remote_on(void) | 337 | void lcd_remote_on(void) |
146 | { | 338 | { |
339 | CS_HI; | ||
340 | CLK_HI; | ||
147 | sleep(10); | 341 | sleep(10); |
148 | 342 | ||
149 | lcd_remote_write_command(LCD_SET_DUTY_RATIO); | 343 | lcd_remote_write_command(LCD_SET_DUTY_RATIO); |