summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Ryabinin <ryabinin.a.a@gmail.com>2012-09-25 11:41:12 +0400
committerMarcin Bukat <marcin.bukat@gmail.com>2012-09-27 09:42:44 +0200
commit84134f737fc4643cad5eb50fef3bae0df657f054 (patch)
treeb2b0b28a4723a2eef9a340f6bc7a18e796ab1b5b
parentf636aa07dfb541b5828d44e8168e7b36e5ad8898 (diff)
downloadrockbox-84134f737fc4643cad5eb50fef3bae0df657f054.tar.gz
rockbox-84134f737fc4643cad5eb50fef3bae0df657f054.zip
rk27xx lcd code rework
Use DMA engine for fullscreen updates and bypass mode for partial updates. This gives major boost on rk27generic: default ARM:AHB:APB 200:100:50 HEAD 1/1: 26.3fps 1/4: 105.0fps patched 1/1: 116.5fps 1/4: 249.5fps with freq scalling NORMAL mode ARM:AHB:APB 50:50:50 HEAD 1/1: 13.1fps 1/4: 52.5fps patched 1/1: 54.5fps 1/4: 119.0fps Tested on rk27generic noname DAP and on Hifimans. Change-Id: Id9dd4d2d61542c7ea6b5c6336b170d6357cefde9
-rw-r--r--firmware/export/rk27xx.h20
-rw-r--r--firmware/target/arm/rk27xx/hm60x/lcd-target.h27
-rw-r--r--firmware/target/arm/rk27xx/hm801/lcd-target.h27
-rw-r--r--firmware/target/arm/rk27xx/lcd-hifiman.c89
-rw-r--r--firmware/target/arm/rk27xx/lcdif-rk27xx.c252
-rw-r--r--firmware/target/arm/rk27xx/lcdif-rk27xx.h7
-rw-r--r--firmware/target/arm/rk27xx/rk27generic/lcd-rk27generic.c41
-rw-r--r--firmware/target/arm/rk27xx/rk27generic/lcd-target.h26
8 files changed, 352 insertions, 137 deletions
diff --git a/firmware/export/rk27xx.h b/firmware/export/rk27xx.h
index d1b9758f65..c75004c5f7 100644
--- a/firmware/export/rk27xx.h
+++ b/firmware/export/rk27xx.h
@@ -846,10 +846,10 @@
846#define VERT_PERIOD (*(volatile unsigned long *)(AHB1_LCDC + 0x0C)) 846#define VERT_PERIOD (*(volatile unsigned long *)(AHB1_LCDC + 0x0C))
847#define HOR_PW (*(volatile unsigned long *)(AHB1_LCDC + 0x10)) 847#define HOR_PW (*(volatile unsigned long *)(AHB1_LCDC + 0x10))
848#define VERT_PW (*(volatile unsigned long *)(AHB1_LCDC + 0x14)) 848#define VERT_PW (*(volatile unsigned long *)(AHB1_LCDC + 0x14))
849#define HOR_ACT (*(volatile unsigned long *)(AHB1_LCDC + 0x18)) 849#define HOR_BP (*(volatile unsigned long *)(AHB1_LCDC + 0x18))
850#define VERT_ACT (*(volatile unsigned long *)(AHB1_LCDC + 0x1C)) 850#define VERT_BP (*(volatile unsigned long *)(AHB1_LCDC + 0x1C))
851#define HOR_BP (*(volatile unsigned long *)(AHB1_LCDC + 0x20)) 851#define HOR_ACT (*(volatile unsigned long *)(AHB1_LCDC + 0x20))
852#define VERT_BP (*(volatile unsigned long *)(AHB1_LCDC + 0x24)) 852#define VERT_ACT (*(volatile unsigned long *)(AHB1_LCDC + 0x24))
853#define LINE0_YADDR (*(volatile unsigned long *)(AHB1_LCDC + 0x28)) 853#define LINE0_YADDR (*(volatile unsigned long *)(AHB1_LCDC + 0x28))
854#define LINE_ALPHA_EN (1<<14) 854#define LINE_ALPHA_EN (1<<14)
855#define LINE_SCALE_EN (1<<13) 855#define LINE_SCALE_EN (1<<13)
@@ -877,13 +877,23 @@
877#define INTR_MASK_VERT (1<<1) 877#define INTR_MASK_VERT (1<<1)
878#define INTR_MASK_HOR (1<<0) 878#define INTR_MASK_HOR (1<<0)
879 879
880#define ALPHA_ALX (*(volatile unsigned long *)(AHB1_LCDC + 0x5C))
881#define ALPHA_ATY (*(volatile unsigned long *)(AHB1_LCDC + 0x60))
882#define ALPHA_ARX (*(volatile unsigned long *)(AHB1_LCDC + 0x64))
883#define ALPHA_ABY (*(volatile unsigned long *)(AHB1_LCDC + 0x68))
884
885#define ALPHA_BLX (*(volatile unsigned long *)(AHB1_LCDC + 0x6C))
886#define ALPHA_BTY (*(volatile unsigned long *)(AHB1_LCDC + 0x70))
887#define ALPHA_BRX (*(volatile unsigned long *)(AHB1_LCDC + 0x74))
888#define ALPHA_BBY (*(volatile unsigned long *)(AHB1_LCDC + 0x78))
889
880#define LCDC_STA (*(volatile unsigned long *)(AHB1_LCDC + 0x7C)) 890#define LCDC_STA (*(volatile unsigned long *)(AHB1_LCDC + 0x7C))
881#define LCDC_MCU_IDLE (1<<12) 891#define LCDC_MCU_IDLE (1<<12)
882 892
883#define LCD_COMMAND (*(volatile unsigned long *)(AHB1_LCDC + 0x1000)) 893#define LCD_COMMAND (*(volatile unsigned long *)(AHB1_LCDC + 0x1000))
884#define LCD_DATA (*(volatile unsigned long *)(AHB1_LCDC + 0x1004)) 894#define LCD_DATA (*(volatile unsigned long *)(AHB1_LCDC + 0x1004))
885 895
886#define LCD_BUFF (*(volatile unsigned long *)(AHB1_LCDC + 0x2000)) 896#define LCD_BUFF ((volatile void *)(AHB1_LCDC + 0x2000))
887/* High speed ADC interface */ 897/* High speed ADC interface */
888#define AHB1_HS_ADC 0x186EC000 898#define AHB1_HS_ADC 0x186EC000
889#define HSADC_DATA (*(volatile unsigned long *)(AHB1_HS_ADC + 0x00)) 899#define HSADC_DATA (*(volatile unsigned long *)(AHB1_HS_ADC + 0x00))
diff --git a/firmware/target/arm/rk27xx/hm60x/lcd-target.h b/firmware/target/arm/rk27xx/hm60x/lcd-target.h
new file mode 100644
index 0000000000..7c2f194e4c
--- /dev/null
+++ b/firmware/target/arm/rk27xx/hm60x/lcd-target.h
@@ -0,0 +1,27 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2012 Andrew Ryabinin
11 *
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22#ifndef LCD_TARGET_H
23#define LCD_TARGET_H
24
25#define LCD_DATABUS_WIDTH LCDIF_16BIT
26
27#endif
diff --git a/firmware/target/arm/rk27xx/hm801/lcd-target.h b/firmware/target/arm/rk27xx/hm801/lcd-target.h
new file mode 100644
index 0000000000..7c2f194e4c
--- /dev/null
+++ b/firmware/target/arm/rk27xx/hm801/lcd-target.h
@@ -0,0 +1,27 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2012 Andrew Ryabinin
11 *
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22#ifndef LCD_TARGET_H
23#define LCD_TARGET_H
24
25#define LCD_DATABUS_WIDTH LCDIF_16BIT
26
27#endif
diff --git a/firmware/target/arm/rk27xx/lcd-hifiman.c b/firmware/target/arm/rk27xx/lcd-hifiman.c
index aaf181690e..4ab04f7653 100644
--- a/firmware/target/arm/rk27xx/lcd-hifiman.c
+++ b/firmware/target/arm/rk27xx/lcd-hifiman.c
@@ -20,6 +20,7 @@
20 * 20 *
21 ****************************************************************************/ 21 ****************************************************************************/
22 22
23
23#include "config.h" 24#include "config.h"
24#include "kernel.h" 25#include "kernel.h"
25#include "lcd.h" 26#include "lcd.h"
@@ -29,7 +30,7 @@
29 30
30static bool display_on = false; 31static bool display_on = false;
31 32
32static void lcd_v1_display_init(void) 33void lcd_v1_display_init(void)
33{ 34{
34 unsigned int x, y; 35 unsigned int x, y;
35 36
@@ -84,7 +85,7 @@ static void lcd_v1_display_init(void)
84 udelay(40); 85 udelay(40);
85 86
86 /* Memmory access setting */ 87 /* Memmory access setting */
87 lcd_write_reg(0x16, 0x48); 88 lcd_write_reg(0x16, 0x68);
88 /* Setup 16bit mode */ 89 /* Setup 16bit mode */
89 lcd_write_reg(0x17, 0x05); 90 lcd_write_reg(0x17, 0x05);
90 91
@@ -92,11 +93,11 @@ static void lcd_v1_display_init(void)
92 lcd_write_reg(0x02, 0x00); 93 lcd_write_reg(0x02, 0x00);
93 lcd_write_reg(0x03, 0x00); 94 lcd_write_reg(0x03, 0x00);
94 lcd_write_reg(0x04, 0x00); 95 lcd_write_reg(0x04, 0x00);
95 lcd_write_reg(0x05, LCD_HEIGHT - 1); 96 lcd_write_reg(0x05, LCD_WIDTH - 1);
96 lcd_write_reg(0x06, 0x00); 97 lcd_write_reg(0x06, 0x00);
97 lcd_write_reg(0x07, 0x00); 98 lcd_write_reg(0x07, 0x00);
98 lcd_write_reg(0x08, 0x00); 99 lcd_write_reg(0x08, 0x00);
99 lcd_write_reg(0x09, LCD_WIDTH - 1); 100 lcd_write_reg(0x09, LCD_HEIGHT - 1);
100 101
101 /* Start GRAM write */ 102 /* Start GRAM write */
102 lcd_cmd(0x22); 103 lcd_cmd(0x22);
@@ -110,6 +111,9 @@ static void lcd_v1_display_init(void)
110 111
111static void lcd_v1_enable (bool on) 112static void lcd_v1_enable (bool on)
112{ 113{
114 lcdctrl_bypass(1);
115 LCDC_CTRL |= RGB24B;
116
113 if (on) 117 if (on)
114 { 118 {
115 lcd_write_reg(0x18, 0x44); 119 lcd_write_reg(0x18, 0x44);
@@ -139,23 +143,33 @@ static void lcd_v1_enable (bool on)
139 lcd_write_reg(0x21, 0x00); 143 lcd_write_reg(0x21, 0x00);
140 } 144 }
141 display_on = on; 145 display_on = on;
146
147 LCDC_CTRL &= ~RGB24B;
148}
149static void lcd_v1_set_gram_area(int x, int y, int width, int height)
150{
151 lcdctrl_bypass(1);
152 LCDC_CTRL |= RGB24B;
153
154 lcd_write_reg(0x03, x);
155 lcd_write_reg(0x05, width-1);
156 lcd_write_reg(0x07, y);
157 lcd_write_reg(0x09, height-1);
158
159 lcd_cmd(0x22);
160 LCDC_CTRL &= ~RGB24B;
142} 161}
143 162
144static void lcd_v1_update_rect(int x, int y, int width, int height) 163static void lcd_v1_update_rect(int x, int y, int width, int height)
145{ 164{
146 int px = x, py = y; 165 int px = x, py = y;
147 int pxmax = x + width, pymax = y + height; 166 int pxmax = x + width, pymax = y + height;
148 167
149 lcd_write_reg(0x03, y); 168 lcd_v1_set_gram_area(x, y, pxmax, pymax);
150 lcd_write_reg(0x05, pymax-1); 169
151 lcd_write_reg(0x07, x); 170 for (py=y; py<pymax; py++)
152 lcd_write_reg(0x09, pxmax-1); 171 for (px=x; px<pxmax; px++)
153 172 LCD_DATA = (*FBADDR(px, py));
154 lcd_cmd(0x22);
155
156 for (px=x; px<pxmax; px++)
157 for (py=y; py<pymax; py++)
158 lcd_data(*FBADDR(px, py));
159} 173}
160 174
161 175
@@ -246,31 +260,34 @@ static void lcd_v2_enable (bool on)
246 display_on = on; 260 display_on = on;
247} 261}
248 262
249static void lcd_v2_update_rect(int x, int y, int width, int height) 263static void lcd_v2_set_gram_area(int x, int y, int width, int height)
250{ 264{
251 int px, py;
252 (void) x; 265 (void) x;
253 (void) y; 266 (void) y;
254 (void) width; 267 (void) width;
255 (void)height; 268 (void) height;
256 269 lcdctrl_bypass(1);
270 LCDC_CTRL |= RGB24B;
257 lcd_cmd(0x22); 271 lcd_cmd(0x22);
258 272 LCDC_CTRL &= ~RGB24B;
259 for (py=0; py<LCD_HEIGHT; py++)
260 for (px=0; px<LCD_WIDTH; px++)
261 lcd_data(*FBADDR(px, py));
262} 273}
263 274
264void lcd_init_device(void) 275static void lcd_v2_update_rect(int x, int y, int width, int height)
265{ 276{
266 lcdif_init(LCDIF_16BIT); 277 (void) x;
278 (void) y;
279 (void) width;
280 (void) height;
281 lcd_update();
282}
267 283
284void lcd_display_init(void)
285{
268 identify_lcd(); 286 identify_lcd();
269 if (lcd_type == LCD_V1) 287 if (lcd_type == LCD_V1)
270 lcd_v1_display_init(); 288 lcd_v1_display_init();
271 else 289 else
272 lcd_v2_display_init(); 290 lcd_v2_display_init();
273
274} 291}
275 292
276void lcd_enable (bool on) 293void lcd_enable (bool on)
@@ -281,6 +298,14 @@ void lcd_enable (bool on)
281 lcd_v2_enable(on); 298 lcd_v2_enable(on);
282} 299}
283 300
301void lcd_set_gram_area(int x, int y, int width, int height)
302{
303 if (lcd_type == LCD_V1)
304 lcd_v1_set_gram_area(x, y, width, height);
305 else
306 lcd_v2_set_gram_area(x, y, width, height);
307}
308
284void lcd_update_rect(int x, int y, int width, int height) 309void lcd_update_rect(int x, int y, int width, int height)
285{ 310{
286 if (lcd_type == LCD_V1) 311 if (lcd_type == LCD_V1)
@@ -293,9 +318,8 @@ void lcd_update_rect(int x, int y, int width, int height)
293 318
294#else /* HM801 */ 319#else /* HM801 */
295 320
296void lcd_init_device(void) 321void lcd_display_init(void)
297{ 322{
298 lcdif_init(LCDIF_16BIT);
299 lcd_v1_display_init(); 323 lcd_v1_display_init();
300} 324}
301 325
@@ -304,6 +328,11 @@ void lcd_enable (bool on)
304 lcd_v1_enable(on); 328 lcd_v1_enable(on);
305} 329}
306 330
331void lcd_set_gram_area(int x, int y, int width, int height)
332{
333 lcd_v1_set_gram_area(x, y, width, height);
334}
335
307void lcd_update_rect(int x, int y, int width, int height) 336void lcd_update_rect(int x, int y, int width, int height)
308{ 337{
309 lcd_v1_update_rect(x, y, width, height); 338 lcd_v1_update_rect(x, y, width, height);
diff --git a/firmware/target/arm/rk27xx/lcdif-rk27xx.c b/firmware/target/arm/rk27xx/lcdif-rk27xx.c
index affc49b213..01b19603fd 100644
--- a/firmware/target/arm/rk27xx/lcdif-rk27xx.c
+++ b/firmware/target/arm/rk27xx/lcdif-rk27xx.c
@@ -5,9 +5,9 @@
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/ 7 * \/ \/ \/ \/ \/
8 * $Id$
9 * 8 *
10 * Copyright (C) 2011 Marcin Bukat 9 * Copyright (C) 2011 Marcin Bukat
10 * Copyright (C) 2012 Andrew Ryabinin
11 * 11 *
12 * This program is free software; you can redistribute it and/or 12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License 13 * modify it under the terms of the GNU General Public License
@@ -25,9 +25,28 @@
25#include "system.h" 25#include "system.h"
26#include "cpu.h" 26#include "cpu.h"
27#include "lcdif-rk27xx.h" 27#include "lcdif-rk27xx.h"
28#include "lcd-target.h"
29#include <string.h>
28 30
31/* dwdma linked list struct - hw defined
32 * we don't use __attribute__((packed)) just because
33 * all fields are 32bits and so are aligned
34 */
35struct llp_t {
36 uint32_t sar;
37 uint32_t dar;
38 struct llp_t *llp;
39 uint32_t ctl_l;
40 uint32_t ctl_h;
41 uint32_t dstat;
42};
43
44/* array of structs which describes full screen update
45 * each struct describes dma transfer for single line
46 */
47static struct llp_t scr_llp[LCD_HEIGHT];
29 48
30unsigned int lcd_data_transform(unsigned int data) 49static uint32_t lcd_data_transform(uint32_t data)
31{ 50{
32 unsigned int r, g, b; 51 unsigned int r, g, b;
33 52
@@ -49,38 +68,10 @@ unsigned int lcd_data_transform(unsigned int data)
49 return (r | g | b); 68 return (r | g | b);
50} 69}
51 70
52void lcd_cmd(unsigned int cmd)
53{
54 LCD_COMMAND = lcd_data_transform(cmd);
55}
56
57void lcd_data(unsigned int data)
58{
59 LCD_DATA = lcd_data_transform(data);
60}
61
62void lcd_write_reg(unsigned int reg, unsigned int val)
63{
64 lcd_cmd(reg);
65 lcd_data(val);
66}
67
68static void lcdctrl_bypass(unsigned int on_off)
69{
70 while (!(LCDC_STA & LCDC_MCU_IDLE));
71
72 if (on_off)
73 MCU_CTRL |= MCU_CTRL_BYPASS;
74 else
75 MCU_CTRL &= ~MCU_CTRL_BYPASS;
76}
77
78/* This part is unclear. I am unable to use buffered/FIFO based writes
79 * to lcd. Depending on settings of IF I get various patterns on display
80 * but not what I want to display apparently.
81 */
82static void lcdctrl_init(void) 71static void lcdctrl_init(void)
83{ 72{
73 int i;
74
84 /* alpha b111 75 /* alpha b111
85 * stop at current frame complete 76 * stop at current frame complete
86 * MCU mode 77 * MCU mode
@@ -89,37 +80,43 @@ static void lcdctrl_init(void)
89 LCDC_CTRL = ALPHA(7) | LCDC_STOP | LCDC_MCU | RGB24B; 80 LCDC_CTRL = ALPHA(7) | LCDC_STOP | LCDC_MCU | RGB24B;
90 MCU_CTRL = ALPHA_BASE(0x3f) | MCU_CTRL_BYPASS; 81 MCU_CTRL = ALPHA_BASE(0x3f) | MCU_CTRL_BYPASS;
91 82
92 HOR_ACT = LCD_WIDTH + 3; /* define horizonatal active region */ 83 /* Warning: datasheet addresses and OF addresses
93 VERT_ACT = LCD_HEIGHT; /* define vertical active region */ 84 * don't match for HOR_ACT and VERT_ACT
94 VERT_PERIOD = 0xfff; /* CSn/WEn/RDn signal timings */ 85 */
95 86 HOR_ACT = LCD_WIDTH + 3; /* define horizonatal active region */
96 LINE0_YADDR = LINE_ALPHA_EN | 0x7fe; 87 VERT_ACT = LCD_HEIGHT; /* define vertical active region */
97 LINE1_YADDR = LINE_ALPHA_EN | ((1 * LCD_WIDTH) - 2); 88 VERT_PERIOD = (1<<7)|(1<<5)|1; /* CSn/WEn/RDn signal timings */
98 LINE2_YADDR = LINE_ALPHA_EN | ((2 * LCD_WIDTH) - 2);
99 LINE3_YADDR = LINE_ALPHA_EN | ((3 * LCD_WIDTH) - 2);
100 89
101 LINE0_UVADDR = 0x7fe + 1; 90 lcd_display_init();
102 LINE1_UVADDR = ((1 * LCD_WIDTH) - 2 + 1); 91 lcdctrl_bypass(0);
103 LINE2_UVADDR = ((2 * LCD_WIDTH) - 2 + 1);
104 LINE3_UVADDR = ((3 * LCD_WIDTH) - 2 + 1);
105 92
106#if 0 93 /* This lines define layout of data in lcdif internal buffer
94 * LINEx_UVADDR = LINEx_YADDR + 1
95 * buffer is organized as 2048 x 32bit
96 * we use RGB565 (16 bits per pixel) so we pack 2 pixels
97 * in every lcdbuffer mem cell
98 */
107 LINE0_YADDR = 0; 99 LINE0_YADDR = 0;
108 LINE1_YADDR = (1 * LCD_WIDTH); 100 LINE1_YADDR = 1 * LCD_WIDTH/2;
109 LINE2_YADDR = (2 * LCD_WIDTH); 101 LINE2_YADDR = 2 * LCD_WIDTH/2;
110 LINE3_YADDR = (3 * LCD_WIDTH); 102 LINE3_YADDR = 3 * LCD_WIDTH/2;
111 103
112 LINE0_UVADDR = 1; 104 LINE0_UVADDR = 1;
113 LINE1_UVADDR = (1 * LCD_WIDTH) + 1; 105 LINE1_UVADDR = (1 * LCD_WIDTH/2) + 1;
114 LINE2_UVADDR = (2 * LCD_WIDTH) + 1; 106 LINE2_UVADDR = (2 * LCD_WIDTH/2) + 1;
115 LINE3_UVADDR = (3 * LCD_WIDTH) + 1; 107 LINE3_UVADDR = (3 * LCD_WIDTH/2) + 1;
116 108
117 START_X = 0; 109 LCDC_INTR_MASK = INTR_MASK_EVENLINE;
118 START_Y = 0; 110
119 DELTA_X = 0x200; /* no scaling */ 111 /* This loop seems to fix strange glitch where
120 DELTA_Y = 0x200; /* no scaling */ 112 * whole lcd content was shifted ~4 lines verticaly
121#endif 113 * on second lcd_update call
122 LCDC_INTR_MASK = INTR_MASK_LINE; /* INTR_MASK_EVENLINE; */ 114 */
115 for (i=0; i<2048; i++)
116 *((uint32_t *)LCD_BUFF + i) = 0;
117
118 /* Setup buffered writes to lcd controler */
119 MCU_CTRL = MCU_CTRL_RS_HIGH|MCU_CTRL_BUFF_WRITE|MCU_CTRL_BUFF_START;
123} 120}
124 121
125/* configure pins to drive lcd in 18bit mode (16bit mode for HiFiMAN's) */ 122/* configure pins to drive lcd in 18bit mode (16bit mode for HiFiMAN's) */
@@ -138,26 +135,133 @@ static void iomux_lcd(enum lcdif_mode_t mode)
138 SCU_IOMUXB_CON |= IOMUX_LCD_D815; 135 SCU_IOMUXB_CON |= IOMUX_LCD_D815;
139} 136}
140 137
141void lcdif_init(enum lcdif_mode_t mode) 138static void dwdma_init(void)
142{ 139{
143 iomux_lcd(mode); /* setup pins for lcd interface */ 140 DWDMA_DMA_CHEN = 0xf00;
144 lcdctrl_init(); /* basic lcdc module configuration */ 141 DWDMA_CLEAR_BLOCK = 0x0f;
145 lcdctrl_bypass(1); /* run in bypass mode - all writes goes directly to lcd controller */ 142 DWDMA_DMA_CFG = 1; /* global enable */
146} 143}
147 144
148/* This is ugly hack. We drive lcd in bypass mode 145static void llp_setup(void *src, void *dst, struct llp_t *llp, uint32_t size)
149 * where all writes goes directly to lcd controller. 146{
150 * This is suboptimal at best. IF module povides 147 llp->sar = (uint32_t)src;
151 * FIFO, internal sram buffer, hardware scaller, 148 llp->dar = (uint32_t)dst;
152 * DMA signals, hardware alpha blending and more. 149 llp->llp = llp + 1;
153 * BUT the fact is that I have no idea how to use 150 llp->ctl_h = size;
154 * this modes. Datasheet floating around is very 151 llp->ctl_l = (1<<20) |
155 * unclean in this regard and OF uses ackward 152 (1<<23) |
156 * lcd update routines which are hard to understand. 153 (1<<17) |
157 * Moreover OF sets some bits in IF module registers 154 (2<<1) |
158 * which are referred as reseved in datasheet. 155 (2<<4) |
156 (3<<11) |
157 (3<<14) |
158 (1<<27) |
159 (1<<28) ;
160}
161
162static void llp_end(struct llp_t *llp)
163{
164 llp->ctl_l &= ~((1<<27)|(1<<28));
165}
166
167
168static void dwdma_start(uint8_t ch, struct llp_t *llp, uint8_t handshake)
169{
170 DWDMA_SAR(ch) = 0;
171 DWDMA_DAR(ch) = 0;
172 DWDMA_LLP(ch) = (uint32_t)llp;
173 DWDMA_CTL_L(ch) = (1<<20) |
174 (1<<23) |
175 (1<<17) |
176 (2<<1) |
177 (2<<4) |
178 (3<<11) |
179 (3<<14) |
180 (1<<27) |
181 (1<<28) ;
182
183 DWDMA_CTL_H(ch) = 1;
184 DWDMA_CFG_L(ch) = (7<<5);
185 DWDMA_CFG_H(ch) = (handshake<<11)|(1<<2);
186 DWDMA_SGR(ch) = (13<<20);
187 DWDMA_DMA_CHEN = (0x101<<ch);
188}
189
190static void create_llp(void)
191{
192 int i;
193
194 /* build LLPs */
195 for (i=0; i<LCD_HEIGHT; i++)
196 llp_setup((void *)FBADDR(0,i),
197 (void*)(LCD_BUFF+((i%4)*4*LCD_WIDTH/2)),
198 &(scr_llp[i]),
199 LCD_WIDTH/2);
200
201 llp_end(&scr_llp[LCD_HEIGHT-1]);
202}
203
204/* Public functions */
205
206/* Switch between lcdif bypass mode and buffered mode
207 * used in private implementations of lcd_set_gram_area()
208 */
209void lcdctrl_bypass(unsigned int on_off)
210{
211 while (!(LCDC_STA & LCDC_MCU_IDLE));
212
213 if (on_off)
214 MCU_CTRL |= MCU_CTRL_BYPASS;
215 else
216 MCU_CTRL &= ~MCU_CTRL_BYPASS;
217}
218
219/* Helper functions used to write commands
220 * to lcd controler in bypass mode
221 * used in controler specific implementations of:
222 * lcd_sleep()
223 * lcd_display_init()
159 */ 224 */
225void lcd_cmd(unsigned int cmd)
226{
227 LCD_COMMAND = lcd_data_transform(cmd);
228}
229
230void lcd_data(unsigned int data)
231{
232 LCD_DATA = lcd_data_transform(data);
233}
234
235void lcd_write_reg(unsigned int reg, unsigned int val)
236{
237 lcd_cmd(reg);
238 lcd_data(val);
239}
240
241/* rockbox API functions */
242void lcd_init_device(void)
243{
244 iomux_lcd(LCD_DATABUS_WIDTH); /* setup pins for lcd interface */
245 dwdma_init(); /* init dwdma module */
246 create_llp(); /* build LLPs for screen update dma */
247 lcdctrl_init(); /* basic lcdc module configuration */
248}
249
160void lcd_update() 250void lcd_update()
161{ 251{
162 lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); 252 lcd_set_gram_area(0, 0, LCD_WIDTH, LCD_HEIGHT);
253 lcdctrl_bypass(0);
254
255 commit_discard_dcache_range(FBADDR(0,0), 2*LCD_WIDTH*LCD_HEIGHT);
256
257 while (!(LCDC_STA & LCDC_MCU_IDLE));
258
259 dwdma_start(0, scr_llp, 6);
260 udelay(10);
261
262 /* Setup buffered writes to lcd controler */
263 MCU_CTRL = MCU_CTRL_RS_HIGH|MCU_CTRL_BUFF_WRITE|MCU_CTRL_BUFF_START;
264
265 /* Wait for DMA transfer to finish */
266 while (DWDMA_CTL_L(0) & (1<<27));
163} 267}
diff --git a/firmware/target/arm/rk27xx/lcdif-rk27xx.h b/firmware/target/arm/rk27xx/lcdif-rk27xx.h
index 1d7b810fa2..ea2dbea255 100644
--- a/firmware/target/arm/rk27xx/lcdif-rk27xx.h
+++ b/firmware/target/arm/rk27xx/lcdif-rk27xx.h
@@ -6,11 +6,12 @@ enum lcdif_mode_t {
6 LCDIF_18BIT 6 LCDIF_18BIT
7}; 7};
8 8
9unsigned int lcd_data_transform(unsigned int data);
10
11void lcd_cmd(unsigned int cmd); 9void lcd_cmd(unsigned int cmd);
12void lcd_data(unsigned int data); 10void lcd_data(unsigned int data);
13void lcd_write_reg(unsigned int reg, unsigned int val); 11void lcd_write_reg(unsigned int reg, unsigned int val);
14void lcdif_init(enum lcdif_mode_t mode); 12void lcdctrl_bypass(unsigned int on_off);
13void lcd_display_init(void);
14
15void lcd_set_gram_area(int x, int y, int width, int height);
15 16
16#endif /* _LCDIF_RK27XX_H */ 17#endif /* _LCDIF_RK27XX_H */
diff --git a/firmware/target/arm/rk27xx/rk27generic/lcd-rk27generic.c b/firmware/target/arm/rk27xx/rk27generic/lcd-rk27generic.c
index 5eca87c6d8..3e0eca1d6f 100644
--- a/firmware/target/arm/rk27xx/rk27generic/lcd-rk27generic.c
+++ b/firmware/target/arm/rk27xx/rk27generic/lcd-rk27generic.c
@@ -5,7 +5,6 @@
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/ 7 * \/ \/ \/ \/ \/
8 * $Id$
9 * 8 *
10 * Copyright (C) 2011 Marcin Bukat 9 * Copyright (C) 2011 Marcin Bukat
11 * 10 *
@@ -37,17 +36,6 @@ static inline void delay_nop(int cycles)
37} 36}
38 37
39 38
40/* converts RGB565 pixel into internal lcd bus format */
41static unsigned int lcd_pixel_transform(unsigned short rgb565)
42{
43 unsigned int r, g, b;
44 b = rgb565 & 0x1f;
45 g = (rgb565 >> 5) & 0x3f;
46 r = (rgb565 >> 11) & 0x1f;
47
48 return r<<19 | g<<10 | b<<3;
49}
50
51/* not tested */ 39/* not tested */
52static void lcd_sleep(bool sleep) 40static void lcd_sleep(bool sleep)
53{ 41{
@@ -71,7 +59,7 @@ static void lcd_sleep(bool sleep)
71 lcd_cmd(GRAM_WRITE); 59 lcd_cmd(GRAM_WRITE);
72} 60}
73 61
74static void lcd_display_init(void) 62void lcd_display_init(void)
75{ 63{
76 unsigned int x, y; 64 unsigned int x, y;
77 65
@@ -173,31 +161,34 @@ static void lcd_display_init(void)
173 lcd_sleep(false); 161 lcd_sleep(false);
174} 162}
175 163
176void lcd_init_device(void) 164void lcd_set_gram_area(int x, int y, int width, int height)
177{ 165{
178 lcdif_init(LCDIF_18BIT); 166 lcdctrl_bypass(1);
179 lcd_display_init(); 167 LCDC_CTRL |= RGB24B;
180}
181
182void lcd_update_rect(int x, int y, int width, int height)
183{
184 int px = x, py = y;
185 int pxmax = x + width, pymax = y + height;
186 168
187 /* addresses setup */ 169 /* addresses setup */
188 lcd_write_reg(WINDOW_H_START, y); 170 lcd_write_reg(WINDOW_H_START, y);
189 lcd_write_reg(WINDOW_H_END, pymax-1); 171 lcd_write_reg(WINDOW_H_END, height-1);
190 lcd_write_reg(WINDOW_V_START, x); 172 lcd_write_reg(WINDOW_V_START, x);
191 lcd_write_reg(WINDOW_V_END, pxmax-1); 173 lcd_write_reg(WINDOW_V_END, width-1);
192 lcd_write_reg(GRAM_H_ADDR, y); 174 lcd_write_reg(GRAM_H_ADDR, y);
193 lcd_write_reg(GRAM_V_ADDR, x); 175 lcd_write_reg(GRAM_V_ADDR, x);
194 176
195 lcd_cmd(GRAM_WRITE); 177 lcd_cmd(GRAM_WRITE);
178 LCDC_CTRL &= ~RGB24B;
179}
180
181void lcd_update_rect(int x, int y, int width, int height)
182{
183 int px = x, py = y;
184 int pxmax = x + width, pymax = y + height;
185
186 lcd_set_gram_area(x, y, pxmax, pymax);
196 187
197 for (py=y; py<pymax; py++) 188 for (py=y; py<pymax; py++)
198 { 189 {
199 for (px=x; px<pxmax; px++) 190 for (px=x; px<pxmax; px++)
200 LCD_DATA = lcd_pixel_transform(*FBADDR(px,py)); 191 LCD_DATA = *FBADDR(px,py);
201 } 192 }
202} 193}
203 194
diff --git a/firmware/target/arm/rk27xx/rk27generic/lcd-target.h b/firmware/target/arm/rk27xx/rk27generic/lcd-target.h
new file mode 100644
index 0000000000..ec139e1002
--- /dev/null
+++ b/firmware/target/arm/rk27xx/rk27generic/lcd-target.h
@@ -0,0 +1,26 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2012 Andrew Ryabinin
10 *
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#ifndef LCD_TARGET_H
22#define LCD_TARGET_H
23
24#define LCD_DATABUS_WIDTH LCDIF_18BIT
25
26#endif