summaryrefslogtreecommitdiff
path: root/firmware/drivers/lcd.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/lcd.c')
-rw-r--r--firmware/drivers/lcd.c362
1 files changed, 0 insertions, 362 deletions
diff --git a/firmware/drivers/lcd.c b/firmware/drivers/lcd.c
deleted file mode 100644
index 68627f7c51..0000000000
--- a/firmware/drivers/lcd.c
+++ /dev/null
@@ -1,362 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Alan Korr, speedup by Jörg Hohensohn
11 * Further speedup and reorganization by Jens Arnold
12 *
13 * All files in this archive are subject to the GNU General Public License.
14 * See the file COPYING in the source tree root for full license agreement.
15 *
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
18 *
19 ****************************************************************************/
20
21#include <stdbool.h>
22#include "system.h"
23
24#define LCDR (PBDR_ADDR+1)
25
26#ifdef HAVE_LCD_CHARCELLS
27#define LCD_DS 1 /* PB0 = 1 --- 0001 --- LCD-DS */
28#define LCD_CS 2 /* PB1 = 1 --- 0010 --- /LCD-CS */
29#define LCD_SD 4 /* PB2 = 1 --- 0100 --- LCD-SD */
30#define LCD_SC 8 /* PB3 = 1 --- 1000 --- LCD-SC */
31#else
32#define LCD_SD 1 /* PB0 = 1 --- 0001 */
33#define LCD_SC 2 /* PB1 = 1 --- 0010 */
34#define LCD_RS 4 /* PB2 = 1 --- 0100 */
35#define LCD_CS 8 /* PB3 = 1 --- 1000 */
36#define LCD_DS LCD_RS
37#endif
38
39/*
40 * About /CS,DS,SC,SD
41 * ------------------
42 *
43 * LCD on JBP and JBR uses a SPI protocol to receive orders (SDA and SCK lines)
44 *
45 * - /CS -> Chip Selection line :
46 * 0 : LCD chipset is activated.
47 * - DS -> Data Selection line, latched at the rising edge
48 * of the 8th serial clock (*) :
49 * 0 : instruction register,
50 * 1 : data register;
51 * - SC -> Serial Clock line (SDA).
52 * - SD -> Serial Data line (SCK), latched at the rising edge
53 * of each serial clock (*).
54 *
55 * _ _
56 * /CS \ /
57 * \______________________________________________________/
58 * _____ ____ ____ ____ ____ ____ ____ ____ ____ _____
59 * SD \/ D7 \/ D6 \/ D5 \/ D4 \/ D3 \/ D2 \/ D1 \/ D0 \/
60 * _____/\____/\____/\____/\____/\____/\____/\____/\____/\_____
61 *
62 * _____ _ _ _ _ _ _ _ ________
63 * SC \ * \ * \ * \ * \ * \ * \ * \ *
64 * \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
65 * _ _________________________________________________________
66 * DS \/
67 * _/\_________________________________________________________
68 *
69 */
70
71/*
72 * The only way to do logical operations in an atomic way
73 * on SH1 is using :
74 *
75 * or.b/and.b/tst.b/xor.b #imm,@(r0,gbr)
76 *
77 * but GCC doesn't generate them at all so some assembly
78 * codes are needed here.
79 *
80 * The Global Base Register gbr is expected to be zero
81 * and r0 is the address of one register in the on-chip
82 * peripheral module.
83 *
84 */
85
86void lcd_write_command(int byte) __attribute__ ((section (".icode")));
87void lcd_write_command(int byte)
88{
89 asm (
90 "and.b %0, @(r0,gbr)"
91 : /* outputs */
92 : /* inputs */
93 /* %0 */ "I"(~(LCD_CS|LCD_DS|LCD_SD|LCD_SC)),
94 /* %1 = r0 */ "z"(LCDR)
95 );
96
97 asm (
98 "0: \n"
99 "and.b %2,@(r0,gbr) \n"
100 "shll %0 \n"
101 "bf 1f \n"
102 "or.b %3,@(r0,gbr) \n"
103 "1: \n"
104 "or.b %4,@(r0,gbr) \n"
105 "add #-1,%1 \n"
106 "cmp/pl %1 \n"
107 "bt 0b \n"
108 : /* outputs */
109 : /* inputs */
110 /* %0 */ "r"(((unsigned)byte)<<24),
111 /* %1 */ "r"(8),
112 /* %2 */ "I"(~(LCD_SC|LCD_SD|LCD_DS)),
113 /* %3 */ "I"(LCD_SD),
114 /* %4 */ "I"(LCD_SC),
115 /* %5 = r0 */ "z"(LCDR)
116 );
117
118 asm (
119 "or.b %0, @(r0,gbr)"
120 : /* outputs */
121 : /* inputs */
122 /* %0 */ "I"(LCD_CS|LCD_DS|LCD_SD|LCD_SC),
123 /* %1 = r0 */ "z"(LCDR)
124 );
125}
126
127
128/* A high performance function to write data to the display,
129 one or multiple bytes. */
130void lcd_write_data(unsigned char* p_bytes, int count) __attribute__ ((section (".icode")));
131
132#ifdef HAVE_LCD_CHARCELLS
133/* This version works for both Player and Recorder models */
134void lcd_write_data(unsigned char* p_bytes, int count)
135{
136 do
137 {
138 unsigned int byte;
139 unsigned int sda1; /* precalculated SC=low,SD=1 */
140
141 byte = *p_bytes++ << 24; /* fetch to MSB position */
142
143 /* This code will fail if an interrupt changes the contents of PBDRL.
144 If so, we must disable the interrupt here. */
145
146 /* precalculate the values for later bit toggling, init data write */
147 asm (
148 "mov.b @%1,r0 \n" /* r0 = PBDRL */
149 "or %3,r0 \n" /* r0 |= LCD_DS | LCD_SD DS and SD high */
150 "and %2,r0 \n" /* r0 &= ~(LCD_CS | LCD_SC) CS and SC low */
151 "mov.b r0,@%1 \n" /* PBDRL = r0 */
152 "mov r0,%0 \n" /* sda1 = r0 */
153 : /* outputs */
154 /* %0 */ "=r"(sda1)
155 : /* inputs */
156 /* %1 */ "r"(LCDR),
157 /* %2 */ "I"(~(LCD_CS | LCD_SC)),
158 /* %3 */ "I"(LCD_DS | LCD_SD)
159 : /* trashed */
160 "r0"
161 );
162
163 /* unrolled loop to serialize the byte */
164 asm (
165 "shll %0 \n" /* shift the msb into carry */
166 ".align 2 \n"
167 "mov %1,r0 \n" /* copy precalculated port value */
168 "bt 1f \n" /* data bit = 1? */
169 "and %5,r0 \n" /* no: r0 &= ~LCD_SD */
170 "1: \n"
171 "shll %0 \n" /* next shift here for alignment */
172 "mov.b r0,@%3 \n" /* set data to port */
173 "or %2,r0 \n" /* rise SC (independent of SD level) */
174 "mov.b r0,@%3 \n" /* set to port */
175
176 "mov %1,r0 \n"
177 "bt 1f \n"
178 "and %5,r0 \n"
179 "1: \n"
180 "mov.b r0,@%3 \n"
181 "or %2,r0 \n"
182 "mov.b r0,@%3 \n"
183
184 "shll %0 \n"
185 "mov %1,r0 \n"
186 "bt 1f \n"
187 "and %5,r0 \n"
188 "1: \n"
189 "shll %0 \n"
190 "mov.b r0,@%3 \n"
191 "or %2,r0 \n"
192 "mov.b r0,@%3 \n"
193
194 "mov %1,r0 \n"
195 "bt 1f \n"
196 "and %5,r0 \n"
197 "1: \n"
198 "mov.b r0,@%3 \n"
199 "or %2,r0 \n"
200 "mov.b r0,@%3 \n"
201
202 "shll %0 \n"
203 "mov %1,r0 \n"
204 "bt 1f \n"
205 "and %5,r0 \n"
206 "1: \n"
207 "shll %0 \n"
208 "mov.b r0,@%3 \n"
209 "or %2,r0 \n"
210 "mov.b r0,@%3 \n"
211
212 "mov %1,r0 \n"
213 "bt 1f \n"
214 "and %5,r0 \n"
215 "1: \n"
216 "mov.b r0,@%3 \n"
217 "or %2,r0 \n"
218 "mov.b r0,@%3 \n"
219
220 "shll %0 \n"
221 "mov %1,r0 \n"
222 "bt 1f \n"
223 "and %5,r0 \n"
224 "1: \n"
225 "shll %0 \n"
226 "mov.b r0,@%3 \n"
227 "or %2,r0 \n"
228 "mov.b r0,@%3 \n"
229
230 "mov %1,r0 \n"
231 "bt 1f \n"
232 "and %5,r0 \n"
233 "1: \n"
234 "mov.b r0,@%3 \n"
235 "or %2,r0 \n"
236 "mov.b r0,@%3 \n"
237
238 "or %4,r0 \n" /* restore port */
239 "mov.b r0,@%3 \n"
240 : /* outputs */
241 : /* inputs */
242 /* %0 */ "r"(byte),
243 /* %1 */ "r"(sda1),
244 /* %2 */ "I"(LCD_SC),
245 /* %3 */ "r"(LCDR),
246 /* %4 */ "I"(LCD_CS | LCD_DS | LCD_SD | LCD_SC),
247 /* %5 */ "I"(~(LCD_SD))
248 : /* trashed */
249 "r0"
250 );
251
252 /* This is the place to reenable the interrupts, if we have disabled
253 them. See above. */
254
255 } while (--count); /* tail loop is faster */
256}
257
258#else /* #ifdef HAVE_LCD_CHARCELLS */
259/* A further optimized version, exploits that SD is on bit 0 for recorders */
260void lcd_write_data(unsigned char* p_bytes, int count)
261{
262 do
263 {
264 unsigned byte;
265 unsigned sda1; /* precalculated SC=low,SD=1 */
266
267 /* take inverse data, so I can use the NEGC instruction below, it is
268 the only carry add/sub which does not destroy a source register */
269 byte = ~(*p_bytes++ << 24); /* fetch to MSB position */
270
271 /* This code will fail if an interrupt changes the contents of PBDRL.
272 If so, we must disable the interrupt here. */
273
274 /* precalculate the values for later bit toggling, init data write */
275 asm (
276 "mov.b @%1,r0 \n" /* r0 = PBDRL */
277 "or %3,r0 \n" /* r0 |= LCD_DS | LCD_SD DS and SD high, */
278 "and %2,r0 \n" /* r0 &= ~(LCD_CS | LCD_SC) CS and SC low */
279 "mov.b r0,@%1 \n" /* PBDRL = r0 */
280 "neg r0,%0 \n" /* sda1 = 0-r0 */
281 : /* outputs: */
282 /* %0 */ "=r"(sda1)
283 : /* inputs: */
284 /* %1 */ "r"(LCDR),
285 /* %2 */ "I"(~(LCD_CS | LCD_SC)),
286 /* %3 */ "I"(LCD_DS | LCD_SD)
287 : /* trashed */
288 "r0"
289 );
290
291 /* unrolled loop to serialize the byte */
292 asm (
293 "shll %0 \n" /* shift the MSB into carry */
294 ".align 2 \n"
295 "negc %1, r0 \n" /* carry to SD, SC low */
296 "shll %0 \n" /* next shift here for alignment */
297 "mov.b r0,@%3 \n" /* set data to port */
298 "or %2, r0 \n" /* rise SC (independent of SD level) */
299 "mov.b r0,@%3 \n" /* set to port */
300
301 "negc %1, r0 \n"
302 "mov.b r0,@%3 \n"
303 "or %2, r0 \n"
304 "mov.b r0,@%3 \n"
305
306 "shll %0 \n"
307 "negc %1, r0 \n"
308 "shll %0 \n"
309 "mov.b r0,@%3 \n"
310 "or %2, r0 \n"
311 "mov.b r0,@%3 \n"
312
313 "negc %1, r0 \n"
314 "mov.b r0,@%3 \n"
315 "or %2, r0 \n"
316 "mov.b r0,@%3 \n"
317
318 "shll %0 \n"
319 "negc %1, r0 \n"
320 "shll %0 \n"
321 "mov.b r0,@%3 \n"
322 "or %2, r0 \n"
323 "mov.b r0,@%3 \n"
324
325 "negc %1, r0 \n"
326 "mov.b r0,@%3 \n"
327 "or %2, r0 \n"
328 "mov.b r0,@%3 \n"
329
330 "shll %0 \n"
331 "negc %1, r0 \n"
332 "shll %0 \n"
333 "mov.b r0,@%3 \n"
334 "or %2, r0 \n"
335 "mov.b r0,@%3 \n"
336
337 "negc %1, r0 \n"
338 "mov.b r0,@%3 \n"
339 "or %2, r0 \n"
340 "mov.b r0,@%3 \n"
341
342 "or %4, r0 \n" /* restore port */
343 "mov.b r0,@%3 \n"
344 : /* outputs: */
345 : /* inputs: */
346 /* %0 */ "r"(byte),
347 /* %1 */ "r"(sda1),
348 /* %2 */ "I"(LCD_SC),
349 /* %3 */ "r"(LCDR),
350 /* %4 */ "I"(LCD_CS|LCD_DS|LCD_SD|LCD_SC)
351 : /* trashed: */
352 "r0"
353 );
354
355 /* This is the place to reenable the interrupts, if we have disabled
356 them. See above. */
357
358 } while (--count); /* tail loop is faster */
359}
360#endif /* #ifdef HAVE_LCD_CHARCELLS */
361
362