aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVincent Sanders <vince@simtec.co.uk>2009-12-15 19:46:35 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-16 10:20:04 -0500
commit9265576daeab1a884b11cc4c1087b72b488ca2e3 (patch)
treee21022eba5e75727ba51fde8d6198cc893dbcf18
parent2d72b11cd2f4f81d7f817c3795224061bcefdd9e (diff)
sm501: implement acceleration features
This patch provides the acceleration entry points for the SM501 framebuffer driver. This patch provides the sync, copyarea and fillrect entry points, using the SM501's 2D acceleration engine to perform the operations in-chip rather than across the bus. Signed-off-by: Ben Dooks <ben@simtec.co.uk> Signed-off-by: Simtec Linux Team <linux@simtec.co.uk> Signed-off-by: Vincent Sanders <vince@simtec.co.uk> Cc: Krzysztof Helt <krzysztof.h1@poczta.fm> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/video/sm501fb.c237
-rw-r--r--include/linux/sm501-regs.h2
2 files changed, 226 insertions, 13 deletions
diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c
index d1c8ea83b41f..35370d0ecf03 100644
--- a/drivers/video/sm501fb.c
+++ b/drivers/video/sm501fb.c
@@ -66,6 +66,7 @@ struct sm501fb_info {
66 struct fb_info *fb[2]; /* fb info for both heads */ 66 struct fb_info *fb[2]; /* fb info for both heads */
67 struct resource *fbmem_res; /* framebuffer resource */ 67 struct resource *fbmem_res; /* framebuffer resource */
68 struct resource *regs_res; /* registers resource */ 68 struct resource *regs_res; /* registers resource */
69 struct resource *regs2d_res; /* 2d registers resource */
69 struct sm501_platdata_fb *pdata; /* our platform data */ 70 struct sm501_platdata_fb *pdata; /* our platform data */
70 71
71 unsigned long pm_crt_ctrl; /* pm: crt ctrl save */ 72 unsigned long pm_crt_ctrl; /* pm: crt ctrl save */
@@ -73,6 +74,7 @@ struct sm501fb_info {
73 int irq; 74 int irq;
74 int swap_endian; /* set to swap rgb=>bgr */ 75 int swap_endian; /* set to swap rgb=>bgr */
75 void __iomem *regs; /* remapped registers */ 76 void __iomem *regs; /* remapped registers */
77 void __iomem *regs2d; /* 2d remapped registers */
76 void __iomem *fbmem; /* remapped framebuffer */ 78 void __iomem *fbmem; /* remapped framebuffer */
77 size_t fbmem_len; /* length of remapped region */ 79 size_t fbmem_len; /* length of remapped region */
78}; 80};
@@ -123,9 +125,9 @@ static inline void sm501fb_sync_regs(struct sm501fb_info *info)
123 * This is an attempt to lay out memory for the two framebuffers and 125 * This is an attempt to lay out memory for the two framebuffers and
124 * everything else 126 * everything else
125 * 127 *
126 * |fbmem_res->start fbmem_res->end| 128 * |fbmem_res->start fbmem_res->end|
127 * | | 129 * | |
128 * |fb[0].fix.smem_start | |fb[1].fix.smem_start | 2K | 130 * |fb[0].fix.smem_start | |fb[1].fix.smem_start | 2K |
129 * |-> fb[0].fix.smem_len <-| spare |-> fb[1].fix.smem_len <-|-> cursors <-| 131 * |-> fb[0].fix.smem_len <-| spare |-> fb[1].fix.smem_len <-|-> cursors <-|
130 * 132 *
131 * The "spare" space is for the 2d engine data 133 * The "spare" space is for the 2d engine data
@@ -1246,7 +1248,173 @@ static ssize_t sm501fb_debug_show_pnl(struct device *dev,
1246 1248
1247static DEVICE_ATTR(fbregs_pnl, 0444, sm501fb_debug_show_pnl, NULL); 1249static DEVICE_ATTR(fbregs_pnl, 0444, sm501fb_debug_show_pnl, NULL);
1248 1250
1249/* framebuffer ops */ 1251/* acceleration operations */
1252static int sm501fb_sync(struct fb_info *info)
1253{
1254 int count = 1000000;
1255 struct sm501fb_par *par = info->par;
1256 struct sm501fb_info *fbi = par->info;
1257
1258 /* wait for the 2d engine to be ready */
1259 while ((count > 0) &&
1260 (readl(fbi->regs + SM501_SYSTEM_CONTROL) &
1261 SM501_SYSCTRL_2D_ENGINE_STATUS) != 0)
1262 count--;
1263
1264 if (count <= 0) {
1265 dev_err(info->dev, "Timeout waiting for 2d engine sync\n");
1266 return 1;
1267 }
1268 return 0;
1269}
1270
1271static void sm501fb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
1272{
1273 struct sm501fb_par *par = info->par;
1274 struct sm501fb_info *fbi = par->info;
1275 int width = area->width;
1276 int height = area->height;
1277 int sx = area->sx;
1278 int sy = area->sy;
1279 int dx = area->dx;
1280 int dy = area->dy;
1281 unsigned long rtl = 0;
1282
1283 /* source clip */
1284 if ((sx >= info->var.xres_virtual) ||
1285 (sy >= info->var.yres_virtual))
1286 /* source Area not within virtual screen, skipping */
1287 return;
1288 if ((sx + width) >= info->var.xres_virtual)
1289 width = info->var.xres_virtual - sx - 1;
1290 if ((sy + height) >= info->var.yres_virtual)
1291 height = info->var.yres_virtual - sy - 1;
1292
1293 /* dest clip */
1294 if ((dx >= info->var.xres_virtual) ||
1295 (dy >= info->var.yres_virtual))
1296 /* Destination Area not within virtual screen, skipping */
1297 return;
1298 if ((dx + width) >= info->var.xres_virtual)
1299 width = info->var.xres_virtual - dx - 1;
1300 if ((dy + height) >= info->var.yres_virtual)
1301 height = info->var.yres_virtual - dy - 1;
1302
1303 if ((sx < dx) || (sy < dy)) {
1304 rtl = 1 << 27;
1305 sx += width - 1;
1306 dx += width - 1;
1307 sy += height - 1;
1308 dy += height - 1;
1309 }
1310
1311 if (sm501fb_sync(info))
1312 return;
1313
1314 /* set the base addresses */
1315 writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE);
1316 writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_DESTINATION_BASE);
1317
1318 /* set the window width */
1319 writel((info->var.xres << 16) | info->var.xres,
1320 fbi->regs2d + SM501_2D_WINDOW_WIDTH);
1321
1322 /* set window stride */
1323 writel((info->var.xres_virtual << 16) | info->var.xres_virtual,
1324 fbi->regs2d + SM501_2D_PITCH);
1325
1326 /* set data format */
1327 switch (info->var.bits_per_pixel) {
1328 case 8:
1329 writel(0, fbi->regs2d + SM501_2D_STRETCH);
1330 break;
1331 case 16:
1332 writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH);
1333 break;
1334 case 32:
1335 writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH);
1336 break;
1337 }
1338
1339 /* 2d compare mask */
1340 writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK);
1341
1342 /* 2d mask */
1343 writel(0xffffffff, fbi->regs2d + SM501_2D_MASK);
1344
1345 /* source and destination x y */
1346 writel((sx << 16) | sy, fbi->regs2d + SM501_2D_SOURCE);
1347 writel((dx << 16) | dy, fbi->regs2d + SM501_2D_DESTINATION);
1348
1349 /* w/h */
1350 writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION);
1351
1352 /* do area move */
1353 writel(0x800000cc | rtl, fbi->regs2d + SM501_2D_CONTROL);
1354}
1355
1356static void sm501fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
1357{
1358 struct sm501fb_par *par = info->par;
1359 struct sm501fb_info *fbi = par->info;
1360 int width = rect->width, height = rect->height;
1361
1362 if ((rect->dx >= info->var.xres_virtual) ||
1363 (rect->dy >= info->var.yres_virtual))
1364 /* Rectangle not within virtual screen, skipping */
1365 return;
1366 if ((rect->dx + width) >= info->var.xres_virtual)
1367 width = info->var.xres_virtual - rect->dx - 1;
1368 if ((rect->dy + height) >= info->var.yres_virtual)
1369 height = info->var.yres_virtual - rect->dy - 1;
1370
1371 if (sm501fb_sync(info))
1372 return;
1373
1374 /* set the base addresses */
1375 writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE);
1376 writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_DESTINATION_BASE);
1377
1378 /* set the window width */
1379 writel((info->var.xres << 16) | info->var.xres,
1380 fbi->regs2d + SM501_2D_WINDOW_WIDTH);
1381
1382 /* set window stride */
1383 writel((info->var.xres_virtual << 16) | info->var.xres_virtual,
1384 fbi->regs2d + SM501_2D_PITCH);
1385
1386 /* set data format */
1387 switch (info->var.bits_per_pixel) {
1388 case 8:
1389 writel(0, fbi->regs2d + SM501_2D_STRETCH);
1390 break;
1391 case 16:
1392 writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH);
1393 break;
1394 case 32:
1395 writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH);
1396 break;
1397 }
1398
1399 /* 2d compare mask */
1400 writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK);
1401
1402 /* 2d mask */
1403 writel(0xffffffff, fbi->regs2d + SM501_2D_MASK);
1404
1405 /* colour */
1406 writel(rect->color, fbi->regs2d + SM501_2D_FOREGROUND);
1407
1408 /* x y */
1409 writel((rect->dx << 16) | rect->dy, fbi->regs2d + SM501_2D_DESTINATION);
1410
1411 /* w/h */
1412 writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION);
1413
1414 /* do rectangle fill */
1415 writel(0x800100cc, fbi->regs2d + SM501_2D_CONTROL);
1416}
1417
1250 1418
1251static struct fb_ops sm501fb_ops_crt = { 1419static struct fb_ops sm501fb_ops_crt = {
1252 .owner = THIS_MODULE, 1420 .owner = THIS_MODULE,
@@ -1256,9 +1424,10 @@ static struct fb_ops sm501fb_ops_crt = {
1256 .fb_setcolreg = sm501fb_setcolreg, 1424 .fb_setcolreg = sm501fb_setcolreg,
1257 .fb_pan_display = sm501fb_pan_crt, 1425 .fb_pan_display = sm501fb_pan_crt,
1258 .fb_cursor = sm501fb_cursor, 1426 .fb_cursor = sm501fb_cursor,
1259 .fb_fillrect = cfb_fillrect, 1427 .fb_fillrect = sm501fb_fillrect,
1260 .fb_copyarea = cfb_copyarea, 1428 .fb_copyarea = sm501fb_copyarea,
1261 .fb_imageblit = cfb_imageblit, 1429 .fb_imageblit = cfb_imageblit,
1430 .fb_sync = sm501fb_sync,
1262}; 1431};
1263 1432
1264static struct fb_ops sm501fb_ops_pnl = { 1433static struct fb_ops sm501fb_ops_pnl = {
@@ -1269,9 +1438,10 @@ static struct fb_ops sm501fb_ops_pnl = {
1269 .fb_blank = sm501fb_blank_pnl, 1438 .fb_blank = sm501fb_blank_pnl,
1270 .fb_setcolreg = sm501fb_setcolreg, 1439 .fb_setcolreg = sm501fb_setcolreg,
1271 .fb_cursor = sm501fb_cursor, 1440 .fb_cursor = sm501fb_cursor,
1272 .fb_fillrect = cfb_fillrect, 1441 .fb_fillrect = sm501fb_fillrect,
1273 .fb_copyarea = cfb_copyarea, 1442 .fb_copyarea = sm501fb_copyarea,
1274 .fb_imageblit = cfb_imageblit, 1443 .fb_imageblit = cfb_imageblit,
1444 .fb_sync = sm501fb_sync,
1275}; 1445};
1276 1446
1277/* sm501_init_cursor 1447/* sm501_init_cursor
@@ -1329,7 +1499,8 @@ static int sm501fb_start(struct sm501fb_info *info,
1329 dev_warn(dev, "no irq for device\n"); 1499 dev_warn(dev, "no irq for device\n");
1330 } 1500 }
1331 1501
1332 /* allocate, reserve and remap resources for registers */ 1502 /* allocate, reserve and remap resources for display
1503 * controller registers */
1333 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1504 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1334 if (res == NULL) { 1505 if (res == NULL) {
1335 dev_err(dev, "no resource definition for registers\n"); 1506 dev_err(dev, "no resource definition for registers\n");
@@ -1354,12 +1525,38 @@ static int sm501fb_start(struct sm501fb_info *info,
1354 goto err_regs_res; 1525 goto err_regs_res;
1355 } 1526 }
1356 1527
1528 /* allocate, reserve and remap resources for 2d
1529 * controller registers */
1530 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
1531 if (res == NULL) {
1532 dev_err(dev, "no resource definition for 2d registers\n");
1533 ret = -ENOENT;
1534 goto err_regs_map;
1535 }
1536
1537 info->regs2d_res = request_mem_region(res->start,
1538 resource_size(res),
1539 pdev->name);
1540
1541 if (info->regs2d_res == NULL) {
1542 dev_err(dev, "cannot claim registers\n");
1543 ret = -ENXIO;
1544 goto err_regs_map;
1545 }
1546
1547 info->regs2d = ioremap(res->start, resource_size(res));
1548 if (info->regs2d == NULL) {
1549 dev_err(dev, "cannot remap registers\n");
1550 ret = -ENXIO;
1551 goto err_regs2d_res;
1552 }
1553
1357 /* allocate, reserve resources for framebuffer */ 1554 /* allocate, reserve resources for framebuffer */
1358 res = platform_get_resource(pdev, IORESOURCE_MEM, 2); 1555 res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
1359 if (res == NULL) { 1556 if (res == NULL) {
1360 dev_err(dev, "no memory resource defined\n"); 1557 dev_err(dev, "no memory resource defined\n");
1361 ret = -ENXIO; 1558 ret = -ENXIO;
1362 goto err_regs_map; 1559 goto err_regs2d_map;
1363 } 1560 }
1364 1561
1365 info->fbmem_res = request_mem_region(res->start, 1562 info->fbmem_res = request_mem_region(res->start,
@@ -1368,7 +1565,7 @@ static int sm501fb_start(struct sm501fb_info *info,
1368 if (info->fbmem_res == NULL) { 1565 if (info->fbmem_res == NULL) {
1369 dev_err(dev, "cannot claim framebuffer\n"); 1566 dev_err(dev, "cannot claim framebuffer\n");
1370 ret = -ENXIO; 1567 ret = -ENXIO;
1371 goto err_regs_map; 1568 goto err_regs2d_map;
1372 } 1569 }
1373 1570
1374 info->fbmem = ioremap(res->start, resource_size(res)); 1571 info->fbmem = ioremap(res->start, resource_size(res));
@@ -1389,8 +1586,10 @@ static int sm501fb_start(struct sm501fb_info *info,
1389 /* enable display controller */ 1586 /* enable display controller */
1390 sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1); 1587 sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1);
1391 1588
1392 /* setup cursors */ 1589 /* enable 2d controller */
1590 sm501_unit_power(dev->parent, SM501_GATE_2D_ENGINE, 1);
1393 1591
1592 /* setup cursors */
1394 sm501_init_cursor(info->fb[HEAD_CRT], SM501_DC_CRT_HWC_ADDR); 1593 sm501_init_cursor(info->fb[HEAD_CRT], SM501_DC_CRT_HWC_ADDR);
1395 sm501_init_cursor(info->fb[HEAD_PANEL], SM501_DC_PANEL_HWC_ADDR); 1594 sm501_init_cursor(info->fb[HEAD_PANEL], SM501_DC_PANEL_HWC_ADDR);
1396 1595
@@ -1400,6 +1599,13 @@ static int sm501fb_start(struct sm501fb_info *info,
1400 release_resource(info->fbmem_res); 1599 release_resource(info->fbmem_res);
1401 kfree(info->fbmem_res); 1600 kfree(info->fbmem_res);
1402 1601
1602 err_regs2d_map:
1603 iounmap(info->regs2d);
1604
1605 err_regs2d_res:
1606 release_resource(info->regs2d_res);
1607 kfree(info->regs2d_res);
1608
1403 err_regs_map: 1609 err_regs_map:
1404 iounmap(info->regs); 1610 iounmap(info->regs);
1405 1611
@@ -1420,6 +1626,10 @@ static void sm501fb_stop(struct sm501fb_info *info)
1420 release_resource(info->fbmem_res); 1626 release_resource(info->fbmem_res);
1421 kfree(info->fbmem_res); 1627 kfree(info->fbmem_res);
1422 1628
1629 iounmap(info->regs2d);
1630 release_resource(info->regs2d_res);
1631 kfree(info->regs2d_res);
1632
1423 iounmap(info->regs); 1633 iounmap(info->regs);
1424 release_resource(info->regs_res); 1634 release_resource(info->regs_res);
1425 kfree(info->regs_res); 1635 kfree(info->regs_res);
@@ -1486,7 +1696,8 @@ static int sm501fb_init_fb(struct fb_info *fb,
1486 par->ops.fb_cursor = NULL; 1696 par->ops.fb_cursor = NULL;
1487 1697
1488 fb->fbops = &par->ops; 1698 fb->fbops = &par->ops;
1489 fb->flags = FBINFO_FLAG_DEFAULT | 1699 fb->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST |
1700 FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
1490 FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN; 1701 FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
1491 1702
1492 /* fixed data */ 1703 /* fixed data */
diff --git a/include/linux/sm501-regs.h b/include/linux/sm501-regs.h
index d53642d2d899..67ed2c542831 100644
--- a/include/linux/sm501-regs.h
+++ b/include/linux/sm501-regs.h
@@ -31,6 +31,8 @@
31#define SM501_SYSCTRL_PCI_SUBSYS_LOCK (1<<11) 31#define SM501_SYSCTRL_PCI_SUBSYS_LOCK (1<<11)
32#define SM501_SYSCTRL_PCI_BURST_READ_EN (1<<15) 32#define SM501_SYSCTRL_PCI_BURST_READ_EN (1<<15)
33 33
34#define SM501_SYSCTRL_2D_ENGINE_STATUS (1<<19)
35
34/* miscellaneous control */ 36/* miscellaneous control */
35 37
36#define SM501_MISC_CONTROL (0x000004) 38#define SM501_MISC_CONTROL (0x000004)