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 * The code for depths like 24 that don't have integer number of pixels per 13 * long is broken and needs to be fixed. For now I turned these types of 14 * mode off. 15 * 16 * Also need to add code to deal with cards endians that are different than 17 * the native cpu endians. I also need to deal with MSB position in the word. 18 * 19 */ 20#include <linux/module.h> 21#include <linux/string.h> 22#include <linux/fb.h> 23#include <asm/types.h> 24#include "fb_draw.h" 25 26#if BITS_PER_LONG == 32 27# define FB_WRITEL fb_writel 28# define FB_READL fb_readl 29#else 30# define FB_WRITEL fb_writeq 31# define FB_READL fb_readq 32#endif 33 34 /* 35 * Aligned pattern fill using 32/64-bit memory accesses 36 */ 37 38static void 39bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits) 40{ 41 unsigned long first, last; 42 43 if (!n) 44 return; 45 46 first = FB_SHIFT_HIGH(~0UL, dst_idx); 47 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); 48 49 if (dst_idx+n <= bits) { 50 // Single word 51 if (last) 52 first &= last; 53 FB_WRITEL(comp(pat, FB_READL(dst), first), dst); 54 } else { 55 // Multiple destination words 56 57 // Leading bits 58 if (first!= ~0UL) { 59 FB_WRITEL(comp(pat, FB_READL(dst), first), dst); 60 dst++; 61 n -= bits - dst_idx; 62 } 63 64 // Main chunk 65 n /= bits; 66 while (n >= 8) { 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 FB_WRITEL(pat, dst++); 73 FB_WRITEL(pat, dst++); 74 FB_WRITEL(pat, dst++); 75 n -= 8; 76 } 77 while (n--) 78 FB_WRITEL(pat, dst++); 79 80 // Trailing bits 81 if (last) 82 FB_WRITEL(comp(pat, FB_READL(dst), last), dst); 83 } 84} 85 86 87 /* 88 * Unaligned generic pattern fill using 32/64-bit memory accesses 89 * The pattern must have been expanded to a full 32/64-bit value 90 * Left/right are the appropriate shifts to convert to the pattern to be 91 * used for the next 32/64-bit word 92 */ 93 94static void 95bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, 96 int left, int right, unsigned n, int bits) 97{ 98 unsigned long first, last; 99 100 if (!n) 101 return; 102 103 first = FB_SHIFT_HIGH(~0UL, dst_idx); 104 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); 105 106 if (dst_idx+n <= bits) { 107 // Single word 108 if (last) 109 first &= last; 110 FB_WRITEL(comp(pat, FB_READL(dst), first), dst); 111 } else { 112 // Multiple destination words 113 // Leading bits 114 if (first) { 115 FB_WRITEL(comp(pat, FB_READL(dst), first), dst); 116 dst++; 117 pat = pat << left | pat >> right; 118 n -= bits - dst_idx; 119 } 120 121 // Main chunk 122 n /= bits; 123 while (n >= 4) { 124 FB_WRITEL(pat, dst++); 125 pat = pat << left | pat >> right; 126 FB_WRITEL(pat, dst++); 127 pat = pat << left | pat >> right; 128 FB_WRITEL(pat, dst++); 129 pat = pat << left | pat >> right; 130 FB_WRITEL(pat, dst++); 131 pat = pat << left | pat >> right; 132 n -= 4; 133 } 134 while (n--) { 135 FB_WRITEL(pat, dst++); 136 pat = pat << left | pat >> right; 137 } 138 139 // Trailing bits 140 if (last) 141 FB_WRITEL(comp(pat, FB_READL(dst), first), dst); 142 } 143} 144 145 /* 146 * Aligned pattern invert using 32/64-bit memory accesses 147 */ 148static void 149bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits) 150{ 151 unsigned long val = pat, dat; 152 unsigned long first, last; 153 154 if (!n) 155 return; 156 157 first = FB_SHIFT_HIGH(~0UL, dst_idx); 158 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); 159 160 if (dst_idx+n <= bits) { 161 // Single word 162 if (last) 163 first &= last; 164 dat = FB_READL(dst); 165 FB_WRITEL(comp(dat ^ val, dat, first), dst); 166 } else { 167 // Multiple destination words 168 // Leading bits 169 if (first!=0UL) { 170 dat = FB_READL(dst); 171 FB_WRITEL(comp(dat ^ val, dat, first), dst); 172 dst++; 173 n -= bits - dst_idx; 174 } 175 176 // Main chunk 177 n /= bits; 178 while (n >= 8) { 179 FB_WRITEL(FB_READL(dst) ^ val, dst); 180 dst++; 181 FB_WRITEL(FB_READL(dst) ^ val, dst); 182 dst++; 183 FB_WRITEL(FB_READL(dst) ^ val, dst); 184 dst++; 185 FB_WRITEL(FB_READL(dst) ^ val, dst); 186 dst++; 187 FB_WRITEL(FB_READL(dst) ^ val, dst); 188 dst++; 189 FB_WRITEL(FB_READL(dst) ^ val, dst); 190 dst++; 191 FB_WRITEL(FB_READL(dst) ^ val, dst); 192 dst++; 193 FB_WRITEL(FB_READL(dst) ^ val, dst); 194 dst++; 195 n -= 8; 196 } 197 while (n--) { 198 FB_WRITEL(FB_READL(dst) ^ val, dst); 199 dst++; 200 } 201 // Trailing bits 202 if (last) { 203 dat = FB_READL(dst); 204 FB_WRITEL(comp(dat ^ val, dat, last), dst); 205 } 206 } 207} 208 209 210 /* 211 * Unaligned generic pattern invert using 32/64-bit memory accesses 212 * The pattern must have been expanded to a full 32/64-bit value 213 * Left/right are the appropriate shifts to convert to the pattern to be 214 * used for the next 32/64-bit word 215 */ 216 217static void 218bitfill_unaligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, 219 int left, int right, unsigned n, int bits) 220{ 221 unsigned long first, last, dat; 222 223 if (!n) 224 return; 225 226 first = FB_SHIFT_HIGH(~0UL, dst_idx); 227 last = ~(FB_SHIFT_HIGH(~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 278void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) 279{ 280 unsigned long pat, 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 left = bits % bpp; 302 if (p->fbops->fb_sync) 303 p->fbops->fb_sync(p); 304 if (!left) { 305 void (*fill_op32)(unsigned long __iomem *dst, int dst_idx, 306 unsigned long pat, unsigned n, int bits) = NULL; 307 308 switch (rect->rop) { 309 case ROP_XOR: 310 fill_op32 = bitfill_aligned_rev; 311 break; 312 case ROP_COPY: 313 fill_op32 = bitfill_aligned; 314 break; 315 default: 316 printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n"); 317 fill_op32 = bitfill_aligned; 318 break; 319 } 320 while (height--) { 321 dst += dst_idx >> (ffs(bits) - 1); 322 dst_idx &= (bits - 1); 323 fill_op32(dst, dst_idx, pat, width*bpp, bits); 324 dst_idx += p->fix.line_length*8; 325 } 326 } else { 327 int right; 328 int r; 329 int rot = (left-dst_idx) % bpp; 330 void (*fill_op)(unsigned long __iomem *dst, int dst_idx, 331 unsigned long pat, int left, int right, 332 unsigned n, int bits) = NULL; 333 334 /* rotate pattern to correct start position */ 335 pat = pat << rot | pat >> (bpp-rot); 336 337 right = bpp-left; 338 switch (rect->rop) { 339 case ROP_XOR: 340 fill_op = bitfill_unaligned_rev; 341 break; 342 case ROP_COPY: 343 fill_op = bitfill_unaligned; 344 break; 345 default: 346 printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n"); 347 fill_op = bitfill_unaligned; 348 break; 349 } 350 while (height--) { 351 dst += dst_idx >> (ffs(bits) - 1); 352 dst_idx &= (bits - 1); 353 fill_op(dst, dst_idx, pat, left, right, 354 width*bpp, bits); 355 r = (p->fix.line_length*8) % bpp; 356 pat = pat << (bpp-r) | pat >> r; 357 dst_idx += p->fix.line_length*8; 358 } 359 } 360} 361 362EXPORT_SYMBOL(cfb_fillrect); 363 364MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>"); 365MODULE_DESCRIPTION("Generic software accelerated fill rectangle"); 366MODULE_LICENSE("GPL"); 367