summaryrefslogtreecommitdiff
path: root/firmware/target
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target')
-rw-r--r--firmware/target/arm/ipod/video/lcd-as-video.S42
-rw-r--r--firmware/target/arm/ipod/video/lcd-video.c177
2 files changed, 116 insertions, 103 deletions
diff --git a/firmware/target/arm/ipod/video/lcd-as-video.S b/firmware/target/arm/ipod/video/lcd-as-video.S
index 938df3e86a..ffd2e0cf10 100644
--- a/firmware/target/arm/ipod/video/lcd-as-video.S
+++ b/firmware/target/arm/ipod/video/lcd-as-video.S
@@ -17,6 +17,47 @@
17 * 17 *
18 ****************************************************************************/ 18 ****************************************************************************/
19 19
20 .section .icode, "ax", %progbits
21
22 .align 2
23 .global lcd_write_data
24 .type lcd_write_data, %function
25 /* r0 = addr */
26lcd_write_data: /* r1 = pixel count */
27 stmfd sp!, {r4-r6}
28 mov r2, #0x30000000 /* LCD data port */
29
30 tst r0, #2 /* first pixel unaligned? */
31 ldrneh r3, [r0], #2
32 strneh r3, [r2]
33 subne r1, r1, #1
34
35 subs r1, r1, #16
36.loop16:
37 ldmgeia r0!, {r3-r6}
38 stmgeia r2, {r3-r6}
39 ldmgeia r0!, {r3-r6}
40 stmgeia r2, {r3-r6}
41 subges r1, r1, #16
42 bge .loop16
43
44 /* no need to correct the count, we're just checking bits from now */
45 tst r1, #8
46 ldmneia r0!, {r3-r6}
47 stmneia r2, {r3-r6}
48 tst r1, #4
49 ldmneia r0!, {r3-r4}
50 stmneia r2, {r3-r4}
51 tst r1, #2
52 ldrne r3, [r0], #4
53 strne r3, [r2]
54 tst r1, #1
55 ldrneh r3, [r0]
56 strneh r3, [r2]
57
58 ldmfd sp!, {r4-r6}
59 bx lr
60
20/**************************************************************************** 61/****************************************************************************
21 * void lcd_write_yuv_420_lines(unsigned char const * const src[3], 62 * void lcd_write_yuv_420_lines(unsigned char const * const src[3],
22 * int width, 63 * int width,
@@ -30,7 +71,6 @@
30 * |G| = |74 -24 -51| |Cb - 128| >> 8 71 * |G| = |74 -24 -51| |Cb - 128| >> 8
31 * |B| |74 128 0| |Cr - 128| >> 9 72 * |B| |74 128 0| |Cr - 128| >> 9
32 */ 73 */
33 .section .icode, "ax", %progbits
34 .align 2 74 .align 2
35 .global lcd_write_yuv420_lines 75 .global lcd_write_yuv420_lines
36 .type lcd_write_yuv420_lines, %function 76 .type lcd_write_yuv420_lines, %function
diff --git a/firmware/target/arm/ipod/video/lcd-video.c b/firmware/target/arm/ipod/video/lcd-video.c
index 8834b39f3f..04a4344125 100644
--- a/firmware/target/arm/ipod/video/lcd-video.c
+++ b/firmware/target/arm/ipod/video/lcd-video.c
@@ -29,6 +29,25 @@
29#include "kernel.h" 29#include "kernel.h"
30#include "system.h" 30#include "system.h"
31 31
32/* The BCM bus width is 16 bits. But since the low address bits aren't decoded
33 * by the chip (the 3 BCM address bits are mapped to address bits 16..18 of the
34 * PP5022), writing 32 bits (and even more, using 'stmia') at once works. */
35#define BCM_DATA (*(volatile unsigned short*)(0x30000000))
36#define BCM_DATA32 (*(volatile unsigned long *)(0x30000000))
37#define BCM_WR_ADDR (*(volatile unsigned short*)(0x30010000))
38#define BCM_WR_ADDR32 (*(volatile unsigned long *)(0x30010000))
39#define BCM_RD_ADDR (*(volatile unsigned short*)(0x30020000))
40#define BCM_RD_ADDR32 (*(volatile unsigned long *)(0x30020000))
41#define BCM_CONTROL (*(volatile unsigned short*)(0x30030000))
42
43#define BCM_ALT_DATA (*(volatile unsigned short*)(0x30040000))
44#define BCM_ALT_DATA32 (*(volatile unsigned long *)(0x30040000))
45#define BCM_ALT_WR_ADDR (*(volatile unsigned short*)(0x30050000))
46#define BCM_ALT_WR_ADDR32 (*(volatile unsigned long *)(0x30050000))
47#define BCM_ALT_RD_ADDR (*(volatile unsigned short*)(0x30060000))
48#define BCM_ALT_RD_ADDR32 (*(volatile unsigned long *)(0x30060000))
49#define BCM_ALT_CONTROL (*(volatile unsigned short*)(0x30070000))
50
32/*** hardware configuration ***/ 51/*** hardware configuration ***/
33 52
34void lcd_set_contrast(int val) 53void lcd_set_contrast(int val)
@@ -74,130 +93,97 @@ void lcd_blit(const fb_data* data, int x, int by, int width,
74 93
75static inline void lcd_bcm_write32(unsigned address, unsigned value) 94static inline void lcd_bcm_write32(unsigned address, unsigned value)
76{ 95{
77 /* write out destination address as two 16bit values */ 96 /* write out destination address */
78 outw(address, 0x30010000); 97 BCM_WR_ADDR32 = address;
79 outw((address >> 16), 0x30010000);
80 98
81 /* wait for it to be write ready */ 99 /* wait for it to be write ready */
82 while ((inw(0x30030000) & 0x2) == 0); 100 while (!(BCM_CONTROL & 0x2));
83 101
84 /* write out the value low 16, high 16 */ 102 /* write out the value */
85 outw(value, 0x30000000); 103 BCM_DATA32 = value;
86 outw((value >> 16), 0x30000000);
87} 104}
88 105
89static void lcd_bcm_setup_rect(unsigned cmd, 106static void lcd_bcm_setup_rect(unsigned cmd,
90 unsigned start_horiz, 107 unsigned x,
91 unsigned start_vert, 108 unsigned y,
92 unsigned max_horiz, 109 unsigned width,
93 unsigned max_vert, 110 unsigned height)
94 unsigned count)
95{ 111{
96 lcd_bcm_write32(0x1F8, 0xFFFA0005); 112 lcd_bcm_write32(0x1F8, 0xFFFA0005);
97 lcd_bcm_write32(0xE0000, cmd); 113 lcd_bcm_write32(0xE0000, cmd);
98 lcd_bcm_write32(0xE0004, start_horiz); 114 lcd_bcm_write32(0xE0004, x);
99 lcd_bcm_write32(0xE0008, start_vert); 115 lcd_bcm_write32(0xE0008, y);
100 lcd_bcm_write32(0xE000C, max_horiz); 116 lcd_bcm_write32(0xE000C, x + width - 1);
101 lcd_bcm_write32(0xE0010, max_vert); 117 lcd_bcm_write32(0xE0010, y + height - 1);
102 lcd_bcm_write32(0xE0014, count); 118 lcd_bcm_write32(0xE0014, (width * height) << 1);
103 lcd_bcm_write32(0xE0018, count); 119 lcd_bcm_write32(0xE0018, (width * height) << 1);
104 lcd_bcm_write32(0xE001C, 0); 120 lcd_bcm_write32(0xE001C, 0);
105} 121}
106 122
107static inline unsigned lcd_bcm_read32(unsigned address) { 123static inline unsigned lcd_bcm_read32(unsigned address)
108 while ((inw(0x30020000) & 1) == 0); 124{
125 while (!(BCM_RD_ADDR & 1));
109 126
110 /* write out destination address as two 16bit values */ 127 /* write out destination address */
111 outw(address, 0x30020000); 128 BCM_RD_ADDR32 = address;
112 outw((address >> 16), 0x30020000);
113 129
114 /* wait for it to be read ready */ 130 /* wait for it to be read ready */
115 while ((inw(0x30030000) & 0x10) == 0); 131 while (!(BCM_CONTROL & 0x10));
116 132
117 /* read the value */ 133 /* read the value */
118 return inw(0x30000000) | inw(0x30000000) << 16; 134 return BCM_DATA32;
119} 135}
120 136
121static int finishup_needed = 0; 137static bool finishup_needed = false;
122 138
123/* Update a fraction of the display. */ 139/* Update a fraction of the display. */
124void lcd_update_rect(int x, int y, int width, int height) ICODE_ATTR;
125void lcd_update_rect(int x, int y, int width, int height) 140void lcd_update_rect(int x, int y, int width, int height)
126{ 141{
127 { 142 const fb_data *addr;
128 int endy = x + width; 143
129 /* Ensure x and width are both even - so we can read 32-bit aligned 144 if (x + width >= LCD_WIDTH)
130 data from lcd_framebuffer */ 145 width = LCD_WIDTH - x;
131 x &= ~1; 146 if (y + height >= LCD_HEIGHT)
132 width &= ~1; 147 height = LCD_HEIGHT - y;
133 if (x + width < endy) { 148
134 width += 2; 149 if ((width <= 0) || (height <= 0))
135 } 150 return; /* Nothing left to do - 0 is harmful to lcd_write_data(). */
136 } 151
137 152 addr = &lcd_framebuffer[y][x];
138 if (finishup_needed) 153
154 if (finishup_needed)
139 { 155 {
140 /* Bottom-half of original lcd_bcm_finishup() function */ 156 /* Bottom-half of original lcd_bcm_finishup() function */
141 unsigned int data = lcd_bcm_read32(0x1F8); 157 unsigned int data = lcd_bcm_read32(0x1F8);
142 while (data == 0xFFFA0005 || data == 0xFFFF) 158 while (data == 0xFFFA0005 || data == 0xFFFF)
143 { 159 {
144 /* This loop can wait for up to 14ms - so we yield() */ 160 /* This loop can wait for up to 14ms - so we yield() */
145 yield(); 161 yield();
146 data = lcd_bcm_read32(0x1F8); 162 data = lcd_bcm_read32(0x1F8);
147 } 163 }
148 } 164 }
149
150 lcd_bcm_read32(0x1FC); 165 lcd_bcm_read32(0x1FC);
151 166
152 { 167 lcd_bcm_setup_rect(0x34, x, y, width, height);
153 int rect1, rect2, rect3, rect4;
154 int count = (width * height) << 1;
155 /* calculate the drawing region */
156 rect1 = x; /* start horiz */
157 rect2 = y; /* start vert */
158 rect3 = (x + width) - 1; /* max horiz */
159 rect4 = (y + height) - 1; /* max vert */
160
161 /* setup the drawing region */
162 lcd_bcm_setup_rect(0x34, rect1, rect2, rect3, rect4, count);
163 }
164 168
165 /* write out destination address as two 16bit values */ 169 /* write out destination address */
166 outw((0xE0020 & 0xffff), 0x30010000); 170 BCM_WR_ADDR32 = 0xE0020;
167 outw((0xE0020 >> 16), 0x30010000);
168 171
169 /* wait for it to be write ready */ 172 while (!(BCM_CONTROL & 0x2)); /* wait for it to be write ready */
170 while ((inw(0x30030000) & 0x2) == 0);
171 173
174 do
172 { 175 {
173 unsigned short *src = (unsigned short*)&lcd_framebuffer[y][x]; 176 lcd_write_data(addr, width);
174 unsigned short *end = &src[LCD_WIDTH * height]; 177 addr += LCD_WIDTH;
175 int line_rem = (LCD_WIDTH - width);
176 while (src < end) {
177 /* Duff's Device to unroll loop */
178 register int count = width ;
179 register int n=( count + 7 ) / 8;
180 switch( count % 8 ) {
181 case 0: do{ outw(*(src++), 0x30000000);
182 case 7: outw(*(src++), 0x30000000);
183 case 6: outw(*(src++), 0x30000000);
184 case 5: outw(*(src++), 0x30000000);
185 case 4: outw(*(src++), 0x30000000);
186 case 3: outw(*(src++), 0x30000000);
187 case 2: outw(*(src++), 0x30000000);
188 case 1: outw(*(src++), 0x30000000);
189 } while(--n>0);
190 }
191 src += line_rem;
192 }
193 } 178 }
179 while (--height > 0);
194 180
195 /* Top-half of original lcd_bcm_finishup() function */ 181 /* Top-half of original lcd_bcm_finishup() function */
196 outw(0x31, 0x30030000); 182 BCM_CONTROL = 0x31;
197 183
198 lcd_bcm_read32(0x1FC); 184 lcd_bcm_read32(0x1FC);
199 185
200 finishup_needed = 1; 186 finishup_needed = true;
201} 187}
202 188
203/* Update the display. 189/* Update the display.
@@ -228,11 +214,11 @@ void lcd_yuv_blit(unsigned char * const src[3],
228 yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1); 214 yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1);
229 yuv_src[2] = src[2] + (yuv_src[1] - src[1]); 215 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
230 216
231 if (finishup_needed) 217 if (finishup_needed)
232 { 218 {
233 /* Bottom-half of original lcd_bcm_finishup() function */ 219 /* Bottom-half of original lcd_bcm_finishup() function */
234 unsigned int data = lcd_bcm_read32(0x1F8); 220 unsigned int data = lcd_bcm_read32(0x1F8);
235 while (data == 0xFFFA0005 || data == 0xFFFF) 221 while (data == 0xFFFA0005 || data == 0xFFFF)
236 { 222 {
237 /* This loop can wait for up to 14ms - so we yield() */ 223 /* This loop can wait for up to 14ms - so we yield() */
238 yield(); 224 yield();
@@ -241,26 +227,13 @@ void lcd_yuv_blit(unsigned char * const src[3],
241 } 227 }
242 228
243 lcd_bcm_read32(0x1FC); 229 lcd_bcm_read32(0x1FC);
230
231 lcd_bcm_setup_rect(0x34, x, y, width, height);
244 232
245 { 233 /* write out destination address */
246 int rect1, rect2, rect3, rect4; 234 BCM_WR_ADDR32 = 0xE0020;
247 int count = (width * height) << 1;
248 /* calculate the drawing region */
249 rect1 = x; /* start horiz */
250 rect2 = y; /* start vert */
251 rect3 = (x + width) - 1; /* max horiz */
252 rect4 = (y + height) - 1; /* max vert */
253
254 /* setup the drawing region */
255 lcd_bcm_setup_rect(0x34, rect1, rect2, rect3, rect4, count);
256 }
257
258 /* write out destination address as two 16bit values */
259 outw((0xE0020 & 0xffff), 0x30010000);
260 outw((0xE0020 >> 16), 0x30010000);
261 235
262 /* wait for it to be write ready */ 236 while (!(BCM_CONTROL & 0x2)); /* wait for it to be write ready */
263 while ((inw(0x30030000) & 0x2) == 0);
264 237
265 height >>= 1; 238 height >>= 1;
266 do 239 do
@@ -274,9 +247,9 @@ void lcd_yuv_blit(unsigned char * const src[3],
274 while (--height > 0); 247 while (--height > 0);
275 248
276 /* Top-half of original lcd_bcm_finishup() function */ 249 /* Top-half of original lcd_bcm_finishup() function */
277 outw(0x31, 0x30030000); 250 BCM_CONTROL = 0x31;
278 251
279 lcd_bcm_read32(0x1FC); 252 lcd_bcm_read32(0x1FC);
280 253
281 finishup_needed = 1; 254 finishup_needed = true;
282} 255}