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 = 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 u32 *cmd = NULL; 188 void (*cmdfn) (u32 *, u16, u16, u16, u16, u16, u32, u32, 189 const struct fb_image *, struct fb_info *) = NULL; 190 u32 cmdlen; 191 u32 fgcolor = 0, bgcolor = 0; 192 u16 step; 193 194 u16 width = image->width, height = image->height; 195 u16 dx = image->dx, dy = image->dy; 196 int x2, y2, vxres, vyres; 197 198 x2 = image->dx + image->width; 199 y2 = image->dy + image->height; 200 vxres = info->var.xres_virtual; 201 vyres = info->var.yres_virtual; 202 x2 = min(x2, vxres); 203 y2 = min(y2, vyres); 204 width = x2 - dx; 205 height = y2 - dy; 206 207 switch (image->depth) { 208 case 1: 209 step = (width + 31) >> 5; 210 cmdlen = 9 + height * step; 211 cmdfn = mb86290fb_imageblit1; 212 if (info->fix.visual == FB_VISUAL_TRUECOLOR || 213 info->fix.visual == FB_VISUAL_DIRECTCOLOR) { 214 fgcolor = 215 ((u32 *) (info->pseudo_palette))[image->fg_color]; 216 bgcolor = 217 ((u32 *) (info->pseudo_palette))[image->bg_color]; 218 } else { 219 fgcolor = image->fg_color; 220 bgcolor = image->bg_color; 221 } 222 223 break; 224 225 case 8: 226 step = (width + 1) >> 1; 227 cmdlen = 3 + height * step; 228 cmdfn = mb86290fb_imageblit8; 229 break; 230 231 case 16: 232 step = (width + 1) >> 1; 233 cmdlen = 3 + height * step; 234 cmdfn = mb86290fb_imageblit16; 235 break; 236 237 default: 238 cfb_imageblit(info, image); 239 return; 240 } 241 242 cmd = kmalloc_array(cmdlen, 4, GFP_DMA); 243 if (!cmd) 244 return cfb_imageblit(info, image); 245 cmdfn(cmd, step, dx, dy, width, height, fgcolor, bgcolor, image, info); 246 mb862xxfb_write_fifo(cmdlen, cmd, info); 247 kfree(cmd); 248 } 249 250 static void mb86290fb_fillrect(struct fb_info *info, 251 const struct fb_fillrect *rect) 252 { 253 254 u32 x2, y2, vxres, vyres, height, width, fg; 255 u32 cmd[7]; 256 257 vxres = info->var.xres_virtual; 258 vyres = info->var.yres_virtual; 259 260 if (!rect->width || !rect->height || rect->dx > vxres 261 || rect->dy > vyres) 262 return; 263 264 /* We could use hardware clipping but on many cards you get around 265 * hardware clipping by writing to framebuffer directly. */ 266 x2 = rect->dx + rect->width; 267 y2 = rect->dy + rect->height; 268 x2 = min(x2, vxres); 269 y2 = min(y2, vyres); 270 width = x2 - rect->dx; 271 height = y2 - rect->dy; 272 if (info->fix.visual == FB_VISUAL_TRUECOLOR || 273 info->fix.visual == FB_VISUAL_DIRECTCOLOR) 274 fg = ((u32 *) (info->pseudo_palette))[rect->color]; 275 else 276 fg = rect->color; 277 278 switch (rect->rop) { 279 280 case ROP_XOR: 281 /* Set raster operation */ 282 cmd[1] = (2 << 7) | (GDC_ROP_XOR << 9); 283 break; 284 285 case ROP_COPY: 286 /* Set raster operation */ 287 cmd[1] = (2 << 7) | (GDC_ROP_COPY << 9); 288 break; 289 290 } 291 292 cmd[0] = (GDC_TYPE_SETREGISTER << 24) | (1 << 16) | GDC_REG_MODE_BITMAP; 293 /* cmd[1] set earlier */ 294 cmd[2] = 295 (GDC_TYPE_SETCOLORREGISTER << 24) | (GDC_CMD_BODY_FORE_COLOR << 16); 296 cmd[3] = fg; 297 cmd[4] = (GDC_TYPE_DRAWRECTP << 24) | (GDC_CMD_BLT_FILL << 16); 298 cmd[5] = (rect->dy << 16) | (rect->dx); 299 cmd[6] = (height << 16) | width; 300 301 mb862xxfb_write_fifo(7, cmd, info); 302 } 303 304 void mb862xxfb_init_accel(struct fb_info *info, struct fb_ops *fbops, int xres) 305 { 306 struct mb862xxfb_par *par = info->par; 307 308 if (info->var.bits_per_pixel == 32) { 309 fbops->fb_fillrect = cfb_fillrect; 310 fbops->fb_copyarea = cfb_copyarea; 311 fbops->fb_imageblit = cfb_imageblit; 312 } else { 313 outreg(disp, GC_L0EM, 3); 314 fbops->fb_fillrect = mb86290fb_fillrect; 315 fbops->fb_copyarea = mb86290fb_copyarea; 316 fbops->fb_imageblit = mb86290fb_imageblit; 317 } 318 outreg(draw, GDC_REG_DRAW_BASE, 0); 319 outreg(draw, GDC_REG_MODE_MISC, 0x8000); 320 outreg(draw, GDC_REG_X_RESOLUTION, xres); 321 322 info->flags |= 323 FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT | 324 FBINFO_HWACCEL_IMAGEBLIT; 325 info->fix.accel = 0xff; /*FIXME: add right define */ 326 } 327 328 MODULE_LICENSE("GPL v2"); 329