1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * drivers/mb862xx/mb862xxfb_accel.c 4 * 5 * Fujitsu Carmine/Coral-P(A)/Lime framebuffer driver acceleration support 6 * 7 * (C) 2007 Alexander Shishkin <virtuoso@slind.org> 8 * (C) 2009 Valentin Sitdikov <v.sitdikov@gmail.com> 9 * (C) 2009 Siemens AG 10 */ 11 #include <linux/fb.h> 12 #include <linux/delay.h> 13 #include <linux/init.h> 14 #include <linux/interrupt.h> 15 #include <linux/module.h> 16 #include <linux/pci.h> 17 #include <linux/slab.h> 18 19 #include "mb862xxfb.h" 20 #include "mb862xx_reg.h" 21 #include "mb862xxfb_accel.h" 22 23 static void mb862xxfb_write_fifo(u32 count, u32 *data, struct fb_info *info) 24 { 25 struct mb862xxfb_par *par = info->par; 26 static u32 free; 27 28 u32 total = 0; 29 while (total < count) { 30 if (free) { 31 outreg(geo, GDC_GEO_REG_INPUT_FIFO, data[total]); 32 total++; 33 free--; 34 } else { 35 free = (u32) inreg(draw, GDC_REG_FIFO_COUNT); 36 } 37 } 38 } 39 40 static void mb86290fb_copyarea(struct fb_info *info, 41 const struct fb_copyarea *area) 42 { 43 __u32 cmd[6]; 44 45 cmd[0] = (GDC_TYPE_SETREGISTER << 24) | (1 << 16) | GDC_REG_MODE_BITMAP; 46 /* Set raster operation */ 47 cmd[1] = (2 << 7) | (GDC_ROP_COPY << 9); 48 cmd[2] = GDC_TYPE_BLTCOPYP << 24; 49 50 if (area->sx >= area->dx && area->sy >= area->dy) 51 cmd[2] |= GDC_CMD_BLTCOPY_TOP_LEFT << 16; 52 else if (area->sx >= area->dx && area->sy <= area->dy) 53 cmd[2] |= GDC_CMD_BLTCOPY_BOTTOM_LEFT << 16; 54 else if (area->sx <= area->dx && area->sy >= area->dy) 55 cmd[2] |= GDC_CMD_BLTCOPY_TOP_RIGHT << 16; 56 else 57 cmd[2] |= GDC_CMD_BLTCOPY_BOTTOM_RIGHT << 16; 58 59 cmd[3] = (area->sy << 16) | area->sx; 60 cmd[4] = (area->dy << 16) | area->dx; 61 cmd[5] = (area->height << 16) | area->width; 62 mb862xxfb_write_fifo(6, cmd, info); 63 } 64 65 /* 66 * Fill in the cmd array /GDC FIFO commands/ to draw a 1bit image. 67 * Make sure cmd has enough room! 68 */ 69 static void mb86290fb_imageblit1(u32 *cmd, u16 step, u16 dx, u16 dy, 70 u16 width, u16 height, u32 fgcolor, 71 u32 bgcolor, const struct fb_image *image, 72 struct fb_info *info) 73 { 74 int i; 75 unsigned const char *line; 76 u16 bytes; 77 78 /* set colors and raster operation regs */ 79 cmd[0] = (GDC_TYPE_SETREGISTER << 24) | (1 << 16) | GDC_REG_MODE_BITMAP; 80 /* Set raster operation */ 81 cmd[1] = (2 << 7) | (GDC_ROP_COPY << 9); 82 cmd[2] = 83 (GDC_TYPE_SETCOLORREGISTER << 24) | (GDC_CMD_BODY_FORE_COLOR << 16); 84 cmd[3] = fgcolor; 85 cmd[4] = 86 (GDC_TYPE_SETCOLORREGISTER << 24) | (GDC_CMD_BODY_BACK_COLOR << 16); 87 cmd[5] = bgcolor; 88 89 i = 0; 90 line = image->data; 91 bytes = (image->width + 7) >> 3; 92 93 /* and the image */ 94 cmd[6] = (GDC_TYPE_DRAWBITMAPP << 24) | 95 (GDC_CMD_BITMAP << 16) | (2 + (step * height)); 96 cmd[7] = (dy << 16) | dx; 97 cmd[8] = (height << 16) | width; 98 99 while (i < height) { 100 memcpy(&cmd[9 + i * step], line, step << 2); 101 #ifdef __LITTLE_ENDIAN 102 { 103 int k = 0; 104 for (k = 0; k < step; k++) 105 cmd[9 + i * step + k] = 106 cpu_to_be32(cmd[9 + i * step + k]); 107 } 108 #endif 109 line += bytes; 110 i++; 111 } 112 } 113 114 /* 115 * Fill in the cmd array /GDC FIFO commands/ to draw a 8bit image. 116 * Make sure cmd has enough room! 117 */ 118 static void mb86290fb_imageblit8(u32 *cmd, u16 step, u16 dx, u16 dy, 119 u16 width, u16 height, u32 fgcolor, 120 u32 bgcolor, const struct fb_image *image, 121 struct fb_info *info) 122 { 123 int i, j; 124 unsigned const char *line, *ptr; 125 u16 bytes; 126 127 cmd[0] = (GDC_TYPE_DRAWBITMAPP << 24) | 128 (GDC_CMD_BLT_DRAW << 16) | (2 + (height * step)); 129 cmd[1] = (dy << 16) | dx; 130 cmd[2] = (height << 16) | width; 131 132 i = 0; 133 line = image->data; 134 bytes = image->width; 135 136 while (i < height) { 137 ptr = line; 138 for (j = 0; j < step; j++) { 139 cmd[3 + i * step + j] = 140 (((u32 *) (info->pseudo_palette))[*ptr]) & 0xffff; 141 ptr++; 142 cmd[3 + i * step + j] |= 143 ((((u32 *) (info-> 144 pseudo_palette))[*ptr]) & 0xffff) << 16; 145 ptr++; 146 } 147 148 line += bytes; 149 i++; 150 } 151 } 152 153 /* 154 * Fill in the cmd array /GDC FIFO commands/ to draw a 16bit image. 155 * Make sure cmd has enough room! 156 */ 157 static void mb86290fb_imageblit16(u32 *cmd, u16 step, u16 dx, u16 dy, 158 u16 width, u16 height, u32 fgcolor, 159 u32 bgcolor, const struct fb_image *image, 160 struct fb_info *info) 161 { 162 int i; 163 unsigned const char *line; 164 u16 bytes; 165 166 i = 0; 167 line = image->data; 168 bytes = image->width << 1; 169 170 cmd[0] = (GDC_TYPE_DRAWBITMAPP << 24) | 171 (GDC_CMD_BLT_DRAW << 16) | (2 + step * height); 172 cmd[1] = (dy << 16) | dx; 173 cmd[2] = (height << 16) | width; 174 175 while (i < height) { 176 memcpy(&cmd[3 + i * step], line, step); 177 line += bytes; 178 i++; 179 } 180 } 181 182 static void mb86290fb_imageblit(struct fb_info *info, 183 const struct fb_image *image) 184 { 185 u32 *cmd = NULL; 186 void (*cmdfn) (u32 *, u16, u16, u16, u16, u16, u32, u32, 187 const struct fb_image *, struct fb_info *) = NULL; 188 u32 cmdlen; 189 u32 fgcolor = 0, bgcolor = 0; 190 u16 step; 191 192 u16 width = image->width, height = image->height; 193 u16 dx = image->dx, dy = image->dy; 194 int x2, y2, vxres, vyres; 195 196 x2 = image->dx + image->width; 197 y2 = image->dy + image->height; 198 vxres = info->var.xres_virtual; 199 vyres = info->var.yres_virtual; 200 x2 = min(x2, vxres); 201 y2 = min(y2, vyres); 202 width = x2 - dx; 203 height = y2 - dy; 204 205 switch (image->depth) { 206 case 1: 207 step = (width + 31) >> 5; 208 cmdlen = 9 + height * step; 209 cmdfn = mb86290fb_imageblit1; 210 if (info->fix.visual == FB_VISUAL_TRUECOLOR || 211 info->fix.visual == FB_VISUAL_DIRECTCOLOR) { 212 fgcolor = 213 ((u32 *) (info->pseudo_palette))[image->fg_color]; 214 bgcolor = 215 ((u32 *) (info->pseudo_palette))[image->bg_color]; 216 } else { 217 fgcolor = image->fg_color; 218 bgcolor = image->bg_color; 219 } 220 221 break; 222 223 case 8: 224 step = (width + 1) >> 1; 225 cmdlen = 3 + height * step; 226 cmdfn = mb86290fb_imageblit8; 227 break; 228 229 case 16: 230 step = (width + 1) >> 1; 231 cmdlen = 3 + height * step; 232 cmdfn = mb86290fb_imageblit16; 233 break; 234 235 default: 236 cfb_imageblit(info, image); 237 return; 238 } 239 240 cmd = kmalloc_array(cmdlen, 4, GFP_DMA); 241 if (!cmd) 242 return cfb_imageblit(info, image); 243 cmdfn(cmd, step, dx, dy, width, height, fgcolor, bgcolor, image, info); 244 mb862xxfb_write_fifo(cmdlen, cmd, info); 245 kfree(cmd); 246 } 247 248 static void mb86290fb_fillrect(struct fb_info *info, 249 const struct fb_fillrect *rect) 250 { 251 252 u32 x2, y2, vxres, vyres, height, width, fg; 253 u32 cmd[7]; 254 255 vxres = info->var.xres_virtual; 256 vyres = info->var.yres_virtual; 257 258 if (!rect->width || !rect->height || rect->dx > vxres 259 || rect->dy > vyres) 260 return; 261 262 /* We could use hardware clipping but on many cards you get around 263 * hardware clipping by writing to framebuffer directly. */ 264 x2 = rect->dx + rect->width; 265 y2 = rect->dy + rect->height; 266 x2 = min(x2, vxres); 267 y2 = min(y2, vyres); 268 width = x2 - rect->dx; 269 height = y2 - rect->dy; 270 if (info->fix.visual == FB_VISUAL_TRUECOLOR || 271 info->fix.visual == FB_VISUAL_DIRECTCOLOR) 272 fg = ((u32 *) (info->pseudo_palette))[rect->color]; 273 else 274 fg = rect->color; 275 276 switch (rect->rop) { 277 278 case ROP_XOR: 279 /* Set raster operation */ 280 cmd[1] = (2 << 7) | (GDC_ROP_XOR << 9); 281 break; 282 283 case ROP_COPY: 284 /* Set raster operation */ 285 cmd[1] = (2 << 7) | (GDC_ROP_COPY << 9); 286 break; 287 288 } 289 290 cmd[0] = (GDC_TYPE_SETREGISTER << 24) | (1 << 16) | GDC_REG_MODE_BITMAP; 291 /* cmd[1] set earlier */ 292 cmd[2] = 293 (GDC_TYPE_SETCOLORREGISTER << 24) | (GDC_CMD_BODY_FORE_COLOR << 16); 294 cmd[3] = fg; 295 cmd[4] = (GDC_TYPE_DRAWRECTP << 24) | (GDC_CMD_BLT_FILL << 16); 296 cmd[5] = (rect->dy << 16) | (rect->dx); 297 cmd[6] = (height << 16) | width; 298 299 mb862xxfb_write_fifo(7, cmd, info); 300 } 301 302 void mb862xxfb_init_accel(struct fb_info *info, struct fb_ops *fbops, int xres) 303 { 304 struct mb862xxfb_par *par = info->par; 305 306 if (info->var.bits_per_pixel == 32) { 307 fbops->fb_fillrect = cfb_fillrect; 308 fbops->fb_copyarea = cfb_copyarea; 309 fbops->fb_imageblit = cfb_imageblit; 310 } else { 311 outreg(disp, GC_L0EM, 3); 312 fbops->fb_fillrect = mb86290fb_fillrect; 313 fbops->fb_copyarea = mb86290fb_copyarea; 314 fbops->fb_imageblit = mb86290fb_imageblit; 315 } 316 outreg(draw, GDC_REG_DRAW_BASE, 0); 317 outreg(draw, GDC_REG_MODE_MISC, 0x8000); 318 outreg(draw, GDC_REG_X_RESOLUTION, xres); 319 320 info->flags |= 321 FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT | 322 FBINFO_HWACCEL_IMAGEBLIT; 323 info->fix.accel = 0xff; /*FIXME: add right define */ 324 } 325 326 MODULE_LICENSE("GPL v2"); 327