1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2010 Marcin Bukat
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
29 /* TOMATO LSI 0350 - definitions and slightly tweaked functions
30 * taken from lcd-remote-iaudio.c
33 #define LCD_SET_DUTY_RATIO 0x48
34 #define LCD_SELECT_ADC 0xa0
35 #define LCD_SELECT_SHL 0xc0
36 #define LCD_SET_COM0 0x44
37 #define LCD_OSC_ON 0xab
38 #define LCD_SELECT_DCDC 0x64
39 #define LCD_SELECT_RES 0x20
40 #define LCD_SET_VOLUME 0x81
41 #define LCD_SET_BIAS 0x50
42 #define LCD_CONTROL_POWER 0x28
43 #define LCD_DISPLAY_ON 0xae
44 #define LCD_SET_INITLINE 0x40
45 #define LCD_SET_COLUMN 0x10
46 #define LCD_SET_PAGE 0xb0
47 #define LCD_SET_GRAY 0x88
48 #define LCD_SET_PWM_FRC 0x90
49 #define LCD_SET_POWER_SAVE 0xa8
50 #define LCD_REVERSE 0xa6
51 #define LCD_RESET 0xe2
54 static bool cached_invert
= false;
55 static bool cached_flip
= false;
56 static int cached_contrast
= DEFAULT_CONTRAST_SETTING
;
58 static struct mutex lcd_mtx
; /* The update functions use DMA and yield */
60 volatile unsigned char page IBSS_ATTR
;
61 unsigned char column IBSS_ATTR
;
62 unsigned int dma_len IBSS_ATTR
;
63 volatile unsigned long dma_count IBSS_ATTR
;
65 /*** hardware configuration ***/
66 int lcd_default_contrast(void)
68 return DEFAULT_CONTRAST_SETTING
;
71 void lcd_powersave(bool on
)
74 /* enter power saving mode
75 * this turns off lcd without controller reset
76 * probably ~1mA saving
78 lcd_write_command(LCD_SET_POWER_SAVE
| 1);
80 /* leave lcd power saving mode
81 * no need to reset and initialize controller
83 lcd_write_command(LCD_SET_POWER_SAVE
| 0);
86 void lcd_set_contrast(int val
)
88 if (val
< MIN_CONTRAST_SETTING
)
89 val
= MIN_CONTRAST_SETTING
;
90 else if (val
> MAX_CONTRAST_SETTING
)
91 val
= MAX_CONTRAST_SETTING
;
93 cached_contrast
= val
;
94 lcd_write_command_e(LCD_SET_VOLUME
, val
);
97 void lcd_set_invert_display(bool yesno
)
99 cached_invert
= yesno
;
100 lcd_write_command(LCD_REVERSE
| yesno
);
104 /* turn the display upside down (call lcd_update() afterwards) */
105 void lcd_set_flip(bool yesno
)
110 lcd_write_command(LCD_SELECT_ADC
| 1);
111 lcd_write_command(LCD_SELECT_SHL
| 0);
112 lcd_write_command_e(LCD_SET_COM0
, 0);
116 lcd_write_command(LCD_SELECT_ADC
| 0);
117 lcd_write_command(LCD_SELECT_SHL
| 8);
118 lcd_write_command_e(LCD_SET_COM0
, 0);
122 void lcd_shutdown(void)
124 /* Set power save -> Power OFF (VDD - VSS) .. that's it */
125 lcd_write_command(LCD_SET_POWER_SAVE
| 1);
128 void lcd_init_device(void)
130 and_l(~0x00000800, &GPIO_FUNCTION
); /* CS3 line */
132 /* LCD Reset GPO34 */
133 or_l(0x00000004, &GPIO1_ENABLE
); /* set as output */
134 or_l(0x00000004, &GPIO1_FUNCTION
); /* switch to secondary function - GPIO */
136 and_l(~0x00000004, &GPIO1_OUT
); /* RESET low */
137 sleep(1); /* delay at least 1000 ns */
138 or_l(0x00000004, &GPIO1_OUT
); /* RESET high */
141 /* parameters setup taken from original firmware */
142 lcd_write_command(LCD_RESET
);
143 lcd_write_command_e(LCD_SET_DUTY_RATIO
,0x80); /* 1/128 */
144 lcd_write_command(LCD_OSC_ON
);
145 lcd_write_command(LCD_SELECT_DCDC
| 3); /* DC/DC 6xboost */
146 lcd_write_command(LCD_SELECT_RES
| 7); /* Regulator resistor: 7.2 */
147 lcd_write_command(LCD_SET_BIAS
| 6); /* 1/11 */
148 lcd_write_command(LCD_SET_PWM_FRC
| 6); /* 3FRC + 12PWM */
149 lcd_write_command_e(LCD_SET_GRAY
| 0, 0x00);
150 lcd_write_command_e(LCD_SET_GRAY
| 1, 0x00);
151 lcd_write_command_e(LCD_SET_GRAY
| 2, 0x0c);
152 lcd_write_command_e(LCD_SET_GRAY
| 3, 0x00);
153 lcd_write_command_e(LCD_SET_GRAY
| 4, 0xc4);
154 lcd_write_command_e(LCD_SET_GRAY
| 5, 0x00);
155 lcd_write_command_e(LCD_SET_GRAY
| 6, 0xcc);
156 lcd_write_command_e(LCD_SET_GRAY
| 7, 0x00);
158 lcd_write_command(LCD_CONTROL_POWER
| 7); /* All circuits ON */
159 lcd_write_command(LCD_DISPLAY_ON
| 1); /* display on */
161 lcd_set_flip(cached_flip
);
162 lcd_set_contrast(cached_contrast
);
163 lcd_set_invert_display(cached_invert
);
168 DIVR3
= 57; /* DMA3 is mapped into vector 57 in system.c */
169 ICR9
= (6 << 2); /* Enable DMA3 interrupt at level 6, priority 0 */
170 and_l(~(1<<17), &IMR
);
172 mutex_init(&lcd_mtx
);
178 void DMA3(void) __attribute__ ((interrupt_handler
, section(".icode")));
185 /* Setup write address in lcd controller ram*/
186 lcd_write_command(LCD_SET_PAGE
| ++page
);
187 lcd_write_command_e(LCD_SET_COLUMN
| ((column
>> 4) & 0xf),
190 SAR3
= (unsigned long)&lcd_framebuffer
[page
][column
];
192 DCR3
= DMA_INT
| DMA_AA
| DMA_BWC(1)
193 | DMA_SINC
| DMA_SSIZE(DMA_SIZE_LINE
)
194 | DMA_DSIZE(DMA_SIZE_BYTE
) | DMA_START
;
199 /* Update the display.
200 This must be called after all other LCD functions that change the display. */
201 void lcd_update(void) ICODE_ATTR
;
202 void lcd_update(void)
204 mutex_lock(&lcd_mtx
);
206 /* Setup initial address in lcd controller */
207 lcd_write_command(LCD_SET_PAGE
| 0);
208 lcd_write_command_e(LCD_SET_COLUMN
, 0);
210 /* Initial lcd ram address */
214 /* Number of pages to address */
215 dma_count
= LCD_FBHEIGHT
;
217 /* Transfer size in bytes to the given page */
218 dma_len
= LCD_WIDTH
*2;
220 /* Initialize DMA transfer */
221 SAR3
= (unsigned long)lcd_framebuffer
;
223 DCR3
= DMA_INT
| DMA_AA
| DMA_BWC(1)
224 | DMA_SINC
| DMA_SSIZE(DMA_SIZE_LINE
)
225 | DMA_DSIZE(DMA_SIZE_BYTE
) | DMA_START
;
227 while (dma_count
> 0)
230 mutex_unlock(&lcd_mtx
);
233 /* Update a fraction of the display. */
234 void lcd_update_rect(int, int, int, int) ICODE_ATTR
;
235 void lcd_update_rect(int x
, int y
, int width
, int height
)
239 /* The Y coordinates have to work on even 8 pixel rows */
240 ymax
= (y
+ height
-1) >> 3;
243 if (x
+ width
> LCD_WIDTH
)
244 width
= LCD_WIDTH
- x
;
247 return; /* nothing left to do, 0 is harmful to lcd_write_data() */
249 mutex_lock(&lcd_mtx
);
251 if (ymax
>= LCD_FBHEIGHT
)
252 ymax
= LCD_FBHEIGHT
-1;
254 /* Initial lcd ram address*/
255 lcd_write_command(LCD_SET_PAGE
| y
);
256 lcd_write_command_e(LCD_SET_COLUMN
| ((x
>> 4) & 0xf), x
& 0x0f);
261 dma_count
= ymax
- y
+ 1;
263 /* Initialize DMA transfer */
264 SAR3
= (unsigned long)&lcd_framebuffer
[page
][column
];
266 DCR3
= DMA_INT
| DMA_AA
| DMA_BWC(1)
267 | DMA_SINC
| DMA_SSIZE(DMA_SIZE_LINE
)
268 | DMA_DSIZE(DMA_SIZE_BYTE
) | DMA_START
;
270 while (dma_count
> 0)
273 mutex_unlock(&lcd_mtx
);
277 /* Helper function. */
278 void lcd_mono_data(const unsigned char *data
, int count
);
280 /* Performance function that works with an external buffer
281 note that by and bheight are in 8-pixel units! */
282 void lcd_blit_mono(const unsigned char *data
, int x
, int by
, int width
,
283 int bheight
, int stride
)
287 lcd_write_command(LCD_SET_PAGE
| (by
& 0xf));
288 lcd_write_command_e(LCD_SET_COLUMN
| ((x
>> 4) & 0xf), x
& 0xf);
290 lcd_mono_data(data
, width
);
296 /* Helper function for lcd_grey_phase_blit(). */
297 void lcd_grey_data(unsigned char *values
, unsigned char *phases
, int count
);
299 /* Performance function that works with an external buffer
300 note that by and bheight are in 8-pixel units! */
301 void lcd_blit_grey_phase(unsigned char *values
, unsigned char *phases
,
302 int x
, int by
, int width
, int bheight
, int stride
)
304 stride
<<= 3; /* 8 pixels per block */
308 lcd_write_command(LCD_SET_PAGE
| (by
& 0xf));
309 lcd_write_command_e(LCD_SET_COLUMN
| ((x
>> 4) & 0xf), x
& 0xf);
311 lcd_grey_data(values
, phases
, width
);