Commit 9265576daeab1a884b11cc4c1087b72b488ca2e3

Authored by Vincent Sanders
Committed by Linus Torvalds
1 parent 2d72b11cd2

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>

Showing 2 changed files with 226 additions and 13 deletions Side-by-side Diff

drivers/video/sm501fb.c
... ... @@ -66,6 +66,7 @@
66 66 struct fb_info *fb[2]; /* fb info for both heads */
67 67 struct resource *fbmem_res; /* framebuffer resource */
68 68 struct resource *regs_res; /* registers resource */
  69 + struct resource *regs2d_res; /* 2d registers resource */
69 70 struct sm501_platdata_fb *pdata; /* our platform data */
70 71  
71 72 unsigned long pm_crt_ctrl; /* pm: crt ctrl save */
... ... @@ -73,6 +74,7 @@
73 74 int irq;
74 75 int swap_endian; /* set to swap rgb=>bgr */
75 76 void __iomem *regs; /* remapped registers */
  77 + void __iomem *regs2d; /* 2d remapped registers */
76 78 void __iomem *fbmem; /* remapped framebuffer */
77 79 size_t fbmem_len; /* length of remapped region */
78 80 };
... ... @@ -123,9 +125,9 @@
123 125 * This is an attempt to lay out memory for the two framebuffers and
124 126 * everything else
125 127 *
126   - * |fbmem_res->start fbmem_res->end|
127   - * | |
128   - * |fb[0].fix.smem_start | |fb[1].fix.smem_start | 2K |
  128 + * |fbmem_res->start fbmem_res->end|
  129 + * | |
  130 + * |fb[0].fix.smem_start | |fb[1].fix.smem_start | 2K |
129 131 * |-> fb[0].fix.smem_len <-| spare |-> fb[1].fix.smem_len <-|-> cursors <-|
130 132 *
131 133 * The "spare" space is for the 2d engine data
132 134  
... ... @@ -1246,8 +1248,174 @@
1246 1248  
1247 1249 static DEVICE_ATTR(fbregs_pnl, 0444, sm501fb_debug_show_pnl, NULL);
1248 1250  
1249   -/* framebuffer ops */
  1251 +/* acceleration operations */
  1252 +static 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;
1250 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 +
  1271 +static 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 +
  1356 +static 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 +
  1418 +
1251 1419 static struct fb_ops sm501fb_ops_crt = {
1252 1420 .owner = THIS_MODULE,
1253 1421 .fb_check_var = sm501fb_check_var_crt,
1254 1422  
... ... @@ -1256,9 +1424,10 @@
1256 1424 .fb_setcolreg = sm501fb_setcolreg,
1257 1425 .fb_pan_display = sm501fb_pan_crt,
1258 1426 .fb_cursor = sm501fb_cursor,
1259   - .fb_fillrect = cfb_fillrect,
1260   - .fb_copyarea = cfb_copyarea,
  1427 + .fb_fillrect = sm501fb_fillrect,
  1428 + .fb_copyarea = sm501fb_copyarea,
1261 1429 .fb_imageblit = cfb_imageblit,
  1430 + .fb_sync = sm501fb_sync,
1262 1431 };
1263 1432  
1264 1433 static struct fb_ops sm501fb_ops_pnl = {
1265 1434  
... ... @@ -1269,9 +1438,10 @@
1269 1438 .fb_blank = sm501fb_blank_pnl,
1270 1439 .fb_setcolreg = sm501fb_setcolreg,
1271 1440 .fb_cursor = sm501fb_cursor,
1272   - .fb_fillrect = cfb_fillrect,
1273   - .fb_copyarea = cfb_copyarea,
  1441 + .fb_fillrect = sm501fb_fillrect,
  1442 + .fb_copyarea = sm501fb_copyarea,
1274 1443 .fb_imageblit = cfb_imageblit,
  1444 + .fb_sync = sm501fb_sync,
1275 1445 };
1276 1446  
1277 1447 /* sm501_init_cursor
... ... @@ -1329,7 +1499,8 @@
1329 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 1504 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1334 1505 if (res == NULL) {
1335 1506 dev_err(dev, "no resource definition for registers\n");
1336 1507  
... ... @@ -1354,12 +1525,38 @@
1354 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 1554 /* allocate, reserve resources for framebuffer */
1358 1555 res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
1359 1556 if (res == NULL) {
1360 1557 dev_err(dev, "no memory resource defined\n");
1361 1558 ret = -ENXIO;
1362   - goto err_regs_map;
  1559 + goto err_regs2d_map;
1363 1560 }
1364 1561  
1365 1562 info->fbmem_res = request_mem_region(res->start,
... ... @@ -1368,7 +1565,7 @@
1368 1565 if (info->fbmem_res == NULL) {
1369 1566 dev_err(dev, "cannot claim framebuffer\n");
1370 1567 ret = -ENXIO;
1371   - goto err_regs_map;
  1568 + goto err_regs2d_map;
1372 1569 }
1373 1570  
1374 1571 info->fbmem = ioremap(res->start, resource_size(res));
1375 1572  
... ... @@ -1389,8 +1586,10 @@
1389 1586 /* enable display controller */
1390 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 1593 sm501_init_cursor(info->fb[HEAD_CRT], SM501_DC_CRT_HWC_ADDR);
1395 1594 sm501_init_cursor(info->fb[HEAD_PANEL], SM501_DC_PANEL_HWC_ADDR);
1396 1595  
... ... @@ -1400,6 +1599,13 @@
1400 1599 release_resource(info->fbmem_res);
1401 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 1609 err_regs_map:
1404 1610 iounmap(info->regs);
1405 1611  
... ... @@ -1420,6 +1626,10 @@
1420 1626 release_resource(info->fbmem_res);
1421 1627 kfree(info->fbmem_res);
1422 1628  
  1629 + iounmap(info->regs2d);
  1630 + release_resource(info->regs2d_res);
  1631 + kfree(info->regs2d_res);
  1632 +
1423 1633 iounmap(info->regs);
1424 1634 release_resource(info->regs_res);
1425 1635 kfree(info->regs_res);
... ... @@ -1486,7 +1696,8 @@
1486 1696 par->ops.fb_cursor = NULL;
1487 1697  
1488 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 1701 FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
1491 1702  
1492 1703 /* fixed data */
include/linux/sm501-regs.h
... ... @@ -31,6 +31,8 @@
31 31 #define SM501_SYSCTRL_PCI_SUBSYS_LOCK (1<<11)
32 32 #define SM501_SYSCTRL_PCI_BURST_READ_EN (1<<15)
33 33  
  34 +#define SM501_SYSCTRL_2D_ENGINE_STATUS (1<<19)
  35 +
34 36 /* miscellaneous control */
35 37  
36 38 #define SM501_MISC_CONTROL (0x000004)