summaryrefslogtreecommitdiff
path: root/firmware/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers')
-rw-r--r--firmware/drivers/i2c-coldfire.c241
-rw-r--r--firmware/drivers/lcd-h100.c1298
-rw-r--r--firmware/drivers/lcd-h300.c425
-rwxr-xr-xfirmware/drivers/lcd.S238
-rw-r--r--firmware/drivers/power.c68
5 files changed, 90 insertions, 2180 deletions
diff --git a/firmware/drivers/i2c-coldfire.c b/firmware/drivers/i2c-coldfire.c
deleted file mode 100644
index a628ce5f0e..0000000000
--- a/firmware/drivers/i2c-coldfire.c
+++ /dev/null
@@ -1,241 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * $Id$
10 *
11 * Copyright (C) 2005 by Andy Young
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 "cpu.h"
22#include "kernel.h"
23#include "logf.h"
24#include "system.h"
25#include "i2c-coldfire.h"
26
27
28/* --- Local functions - declarations --- */
29
30static int i2c_start(volatile unsigned char *iface);
31static int i2c_wait_for_slave(volatile unsigned char *iface);
32static int i2c_outb(volatile unsigned char *iface, unsigned char byte);
33inline void i2c_stop(volatile unsigned char *iface);
34
35
36/* --- Public functions - implementation --- */
37
38void i2c_init(void)
39{
40#ifdef IRIVER_H100_SERIES
41 /* The FM chip has no pullup for SCL, so we have to bit-bang the
42 I2C for that one. */
43 or_l(0x00800000, &GPIO1_OUT);
44 or_l(0x00000008, &GPIO_OUT);
45 or_l(0x00800000, &GPIO1_ENABLE);
46 or_l(0x00000008, &GPIO_ENABLE);
47 or_l(0x00800000, &GPIO1_FUNCTION);
48 or_l(0x00000008, &GPIO_FUNCTION);
49#elif defined(IRIVER_H300_SERIES)
50 /* The FM chip has no pullup for SCL, so we have to bit-bang the
51 I2C for that one. */
52 or_l(0x03000000, &GPIO1_OUT);
53 or_l(0x03000000, &GPIO1_ENABLE);
54 or_l(0x03000000, &GPIO1_FUNCTION);
55#endif
56
57 /* I2C Clock divisor = 160 => 124.1556 MHz / 2 / 160 = 388.08 kHz */
58 MFDR = 0x0d;
59 MFDR2 = 0x0d;
60
61#ifdef IAUDIO_X5
62 MBCR = IEN; /* Enable interface */
63 MBCR2 = IEN;
64#endif
65
66#if defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES)
67 /* Audio Codec */
68 MBDR = 0; /* iRiver firmware does this */
69 MBCR = IEN; /* Enable interface */
70#endif
71}
72
73void i2c_close(void)
74{
75 MBCR = 0;
76 MBCR2 = 0;
77}
78
79/*
80 * Writes bytes to a I2C device.
81 *
82 * Returns number of bytes successfully sent or a negative value on error.
83 */
84int i2c_write(volatile unsigned char *iface, unsigned char addr,
85 const unsigned char *buf, int count)
86{
87 int i, rc;
88
89 if ( ! count)
90 return 0;
91
92 rc = i2c_start(iface);
93 if (rc < 0)
94 return rc;
95
96 rc = i2c_outb(iface, addr & 0xfe);
97 if (rc < 0)
98 return rc;
99
100 for (i = 0; i < count; i++)
101 {
102 rc = i2c_outb(iface, *buf++);
103 if (rc < 0)
104 return rc;
105 }
106 i2c_stop(iface);
107
108 return count;
109}
110
111/*
112 * Reads bytes from a I2C device.
113 *
114 * Returns number of bytes successfully received or a negative value on error.
115 */
116int i2c_read(volatile unsigned char *iface, unsigned char addr,
117 unsigned char *buf, int count)
118{
119 int i, rc;
120
121 if ( ! count)
122 return 0;
123
124 rc = i2c_start(iface);
125 if (rc < 0)
126 return rc;
127
128 rc = i2c_outb(iface, addr | 1);
129 if (rc < 0)
130 return rc;
131
132 /* Switch to Rx mode */
133 iface[O_MBCR] &= ~MTX;
134 iface[O_MBCR] &= ~TXAK;
135
136 /* Dummy read */
137 rc = (int) iface[O_MBDR];
138
139 for (i = 0; i < count; i++)
140 {
141 rc = i2c_wait_for_slave(iface);
142 if (rc < 0)
143 return rc;
144
145 if (i == count-2)
146 /* Don't ACK the next-to-last byte */
147 iface[O_MBCR] |= TXAK;
148
149 if (i == count-1)
150 /* Generate STOP before reading last byte */
151 i2c_stop(iface);
152
153 *buf++ = iface[O_MBDR];
154 }
155 return count;
156}
157
158/* --- Local functions - implementation --- */
159
160/* Begin I2C session on the given interface.
161 *
162 * Returns 0 on success, negative value on error.
163 */
164int i2c_start(volatile unsigned char *iface)
165{
166 /* Wait for bus to become free */
167 int j = MAX_LOOP;
168 while (--j && (iface[O_MBSR] & IBB))
169 ;
170 if (!j)
171 {
172 logf("i2c: bus is busy (iface=%08x)", iface);
173 return -1;
174 }
175
176 /* Generate START and prepare for write */
177 iface[O_MBCR] |= (MSTA | TXAK | MTX);
178
179 return 0;
180}
181
182/* Wait for slave to act on given I2C interface.
183 *
184 * Returns 0 on success, negative value on error.
185 */
186int i2c_wait_for_slave(volatile unsigned char *iface)
187{
188 int j = MAX_LOOP;
189 while (--j && ! (iface[O_MBSR] & IFF))
190 ;
191 if (!j)
192 {
193 logf("i2c: IFF not set (iface=%08x)", iface);
194 i2c_stop(iface);
195 return -2;
196 }
197
198 /* Clear interrupt flag */
199 iface[O_MBSR] &= ~IFF;
200
201 return 0;
202}
203
204/* Write the given byte to the given I2C interface.
205 *
206 * Returns 0 on success, negative value on error.
207 */
208int i2c_outb(volatile unsigned char *iface, unsigned char byte)
209{
210 int rc;
211
212 iface[O_MBDR] = byte;
213
214 rc = i2c_wait_for_slave(iface);
215 if (rc < 0)
216 return rc;
217
218 /* Check that transfer is complete */
219 if ( !(iface[O_MBSR] & ICF))
220 {
221 logf("i2c: transfer error (iface=%08x)", iface);
222 i2c_stop(iface);
223 return -3;
224 }
225
226 /* Check that the byte has been ACKed */
227 if (iface[O_MBSR] & RXAK)
228 {
229 logf("i2c: no ACK (iface=%08x)", iface);
230 i2c_stop(iface);
231 return -4;
232 }
233
234 return 0;
235}
236
237/* End I2C session on the given interface. */
238inline void i2c_stop(volatile unsigned char *iface)
239{
240 iface[O_MBCR] &= ~MSTA;
241}
diff --git a/firmware/drivers/lcd-h100.c b/firmware/drivers/lcd-h100.c
deleted file mode 100644
index 9ed63661a0..0000000000
--- a/firmware/drivers/lcd-h100.c
+++ /dev/null
@@ -1,1298 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2004 by Linus Nielsen Feltzing
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include "config.h"
20
21#include "cpu.h"
22#include "lcd.h"
23#include "kernel.h"
24#include "thread.h"
25#include <string.h>
26#include <stdlib.h>
27#include "file.h"
28#include "debug.h"
29#include "system.h"
30#include "font.h"
31#include "rbunicode.h"
32#include "bidi.h"
33
34/*** definitions ***/
35
36/* LCD command codes */
37#define LCD_CNTL_POWER_CONTROL 0x25
38#define LCD_CNTL_VOLTAGE_SELECT 0x2b
39#define LCD_CNTL_LINE_INVERT_DRIVE 0x36
40#define LCD_CNTL_GRAY_SCALE_PATTERN 0x39
41#define LCD_CNTL_TEMP_GRADIENT_SELECT 0x4e
42#define LCD_CNTL_OSC_FREQUENCY 0x5f
43#define LCD_CNTL_ON_OFF 0xae
44#define LCD_CNTL_OSC_ON_OFF 0xaa
45#define LCD_CNTL_OFF_MODE 0xbe
46#define LCD_CNTL_REVERSE 0xa6
47#define LCD_CNTL_ALL_LIGHTING 0xa4
48#define LCD_CNTL_COMMON_OUTPUT_STATUS 0xc4
49#define LCD_CNTL_COLUMN_ADDRESS_DIR 0xa0
50#define LCD_CNTL_NLINE_ON_OFF 0xe4
51#define LCD_CNTL_DISPLAY_MODE 0x66
52#define LCD_CNTL_DUTY_SET 0x6d
53#define LCD_CNTL_ELECTRONIC_VOLUME 0x81
54#define LCD_CNTL_DATA_INPUT_DIR 0x84
55#define LCD_CNTL_DISPLAY_START_LINE 0x8a
56#define LCD_CNTL_AREA_SCROLL 0x10
57
58#define LCD_CNTL_PAGE 0xb1
59#define LCD_CNTL_COLUMN 0x13
60#define LCD_CNTL_DATA_WRITE 0x1d
61
62#define SCROLLABLE_LINES 26
63
64/*** globals ***/
65
66fb_data lcd_framebuffer[LCD_HEIGHT/4][LCD_WIDTH] IBSS_ATTR;
67
68static const unsigned char dibits[16] ICONST_ATTR = {
69 0x00, 0x03, 0x0C, 0x0F, 0x30, 0x33, 0x3C, 0x3F,
70 0xC0, 0xC3, 0xCC, 0xCF, 0xF0, 0xF3, 0xFC, 0xFF
71};
72
73static const unsigned char pixmask[4] ICONST_ATTR = {
74 0x03, 0x0C, 0x30, 0xC0
75};
76
77static unsigned fg_pattern IDATA_ATTR = 0xFF; /* initially black */
78static unsigned bg_pattern IDATA_ATTR = 0x00; /* initially white */
79static int drawmode = DRMODE_SOLID;
80static int xmargin = 0;
81static int ymargin = 0;
82static int curfont = FONT_SYSFIXED;
83
84/* scrolling */
85static volatile int scrolling_lines=0; /* Bitpattern of which lines are scrolling */
86static void scroll_thread(void);
87static long scroll_stack[DEFAULT_STACK_SIZE/sizeof(long)];
88static const char scroll_name[] = "scroll";
89static int scroll_ticks = 12; /* # of ticks between updates*/
90static int scroll_delay = HZ/2; /* ticks delay before start */
91static int scroll_step = 6; /* pixels per scroll step */
92static int bidir_limit = 50; /* percent */
93static struct scrollinfo scroll[SCROLLABLE_LINES];
94
95static const char scroll_tick_table[16] = {
96 /* Hz values:
97 1, 1.25, 1.55, 2, 2.5, 3.12, 4, 5, 6.25, 8.33, 10, 12.5, 16.7, 20, 25, 33 */
98 100, 80, 64, 50, 40, 32, 25, 20, 16, 12, 10, 8, 6, 5, 4, 3
99};
100
101/*** driver code is in lcd.S ***/
102
103/*** hardware configuration ***/
104
105#ifndef SIMULATOR
106
107int lcd_default_contrast(void)
108{
109 return 28;
110}
111
112void lcd_set_contrast(int val)
113{
114 lcd_write_command_ex(LCD_CNTL_ELECTRONIC_VOLUME, val, -1);
115}
116
117void lcd_set_invert_display(bool yesno)
118{
119 lcd_write_command(LCD_CNTL_REVERSE | (yesno?1:0));
120}
121
122/* turn the display upside down (call lcd_update() afterwards) */
123void lcd_set_flip(bool yesno)
124{
125 if (yesno)
126 {
127 lcd_write_command(LCD_CNTL_COLUMN_ADDRESS_DIR | 1);
128 lcd_write_command(LCD_CNTL_COMMON_OUTPUT_STATUS | 0);
129 lcd_write_command_ex(LCD_CNTL_DUTY_SET, 0x20, 0);
130 }
131 else
132 {
133 lcd_write_command(LCD_CNTL_COLUMN_ADDRESS_DIR | 0);
134 lcd_write_command(LCD_CNTL_COMMON_OUTPUT_STATUS | 1);
135 lcd_write_command_ex(LCD_CNTL_DUTY_SET, 0x20, 1);
136 }
137}
138
139#endif /* !SIMULATOR */
140
141/* LCD init */
142#ifdef SIMULATOR
143
144void lcd_init(void)
145{
146 create_thread(scroll_thread, scroll_stack,
147 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE));
148}
149#else
150
151void lcd_init(void)
152{
153 /* GPO35 is the LCD A0 pin
154 GPO46 is LCD RESET */
155 or_l(0x00004008, &GPIO1_OUT);
156 or_l(0x00004008, &GPIO1_ENABLE);
157 or_l(0x00004008, &GPIO1_FUNCTION);
158
159 /* Reset LCD */
160 sleep(1);
161 and_l(~0x00004000, &GPIO1_OUT);
162 sleep(1);
163 or_l(0x00004000, &GPIO1_OUT);
164 sleep(1);
165
166 lcd_write_command(LCD_CNTL_COLUMN_ADDRESS_DIR | 0); /* Normal */
167 lcd_write_command(LCD_CNTL_COMMON_OUTPUT_STATUS | 1); /* Reverse dir */
168 lcd_write_command(LCD_CNTL_REVERSE | 0); /* Reverse OFF */
169 lcd_write_command(LCD_CNTL_ALL_LIGHTING | 0); /* Normal */
170 lcd_write_command_ex(LCD_CNTL_DUTY_SET, 0x20, 1);
171 lcd_write_command(LCD_CNTL_OFF_MODE | 1); /* OFF -> VCC on drivers */
172 lcd_write_command_ex(LCD_CNTL_VOLTAGE_SELECT, 3, -1);
173 lcd_write_command_ex(LCD_CNTL_ELECTRONIC_VOLUME, 0x1c, -1);
174 lcd_write_command_ex(LCD_CNTL_TEMP_GRADIENT_SELECT, 0, -1);
175
176 lcd_write_command_ex(LCD_CNTL_LINE_INVERT_DRIVE, 0x10, -1);
177 lcd_write_command(LCD_CNTL_NLINE_ON_OFF | 1); /* N-line ON */
178
179 lcd_write_command_ex(LCD_CNTL_OSC_FREQUENCY, 3, -1);
180 lcd_write_command(LCD_CNTL_OSC_ON_OFF | 1); /* Oscillator ON */
181
182 lcd_write_command_ex(LCD_CNTL_POWER_CONTROL, 0x16, -1);
183 sleep(HZ/10); /* 100 ms pause */
184 lcd_write_command_ex(LCD_CNTL_POWER_CONTROL, 0x17, -1);
185
186 lcd_write_command_ex(LCD_CNTL_DISPLAY_START_LINE, 0, -1);
187 lcd_write_command_ex(LCD_CNTL_GRAY_SCALE_PATTERN, 0x32, -1);
188 lcd_write_command_ex(LCD_CNTL_DISPLAY_MODE, 0, -1); /* Greyscale mode */
189 lcd_write_command(LCD_CNTL_DATA_INPUT_DIR | 0); /* Column mode */
190
191 lcd_clear_display();
192 lcd_update();
193 lcd_write_command(LCD_CNTL_ON_OFF | 1); /* LCD ON */
194
195 create_thread(scroll_thread, scroll_stack,
196 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE));
197}
198
199/*** update functions ***/
200
201/* Performance function that works with an external buffer
202 note that by and bheight are in 8-pixel units! */
203void lcd_blit(const unsigned char* data, int x, int by, int width,
204 int bheight, int stride)
205{
206 const unsigned char *src, *src_end;
207 unsigned char *dst_u, *dst_l;
208 static unsigned char upper[LCD_WIDTH] IBSS_ATTR;
209 static unsigned char lower[LCD_WIDTH] IBSS_ATTR;
210 unsigned int byte;
211
212 by *= 2;
213
214 while (bheight--)
215 {
216 src = data;
217 src_end = data + width;
218 dst_u = upper;
219 dst_l = lower;
220 do
221 {
222 byte = *src++;
223 *dst_u++ = dibits[byte & 0x0F];
224 byte >>= 4;
225 *dst_l++ = dibits[byte & 0x0F];
226 }
227 while (src < src_end);
228
229 lcd_write_command_ex(LCD_CNTL_PAGE, by++, -1);
230 lcd_write_command_ex(LCD_CNTL_COLUMN, x, -1);
231 lcd_write_command(LCD_CNTL_DATA_WRITE);
232 lcd_write_data(upper, width);
233
234 lcd_write_command_ex(LCD_CNTL_PAGE, by++, -1);
235 lcd_write_command_ex(LCD_CNTL_COLUMN, x, -1);
236 lcd_write_command(LCD_CNTL_DATA_WRITE);
237 lcd_write_data(lower, width);
238
239 data += stride;
240 }
241}
242
243
244/* Update the display.
245 This must be called after all other LCD functions that change the display. */
246void lcd_update(void) ICODE_ATTR;
247void lcd_update(void)
248{
249 int y;
250
251 /* Copy display bitmap to hardware */
252 for (y = 0; y < LCD_HEIGHT/4; y++)
253 {
254 lcd_write_command_ex(LCD_CNTL_PAGE, y, -1);
255 lcd_write_command_ex(LCD_CNTL_COLUMN, 0, -1);
256
257 lcd_write_command(LCD_CNTL_DATA_WRITE);
258 lcd_write_data (lcd_framebuffer[y], LCD_WIDTH);
259 }
260}
261
262/* Update a fraction of the display. */
263void lcd_update_rect(int, int, int, int) ICODE_ATTR;
264void lcd_update_rect(int x, int y, int width, int height)
265{
266 int ymax;
267
268 /* The Y coordinates have to work on even 8 pixel rows */
269 ymax = (y + height-1) >> 2;
270 y >>= 2;
271
272 if(x + width > LCD_WIDTH)
273 width = LCD_WIDTH - x;
274 if (width <= 0)
275 return; /* nothing left to do, 0 is harmful to lcd_write_data() */
276 if(ymax >= LCD_HEIGHT/4)
277 ymax = LCD_HEIGHT/4-1;
278
279 /* Copy specified rectange bitmap to hardware */
280 for (; y <= ymax; y++)
281 {
282 lcd_write_command_ex(LCD_CNTL_PAGE, y, -1);
283 lcd_write_command_ex(LCD_CNTL_COLUMN, x, -1);
284
285 lcd_write_command(LCD_CNTL_DATA_WRITE);
286 lcd_write_data (&lcd_framebuffer[y][x], width);
287 }
288}
289#endif /* !SIMULATOR */
290
291/*** parameter handling ***/
292
293void lcd_set_drawmode(int mode)
294{
295 drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
296}
297
298int lcd_get_drawmode(void)
299{
300 return drawmode;
301}
302
303void lcd_set_foreground(unsigned brightness)
304{
305 fg_pattern = 0x55 * (~brightness & 3);
306}
307
308unsigned lcd_get_foreground(void)
309{
310 return ~fg_pattern & 3;
311}
312
313void lcd_set_background(unsigned brightness)
314{
315 bg_pattern = 0x55 * (~brightness & 3);
316}
317
318unsigned lcd_get_background(void)
319{
320 return ~bg_pattern & 3;
321}
322
323void lcd_set_drawinfo(int mode, unsigned fg_brightness, unsigned bg_brightness)
324{
325 lcd_set_drawmode(mode);
326 lcd_set_foreground(fg_brightness);
327 lcd_set_background(bg_brightness);
328}
329
330void lcd_setmargins(int x, int y)
331{
332 xmargin = x;
333 ymargin = y;
334}
335
336int lcd_getxmargin(void)
337{
338 return xmargin;
339}
340
341int lcd_getymargin(void)
342{
343 return ymargin;
344}
345
346void lcd_setfont(int newfont)
347{
348 curfont = newfont;
349}
350
351int lcd_getstringsize(const unsigned char *str, int *w, int *h)
352{
353 return font_getstringsize(str, w, h, curfont);
354}
355
356/*** low-level drawing functions ***/
357
358static void setpixel(int x, int y)
359{
360 unsigned mask = pixmask[y & 3];
361 fb_data *address = &lcd_framebuffer[y>>2][x];
362 unsigned data = *address;
363
364 *address = data ^ ((data ^ fg_pattern) & mask);
365}
366
367static void clearpixel(int x, int y)
368{
369 unsigned mask = pixmask[y & 3];
370 fb_data *address = &lcd_framebuffer[y>>2][x];
371 unsigned data = *address;
372
373 *address = data ^ ((data ^ bg_pattern) & mask);
374}
375
376static void flippixel(int x, int y)
377{
378 unsigned mask = pixmask[y & 3];
379 fb_data *address = &lcd_framebuffer[y>>2][x];
380
381 *address ^= mask;
382}
383
384static void nopixel(int x, int y)
385{
386 (void)x;
387 (void)y;
388}
389
390lcd_pixelfunc_type* const lcd_pixelfuncs[8] = {
391 flippixel, nopixel, setpixel, setpixel,
392 nopixel, clearpixel, nopixel, clearpixel
393};
394
395/* 'mask' and 'bits' contain 2 bits per pixel */
396static void flipblock(fb_data *address, unsigned mask, unsigned bits)
397 ICODE_ATTR;
398static void flipblock(fb_data *address, unsigned mask, unsigned bits)
399{
400 *address ^= bits & mask;
401}
402
403static void bgblock(fb_data *address, unsigned mask, unsigned bits)
404 ICODE_ATTR;
405static void bgblock(fb_data *address, unsigned mask, unsigned bits)
406{
407 unsigned data = *address;
408
409 *address = data ^ ((data ^ bg_pattern) & mask & ~bits);
410}
411
412static void fgblock(fb_data *address, unsigned mask, unsigned bits)
413 ICODE_ATTR;
414static void fgblock(fb_data *address, unsigned mask, unsigned bits)
415{
416 unsigned data = *address;
417
418 *address = data ^ ((data ^ fg_pattern) & mask & bits);
419}
420
421static void solidblock(fb_data *address, unsigned mask, unsigned bits)
422 ICODE_ATTR;
423static void solidblock(fb_data *address, unsigned mask, unsigned bits)
424{
425 unsigned data = *address;
426 unsigned bgp = bg_pattern;
427
428 bits = bgp ^ ((bgp ^ fg_pattern) & bits);
429 *address = data ^ ((data ^ bits) & mask);
430}
431
432static void flipinvblock(fb_data *address, unsigned mask, unsigned bits)
433 ICODE_ATTR;
434static void flipinvblock(fb_data *address, unsigned mask, unsigned bits)
435{
436 *address ^= ~bits & mask;
437}
438
439static void bginvblock(fb_data *address, unsigned mask, unsigned bits)
440 ICODE_ATTR;
441static void bginvblock(fb_data *address, unsigned mask, unsigned bits)
442{
443 unsigned data = *address;
444
445 *address = data ^ ((data ^ bg_pattern) & mask & bits);
446}
447
448static void fginvblock(fb_data *address, unsigned mask, unsigned bits)
449 ICODE_ATTR;
450static void fginvblock(fb_data *address, unsigned mask, unsigned bits)
451{
452 unsigned data = *address;
453
454 *address = data ^ ((data ^ fg_pattern) & mask & ~bits);
455}
456
457static void solidinvblock(fb_data *address, unsigned mask, unsigned bits)
458 ICODE_ATTR;
459static void solidinvblock(fb_data *address, unsigned mask, unsigned bits)
460{
461 unsigned data = *address;
462 unsigned fgp = fg_pattern;
463
464 bits = fgp ^ ((fgp ^ bg_pattern) & bits);
465 *address = data ^ ((data ^ bits) & mask);
466}
467
468lcd_blockfunc_type* const lcd_blockfuncs[8] = {
469 flipblock, bgblock, fgblock, solidblock,
470 flipinvblock, bginvblock, fginvblock, solidinvblock
471};
472
473static inline void setblock(fb_data *address, unsigned mask, unsigned bits)
474{
475 unsigned data = *address;
476
477 bits ^= data;
478 *address = data ^ (bits & mask);
479}
480
481/*** drawing functions ***/
482
483/* Clear the whole display */
484void lcd_clear_display(void)
485{
486 unsigned bits = (drawmode & DRMODE_INVERSEVID) ? fg_pattern : bg_pattern;
487
488 memset(lcd_framebuffer, bits, sizeof lcd_framebuffer);
489 scrolling_lines = 0;
490}
491
492/* Set a single pixel */
493void lcd_drawpixel(int x, int y)
494{
495 if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT))
496 lcd_pixelfuncs[drawmode](x, y);
497}
498
499/* Draw a line */
500void lcd_drawline(int x1, int y1, int x2, int y2)
501{
502 int numpixels;
503 int i;
504 int deltax, deltay;
505 int d, dinc1, dinc2;
506 int x, xinc1, xinc2;
507 int y, yinc1, yinc2;
508 lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[drawmode];
509
510 deltax = abs(x2 - x1);
511 deltay = abs(y2 - y1);
512 xinc2 = 1;
513 yinc2 = 1;
514
515 if (deltax >= deltay)
516 {
517 numpixels = deltax;
518 d = 2 * deltay - deltax;
519 dinc1 = deltay * 2;
520 dinc2 = (deltay - deltax) * 2;
521 xinc1 = 1;
522 yinc1 = 0;
523 }
524 else
525 {
526 numpixels = deltay;
527 d = 2 * deltax - deltay;
528 dinc1 = deltax * 2;
529 dinc2 = (deltax - deltay) * 2;
530 xinc1 = 0;
531 yinc1 = 1;
532 }
533 numpixels++; /* include endpoints */
534
535 if (x1 > x2)
536 {
537 xinc1 = -xinc1;
538 xinc2 = -xinc2;
539 }
540
541 if (y1 > y2)
542 {
543 yinc1 = -yinc1;
544 yinc2 = -yinc2;
545 }
546
547 x = x1;
548 y = y1;
549
550 for (i = 0; i < numpixels; i++)
551 {
552 if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT))
553 pfunc(x, y);
554
555 if (d < 0)
556 {
557 d += dinc1;
558 x += xinc1;
559 y += yinc1;
560 }
561 else
562 {
563 d += dinc2;
564 x += xinc2;
565 y += yinc2;
566 }
567 }
568}
569
570/* Draw a horizontal line (optimised) */
571void lcd_hline(int x1, int x2, int y)
572{
573 int x;
574 fb_data *dst, *dst_end;
575 unsigned mask;
576 lcd_blockfunc_type *bfunc;
577
578 /* direction flip */
579 if (x2 < x1)
580 {
581 x = x1;
582 x1 = x2;
583 x2 = x;
584 }
585
586 /* nothing to draw? */
587 if (((unsigned)y >= LCD_HEIGHT) || (x1 >= LCD_WIDTH) || (x2 < 0))
588 return;
589
590 /* clipping */
591 if (x1 < 0)
592 x1 = 0;
593 if (x2 >= LCD_WIDTH)
594 x2 = LCD_WIDTH-1;
595
596 bfunc = lcd_blockfuncs[drawmode];
597 dst = &lcd_framebuffer[y>>2][x1];
598 mask = pixmask[y & 3];
599
600 dst_end = dst + x2 - x1;
601 do
602 bfunc(dst++, mask, 0xFFu);
603 while (dst <= dst_end);
604}
605
606/* Draw a vertical line (optimised) */
607void lcd_vline(int x, int y1, int y2)
608{
609 int ny;
610 fb_data *dst;
611 unsigned mask, mask_bottom;
612 lcd_blockfunc_type *bfunc;
613
614 /* direction flip */
615 if (y2 < y1)
616 {
617 ny = y1;
618 y1 = y2;
619 y2 = ny;
620 }
621
622 /* nothing to draw? */
623 if (((unsigned)x >= LCD_WIDTH) || (y1 >= LCD_HEIGHT) || (y2 < 0))
624 return;
625
626 /* clipping */
627 if (y1 < 0)
628 y1 = 0;
629 if (y2 >= LCD_HEIGHT)
630 y2 = LCD_HEIGHT-1;
631
632 bfunc = lcd_blockfuncs[drawmode];
633 dst = &lcd_framebuffer[y1>>2][x];
634 ny = y2 - (y1 & ~3);
635 mask = 0xFFu << (2 * (y1 & 3));
636 mask_bottom = 0xFFu >> (2 * (~ny & 3));
637
638 for (; ny >= 4; ny -= 4)
639 {
640 bfunc(dst, mask, 0xFFu);
641 dst += LCD_WIDTH;
642 mask = 0xFFu;
643 }
644 mask &= mask_bottom;
645 bfunc(dst, mask, 0xFFu);
646}
647
648/* Draw a rectangular box */
649void lcd_drawrect(int x, int y, int width, int height)
650{
651 if ((width <= 0) || (height <= 0))
652 return;
653
654 int x2 = x + width - 1;
655 int y2 = y + height - 1;
656
657 lcd_vline(x, y, y2);
658 lcd_vline(x2, y, y2);
659 lcd_hline(x, x2, y);
660 lcd_hline(x, x2, y2);
661}
662
663/* Fill a rectangular area */
664void lcd_fillrect(int x, int y, int width, int height)
665{
666 int ny;
667 fb_data *dst, *dst_end;
668 unsigned mask, mask_bottom;
669 unsigned bits = 0;
670 lcd_blockfunc_type *bfunc;
671 bool fillopt = false;
672
673 /* nothing to draw? */
674 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
675 || (x + width <= 0) || (y + height <= 0))
676 return;
677
678 /* clipping */
679 if (x < 0)
680 {
681 width += x;
682 x = 0;
683 }
684 if (y < 0)
685 {
686 height += y;
687 y = 0;
688 }
689 if (x + width > LCD_WIDTH)
690 width = LCD_WIDTH - x;
691 if (y + height > LCD_HEIGHT)
692 height = LCD_HEIGHT - y;
693
694 if (drawmode & DRMODE_INVERSEVID)
695 {
696 if (drawmode & DRMODE_BG)
697 {
698 fillopt = true;
699 bits = bg_pattern;
700 }
701 }
702 else
703 {
704 if (drawmode & DRMODE_FG)
705 {
706 fillopt = true;
707 bits = fg_pattern;
708 }
709 }
710 bfunc = lcd_blockfuncs[drawmode];
711 dst = &lcd_framebuffer[y>>2][x];
712 ny = height - 1 + (y & 3);
713 mask = 0xFFu << (2 * (y & 3));
714 mask_bottom = 0xFFu >> (2 * (~ny & 3));
715
716 for (; ny >= 4; ny -= 4)
717 {
718 if (fillopt && (mask == 0xFFu))
719 memset(dst, bits, width);
720 else
721 {
722 fb_data *dst_row = dst;
723
724 dst_end = dst_row + width;
725 do
726 bfunc(dst_row++, mask, 0xFFu);
727 while (dst_row < dst_end);
728 }
729
730 dst += LCD_WIDTH;
731 mask = 0xFFu;
732 }
733 mask &= mask_bottom;
734
735 if (fillopt && (mask == 0xFFu))
736 memset(dst, bits, width);
737 else
738 {
739 dst_end = dst + width;
740 do
741 bfunc(dst++, mask, 0xFFu);
742 while (dst < dst_end);
743 }
744}
745
746/* About Rockbox' internal monochrome bitmap format:
747 *
748 * A bitmap contains one bit for every pixel that defines if that pixel is
749 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
750 * at top.
751 * The bytes are stored in row-major order, with byte 0 being top left,
752 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
753 * 0..7, the second row defines pixel row 8..15 etc.
754 *
755 * This is similar to the internal lcd hw format. */
756
757/* Draw a partial monochrome bitmap */
758void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
759 int stride, int x, int y, int width, int height)
760 ICODE_ATTR;
761void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
762 int stride, int x, int y, int width, int height)
763{
764 int shift, ny;
765 fb_data *dst, *dst_end;
766 unsigned mask, mask_bottom;
767 lcd_blockfunc_type *bfunc;
768
769 /* nothing to draw? */
770 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
771 || (x + width <= 0) || (y + height <= 0))
772 return;
773
774 /* clipping */
775 if (x < 0)
776 {
777 width += x;
778 src_x -= x;
779 x = 0;
780 }
781 if (y < 0)
782 {
783 height += y;
784 src_y -= y;
785 y = 0;
786 }
787 if (x + width > LCD_WIDTH)
788 width = LCD_WIDTH - x;
789 if (y + height > LCD_HEIGHT)
790 height = LCD_HEIGHT - y;
791
792 src += stride * (src_y >> 3) + src_x; /* move starting point */
793 src_y &= 7;
794 y -= src_y;
795 dst = &lcd_framebuffer[y>>2][x];
796 shift = y & 3;
797 ny = height - 1 + shift + src_y;
798
799 bfunc = lcd_blockfuncs[drawmode];
800 mask = 0xFFu << (shift + src_y);
801 mask_bottom = 0xFFu >> (~ny & 7);
802
803 if (shift == 0)
804 {
805 unsigned dmask1, dmask2, data;
806
807 for (; ny >= 8; ny -= 8)
808 {
809 const unsigned char *src_row = src;
810 fb_data *dst_row = dst + LCD_WIDTH;
811
812 dmask1 = dibits[mask&0x0F];
813 dmask2 = dibits[(mask>>4)&0x0F];
814 dst_end = dst_row + width;
815
816 if (dmask1 != 0)
817 {
818 do
819 {
820 data = *src_row++;
821 bfunc(dst_row - LCD_WIDTH, dmask1, dibits[data&0x0F]);
822 bfunc(dst_row++, dmask2, dibits[(data>>4)&0x0F]);
823 }
824 while (dst_row < dst_end);
825 }
826 else
827 {
828 do
829 bfunc(dst_row++, dmask2, dibits[((*src_row++)>>4)&0x0F]);
830 while (dst_row < dst_end);
831 }
832 src += stride;
833 dst += 2*LCD_WIDTH;
834 mask = 0xFFu;
835 }
836 mask &= mask_bottom;
837 dmask1 = dibits[mask&0x0F];
838 dmask2 = dibits[(mask>>4)&0x0F];
839 dst_end = dst + width;
840
841 if (dmask1 != 0)
842 {
843 if (dmask2 != 0)
844 {
845 do
846 {
847 data = *src++;
848 bfunc(dst, dmask1, dibits[data&0x0F]);
849 bfunc((dst++) + LCD_WIDTH, dmask2, dibits[(data>>4)&0x0F]);
850 }
851 while (dst < dst_end);
852 }
853 else
854 {
855 do
856 bfunc(dst++, dmask1, dibits[(*src++)&0x0F]);
857 while (dst < dst_end);
858 }
859 }
860 else
861 {
862 do
863 bfunc((dst++) + LCD_WIDTH, dmask2, dibits[((*src++)>>4)&0x0F]);
864 while (dst < dst_end);
865 }
866 }
867 else
868 {
869 dst_end = dst + width;
870 do
871 {
872 const unsigned char *src_col = src++;
873 fb_data *dst_col = dst++;
874 unsigned mask_col = mask;
875 unsigned data = 0;
876
877 for (y = ny; y >= 8; y -= 8)
878 {
879 data |= *src_col << shift;
880
881 if (mask_col & 0xFFu)
882 {
883 if (mask_col & 0x0F)
884 bfunc(dst_col, dibits[mask_col&0x0F], dibits[data&0x0F]);
885 bfunc(dst_col + LCD_WIDTH, dibits[(mask_col>>4)&0x0F],
886 dibits[(data>>4)&0x0F]);
887 mask_col = 0xFFu;
888 }
889 else
890 mask_col >>= 8;
891
892 src_col += stride;
893 dst_col += 2*LCD_WIDTH;
894 data >>= 8;
895 }
896 data |= *src_col << shift;
897 mask_bottom &= mask_col;
898 if (mask_bottom & 0x0F)
899 bfunc(dst_col, dibits[mask_bottom&0x0F], dibits[data&0x0F]);
900 if (mask_bottom & 0xF0)
901 bfunc(dst_col + LCD_WIDTH, dibits[(mask_bottom&0xF0)>>4],
902 dibits[(data>>4)&0x0F]);
903 }
904 while (dst < dst_end);
905 }
906}
907
908/* Draw a full monochrome bitmap */
909void lcd_mono_bitmap(const unsigned char *src, int x, int y, int width, int height)
910{
911 lcd_mono_bitmap_part(src, 0, 0, width, x, y, width, height);
912}
913
914/* About Rockbox' internal native bitmap format:
915 *
916 * A bitmap contains two bits for every pixel. 00 = white, 01 = light grey,
917 * 10 = dark grey, 11 = black. Bits within a byte are arranged vertically, LSB
918 * at top.
919 * The bytes are stored in row-major order, with byte 0 being top left,
920 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
921 * 0..3, the second row defines pixel row 4..7 etc.
922 *
923 * This is the same as the internal lcd hw format. */
924
925/* Draw a partial native bitmap */
926void lcd_bitmap_part(const fb_data *src, int src_x, int src_y,
927 int stride, int x, int y, int width, int height)
928 ICODE_ATTR;
929void lcd_bitmap_part(const fb_data *src, int src_x, int src_y,
930 int stride, int x, int y, int width, int height)
931{
932 int shift, ny;
933 fb_data *dst, *dst_end;
934 unsigned mask, mask_bottom;
935
936 /* nothing to draw? */
937 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
938 || (x + width <= 0) || (y + height <= 0))
939 return;
940
941 /* clipping */
942 if (x < 0)
943 {
944 width += x;
945 src_x -= x;
946 x = 0;
947 }
948 if (y < 0)
949 {
950 height += y;
951 src_y -= y;
952 y = 0;
953 }
954 if (x + width > LCD_WIDTH)
955 width = LCD_WIDTH - x;
956 if (y + height > LCD_HEIGHT)
957 height = LCD_HEIGHT - y;
958
959 src += stride * (src_y >> 2) + src_x; /* move starting point */
960 src_y &= 3;
961 y -= src_y;
962 dst = &lcd_framebuffer[y>>2][x];
963 shift = y & 3;
964 ny = height - 1 + shift + src_y;
965
966 mask = 0xFFu << (2 * (shift + src_y));
967 mask_bottom = 0xFFu >> (2 * (~ny & 3));
968
969 if (shift == 0)
970 {
971 for (; ny >= 4; ny -= 4)
972 {
973 if (mask == 0xFFu)
974 memcpy(dst, src, width);
975 else
976 {
977 const fb_data *src_row = src;
978 fb_data *dst_row = dst;
979
980 dst_end = dst_row + width;
981 do
982 setblock(dst_row++, mask, *src_row++);
983 while (dst_row < dst_end);
984 }
985 src += stride;
986 dst += LCD_WIDTH;
987 mask = 0xFFu;
988 }
989 mask &= mask_bottom;
990
991 if (mask == 0xFFu)
992 memcpy(dst, src, width);
993 else
994 {
995 dst_end = dst + width;
996 do
997 setblock(dst++, mask, *src++);
998 while (dst < dst_end);
999 }
1000 }
1001 else
1002 {
1003 shift *= 2;
1004 dst_end = dst + width;
1005 do
1006 {
1007 const fb_data *src_col = src++;
1008 fb_data *dst_col = dst++;
1009 unsigned mask_col = mask;
1010 unsigned data = 0;
1011
1012 for (y = ny; y >= 4; y -= 4)
1013 {
1014 data |= *src_col << shift;
1015
1016 if (mask_col & 0xFFu)
1017 {
1018 setblock(dst_col, mask_col, data);
1019 mask_col = 0xFFu;
1020 }
1021 else
1022 mask_col >>= 8;
1023
1024 src_col += stride;
1025 dst_col += LCD_WIDTH;
1026 data >>= 8;
1027 }
1028 data |= *src_col << shift;
1029 setblock(dst_col, mask_col & mask_bottom, data);
1030 }
1031 while (dst < dst_end);
1032 }
1033}
1034
1035/* Draw a full native bitmap */
1036void lcd_bitmap(const fb_data *src, int x, int y, int width, int height)
1037{
1038 lcd_bitmap_part(src, 0, 0, width, x, y, width, height);
1039}
1040
1041/* put a string at a given pixel position, skipping first ofs pixel columns */
1042static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
1043{
1044 unsigned short ch;
1045 unsigned short *ucs;
1046 struct font* pf = font_get(curfont);
1047
1048 ucs = bidi_l2v(str, 1);
1049
1050 while ((ch = *ucs++) != 0 && x < LCD_WIDTH)
1051 {
1052 int width;
1053 const unsigned char *bits;
1054
1055 /* get proportional width and glyph bits */
1056 width = font_get_width(pf,ch);
1057
1058 if (ofs > width)
1059 {
1060 ofs -= width;
1061 continue;
1062 }
1063
1064 bits = font_get_bits(pf, ch);
1065
1066 lcd_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs,
1067 pf->height);
1068
1069 x += width - ofs;
1070 ofs = 0;
1071 }
1072}
1073
1074/* put a string at a given pixel position */
1075void lcd_putsxy(int x, int y, const unsigned char *str)
1076{
1077 lcd_putsxyofs(x, y, 0, str);
1078}
1079
1080/*** line oriented text output ***/
1081
1082/* put a string at a given char position */
1083void lcd_puts(int x, int y, const unsigned char *str)
1084{
1085 lcd_puts_style_offset(x, y, str, STYLE_DEFAULT, 0);
1086}
1087
1088void lcd_puts_style(int x, int y, const unsigned char *str, int style)
1089{
1090 lcd_puts_style_offset(x, y, str, style, 0);
1091}
1092
1093void lcd_puts_offset(int x, int y, const unsigned char *str, int offset)
1094{
1095 lcd_puts_style_offset(x, y, str, STYLE_DEFAULT, offset);
1096}
1097
1098/* put a string at a given char position, style, and pixel position,
1099 * skipping first offset pixel columns */
1100void lcd_puts_style_offset(int x, int y, const unsigned char *str,
1101 int style, int offset)
1102{
1103 int xpos,ypos,w,h,xrect;
1104 int lastmode = drawmode;
1105
1106 /* make sure scrolling is turned off on the line we are updating */
1107 scrolling_lines &= ~(1 << y);
1108
1109 if(!str || !str[0])
1110 return;
1111
1112 lcd_getstringsize(str, &w, &h);
1113 xpos = xmargin + x*w / utf8length((char *)str);
1114 ypos = ymargin + y*h;
1115 drawmode = (style & STYLE_INVERT) ?
1116 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
1117 lcd_putsxyofs(xpos, ypos, offset, str);
1118 drawmode ^= DRMODE_INVERSEVID;
1119 xrect = xpos + MAX(w - offset, 0);
1120 lcd_fillrect(xrect, ypos, LCD_WIDTH - xrect, h);
1121 drawmode = lastmode;
1122}
1123
1124/*** scrolling ***/
1125
1126/* Reverse the invert setting of the scrolling line (if any) at given char
1127 position. Setting will go into affect next time line scrolls. */
1128void lcd_invertscroll(int x, int y)
1129{
1130 struct scrollinfo* s;
1131
1132 (void)x;
1133
1134 s = &scroll[y];
1135 s->invert = !s->invert;
1136}
1137
1138void lcd_stop_scroll(void)
1139{
1140 scrolling_lines=0;
1141}
1142
1143void lcd_scroll_speed(int speed)
1144{
1145 scroll_ticks = scroll_tick_table[speed];
1146}
1147
1148void lcd_scroll_step(int step)
1149{
1150 scroll_step = step;
1151}
1152
1153void lcd_scroll_delay(int ms)
1154{
1155 scroll_delay = ms / (HZ / 10);
1156}
1157
1158void lcd_bidir_scroll(int percent)
1159{
1160 bidir_limit = percent;
1161}
1162
1163void lcd_puts_scroll(int x, int y, const unsigned char *string)
1164{
1165 lcd_puts_scroll_style(x, y, string, STYLE_DEFAULT);
1166}
1167
1168void lcd_puts_scroll_style(int x, int y, const unsigned char *string, int style)
1169{
1170 lcd_puts_scroll_style_offset(x, y, string, style, 0);
1171}
1172
1173void lcd_puts_scroll_offset(int x, int y, const unsigned char *string, int offset)
1174{
1175 lcd_puts_scroll_style_offset(x, y, string, STYLE_DEFAULT, offset);
1176}
1177
1178void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
1179 int style, int offset)
1180{
1181 struct scrollinfo* s;
1182 int w, h;
1183
1184 s = &scroll[y];
1185
1186 s->start_tick = current_tick + scroll_delay;
1187 s->invert = false;
1188 if (style & STYLE_INVERT) {
1189 s->invert = true;
1190 lcd_puts_style_offset(x,y,string,STYLE_INVERT,offset);
1191 }
1192 else
1193 lcd_puts_offset(x,y,string,offset);
1194
1195 lcd_getstringsize(string, &w, &h);
1196
1197 if (LCD_WIDTH - x * 8 - xmargin < w) {
1198 /* prepare scroll line */
1199 char *end;
1200
1201 memset(s->line, 0, sizeof s->line);
1202 strcpy(s->line, (char *)string);
1203
1204 /* get width */
1205 s->width = lcd_getstringsize((unsigned char *)s->line, &w, &h);
1206
1207 /* scroll bidirectional or forward only depending on the string
1208 width */
1209 if ( bidir_limit ) {
1210 s->bidir = s->width < (LCD_WIDTH - xmargin) *
1211 (100 + bidir_limit) / 100;
1212 }
1213 else
1214 s->bidir = false;
1215
1216 if (!s->bidir) { /* add spaces if scrolling in the round */
1217 strcat(s->line, " ");
1218 /* get new width incl. spaces */
1219 s->width = lcd_getstringsize((unsigned char *)s->line, &w, &h);
1220 }
1221
1222 end = strchr(s->line, '\0');
1223 strncpy(end, (char *)string, LCD_WIDTH/2);
1224
1225 s->len = utf8length((char *)string);
1226 s->offset = offset;
1227 s->startx = xmargin + x * s->width / s->len;
1228 s->backward = false;
1229 scrolling_lines |= (1<<y);
1230 }
1231 else
1232 /* force a bit switch-off since it doesn't scroll */
1233 scrolling_lines &= ~(1<<y);
1234}
1235
1236static void scroll_thread(void)
1237{
1238 struct font* pf;
1239 struct scrollinfo* s;
1240 int index;
1241 int xpos, ypos;
1242 int lastmode;
1243
1244 /* initialize scroll struct array */
1245 scrolling_lines = 0;
1246
1247 while ( 1 ) {
1248 for ( index = 0; index < SCROLLABLE_LINES; index++ ) {
1249 /* really scroll? */
1250 if ( !(scrolling_lines&(1<<index)) )
1251 continue;
1252
1253 s = &scroll[index];
1254
1255 /* check pause */
1256 if (TIME_BEFORE(current_tick, s->start_tick))
1257 continue;
1258
1259 if (s->backward)
1260 s->offset -= scroll_step;
1261 else
1262 s->offset += scroll_step;
1263
1264 pf = font_get(curfont);
1265 xpos = s->startx;
1266 ypos = ymargin + index * pf->height;
1267
1268 if (s->bidir) { /* scroll bidirectional */
1269 if (s->offset <= 0) {
1270 /* at beginning of line */
1271 s->offset = 0;
1272 s->backward = false;
1273 s->start_tick = current_tick + scroll_delay * 2;
1274 }
1275 if (s->offset >= s->width - (LCD_WIDTH - xpos)) {
1276 /* at end of line */
1277 s->offset = s->width - (LCD_WIDTH - xpos);
1278 s->backward = true;
1279 s->start_tick = current_tick + scroll_delay * 2;
1280 }
1281 }
1282 else {
1283 /* scroll forward the whole time */
1284 if (s->offset >= s->width)
1285 s->offset %= s->width;
1286 }
1287
1288 lastmode = drawmode;
1289 drawmode = s->invert ?
1290 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
1291 lcd_putsxyofs(xpos, ypos, s->offset, s->line);
1292 drawmode = lastmode;
1293 lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height);
1294 }
1295
1296 sleep(scroll_ticks);
1297 }
1298}
diff --git a/firmware/drivers/lcd-h300.c b/firmware/drivers/lcd-h300.c
deleted file mode 100644
index 3e5642e35d..0000000000
--- a/firmware/drivers/lcd-h300.c
+++ /dev/null
@@ -1,425 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2004 by Linus Nielsen Feltzing
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include "config.h"
20
21#include "cpu.h"
22#include "lcd.h"
23#include "kernel.h"
24#include "thread.h"
25#include <string.h>
26#include <stdlib.h>
27#include "file.h"
28#include "debug.h"
29#include "system.h"
30#include "font.h"
31#include "bidi.h"
32
33static bool display_on = false; /* is the display turned on? */
34static bool display_flipped = false;
35static int xoffset = 0; /* needed for flip */
36
37/* register defines */
38#define R_START_OSC 0x00
39#define R_DRV_OUTPUT_CONTROL 0x01
40#define R_DRV_WAVEFORM_CONTROL 0x02
41#define R_ENTRY_MODE 0x03
42#define R_COMPARE_REG1 0x04
43#define R_COMPARE_REG2 0x05
44
45#define R_DISP_CONTROL1 0x07
46#define R_DISP_CONTROL2 0x08
47#define R_DISP_CONTROL3 0x09
48
49#define R_FRAME_CYCLE_CONTROL 0x0b
50#define R_EXT_DISP_IF_CONTROL 0x0c
51
52#define R_POWER_CONTROL1 0x10
53#define R_POWER_CONTROL2 0x11
54#define R_POWER_CONTROL3 0x12
55#define R_POWER_CONTROL4 0x13
56
57#define R_RAM_ADDR_SET 0x21
58#define R_WRITE_DATA_2_GRAM 0x22
59
60#define R_GAMMA_FINE_ADJ_POS1 0x30
61#define R_GAMMA_FINE_ADJ_POS2 0x31
62#define R_GAMMA_FINE_ADJ_POS3 0x32
63#define R_GAMMA_GRAD_ADJ_POS 0x33
64
65#define R_GAMMA_FINE_ADJ_NEG1 0x34
66#define R_GAMMA_FINE_ADJ_NEG2 0x35
67#define R_GAMMA_FINE_ADJ_NEG3 0x36
68#define R_GAMMA_GRAD_ADJ_NEG 0x37
69
70#define R_GAMMA_AMP_ADJ_RES_POS 0x38
71#define R_GAMMA_AMP_AVG_ADJ_RES_NEG 0x39
72
73#define R_GATE_SCAN_POS 0x40
74#define R_VERT_SCROLL_CONTROL 0x41
75#define R_1ST_SCR_DRV_POS 0x42
76#define R_2ND_SCR_DRV_POS 0x43
77#define R_HORIZ_RAM_ADDR_POS 0x44
78#define R_VERT_RAM_ADDR_POS 0x45
79
80#define LCD_CMD (*(volatile unsigned short *)0xf0000000)
81#define LCD_DATA (*(volatile unsigned short *)0xf0000002)
82
83/* called very frequently - inline! */
84static inline void lcd_write_reg(int reg, int val)
85{
86 LCD_CMD = reg;
87 LCD_DATA = val;
88}
89
90/* called very frequently - inline! */
91static inline void lcd_begin_write_gram(void)
92{
93 LCD_CMD = R_WRITE_DATA_2_GRAM;
94}
95
96/*** hardware configuration ***/
97
98void lcd_set_contrast(int val)
99{
100 (void)val;
101}
102
103void lcd_set_invert_display(bool yesno)
104{
105 (void)yesno;
106}
107
108static void flip_lcd(bool yesno)
109{
110 if (yesno)
111 {
112 lcd_write_reg(R_DRV_OUTPUT_CONTROL, 0x031b); /* 224 lines, GS=SS=1 */
113 lcd_write_reg(R_GATE_SCAN_POS, 0x0002); /* 16 lines offset */
114 lcd_write_reg(R_1ST_SCR_DRV_POS, 0xdf04); /* 4..223 */
115 }
116 else
117 {
118 lcd_write_reg(R_DRV_OUTPUT_CONTROL, 0x001b); /* 224 lines, GS=SS=0 */
119 lcd_write_reg(R_GATE_SCAN_POS, 0x0000);
120 lcd_write_reg(R_1ST_SCR_DRV_POS, 0xdb00); /* 0..219 */
121 }
122}
123
124/* turn the display upside down (call lcd_update() afterwards) */
125void lcd_set_flip(bool yesno)
126{
127 display_flipped = yesno;
128 xoffset = yesno ? 4 : 0;
129
130 if (display_on)
131 flip_lcd(yesno);
132}
133
134static void _display_on(void)
135{
136 /** Sequence according to datasheet, p. 132 **/
137
138 lcd_write_reg(R_START_OSC, 0x0001); /* Start Oscilation */
139 sleep(1);
140
141 /* zero everything*/
142 lcd_write_reg(R_POWER_CONTROL1, 0x0000); /* STB = 0, SLP = 0 */
143 lcd_write_reg(R_DISP_CONTROL1, 0x0000); /* GON = 0, DTE = 0, D1-0 = 00b */
144 lcd_write_reg(R_POWER_CONTROL3, 0x0000); /* PON = 0 */
145 lcd_write_reg(R_POWER_CONTROL4, 0x0000); /* VCOMG = 0 */
146 sleep(1);
147
148 /* initialise power supply */
149
150 /* DC12-10 = 000b: Step-up1 = clock/8,
151 * DC02-00 = 000b: Step-up2 = clock/16,
152 * VC2-0 = 010b: VciOUT = 0.87 * VciLVL */
153 lcd_write_reg(R_POWER_CONTROL2, 0x0002);
154
155 /* VRH3-0 = 1000b: Vreg1OUT = REGP * 1.90 */
156 lcd_write_reg(R_POWER_CONTROL3, 0x0008);
157
158 /* VDV4-0 = 00110b: VcomA = Vreg1OUT * 0.76,
159 * VCM4-0 = 10000b: VcomH = Vreg1OUT * 0.70*/
160 lcd_write_reg(R_POWER_CONTROL4, 0x0610);
161
162 lcd_write_reg(R_POWER_CONTROL1, 0x0044); /* AP2-0 = 100b, DK = 1 */
163 lcd_write_reg(R_POWER_CONTROL3, 0x0018); /* PON = 1 */
164
165 sleep(4); /* Step-up circuit stabilising time */
166
167 /* start power supply */
168
169 lcd_write_reg(R_POWER_CONTROL1, 0x0540); /* BT2-0 = 101b, DK = 0 */
170 lcd_write_reg(R_POWER_CONTROL4, 0x2610); /* VCOMG = 1 */
171
172 /* other settings */
173
174 /* B/C = 1: n-line inversion form
175 * EOR = 1: polarity inversion occurs by applying an EOR to odd/even
176 * frame select signal and an n-line inversion signal.
177 * FLD = 01b: 1 field interlaced scan, external display iface */
178 lcd_write_reg(R_DRV_WAVEFORM_CONTROL, 0x0700);
179
180 /* Address counter updated in vertical direction; left to right;
181 * vertical increment horizontal increment.
182 * data format for 8bit transfer or spi = 65k (5,6,5)
183 * Reverse order of RGB to BGR for 18bit data written to GRAM
184 * Replace data on writing to GRAM */
185 lcd_write_reg(R_ENTRY_MODE, 0x7038);
186
187 flip_lcd(display_flipped);
188
189 lcd_write_reg(R_2ND_SCR_DRV_POS, 0x0000);
190 lcd_write_reg(R_VERT_SCROLL_CONTROL, 0x0000);
191
192 /* 19 clocks,no equalization */
193 lcd_write_reg(R_FRAME_CYCLE_CONTROL, 0x0002);
194
195 /* Transfer mode for RGB interface disabled
196 * internal clock operation;
197 * System interface/VSYNC interface */
198 lcd_write_reg(R_EXT_DISP_IF_CONTROL, 0x0003);
199
200 /* Front porch lines: 8; Back porch lines: 8; */
201 lcd_write_reg(R_DISP_CONTROL2, 0x0808);
202
203 /* Scan mode by the gate driver in the non-display area: disabled;
204 * Cycle of scan by the gate driver - set to 31frames(518ms),
205 * disabled by above setting */
206 lcd_write_reg(R_DISP_CONTROL3, 0x003f);
207
208 lcd_write_reg(R_GAMMA_FINE_ADJ_POS1, 0x0003);
209 lcd_write_reg(R_GAMMA_FINE_ADJ_POS2, 0x0707);
210 lcd_write_reg(R_GAMMA_FINE_ADJ_POS3, 0x0007);
211 lcd_write_reg(R_GAMMA_GRAD_ADJ_POS, 0x0705);
212 lcd_write_reg(R_GAMMA_FINE_ADJ_NEG1, 0x0007);
213 lcd_write_reg(R_GAMMA_FINE_ADJ_NEG2, 0x0000);
214 lcd_write_reg(R_GAMMA_FINE_ADJ_NEG3, 0x0407);
215 lcd_write_reg(R_GAMMA_GRAD_ADJ_NEG, 0x0507);
216 lcd_write_reg(R_GAMMA_AMP_ADJ_RES_POS, 0x1d09);
217 lcd_write_reg(R_GAMMA_AMP_AVG_ADJ_RES_NEG, 0x0303);
218
219 display_on=true; /* must be done before calling lcd_update() */
220 lcd_update();
221
222 sleep(4); /* op-amp stabilising time */
223
224 /** Sequence according to datasheet, p. 130 **/
225
226 lcd_write_reg(R_POWER_CONTROL1, 0x4540); /* SAP2-0=100, BT2-0=101, AP2-0=100 */
227 lcd_write_reg(R_DISP_CONTROL1, 0x0005); /* GON=0, DTE=0, REV=1, D1-0=01 */
228 sleep(2);
229
230 lcd_write_reg(R_DISP_CONTROL1, 0x0025); /* GON=1, DTE=0, REV=1, D1-0=01 */
231 lcd_write_reg(R_DISP_CONTROL1, 0x0027); /* GON=1, DTE=0, REV=1, D1-0=11 */
232 sleep(2);
233
234 lcd_write_reg(R_DISP_CONTROL1, 0x0037); /* GON=1, DTE=1, REV=1, D1-0=11 */
235}
236
237/* LCD init */
238void lcd_init_device(void)
239{
240 /* GPO46 is LCD RESET */
241 or_l(0x00004000, &GPIO1_OUT);
242 or_l(0x00004000, &GPIO1_ENABLE);
243 or_l(0x00004000, &GPIO1_FUNCTION);
244
245 /* Reset LCD */
246 and_l(~0x00004000, &GPIO1_OUT);
247 sleep(1);
248 or_l(0x00004000, &GPIO1_OUT);
249 sleep(1);
250
251 _display_on();
252}
253
254void lcd_enable(bool on)
255{
256 if(display_on!=on)
257 {
258 if(on)
259 {
260 _display_on();
261 }
262 else
263 {
264 /** Off sequence according to datasheet, p. 130 **/
265
266 lcd_write_reg(R_FRAME_CYCLE_CONTROL, 0x0002); /* EQ=0, 18 clks/line */
267 lcd_write_reg(R_DISP_CONTROL1, 0x0036); /* GON=1, DTE=1, REV=1, D1-0=10 */
268 sleep(2);
269
270 lcd_write_reg(R_DISP_CONTROL1, 0x0026); /* GON=1, DTE=0, REV=1, D1-0=10 */
271 sleep(2);
272
273 lcd_write_reg(R_DISP_CONTROL1, 0x0000); /* GON=0, DTE=0, D1-0=00 */
274
275 lcd_write_reg(R_POWER_CONTROL1, 0x0000); /* SAP2-0=000, AP2-0=000 */
276 lcd_write_reg(R_POWER_CONTROL3, 0x0000); /* PON=0 */
277 lcd_write_reg(R_POWER_CONTROL4, 0x0000); /* VCOMG=0 */
278
279 /* datasheet p. 131 */
280 lcd_write_reg(R_POWER_CONTROL1, 0x0001); /* STB=1: standby mode */
281
282 display_on=false;
283 }
284 }
285}
286
287/*** update functions ***/
288
289/* Performance function that works with an external buffer
290 note that by and bheight are in 8-pixel units! */
291void lcd_blit(const fb_data* data, int x, int by, int width,
292 int bheight, int stride)
293{
294 /* TODO: Implement lcd_blit() */
295 (void)data;
296 (void)x;
297 (void)by;
298 (void)width;
299 (void)bheight;
300 (void)stride;
301 /*if(display_on)*/
302}
303
304/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420.
305 * y should have two lines of Y back to back.
306 * bu and rv should contain the Cb and Cr data for the two lines of Y.
307 * Needs EMAC set to saturated, signed integer mode.
308 */
309extern void lcd_write_yuv420_lines(const unsigned char *y,
310 const unsigned char *bu,
311 const unsigned char *rv, int width);
312
313/* Performance function to blit a YUV bitmap directly to the LCD
314 * src_x, src_y, width and height should be even
315 * x, y, width and height have to be within LCD bounds
316 */
317void lcd_yuv_blit(unsigned char * const src[3],
318 int src_x, int src_y, int stride,
319 int x, int y, int width, int height)
320{
321 /* IRAM Y, Cb and Cb buffers. */
322 unsigned char y_ibuf[LCD_WIDTH*2];
323 unsigned char bu_ibuf[LCD_WIDTH/2];
324 unsigned char rv_ibuf[LCD_WIDTH/2];
325 const unsigned char *ysrc, *usrc, *vsrc;
326 const unsigned char *ysrc_max;
327
328 if (!display_on)
329 return;
330
331 width &= ~1; /* stay on the safe side */
332 height &= ~1;
333
334 /* Set start position and window */
335 lcd_write_reg(R_VERT_RAM_ADDR_POS,((x+xoffset+width-1) << 8) | (x+xoffset));
336 lcd_write_reg(R_RAM_ADDR_SET, ((x+xoffset) << 8) | y);
337
338 lcd_begin_write_gram();
339
340 ysrc = src[0] + src_y * stride + src_x;
341 usrc = src[1] + (src_y * stride >> 2) + (src_x >> 1);
342 vsrc = src[2] + (src_y * stride >> 2) + (src_x >> 1);
343 ysrc_max = ysrc + height * stride;
344
345 coldfire_set_macsr(EMAC_SATURATE);
346 do
347 {
348 memcpy(y_ibuf, ysrc, width);
349 memcpy(y_ibuf + width, ysrc + stride, width);
350 memcpy(bu_ibuf, usrc, width >> 1);
351 memcpy(rv_ibuf, vsrc, width >> 1);
352 lcd_write_yuv420_lines(y_ibuf, bu_ibuf, rv_ibuf, width);
353 ysrc += 2 * stride;
354 usrc += stride >> 1;
355 vsrc += stride >> 1;
356 }
357 while (ysrc < ysrc_max);
358}
359
360/* Update the display.
361 This must be called after all other LCD functions that change the display. */
362void lcd_update(void) ICODE_ATTR;
363void lcd_update(void)
364{
365 if(display_on){
366 /* reset update window */
367 lcd_write_reg(R_VERT_RAM_ADDR_POS,((xoffset+219)<<8) | xoffset);
368
369 /* Copy display bitmap to hardware */
370 lcd_write_reg(R_RAM_ADDR_SET, xoffset << 8);
371 lcd_begin_write_gram();
372
373 DAR3 = 0xf0000002;
374 SAR3 = (unsigned long)lcd_framebuffer;
375 BCR3 = LCD_WIDTH*LCD_HEIGHT*2;
376 DCR3 = DMA_AA | DMA_BWC(1)
377 | DMA_SINC | DMA_SSIZE(DMA_SIZE_LINE)
378 | DMA_DSIZE(DMA_SIZE_WORD) | DMA_START;
379
380 while (!(DSR3 & 1));
381 DSR3 = 1;
382 }
383}
384
385
386/* Update a fraction of the display. */
387void lcd_update_rect(int, int, int, int) ICODE_ATTR;
388void lcd_update_rect(int x, int y, int width, int height)
389{
390 unsigned long dma_addr;
391
392 if(display_on) {
393
394 if(x + width > LCD_WIDTH)
395 width = LCD_WIDTH - x;
396 if(width <= 0) /* nothing to do */
397 return;
398 if(y + height > LCD_HEIGHT)
399 height = LCD_HEIGHT - y;
400
401 /* set update window */
402
403 lcd_write_reg(R_VERT_RAM_ADDR_POS,((x+xoffset+width-1) << 8) | (x+xoffset));
404 lcd_write_reg(R_RAM_ADDR_SET, ((x+xoffset) << 8) | y);
405 lcd_begin_write_gram();
406
407 DAR3 = 0xf0000002;
408 dma_addr = (unsigned long)&lcd_framebuffer[y][x];
409 width *= 2;
410
411 for (; height > 0; height--)
412 {
413 SAR3 = dma_addr;
414 BCR3 = width;
415 DCR3 = DMA_AA | DMA_BWC(1)
416 | DMA_SINC | DMA_SSIZE(DMA_SIZE_LINE)
417 | DMA_DSIZE(DMA_SIZE_WORD) | DMA_START;
418
419 dma_addr += LCD_WIDTH*2;
420
421 while (!(DSR3 & 1));
422 DSR3 = 1;
423 }
424 }
425}
diff --git a/firmware/drivers/lcd.S b/firmware/drivers/lcd.S
index d9e7092c94..ed0bc8d15b 100755
--- a/firmware/drivers/lcd.S
+++ b/firmware/drivers/lcd.S
@@ -48,23 +48,23 @@
48 * - DS -> Data Selection line, latched at the rising edge 48 * - DS -> Data Selection line, latched at the rising edge
49 * of the 8th serial clock (*) : 49 * of the 8th serial clock (*) :
50 * 0 : instruction register, 50 * 0 : instruction register,
51 * 1 : data register; 51 * 1 : data register;
52 * - SC -> Serial Clock line (SDA). 52 * - SC -> Serial Clock line (SDA).
53 * - SD -> Serial Data line (SCK), latched at the rising edge 53 * - SD -> Serial Data line (SCK), latched at the rising edge
54 * of each serial clock (*). 54 * of each serial clock (*).
55 * 55 *
56 * _ _ 56 * _ _
57 * /CS \ / 57 * /CS \ /
58 * \______________________________________________________/ 58 * \______________________________________________________/
59 * _____ ____ ____ ____ ____ ____ ____ ____ ____ _____ 59 * _____ ____ ____ ____ ____ ____ ____ ____ ____ _____
60 * SD \/ D7 \/ D6 \/ D5 \/ D4 \/ D3 \/ D2 \/ D1 \/ D0 \/ 60 * SD \/ D7 \/ D6 \/ D5 \/ D4 \/ D3 \/ D2 \/ D1 \/ D0 \/
61 * _____/\____/\____/\____/\____/\____/\____/\____/\____/\_____ 61 * _____/\____/\____/\____/\____/\____/\____/\____/\____/\_____
62 * 62 *
63 * _____ _ _ _ _ _ _ _ ________ 63 * _____ _ _ _ _ _ _ _ ________
64 * SC \ * \ * \ * \ * \ * \ * \ * \ * 64 * SC \ * \ * \ * \ * \ * \ * \ * \ *
65 * \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ 65 * \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
66 * _ _________________________________________________________ 66 * _ _________________________________________________________
67 * DS \/ 67 * DS \/
68 * _/\_________________________________________________________ 68 * _/\_________________________________________________________
69 * 69 *
70 */ 70 */
@@ -93,14 +93,14 @@ _lcd_write_command:
93 mov.l .lcdr,r3 /* put lcd data port address in r3 */ 93 mov.l .lcdr,r3 /* put lcd data port address in r3 */
94 mov r4,r1 /* copy data byte to r1 */ 94 mov r4,r1 /* copy data byte to r1 */
95 mov #1,r5 /* set byte count to 1 (!) */ 95 mov #1,r5 /* set byte count to 1 (!) */
96 96
97 /* This code will fail if an interrupt changes the contents of PBDRL. 97 /* This code will fail if an interrupt changes the contents of PBDRL.
98 * If so, we must disable the interrupt here. */ 98 * If so, we must disable the interrupt here. */
99 99
100 mov.b @r3,r0 /* r0 = PBDRL */ 100 mov.b @r3,r0 /* r0 = PBDRL */
101 or #(LCD_SD),r0 /* r0 |= LCD_SD */ 101 or #(LCD_SD),r0 /* r0 |= LCD_SD */
102 and #(~(LCD_CS|LCD_DS|LCD_SC)),r0 /* r0 &= ~(LCD_CS|LCD_DS|LCD_SC) */ 102 and #(~(LCD_CS|LCD_DS|LCD_SC)),r0 /* r0 &= ~(LCD_CS|LCD_DS|LCD_SC) */
103 103
104 bra .single_transfer /* jump into the transfer loop */ 104 bra .single_transfer /* jump into the transfer loop */
105 neg r0,r2 /* r2 = 0 - r0 */ 105 neg r0,r2 /* r2 = 0 - r0 */
106 106
@@ -131,7 +131,7 @@ _lcd_write_data:
131 131
132 /* This code will fail if an interrupt changes the contents of PBDRL. 132 /* This code will fail if an interrupt changes the contents of PBDRL.
133 * If so, we must disable the interrupt here. If disabling interrupts 133 * If so, we must disable the interrupt here. If disabling interrupts
134 * for a long time (~9200 clks = ~830 µs for transferring 112 bytes on 134 * for a long time (~9200 clks = ~830 µs for transferring 112 bytes on
135 * recorders)is undesirable, the loop has to be rewritten to 135 * recorders)is undesirable, the loop has to be rewritten to
136 * disable/precalculate/transfer/enable for each iteration. However, 136 * disable/precalculate/transfer/enable for each iteration. However,
137 * this would significantly decrease performance. */ 137 * this would significantly decrease performance. */
@@ -148,7 +148,7 @@ _lcd_write_data:
148.multi_transfer: 148.multi_transfer:
149 mov.b @r4+,r1 /* load data byte from memory */ 149 mov.b @r4+,r1 /* load data byte from memory */
150 150
151.single_transfer: 151.single_transfer:
152 shll16 r1 /* shift data to most significant byte */ 152 shll16 r1 /* shift data to most significant byte */
153 shll8 r1 153 shll8 r1
154 154
@@ -157,85 +157,85 @@ _lcd_write_data:
157 /* uses neg here for compatibility with recorder version */ 157 /* uses neg here for compatibility with recorder version */
158 bt 1f /* data bit = 1? */ 158 bt 1f /* data bit = 1? */
159 and #(~LCD_SD),r0 /* no: r0 &= ~LCD_SD */ 159 and #(~LCD_SD),r0 /* no: r0 &= ~LCD_SD */
160 1: 160 1:
161 shll r1 /* next shift here for alignment */ 161 shll r1 /* next shift here for alignment */
162 mov.b r0,@r3 /* set data to port */ 162 mov.b r0,@r3 /* set data to port */
163 or #(LCD_SC),r0 /* rise SC (independent of SD level) */ 163 or #(LCD_SC),r0 /* rise SC (independent of SD level) */
164 mov.b r0,@r3 /* set to port */ 164 mov.b r0,@r3 /* set to port */
165 165
166 neg r2,r0 166 neg r2,r0
167 bt 1f 167 bt 1f
168 and #(~LCD_SD),r0 168 and #(~LCD_SD),r0
169 1: 169 1:
170 mov.b r0,@r3 170 mov.b r0,@r3
171 or #(LCD_SC),r0 171 or #(LCD_SC),r0
172 mov.b r0,@r3 172 mov.b r0,@r3
173 173
174 shll r1 174 shll r1
175 neg r2,r0 175 neg r2,r0
176 bt 1f 176 bt 1f
177 and #(~LCD_SD),r0 177 and #(~LCD_SD),r0
178 1: 178 1:
179 shll r1 179 shll r1
180 mov.b r0,@r3 180 mov.b r0,@r3
181 or #(LCD_SC),r0 181 or #(LCD_SC),r0
182 mov.b r0,@r3 182 mov.b r0,@r3
183 183
184 neg r2,r0 184 neg r2,r0
185 bt 1f 185 bt 1f
186 and #(~LCD_SD),r0 186 and #(~LCD_SD),r0
187 1: 187 1:
188 mov.b r0,@r3 188 mov.b r0,@r3
189 or #(LCD_SC),r0 189 or #(LCD_SC),r0
190 mov.b r0,@r3 190 mov.b r0,@r3
191 191
192 shll r1 192 shll r1
193 neg r2,r0 193 neg r2,r0
194 bt 1f 194 bt 1f
195 and #(~LCD_SD),r0 195 and #(~LCD_SD),r0
196 1: 196 1:
197 shll r1 197 shll r1
198 mov.b r0,@r3 198 mov.b r0,@r3
199 or #(LCD_SC),r0 199 or #(LCD_SC),r0
200 mov.b r0,@r3 200 mov.b r0,@r3
201 201
202 neg r2,r0 202 neg r2,r0
203 bt 1f 203 bt 1f
204 and #(~LCD_SD),r0 204 and #(~LCD_SD),r0
205 1: 205 1:
206 mov.b r0,@r3 206 mov.b r0,@r3
207 or #(LCD_SC),r0 207 or #(LCD_SC),r0
208 mov.b r0,@r3 208 mov.b r0,@r3
209 209
210 shll r1 210 shll r1
211 neg r2,r0 211 neg r2,r0
212 bt 1f 212 bt 1f
213 and #(~LCD_SD),r0 213 and #(~LCD_SD),r0
214 1: 214 1:
215 shll r1 215 shll r1
216 mov.b r0,@r3 216 mov.b r0,@r3
217 or #(LCD_SC),r0 217 or #(LCD_SC),r0
218 mov.b r0,@r3 218 mov.b r0,@r3
219 219
220 neg r2,r0 220 neg r2,r0
221 bt 1f 221 bt 1f
222 and #(~LCD_SD),r0 222 and #(~LCD_SD),r0
223 1: 223 1:
224 mov.b r0,@r3 224 mov.b r0,@r3
225 or #(LCD_SC),r0 225 or #(LCD_SC),r0
226 mov.b r0,@r3 226 mov.b r0,@r3
227 227
228#else /* HAVE_LCD_CHARCELLS */ 228#else /* HAVE_LCD_CHARCELLS */
229/* further optimized version, exploits that SD is on bit 0 for recorders */ 229/* further optimized version, exploits that SD is on bit 0 for recorders */
230 230
231 .align 2 231 .align 2
232.multi_transfer: 232.multi_transfer:
233 mov.b @r4+,r1 /* load data byte from memory */ 233 mov.b @r4+,r1 /* load data byte from memory */
234 nop 234 nop
235 235
236.single_transfer: 236.single_transfer:
237 shll16 r1 /* shift data to most significant byte */ 237 shll16 r1 /* shift data to most significant byte */
238 shll8 r1 238 shll8 r1
239 not r1,r1 /* and invert for use with negc */ 239 not r1,r1 /* and invert for use with negc */
240 240
241 shll r1 /* shift the MSB into carry */ 241 shll r1 /* shift the MSB into carry */
@@ -245,46 +245,46 @@ _lcd_write_data:
245 or #(LCD_SC),r0 /* rise SC (independent of SD level) */ 245 or #(LCD_SC),r0 /* rise SC (independent of SD level) */
246 mov.b r0,@r3 /* set to port */ 246 mov.b r0,@r3 /* set to port */
247 247
248 negc r2,r0 248 negc r2,r0
249 mov.b r0,@r3 249 mov.b r0,@r3
250 or #(LCD_SC),r0 250 or #(LCD_SC),r0
251 mov.b r0,@r3 251 mov.b r0,@r3
252 252
253 shll r1 253 shll r1
254 negc r2,r0 254 negc r2,r0
255 shll r1 255 shll r1
256 mov.b r0,@r3 256 mov.b r0,@r3
257 or #(LCD_SC),r0 257 or #(LCD_SC),r0
258 mov.b r0,@r3 258 mov.b r0,@r3
259 259
260 negc r2,r0 260 negc r2,r0
261 mov.b r0,@r3 261 mov.b r0,@r3
262 or #(LCD_SC),r0 262 or #(LCD_SC),r0
263 mov.b r0,@r3 263 mov.b r0,@r3
264 264
265 shll r1 265 shll r1
266 negc r2,r0 266 negc r2,r0
267 shll r1 267 shll r1
268 mov.b r0,@r3 268 mov.b r0,@r3
269 or #(LCD_SC),r0 269 or #(LCD_SC),r0
270 mov.b r0,@r3 270 mov.b r0,@r3
271 271
272 negc r2,r0 272 negc r2,r0
273 mov.b r0,@r3 273 mov.b r0,@r3
274 or #(LCD_SC),r0 274 or #(LCD_SC),r0
275 mov.b r0,@r3 275 mov.b r0,@r3
276 276
277 shll r1 277 shll r1
278 negc r2,r0 278 negc r2,r0
279 shll r1 279 shll r1
280 mov.b r0,@r3 280 mov.b r0,@r3
281 or #(LCD_SC),r0 281 or #(LCD_SC),r0
282 mov.b r0,@r3 282 mov.b r0,@r3
283 283
284 negc r2,r0 284 negc r2,r0
285 mov.b r0,@r3 285 mov.b r0,@r3
286 or #(LCD_SC),r0 286 or #(LCD_SC),r0
287 mov.b r0,@r3 287 mov.b r0,@r3
288 288
289#endif /* HAVE_LCD_CHARCELLS */ 289#endif /* HAVE_LCD_CHARCELLS */
290 290
@@ -293,7 +293,7 @@ _lcd_write_data:
293 bf .multi_transfer /* no: next iteration */ 293 bf .multi_transfer /* no: next iteration */
294 294
295 or #(LCD_CS|LCD_DS|LCD_SD|LCD_SC),r0 /* restore port */ 295 or #(LCD_CS|LCD_DS|LCD_SD|LCD_SC),r0 /* restore port */
296 rts 296 rts
297 mov.b r0,@r3 297 mov.b r0,@r3
298 298
299 /* This is the place to reenable the interrupts, if we have disabled 299 /* This is the place to reenable the interrupts, if we have disabled
@@ -305,70 +305,4 @@ _lcd_write_data:
305 305
306.end: 306.end:
307 .size _lcd_write_command,.end-_lcd_write_command 307 .size _lcd_write_command,.end-_lcd_write_command
308#elif defined(IRIVER_H100_SERIES)
309 .section .icode,"ax",@progbits
310
311 .align 2
312 .global lcd_write_command
313 .type lcd_write_command,@function
314
315lcd_write_command:
316 move.l (4,%sp),%d0
317 lea MBAR2,%a1
318 move.l #~8,%d1
319 and.l %d1,(0xb4,%a1)
320 move.w %d0,0xf0000000
321 rts
322
323 .align 2
324 .global lcd_write_command_ex
325 .type lcd_write_command_ex,@function
326
327lcd_write_command_ex:
328 lea MBAR2,%a1
329
330 move.l (4,%sp),%d0 /* Command */
331
332 move.l #~8,%d1 /* Set A0 = 0 */
333 and.l %d1,(0xb4,%a1)
334 move.w %d0,0xf0000000 /* Write to LCD */
335
336 not.l %d1 /* Set A0 = 1 */
337 or.l %d1,(0xb4,%a1)
338
339 move.l (8,%sp),%d0 /* Data */
340 cmp.l #0xffffffff,%d0 /* -1? */
341 beq.b .last
342 move.w %d0,0xf0000000 /* Write to LCD */
343
344 move.l (12,%sp),%d0 /* Data */
345 cmp.l #0xffffffff,%d0 /* -1? */
346 beq.b .last
347 move.w %d0,0xf0000000 /* Write to LCD */
348
349.last:
350 rts
351
352 .align 2
353 .global lcd_write_data
354 .type lcd_write_data,@function
355
356lcd_write_data:
357 move.l (4,%sp),%a0 /* Data pointer */
358 move.l (8,%sp),%d0 /* Length */
359 lea MBAR2,%a1
360 moveq #8,%d1
361 or.l %d1,(0xb4,%a1)
362
363 lea 0xf0000000,%a1
364.loop:
365 /* When running in IRAM, this loop takes 7 cycles plus the LCD write.
366 The 7 cycles are necessary to follow the LCD timing specs
367 at 140MHz */
368 move.b (%a0)+,%d1 /* 3(1/0) */
369 move.w %d1,(%a1) /* 1(0/1) */
370 subq.l #1,%d0 /* 1(0/0) */
371 nop /* 1(0/0) */
372 bne .loop /* 2(0/0) */
373 rts
374#endif 308#endif
diff --git a/firmware/drivers/power.c b/firmware/drivers/power.c
index af70ac8ef2..e48993c2aa 100644
--- a/firmware/drivers/power.c
+++ b/firmware/drivers/power.c
@@ -65,26 +65,6 @@ bool radio_power(bool status)
65 65
66void power_init(void) 66void power_init(void)
67{ 67{
68#if CONFIG_CPU == MCF5249
69#if defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES)
70 or_l(0x00080000, &GPIO1_OUT);
71 or_l(0x00080000, &GPIO1_ENABLE);
72 or_l(0x00080000, &GPIO1_FUNCTION);
73
74#ifndef BOOTLOADER
75 /* The boot loader controls the power */
76 ide_power_enable(true);
77#endif
78 or_l(0x80000000, &GPIO_ENABLE);
79 or_l(0x80000000, &GPIO_FUNCTION);
80#ifdef HAVE_SPDIF_POWER
81 spdif_power_enable(false);
82#endif
83#ifdef IRIVER_H300_SERIES
84 pcf50606_init();
85#endif
86#endif
87#else
88#ifdef HAVE_POWEROFF_ON_PB5 68#ifdef HAVE_POWEROFF_ON_PB5
89 PBCR2 &= ~0x0c00; /* GPIO for PB5 */ 69 PBCR2 &= ~0x0c00; /* GPIO for PB5 */
90 or_b(0x20, &PBIORL); 70 or_b(0x20, &PBIORL);
@@ -100,19 +80,14 @@ void power_init(void)
100 or_b(0x04, &PADRL); /* drive PA2 high for tuner disable */ 80 or_b(0x04, &PADRL); /* drive PA2 high for tuner disable */
101 or_b(0x04, &PAIORL); /* output for PA2 */ 81 or_b(0x04, &PAIORL); /* output for PA2 */
102#endif 82#endif
103#endif
104} 83}
105 84
106 85
107#ifdef CONFIG_CHARGING 86#ifdef CONFIG_CHARGING
108bool charger_inserted(void) 87bool charger_inserted(void)
109{ 88{
110#if defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES) 89#if defined(GMINI_ARCH)
111 return (GPIO1_READ & 0x00400000)?true:false;
112#elif defined(GMINI_ARCH)
113 return (P7 & 0x80) == 0; 90 return (P7 & 0x80) == 0;
114#elif defined(IAUDIO_X5)
115 return (GPIO1_READ & 0x01000000)?true:false;
116#elif CONFIG_CHARGING == CHARGING_CONTROL 91#elif CONFIG_CHARGING == CHARGING_CONTROL
117 /* Recorder */ 92 /* Recorder */
118 return adc_read(ADC_EXT_POWER) > 0x100; 93 return adc_read(ADC_EXT_POWER) > 0x100;
@@ -155,28 +130,7 @@ bool charging_state(void) {
155 charge. My tests show that ADC readings below about 0x80 means 130 charge. My tests show that ADC readings below about 0x80 means
156 that the LTC1734 is only maintaining the charge. */ 131 that the LTC1734 is only maintaining the charge. */
157 return adc_read(ADC_EXT_POWER) >= 0x80; 132 return adc_read(ADC_EXT_POWER) >= 0x80;
158#elif defined(IRIVER_H100_SERIES) /* FIXME */
159 return charger_inserted();
160#elif defined IRIVER_H300_SERIES
161 return (GPIO_READ & 0x00800000)?true:false;
162#endif
163}
164#endif
165
166#ifdef HAVE_SPDIF_POWER
167void spdif_power_enable(bool on)
168{
169 or_l(0x01000000, &GPIO1_FUNCTION);
170 or_l(0x01000000, &GPIO1_ENABLE);
171
172#ifdef SPDIF_POWER_INVERTED
173 if(!on)
174#else
175 if(on)
176#endif 133#endif
177 and_l(~0x01000000, &GPIO1_OUT);
178 else
179 or_l(0x01000000, &GPIO1_OUT);
180} 134}
181#endif 135#endif
182 136
@@ -185,14 +139,7 @@ void ide_power_enable(bool on)
185{ 139{
186 (void)on; 140 (void)on;
187 141
188#if defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES) 142#if defined(GMINI_ARCH)
189 if(on)
190 and_l(~0x80000000, &GPIO_OUT);
191 else
192 or_l(0x80000000, &GPIO_OUT);
193#elif defined(IAUDIO_X5)
194 /* X5 TODO */
195#elif defined(GMINI_ARCH)
196 if(on) 143 if(on)
197 P1 |= 0x08; 144 P1 |= 0x08;
198 else 145 else
@@ -244,11 +191,7 @@ void ide_power_enable(bool on)
244 191
245bool ide_powered(void) 192bool ide_powered(void)
246{ 193{
247#if defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES) 194#if defined(GMINI_ARCH)
248 return (GPIO_OUT & 0x80000000)?false:true;
249#elif defined(IAUDIO_X5)
250 return false; /* X5 TODO */
251#elif defined(GMINI_ARCH)
252 return (P1 & 0x08?true:false); 195 return (P1 & 0x08?true:false);
253#elif defined(TOSHIBA_GIGABEAT_F) 196#elif defined(TOSHIBA_GIGABEAT_F)
254 return false; 197 return false;
@@ -279,10 +222,7 @@ bool ide_powered(void)
279void power_off(void) 222void power_off(void)
280{ 223{
281 set_irq_level(HIGHEST_IRQ_LEVEL); 224 set_irq_level(HIGHEST_IRQ_LEVEL);
282#if defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES) 225#if CONFIG_CPU == PNX0101
283 and_l(~0x00080000, &GPIO1_OUT);
284 asm("halt");
285#elif CONFIG_CPU == PNX0101
286 GPIO1_CLR = 1 << 16; 226 GPIO1_CLR = 1 << 16;
287 GPIO2_SET = 1; 227 GPIO2_SET = 1;
288#elif defined(GMINI_ARCH) 228#elif defined(GMINI_ARCH)