0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/fb.h>
0012 #include <linux/delay.h>
0013 #include <linux/init.h>
0014 #include <linux/interrupt.h>
0015 #include <linux/module.h>
0016 #include <linux/pci.h>
0017 #include <linux/slab.h>
0018 #if defined(CONFIG_OF)
0019 #include <linux/of_platform.h>
0020 #endif
0021 #include "mb862xxfb.h"
0022 #include "mb862xx_reg.h"
0023 #include "mb862xxfb_accel.h"
0024
0025 static void mb862xxfb_write_fifo(u32 count, u32 *data, struct fb_info *info)
0026 {
0027 struct mb862xxfb_par *par = info->par;
0028 static u32 free;
0029
0030 u32 total = 0;
0031 while (total < count) {
0032 if (free) {
0033 outreg(geo, GDC_GEO_REG_INPUT_FIFO, data[total]);
0034 total++;
0035 free--;
0036 } else {
0037 free = (u32) inreg(draw, GDC_REG_FIFO_COUNT);
0038 }
0039 }
0040 }
0041
0042 static void mb86290fb_copyarea(struct fb_info *info,
0043 const struct fb_copyarea *area)
0044 {
0045 __u32 cmd[6];
0046
0047 cmd[0] = (GDC_TYPE_SETREGISTER << 24) | (1 << 16) | GDC_REG_MODE_BITMAP;
0048
0049 cmd[1] = (2 << 7) | (GDC_ROP_COPY << 9);
0050 cmd[2] = GDC_TYPE_BLTCOPYP << 24;
0051
0052 if (area->sx >= area->dx && area->sy >= area->dy)
0053 cmd[2] |= GDC_CMD_BLTCOPY_TOP_LEFT << 16;
0054 else if (area->sx >= area->dx && area->sy <= area->dy)
0055 cmd[2] |= GDC_CMD_BLTCOPY_BOTTOM_LEFT << 16;
0056 else if (area->sx <= area->dx && area->sy >= area->dy)
0057 cmd[2] |= GDC_CMD_BLTCOPY_TOP_RIGHT << 16;
0058 else
0059 cmd[2] |= GDC_CMD_BLTCOPY_BOTTOM_RIGHT << 16;
0060
0061 cmd[3] = (area->sy << 16) | area->sx;
0062 cmd[4] = (area->dy << 16) | area->dx;
0063 cmd[5] = (area->height << 16) | area->width;
0064 mb862xxfb_write_fifo(6, cmd, info);
0065 }
0066
0067
0068
0069
0070
0071 static void mb86290fb_imageblit1(u32 *cmd, u16 step, u16 dx, u16 dy,
0072 u16 width, u16 height, u32 fgcolor,
0073 u32 bgcolor, const struct fb_image *image,
0074 struct fb_info *info)
0075 {
0076 int i;
0077 unsigned const char *line;
0078 u16 bytes;
0079
0080
0081 cmd[0] = (GDC_TYPE_SETREGISTER << 24) | (1 << 16) | GDC_REG_MODE_BITMAP;
0082
0083 cmd[1] = (2 << 7) | (GDC_ROP_COPY << 9);
0084 cmd[2] =
0085 (GDC_TYPE_SETCOLORREGISTER << 24) | (GDC_CMD_BODY_FORE_COLOR << 16);
0086 cmd[3] = fgcolor;
0087 cmd[4] =
0088 (GDC_TYPE_SETCOLORREGISTER << 24) | (GDC_CMD_BODY_BACK_COLOR << 16);
0089 cmd[5] = bgcolor;
0090
0091 i = 0;
0092 line = image->data;
0093 bytes = (image->width + 7) >> 3;
0094
0095
0096 cmd[6] = (GDC_TYPE_DRAWBITMAPP << 24) |
0097 (GDC_CMD_BITMAP << 16) | (2 + (step * height));
0098 cmd[7] = (dy << 16) | dx;
0099 cmd[8] = (height << 16) | width;
0100
0101 while (i < height) {
0102 memcpy(&cmd[9 + i * step], line, step << 2);
0103 #ifdef __LITTLE_ENDIAN
0104 {
0105 int k = 0;
0106 for (k = 0; k < step; k++)
0107 cmd[9 + i * step + k] =
0108 cpu_to_be32(cmd[9 + i * step + k]);
0109 }
0110 #endif
0111 line += bytes;
0112 i++;
0113 }
0114 }
0115
0116
0117
0118
0119
0120 static void mb86290fb_imageblit8(u32 *cmd, u16 step, u16 dx, u16 dy,
0121 u16 width, u16 height, u32 fgcolor,
0122 u32 bgcolor, const struct fb_image *image,
0123 struct fb_info *info)
0124 {
0125 int i, j;
0126 unsigned const char *line, *ptr;
0127 u16 bytes;
0128
0129 cmd[0] = (GDC_TYPE_DRAWBITMAPP << 24) |
0130 (GDC_CMD_BLT_DRAW << 16) | (2 + (height * step));
0131 cmd[1] = (dy << 16) | dx;
0132 cmd[2] = (height << 16) | width;
0133
0134 i = 0;
0135 line = image->data;
0136 bytes = image->width;
0137
0138 while (i < height) {
0139 ptr = line;
0140 for (j = 0; j < step; j++) {
0141 cmd[3 + i * step + j] =
0142 (((u32 *) (info->pseudo_palette))[*ptr]) & 0xffff;
0143 ptr++;
0144 cmd[3 + i * step + j] |=
0145 ((((u32 *) (info->
0146 pseudo_palette))[*ptr]) & 0xffff) << 16;
0147 ptr++;
0148 }
0149
0150 line += bytes;
0151 i++;
0152 }
0153 }
0154
0155
0156
0157
0158
0159 static void mb86290fb_imageblit16(u32 *cmd, u16 step, u16 dx, u16 dy,
0160 u16 width, u16 height, u32 fgcolor,
0161 u32 bgcolor, const struct fb_image *image,
0162 struct fb_info *info)
0163 {
0164 int i;
0165 unsigned const char *line;
0166 u16 bytes;
0167
0168 i = 0;
0169 line = image->data;
0170 bytes = image->width << 1;
0171
0172 cmd[0] = (GDC_TYPE_DRAWBITMAPP << 24) |
0173 (GDC_CMD_BLT_DRAW << 16) | (2 + step * height);
0174 cmd[1] = (dy << 16) | dx;
0175 cmd[2] = (height << 16) | width;
0176
0177 while (i < height) {
0178 memcpy(&cmd[3 + i * step], line, step);
0179 line += bytes;
0180 i++;
0181 }
0182 }
0183
0184 static void mb86290fb_imageblit(struct fb_info *info,
0185 const struct fb_image *image)
0186 {
0187 u32 *cmd = NULL;
0188 void (*cmdfn) (u32 *, u16, u16, u16, u16, u16, u32, u32,
0189 const struct fb_image *, struct fb_info *) = NULL;
0190 u32 cmdlen;
0191 u32 fgcolor = 0, bgcolor = 0;
0192 u16 step;
0193
0194 u16 width = image->width, height = image->height;
0195 u16 dx = image->dx, dy = image->dy;
0196 int x2, y2, vxres, vyres;
0197
0198 x2 = image->dx + image->width;
0199 y2 = image->dy + image->height;
0200 vxres = info->var.xres_virtual;
0201 vyres = info->var.yres_virtual;
0202 x2 = min(x2, vxres);
0203 y2 = min(y2, vyres);
0204 width = x2 - dx;
0205 height = y2 - dy;
0206
0207 switch (image->depth) {
0208 case 1:
0209 step = (width + 31) >> 5;
0210 cmdlen = 9 + height * step;
0211 cmdfn = mb86290fb_imageblit1;
0212 if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
0213 info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
0214 fgcolor =
0215 ((u32 *) (info->pseudo_palette))[image->fg_color];
0216 bgcolor =
0217 ((u32 *) (info->pseudo_palette))[image->bg_color];
0218 } else {
0219 fgcolor = image->fg_color;
0220 bgcolor = image->bg_color;
0221 }
0222
0223 break;
0224
0225 case 8:
0226 step = (width + 1) >> 1;
0227 cmdlen = 3 + height * step;
0228 cmdfn = mb86290fb_imageblit8;
0229 break;
0230
0231 case 16:
0232 step = (width + 1) >> 1;
0233 cmdlen = 3 + height * step;
0234 cmdfn = mb86290fb_imageblit16;
0235 break;
0236
0237 default:
0238 cfb_imageblit(info, image);
0239 return;
0240 }
0241
0242 cmd = kmalloc_array(cmdlen, 4, GFP_DMA);
0243 if (!cmd)
0244 return cfb_imageblit(info, image);
0245 cmdfn(cmd, step, dx, dy, width, height, fgcolor, bgcolor, image, info);
0246 mb862xxfb_write_fifo(cmdlen, cmd, info);
0247 kfree(cmd);
0248 }
0249
0250 static void mb86290fb_fillrect(struct fb_info *info,
0251 const struct fb_fillrect *rect)
0252 {
0253
0254 u32 x2, y2, vxres, vyres, height, width, fg;
0255 u32 cmd[7];
0256
0257 vxres = info->var.xres_virtual;
0258 vyres = info->var.yres_virtual;
0259
0260 if (!rect->width || !rect->height || rect->dx > vxres
0261 || rect->dy > vyres)
0262 return;
0263
0264
0265
0266 x2 = rect->dx + rect->width;
0267 y2 = rect->dy + rect->height;
0268 x2 = min(x2, vxres);
0269 y2 = min(y2, vyres);
0270 width = x2 - rect->dx;
0271 height = y2 - rect->dy;
0272 if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
0273 info->fix.visual == FB_VISUAL_DIRECTCOLOR)
0274 fg = ((u32 *) (info->pseudo_palette))[rect->color];
0275 else
0276 fg = rect->color;
0277
0278 switch (rect->rop) {
0279
0280 case ROP_XOR:
0281
0282 cmd[1] = (2 << 7) | (GDC_ROP_XOR << 9);
0283 break;
0284
0285 case ROP_COPY:
0286
0287 cmd[1] = (2 << 7) | (GDC_ROP_COPY << 9);
0288 break;
0289
0290 }
0291
0292 cmd[0] = (GDC_TYPE_SETREGISTER << 24) | (1 << 16) | GDC_REG_MODE_BITMAP;
0293
0294 cmd[2] =
0295 (GDC_TYPE_SETCOLORREGISTER << 24) | (GDC_CMD_BODY_FORE_COLOR << 16);
0296 cmd[3] = fg;
0297 cmd[4] = (GDC_TYPE_DRAWRECTP << 24) | (GDC_CMD_BLT_FILL << 16);
0298 cmd[5] = (rect->dy << 16) | (rect->dx);
0299 cmd[6] = (height << 16) | width;
0300
0301 mb862xxfb_write_fifo(7, cmd, info);
0302 }
0303
0304 void mb862xxfb_init_accel(struct fb_info *info, struct fb_ops *fbops, int xres)
0305 {
0306 struct mb862xxfb_par *par = info->par;
0307
0308 if (info->var.bits_per_pixel == 32) {
0309 fbops->fb_fillrect = cfb_fillrect;
0310 fbops->fb_copyarea = cfb_copyarea;
0311 fbops->fb_imageblit = cfb_imageblit;
0312 } else {
0313 outreg(disp, GC_L0EM, 3);
0314 fbops->fb_fillrect = mb86290fb_fillrect;
0315 fbops->fb_copyarea = mb86290fb_copyarea;
0316 fbops->fb_imageblit = mb86290fb_imageblit;
0317 }
0318 outreg(draw, GDC_REG_DRAW_BASE, 0);
0319 outreg(draw, GDC_REG_MODE_MISC, 0x8000);
0320 outreg(draw, GDC_REG_X_RESOLUTION, xres);
0321
0322 info->flags |=
0323 FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
0324 FBINFO_HWACCEL_IMAGEBLIT;
0325 info->fix.accel = 0xff;
0326 }
0327
0328 MODULE_LICENSE("GPL v2");