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