summaryrefslogtreecommitdiff
path: root/firmware/target/mips/ingenic_jz47xx/xduoo_x3/lcd-xduoo_x3.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/mips/ingenic_jz47xx/xduoo_x3/lcd-xduoo_x3.c')
-rw-r--r--firmware/target/mips/ingenic_jz47xx/xduoo_x3/lcd-xduoo_x3.c420
1 files changed, 420 insertions, 0 deletions
diff --git a/firmware/target/mips/ingenic_jz47xx/xduoo_x3/lcd-xduoo_x3.c b/firmware/target/mips/ingenic_jz47xx/xduoo_x3/lcd-xduoo_x3.c
new file mode 100644
index 0000000000..89251b727d
--- /dev/null
+++ b/firmware/target/mips/ingenic_jz47xx/xduoo_x3/lcd-xduoo_x3.c
@@ -0,0 +1,420 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2016 by Roman Stolyarov
11 *
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.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "config.h"
22
23#include "lcd.h"
24#include "system.h"
25#include "cpu.h"
26#include "string.h"
27
28/* LCD pins */
29#define PIN_BL_EN (32*4+0)
30
31#define PIN_LCD_D0 (32*2+2)
32#define PIN_LCD_D1 (32*2+3)
33#define PIN_LCD_D2 (32*2+4)
34#define PIN_LCD_D3 (32*2+5)
35#define PIN_LCD_D4 (32*2+6)
36#define PIN_LCD_D5 (32*2+7)
37#define PIN_LCD_D6 (32*2+12)
38#define PIN_LCD_D7 (32*2+13)
39
40#define PIN_LCD_RD (32*2+8)
41#define PIN_LCD_DC (32*2+9)
42#define PIN_LCD_CS (32*2+14)
43#define PIN_LCD_RES (32*2+18)
44#define PIN_LCD_WR (32*2+19)
45
46/* LCD setup codes */
47#define LCD_SET_LOWER_COLUMN_ADDRESS ((char)0x00)
48#define LCD_SET_HIGHER_COLUMN_ADDRESS ((char)0x10)
49#define LCD_SET_DISPLAY_START_LINE ((char)0x40)
50#define LCD_SET_CONTRAST_CONTROL_REGISTER ((char)0x81)
51#define LCD_SET_CHARGE_PUMP ((char)0x8D)
52#define LCD_SET_SEGMENT_REMAP ((char)0xA0)
53#define LCD_SET_SEGMENT_REMAP_INV ((char)0xA1)
54#define LCD_SET_ENTIRE_DISPLAY_OFF ((char)0xA4)
55#define LCD_SET_ENTIRE_DISPLAY_ON ((char)0xA5)
56#define LCD_SET_NORMAL_DISPLAY ((char)0xA6)
57#define LCD_SET_REVERSE_DISPLAY ((char)0xA7)
58#define LCD_SET_MULTIPLEX_RATIO ((char)0xA8)
59#define LCD_SET_DC_DC ((char)0xAD)
60#define LCD_SET_DISPLAY_OFF ((char)0xAE)
61#define LCD_SET_DISPLAY_ON ((char)0xAF)
62#define LCD_SET_PAGE_ADDRESS ((char)0xB0)
63#define LCD_SET_COM_OUTPUT_SCAN_DIRECTION ((char)0xC0)
64#define LCD_SET_COM_OUTPUT_SCAN_DIRECTION_INV ((char)0xC8)
65#define LCD_SET_DISPLAY_OFFSET ((char)0xD3)
66#define LCD_SET_DISPLAY_CLOCK_AND_OSC_FREQ ((char)0xD5)
67#define LCD_SET_VCOM_HW_CONFIGURATION ((char)0xDA)
68#define LCD_SET_VCOM_DESELECT_LEVEL ((char)0xDB)
69#define LCD_SET_PRECHARGE_PERIOD ((char)0xD9)
70#define LCD_NOP ((char)0xE3)
71
72/* LCD command codes */
73#define LCD_CNTL_CONTRAST 0x81 /* Contrast */
74#define LCD_CNTL_OUTSCAN 0xc8 /* Output scan direction */
75#define LCD_CNTL_SEGREMAP 0xa1 /* Segment remap */
76#define LCD_CNTL_DISPON 0xaf /* Display on */
77
78#define LCD_CNTL_PAGE 0xb0 /* Page address */
79#define LCD_CNTL_HIGHCOL 0x10 /* Upper column address */
80#define LCD_CNTL_LOWCOL 0x00 /* Lower column address */
81
82#define LCD_COL_OFFSET 2 /* column offset */
83
84static inline void bitdelay(void)
85{
86 unsigned int i = 15;
87 __asm__ __volatile__ (
88 ".set noreorder \n"
89 "1: \n"
90 "bne %0, $0, 1b \n"
91 "addi %0, %0, -1 \n"
92 ".set reorder \n"
93 : "=r" (i)
94 : "0" (i)
95 );
96}
97
98void lcd_hw_init(void)
99{
100 REG_GPIO_PXFUNC(2) = 0x000C73FC; /* D0-D7 RD DC CS RES WR */
101 REG_GPIO_PXSELC(2) = 0x000C73FC;
102 REG_GPIO_PXDIRS(2) = 0x000C73FC;
103 REG_GPIO_PXDATS(2) = 0x000C73FC;
104 __gpio_clear_pin(PIN_BL_EN);
105 __gpio_as_output(PIN_BL_EN);
106 __gpio_clear_pin(PIN_LCD_RES);
107 udelay(1);
108 __gpio_set_pin(PIN_LCD_RES);
109 __gpio_clear_pin(PIN_LCD_CS);
110}
111
112void lcd_write_command(int byte)
113{
114 __gpio_clear_pin(PIN_LCD_DC);
115 REG_GPIO_PXDATC(2) = 0x000030FC;
116 REG_GPIO_PXDATS(2) = ((byte & 0xC0) << 6) | ((byte & 0x3F) << 2);
117 __gpio_clear_pin(PIN_LCD_WR);
118 bitdelay();
119 __gpio_set_pin(PIN_LCD_WR);
120 bitdelay();
121}
122
123void lcd_write_data(const fb_data* p_bytes, int count)
124{
125 __gpio_set_pin(PIN_LCD_DC);
126 while (count--)
127 {
128 REG_GPIO_PXDATC(2) = 0x000030FC;
129 REG_GPIO_PXDATS(2) = ((*p_bytes & 0xC0) << 6) | ((*p_bytes & 0x3F) << 2);
130 p_bytes++;
131 __gpio_clear_pin(PIN_LCD_WR);
132 bitdelay();
133 __gpio_set_pin(PIN_LCD_WR);
134 bitdelay();
135 }
136}
137
138void lcd_enable_power(bool onoff)
139{
140 if (onoff)
141 __gpio_set_pin(PIN_BL_EN);
142 else
143 __gpio_clear_pin(PIN_BL_EN);
144}
145
146/** globals **/
147
148static bool display_on = false; /* used by lcd_enable */
149
150/*** hardware configuration ***/
151
152void lcd_set_contrast(int val)
153{
154 lcd_write_command(LCD_CNTL_CONTRAST);
155 lcd_write_command(val);
156}
157
158void lcd_set_invert_display(bool yesno)
159{
160 if (yesno)
161 lcd_write_command(LCD_SET_REVERSE_DISPLAY);
162 else
163 lcd_write_command(LCD_SET_NORMAL_DISPLAY);
164}
165
166/* turn the display upside down (call lcd_update() afterwards) */
167void lcd_set_flip(bool yesno)
168{
169 if (yesno)
170 {
171 lcd_write_command(LCD_SET_SEGMENT_REMAP);
172 lcd_write_command(LCD_SET_COM_OUTPUT_SCAN_DIRECTION);
173 }
174 else
175 {
176 lcd_write_command(LCD_SET_SEGMENT_REMAP_INV);
177 lcd_write_command(LCD_SET_COM_OUTPUT_SCAN_DIRECTION_INV);
178 }
179}
180
181#ifdef HAVE_LCD_ENABLE
182void lcd_enable(bool enable)
183{
184 if(display_on == enable)
185 return;
186
187 if( (display_on = enable) ) /* simple '=' is not a typo ! */
188 {
189 lcd_enable_power(enable);
190 lcd_write_command(LCD_SET_DISPLAY_ON);
191 send_event(LCD_EVENT_ACTIVATION, NULL);
192 }
193 else
194 {
195 lcd_write_command(LCD_SET_DISPLAY_OFF);
196 lcd_enable_power(enable);
197 }
198}
199
200bool lcd_active(void)
201{
202 return display_on;
203}
204#endif
205
206/* LCD init, largely based on what OF does */
207void lcd_init_device(void)
208{
209 int i;
210
211 lcd_hw_init();
212
213 /* Set display off */
214 lcd_write_command(LCD_SET_DISPLAY_OFF);
215
216 /* Set display clock and oscillator frequency */
217 lcd_write_command(LCD_SET_DISPLAY_CLOCK_AND_OSC_FREQ);
218 lcd_write_command(0x80);
219
220 /* Set multiplex ratio*/
221 lcd_write_command(LCD_SET_MULTIPLEX_RATIO);
222 lcd_write_command(0x3F);
223
224 /* Set display offset */
225 lcd_write_command(LCD_SET_DISPLAY_OFFSET);
226 lcd_write_command(0x00);
227
228 /* Set starting line as 0 */
229 lcd_write_command(LCD_SET_DISPLAY_START_LINE);
230
231 /* Set charge pump */
232 lcd_write_command(LCD_SET_CHARGE_PUMP);
233 lcd_write_command(0x14); /* VCC Generated by Internal DC/DC Circuit */
234
235 /* Column 131 is remapped to SEG0 */
236 lcd_write_command(LCD_SET_SEGMENT_REMAP_INV);
237
238 /* Invert COM scan direction (N-1 to 0) */
239 lcd_write_command(LCD_SET_COM_OUTPUT_SCAN_DIRECTION_INV);
240
241 /* Set COM hardware configuration */
242 lcd_write_command(LCD_SET_VCOM_HW_CONFIGURATION);
243 lcd_write_command(0x12);
244
245 /* Set contrast control */
246 lcd_write_command(LCD_SET_CONTRAST_CONTROL_REGISTER);
247 lcd_write_command(0xCF); /* VCC Generated by Internal DC/DC Circuit */
248
249 /* Set pre-charge period */
250 lcd_write_command(LCD_SET_PRECHARGE_PERIOD);
251 lcd_write_command(0xF1); /* VCC Generated by Internal DC/DC Circuit */
252
253 /* Set VCOM deselect level */
254 lcd_write_command(LCD_SET_VCOM_DESELECT_LEVEL);
255 lcd_write_command(0x40);
256
257 /* Set normal display mode (not every pixel ON) */
258 lcd_write_command(LCD_SET_ENTIRE_DISPLAY_OFF);
259
260 /* Set normal display mode (not inverted) */
261 lcd_write_command(LCD_SET_NORMAL_DISPLAY);
262
263 fb_data p_bytes[LCD_WIDTH + 2 * LCD_COL_OFFSET];
264 memset(p_bytes, 0, sizeof(p_bytes)); /* fills with 0 : pixel off */
265 for(i = 0; i < 8; i++)
266 {
267 lcd_write_command (LCD_SET_PAGE_ADDRESS | (i /*& 0xf*/));
268 lcd_write_data(p_bytes, LCD_WIDTH + 2 * LCD_COL_OFFSET);
269 }
270
271 lcd_enable(true);
272
273 lcd_update();
274}
275
276/*** Update functions ***/
277
278/* Performance function that works with an external buffer
279 note that by and bheight are in 8-pixel units! */
280void lcd_blit_mono(const unsigned char *data, int x, int by, int width,
281 int bheight, int stride)
282{
283 if(!display_on)
284 return;
285
286 /* Copy display bitmap to hardware */
287 while (bheight--)
288 {
289 lcd_write_command (LCD_CNTL_PAGE | (by++ & 0xf));
290 lcd_write_command (LCD_CNTL_HIGHCOL | (((x+LCD_COL_OFFSET)>>4) & 0xf));
291 lcd_write_command (LCD_CNTL_LOWCOL | ((x+LCD_COL_OFFSET) & 0xf));
292
293 lcd_write_data(data, width);
294 data += stride;
295 }
296}
297
298
299#ifndef BOOTLOADER
300/* Helper function for lcd_grey_phase_blit(). */
301void lcd_grey_data(unsigned char *values, unsigned char *phases, int count) ICODE_ATTR;
302void lcd_grey_data(unsigned char *values, unsigned char *phases, int count)
303{
304 unsigned char a, b, c, d;
305
306 __gpio_set_pin(PIN_LCD_DC);
307 while(count--)
308 {
309 c = 0;
310 d = 8;
311 while(d--)
312 {
313 a = *phases;
314 b = *values++;
315 b += a & ~0x80;
316 *phases++ = b;
317 c <<= 1;
318 c |= a >> 7;
319 }
320 REG_GPIO_PXDATC(2) = 0x000030FC;
321 REG_GPIO_PXDATS(2) = ((c & 0xC0) << 6) | ((c & 0x3F) << 2);
322 __gpio_clear_pin(PIN_LCD_WR);
323 bitdelay();
324 __gpio_set_pin(PIN_LCD_WR);
325 bitdelay();
326 }
327}
328
329/* Performance function that works with an external buffer
330 note that by and bheight are in 8-pixel units! */
331void lcd_blit_grey_phase(unsigned char *values, unsigned char *phases,
332 int x, int by, int width, int bheight, int stride)
333{
334 if(!display_on)
335 return;
336
337 stride <<= 3; /* 8 pixels per block */
338 /* Copy display bitmap to hardware */
339 while (bheight--)
340 {
341 lcd_write_command (LCD_CNTL_PAGE | (by++ & 0xf));
342 lcd_write_command (LCD_CNTL_HIGHCOL | (((x+LCD_COL_OFFSET)>>4) & 0xf));
343 lcd_write_command (LCD_CNTL_LOWCOL | ((x+LCD_COL_OFFSET) & 0xf));
344
345 lcd_grey_data(values, phases, width);
346
347 values += stride;
348 phases += stride;
349 }
350}
351#endif
352
353/* Update the display.
354 This must be called after all other LCD functions that change the display. */
355void lcd_update(void) ICODE_ATTR;
356void lcd_update(void)
357{
358 int y;
359
360 if(!display_on)
361 return;
362
363 /* Copy display bitmap to hardware */
364 for (y = 0; y < LCD_FBHEIGHT; y++)
365 {
366 lcd_write_command (LCD_CNTL_PAGE | (y & 0xf));
367 lcd_write_command (LCD_CNTL_HIGHCOL | ((LCD_COL_OFFSET >> 4) & 0xf));
368 lcd_write_command (LCD_CNTL_LOWCOL | (LCD_COL_OFFSET & 0xf));
369
370 lcd_write_data (FBADDR(0, y), LCD_WIDTH);
371 }
372}
373
374/* Update a fraction of the display. */
375void lcd_update_rect(int, int, int, int) ICODE_ATTR;
376void lcd_update_rect(int x, int y, int width, int height)
377{
378 int ymax;
379
380 if(!display_on)
381 return;
382
383 /* The Y coordinates have to work on even 8 pixel rows */
384 if (x < 0)
385 {
386 width += x;
387 x = 0;
388 }
389
390 if (x + width > LCD_WIDTH)
391 width = LCD_WIDTH - x;
392
393 if (width <= 0)
394 return; /* nothing left to do, 0 is harmful to lcd_write_data() */
395
396 if (y < 0)
397 {
398 height += y;
399 y = 0;
400 }
401
402 if (y + height > LCD_HEIGHT)
403 height = LCD_HEIGHT - y;
404
405 if (height <= 0)
406 return; /* nothing left to do */
407
408 ymax = (y + height-1) >> 3;
409 y >>= 3;
410
411 /* Copy specified rectange bitmap to hardware */
412 for (; y <= ymax; y++)
413 {
414 lcd_write_command (LCD_CNTL_PAGE | (y & 0xf));
415 lcd_write_command (LCD_CNTL_HIGHCOL | (((x+LCD_COL_OFFSET) >> 4) & 0xf));
416 lcd_write_command (LCD_CNTL_LOWCOL | ((x+LCD_COL_OFFSET) & 0xf));
417
418 lcd_write_data (FBADDR(x,y), width);
419 }
420}