aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/sh_mobile_lcdcfb.c
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2011-09-07 05:09:26 -0400
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2012-03-12 17:40:41 -0400
commitf1f60b5f55099a658a5f79cc453b371a439864e6 (patch)
treec6f027aba0066f0b79fca0e26763d61e0d61221e /drivers/video/sh_mobile_lcdcfb.c
parentc2bc0a756b1f98bd712fabe78eb49d7d5ae72075 (diff)
fbdev: sh_mobile_lcdc: Reorder code into sections
Make the driver more readable by reordering code and splitting it into logical sections. Reorder the headers alphabetically. No modification to the code have been performed. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Diffstat (limited to 'drivers/video/sh_mobile_lcdcfb.c')
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c421
1 files changed, 231 insertions, 190 deletions
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index aac5b369d73c..8b18360fd47a 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -8,26 +8,27 @@
8 * for more details. 8 * for more details.
9 */ 9 */
10 10
11#include <linux/kernel.h> 11#include <linux/atomic.h>
12#include <linux/init.h> 12#include <linux/backlight.h>
13#include <linux/delay.h>
14#include <linux/mm.h>
15#include <linux/clk.h> 13#include <linux/clk.h>
16#include <linux/pm_runtime.h> 14#include <linux/console.h>
17#include <linux/platform_device.h>
18#include <linux/dma-mapping.h> 15#include <linux/dma-mapping.h>
16#include <linux/delay.h>
17#include <linux/gpio.h>
18#include <linux/init.h>
19#include <linux/interrupt.h> 19#include <linux/interrupt.h>
20#include <linux/videodev2.h>
21#include <linux/vmalloc.h>
22#include <linux/ioctl.h> 20#include <linux/ioctl.h>
23#include <linux/slab.h> 21#include <linux/kernel.h>
24#include <linux/console.h> 22#include <linux/mm.h>
25#include <linux/backlight.h>
26#include <linux/gpio.h>
27#include <linux/module.h> 23#include <linux/module.h>
24#include <linux/platform_device.h>
25#include <linux/pm_runtime.h>
26#include <linux/slab.h>
27#include <linux/videodev2.h>
28#include <linux/vmalloc.h>
29
28#include <video/sh_mobile_lcdc.h> 30#include <video/sh_mobile_lcdc.h>
29#include <video/sh_mobile_meram.h> 31#include <video/sh_mobile_meram.h>
30#include <linux/atomic.h>
31 32
32#include "sh_mobile_lcdcfb.h" 33#include "sh_mobile_lcdcfb.h"
33 34
@@ -37,6 +38,24 @@
37#define MAX_XRES 1920 38#define MAX_XRES 1920
38#define MAX_YRES 1080 39#define MAX_YRES 1080
39 40
41struct sh_mobile_lcdc_priv {
42 void __iomem *base;
43 int irq;
44 atomic_t hw_usecnt;
45 struct device *dev;
46 struct clk *dot_clk;
47 unsigned long lddckr;
48 struct sh_mobile_lcdc_chan ch[2];
49 struct notifier_block notifier;
50 int started;
51 int forced_fourcc; /* 2 channel LCDC must share fourcc setting */
52 struct sh_mobile_meram_info *meram_dev;
53};
54
55/* -----------------------------------------------------------------------------
56 * Registers access
57 */
58
40static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = { 59static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = {
41 [LDDCKPAT1R] = 0x400, 60 [LDDCKPAT1R] = 0x400,
42 [LDDCKPAT2R] = 0x404, 61 [LDDCKPAT2R] = 0x404,
@@ -75,38 +94,6 @@ static unsigned long lcdc_offs_sublcd[NR_CH_REGS] = {
75 [LDPMR] = 0x63c, 94 [LDPMR] = 0x63c,
76}; 95};
77 96
78static const struct fb_videomode default_720p = {
79 .name = "HDMI 720p",
80 .xres = 1280,
81 .yres = 720,
82
83 .left_margin = 220,
84 .right_margin = 110,
85 .hsync_len = 40,
86
87 .upper_margin = 20,
88 .lower_margin = 5,
89 .vsync_len = 5,
90
91 .pixclock = 13468,
92 .refresh = 60,
93 .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
94};
95
96struct sh_mobile_lcdc_priv {
97 void __iomem *base;
98 int irq;
99 atomic_t hw_usecnt;
100 struct device *dev;
101 struct clk *dot_clk;
102 unsigned long lddckr;
103 struct sh_mobile_lcdc_chan ch[2];
104 struct notifier_block notifier;
105 int started;
106 int forced_fourcc; /* 2 channel LCDC must share fourcc setting */
107 struct sh_mobile_meram_info *meram_dev;
108};
109
110static bool banked(int reg_nr) 97static bool banked(int reg_nr)
111{ 98{
112 switch (reg_nr) { 99 switch (reg_nr) {
@@ -127,6 +114,11 @@ static bool banked(int reg_nr)
127 return false; 114 return false;
128} 115}
129 116
117static int lcdc_chan_is_sublcd(struct sh_mobile_lcdc_chan *chan)
118{
119 return chan->cfg.chan == LCDC_CHAN_SUBLCD;
120}
121
130static void lcdc_write_chan(struct sh_mobile_lcdc_chan *chan, 122static void lcdc_write_chan(struct sh_mobile_lcdc_chan *chan,
131 int reg_nr, unsigned long data) 123 int reg_nr, unsigned long data)
132{ 124{
@@ -169,11 +161,77 @@ static void lcdc_wait_bit(struct sh_mobile_lcdc_priv *priv,
169 cpu_relax(); 161 cpu_relax();
170} 162}
171 163
172static int lcdc_chan_is_sublcd(struct sh_mobile_lcdc_chan *chan) 164/* -----------------------------------------------------------------------------
165 * Clock management
166 */
167
168static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv)
173{ 169{
174 return chan->cfg.chan == LCDC_CHAN_SUBLCD; 170 if (atomic_inc_and_test(&priv->hw_usecnt)) {
171 if (priv->dot_clk)
172 clk_enable(priv->dot_clk);
173 pm_runtime_get_sync(priv->dev);
174 if (priv->meram_dev && priv->meram_dev->pdev)
175 pm_runtime_get_sync(&priv->meram_dev->pdev->dev);
176 }
175} 177}
176 178
179static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv)
180{
181 if (atomic_sub_return(1, &priv->hw_usecnt) == -1) {
182 if (priv->meram_dev && priv->meram_dev->pdev)
183 pm_runtime_put_sync(&priv->meram_dev->pdev->dev);
184 pm_runtime_put(priv->dev);
185 if (priv->dot_clk)
186 clk_disable(priv->dot_clk);
187 }
188}
189
190static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev,
191 int clock_source,
192 struct sh_mobile_lcdc_priv *priv)
193{
194 char *str;
195
196 switch (clock_source) {
197 case LCDC_CLK_BUS:
198 str = "bus_clk";
199 priv->lddckr = LDDCKR_ICKSEL_BUS;
200 break;
201 case LCDC_CLK_PERIPHERAL:
202 str = "peripheral_clk";
203 priv->lddckr = LDDCKR_ICKSEL_MIPI;
204 break;
205 case LCDC_CLK_EXTERNAL:
206 str = NULL;
207 priv->lddckr = LDDCKR_ICKSEL_HDMI;
208 break;
209 default:
210 return -EINVAL;
211 }
212
213 if (str) {
214 priv->dot_clk = clk_get(&pdev->dev, str);
215 if (IS_ERR(priv->dot_clk)) {
216 dev_err(&pdev->dev, "cannot get dot clock %s\n", str);
217 return PTR_ERR(priv->dot_clk);
218 }
219 }
220
221 /* Runtime PM support involves two step for this driver:
222 * 1) Enable Runtime PM
223 * 2) Force Runtime PM Resume since hardware is accessed from probe()
224 */
225 priv->dev = &pdev->dev;
226 pm_runtime_enable(priv->dev);
227 pm_runtime_resume(priv->dev);
228 return 0;
229}
230
231/* -----------------------------------------------------------------------------
232 * Sys panel and deferred I/O
233 */
234
177static void lcdc_sys_write_index(void *handle, unsigned long data) 235static void lcdc_sys_write_index(void *handle, unsigned long data)
178{ 236{
179 struct sh_mobile_lcdc_chan *ch = handle; 237 struct sh_mobile_lcdc_chan *ch = handle;
@@ -216,69 +274,6 @@ struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = {
216 lcdc_sys_read_data, 274 lcdc_sys_read_data,
217}; 275};
218 276
219static int sh_mobile_format_fourcc(const struct fb_var_screeninfo *var)
220{
221 if (var->grayscale > 1)
222 return var->grayscale;
223
224 switch (var->bits_per_pixel) {
225 case 16:
226 return V4L2_PIX_FMT_RGB565;
227 case 24:
228 return V4L2_PIX_FMT_BGR24;
229 case 32:
230 return V4L2_PIX_FMT_BGR32;
231 default:
232 return 0;
233 }
234}
235
236static int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var)
237{
238 return var->grayscale > 1;
239}
240
241static bool sh_mobile_format_is_yuv(const struct fb_var_screeninfo *var)
242{
243 if (var->grayscale <= 1)
244 return false;
245
246 switch (var->grayscale) {
247 case V4L2_PIX_FMT_NV12:
248 case V4L2_PIX_FMT_NV21:
249 case V4L2_PIX_FMT_NV16:
250 case V4L2_PIX_FMT_NV61:
251 case V4L2_PIX_FMT_NV24:
252 case V4L2_PIX_FMT_NV42:
253 return true;
254
255 default:
256 return false;
257 }
258}
259
260static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv)
261{
262 if (atomic_inc_and_test(&priv->hw_usecnt)) {
263 if (priv->dot_clk)
264 clk_enable(priv->dot_clk);
265 pm_runtime_get_sync(priv->dev);
266 if (priv->meram_dev && priv->meram_dev->pdev)
267 pm_runtime_get_sync(&priv->meram_dev->pdev->dev);
268 }
269}
270
271static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv)
272{
273 if (atomic_sub_return(1, &priv->hw_usecnt) == -1) {
274 if (priv->meram_dev && priv->meram_dev->pdev)
275 pm_runtime_put_sync(&priv->meram_dev->pdev->dev);
276 pm_runtime_put(priv->dev);
277 if (priv->dot_clk)
278 clk_disable(priv->dot_clk);
279 }
280}
281
282static int sh_mobile_lcdc_sginit(struct fb_info *info, 277static int sh_mobile_lcdc_sginit(struct fb_info *info,
283 struct list_head *pagelist) 278 struct list_head *pagelist)
284{ 279{
@@ -345,6 +340,55 @@ static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info)
345 schedule_delayed_work(&info->deferred_work, fbdefio->delay); 340 schedule_delayed_work(&info->deferred_work, fbdefio->delay);
346} 341}
347 342
343/* -----------------------------------------------------------------------------
344 * Format helpers
345 */
346
347static int sh_mobile_format_fourcc(const struct fb_var_screeninfo *var)
348{
349 if (var->grayscale > 1)
350 return var->grayscale;
351
352 switch (var->bits_per_pixel) {
353 case 16:
354 return V4L2_PIX_FMT_RGB565;
355 case 24:
356 return V4L2_PIX_FMT_BGR24;
357 case 32:
358 return V4L2_PIX_FMT_BGR32;
359 default:
360 return 0;
361 }
362}
363
364static int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var)
365{
366 return var->grayscale > 1;
367}
368
369static bool sh_mobile_format_is_yuv(const struct fb_var_screeninfo *var)
370{
371 if (var->grayscale <= 1)
372 return false;
373
374 switch (var->grayscale) {
375 case V4L2_PIX_FMT_NV12:
376 case V4L2_PIX_FMT_NV21:
377 case V4L2_PIX_FMT_NV16:
378 case V4L2_PIX_FMT_NV61:
379 case V4L2_PIX_FMT_NV24:
380 case V4L2_PIX_FMT_NV42:
381 return true;
382
383 default:
384 return false;
385 }
386}
387
388/* -----------------------------------------------------------------------------
389 * Start, stop and IRQ
390 */
391
348static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data) 392static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
349{ 393{
350 struct sh_mobile_lcdc_priv *priv = data; 394 struct sh_mobile_lcdc_priv *priv = data;
@@ -790,86 +834,9 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
790 sh_mobile_lcdc_clk_off(priv); 834 sh_mobile_lcdc_clk_off(priv);
791} 835}
792 836
793static int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch) 837/* -----------------------------------------------------------------------------
794{ 838 * Frame buffer operations
795 int interface_type = ch->cfg.interface_type; 839 */
796
797 switch (interface_type) {
798 case RGB8:
799 case RGB9:
800 case RGB12A:
801 case RGB12B:
802 case RGB16:
803 case RGB18:
804 case RGB24:
805 case SYS8A:
806 case SYS8B:
807 case SYS8C:
808 case SYS8D:
809 case SYS9:
810 case SYS12:
811 case SYS16A:
812 case SYS16B:
813 case SYS16C:
814 case SYS18:
815 case SYS24:
816 break;
817 default:
818 return -EINVAL;
819 }
820
821 /* SUBLCD only supports SYS interface */
822 if (lcdc_chan_is_sublcd(ch)) {
823 if (!(interface_type & LDMT1R_IFM))
824 return -EINVAL;
825
826 interface_type &= ~LDMT1R_IFM;
827 }
828
829 ch->ldmt1r_value = interface_type;
830 return 0;
831}
832
833static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev,
834 int clock_source,
835 struct sh_mobile_lcdc_priv *priv)
836{
837 char *str;
838
839 switch (clock_source) {
840 case LCDC_CLK_BUS:
841 str = "bus_clk";
842 priv->lddckr = LDDCKR_ICKSEL_BUS;
843 break;
844 case LCDC_CLK_PERIPHERAL:
845 str = "peripheral_clk";
846 priv->lddckr = LDDCKR_ICKSEL_MIPI;
847 break;
848 case LCDC_CLK_EXTERNAL:
849 str = NULL;
850 priv->lddckr = LDDCKR_ICKSEL_HDMI;
851 break;
852 default:
853 return -EINVAL;
854 }
855
856 if (str) {
857 priv->dot_clk = clk_get(&pdev->dev, str);
858 if (IS_ERR(priv->dot_clk)) {
859 dev_err(&pdev->dev, "cannot get dot clock %s\n", str);
860 return PTR_ERR(priv->dot_clk);
861 }
862 }
863
864 /* Runtime PM support involves two step for this driver:
865 * 1) Enable Runtime PM
866 * 2) Force Runtime PM Resume since hardware is accessed from probe()
867 */
868 priv->dev = &pdev->dev;
869 pm_runtime_enable(priv->dev);
870 pm_runtime_resume(priv->dev);
871 return 0;
872}
873 840
874static int sh_mobile_lcdc_setcolreg(u_int regno, 841static int sh_mobile_lcdc_setcolreg(u_int regno,
875 u_int red, u_int green, u_int blue, 842 u_int red, u_int green, u_int blue,
@@ -1334,6 +1301,10 @@ static struct fb_ops sh_mobile_lcdc_ops = {
1334 .fb_set_par = sh_mobile_set_par, 1301 .fb_set_par = sh_mobile_set_par,
1335}; 1302};
1336 1303
1304/* -----------------------------------------------------------------------------
1305 * Backlight
1306 */
1307
1337static int sh_mobile_lcdc_update_bl(struct backlight_device *bdev) 1308static int sh_mobile_lcdc_update_bl(struct backlight_device *bdev)
1338{ 1309{
1339 struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev); 1310 struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev);
@@ -1393,6 +1364,10 @@ static void sh_mobile_lcdc_bl_remove(struct backlight_device *bdev)
1393 backlight_device_unregister(bdev); 1364 backlight_device_unregister(bdev);
1394} 1365}
1395 1366
1367/* -----------------------------------------------------------------------------
1368 * Power management
1369 */
1370
1396static int sh_mobile_lcdc_suspend(struct device *dev) 1371static int sh_mobile_lcdc_suspend(struct device *dev)
1397{ 1372{
1398 struct platform_device *pdev = to_platform_device(dev); 1373 struct platform_device *pdev = to_platform_device(dev);
@@ -1436,6 +1411,10 @@ static const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = {
1436 .runtime_resume = sh_mobile_lcdc_runtime_resume, 1411 .runtime_resume = sh_mobile_lcdc_runtime_resume,
1437}; 1412};
1438 1413
1414/* -----------------------------------------------------------------------------
1415 * Framebuffer notifier
1416 */
1417
1439/* locking: called with info->lock held */ 1418/* locking: called with info->lock held */
1440static int sh_mobile_lcdc_notify(struct notifier_block *nb, 1419static int sh_mobile_lcdc_notify(struct notifier_block *nb,
1441 unsigned long action, void *data) 1420 unsigned long action, void *data)
@@ -1476,6 +1455,28 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb,
1476 return NOTIFY_OK; 1455 return NOTIFY_OK;
1477} 1456}
1478 1457
1458/* -----------------------------------------------------------------------------
1459 * Probe/remove and driver init/exit
1460 */
1461
1462static const struct fb_videomode default_720p = {
1463 .name = "HDMI 720p",
1464 .xres = 1280,
1465 .yres = 720,
1466
1467 .left_margin = 220,
1468 .right_margin = 110,
1469 .hsync_len = 40,
1470
1471 .upper_margin = 20,
1472 .lower_margin = 5,
1473 .vsync_len = 5,
1474
1475 .pixclock = 13468,
1476 .refresh = 60,
1477 .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
1478};
1479
1479static int sh_mobile_lcdc_remove(struct platform_device *pdev) 1480static int sh_mobile_lcdc_remove(struct platform_device *pdev)
1480{ 1481{
1481 struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev); 1482 struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
@@ -1527,6 +1528,46 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
1527 return 0; 1528 return 0;
1528} 1529}
1529 1530
1531static int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
1532{
1533 int interface_type = ch->cfg.interface_type;
1534
1535 switch (interface_type) {
1536 case RGB8:
1537 case RGB9:
1538 case RGB12A:
1539 case RGB12B:
1540 case RGB16:
1541 case RGB18:
1542 case RGB24:
1543 case SYS8A:
1544 case SYS8B:
1545 case SYS8C:
1546 case SYS8D:
1547 case SYS9:
1548 case SYS12:
1549 case SYS16A:
1550 case SYS16B:
1551 case SYS16C:
1552 case SYS18:
1553 case SYS24:
1554 break;
1555 default:
1556 return -EINVAL;
1557 }
1558
1559 /* SUBLCD only supports SYS interface */
1560 if (lcdc_chan_is_sublcd(ch)) {
1561 if (!(interface_type & LDMT1R_IFM))
1562 return -EINVAL;
1563
1564 interface_type &= ~LDMT1R_IFM;
1565 }
1566
1567 ch->ldmt1r_value = interface_type;
1568 return 0;
1569}
1570
1530static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch, 1571static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch,
1531 struct device *dev) 1572 struct device *dev)
1532{ 1573{