brcm2708: update to v3.18
[openwrt/svn-archive/archive.git] / target / linux / brcm2708 / patches-3.18 / 0007-Speed-up-console-framebuffer-imageblit-function.patch
1 From 91fca9dd33742a38061dc9e949e4e88b9d5f645b Mon Sep 17 00:00:00 2001
2 From: Harm Hanemaaijer <fgenfb@yahoo.com>
3 Date: Thu, 20 Jun 2013 20:21:39 +0200
4 Subject: [PATCH 007/114] Speed up console framebuffer imageblit function
5
6 Especially on platforms with a slower CPU but a relatively high
7 framebuffer fill bandwidth, like current ARM devices, the existing
8 console monochrome imageblit function used to draw console text is
9 suboptimal for common pixel depths such as 16bpp and 32bpp. The existing
10 code is quite general and can deal with several pixel depths. By creating
11 special case functions for 16bpp and 32bpp, by far the most common pixel
12 formats used on modern systems, a significant speed-up is attained
13 which can be readily felt on ARM-based devices like the Raspberry Pi
14 and the Allwinner platform, but should help any platform using the
15 fb layer.
16
17 The special case functions allow constant folding, eliminating a number
18 of instructions including divide operations, and allow the use of an
19 unrolled loop, eliminating instructions with a variable shift size,
20 reducing source memory access instructions, and eliminating excessive
21 branching. These unrolled loops also allow much better code optimization
22 by the C compiler. The code that selects which optimized variant is used
23 is also simplified, eliminating integer divide instructions.
24
25 The speed-up, measured by timing 'cat file.txt' in the console, varies
26 between 40% and 70%, when testing on the Raspberry Pi and Allwinner
27 ARM-based platforms, depending on font size and the pixel depth, with
28 the greater benefit for 32bpp.
29
30 Signed-off-by: Harm Hanemaaijer <fgenfb@yahoo.com>
31 ---
32 drivers/video/fbdev/core/cfbimgblt.c | 152 +++++++++++++++++++++++++++++++++--
33 1 file changed, 147 insertions(+), 5 deletions(-)
34
35 diff --git a/drivers/video/fbdev/core/cfbimgblt.c b/drivers/video/fbdev/core/cfbimgblt.c
36 index a2bb276..436494f 100644
37 --- a/drivers/video/fbdev/core/cfbimgblt.c
38 +++ b/drivers/video/fbdev/core/cfbimgblt.c
39 @@ -28,6 +28,11 @@
40 *
41 * Also need to add code to deal with cards endians that are different than
42 * the native cpu endians. I also need to deal with MSB position in the word.
43 + * Modified by Harm Hanemaaijer (fgenfb@yahoo.com) 2013:
44 + * - Provide optimized versions of fast_imageblit for 16 and 32bpp that are
45 + * significantly faster than the previous implementation.
46 + * - Simplify the fast/slow_imageblit selection code, avoiding integer
47 + * divides.
48 */
49 #include <linux/module.h>
50 #include <linux/string.h>
51 @@ -262,6 +267,133 @@ static inline void fast_imageblit(const struct fb_image *image, struct fb_info *
52 }
53 }
54
55 +/*
56 + * Optimized fast_imageblit for bpp == 16. ppw = 2, bit_mask = 3 folded
57 + * into the code, main loop unrolled.
58 + */
59 +
60 +static inline void fast_imageblit16(const struct fb_image *image,
61 + struct fb_info *p, u8 __iomem * dst1,
62 + u32 fgcolor, u32 bgcolor)
63 +{
64 + u32 fgx = fgcolor, bgx = bgcolor;
65 + u32 spitch = (image->width + 7) / 8;
66 + u32 end_mask, eorx;
67 + const char *s = image->data, *src;
68 + u32 __iomem *dst;
69 + const u32 *tab = NULL;
70 + int i, j, k;
71 +
72 + tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le;
73 +
74 + fgx <<= 16;
75 + bgx <<= 16;
76 + fgx |= fgcolor;
77 + bgx |= bgcolor;
78 +
79 + eorx = fgx ^ bgx;
80 + k = image->width / 2;
81 +
82 + for (i = image->height; i--;) {
83 + dst = (u32 __iomem *) dst1;
84 + src = s;
85 +
86 + j = k;
87 + while (j >= 4) {
88 + u8 bits = *src;
89 + end_mask = tab[(bits >> 6) & 3];
90 + FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
91 + end_mask = tab[(bits >> 4) & 3];
92 + FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
93 + end_mask = tab[(bits >> 2) & 3];
94 + FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
95 + end_mask = tab[bits & 3];
96 + FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
97 + src++;
98 + j -= 4;
99 + }
100 + if (j != 0) {
101 + u8 bits = *src;
102 + end_mask = tab[(bits >> 6) & 3];
103 + FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
104 + if (j >= 2) {
105 + end_mask = tab[(bits >> 4) & 3];
106 + FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
107 + if (j == 3) {
108 + end_mask = tab[(bits >> 2) & 3];
109 + FB_WRITEL((end_mask & eorx) ^ bgx, dst);
110 + }
111 + }
112 + }
113 + dst1 += p->fix.line_length;
114 + s += spitch;
115 + }
116 +}
117 +
118 +/*
119 + * Optimized fast_imageblit for bpp == 32. ppw = 1, bit_mask = 1 folded
120 + * into the code, main loop unrolled.
121 + */
122 +
123 +static inline void fast_imageblit32(const struct fb_image *image,
124 + struct fb_info *p, u8 __iomem * dst1,
125 + u32 fgcolor, u32 bgcolor)
126 +{
127 + u32 fgx = fgcolor, bgx = bgcolor;
128 + u32 spitch = (image->width + 7) / 8;
129 + u32 end_mask, eorx;
130 + const char *s = image->data, *src;
131 + u32 __iomem *dst;
132 + const u32 *tab = NULL;
133 + int i, j, k;
134 +
135 + tab = cfb_tab32;
136 +
137 + eorx = fgx ^ bgx;
138 + k = image->width;
139 +
140 + for (i = image->height; i--;) {
141 + dst = (u32 __iomem *) dst1;
142 + src = s;
143 +
144 + j = k;
145 + while (j >= 8) {
146 + u8 bits = *src;
147 + end_mask = tab[(bits >> 7) & 1];
148 + FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
149 + end_mask = tab[(bits >> 6) & 1];
150 + FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
151 + end_mask = tab[(bits >> 5) & 1];
152 + FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
153 + end_mask = tab[(bits >> 4) & 1];
154 + FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
155 + end_mask = tab[(bits >> 3) & 1];
156 + FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
157 + end_mask = tab[(bits >> 2) & 1];
158 + FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
159 + end_mask = tab[(bits >> 1) & 1];
160 + FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
161 + end_mask = tab[bits & 1];
162 + FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
163 + src++;
164 + j -= 8;
165 + }
166 + if (j != 0) {
167 + u32 bits = (u32) * src;
168 + while (j > 1) {
169 + end_mask = tab[(bits >> 7) & 1];
170 + FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
171 + bits <<= 1;
172 + j--;
173 + }
174 + end_mask = tab[(bits >> 7) & 1];
175 + FB_WRITEL((end_mask & eorx) ^ bgx, dst);
176 + }
177 + dst1 += p->fix.line_length;
178 + s += spitch;
179 + }
180 +}
181 +
182 void cfb_imageblit(struct fb_info *p, const struct fb_image *image)
183 {
184 u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0;
185 @@ -294,11 +426,21 @@ void cfb_imageblit(struct fb_info *p, const struct fb_image *image)
186 bgcolor = image->bg_color;
187 }
188
189 - if (32 % bpp == 0 && !start_index && !pitch_index &&
190 - ((width & (32/bpp-1)) == 0) &&
191 - bpp >= 8 && bpp <= 32)
192 - fast_imageblit(image, p, dst1, fgcolor, bgcolor);
193 - else
194 + if (!start_index && !pitch_index) {
195 + if (bpp == 32)
196 + fast_imageblit32(image, p, dst1, fgcolor,
197 + bgcolor);
198 + else if (bpp == 16 && (width & 1) == 0)
199 + fast_imageblit16(image, p, dst1, fgcolor,
200 + bgcolor);
201 + else if (bpp == 8 && (width & 3) == 0)
202 + fast_imageblit(image, p, dst1, fgcolor,
203 + bgcolor);
204 + else
205 + slow_imageblit(image, p, dst1, fgcolor,
206 + bgcolor,
207 + start_index, pitch_index);
208 + } else
209 slow_imageblit(image, p, dst1, fgcolor, bgcolor,
210 start_index, pitch_index);
211 } else
212 --
213 1.8.3.2
214