diff options
author | Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | 2011-08-30 16:02:02 -0400 |
---|---|---|
committer | Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | 2011-08-30 16:02:02 -0400 |
commit | 8edbeb6eea647c26da482bd268ff67da209cba81 (patch) | |
tree | 251e607854abb6f8e7d82838ff3d7fd36586cc27 | |
parent | d4a7dbfdf180a656de3eb9e64614e2b991ffaa53 (diff) | |
parent | 8a20974f0370fe1b924704399e7ba327d894ef72 (diff) |
Merge branch 'sh-mobile-lcdc' of git://linuxtv.org/pinchartl/fbdev into fbdev-next
-rw-r--r-- | arch/arm/mach-shmobile/board-mackerel.c | 1 | ||||
-rw-r--r-- | drivers/video/sh_mobile_lcdcfb.c | 592 | ||||
-rw-r--r-- | drivers/video/sh_mobile_lcdcfb.h | 12 | ||||
-rw-r--r-- | drivers/video/sh_mobile_meram.c | 202 | ||||
-rw-r--r-- | drivers/video/sh_mobile_meram.h | 41 | ||||
-rw-r--r-- | include/video/sh_mobile_lcdc.h | 135 |
6 files changed, 556 insertions, 427 deletions
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index d41c01f83f15..6e3c2dfdcb81 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c | |||
@@ -1583,6 +1583,7 @@ static void __init mackerel_init(void) | |||
1583 | 1583 | ||
1584 | sh7372_add_device_to_domain(&sh7372_a4lc, &lcdc_device); | 1584 | sh7372_add_device_to_domain(&sh7372_a4lc, &lcdc_device); |
1585 | sh7372_add_device_to_domain(&sh7372_a4lc, &hdmi_lcdc_device); | 1585 | sh7372_add_device_to_domain(&sh7372_a4lc, &hdmi_lcdc_device); |
1586 | sh7372_add_device_to_domain(&sh7372_a4lc, &meram_device); | ||
1586 | sh7372_add_device_to_domain(&sh7372_a4mp, &fsi_device); | 1587 | sh7372_add_device_to_domain(&sh7372_a4mp, &fsi_device); |
1587 | 1588 | ||
1588 | hdmi_init_pm_clock(); | 1589 | hdmi_init_pm_clock(); |
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index b048417247e8..088cb17857e3 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c | |||
@@ -24,39 +24,14 @@ | |||
24 | #include <linux/backlight.h> | 24 | #include <linux/backlight.h> |
25 | #include <linux/gpio.h> | 25 | #include <linux/gpio.h> |
26 | #include <video/sh_mobile_lcdc.h> | 26 | #include <video/sh_mobile_lcdc.h> |
27 | #include <video/sh_mobile_meram.h> | ||
27 | #include <linux/atomic.h> | 28 | #include <linux/atomic.h> |
28 | 29 | ||
29 | #include "sh_mobile_lcdcfb.h" | 30 | #include "sh_mobile_lcdcfb.h" |
30 | #include "sh_mobile_meram.h" | ||
31 | 31 | ||
32 | #define SIDE_B_OFFSET 0x1000 | 32 | #define SIDE_B_OFFSET 0x1000 |
33 | #define MIRROR_OFFSET 0x2000 | 33 | #define MIRROR_OFFSET 0x2000 |
34 | 34 | ||
35 | /* shared registers */ | ||
36 | #define _LDDCKR 0x410 | ||
37 | #define _LDDCKSTPR 0x414 | ||
38 | #define _LDINTR 0x468 | ||
39 | #define _LDSR 0x46c | ||
40 | #define _LDCNT1R 0x470 | ||
41 | #define _LDCNT2R 0x474 | ||
42 | #define _LDRCNTR 0x478 | ||
43 | #define _LDDDSR 0x47c | ||
44 | #define _LDDWD0R 0x800 | ||
45 | #define _LDDRDR 0x840 | ||
46 | #define _LDDWAR 0x900 | ||
47 | #define _LDDRAR 0x904 | ||
48 | |||
49 | /* shared registers and their order for context save/restore */ | ||
50 | static int lcdc_shared_regs[] = { | ||
51 | _LDDCKR, | ||
52 | _LDDCKSTPR, | ||
53 | _LDINTR, | ||
54 | _LDDDSR, | ||
55 | _LDCNT1R, | ||
56 | _LDCNT2R, | ||
57 | }; | ||
58 | #define NR_SHARED_REGS ARRAY_SIZE(lcdc_shared_regs) | ||
59 | |||
60 | #define MAX_XRES 1920 | 35 | #define MAX_XRES 1920 |
61 | #define MAX_YRES 1080 | 36 | #define MAX_YRES 1080 |
62 | 37 | ||
@@ -98,22 +73,6 @@ static unsigned long lcdc_offs_sublcd[NR_CH_REGS] = { | |||
98 | [LDPMR] = 0x63c, | 73 | [LDPMR] = 0x63c, |
99 | }; | 74 | }; |
100 | 75 | ||
101 | #define START_LCDC 0x00000001 | ||
102 | #define LCDC_RESET 0x00000100 | ||
103 | #define DISPLAY_BEU 0x00000008 | ||
104 | #define LCDC_ENABLE 0x00000001 | ||
105 | #define LDINTR_FE 0x00000400 | ||
106 | #define LDINTR_VSE 0x00000200 | ||
107 | #define LDINTR_VEE 0x00000100 | ||
108 | #define LDINTR_FS 0x00000004 | ||
109 | #define LDINTR_VSS 0x00000002 | ||
110 | #define LDINTR_VES 0x00000001 | ||
111 | #define LDRCNTR_SRS 0x00020000 | ||
112 | #define LDRCNTR_SRC 0x00010000 | ||
113 | #define LDRCNTR_MRS 0x00000002 | ||
114 | #define LDRCNTR_MRC 0x00000001 | ||
115 | #define LDSR_MRS 0x00000100 | ||
116 | |||
117 | static const struct fb_videomode default_720p = { | 76 | static const struct fb_videomode default_720p = { |
118 | .name = "HDMI 720p", | 77 | .name = "HDMI 720p", |
119 | .xres = 1280, | 78 | .xres = 1280, |
@@ -141,7 +100,6 @@ struct sh_mobile_lcdc_priv { | |||
141 | unsigned long lddckr; | 100 | unsigned long lddckr; |
142 | struct sh_mobile_lcdc_chan ch[2]; | 101 | struct sh_mobile_lcdc_chan ch[2]; |
143 | struct notifier_block notifier; | 102 | struct notifier_block notifier; |
144 | unsigned long saved_shared_regs[NR_SHARED_REGS]; | ||
145 | int started; | 103 | int started; |
146 | int forced_bpp; /* 2 channel LCDC must share bpp setting */ | 104 | int forced_bpp; /* 2 channel LCDC must share bpp setting */ |
147 | struct sh_mobile_meram_info *meram_dev; | 105 | struct sh_mobile_meram_info *meram_dev; |
@@ -218,33 +176,36 @@ static void lcdc_sys_write_index(void *handle, unsigned long data) | |||
218 | { | 176 | { |
219 | struct sh_mobile_lcdc_chan *ch = handle; | 177 | struct sh_mobile_lcdc_chan *ch = handle; |
220 | 178 | ||
221 | lcdc_write(ch->lcdc, _LDDWD0R, data | 0x10000000); | 179 | lcdc_write(ch->lcdc, _LDDWD0R, data | LDDWDxR_WDACT); |
222 | lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); | 180 | lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0); |
223 | lcdc_write(ch->lcdc, _LDDWAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0)); | 181 | lcdc_write(ch->lcdc, _LDDWAR, LDDWAR_WA | |
224 | lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); | 182 | (lcdc_chan_is_sublcd(ch) ? 2 : 0)); |
183 | lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0); | ||
225 | } | 184 | } |
226 | 185 | ||
227 | static void lcdc_sys_write_data(void *handle, unsigned long data) | 186 | static void lcdc_sys_write_data(void *handle, unsigned long data) |
228 | { | 187 | { |
229 | struct sh_mobile_lcdc_chan *ch = handle; | 188 | struct sh_mobile_lcdc_chan *ch = handle; |
230 | 189 | ||
231 | lcdc_write(ch->lcdc, _LDDWD0R, data | 0x11000000); | 190 | lcdc_write(ch->lcdc, _LDDWD0R, data | LDDWDxR_WDACT | LDDWDxR_RSW); |
232 | lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); | 191 | lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0); |
233 | lcdc_write(ch->lcdc, _LDDWAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0)); | 192 | lcdc_write(ch->lcdc, _LDDWAR, LDDWAR_WA | |
234 | lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); | 193 | (lcdc_chan_is_sublcd(ch) ? 2 : 0)); |
194 | lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0); | ||
235 | } | 195 | } |
236 | 196 | ||
237 | static unsigned long lcdc_sys_read_data(void *handle) | 197 | static unsigned long lcdc_sys_read_data(void *handle) |
238 | { | 198 | { |
239 | struct sh_mobile_lcdc_chan *ch = handle; | 199 | struct sh_mobile_lcdc_chan *ch = handle; |
240 | 200 | ||
241 | lcdc_write(ch->lcdc, _LDDRDR, 0x01000000); | 201 | lcdc_write(ch->lcdc, _LDDRDR, LDDRDR_RSR); |
242 | lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); | 202 | lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0); |
243 | lcdc_write(ch->lcdc, _LDDRAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0)); | 203 | lcdc_write(ch->lcdc, _LDDRAR, LDDRAR_RA | |
204 | (lcdc_chan_is_sublcd(ch) ? 2 : 0)); | ||
244 | udelay(1); | 205 | udelay(1); |
245 | lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); | 206 | lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0); |
246 | 207 | ||
247 | return lcdc_read(ch->lcdc, _LDDRDR) & 0x3ffff; | 208 | return lcdc_read(ch->lcdc, _LDDRDR) & LDDRDR_DRD_MASK; |
248 | } | 209 | } |
249 | 210 | ||
250 | struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = { | 211 | struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = { |
@@ -256,18 +217,22 @@ struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = { | |||
256 | static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) | 217 | static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) |
257 | { | 218 | { |
258 | if (atomic_inc_and_test(&priv->hw_usecnt)) { | 219 | if (atomic_inc_and_test(&priv->hw_usecnt)) { |
259 | pm_runtime_get_sync(priv->dev); | ||
260 | if (priv->dot_clk) | 220 | if (priv->dot_clk) |
261 | clk_enable(priv->dot_clk); | 221 | clk_enable(priv->dot_clk); |
222 | pm_runtime_get_sync(priv->dev); | ||
223 | if (priv->meram_dev && priv->meram_dev->pdev) | ||
224 | pm_runtime_get_sync(&priv->meram_dev->pdev->dev); | ||
262 | } | 225 | } |
263 | } | 226 | } |
264 | 227 | ||
265 | static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv) | 228 | static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv) |
266 | { | 229 | { |
267 | if (atomic_sub_return(1, &priv->hw_usecnt) == -1) { | 230 | if (atomic_sub_return(1, &priv->hw_usecnt) == -1) { |
231 | if (priv->meram_dev && priv->meram_dev->pdev) | ||
232 | pm_runtime_put_sync(&priv->meram_dev->pdev->dev); | ||
233 | pm_runtime_put(priv->dev); | ||
268 | if (priv->dot_clk) | 234 | if (priv->dot_clk) |
269 | clk_disable(priv->dot_clk); | 235 | clk_disable(priv->dot_clk); |
270 | pm_runtime_put(priv->dev); | ||
271 | } | 236 | } |
272 | } | 237 | } |
273 | 238 | ||
@@ -319,13 +284,13 @@ static void sh_mobile_lcdc_deferred_io(struct fb_info *info, | |||
319 | if (bcfg->start_transfer) | 284 | if (bcfg->start_transfer) |
320 | bcfg->start_transfer(bcfg->board_data, ch, | 285 | bcfg->start_transfer(bcfg->board_data, ch, |
321 | &sh_mobile_lcdc_sys_bus_ops); | 286 | &sh_mobile_lcdc_sys_bus_ops); |
322 | lcdc_write_chan(ch, LDSM2R, 1); | 287 | lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG); |
323 | dma_unmap_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE); | 288 | dma_unmap_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE); |
324 | } else { | 289 | } else { |
325 | if (bcfg->start_transfer) | 290 | if (bcfg->start_transfer) |
326 | bcfg->start_transfer(bcfg->board_data, ch, | 291 | bcfg->start_transfer(bcfg->board_data, ch, |
327 | &sh_mobile_lcdc_sys_bus_ops); | 292 | &sh_mobile_lcdc_sys_bus_ops); |
328 | lcdc_write_chan(ch, LDSM2R, 1); | 293 | lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG); |
329 | } | 294 | } |
330 | } | 295 | } |
331 | 296 | ||
@@ -341,22 +306,16 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data) | |||
341 | { | 306 | { |
342 | struct sh_mobile_lcdc_priv *priv = data; | 307 | struct sh_mobile_lcdc_priv *priv = data; |
343 | struct sh_mobile_lcdc_chan *ch; | 308 | struct sh_mobile_lcdc_chan *ch; |
344 | unsigned long tmp; | ||
345 | unsigned long ldintr; | 309 | unsigned long ldintr; |
346 | int is_sub; | 310 | int is_sub; |
347 | int k; | 311 | int k; |
348 | 312 | ||
349 | /* acknowledge interrupt */ | 313 | /* Acknowledge interrupts and disable further VSYNC End IRQs. */ |
350 | ldintr = tmp = lcdc_read(priv, _LDINTR); | 314 | ldintr = lcdc_read(priv, _LDINTR); |
351 | /* | 315 | lcdc_write(priv, _LDINTR, (ldintr ^ LDINTR_STATUS_MASK) & ~LDINTR_VEE); |
352 | * disable further VSYNC End IRQs, preserve all other enabled IRQs, | ||
353 | * write 0 to bits 0-6 to ack all triggered IRQs. | ||
354 | */ | ||
355 | tmp &= 0xffffff00 & ~LDINTR_VEE; | ||
356 | lcdc_write(priv, _LDINTR, tmp); | ||
357 | 316 | ||
358 | /* figure out if this interrupt is for main or sub lcd */ | 317 | /* figure out if this interrupt is for main or sub lcd */ |
359 | is_sub = (lcdc_read(priv, _LDSR) & (1 << 10)) ? 1 : 0; | 318 | is_sub = (lcdc_read(priv, _LDSR) & LDSR_MSS) ? 1 : 0; |
360 | 319 | ||
361 | /* wake up channel and disable clocks */ | 320 | /* wake up channel and disable clocks */ |
362 | for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { | 321 | for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { |
@@ -365,7 +324,7 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data) | |||
365 | if (!ch->enabled) | 324 | if (!ch->enabled) |
366 | continue; | 325 | continue; |
367 | 326 | ||
368 | /* Frame Start */ | 327 | /* Frame End */ |
369 | if (ldintr & LDINTR_FS) { | 328 | if (ldintr & LDINTR_FS) { |
370 | if (is_sub == lcdc_chan_is_sublcd(ch)) { | 329 | if (is_sub == lcdc_chan_is_sublcd(ch)) { |
371 | ch->frame_end = 1; | 330 | ch->frame_end = 1; |
@@ -391,16 +350,17 @@ static void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv, | |||
391 | 350 | ||
392 | /* start or stop the lcdc */ | 351 | /* start or stop the lcdc */ |
393 | if (start) | 352 | if (start) |
394 | lcdc_write(priv, _LDCNT2R, tmp | START_LCDC); | 353 | lcdc_write(priv, _LDCNT2R, tmp | LDCNT2R_DO); |
395 | else | 354 | else |
396 | lcdc_write(priv, _LDCNT2R, tmp & ~START_LCDC); | 355 | lcdc_write(priv, _LDCNT2R, tmp & ~LDCNT2R_DO); |
397 | 356 | ||
398 | /* wait until power is applied/stopped on all channels */ | 357 | /* wait until power is applied/stopped on all channels */ |
399 | for (k = 0; k < ARRAY_SIZE(priv->ch); k++) | 358 | for (k = 0; k < ARRAY_SIZE(priv->ch); k++) |
400 | if (lcdc_read(priv, _LDCNT2R) & priv->ch[k].enabled) | 359 | if (lcdc_read(priv, _LDCNT2R) & priv->ch[k].enabled) |
401 | while (1) { | 360 | while (1) { |
402 | tmp = lcdc_read_chan(&priv->ch[k], LDPMR) & 3; | 361 | tmp = lcdc_read_chan(&priv->ch[k], LDPMR) |
403 | if (start && tmp == 3) | 362 | & LDPMR_LPS; |
363 | if (start && tmp == LDPMR_LPS) | ||
404 | break; | 364 | break; |
405 | if (!start && tmp == 0) | 365 | if (!start && tmp == 0) |
406 | break; | 366 | break; |
@@ -418,13 +378,13 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) | |||
418 | u32 tmp; | 378 | u32 tmp; |
419 | 379 | ||
420 | tmp = ch->ldmt1r_value; | 380 | tmp = ch->ldmt1r_value; |
421 | tmp |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1 << 28; | 381 | tmp |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : LDMT1R_VPOL; |
422 | tmp |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1 << 27; | 382 | tmp |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : LDMT1R_HPOL; |
423 | tmp |= (ch->cfg.flags & LCDC_FLAGS_DWPOL) ? 1 << 26 : 0; | 383 | tmp |= (ch->cfg.flags & LCDC_FLAGS_DWPOL) ? LDMT1R_DWPOL : 0; |
424 | tmp |= (ch->cfg.flags & LCDC_FLAGS_DIPOL) ? 1 << 25 : 0; | 384 | tmp |= (ch->cfg.flags & LCDC_FLAGS_DIPOL) ? LDMT1R_DIPOL : 0; |
425 | tmp |= (ch->cfg.flags & LCDC_FLAGS_DAPOL) ? 1 << 24 : 0; | 385 | tmp |= (ch->cfg.flags & LCDC_FLAGS_DAPOL) ? LDMT1R_DAPOL : 0; |
426 | tmp |= (ch->cfg.flags & LCDC_FLAGS_HSCNT) ? 1 << 17 : 0; | 386 | tmp |= (ch->cfg.flags & LCDC_FLAGS_HSCNT) ? LDMT1R_HSCNT : 0; |
427 | tmp |= (ch->cfg.flags & LCDC_FLAGS_DWCNT) ? 1 << 16 : 0; | 387 | tmp |= (ch->cfg.flags & LCDC_FLAGS_DWCNT) ? LDMT1R_DWCNT : 0; |
428 | lcdc_write_chan(ch, LDMT1R, tmp); | 388 | lcdc_write_chan(ch, LDMT1R, tmp); |
429 | 389 | ||
430 | /* setup SYS bus */ | 390 | /* setup SYS bus */ |
@@ -463,242 +423,239 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) | |||
463 | lcdc_write_chan(ch, LDHAJR, tmp); | 423 | lcdc_write_chan(ch, LDHAJR, tmp); |
464 | } | 424 | } |
465 | 425 | ||
466 | static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | 426 | /* |
427 | * __sh_mobile_lcdc_start - Configure and tart the LCDC | ||
428 | * @priv: LCDC device | ||
429 | * | ||
430 | * Configure all enabled channels and start the LCDC device. All external | ||
431 | * devices (clocks, MERAM, panels, ...) are not touched by this function. | ||
432 | */ | ||
433 | static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | ||
467 | { | 434 | { |
468 | struct sh_mobile_lcdc_chan *ch; | 435 | struct sh_mobile_lcdc_chan *ch; |
469 | struct sh_mobile_lcdc_board_cfg *board_cfg; | ||
470 | unsigned long tmp; | 436 | unsigned long tmp; |
471 | int bpp = 0; | 437 | int bpp = 0; |
472 | unsigned long ldddsr; | 438 | int k, m; |
473 | int k, m, ret; | ||
474 | |||
475 | /* enable clocks before accessing the hardware */ | ||
476 | for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { | ||
477 | if (priv->ch[k].enabled) { | ||
478 | sh_mobile_lcdc_clk_on(priv); | ||
479 | if (!bpp) | ||
480 | bpp = priv->ch[k].info->var.bits_per_pixel; | ||
481 | } | ||
482 | } | ||
483 | |||
484 | /* reset */ | ||
485 | lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LCDC_RESET); | ||
486 | lcdc_wait_bit(priv, _LDCNT2R, LCDC_RESET, 0); | ||
487 | |||
488 | /* enable LCDC channels */ | ||
489 | tmp = lcdc_read(priv, _LDCNT2R); | ||
490 | tmp |= priv->ch[0].enabled; | ||
491 | tmp |= priv->ch[1].enabled; | ||
492 | lcdc_write(priv, _LDCNT2R, tmp); | ||
493 | 439 | ||
494 | /* read data from external memory, avoid using the BEU for now */ | 440 | /* Enable LCDC channels. Read data from external memory, avoid using the |
495 | lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) & ~DISPLAY_BEU); | 441 | * BEU for now. |
442 | */ | ||
443 | lcdc_write(priv, _LDCNT2R, priv->ch[0].enabled | priv->ch[1].enabled); | ||
496 | 444 | ||
497 | /* stop the lcdc first */ | 445 | /* Stop the LCDC first and disable all interrupts. */ |
498 | sh_mobile_lcdc_start_stop(priv, 0); | 446 | sh_mobile_lcdc_start_stop(priv, 0); |
447 | lcdc_write(priv, _LDINTR, 0); | ||
499 | 448 | ||
500 | /* configure clocks */ | 449 | /* Configure power supply, dot clocks and start them. */ |
501 | tmp = priv->lddckr; | 450 | tmp = priv->lddckr; |
502 | for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { | 451 | for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { |
503 | ch = &priv->ch[k]; | 452 | ch = &priv->ch[k]; |
504 | 453 | if (!ch->enabled) | |
505 | if (!priv->ch[k].enabled) | ||
506 | continue; | 454 | continue; |
507 | 455 | ||
456 | if (!bpp) | ||
457 | bpp = ch->info->var.bits_per_pixel; | ||
458 | |||
459 | /* Power supply */ | ||
460 | lcdc_write_chan(ch, LDPMR, 0); | ||
461 | |||
508 | m = ch->cfg.clock_divider; | 462 | m = ch->cfg.clock_divider; |
509 | if (!m) | 463 | if (!m) |
510 | continue; | 464 | continue; |
511 | 465 | ||
512 | if (m == 1) | 466 | /* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider |
513 | m = 1 << 6; | 467 | * denominator. |
514 | tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0); | 468 | */ |
515 | |||
516 | /* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider denominator */ | ||
517 | lcdc_write_chan(ch, LDDCKPAT1R, 0); | 469 | lcdc_write_chan(ch, LDDCKPAT1R, 0); |
518 | lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1); | 470 | lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1); |
471 | |||
472 | if (m == 1) | ||
473 | m = LDDCKR_MOSEL; | ||
474 | tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0); | ||
519 | } | 475 | } |
520 | 476 | ||
521 | lcdc_write(priv, _LDDCKR, tmp); | 477 | lcdc_write(priv, _LDDCKR, tmp); |
522 | |||
523 | /* start dotclock again */ | ||
524 | lcdc_write(priv, _LDDCKSTPR, 0); | 478 | lcdc_write(priv, _LDDCKSTPR, 0); |
525 | lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0); | 479 | lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0); |
526 | 480 | ||
527 | /* interrupts are disabled to begin with */ | 481 | /* Setup geometry, format, frame buffer memory and operation mode. */ |
528 | lcdc_write(priv, _LDINTR, 0); | ||
529 | |||
530 | for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { | 482 | for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { |
531 | ch = &priv->ch[k]; | 483 | ch = &priv->ch[k]; |
532 | |||
533 | if (!ch->enabled) | 484 | if (!ch->enabled) |
534 | continue; | 485 | continue; |
535 | 486 | ||
536 | sh_mobile_lcdc_geometry(ch); | 487 | sh_mobile_lcdc_geometry(ch); |
537 | 488 | ||
538 | /* power supply */ | ||
539 | lcdc_write_chan(ch, LDPMR, 0); | ||
540 | |||
541 | board_cfg = &ch->cfg.board_cfg; | ||
542 | if (board_cfg->setup_sys) { | ||
543 | ret = board_cfg->setup_sys(board_cfg->board_data, | ||
544 | ch, &sh_mobile_lcdc_sys_bus_ops); | ||
545 | if (ret) | ||
546 | return ret; | ||
547 | } | ||
548 | } | ||
549 | |||
550 | /* word and long word swap */ | ||
551 | ldddsr = lcdc_read(priv, _LDDDSR); | ||
552 | if (priv->ch[0].info->var.nonstd) | ||
553 | lcdc_write(priv, _LDDDSR, ldddsr | 7); | ||
554 | else { | ||
555 | switch (bpp) { | ||
556 | case 16: | ||
557 | lcdc_write(priv, _LDDDSR, ldddsr | 6); | ||
558 | break; | ||
559 | case 24: | ||
560 | lcdc_write(priv, _LDDDSR, ldddsr | 7); | ||
561 | break; | ||
562 | case 32: | ||
563 | lcdc_write(priv, _LDDDSR, ldddsr | 4); | ||
564 | break; | ||
565 | } | ||
566 | } | ||
567 | |||
568 | for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { | ||
569 | unsigned long base_addr_y; | ||
570 | unsigned long base_addr_c = 0; | ||
571 | int pitch; | ||
572 | ch = &priv->ch[k]; | ||
573 | |||
574 | if (!priv->ch[k].enabled) | ||
575 | continue; | ||
576 | |||
577 | /* set bpp format in PKF[4:0] */ | ||
578 | tmp = lcdc_read_chan(ch, LDDFR); | ||
579 | tmp &= ~0x0003031f; | ||
580 | if (ch->info->var.nonstd) { | 489 | if (ch->info->var.nonstd) { |
581 | tmp |= (ch->info->var.nonstd << 16); | 490 | tmp = (ch->info->var.nonstd << 16); |
582 | switch (ch->info->var.bits_per_pixel) { | 491 | switch (ch->info->var.bits_per_pixel) { |
583 | case 12: | 492 | case 12: |
493 | tmp |= LDDFR_YF_420; | ||
584 | break; | 494 | break; |
585 | case 16: | 495 | case 16: |
586 | tmp |= (0x1 << 8); | 496 | tmp |= LDDFR_YF_422; |
587 | break; | 497 | break; |
588 | case 24: | 498 | case 24: |
589 | tmp |= (0x2 << 8); | 499 | default: |
500 | tmp |= LDDFR_YF_444; | ||
590 | break; | 501 | break; |
591 | } | 502 | } |
592 | } else { | 503 | } else { |
593 | switch (ch->info->var.bits_per_pixel) { | 504 | switch (ch->info->var.bits_per_pixel) { |
594 | case 16: | 505 | case 16: |
595 | tmp |= 0x03; | 506 | tmp = LDDFR_PKF_RGB16; |
596 | break; | 507 | break; |
597 | case 24: | 508 | case 24: |
598 | tmp |= 0x0b; | 509 | tmp = LDDFR_PKF_RGB24; |
599 | break; | 510 | break; |
600 | case 32: | 511 | case 32: |
512 | default: | ||
513 | tmp = LDDFR_PKF_ARGB32; | ||
601 | break; | 514 | break; |
602 | } | 515 | } |
603 | } | 516 | } |
517 | |||
604 | lcdc_write_chan(ch, LDDFR, tmp); | 518 | lcdc_write_chan(ch, LDDFR, tmp); |
519 | lcdc_write_chan(ch, LDMLSR, ch->pitch); | ||
520 | lcdc_write_chan(ch, LDSA1R, ch->base_addr_y); | ||
521 | if (ch->info->var.nonstd) | ||
522 | lcdc_write_chan(ch, LDSA2R, ch->base_addr_c); | ||
605 | 523 | ||
606 | base_addr_y = ch->info->fix.smem_start; | 524 | /* When using deferred I/O mode, configure the LCDC for one-shot |
607 | base_addr_c = base_addr_y + | 525 | * operation and enable the frame end interrupt. Otherwise use |
608 | ch->info->var.xres * | 526 | * continuous read mode. |
609 | ch->info->var.yres_virtual; | 527 | */ |
610 | pitch = ch->info->fix.line_length; | 528 | if (ch->ldmt1r_value & LDMT1R_IFM && |
529 | ch->cfg.sys_bus_cfg.deferred_io_msec) { | ||
530 | lcdc_write_chan(ch, LDSM1R, LDSM1R_OS); | ||
531 | lcdc_write(priv, _LDINTR, LDINTR_FE); | ||
532 | } else { | ||
533 | lcdc_write_chan(ch, LDSM1R, 0); | ||
534 | } | ||
535 | } | ||
611 | 536 | ||
612 | /* test if we can enable meram */ | 537 | /* Word and long word swap. */ |
613 | if (ch->cfg.meram_cfg && priv->meram_dev && | 538 | if (priv->ch[0].info->var.nonstd) |
614 | priv->meram_dev->ops) { | 539 | tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS; |
615 | struct sh_mobile_meram_cfg *cfg; | 540 | else { |
616 | struct sh_mobile_meram_info *mdev; | 541 | switch (bpp) { |
617 | unsigned long icb_addr_y, icb_addr_c; | 542 | case 16: |
618 | int icb_pitch; | 543 | tmp = LDDDSR_LS | LDDDSR_WS; |
619 | int pf; | 544 | break; |
545 | case 24: | ||
546 | tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS; | ||
547 | break; | ||
548 | case 32: | ||
549 | default: | ||
550 | tmp = LDDDSR_LS; | ||
551 | break; | ||
552 | } | ||
553 | } | ||
554 | lcdc_write(priv, _LDDDSR, tmp); | ||
620 | 555 | ||
621 | cfg = ch->cfg.meram_cfg; | 556 | /* Enable the display output. */ |
622 | mdev = priv->meram_dev; | 557 | lcdc_write(priv, _LDCNT1R, LDCNT1R_DE); |
623 | /* we need to de-init configured ICBs before we | 558 | sh_mobile_lcdc_start_stop(priv, 1); |
624 | * we can re-initialize them. | 559 | priv->started = 1; |
625 | */ | 560 | } |
626 | if (ch->meram_enabled) | ||
627 | mdev->ops->meram_unregister(mdev, cfg); | ||
628 | 561 | ||
629 | ch->meram_enabled = 0; | 562 | static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) |
563 | { | ||
564 | struct sh_mobile_meram_info *mdev = priv->meram_dev; | ||
565 | struct sh_mobile_lcdc_board_cfg *board_cfg; | ||
566 | struct sh_mobile_lcdc_chan *ch; | ||
567 | unsigned long tmp; | ||
568 | int ret; | ||
569 | int k; | ||
630 | 570 | ||
631 | if (ch->info->var.nonstd) { | 571 | /* enable clocks before accessing the hardware */ |
632 | if (ch->info->var.bits_per_pixel == 24) | 572 | for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { |
633 | pf = SH_MOBILE_MERAM_PF_NV24; | 573 | if (priv->ch[k].enabled) |
634 | else | 574 | sh_mobile_lcdc_clk_on(priv); |
635 | pf = SH_MOBILE_MERAM_PF_NV; | 575 | } |
636 | } else { | ||
637 | pf = SH_MOBILE_MERAM_PF_RGB; | ||
638 | } | ||
639 | 576 | ||
640 | ret = mdev->ops->meram_register(mdev, cfg, pitch, | 577 | /* reset */ |
641 | ch->info->var.yres, | 578 | lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LDCNT2R_BR); |
642 | pf, | 579 | lcdc_wait_bit(priv, _LDCNT2R, LDCNT2R_BR, 0); |
643 | base_addr_y, | ||
644 | base_addr_c, | ||
645 | &icb_addr_y, | ||
646 | &icb_addr_c, | ||
647 | &icb_pitch); | ||
648 | if (!ret) { | ||
649 | /* set LDSA1R value */ | ||
650 | base_addr_y = icb_addr_y; | ||
651 | pitch = icb_pitch; | ||
652 | |||
653 | /* set LDSA2R value if required */ | ||
654 | if (base_addr_c) | ||
655 | base_addr_c = icb_addr_c; | ||
656 | |||
657 | ch->meram_enabled = 1; | ||
658 | } | ||
659 | } | ||
660 | 580 | ||
661 | /* point out our frame buffer */ | 581 | for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { |
662 | lcdc_write_chan(ch, LDSA1R, base_addr_y); | 582 | ch = &priv->ch[k]; |
663 | if (ch->info->var.nonstd) | ||
664 | lcdc_write_chan(ch, LDSA2R, base_addr_c); | ||
665 | 583 | ||
666 | /* set line size */ | 584 | if (!ch->enabled) |
667 | lcdc_write_chan(ch, LDMLSR, pitch); | 585 | continue; |
668 | 586 | ||
669 | /* setup deferred io if SYS bus */ | 587 | board_cfg = &ch->cfg.board_cfg; |
670 | tmp = ch->cfg.sys_bus_cfg.deferred_io_msec; | 588 | if (board_cfg->setup_sys) { |
671 | if (ch->ldmt1r_value & (1 << 12) && tmp) { | 589 | ret = board_cfg->setup_sys(board_cfg->board_data, ch, |
672 | ch->defio.deferred_io = sh_mobile_lcdc_deferred_io; | 590 | &sh_mobile_lcdc_sys_bus_ops); |
673 | ch->defio.delay = msecs_to_jiffies(tmp); | 591 | if (ret) |
674 | ch->info->fbdefio = &ch->defio; | 592 | return ret; |
675 | fb_deferred_io_init(ch->info); | 593 | } |
594 | } | ||
676 | 595 | ||
677 | /* one-shot mode */ | 596 | /* Compute frame buffer base address and pitch for each channel. */ |
678 | lcdc_write_chan(ch, LDSM1R, 1); | 597 | for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { |
598 | struct sh_mobile_meram_cfg *cfg; | ||
599 | int pixelformat; | ||
679 | 600 | ||
680 | /* enable "Frame End Interrupt Enable" bit */ | 601 | ch = &priv->ch[k]; |
681 | lcdc_write(priv, _LDINTR, LDINTR_FE); | 602 | if (!ch->enabled) |
603 | continue; | ||
682 | 604 | ||
683 | } else { | 605 | ch->base_addr_y = ch->info->fix.smem_start; |
684 | /* continuous read mode */ | 606 | ch->base_addr_c = ch->base_addr_y |
685 | lcdc_write_chan(ch, LDSM1R, 0); | 607 | + ch->info->var.xres |
608 | * ch->info->var.yres_virtual; | ||
609 | ch->pitch = ch->info->fix.line_length; | ||
610 | |||
611 | /* Enable MERAM if possible. */ | ||
612 | cfg = ch->cfg.meram_cfg; | ||
613 | if (mdev == NULL || mdev->ops == NULL || cfg == NULL) | ||
614 | continue; | ||
615 | |||
616 | /* we need to de-init configured ICBs before we can | ||
617 | * re-initialize them. | ||
618 | */ | ||
619 | if (ch->meram_enabled) { | ||
620 | mdev->ops->meram_unregister(mdev, cfg); | ||
621 | ch->meram_enabled = 0; | ||
686 | } | 622 | } |
687 | } | ||
688 | 623 | ||
689 | /* display output */ | 624 | if (!ch->info->var.nonstd) |
690 | lcdc_write(priv, _LDCNT1R, LCDC_ENABLE); | 625 | pixelformat = SH_MOBILE_MERAM_PF_RGB; |
626 | else if (ch->info->var.bits_per_pixel == 24) | ||
627 | pixelformat = SH_MOBILE_MERAM_PF_NV24; | ||
628 | else | ||
629 | pixelformat = SH_MOBILE_MERAM_PF_NV; | ||
630 | |||
631 | ret = mdev->ops->meram_register(mdev, cfg, ch->pitch, | ||
632 | ch->info->var.yres, pixelformat, | ||
633 | ch->base_addr_y, ch->base_addr_c, | ||
634 | &ch->base_addr_y, &ch->base_addr_c, | ||
635 | &ch->pitch); | ||
636 | if (!ret) | ||
637 | ch->meram_enabled = 1; | ||
638 | } | ||
691 | 639 | ||
692 | /* start the lcdc */ | 640 | /* Start the LCDC. */ |
693 | sh_mobile_lcdc_start_stop(priv, 1); | 641 | __sh_mobile_lcdc_start(priv); |
694 | priv->started = 1; | ||
695 | 642 | ||
696 | /* tell the board code to enable the panel */ | 643 | /* Setup deferred I/O, tell the board code to enable the panels, and |
644 | * turn backlight on. | ||
645 | */ | ||
697 | for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { | 646 | for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { |
698 | ch = &priv->ch[k]; | 647 | ch = &priv->ch[k]; |
699 | if (!ch->enabled) | 648 | if (!ch->enabled) |
700 | continue; | 649 | continue; |
701 | 650 | ||
651 | tmp = ch->cfg.sys_bus_cfg.deferred_io_msec; | ||
652 | if (ch->ldmt1r_value & LDMT1R_IFM && tmp) { | ||
653 | ch->defio.deferred_io = sh_mobile_lcdc_deferred_io; | ||
654 | ch->defio.delay = msecs_to_jiffies(tmp); | ||
655 | ch->info->fbdefio = &ch->defio; | ||
656 | fb_deferred_io_init(ch->info); | ||
657 | } | ||
658 | |||
702 | board_cfg = &ch->cfg.board_cfg; | 659 | board_cfg = &ch->cfg.board_cfg; |
703 | if (board_cfg->display_on && try_module_get(board_cfg->owner)) { | 660 | if (board_cfg->display_on && try_module_get(board_cfg->owner)) { |
704 | board_cfg->display_on(board_cfg->board_data, ch->info); | 661 | board_cfg->display_on(board_cfg->board_data, ch->info); |
@@ -776,42 +733,42 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) | |||
776 | 733 | ||
777 | static int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch) | 734 | static int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch) |
778 | { | 735 | { |
779 | int ifm, miftyp; | 736 | int interface_type = ch->cfg.interface_type; |
780 | 737 | ||
781 | switch (ch->cfg.interface_type) { | 738 | switch (interface_type) { |
782 | case RGB8: ifm = 0; miftyp = 0; break; | 739 | case RGB8: |
783 | case RGB9: ifm = 0; miftyp = 4; break; | 740 | case RGB9: |
784 | case RGB12A: ifm = 0; miftyp = 5; break; | 741 | case RGB12A: |
785 | case RGB12B: ifm = 0; miftyp = 6; break; | 742 | case RGB12B: |
786 | case RGB16: ifm = 0; miftyp = 7; break; | 743 | case RGB16: |
787 | case RGB18: ifm = 0; miftyp = 10; break; | 744 | case RGB18: |
788 | case RGB24: ifm = 0; miftyp = 11; break; | 745 | case RGB24: |
789 | case SYS8A: ifm = 1; miftyp = 0; break; | 746 | case SYS8A: |
790 | case SYS8B: ifm = 1; miftyp = 1; break; | 747 | case SYS8B: |
791 | case SYS8C: ifm = 1; miftyp = 2; break; | 748 | case SYS8C: |
792 | case SYS8D: ifm = 1; miftyp = 3; break; | 749 | case SYS8D: |
793 | case SYS9: ifm = 1; miftyp = 4; break; | 750 | case SYS9: |
794 | case SYS12: ifm = 1; miftyp = 5; break; | 751 | case SYS12: |
795 | case SYS16A: ifm = 1; miftyp = 7; break; | 752 | case SYS16A: |
796 | case SYS16B: ifm = 1; miftyp = 8; break; | 753 | case SYS16B: |
797 | case SYS16C: ifm = 1; miftyp = 9; break; | 754 | case SYS16C: |
798 | case SYS18: ifm = 1; miftyp = 10; break; | 755 | case SYS18: |
799 | case SYS24: ifm = 1; miftyp = 11; break; | 756 | case SYS24: |
800 | default: goto bad; | 757 | break; |
758 | default: | ||
759 | return -EINVAL; | ||
801 | } | 760 | } |
802 | 761 | ||
803 | /* SUBLCD only supports SYS interface */ | 762 | /* SUBLCD only supports SYS interface */ |
804 | if (lcdc_chan_is_sublcd(ch)) { | 763 | if (lcdc_chan_is_sublcd(ch)) { |
805 | if (ifm == 0) | 764 | if (!(interface_type & LDMT1R_IFM)) |
806 | goto bad; | 765 | return -EINVAL; |
807 | else | 766 | |
808 | ifm = 0; | 767 | interface_type &= ~LDMT1R_IFM; |
809 | } | 768 | } |
810 | 769 | ||
811 | ch->ldmt1r_value = (ifm << 12) | miftyp; | 770 | ch->ldmt1r_value = interface_type; |
812 | return 0; | 771 | return 0; |
813 | bad: | ||
814 | return -EINVAL; | ||
815 | } | 772 | } |
816 | 773 | ||
817 | static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev, | 774 | static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev, |
@@ -819,18 +776,24 @@ static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev, | |||
819 | struct sh_mobile_lcdc_priv *priv) | 776 | struct sh_mobile_lcdc_priv *priv) |
820 | { | 777 | { |
821 | char *str; | 778 | char *str; |
822 | int icksel; | ||
823 | 779 | ||
824 | switch (clock_source) { | 780 | switch (clock_source) { |
825 | case LCDC_CLK_BUS: str = "bus_clk"; icksel = 0; break; | 781 | case LCDC_CLK_BUS: |
826 | case LCDC_CLK_PERIPHERAL: str = "peripheral_clk"; icksel = 1; break; | 782 | str = "bus_clk"; |
827 | case LCDC_CLK_EXTERNAL: str = NULL; icksel = 2; break; | 783 | priv->lddckr = LDDCKR_ICKSEL_BUS; |
784 | break; | ||
785 | case LCDC_CLK_PERIPHERAL: | ||
786 | str = "peripheral_clk"; | ||
787 | priv->lddckr = LDDCKR_ICKSEL_MIPI; | ||
788 | break; | ||
789 | case LCDC_CLK_EXTERNAL: | ||
790 | str = NULL; | ||
791 | priv->lddckr = LDDCKR_ICKSEL_HDMI; | ||
792 | break; | ||
828 | default: | 793 | default: |
829 | return -EINVAL; | 794 | return -EINVAL; |
830 | } | 795 | } |
831 | 796 | ||
832 | priv->lddckr = icksel << 16; | ||
833 | |||
834 | if (str) { | 797 | if (str) { |
835 | priv->dot_clk = clk_get(&pdev->dev, str); | 798 | priv->dot_clk = clk_get(&pdev->dev, str); |
836 | if (IS_ERR(priv->dot_clk)) { | 799 | if (IS_ERR(priv->dot_clk)) { |
@@ -940,32 +903,28 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, | |||
940 | base_addr_c += 2 * var->xoffset; | 903 | base_addr_c += 2 * var->xoffset; |
941 | else | 904 | else |
942 | base_addr_c += var->xoffset; | 905 | base_addr_c += var->xoffset; |
943 | } else | 906 | } |
944 | base_addr_c = 0; | ||
945 | 907 | ||
946 | if (!ch->meram_enabled) { | 908 | if (ch->meram_enabled) { |
947 | lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y); | ||
948 | if (base_addr_c) | ||
949 | lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c); | ||
950 | } else { | ||
951 | struct sh_mobile_meram_cfg *cfg; | 909 | struct sh_mobile_meram_cfg *cfg; |
952 | struct sh_mobile_meram_info *mdev; | 910 | struct sh_mobile_meram_info *mdev; |
953 | unsigned long icb_addr_y, icb_addr_c; | ||
954 | int ret; | 911 | int ret; |
955 | 912 | ||
956 | cfg = ch->cfg.meram_cfg; | 913 | cfg = ch->cfg.meram_cfg; |
957 | mdev = priv->meram_dev; | 914 | mdev = priv->meram_dev; |
958 | ret = mdev->ops->meram_update(mdev, cfg, | 915 | ret = mdev->ops->meram_update(mdev, cfg, |
959 | base_addr_y, base_addr_c, | 916 | base_addr_y, base_addr_c, |
960 | &icb_addr_y, &icb_addr_c); | 917 | &base_addr_y, &base_addr_c); |
961 | if (ret) | 918 | if (ret) |
962 | return ret; | 919 | return ret; |
920 | } | ||
963 | 921 | ||
964 | lcdc_write_chan_mirror(ch, LDSA1R, icb_addr_y); | 922 | ch->base_addr_y = base_addr_y; |
965 | if (icb_addr_c) | 923 | ch->base_addr_c = base_addr_c; |
966 | lcdc_write_chan_mirror(ch, LDSA2R, icb_addr_c); | ||
967 | 924 | ||
968 | } | 925 | lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y); |
926 | if (var->nonstd) | ||
927 | lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c); | ||
969 | 928 | ||
970 | if (lcdc_chan_is_sublcd(ch)) | 929 | if (lcdc_chan_is_sublcd(ch)) |
971 | lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS); | 930 | lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS); |
@@ -985,9 +944,11 @@ static int sh_mobile_wait_for_vsync(struct fb_info *info) | |||
985 | unsigned long ldintr; | 944 | unsigned long ldintr; |
986 | int ret; | 945 | int ret; |
987 | 946 | ||
988 | /* Enable VSync End interrupt */ | 947 | /* Enable VSync End interrupt and be careful not to acknowledge any |
948 | * pending interrupt. | ||
949 | */ | ||
989 | ldintr = lcdc_read(ch->lcdc, _LDINTR); | 950 | ldintr = lcdc_read(ch->lcdc, _LDINTR); |
990 | ldintr |= LDINTR_VEE; | 951 | ldintr |= LDINTR_VEE | LDINTR_STATUS_MASK; |
991 | lcdc_write(ch->lcdc, _LDINTR, ldintr); | 952 | lcdc_write(ch->lcdc, _LDINTR, ldintr); |
992 | 953 | ||
993 | ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion, | 954 | ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion, |
@@ -1316,47 +1277,20 @@ static int sh_mobile_lcdc_resume(struct device *dev) | |||
1316 | static int sh_mobile_lcdc_runtime_suspend(struct device *dev) | 1277 | static int sh_mobile_lcdc_runtime_suspend(struct device *dev) |
1317 | { | 1278 | { |
1318 | struct platform_device *pdev = to_platform_device(dev); | 1279 | struct platform_device *pdev = to_platform_device(dev); |
1319 | struct sh_mobile_lcdc_priv *p = platform_get_drvdata(pdev); | 1280 | struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev); |
1320 | struct sh_mobile_lcdc_chan *ch; | ||
1321 | int k, n; | ||
1322 | |||
1323 | /* save per-channel registers */ | ||
1324 | for (k = 0; k < ARRAY_SIZE(p->ch); k++) { | ||
1325 | ch = &p->ch[k]; | ||
1326 | if (!ch->enabled) | ||
1327 | continue; | ||
1328 | for (n = 0; n < NR_CH_REGS; n++) | ||
1329 | ch->saved_ch_regs[n] = lcdc_read_chan(ch, n); | ||
1330 | } | ||
1331 | |||
1332 | /* save shared registers */ | ||
1333 | for (n = 0; n < NR_SHARED_REGS; n++) | ||
1334 | p->saved_shared_regs[n] = lcdc_read(p, lcdc_shared_regs[n]); | ||
1335 | 1281 | ||
1336 | /* turn off LCDC hardware */ | 1282 | /* turn off LCDC hardware */ |
1337 | lcdc_write(p, _LDCNT1R, 0); | 1283 | lcdc_write(priv, _LDCNT1R, 0); |
1284 | |||
1338 | return 0; | 1285 | return 0; |
1339 | } | 1286 | } |
1340 | 1287 | ||
1341 | static int sh_mobile_lcdc_runtime_resume(struct device *dev) | 1288 | static int sh_mobile_lcdc_runtime_resume(struct device *dev) |
1342 | { | 1289 | { |
1343 | struct platform_device *pdev = to_platform_device(dev); | 1290 | struct platform_device *pdev = to_platform_device(dev); |
1344 | struct sh_mobile_lcdc_priv *p = platform_get_drvdata(pdev); | 1291 | struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev); |
1345 | struct sh_mobile_lcdc_chan *ch; | ||
1346 | int k, n; | ||
1347 | |||
1348 | /* restore per-channel registers */ | ||
1349 | for (k = 0; k < ARRAY_SIZE(p->ch); k++) { | ||
1350 | ch = &p->ch[k]; | ||
1351 | if (!ch->enabled) | ||
1352 | continue; | ||
1353 | for (n = 0; n < NR_CH_REGS; n++) | ||
1354 | lcdc_write_chan(ch, n, ch->saved_ch_regs[n]); | ||
1355 | } | ||
1356 | 1292 | ||
1357 | /* restore shared registers */ | 1293 | __sh_mobile_lcdc_start(priv); |
1358 | for (n = 0; n < NR_SHARED_REGS; n++) | ||
1359 | lcdc_write(p, lcdc_shared_regs[n], p->saved_shared_regs[n]); | ||
1360 | 1294 | ||
1361 | return 0; | 1295 | return 0; |
1362 | } | 1296 | } |
@@ -1472,12 +1406,12 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
1472 | 1406 | ||
1473 | switch (pdata->ch[i].chan) { | 1407 | switch (pdata->ch[i].chan) { |
1474 | case LCDC_CHAN_MAINLCD: | 1408 | case LCDC_CHAN_MAINLCD: |
1475 | ch->enabled = 1 << 1; | 1409 | ch->enabled = LDCNT2R_ME; |
1476 | ch->reg_offs = lcdc_offs_mainlcd; | 1410 | ch->reg_offs = lcdc_offs_mainlcd; |
1477 | j++; | 1411 | j++; |
1478 | break; | 1412 | break; |
1479 | case LCDC_CHAN_SUBLCD: | 1413 | case LCDC_CHAN_SUBLCD: |
1480 | ch->enabled = 1 << 2; | 1414 | ch->enabled = LDCNT2R_SE; |
1481 | ch->reg_offs = lcdc_offs_sublcd; | 1415 | ch->reg_offs = lcdc_offs_sublcd; |
1482 | j++; | 1416 | j++; |
1483 | break; | 1417 | break; |
diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h index aeed6687e6a7..a58a0f38848b 100644 --- a/drivers/video/sh_mobile_lcdcfb.h +++ b/drivers/video/sh_mobile_lcdcfb.h | |||
@@ -18,6 +18,13 @@ struct sh_mobile_lcdc_priv; | |||
18 | struct fb_info; | 18 | struct fb_info; |
19 | struct backlight_device; | 19 | struct backlight_device; |
20 | 20 | ||
21 | /* | ||
22 | * struct sh_mobile_lcdc_chan - LCDC display channel | ||
23 | * | ||
24 | * @base_addr_y: Frame buffer viewport base address (luma component) | ||
25 | * @base_addr_c: Frame buffer viewport base address (chroma component) | ||
26 | * @pitch: Frame buffer line pitch | ||
27 | */ | ||
21 | struct sh_mobile_lcdc_chan { | 28 | struct sh_mobile_lcdc_chan { |
22 | struct sh_mobile_lcdc_priv *lcdc; | 29 | struct sh_mobile_lcdc_priv *lcdc; |
23 | unsigned long *reg_offs; | 30 | unsigned long *reg_offs; |
@@ -25,7 +32,6 @@ struct sh_mobile_lcdc_chan { | |||
25 | unsigned long enabled; /* ME and SE in LDCNT2R */ | 32 | unsigned long enabled; /* ME and SE in LDCNT2R */ |
26 | struct sh_mobile_lcdc_chan_cfg cfg; | 33 | struct sh_mobile_lcdc_chan_cfg cfg; |
27 | u32 pseudo_palette[PALETTE_NR]; | 34 | u32 pseudo_palette[PALETTE_NR]; |
28 | unsigned long saved_ch_regs[NR_CH_REGS]; | ||
29 | struct fb_info *info; | 35 | struct fb_info *info; |
30 | struct backlight_device *bl; | 36 | struct backlight_device *bl; |
31 | dma_addr_t dma_handle; | 37 | dma_addr_t dma_handle; |
@@ -40,6 +46,10 @@ struct sh_mobile_lcdc_chan { | |||
40 | int blank_status; | 46 | int blank_status; |
41 | struct mutex open_lock; /* protects the use counter */ | 47 | struct mutex open_lock; /* protects the use counter */ |
42 | int meram_enabled; | 48 | int meram_enabled; |
49 | |||
50 | unsigned long base_addr_y; | ||
51 | unsigned long base_addr_c; | ||
52 | unsigned int pitch; | ||
43 | }; | 53 | }; |
44 | 54 | ||
45 | #endif | 55 | #endif |
diff --git a/drivers/video/sh_mobile_meram.c b/drivers/video/sh_mobile_meram.c index cc7d7329dc15..f63297099193 100644 --- a/drivers/video/sh_mobile_meram.c +++ b/drivers/video/sh_mobile_meram.c | |||
@@ -12,29 +12,103 @@ | |||
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/device.h> | 14 | #include <linux/device.h> |
15 | #include <linux/pm_runtime.h> | ||
15 | #include <linux/io.h> | 16 | #include <linux/io.h> |
16 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
17 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
18 | 19 | #include <video/sh_mobile_meram.h> | |
19 | #include "sh_mobile_meram.h" | ||
20 | 20 | ||
21 | /* meram registers */ | 21 | /* meram registers */ |
22 | #define MExxCTL 0x0 | 22 | #define MEVCR1 0x4 |
23 | #define MExxBSIZE 0x4 | 23 | #define MEVCR1_RST (1 << 31) |
24 | #define MExxMNCF 0x8 | 24 | #define MEVCR1_WD (1 << 30) |
25 | #define MExxSARA 0x10 | 25 | #define MEVCR1_AMD1 (1 << 29) |
26 | #define MExxSARB 0x14 | 26 | #define MEVCR1_AMD0 (1 << 28) |
27 | #define MExxSBSIZE 0x18 | 27 | #define MEQSEL1 0x40 |
28 | 28 | #define MEQSEL2 0x44 | |
29 | #define MERAM_MExxCTL_VAL(ctl, next_icb, addr) \ | 29 | |
30 | ((ctl) | (((next_icb) & 0x1f) << 11) | (((addr) & 0x7ff) << 16)) | 30 | #define MExxCTL 0x400 |
31 | #define MERAM_MExxBSIZE_VAL(a, b, c) \ | 31 | #define MExxCTL_BV (1 << 31) |
32 | (((a) << 28) | ((b) << 16) | (c)) | 32 | #define MExxCTL_BSZ_SHIFT 28 |
33 | 33 | #define MExxCTL_MSAR_MASK (0x7ff << MExxCTL_MSAR_SHIFT) | |
34 | #define MEVCR1 0x4 | 34 | #define MExxCTL_MSAR_SHIFT 16 |
35 | #define MEACTS 0x10 | 35 | #define MExxCTL_NXT_MASK (0x1f << MExxCTL_NXT_SHIFT) |
36 | #define MEQSEL1 0x40 | 36 | #define MExxCTL_NXT_SHIFT 11 |
37 | #define MEQSEL2 0x44 | 37 | #define MExxCTL_WD1 (1 << 10) |
38 | #define MExxCTL_WD0 (1 << 9) | ||
39 | #define MExxCTL_WS (1 << 8) | ||
40 | #define MExxCTL_CB (1 << 7) | ||
41 | #define MExxCTL_WBF (1 << 6) | ||
42 | #define MExxCTL_WF (1 << 5) | ||
43 | #define MExxCTL_RF (1 << 4) | ||
44 | #define MExxCTL_CM (1 << 3) | ||
45 | #define MExxCTL_MD_READ (1 << 0) | ||
46 | #define MExxCTL_MD_WRITE (2 << 0) | ||
47 | #define MExxCTL_MD_ICB_WB (3 << 0) | ||
48 | #define MExxCTL_MD_ICB (4 << 0) | ||
49 | #define MExxCTL_MD_FB (7 << 0) | ||
50 | #define MExxCTL_MD_MASK (7 << 0) | ||
51 | #define MExxBSIZE 0x404 | ||
52 | #define MExxBSIZE_RCNT_SHIFT 28 | ||
53 | #define MExxBSIZE_YSZM1_SHIFT 16 | ||
54 | #define MExxBSIZE_XSZM1_SHIFT 0 | ||
55 | #define MExxMNCF 0x408 | ||
56 | #define MExxMNCF_KWBNM_SHIFT 28 | ||
57 | #define MExxMNCF_KRBNM_SHIFT 24 | ||
58 | #define MExxMNCF_BNM_SHIFT 16 | ||
59 | #define MExxMNCF_XBV (1 << 15) | ||
60 | #define MExxMNCF_CPL_YCBCR444 (1 << 12) | ||
61 | #define MExxMNCF_CPL_YCBCR420 (2 << 12) | ||
62 | #define MExxMNCF_CPL_YCBCR422 (3 << 12) | ||
63 | #define MExxMNCF_CPL_MSK (3 << 12) | ||
64 | #define MExxMNCF_BL (1 << 2) | ||
65 | #define MExxMNCF_LNM_SHIFT 0 | ||
66 | #define MExxSARA 0x410 | ||
67 | #define MExxSARB 0x414 | ||
68 | #define MExxSBSIZE 0x418 | ||
69 | #define MExxSBSIZE_HDV (1 << 31) | ||
70 | #define MExxSBSIZE_HSZ16 (0 << 28) | ||
71 | #define MExxSBSIZE_HSZ32 (1 << 28) | ||
72 | #define MExxSBSIZE_HSZ64 (2 << 28) | ||
73 | #define MExxSBSIZE_HSZ128 (3 << 28) | ||
74 | #define MExxSBSIZE_SBSIZZ_SHIFT 0 | ||
75 | |||
76 | #define MERAM_MExxCTL_VAL(next, addr) \ | ||
77 | ((((next) << MExxCTL_NXT_SHIFT) & MExxCTL_NXT_MASK) | \ | ||
78 | (((addr) << MExxCTL_MSAR_SHIFT) & MExxCTL_MSAR_MASK)) | ||
79 | #define MERAM_MExxBSIZE_VAL(rcnt, yszm1, xszm1) \ | ||
80 | (((rcnt) << MExxBSIZE_RCNT_SHIFT) | \ | ||
81 | ((yszm1) << MExxBSIZE_YSZM1_SHIFT) | \ | ||
82 | ((xszm1) << MExxBSIZE_XSZM1_SHIFT)) | ||
83 | |||
84 | #define SH_MOBILE_MERAM_ICB_NUM 32 | ||
85 | |||
86 | static unsigned long common_regs[] = { | ||
87 | MEVCR1, | ||
88 | MEQSEL1, | ||
89 | MEQSEL2, | ||
90 | }; | ||
91 | #define CMN_REGS_SIZE ARRAY_SIZE(common_regs) | ||
92 | |||
93 | static unsigned long icb_regs[] = { | ||
94 | MExxCTL, | ||
95 | MExxBSIZE, | ||
96 | MExxMNCF, | ||
97 | MExxSARA, | ||
98 | MExxSARB, | ||
99 | MExxSBSIZE, | ||
100 | }; | ||
101 | #define ICB_REGS_SIZE ARRAY_SIZE(icb_regs) | ||
102 | |||
103 | struct sh_mobile_meram_priv { | ||
104 | void __iomem *base; | ||
105 | struct mutex lock; | ||
106 | unsigned long used_icb; | ||
107 | int used_meram_cache_regions; | ||
108 | unsigned long used_meram_cache[SH_MOBILE_MERAM_ICB_NUM]; | ||
109 | unsigned long cmn_saved_regs[CMN_REGS_SIZE]; | ||
110 | unsigned long icb_saved_regs[ICB_REGS_SIZE * SH_MOBILE_MERAM_ICB_NUM]; | ||
111 | }; | ||
38 | 112 | ||
39 | /* settings */ | 113 | /* settings */ |
40 | #define MERAM_SEC_LINE 15 | 114 | #define MERAM_SEC_LINE 15 |
@@ -44,8 +118,7 @@ | |||
44 | * MERAM/ICB access functions | 118 | * MERAM/ICB access functions |
45 | */ | 119 | */ |
46 | 120 | ||
47 | #define MERAM_ICB_OFFSET(base, idx, off) \ | 121 | #define MERAM_ICB_OFFSET(base, idx, off) ((base) + (off) + (idx) * 0x20) |
48 | ((base) + (0x400 + ((idx) * 0x20) + (off))) | ||
49 | 122 | ||
50 | static inline void meram_write_icb(void __iomem *base, int idx, int off, | 123 | static inline void meram_write_icb(void __iomem *base, int idx, int off, |
51 | unsigned long val) | 124 | unsigned long val) |
@@ -280,17 +353,18 @@ static int meram_init(struct sh_mobile_meram_priv *priv, | |||
280 | /* | 353 | /* |
281 | * Set MERAM for framebuffer | 354 | * Set MERAM for framebuffer |
282 | * | 355 | * |
283 | * 0x70f: WD = 0x3, WS=0x1, CM=0x1, MD=FB mode | ||
284 | * we also chain the cache_icb and the marker_icb. | 356 | * we also chain the cache_icb and the marker_icb. |
285 | * we also split the allocated MERAM buffer between two ICBs. | 357 | * we also split the allocated MERAM buffer between two ICBs. |
286 | */ | 358 | */ |
287 | meram_write_icb(priv->base, icb->cache_icb, MExxCTL, | 359 | meram_write_icb(priv->base, icb->cache_icb, MExxCTL, |
288 | MERAM_MExxCTL_VAL(0x70f, icb->marker_icb, | 360 | MERAM_MExxCTL_VAL(icb->marker_icb, icb->meram_offset) | |
289 | icb->meram_offset)); | 361 | MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM | |
362 | MExxCTL_MD_FB); | ||
290 | meram_write_icb(priv->base, icb->marker_icb, MExxCTL, | 363 | meram_write_icb(priv->base, icb->marker_icb, MExxCTL, |
291 | MERAM_MExxCTL_VAL(0x70f, icb->cache_icb, | 364 | MERAM_MExxCTL_VAL(icb->cache_icb, icb->meram_offset + |
292 | icb->meram_offset + | 365 | icb->meram_size / 2) | |
293 | icb->meram_size / 2)); | 366 | MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM | |
367 | MExxCTL_MD_FB); | ||
294 | 368 | ||
295 | return 0; | 369 | return 0; |
296 | } | 370 | } |
@@ -337,24 +411,22 @@ static int sh_mobile_meram_register(struct sh_mobile_meram_info *pdata, | |||
337 | xres, yres, (!pixelformat) ? "yuv" : "rgb", | 411 | xres, yres, (!pixelformat) ? "yuv" : "rgb", |
338 | base_addr_y, base_addr_c); | 412 | base_addr_y, base_addr_c); |
339 | 413 | ||
340 | mutex_lock(&priv->lock); | ||
341 | |||
342 | /* we can't handle wider than 8192px */ | 414 | /* we can't handle wider than 8192px */ |
343 | if (xres > 8192) { | 415 | if (xres > 8192) { |
344 | dev_err(&pdev->dev, "width exceeding the limit (> 8192)."); | 416 | dev_err(&pdev->dev, "width exceeding the limit (> 8192)."); |
345 | error = -EINVAL; | 417 | return -EINVAL; |
346 | goto err; | ||
347 | } | ||
348 | |||
349 | if (priv->used_meram_cache_regions + 2 > SH_MOBILE_MERAM_ICB_NUM) { | ||
350 | dev_err(&pdev->dev, "no more ICB available."); | ||
351 | error = -EINVAL; | ||
352 | goto err; | ||
353 | } | 418 | } |
354 | 419 | ||
355 | /* do we have at least one ICB config? */ | 420 | /* do we have at least one ICB config? */ |
356 | if (cfg->icb[0].marker_icb < 0 || cfg->icb[0].cache_icb < 0) { | 421 | if (cfg->icb[0].marker_icb < 0 || cfg->icb[0].cache_icb < 0) { |
357 | dev_err(&pdev->dev, "at least one ICB is required."); | 422 | dev_err(&pdev->dev, "at least one ICB is required."); |
423 | return -EINVAL; | ||
424 | } | ||
425 | |||
426 | mutex_lock(&priv->lock); | ||
427 | |||
428 | if (priv->used_meram_cache_regions + 2 > SH_MOBILE_MERAM_ICB_NUM) { | ||
429 | dev_err(&pdev->dev, "no more ICB available."); | ||
358 | error = -EINVAL; | 430 | error = -EINVAL; |
359 | goto err; | 431 | goto err; |
360 | } | 432 | } |
@@ -460,6 +532,57 @@ static int sh_mobile_meram_update(struct sh_mobile_meram_info *pdata, | |||
460 | return 0; | 532 | return 0; |
461 | } | 533 | } |
462 | 534 | ||
535 | static int sh_mobile_meram_runtime_suspend(struct device *dev) | ||
536 | { | ||
537 | struct platform_device *pdev = to_platform_device(dev); | ||
538 | struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev); | ||
539 | int k, j; | ||
540 | |||
541 | for (k = 0; k < CMN_REGS_SIZE; k++) | ||
542 | priv->cmn_saved_regs[k] = meram_read_reg(priv->base, | ||
543 | common_regs[k]); | ||
544 | |||
545 | for (j = 0; j < 32; j++) { | ||
546 | if (!test_bit(j, &priv->used_icb)) | ||
547 | continue; | ||
548 | for (k = 0; k < ICB_REGS_SIZE; k++) { | ||
549 | priv->icb_saved_regs[j * ICB_REGS_SIZE + k] = | ||
550 | meram_read_icb(priv->base, j, icb_regs[k]); | ||
551 | /* Reset ICB on resume */ | ||
552 | if (icb_regs[k] == MExxCTL) | ||
553 | priv->icb_saved_regs[j * ICB_REGS_SIZE + k] |= | ||
554 | MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF; | ||
555 | } | ||
556 | } | ||
557 | return 0; | ||
558 | } | ||
559 | |||
560 | static int sh_mobile_meram_runtime_resume(struct device *dev) | ||
561 | { | ||
562 | struct platform_device *pdev = to_platform_device(dev); | ||
563 | struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev); | ||
564 | int k, j; | ||
565 | |||
566 | for (j = 0; j < 32; j++) { | ||
567 | if (!test_bit(j, &priv->used_icb)) | ||
568 | continue; | ||
569 | for (k = 0; k < ICB_REGS_SIZE; k++) { | ||
570 | meram_write_icb(priv->base, j, icb_regs[k], | ||
571 | priv->icb_saved_regs[j * ICB_REGS_SIZE + k]); | ||
572 | } | ||
573 | } | ||
574 | |||
575 | for (k = 0; k < CMN_REGS_SIZE; k++) | ||
576 | meram_write_reg(priv->base, common_regs[k], | ||
577 | priv->cmn_saved_regs[k]); | ||
578 | return 0; | ||
579 | } | ||
580 | |||
581 | static const struct dev_pm_ops sh_mobile_meram_dev_pm_ops = { | ||
582 | .runtime_suspend = sh_mobile_meram_runtime_suspend, | ||
583 | .runtime_resume = sh_mobile_meram_runtime_resume, | ||
584 | }; | ||
585 | |||
463 | static struct sh_mobile_meram_ops sh_mobile_meram_ops = { | 586 | static struct sh_mobile_meram_ops sh_mobile_meram_ops = { |
464 | .module = THIS_MODULE, | 587 | .module = THIS_MODULE, |
465 | .meram_register = sh_mobile_meram_register, | 588 | .meram_register = sh_mobile_meram_register, |
@@ -513,7 +636,9 @@ static int __devinit sh_mobile_meram_probe(struct platform_device *pdev) | |||
513 | 636 | ||
514 | /* initialize ICB addressing mode */ | 637 | /* initialize ICB addressing mode */ |
515 | if (pdata->addr_mode == SH_MOBILE_MERAM_MODE1) | 638 | if (pdata->addr_mode == SH_MOBILE_MERAM_MODE1) |
516 | meram_write_reg(priv->base, MEVCR1, 1 << 29); | 639 | meram_write_reg(priv->base, MEVCR1, MEVCR1_AMD1); |
640 | |||
641 | pm_runtime_enable(&pdev->dev); | ||
517 | 642 | ||
518 | dev_info(&pdev->dev, "sh_mobile_meram initialized."); | 643 | dev_info(&pdev->dev, "sh_mobile_meram initialized."); |
519 | 644 | ||
@@ -530,6 +655,8 @@ static int sh_mobile_meram_remove(struct platform_device *pdev) | |||
530 | { | 655 | { |
531 | struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev); | 656 | struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev); |
532 | 657 | ||
658 | pm_runtime_disable(&pdev->dev); | ||
659 | |||
533 | if (priv->base) | 660 | if (priv->base) |
534 | iounmap(priv->base); | 661 | iounmap(priv->base); |
535 | 662 | ||
@@ -544,6 +671,7 @@ static struct platform_driver sh_mobile_meram_driver = { | |||
544 | .driver = { | 671 | .driver = { |
545 | .name = "sh_mobile_meram", | 672 | .name = "sh_mobile_meram", |
546 | .owner = THIS_MODULE, | 673 | .owner = THIS_MODULE, |
674 | .pm = &sh_mobile_meram_dev_pm_ops, | ||
547 | }, | 675 | }, |
548 | .probe = sh_mobile_meram_probe, | 676 | .probe = sh_mobile_meram_probe, |
549 | .remove = sh_mobile_meram_remove, | 677 | .remove = sh_mobile_meram_remove, |
diff --git a/drivers/video/sh_mobile_meram.h b/drivers/video/sh_mobile_meram.h deleted file mode 100644 index 82c54fbce8bd..000000000000 --- a/drivers/video/sh_mobile_meram.h +++ /dev/null | |||
@@ -1,41 +0,0 @@ | |||
1 | #ifndef __sh_mobile_meram_h__ | ||
2 | #define __sh_mobile_meram_h__ | ||
3 | |||
4 | #include <linux/mutex.h> | ||
5 | #include <video/sh_mobile_meram.h> | ||
6 | |||
7 | /* | ||
8 | * MERAM private | ||
9 | */ | ||
10 | |||
11 | #define MERAM_ICB_Y 0x1 | ||
12 | #define MERAM_ICB_C 0x2 | ||
13 | |||
14 | /* MERAM cache size */ | ||
15 | #define SH_MOBILE_MERAM_ICB_NUM 32 | ||
16 | |||
17 | #define SH_MOBILE_MERAM_CACHE_OFFSET(p) ((p) >> 16) | ||
18 | #define SH_MOBILE_MERAM_CACHE_SIZE(p) ((p) & 0xffff) | ||
19 | |||
20 | struct sh_mobile_meram_priv { | ||
21 | void __iomem *base; | ||
22 | struct mutex lock; | ||
23 | unsigned long used_icb; | ||
24 | int used_meram_cache_regions; | ||
25 | unsigned long used_meram_cache[SH_MOBILE_MERAM_ICB_NUM]; | ||
26 | }; | ||
27 | |||
28 | int sh_mobile_meram_alloc_icb(const struct sh_mobile_meram_cfg *cfg, | ||
29 | int xres, | ||
30 | int yres, | ||
31 | unsigned int base_addr, | ||
32 | int yuv_mode, | ||
33 | int *marker_icb, | ||
34 | int *out_pitch); | ||
35 | |||
36 | void sh_mobile_meram_free_icb(int marker_icb); | ||
37 | |||
38 | #define SH_MOBILE_MERAM_START(ind, ab) \ | ||
39 | (0xC0000000 | ((ab & 0x1) << 23) | ((ind & 0x1F) << 24)) | ||
40 | |||
41 | #endif /* !__sh_mobile_meram_h__ */ | ||
diff --git a/include/video/sh_mobile_lcdc.h b/include/video/sh_mobile_lcdc.h index d964e68fc61d..8101b726b48a 100644 --- a/include/video/sh_mobile_lcdc.h +++ b/include/video/sh_mobile_lcdc.h | |||
@@ -4,26 +4,123 @@ | |||
4 | #include <linux/fb.h> | 4 | #include <linux/fb.h> |
5 | #include <video/sh_mobile_meram.h> | 5 | #include <video/sh_mobile_meram.h> |
6 | 6 | ||
7 | /* Register definitions */ | ||
8 | #define _LDDCKR 0x410 | ||
9 | #define LDDCKR_ICKSEL_BUS (0 << 16) | ||
10 | #define LDDCKR_ICKSEL_MIPI (1 << 16) | ||
11 | #define LDDCKR_ICKSEL_HDMI (2 << 16) | ||
12 | #define LDDCKR_ICKSEL_EXT (3 << 16) | ||
13 | #define LDDCKR_ICKSEL_MASK (7 << 16) | ||
14 | #define LDDCKR_MOSEL (1 << 6) | ||
15 | #define _LDDCKSTPR 0x414 | ||
16 | #define _LDINTR 0x468 | ||
17 | #define LDINTR_FE (1 << 10) | ||
18 | #define LDINTR_VSE (1 << 9) | ||
19 | #define LDINTR_VEE (1 << 8) | ||
20 | #define LDINTR_FS (1 << 2) | ||
21 | #define LDINTR_VSS (1 << 1) | ||
22 | #define LDINTR_VES (1 << 0) | ||
23 | #define LDINTR_STATUS_MASK (0xff << 0) | ||
24 | #define _LDSR 0x46c | ||
25 | #define LDSR_MSS (1 << 10) | ||
26 | #define LDSR_MRS (1 << 8) | ||
27 | #define LDSR_AS (1 << 1) | ||
28 | #define _LDCNT1R 0x470 | ||
29 | #define LDCNT1R_DE (1 << 0) | ||
30 | #define _LDCNT2R 0x474 | ||
31 | #define LDCNT2R_BR (1 << 8) | ||
32 | #define LDCNT2R_MD (1 << 3) | ||
33 | #define LDCNT2R_SE (1 << 2) | ||
34 | #define LDCNT2R_ME (1 << 1) | ||
35 | #define LDCNT2R_DO (1 << 0) | ||
36 | #define _LDRCNTR 0x478 | ||
37 | #define LDRCNTR_SRS (1 << 17) | ||
38 | #define LDRCNTR_SRC (1 << 16) | ||
39 | #define LDRCNTR_MRS (1 << 1) | ||
40 | #define LDRCNTR_MRC (1 << 0) | ||
41 | #define _LDDDSR 0x47c | ||
42 | #define LDDDSR_LS (1 << 2) | ||
43 | #define LDDDSR_WS (1 << 1) | ||
44 | #define LDDDSR_BS (1 << 0) | ||
45 | |||
46 | #define LDMT1R_VPOL (1 << 28) | ||
47 | #define LDMT1R_HPOL (1 << 27) | ||
48 | #define LDMT1R_DWPOL (1 << 26) | ||
49 | #define LDMT1R_DIPOL (1 << 25) | ||
50 | #define LDMT1R_DAPOL (1 << 24) | ||
51 | #define LDMT1R_HSCNT (1 << 17) | ||
52 | #define LDMT1R_DWCNT (1 << 16) | ||
53 | #define LDMT1R_IFM (1 << 12) | ||
54 | #define LDMT1R_MIFTYP_RGB8 (0x0 << 0) | ||
55 | #define LDMT1R_MIFTYP_RGB9 (0x4 << 0) | ||
56 | #define LDMT1R_MIFTYP_RGB12A (0x5 << 0) | ||
57 | #define LDMT1R_MIFTYP_RGB12B (0x6 << 0) | ||
58 | #define LDMT1R_MIFTYP_RGB16 (0x7 << 0) | ||
59 | #define LDMT1R_MIFTYP_RGB18 (0xa << 0) | ||
60 | #define LDMT1R_MIFTYP_RGB24 (0xb << 0) | ||
61 | #define LDMT1R_MIFTYP_YCBCR (0xf << 0) | ||
62 | #define LDMT1R_MIFTYP_SYS8A (0x0 << 0) | ||
63 | #define LDMT1R_MIFTYP_SYS8B (0x1 << 0) | ||
64 | #define LDMT1R_MIFTYP_SYS8C (0x2 << 0) | ||
65 | #define LDMT1R_MIFTYP_SYS8D (0x3 << 0) | ||
66 | #define LDMT1R_MIFTYP_SYS9 (0x4 << 0) | ||
67 | #define LDMT1R_MIFTYP_SYS12 (0x5 << 0) | ||
68 | #define LDMT1R_MIFTYP_SYS16A (0x7 << 0) | ||
69 | #define LDMT1R_MIFTYP_SYS16B (0x8 << 0) | ||
70 | #define LDMT1R_MIFTYP_SYS16C (0x9 << 0) | ||
71 | #define LDMT1R_MIFTYP_SYS18 (0xa << 0) | ||
72 | #define LDMT1R_MIFTYP_SYS24 (0xb << 0) | ||
73 | #define LDMT1R_MIFTYP_MASK (0xf << 0) | ||
74 | |||
75 | #define LDDFR_CF1 (1 << 18) | ||
76 | #define LDDFR_CF0 (1 << 17) | ||
77 | #define LDDFR_CC (1 << 16) | ||
78 | #define LDDFR_YF_420 (0 << 8) | ||
79 | #define LDDFR_YF_422 (1 << 8) | ||
80 | #define LDDFR_YF_444 (2 << 8) | ||
81 | #define LDDFR_YF_MASK (3 << 8) | ||
82 | #define LDDFR_PKF_ARGB32 (0x00 << 0) | ||
83 | #define LDDFR_PKF_RGB16 (0x03 << 0) | ||
84 | #define LDDFR_PKF_RGB24 (0x0b << 0) | ||
85 | #define LDDFR_PKF_MASK (0x1f << 0) | ||
86 | |||
87 | #define LDSM1R_OS (1 << 0) | ||
88 | |||
89 | #define LDSM2R_OSTRG (1 << 0) | ||
90 | |||
91 | #define LDPMR_LPS (3 << 0) | ||
92 | |||
93 | #define _LDDWD0R 0x800 | ||
94 | #define LDDWDxR_WDACT (1 << 28) | ||
95 | #define LDDWDxR_RSW (1 << 24) | ||
96 | #define _LDDRDR 0x840 | ||
97 | #define LDDRDR_RSR (1 << 24) | ||
98 | #define LDDRDR_DRD_MASK (0x3ffff << 0) | ||
99 | #define _LDDWAR 0x900 | ||
100 | #define LDDWAR_WA (1 << 0) | ||
101 | #define _LDDRAR 0x904 | ||
102 | #define LDDRAR_RA (1 << 0) | ||
103 | |||
7 | enum { | 104 | enum { |
8 | RGB8, /* 24bpp, 8:8:8 */ | 105 | RGB8 = LDMT1R_MIFTYP_RGB8, /* 24bpp, 8:8:8 */ |
9 | RGB9, /* 18bpp, 9:9 */ | 106 | RGB9 = LDMT1R_MIFTYP_RGB9, /* 18bpp, 9:9 */ |
10 | RGB12A, /* 24bpp, 12:12 */ | 107 | RGB12A = LDMT1R_MIFTYP_RGB12A, /* 24bpp, 12:12 */ |
11 | RGB12B, /* 12bpp */ | 108 | RGB12B = LDMT1R_MIFTYP_RGB12B, /* 12bpp */ |
12 | RGB16, /* 16bpp */ | 109 | RGB16 = LDMT1R_MIFTYP_RGB16, /* 16bpp */ |
13 | RGB18, /* 18bpp */ | 110 | RGB18 = LDMT1R_MIFTYP_RGB18, /* 18bpp */ |
14 | RGB24, /* 24bpp */ | 111 | RGB24 = LDMT1R_MIFTYP_RGB24, /* 24bpp */ |
15 | YUV422, /* 16bpp */ | 112 | YUV422 = LDMT1R_MIFTYP_YCBCR, /* 16bpp */ |
16 | SYS8A, /* 24bpp, 8:8:8 */ | 113 | SYS8A = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8A, /* 24bpp, 8:8:8 */ |
17 | SYS8B, /* 18bpp, 8:8:2 */ | 114 | SYS8B = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8B, /* 18bpp, 8:8:2 */ |
18 | SYS8C, /* 18bpp, 2:8:8 */ | 115 | SYS8C = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8C, /* 18bpp, 2:8:8 */ |
19 | SYS8D, /* 16bpp, 8:8 */ | 116 | SYS8D = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8D, /* 16bpp, 8:8 */ |
20 | SYS9, /* 18bpp, 9:9 */ | 117 | SYS9 = LDMT1R_IFM | LDMT1R_MIFTYP_SYS9, /* 18bpp, 9:9 */ |
21 | SYS12, /* 24bpp, 12:12 */ | 118 | SYS12 = LDMT1R_IFM | LDMT1R_MIFTYP_SYS12, /* 24bpp, 12:12 */ |
22 | SYS16A, /* 16bpp */ | 119 | SYS16A = LDMT1R_IFM | LDMT1R_MIFTYP_SYS16A, /* 16bpp */ |
23 | SYS16B, /* 18bpp, 16:2 */ | 120 | SYS16B = LDMT1R_IFM | LDMT1R_MIFTYP_SYS16B, /* 18bpp, 16:2 */ |
24 | SYS16C, /* 18bpp, 2:16 */ | 121 | SYS16C = LDMT1R_IFM | LDMT1R_MIFTYP_SYS16C, /* 18bpp, 2:16 */ |
25 | SYS18, /* 18bpp */ | 122 | SYS18 = LDMT1R_IFM | LDMT1R_MIFTYP_SYS18, /* 18bpp */ |
26 | SYS24, /* 24bpp */ | 123 | SYS24 = LDMT1R_IFM | LDMT1R_MIFTYP_SYS24, /* 24bpp */ |
27 | }; | 124 | }; |
28 | 125 | ||
29 | enum { LCDC_CHAN_DISABLED = 0, | 126 | enum { LCDC_CHAN_DISABLED = 0, |