1 /* 2 * Generic fillrect for frame buffers with packed pixels of any depth. 3 * 4 * Copyright (C) 2000 James Simmons (jsimmons@linux-fbdev.org) 5 * 6 * This file is subject to the terms and conditions of the GNU General Public 7 * License. See the file COPYING in the main directory of this archive for 8 * more details. 9 * 10 * NOTES: 11 * 12 * Also need to add code to deal with cards endians that are different than 13 * the native cpu endians. I also need to deal with MSB position in the word. 14 * 15 */ 16 #include <linux/module.h> 17 #include <linux/string.h> 18 #include <linux/fb.h> 19 #include <asm/types.h> 20 #include "fb_draw.h" 21 22 #if BITS_PER_LONG == 32 23 # define FB_WRITEL fb_writel 24 # define FB_READL fb_readl 25 #else 26 # define FB_WRITEL fb_writeq 27 # define FB_READL fb_readq 28 #endif 29 30 /* 31 * Aligned pattern fill using 32/64-bit memory accesses 32 */ 33 34 static void 35 bitfill_aligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, 36 unsigned long pat, unsigned n, int bits, u32 bswapmask) 37 { 38 unsigned long first, last; 39 40 if (!n) 41 return; 42 43 first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask); 44 last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask); 45 46 if (dst_idx+n <= bits) { 47 // Single word 48 if (last) 49 first &= last; 50 FB_WRITEL(comp(pat, FB_READL(dst), first), dst); 51 } else { 52 // Multiple destination words 53 54 // Leading bits 55 if (first!= ~0UL) { 56 FB_WRITEL(comp(pat, FB_READL(dst), first), dst); 57 dst++; 58 n -= bits - dst_idx; 59 } 60 61 // Main chunk 62 n /= bits; 63 while (n >= 8) { 64 FB_WRITEL(pat, dst++); 65 FB_WRITEL(pat, dst++); 66 FB_WRITEL(pat, dst++); 67 FB_WRITEL(pat, dst++); 68 FB_WRITEL(pat, dst++); 69 FB_WRITEL(pat, dst++); 70 FB_WRITEL(pat, dst++); 71 FB_WRITEL(pat, dst++); 72 n -= 8; 73 } 74 while (n--) 75 FB_WRITEL(pat, dst++); 76 77 // Trailing bits 78 if (last) 79 FB_WRITEL(comp(pat, FB_READL(dst), last), dst); 80 } 81 } 82 83 84 /* 85 * Unaligned generic pattern fill using 32/64-bit memory accesses 86 * The pattern must have been expanded to a full 32/64-bit value 87 * Left/right are the appropriate shifts to convert to the pattern to be 88 * used for the next 32/64-bit word 89 */ 90 91 static void 92 bitfill_unaligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, 93 unsigned long pat, int left, int right, unsigned n, int bits) 94 { 95 unsigned long first, last; 96 97 if (!n) 98 return; 99 100 first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); 101 last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); 102 103 if (dst_idx+n <= bits) { 104 // Single word 105 if (last) 106 first &= last; 107 FB_WRITEL(comp(pat, FB_READL(dst), first), dst); 108 } else { 109 // Multiple destination words 110 // Leading bits 111 if (first) { 112 FB_WRITEL(comp(pat, FB_READL(dst), first), dst); 113 dst++; 114 pat = pat << left | pat >> right; 115 n -= bits - dst_idx; 116 } 117 118 // Main chunk 119 n /= bits; 120 while (n >= 4) { 121 FB_WRITEL(pat, dst++); 122 pat = pat << left | pat >> right; 123 FB_WRITEL(pat, dst++); 124 pat = pat << left | pat >> right; 125 FB_WRITEL(pat, dst++); 126 pat = pat << left | pat >> right; 127 FB_WRITEL(pat, dst++); 128 pat = pat << left | pat >> right; 129 n -= 4; 130 } 131 while (n--) { 132 FB_WRITEL(pat, dst++); 133 pat = pat << left | pat >> right; 134 } 135 136 // Trailing bits 137 if (last) 138 FB_WRITEL(comp(pat, FB_READL(dst), last), dst); 139 } 140 } 141 142 /* 143 * Aligned pattern invert using 32/64-bit memory accesses 144 */ 145 static void 146 bitfill_aligned_rev(struct fb_info *p, unsigned long __iomem *dst, 147 int dst_idx, unsigned long pat, unsigned n, int bits, 148 u32 bswapmask) 149 { 150 unsigned long val = pat, dat; 151 unsigned long first, last; 152 153 if (!n) 154 return; 155 156 first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask); 157 last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask); 158 159 if (dst_idx+n <= bits) { 160 // Single word 161 if (last) 162 first &= last; 163 dat = FB_READL(dst); 164 FB_WRITEL(comp(dat ^ val, dat, first), dst); 165 } else { 166 // Multiple destination words 167 // Leading bits 168 if (first!=0UL) { 169 dat = FB_READL(dst); 170 FB_WRITEL(comp(dat ^ val, dat, first), dst); 171 dst++; 172 n -= bits - dst_idx; 173 } 174 175 // Main chunk 176 n /= bits; 177 while (n >= 8) { 178 FB_WRITEL(FB_READL(dst) ^ val, dst); 179 dst++; 180 FB_WRITEL(FB_READL(dst) ^ val, dst); 181 dst++; 182 FB_WRITEL(FB_READL(dst) ^ val, dst); 183 dst++; 184 FB_WRITEL(FB_READL(dst) ^ val, dst); 185 dst++; 186 FB_WRITEL(FB_READL(dst) ^ val, dst); 187 dst++; 188 FB_WRITEL(FB_READL(dst) ^ val, dst); 189 dst++; 190 FB_WRITEL(FB_READL(dst) ^ val, dst); 191 dst++; 192 FB_WRITEL(FB_READL(dst) ^ val, dst); 193 dst++; 194 n -= 8; 195 } 196 while (n--) { 197 FB_WRITEL(FB_READL(dst) ^ val, dst); 198 dst++; 199 } 200 // Trailing bits 201 if (last) { 202 dat = FB_READL(dst); 203 FB_WRITEL(comp(dat ^ val, dat, last), dst); 204 } 205 } 206 } 207 208 209 /* 210 * Unaligned generic pattern invert using 32/64-bit memory accesses 211 * The pattern must have been expanded to a full 32/64-bit value 212 * Left/right are the appropriate shifts to convert to the pattern to be 213 * used for the next 32/64-bit word 214 */ 215 216 static void 217 bitfill_unaligned_rev(struct fb_info *p, unsigned long __iomem *dst, 218 int dst_idx, unsigned long pat, int left, int right, 219 unsigned n, int bits) 220 { 221 unsigned long first, last, dat; 222 223 if (!n) 224 return; 225 226 first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); 227 last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); 228 229 if (dst_idx+n <= bits) { 230 // Single word 231 if (last) 232 first &= last; 233 dat = FB_READL(dst); 234 FB_WRITEL(comp(dat ^ pat, dat, first), dst); 235 } else { 236 // Multiple destination words 237 238 // Leading bits 239 if (first != 0UL) { 240 dat = FB_READL(dst); 241 FB_WRITEL(comp(dat ^ pat, dat, first), dst); 242 dst++; 243 pat = pat << left | pat >> right; 244 n -= bits - dst_idx; 245 } 246 247 // Main chunk 248 n /= bits; 249 while (n >= 4) { 250 FB_WRITEL(FB_READL(dst) ^ pat, dst); 251 dst++; 252 pat = pat << left | pat >> right; 253 FB_WRITEL(FB_READL(dst) ^ pat, dst); 254 dst++; 255 pat = pat << left | pat >> right; 256 FB_WRITEL(FB_READL(dst) ^ pat, dst); 257 dst++; 258 pat = pat << left | pat >> right; 259 FB_WRITEL(FB_READL(dst) ^ pat, dst); 260 dst++; 261 pat = pat << left | pat >> right; 262 n -= 4; 263 } 264 while (n--) { 265 FB_WRITEL(FB_READL(dst) ^ pat, dst); 266 dst++; 267 pat = pat << left | pat >> right; 268 } 269 270 // Trailing bits 271 if (last) { 272 dat = FB_READL(dst); 273 FB_WRITEL(comp(dat ^ pat, dat, last), dst); 274 } 275 } 276 } 277 278 void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) 279 { 280 unsigned long pat, pat2, fg; 281 unsigned long width = rect->width, height = rect->height; 282 int bits = BITS_PER_LONG, bytes = bits >> 3; 283 u32 bpp = p->var.bits_per_pixel; 284 unsigned long __iomem *dst; 285 int dst_idx, left; 286 287 if (p->state != FBINFO_STATE_RUNNING) 288 return; 289 290 if (p->fix.visual == FB_VISUAL_TRUECOLOR || 291 p->fix.visual == FB_VISUAL_DIRECTCOLOR ) 292 fg = ((u32 *) (p->pseudo_palette))[rect->color]; 293 else 294 fg = rect->color; 295 296 pat = pixel_to_pat(bpp, fg); 297 298 dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1)); 299 dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8; 300 dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp; 301 /* FIXME For now we support 1-32 bpp only */ 302 left = bits % bpp; 303 if (p->fbops->fb_sync) 304 p->fbops->fb_sync(p); 305 if (!left) { 306 u32 bswapmask = fb_compute_bswapmask(p); 307 void (*fill_op32)(struct fb_info *p, 308 unsigned long __iomem *dst, int dst_idx, 309 unsigned long pat, unsigned n, int bits, 310 u32 bswapmask) = NULL; 311 312 switch (rect->rop) { 313 case ROP_XOR: 314 fill_op32 = bitfill_aligned_rev; 315 break; 316 case ROP_COPY: 317 fill_op32 = bitfill_aligned; 318 break; 319 default: 320 printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n"); 321 fill_op32 = bitfill_aligned; 322 break; 323 } 324 while (height--) { 325 dst += dst_idx >> (ffs(bits) - 1); 326 dst_idx &= (bits - 1); 327 fill_op32(p, dst, dst_idx, pat, width*bpp, bits, 328 bswapmask); 329 dst_idx += p->fix.line_length*8; 330 } 331 } else { 332 int right, r; 333 void (*fill_op)(struct fb_info *p, unsigned long __iomem *dst, 334 int dst_idx, unsigned long pat, int left, 335 int right, unsigned n, int bits) = NULL; 336 #ifdef __LITTLE_ENDIAN 337 right = left; 338 left = bpp - right; 339 #else 340 right = bpp - left; 341 #endif 342 switch (rect->rop) { 343 case ROP_XOR: 344 fill_op = bitfill_unaligned_rev; 345 break; 346 case ROP_COPY: 347 fill_op = bitfill_unaligned; 348 break; 349 default: 350 printk(KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n"); 351 fill_op = bitfill_unaligned; 352 break; 353 } 354 while (height--) { 355 dst += dst_idx / bits; 356 dst_idx &= (bits - 1); 357 r = dst_idx % bpp; 358 /* rotate pattern to the correct start position */ 359 pat2 = le_long_to_cpu(rolx(cpu_to_le_long(pat), r, bpp)); 360 fill_op(p, dst, dst_idx, pat2, left, right, 361 width*bpp, bits); 362 dst_idx += p->fix.line_length*8; 363 } 364 } 365 } 366 367 EXPORT_SYMBOL(cfb_fillrect); 368 369 MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>"); 370 MODULE_DESCRIPTION("Generic software accelerated fill rectangle"); 371 MODULE_LICENSE("GPL"); 372