aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/sm501fb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/sm501fb.c')
-rw-r--r--drivers/video/sm501fb.c329
1 files changed, 206 insertions, 123 deletions
diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c
index 15d4a768b1f6..f94ae84a58cd 100644
--- a/drivers/video/sm501fb.c
+++ b/drivers/video/sm501fb.c
@@ -48,10 +48,15 @@ enum sm501_controller {
48 HEAD_PANEL = 1, 48 HEAD_PANEL = 1,
49}; 49};
50 50
51/* SM501 memory address */ 51/* SM501 memory address.
52 *
53 * This structure is used to track memory usage within the SM501 framebuffer
54 * allocation. The sm_addr field is stored as an offset as it is often used
55 * against both the physical and mapped addresses.
56 */
52struct sm501_mem { 57struct sm501_mem {
53 unsigned long size; 58 unsigned long size;
54 unsigned long sm_addr; 59 unsigned long sm_addr; /* offset from base of sm501 fb. */
55 void __iomem *k_addr; 60 void __iomem *k_addr;
56}; 61};
57 62
@@ -142,31 +147,68 @@ static inline void sm501fb_sync_regs(struct sm501fb_info *info)
142static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem, 147static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
143 unsigned int why, size_t size) 148 unsigned int why, size_t size)
144{ 149{
145 unsigned int ptr = 0; 150 struct sm501fb_par *par;
151 struct fb_info *fbi;
152 unsigned int ptr;
153 unsigned int end;
146 154
147 switch (why) { 155 switch (why) {
148 case SM501_MEMF_CURSOR: 156 case SM501_MEMF_CURSOR:
149 ptr = inf->fbmem_len - size; 157 ptr = inf->fbmem_len - size;
150 inf->fbmem_len = ptr; 158 inf->fbmem_len = ptr; /* adjust available memory. */
151 break; 159 break;
152 160
153 case SM501_MEMF_PANEL: 161 case SM501_MEMF_PANEL:
154 ptr = inf->fbmem_len - size; 162 ptr = inf->fbmem_len - size;
155 if (ptr < inf->fb[0]->fix.smem_len) 163 fbi = inf->fb[HEAD_CRT];
164
165 /* round down, some programs such as directfb do not draw
166 * 0,0 correctly unless the start is aligned to a page start.
167 */
168
169 if (ptr > 0)
170 ptr &= ~(PAGE_SIZE - 1);
171
172 if (fbi && ptr < fbi->fix.smem_len)
173 return -ENOMEM;
174
175 if (ptr < 0)
156 return -ENOMEM; 176 return -ENOMEM;
157 177
158 break; 178 break;
159 179
160 case SM501_MEMF_CRT: 180 case SM501_MEMF_CRT:
161 ptr = 0; 181 ptr = 0;
182
183 /* check to see if we have panel memory allocated
184 * which would put an limit on available memory. */
185
186 fbi = inf->fb[HEAD_PANEL];
187 if (fbi) {
188 par = fbi->par;
189 end = par->screen.k_addr ? par->screen.sm_addr : inf->fbmem_len;
190 } else
191 end = inf->fbmem_len;
192
193 if ((ptr + size) > end)
194 return -ENOMEM;
195
162 break; 196 break;
163 197
164 case SM501_MEMF_ACCEL: 198 case SM501_MEMF_ACCEL:
165 ptr = inf->fb[0]->fix.smem_len; 199 fbi = inf->fb[HEAD_CRT];
200 ptr = fbi ? fbi->fix.smem_len : 0;
201
202 fbi = inf->fb[HEAD_PANEL];
203 if (fbi) {
204 par = fbi->par;
205 end = par->screen.sm_addr;
206 } else
207 end = inf->fbmem_len;
166 208
167 if ((ptr + size) > 209 if ((ptr + size) > end)
168 (inf->fb[1]->fix.smem_start - inf->fbmem_res->start))
169 return -ENOMEM; 210 return -ENOMEM;
211
170 break; 212 break;
171 213
172 default: 214 default:
@@ -663,15 +705,25 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
663 sm501fb_sync_regs(fbi); 705 sm501fb_sync_regs(fbi);
664 mdelay(10); 706 mdelay(10);
665 707
708 /* VBIASEN */
709
666 if (!(pd->flags & SM501FB_FLAG_PANEL_NO_VBIASEN)) { 710 if (!(pd->flags & SM501FB_FLAG_PANEL_NO_VBIASEN)) {
667 control |= SM501_DC_PANEL_CONTROL_BIAS; /* VBIASEN */ 711 if (pd->flags & SM501FB_FLAG_PANEL_INV_VBIASEN)
712 control &= ~SM501_DC_PANEL_CONTROL_BIAS;
713 else
714 control |= SM501_DC_PANEL_CONTROL_BIAS;
715
668 writel(control, ctrl_reg); 716 writel(control, ctrl_reg);
669 sm501fb_sync_regs(fbi); 717 sm501fb_sync_regs(fbi);
670 mdelay(10); 718 mdelay(10);
671 } 719 }
672 720
673 if (!(pd->flags & SM501FB_FLAG_PANEL_NO_FPEN)) { 721 if (!(pd->flags & SM501FB_FLAG_PANEL_NO_FPEN)) {
674 control |= SM501_DC_PANEL_CONTROL_FPEN; 722 if (pd->flags & SM501FB_FLAG_PANEL_INV_FPEN)
723 control &= ~SM501_DC_PANEL_CONTROL_FPEN;
724 else
725 control |= SM501_DC_PANEL_CONTROL_FPEN;
726
675 writel(control, ctrl_reg); 727 writel(control, ctrl_reg);
676 sm501fb_sync_regs(fbi); 728 sm501fb_sync_regs(fbi);
677 mdelay(10); 729 mdelay(10);
@@ -679,14 +731,22 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
679 } else if (!to && (control & SM501_DC_PANEL_CONTROL_VDD) != 0) { 731 } else if (!to && (control & SM501_DC_PANEL_CONTROL_VDD) != 0) {
680 /* disable panel power */ 732 /* disable panel power */
681 if (!(pd->flags & SM501FB_FLAG_PANEL_NO_FPEN)) { 733 if (!(pd->flags & SM501FB_FLAG_PANEL_NO_FPEN)) {
682 control &= ~SM501_DC_PANEL_CONTROL_FPEN; 734 if (pd->flags & SM501FB_FLAG_PANEL_INV_FPEN)
735 control |= SM501_DC_PANEL_CONTROL_FPEN;
736 else
737 control &= ~SM501_DC_PANEL_CONTROL_FPEN;
738
683 writel(control, ctrl_reg); 739 writel(control, ctrl_reg);
684 sm501fb_sync_regs(fbi); 740 sm501fb_sync_regs(fbi);
685 mdelay(10); 741 mdelay(10);
686 } 742 }
687 743
688 if (!(pd->flags & SM501FB_FLAG_PANEL_NO_VBIASEN)) { 744 if (!(pd->flags & SM501FB_FLAG_PANEL_NO_VBIASEN)) {
689 control &= ~SM501_DC_PANEL_CONTROL_BIAS; 745 if (pd->flags & SM501FB_FLAG_PANEL_INV_VBIASEN)
746 control |= SM501_DC_PANEL_CONTROL_BIAS;
747 else
748 control &= ~SM501_DC_PANEL_CONTROL_BIAS;
749
690 writel(control, ctrl_reg); 750 writel(control, ctrl_reg);
691 sm501fb_sync_regs(fbi); 751 sm501fb_sync_regs(fbi);
692 mdelay(10); 752 mdelay(10);
@@ -1210,39 +1270,6 @@ static struct fb_ops sm501fb_ops_pnl = {
1210 .fb_imageblit = cfb_imageblit, 1270 .fb_imageblit = cfb_imageblit,
1211}; 1271};
1212 1272
1213/* sm501fb_info_alloc
1214 *
1215 * creates and initialises an sm501fb_info structure
1216*/
1217
1218static struct sm501fb_info *sm501fb_info_alloc(struct fb_info *fbinfo_crt,
1219 struct fb_info *fbinfo_pnl)
1220{
1221 struct sm501fb_info *info;
1222 struct sm501fb_par *par;
1223
1224 info = kzalloc(sizeof(struct sm501fb_info), GFP_KERNEL);
1225 if (info) {
1226 /* set the references back */
1227
1228 par = fbinfo_crt->par;
1229 par->info = info;
1230 par->head = HEAD_CRT;
1231 fbinfo_crt->pseudo_palette = &par->pseudo_palette;
1232
1233 par = fbinfo_pnl->par;
1234 par->info = info;
1235 par->head = HEAD_PANEL;
1236 fbinfo_pnl->pseudo_palette = &par->pseudo_palette;
1237
1238 /* store the two fbs into our info */
1239 info->fb[HEAD_CRT] = fbinfo_crt;
1240 info->fb[HEAD_PANEL] = fbinfo_pnl;
1241 }
1242
1243 return info;
1244}
1245
1246/* sm501_init_cursor 1273/* sm501_init_cursor
1247 * 1274 *
1248 * initialise hw cursor parameters 1275 * initialise hw cursor parameters
@@ -1250,10 +1277,16 @@ static struct sm501fb_info *sm501fb_info_alloc(struct fb_info *fbinfo_crt,
1250 1277
1251static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base) 1278static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base)
1252{ 1279{
1253 struct sm501fb_par *par = fbi->par; 1280 struct sm501fb_par *par;
1254 struct sm501fb_info *info = par->info; 1281 struct sm501fb_info *info;
1255 int ret; 1282 int ret;
1256 1283
1284 if (fbi == NULL)
1285 return 0;
1286
1287 par = fbi->par;
1288 info = par->info;
1289
1257 par->cursor_regs = info->regs + reg_base; 1290 par->cursor_regs = info->regs + reg_base;
1258 1291
1259 ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024); 1292 ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024);
@@ -1281,13 +1314,10 @@ static int sm501fb_start(struct sm501fb_info *info,
1281 struct platform_device *pdev) 1314 struct platform_device *pdev)
1282{ 1315{
1283 struct resource *res; 1316 struct resource *res;
1284 struct device *dev; 1317 struct device *dev = &pdev->dev;
1285 int k; 1318 int k;
1286 int ret; 1319 int ret;
1287 1320
1288 info->dev = dev = &pdev->dev;
1289 platform_set_drvdata(pdev, info);
1290
1291 info->irq = ret = platform_get_irq(pdev, 0); 1321 info->irq = ret = platform_get_irq(pdev, 0);
1292 if (ret < 0) { 1322 if (ret < 0) {
1293 /* we currently do not use the IRQ */ 1323 /* we currently do not use the IRQ */
@@ -1390,11 +1420,6 @@ static void sm501fb_stop(struct sm501fb_info *info)
1390 kfree(info->regs_res); 1420 kfree(info->regs_res);
1391} 1421}
1392 1422
1393static void sm501fb_info_release(struct sm501fb_info *info)
1394{
1395 kfree(info);
1396}
1397
1398static int sm501fb_init_fb(struct fb_info *fb, 1423static int sm501fb_init_fb(struct fb_info *fb,
1399 enum sm501_controller head, 1424 enum sm501_controller head,
1400 const char *fbname) 1425 const char *fbname)
@@ -1539,36 +1564,93 @@ static struct sm501_platdata_fb sm501fb_def_pdata = {
1539static char driver_name_crt[] = "sm501fb-crt"; 1564static char driver_name_crt[] = "sm501fb-crt";
1540static char driver_name_pnl[] = "sm501fb-panel"; 1565static char driver_name_pnl[] = "sm501fb-panel";
1541 1566
1542static int __init sm501fb_probe(struct platform_device *pdev) 1567static int __devinit sm501fb_probe_one(struct sm501fb_info *info,
1568 enum sm501_controller head)
1543{ 1569{
1544 struct sm501fb_info *info; 1570 unsigned char *name = (head == HEAD_CRT) ? "crt" : "panel";
1545 struct device *dev = &pdev->dev; 1571 struct sm501_platdata_fbsub *pd;
1546 struct fb_info *fbinfo_crt; 1572 struct sm501fb_par *par;
1547 struct fb_info *fbinfo_pnl; 1573 struct fb_info *fbi;
1548 int ret;
1549 1574
1550 /* allocate our framebuffers */ 1575 pd = (head == HEAD_CRT) ? info->pdata->fb_crt : info->pdata->fb_pnl;
1576
1577 /* Do not initialise if we've not been given any platform data */
1578 if (pd == NULL) {
1579 dev_info(info->dev, "no data for fb %s (disabled)\n", name);
1580 return 0;
1581 }
1551 1582
1552 fbinfo_crt = framebuffer_alloc(sizeof(struct sm501fb_par), dev); 1583 fbi = framebuffer_alloc(sizeof(struct sm501fb_par), info->dev);
1553 if (fbinfo_crt == NULL) { 1584 if (fbi == NULL) {
1554 dev_err(dev, "cannot allocate crt framebuffer\n"); 1585 dev_err(info->dev, "cannot allocate %s framebuffer\n", name);
1555 return -ENOMEM; 1586 return -ENOMEM;
1556 } 1587 }
1557 1588
1558 fbinfo_pnl = framebuffer_alloc(sizeof(struct sm501fb_par), dev); 1589 par = fbi->par;
1559 if (fbinfo_pnl == NULL) { 1590 par->info = info;
1560 dev_err(dev, "cannot allocate panel framebuffer\n"); 1591 par->head = head;
1561 ret = -ENOMEM; 1592 fbi->pseudo_palette = &par->pseudo_palette;
1562 goto fbinfo_crt_alloc_fail; 1593
1594 info->fb[head] = fbi;
1595
1596 return 0;
1597}
1598
1599/* Free up anything allocated by sm501fb_init_fb */
1600
1601static void sm501_free_init_fb(struct sm501fb_info *info,
1602 enum sm501_controller head)
1603{
1604 struct fb_info *fbi = info->fb[head];
1605
1606 fb_dealloc_cmap(&fbi->cmap);
1607}
1608
1609static int __devinit sm501fb_start_one(struct sm501fb_info *info,
1610 enum sm501_controller head,
1611 const char *drvname)
1612{
1613 struct fb_info *fbi = info->fb[head];
1614 int ret;
1615
1616 if (!fbi)
1617 return 0;
1618
1619 ret = sm501fb_init_fb(info->fb[head], head, drvname);
1620 if (ret) {
1621 dev_err(info->dev, "cannot initialise fb %s\n", drvname);
1622 return ret;
1623 }
1624
1625 ret = register_framebuffer(info->fb[head]);
1626 if (ret) {
1627 dev_err(info->dev, "failed to register fb %s\n", drvname);
1628 sm501_free_init_fb(info, head);
1629 return ret;
1563 } 1630 }
1564 1631
1565 info = sm501fb_info_alloc(fbinfo_crt, fbinfo_pnl); 1632 dev_info(info->dev, "fb%d: %s frame buffer\n", fbi->node, fbi->fix.id);
1566 if (info == NULL) { 1633
1567 dev_err(dev, "cannot allocate par\n"); 1634 return 0;
1568 ret = -ENOMEM; 1635}
1569 goto sm501fb_alloc_fail; 1636
1637static int __devinit sm501fb_probe(struct platform_device *pdev)
1638{
1639 struct sm501fb_info *info;
1640 struct device *dev = &pdev->dev;
1641 int ret;
1642
1643 /* allocate our framebuffers */
1644
1645 info = kzalloc(sizeof(struct sm501fb_info), GFP_KERNEL);
1646 if (!info) {
1647 dev_err(dev, "failed to allocate state\n");
1648 return -ENOMEM;
1570 } 1649 }
1571 1650
1651 info->dev = dev = &pdev->dev;
1652 platform_set_drvdata(pdev, info);
1653
1572 if (dev->parent->platform_data) { 1654 if (dev->parent->platform_data) {
1573 struct sm501_platdata *pd = dev->parent->platform_data; 1655 struct sm501_platdata *pd = dev->parent->platform_data;
1574 info->pdata = pd->fb; 1656 info->pdata = pd->fb;
@@ -1579,90 +1661,88 @@ static int __init sm501fb_probe(struct platform_device *pdev)
1579 info->pdata = &sm501fb_def_pdata; 1661 info->pdata = &sm501fb_def_pdata;
1580 } 1662 }
1581 1663
1582 /* start the framebuffers */ 1664 /* probe for the presence of each panel */
1583 1665
1584 ret = sm501fb_start(info, pdev); 1666 ret = sm501fb_probe_one(info, HEAD_CRT);
1585 if (ret) { 1667 if (ret < 0) {
1586 dev_err(dev, "cannot initialise SM501\n"); 1668 dev_err(dev, "failed to probe CRT\n");
1587 goto sm501fb_start_fail; 1669 goto err_alloc;
1588 } 1670 }
1589 1671
1590 /* CRT framebuffer setup */ 1672 ret = sm501fb_probe_one(info, HEAD_PANEL);
1673 if (ret < 0) {
1674 dev_err(dev, "failed to probe PANEL\n");
1675 goto err_probed_crt;
1676 }
1591 1677
1592 ret = sm501fb_init_fb(fbinfo_crt, HEAD_CRT, driver_name_crt); 1678 if (info->fb[HEAD_PANEL] == NULL &&
1593 if (ret) { 1679 info->fb[HEAD_CRT] == NULL) {
1594 dev_err(dev, "cannot initialise CRT fb\n"); 1680 dev_err(dev, "no framebuffers found\n");
1595 goto sm501fb_start_fail; 1681 goto err_alloc;
1596 } 1682 }
1597 1683
1598 /* Panel framebuffer setup */ 1684 /* get the resources for both of the framebuffers */
1599 1685
1600 ret = sm501fb_init_fb(fbinfo_pnl, HEAD_PANEL, driver_name_pnl); 1686 ret = sm501fb_start(info, pdev);
1601 if (ret) { 1687 if (ret) {
1602 dev_err(dev, "cannot initialise Panel fb\n"); 1688 dev_err(dev, "cannot initialise SM501\n");
1603 goto sm501fb_start_fail; 1689 goto err_probed_panel;
1604 } 1690 }
1605 1691
1606 /* register framebuffers */ 1692 ret = sm501fb_start_one(info, HEAD_CRT, driver_name_crt);
1607 1693 if (ret) {
1608 ret = register_framebuffer(fbinfo_crt); 1694 dev_err(dev, "failed to start CRT\n");
1609 if (ret < 0) { 1695 goto err_started;
1610 dev_err(dev, "failed to register CRT fb (%d)\n", ret);
1611 goto register_crt_fail;
1612 } 1696 }
1613 1697
1614 ret = register_framebuffer(fbinfo_pnl); 1698 ret = sm501fb_start_one(info, HEAD_PANEL, driver_name_pnl);
1615 if (ret < 0) { 1699 if (ret) {
1616 dev_err(dev, "failed to register panel fb (%d)\n", ret); 1700 dev_err(dev, "failed to start Panel\n");
1617 goto register_pnl_fail; 1701 goto err_started_crt;
1618 } 1702 }
1619 1703
1620 dev_info(dev, "fb%d: %s frame buffer device\n",
1621 fbinfo_crt->node, fbinfo_crt->fix.id);
1622
1623 dev_info(dev, "fb%d: %s frame buffer device\n",
1624 fbinfo_pnl->node, fbinfo_pnl->fix.id);
1625
1626 /* create device files */ 1704 /* create device files */
1627 1705
1628 ret = device_create_file(dev, &dev_attr_crt_src); 1706 ret = device_create_file(dev, &dev_attr_crt_src);
1629 if (ret) 1707 if (ret)
1630 goto crtsrc_fail; 1708 goto err_started_panel;
1631 1709
1632 ret = device_create_file(dev, &dev_attr_fbregs_pnl); 1710 ret = device_create_file(dev, &dev_attr_fbregs_pnl);
1633 if (ret) 1711 if (ret)
1634 goto fbregs_pnl_fail; 1712 goto err_attached_crtsrc_file;
1635 1713
1636 ret = device_create_file(dev, &dev_attr_fbregs_crt); 1714 ret = device_create_file(dev, &dev_attr_fbregs_crt);
1637 if (ret) 1715 if (ret)
1638 goto fbregs_crt_fail; 1716 goto err_attached_pnlregs_file;
1639 1717
1640 /* we registered, return ok */ 1718 /* we registered, return ok */
1641 return 0; 1719 return 0;
1642 1720
1643 fbregs_crt_fail: 1721err_attached_pnlregs_file:
1644 device_remove_file(dev, &dev_attr_fbregs_pnl); 1722 device_remove_file(dev, &dev_attr_fbregs_pnl);
1645 1723
1646 fbregs_pnl_fail: 1724err_attached_crtsrc_file:
1647 device_remove_file(dev, &dev_attr_crt_src); 1725 device_remove_file(dev, &dev_attr_crt_src);
1648 1726
1649 crtsrc_fail: 1727err_started_panel:
1650 unregister_framebuffer(fbinfo_pnl); 1728 unregister_framebuffer(info->fb[HEAD_PANEL]);
1729 sm501_free_init_fb(info, HEAD_PANEL);
1651 1730
1652 register_pnl_fail: 1731err_started_crt:
1653 unregister_framebuffer(fbinfo_crt); 1732 unregister_framebuffer(info->fb[HEAD_CRT]);
1733 sm501_free_init_fb(info, HEAD_CRT);
1654 1734
1655 register_crt_fail: 1735err_started:
1656 sm501fb_stop(info); 1736 sm501fb_stop(info);
1657 1737
1658 sm501fb_start_fail: 1738err_probed_panel:
1659 sm501fb_info_release(info); 1739 framebuffer_release(info->fb[HEAD_PANEL]);
1660 1740
1661 sm501fb_alloc_fail: 1741err_probed_crt:
1662 framebuffer_release(fbinfo_pnl); 1742 framebuffer_release(info->fb[HEAD_CRT]);
1663 1743
1664 fbinfo_crt_alloc_fail: 1744err_alloc:
1665 framebuffer_release(fbinfo_crt); 1745 kfree(info);
1666 1746
1667 return ret; 1747 return ret;
1668} 1748}
@@ -1681,11 +1761,14 @@ static int sm501fb_remove(struct platform_device *pdev)
1681 device_remove_file(&pdev->dev, &dev_attr_fbregs_pnl); 1761 device_remove_file(&pdev->dev, &dev_attr_fbregs_pnl);
1682 device_remove_file(&pdev->dev, &dev_attr_crt_src); 1762 device_remove_file(&pdev->dev, &dev_attr_crt_src);
1683 1763
1764 sm501_free_init_fb(info, HEAD_CRT);
1765 sm501_free_init_fb(info, HEAD_PANEL);
1766
1684 unregister_framebuffer(fbinfo_crt); 1767 unregister_framebuffer(fbinfo_crt);
1685 unregister_framebuffer(fbinfo_pnl); 1768 unregister_framebuffer(fbinfo_pnl);
1686 1769
1687 sm501fb_stop(info); 1770 sm501fb_stop(info);
1688 sm501fb_info_release(info); 1771 kfree(info);
1689 1772
1690 framebuffer_release(fbinfo_pnl); 1773 framebuffer_release(fbinfo_pnl);
1691 framebuffer_release(fbinfo_crt); 1774 framebuffer_release(fbinfo_crt);