summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx31/gigabeat-s/lcd-imx31.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/imx31/gigabeat-s/lcd-imx31.c')
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/lcd-imx31.c224
1 files changed, 124 insertions, 100 deletions
diff --git a/firmware/target/arm/imx31/gigabeat-s/lcd-imx31.c b/firmware/target/arm/imx31/gigabeat-s/lcd-imx31.c
index c9cce6d653..b39ddbe77d 100644
--- a/firmware/target/arm/imx31/gigabeat-s/lcd-imx31.c
+++ b/firmware/target/arm/imx31/gigabeat-s/lcd-imx31.c
@@ -9,12 +9,15 @@
9 9
10static volatile bool lcd_on = true; 10static volatile bool lcd_on = true;
11volatile bool lcd_poweroff = false; 11volatile bool lcd_poweroff = false;
12static unsigned lcd_yuv_options = 0;
12/* 13/*
13** These are imported from lcd-16bit.c 14** These are imported from lcd-16bit.c
14*/ 15*/
15extern unsigned fg_pattern; 16extern unsigned fg_pattern;
16extern unsigned bg_pattern; 17extern unsigned bg_pattern;
17 18
19extern struct viewport* current_vp;
20
18#if 0 21#if 0
19bool lcd_enabled() 22bool lcd_enabled()
20{ 23{
@@ -22,68 +25,60 @@ bool lcd_enabled()
22} 25}
23#endif 26#endif
24 27
25void printscreen(unsigned int colour) { 28void printscreen(unsigned int colour)
29{
26 int i; 30 int i;
27 int base = 0x84100000; 31 char * base = (char *)FRAME;
28 for(i=0;i<(320*240*2);i++) { 32 for(i = 0; i < (320*240*2); i++)
29 writel(colour,base); 33 {
34 writel(colour, base);
30 base++; 35 base++;
31 } 36 }
32} 37}
33 38
34unsigned int LCDBANK(unsigned int address)
35{
36 return ((address >> 22) & 0xff);
37}
38
39unsigned int LCDBASEU(unsigned int address)
40{
41 return (address & ((1 << 22)-1)) >> 1;
42}
43
44unsigned int LCDBASEL(unsigned int address)
45{
46 address += 320*240*2;
47 return (address & ((1 << 22)-1)) >> 1;
48}
49
50
51/* LCD init */ 39/* LCD init */
52void lcd_init_device(void) 40void lcd_init_device(void)
53{ 41{
54 int i;
55#ifdef BOOTLOADER
56 /* When the Rockbox bootloader starts, we are changing framebuffer address,
57 but we don't want what's shown on the LCD to change until we do an
58 lcd_update(), so copy the data from the old framebuffer to the new one */
59 unsigned short *buf = (unsigned short*)FRAME1;
60
61 memcpy(FRAME1, (short *)((LCDSADDR1)<<1), 320*240*2);
62
63 /* The Rockbox bootloader is transitioning from RGB555I to RGB565 mode
64 so convert the frambuffer data accordingly */
65 for(i=0; i< 320*240; i++){
66 *buf = ((*buf>>1) & 0x1F) | (*buf & 0xffc0);
67 buf++;
68 }
69 return;
70#endif
71} 42}
72 43
73/* Update a fraction of the display. */ 44/* Update a fraction of the display. */
74void lcd_update_rect(int x, int y, int width, int height) 45void lcd_update_rect(int x, int y, int width, int height)
75{ 46{
76 (void)x; 47 fb_data *dst, *src;
77 (void)width;
78 (void)y;
79 (void)height;
80 48
81 if(!lcd_on) 49 if (!lcd_on)
82 {
83 sleep(200);
84 return; 50 return;
51
52 if (x + width > LCD_WIDTH)
53 width = LCD_WIDTH - x; /* Clip right */
54 if (x < 0)
55 width += x, x = 0; /* Clip left */
56 if (width <= 0)
57 return; /* nothing left to do */
58
59 if (y + height > LCD_HEIGHT)
60 height = LCD_HEIGHT - y; /* Clip bottom */
61 if (y < 0)
62 height += y, y = 0; /* Clip top */
63 if (height <= 0)
64 return; /* nothing left to do */
65
66 /* TODO: It may be faster to swap the addresses of lcd_driver_framebuffer
67 * and lcd_framebuffer */
68 dst = (fb_data *)FRAME + LCD_WIDTH*y + x;
69 src = &lcd_framebuffer[y][x];
70
71 /* Copy part of the Rockbox framebuffer to the second framebuffer */
72 if (width < LCD_WIDTH)
73 {
74 /* Not full width - do line-by-line */
75 lcd_copy_buffer_rect(dst, src, width, height);
76 }
77 else
78 {
79 /* Full width - copy as one line */
80 lcd_copy_buffer_rect(dst, src, LCD_WIDTH*height, 1);
85 } 81 }
86 memcpy(((char*)FRAME2) + (y * sizeof(fb_data) * LCD_WIDTH), ((char *)&lcd_framebuffer) + (y * sizeof(fb_data) * LCD_WIDTH), ((height * sizeof(fb_data) * LCD_WIDTH)));
87} 82}
88 83
89void lcd_enable(bool state) 84void lcd_enable(bool state)
@@ -100,68 +95,82 @@ bool lcd_enabled(void)
100 This must be called after all other LCD functions that change the display. */ 95 This must be called after all other LCD functions that change the display. */
101void lcd_update(void) 96void lcd_update(void)
102{ 97{
103 lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); 98 if (!lcd_on)
99 return;
100
101 lcd_copy_buffer_rect((fb_data *)FRAME, &lcd_framebuffer[0][0],
102 LCD_WIDTH*LCD_HEIGHT, 1);
104} 103}
105 104
106void lcd_bitmap_transparent_part(const fb_data *src, int src_x, int src_y, 105void lcd_bitmap_transparent_part(const fb_data *src, int src_x, int src_y,
107 int stride, int x, int y, int width, 106 int stride, int x, int y, int width,
108 int height) 107 int height)
109{ 108{
110 fb_data *dst, *dst_end; 109#if 0
111 unsigned int transcolor; 110 int w, px;
112 111 fb_data *dst;
113 /* nothing to draw? */
114 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
115 || (x + width <= 0) || (y + height <= 0))
116 return;
117 112
118 /* clipping */
119 if (x < 0)
120 {
121 width += x;
122 src_x -= x;
123 x = 0;
124 }
125 if (y < 0)
126 {
127 height += y;
128 src_y -= y;
129 y = 0;
130 }
131 if (x + width > LCD_WIDTH) 113 if (x + width > LCD_WIDTH)
132 width = LCD_WIDTH - x; 114 width = LCD_WIDTH - x; /* Clip right */
115 if (x < 0)
116 width += x, x = 0; /* Clip left */
117 if (width <= 0)
118 return; /* nothing left to do */
119
133 if (y + height > LCD_HEIGHT) 120 if (y + height > LCD_HEIGHT)
134 height = LCD_HEIGHT - y; 121 height = LCD_HEIGHT - y; /* Clip bottom */
122 if (y < 0)
123 height += y, y = 0; /* Clip top */
124 if (height <= 0)
125 return; /* nothing left to do */
135 126
136 src += stride * src_y + src_x; /* move starting point */ 127 src += stride * src_y + src_x; /* move starting point */
137 dst = &lcd_framebuffer[(y)][(x)]; 128 dst = &lcd_framebuffer[y][x];
138 dst_end = dst + height * LCD_WIDTH; 129
139 width *= 2; 130 asm volatile (
140 stride *= 2; 131 ".rowstart: \r\n"
141 transcolor = TRANSPARENT_COLOR; 132 "mov %[w], %[width] \r\n" /* Load width for inner loop */
142 asm volatile( 133 ".nextpixel: \r\n"
143 "rowstart: \n" 134 "ldrh %[px], [%[s]], #2 \r\n" /* Load src pixel */
144 "mov r0, #0 \n" 135 "add %[d], %[d], #2 \r\n" /* Uncoditionally increment dst */
145 "nextpixel: \n" 136 "cmp %[px], %[fgcolor] \r\n" /* Compare to foreground color */
146 "ldrh r1, [%0, r0] \n" /* Load word src+r0 */ 137 "streqh %[fgpat], [%[d], #-2] \r\n" /* Store foregroud if match */
147 "cmp r1, %5 \n" /* Compare to transparent color */ 138 "cmpne %[px], %[transcolor] \r\n" /* Compare to transparent color */
148 "strneh r1, [%1, r0] \n" /* Store dst+r0 if not transparent */ 139 "strneh %[px], [%[d], #-2] \r\n" /* Store dst if not transparent */
149 "add r0, r0, #2 \n" 140 "subs %[w], %[w], #1 \r\n" /* Width counter has run down? */
150 "cmp r0, %2 \n" /* r0 == width? */ 141 "bgt .nextpixel \r\n" /* More in this row? */
151 "bne nextpixel \n" /* More in this row? */ 142 "add %[s], %[s], %[sstp], lsl #1 \r\n" /* Skip over to start of next line */
152 "add %0, %0, %4 \n" /* src += stride */ 143 "add %[d], %[d], %[dstp], lsl #1 \r\n"
153 "add %1, %1, #480 \n" /* dst += LCD_WIDTH (x2) */ 144 "subs %[h], %[h], #1 \r\n" /* Height counter has run down? */
154 "cmp %1, %3 \n" 145 "bgt .rowstart \r\n" /* More rows? */
155 "bne rowstart \n" /* if(dst != dst_end), keep going */ 146 : [w]"=&r"(w), [h]"+&r"(height), [px]"=&r"(px),
156 : : "r" (src), "r" (dst), "r" (width), "r" (dst_end), "r" (stride), "r" (transcolor) : "r0", "r1" ); 147 [s]"+&r"(src), [d]"+&r"(dst)
148 : [width]"r"(width),
149 [sstp]"r"(stride - width),
150 [dstp]"r"(LCD_WIDTH - width),
151 [transcolor]"r"(TRANSPARENT_COLOR),
152 [fgcolor]"r"(REPLACEWITHFG_COLOR),
153 [fgpat]"r"(current_vp->fg_pattern)
154 );
155#endif
156}
157
158void lcd_yuv_set_options(unsigned options)
159{
160 lcd_yuv_options = options;
157} 161}
158 162
159/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */ 163/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */
160extern void lcd_write_yuv420_lines(fb_data *dst, 164extern void lcd_write_yuv420_lines(fb_data *dst,
161 unsigned char chroma_buf[LCD_HEIGHT/2*3],
162 unsigned char const * const src[3], 165 unsigned char const * const src[3],
163 int width, 166 int width,
164 int stride); 167 int stride);
168extern void lcd_write_yuv420_lines_odither(fb_data *dst,
169 unsigned char const * const src[3],
170 int width,
171 int stride,
172 int x_screen, /* To align dither pattern */
173 int y_screen);
165/* Performance function to blit a YUV bitmap directly to the LCD */ 174/* Performance function to blit a YUV bitmap directly to the LCD */
166/* For the Gigabeat - show it rotated */ 175/* For the Gigabeat - show it rotated */
167/* So the LCD_WIDTH is now the height */ 176/* So the LCD_WIDTH is now the height */
@@ -171,7 +180,6 @@ void lcd_yuv_blit(unsigned char * const src[3],
171{ 180{
172 /* Caches for chroma data so it only need be recaculated every other 181 /* Caches for chroma data so it only need be recaculated every other
173 line */ 182 line */
174 unsigned char chroma_buf[LCD_HEIGHT/2*3]; /* 480 bytes */
175 unsigned char const * yuv_src[3]; 183 unsigned char const * yuv_src[3];
176 off_t z; 184 off_t z;
177 185
@@ -182,23 +190,39 @@ void lcd_yuv_blit(unsigned char * const src[3],
182 width &= ~1; 190 width &= ~1;
183 height >>= 1; 191 height >>= 1;
184 192
185 fb_data *dst = (fb_data*)FRAME1 + x * LCD_WIDTH + (LCD_WIDTH - y) - 1; 193 y = LCD_WIDTH - 1 - y;
194 fb_data *dst = (fb_data*)FRAME + x * LCD_WIDTH + y;
186 195
187 z = stride*src_y; 196 z = stride*src_y;
188 yuv_src[0] = src[0] + z + src_x; 197 yuv_src[0] = src[0] + z + src_x;
189 yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1); 198 yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1);
190 yuv_src[2] = src[2] + (yuv_src[1] - src[1]); 199 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
191 200
192 do 201 if (lcd_yuv_options & LCD_YUV_DITHER)
202 {
203 do
204 {
205 lcd_write_yuv420_lines_odither(dst, yuv_src, width, stride, y, x);
206 yuv_src[0] += stride << 1; /* Skip down two luma lines */
207 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
208 yuv_src[2] += stride >> 1;
209 dst -= 2;
210 y -= 2;
211 }
212 while (--height > 0);
213 }
214 else
193 { 215 {
194 lcd_write_yuv420_lines(dst, chroma_buf, yuv_src, width, 216 do
195 stride); 217 {
196 yuv_src[0] += stride << 1; /* Skip down two luma lines */ 218 lcd_write_yuv420_lines(dst, yuv_src, width, stride);
197 yuv_src[1] += stride >> 1; /* Skip down one chroma line */ 219 yuv_src[0] += stride << 1; /* Skip down two luma lines */
198 yuv_src[2] += stride >> 1; 220 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
199 dst -= 2; 221 yuv_src[2] += stride >> 1;
222 dst -= 2;
223 }
224 while (--height > 0);
200 } 225 }
201 while (--height > 0);
202} 226}
203 227
204void lcd_set_contrast(int val) { 228void lcd_set_contrast(int val) {