~ubuntu-branches/debian/wheezy/linux-2.6/wheezy

« back to all changes in this revision

Viewing changes to drivers/video/sm501fb.c

  • Committer: Bazaar Package Importer
  • Author(s): Ben Hutchings, Ben Hutchings, Aurelien Jarno, Martin Michlmayr
  • Date: 2011-04-06 13:53:30 UTC
  • mfrom: (43.1.5 sid)
  • Revision ID: james.westby@ubuntu.com-20110406135330-wjufxhd0tvn3zx4z
Tags: 2.6.38-3
[ Ben Hutchings ]
* [ppc64] Add to linux-tools package architectures (Closes: #620124)
* [amd64] Save cr4 to mmu_cr4_features at boot time (Closes: #620284)
* appletalk: Fix bugs introduced when removing use of BKL
* ALSA: Fix yet another race in disconnection
* cciss: Fix lost command issue
* ath9k: Fix kernel panic in AR2427
* ses: Avoid kernel panic when lun 0 is not mapped
* PCI/ACPI: Report ASPM support to BIOS if not disabled from command line

[ Aurelien Jarno ]
* rtlwifi: fix build when PCI is not enabled.

[ Martin Michlmayr ]
* rtlwifi: Eliminate udelay calls with too large values (Closes: #620204)

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
#include <linux/platform_device.h>
30
30
#include <linux/clk.h>
31
31
#include <linux/console.h>
 
32
#include <linux/io.h>
32
33
 
33
 
#include <asm/io.h>
34
34
#include <asm/uaccess.h>
35
35
#include <asm/div64.h>
36
36
 
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
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
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
409
411
        struct sm501fb_par  *par = info->par;
410
412
        struct sm501fb_info *fbi = par->info;
411
413
        unsigned long pixclock;      /* pixelclock in Hz */
412
 
        unsigned long sm501pixclock; /* pixelclock the 501 can achive in Hz */
 
414
        unsigned long sm501pixclock; /* pixelclock the 501 can achieve in Hz */
413
415
        unsigned int mem_type;
414
416
        unsigned int clock_type;
415
417
        unsigned int head_addr;
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;
 
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
 
1250
1418
 
1251
1419
static struct fb_ops sm501fb_ops_crt = {
1252
1420
        .owner          = THIS_MODULE,
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 = {
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
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");
1338
1509
        }
1339
1510
 
1340
1511
        info->regs_res = request_mem_region(res->start,
1341
 
                                            res->end - res->start,
 
1512
                                            resource_size(res),
1342
1513
                                            pdev->name);
1343
1514
 
1344
1515
        if (info->regs_res == NULL) {
1347
1518
                goto err_release;
1348
1519
        }
1349
1520
 
1350
 
        info->regs = ioremap(res->start, (res->end - res->start)+1);
 
1521
        info->regs = ioremap(res->start, resource_size(res));
1351
1522
        if (info->regs == NULL) {
1352
1523
                dev_err(dev, "cannot remap registers\n");
1353
1524
                ret = -ENXIO;
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,
1366
 
                                             (res->end - res->start)+1,
 
1563
                                             resource_size(res),
1367
1564
                                             pdev->name);
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
 
        info->fbmem = ioremap(res->start, (res->end - res->start)+1);
 
1571
        info->fbmem = ioremap(res->start, resource_size(res));
1375
1572
        if (info->fbmem == NULL) {
1376
1573
                dev_err(dev, "cannot remap framebuffer\n");
1377
1574
                goto err_mem_res;
1378
1575
        }
1379
1576
 
1380
 
        info->fbmem_len = (res->end - res->start)+1;
 
1577
        info->fbmem_len = resource_size(res);
1381
1578
 
1382
1579
        /* clear framebuffer memory - avoids garbage data on unused fb */
1383
1580
        memset(info->fbmem, 0, info->fbmem_len);
1389
1586
        /* enable display controller */
1390
1587
        sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1);
1391
1588
 
 
1589
        /* enable 2d controller */
 
1590
        sm501_unit_power(dev->parent, SM501_GATE_2D_ENGINE, 1);
 
1591
 
1392
1592
        /* setup cursors */
1393
 
 
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
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
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
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 */
1799
2010
 
1800
2011
        /* tell console/fb driver we are suspending */
1801
2012
 
1802
 
        acquire_console_sem();
 
2013
        console_lock();
1803
2014
        fb_set_suspend(fbi, 1);
1804
 
        release_console_sem();
 
2015
        console_unlock();
1805
2016
 
1806
2017
        /* backup copies in case chip is powered down over suspend */
1807
2018
 
1858
2069
                memcpy_toio(par->cursor.k_addr, par->store_cursor,
1859
2070
                            par->cursor.size);
1860
2071
 
1861
 
        acquire_console_sem();
 
2072
        console_lock();
1862
2073
        fb_set_suspend(fbi, 0);
1863
 
        release_console_sem();
 
2074
        console_unlock();
1864
2075
 
1865
2076
        vfree(par->store_fb);
1866
2077
        vfree(par->store_cursor);