diff options
author | Jens Arnold <amiconn@rockbox.org> | 2007-10-28 12:09:46 +0000 |
---|---|---|
committer | Jens Arnold <amiconn@rockbox.org> | 2007-10-28 12:09:46 +0000 |
commit | b05066de125c26cae2780efed7279b84ad9506b1 (patch) | |
tree | ac7227ef988c86ae530c6d77d6590502227ee2bd /firmware/target/arm/ipod/video/lcd-video.c | |
parent | 868d3ce39c9675ec778fa53a592b471775662264 (diff) | |
download | rockbox-b05066de125c26cae2780efed7279b84ad9506b1.tar.gz rockbox-b05066de125c26cae2780efed7279b84ad9506b1.zip |
iPod Video: Further optimised LCD data transfer (5..6% speedup, but increase in FPS measured with test_fps is less), making use of the fact that the low address bits aren't decoded by the BCM. Major cleanup of the driver, and introduced register names.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@15341 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm/ipod/video/lcd-video.c')
-rw-r--r-- | firmware/target/arm/ipod/video/lcd-video.c | 177 |
1 files changed, 75 insertions, 102 deletions
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 | ||
34 | void lcd_set_contrast(int val) | 53 | void lcd_set_contrast(int val) |
@@ -74,130 +93,97 @@ void lcd_blit(const fb_data* data, int x, int by, int width, | |||
74 | 93 | ||
75 | static inline void lcd_bcm_write32(unsigned address, unsigned value) | 94 | static 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 | ||
89 | static void lcd_bcm_setup_rect(unsigned cmd, | 106 | static 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 | ||
107 | static inline unsigned lcd_bcm_read32(unsigned address) { | 123 | static 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 | ||
121 | static int finishup_needed = 0; | 137 | static bool finishup_needed = false; |
122 | 138 | ||
123 | /* Update a fraction of the display. */ | 139 | /* Update a fraction of the display. */ |
124 | void lcd_update_rect(int x, int y, int width, int height) ICODE_ATTR; | ||
125 | void lcd_update_rect(int x, int y, int width, int height) | 140 | void 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 | } |