sh_mobile_lcdcfb.c revision 0c75c4e073a8ec35bfd6c8adcceb2b896f2063e2
1cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm/*
2cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm * SuperH Mobile LCDC Framebuffer
3cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm *
4cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm * Copyright (c) 2008 Magnus Damm
5cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm *
6cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm * This file is subject to the terms and conditions of the GNU General Public
7cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm * License.  See the file "COPYING" in the main directory of this archive
8cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm * for more details.
9cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm */
10cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
11f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart#include <linux/atomic.h>
12f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart#include <linux/backlight.h>
13cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#include <linux/clk.h>
14f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart#include <linux/console.h>
15c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#include <linux/ctype.h>
16cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#include <linux/dma-mapping.h>
17f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart#include <linux/delay.h>
18f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart#include <linux/gpio.h>
19f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart#include <linux/init.h>
208564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm#include <linux/interrupt.h>
2140331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy#include <linux/ioctl.h>
22f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart#include <linux/kernel.h>
23f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart#include <linux/mm.h>
24355b200bacdb6017669cdc5bc9e7b1037aac42a2Paul Gortmaker#include <linux/module.h>
25f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart#include <linux/platform_device.h>
26f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart#include <linux/pm_runtime.h>
27f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart#include <linux/slab.h>
28f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart#include <linux/videodev2.h>
29f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart#include <linux/vmalloc.h>
30f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
31225c9a8d1da274bf23efec43ec28b1c9e45e12f8Paul Mundt#include <video/sh_mobile_lcdc.h>
328a20974f0370fe1b924704399e7ba327d894ef72Laurent Pinchart#include <video/sh_mobile_meram.h>
33cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
346de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski#include "sh_mobile_lcdcfb.h"
356de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski
36c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart/* ----------------------------------------------------------------------------
37c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * Overlay register definitions
38c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart */
39c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
40c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBCR			0xb00
41c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBCR_UPC(n)		(1 << ((n) + 16))
42c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBCR_UPF(n)		(1 << ((n) + 8))
43c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBCR_UPD(n)		(1 << ((n) + 0))
44c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBnBSIFR(n)		(0xb20 + (n) * 0x20 + 0x00)
45c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_EN		(1 << 31)
46c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_VS		(1 << 29)
47c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_BRSEL		(1 << 28)
48c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_MX		(1 << 27)
49c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_MY		(1 << 26)
50c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_CV3		(3 << 24)
51c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_CV2		(2 << 24)
52c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_CV1		(1 << 24)
53c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_CV0		(0 << 24)
54c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_CV_MASK	(3 << 24)
55c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_LAY_MASK	(0xff << 16)
56c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_LAY_SHIFT	16
57c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_ROP3_MASK	(0xff << 16)
58c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_ROP3_SHIFT	16
59c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_AL_PL8		(3 << 14)
60c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_AL_PL1		(2 << 14)
61c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_AL_PK		(1 << 14)
62c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_AL_1		(0 << 14)
63c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_AL_MASK	(3 << 14)
64c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_SWPL		(1 << 10)
65c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_SWPW		(1 << 9)
66c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_SWPB		(1 << 8)
67c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_RY		(1 << 7)
68c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_CHRR_420	(2 << 0)
69c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_CHRR_422	(1 << 0)
70c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_CHRR_444	(0 << 0)
71c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_RPKF_ARGB32	(0x00 << 0)
72c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_RPKF_RGB16	(0x03 << 0)
73c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_RPKF_RGB24	(0x0b << 0)
74c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSIFR_RPKF_MASK	(0x1f << 0)
75c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBnBSSZR(n)		(0xb20 + (n) * 0x20 + 0x04)
76c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSSZR_BVSS_MASK	(0xfff << 16)
77c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSSZR_BVSS_SHIFT	16
78c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSSZR_BHSS_MASK	(0xfff << 0)
79c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSSZR_BHSS_SHIFT	0
80c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBnBLOCR(n)		(0xb20 + (n) * 0x20 + 0x08)
81c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBLOCR_CVLC_MASK	(0xfff << 16)
82c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBLOCR_CVLC_SHIFT	16
83c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBLOCR_CHLC_MASK	(0xfff << 0)
84c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBLOCR_CHLC_SHIFT	0
85c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBnBSMWR(n)		(0xb20 + (n) * 0x20 + 0x0c)
86c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSMWR_BSMWA_MASK	(0xffff << 16)
87c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSMWR_BSMWA_SHIFT	16
88c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSMWR_BSMW_MASK	(0xffff << 0)
89c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSMWR_BSMW_SHIFT	0
90c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBnBSAYR(n)		(0xb20 + (n) * 0x20 + 0x10)
91c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSAYR_FG1A_MASK	(0xff << 24)
92c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSAYR_FG1A_SHIFT	24
93c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSAYR_FG1R_MASK	(0xff << 16)
94c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSAYR_FG1R_SHIFT	16
95c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSAYR_FG1G_MASK	(0xff << 8)
96c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSAYR_FG1G_SHIFT	8
97c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSAYR_FG1B_MASK	(0xff << 0)
98c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSAYR_FG1B_SHIFT	0
99c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBnBSACR(n)		(0xb20 + (n) * 0x20 + 0x14)
100c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSACR_FG2A_MASK	(0xff << 24)
101c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSACR_FG2A_SHIFT	24
102c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSACR_FG2R_MASK	(0xff << 16)
103c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSACR_FG2R_SHIFT	16
104c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSACR_FG2G_MASK	(0xff << 8)
105c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSACR_FG2G_SHIFT	8
106c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSACR_FG2B_MASK	(0xff << 0)
107c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSACR_FG2B_SHIFT	0
108c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBnBSAAR(n)		(0xb20 + (n) * 0x20 + 0x18)
109c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSAAR_AP_MASK	(0xff << 24)
110c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSAAR_AP_SHIFT	24
111c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSAAR_R_MASK		(0xff << 16)
112c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSAAR_R_SHIFT	16
113c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSAAR_GY_MASK	(0xff << 8)
114c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSAAR_GY_SHIFT	8
115c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSAAR_B_MASK		(0xff << 0)
116c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBSAAR_B_SHIFT	0
117c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBnBPPCR(n)		(0xb20 + (n) * 0x20 + 0x1c)
118c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBPPCR_AP_MASK	(0xff << 24)
119c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBPPCR_AP_SHIFT	24
120c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBPPCR_R_MASK		(0xff << 16)
121c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBPPCR_R_SHIFT	16
122c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBPPCR_GY_MASK	(0xff << 8)
123c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBPPCR_GY_SHIFT	8
124c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBPPCR_B_MASK		(0xff << 0)
125c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBPPCR_B_SHIFT	0
126c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBnBBGCL(n)		(0xb10 + (n) * 0x04)
127c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBBGCL_BGA_MASK	(0xff << 24)
128c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBBGCL_BGA_SHIFT	24
129c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBBGCL_BGR_MASK	(0xff << 16)
130c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBBGCL_BGR_SHIFT	16
131c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBBGCL_BGG_MASK	(0xff << 8)
132c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBBGCL_BGG_SHIFT	8
133c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBBGCL_BGB_MASK	(0xff << 0)
134c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart#define LDBBBGCL_BGB_SHIFT	0
135c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
136a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy#define SIDE_B_OFFSET 0x1000
137a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy#define MIRROR_OFFSET 0x2000
138cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
139d2ecbab5960d9814a269d36723647d6ef391ba8fGuennadi Liakhovetski#define MAX_XRES 1920
140d2ecbab5960d9814a269d36723647d6ef391ba8fGuennadi Liakhovetski#define MAX_YRES 1080
141cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
142c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartenum sh_mobile_lcdc_overlay_mode {
143c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	LCDC_OVERLAY_BLEND,
144c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	LCDC_OVERLAY_ROP3,
145c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart};
146c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
147c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart/*
148c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * struct sh_mobile_lcdc_overlay - LCDC display overlay
149c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart *
150c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * @channel: LCDC channel this overlay belongs to
151c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * @cfg: Overlay configuration
152c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * @info: Frame buffer device
153c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * @index: Overlay index (0-3)
154c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * @base: Overlay registers base address
155c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * @enabled: True if the overlay is enabled
156c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * @mode: Overlay blending mode (alpha blend or ROP3)
157c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * @alpha: Global alpha blending value (0-255, for alpha blending mode)
158c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * @rop3: Raster operation (for ROP3 mode)
159c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * @fb_mem: Frame buffer virtual memory address
160c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * @fb_size: Frame buffer size in bytes
161c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * @dma_handle: Frame buffer DMA address
162c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * @base_addr_y: Overlay base address (RGB or luma component)
163c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * @base_addr_c: Overlay base address (chroma component)
164c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * @pan_offset: Current pan offset in bytes
165c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * @format: Current pixelf format
166c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * @xres: Horizontal visible resolution
167c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * @xres_virtual: Horizontal total resolution
168c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * @yres: Vertical visible resolution
169c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * @yres_virtual: Vertical total resolution
170c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * @pitch: Overlay line pitch
171c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * @pos_x: Horizontal overlay position
172c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * @pos_y: Vertical overlay position
173c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart */
174c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstruct sh_mobile_lcdc_overlay {
175c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_chan *channel;
176c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
177c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	const struct sh_mobile_lcdc_overlay_cfg *cfg;
178c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info;
179c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
180c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned int index;
181c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned long base;
182c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
183c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	bool enabled;
184c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	enum sh_mobile_lcdc_overlay_mode mode;
185c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned int alpha;
186c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned int rop3;
187c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
188c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	void *fb_mem;
189c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned long fb_size;
190c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
191c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	dma_addr_t dma_handle;
192c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned long base_addr_y;
193c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned long base_addr_c;
194c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned long pan_offset;
195c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
196c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	const struct sh_mobile_lcdc_format_info *format;
197c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned int xres;
198c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned int xres_virtual;
199c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned int yres;
200c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned int yres_virtual;
201c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned int pitch;
202c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	int pos_x;
203c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	int pos_y;
204c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart};
205c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
206f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchartstruct sh_mobile_lcdc_priv {
207f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	void __iomem *base;
208f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	int irq;
209f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	atomic_t hw_usecnt;
210f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	struct device *dev;
211f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	struct clk *dot_clk;
212f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	unsigned long lddckr;
213c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
214f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	struct sh_mobile_lcdc_chan ch[2];
215c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay overlays[4];
216c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
217f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	struct notifier_block notifier;
218f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	int started;
219f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	int forced_fourcc; /* 2 channel LCDC must share fourcc setting */
220f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	struct sh_mobile_meram_info *meram_dev;
221f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart};
222f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
223f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
224f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Registers access
225f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
226f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2270246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = {
228cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDDCKPAT1R] = 0x400,
229cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDDCKPAT2R] = 0x404,
230cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDMT1R] = 0x418,
231cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDMT2R] = 0x41c,
232cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDMT3R] = 0x420,
233cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDDFR] = 0x424,
234cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDSM1R] = 0x428,
2358564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	[LDSM2R] = 0x42c,
236cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDSA1R] = 0x430,
23753b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia	[LDSA2R] = 0x434,
238cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDMLSR] = 0x438,
239cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDHCNR] = 0x448,
240cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDHSYNR] = 0x44c,
241cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDVLNR] = 0x450,
242cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDVSYNR] = 0x454,
243cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDPMR] = 0x460,
2446011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	[LDHAJR] = 0x4a0,
245cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm};
246cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2470246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic unsigned long lcdc_offs_sublcd[NR_CH_REGS] = {
248cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDDCKPAT1R] = 0x408,
249cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDDCKPAT2R] = 0x40c,
250cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDMT1R] = 0x600,
251cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDMT2R] = 0x604,
252cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDMT3R] = 0x608,
253cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDDFR] = 0x60c,
254cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDSM1R] = 0x610,
2558564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	[LDSM2R] = 0x614,
256cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDSA1R] = 0x618,
257cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDMLSR] = 0x620,
258cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDHCNR] = 0x624,
259cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDHSYNR] = 0x628,
260cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDVLNR] = 0x62c,
261cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDVSYNR] = 0x630,
262cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDPMR] = 0x63c,
263cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm};
264cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
265a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthystatic bool banked(int reg_nr)
266a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy{
267a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	switch (reg_nr) {
268a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	case LDMT1R:
269a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	case LDMT2R:
270a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	case LDMT3R:
271a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	case LDDFR:
272a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	case LDSM1R:
273a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	case LDSA1R:
27453b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia	case LDSA2R:
275a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	case LDMLSR:
276a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	case LDHCNR:
277a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	case LDHSYNR:
278a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	case LDVLNR:
279a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	case LDVSYNR:
280a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy		return true;
281a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	}
282a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	return false;
283a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy}
284a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy
285f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchartstatic int lcdc_chan_is_sublcd(struct sh_mobile_lcdc_chan *chan)
286f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart{
287b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	return chan->cfg->chan == LCDC_CHAN_SUBLCD;
288f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart}
289f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
290cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_write_chan(struct sh_mobile_lcdc_chan *chan,
291cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			    int reg_nr, unsigned long data)
292cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
293cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr]);
294a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	if (banked(reg_nr))
295a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy		iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr] +
296a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy			  SIDE_B_OFFSET);
297a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy}
298a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy
299a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthystatic void lcdc_write_chan_mirror(struct sh_mobile_lcdc_chan *chan,
300a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy			    int reg_nr, unsigned long data)
301a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy{
302a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr] +
303a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy		  MIRROR_OFFSET);
304cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
305cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
306cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic unsigned long lcdc_read_chan(struct sh_mobile_lcdc_chan *chan,
307cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm				    int reg_nr)
308cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
309cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	return ioread32(chan->lcdc->base + chan->reg_offs[reg_nr]);
310cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
311cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
312c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic void lcdc_write_overlay(struct sh_mobile_lcdc_overlay *ovl,
313c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			       int reg, unsigned long data)
314c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
315c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	iowrite32(data, ovl->channel->lcdc->base + reg);
316c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	iowrite32(data, ovl->channel->lcdc->base + reg + SIDE_B_OFFSET);
317c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
318c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
319cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_write(struct sh_mobile_lcdc_priv *priv,
320cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		       unsigned long reg_offs, unsigned long data)
321cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
322cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	iowrite32(data, priv->base + reg_offs);
323cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
324cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
325cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic unsigned long lcdc_read(struct sh_mobile_lcdc_priv *priv,
326cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			       unsigned long reg_offs)
327cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
328cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	return ioread32(priv->base + reg_offs);
329cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
330cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
331cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_wait_bit(struct sh_mobile_lcdc_priv *priv,
332cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			  unsigned long reg_offs,
333cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			  unsigned long mask, unsigned long until)
334cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
335cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	while ((lcdc_read(priv, reg_offs) & mask) != until)
336cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		cpu_relax();
337cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
338cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
339f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
340f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Clock management
341f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
342f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
343f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchartstatic void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv)
344cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
345f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	if (atomic_inc_and_test(&priv->hw_usecnt)) {
346f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		if (priv->dot_clk)
347f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart			clk_enable(priv->dot_clk);
348f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		pm_runtime_get_sync(priv->dev);
349f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		if (priv->meram_dev && priv->meram_dev->pdev)
350f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart			pm_runtime_get_sync(&priv->meram_dev->pdev->dev);
351f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
352cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
353cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
354f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchartstatic void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv)
355f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart{
356f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	if (atomic_sub_return(1, &priv->hw_usecnt) == -1) {
357f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		if (priv->meram_dev && priv->meram_dev->pdev)
358f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart			pm_runtime_put_sync(&priv->meram_dev->pdev->dev);
359f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		pm_runtime_put(priv->dev);
360f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		if (priv->dot_clk)
361f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart			clk_disable(priv->dot_clk);
362f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
363f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart}
364f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
3650a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchartstatic int sh_mobile_lcdc_setup_clocks(struct sh_mobile_lcdc_priv *priv,
3660a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart				       int clock_source)
367f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart{
3684774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	struct clk *clk;
369f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	char *str;
370f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
371f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	switch (clock_source) {
372f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case LCDC_CLK_BUS:
373f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		str = "bus_clk";
374f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		priv->lddckr = LDDCKR_ICKSEL_BUS;
375f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		break;
376f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case LCDC_CLK_PERIPHERAL:
377f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		str = "peripheral_clk";
378f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		priv->lddckr = LDDCKR_ICKSEL_MIPI;
379f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		break;
380f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case LCDC_CLK_EXTERNAL:
381f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		str = NULL;
382f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		priv->lddckr = LDDCKR_ICKSEL_HDMI;
383f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		break;
384f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	default:
385f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return -EINVAL;
386f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
387f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
3884774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	if (str == NULL)
3894774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart		return 0;
3904774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart
3910a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart	clk = clk_get(priv->dev, str);
3924774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	if (IS_ERR(clk)) {
3930a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart		dev_err(priv->dev, "cannot get dot clock %s\n", str);
3944774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart		return PTR_ERR(clk);
395f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
396f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
3974774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	priv->dot_clk = clk;
398f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	return 0;
399f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart}
400f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
401f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
40237c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart * Display, panel and deferred I/O
403f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
404f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
405cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_sys_write_index(void *handle, unsigned long data)
406cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
407cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	struct sh_mobile_lcdc_chan *ch = handle;
408cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
409ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_write(ch->lcdc, _LDDWD0R, data | LDDWDxR_WDACT);
410ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
411ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_write(ch->lcdc, _LDDWAR, LDDWAR_WA |
412ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart		   (lcdc_chan_is_sublcd(ch) ? 2 : 0));
413ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
414cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
415cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
416cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_sys_write_data(void *handle, unsigned long data)
417cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
418cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	struct sh_mobile_lcdc_chan *ch = handle;
419cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
420ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_write(ch->lcdc, _LDDWD0R, data | LDDWDxR_WDACT | LDDWDxR_RSW);
421ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
422ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_write(ch->lcdc, _LDDWAR, LDDWAR_WA |
423ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart		   (lcdc_chan_is_sublcd(ch) ? 2 : 0));
424ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
425cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
426cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
427cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic unsigned long lcdc_sys_read_data(void *handle)
428cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
429cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	struct sh_mobile_lcdc_chan *ch = handle;
430cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
431ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_write(ch->lcdc, _LDDRDR, LDDRDR_RSR);
432ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
433ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_write(ch->lcdc, _LDDRAR, LDDRAR_RA |
434ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart		   (lcdc_chan_is_sublcd(ch) ? 2 : 0));
435cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	udelay(1);
436ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
437cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
438ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	return lcdc_read(ch->lcdc, _LDDRDR) & LDDRDR_DRD_MASK;
439cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
440cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
441cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstruct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = {
442cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	lcdc_sys_write_index,
443cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	lcdc_sys_write_data,
444cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	lcdc_sys_read_data,
445cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm};
446cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
4471c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundtstatic int sh_mobile_lcdc_sginit(struct fb_info *info,
4481c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt				  struct list_head *pagelist)
4491c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt{
4501c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt	struct sh_mobile_lcdc_chan *ch = info->par;
45158f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	unsigned int nr_pages_max = ch->fb_size >> PAGE_SHIFT;
4521c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt	struct page *page;
4531c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt	int nr_pages = 0;
4541c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt
4551c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt	sg_init_table(ch->sglist, nr_pages_max);
4561c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt
4571c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt	list_for_each_entry(page, pagelist, lru)
4581c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt		sg_set_page(&ch->sglist[nr_pages++], page, PAGE_SIZE, 0);
4591c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt
4601c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt	return nr_pages;
4611c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt}
4621c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt
4638564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_deferred_io(struct fb_info *info,
4648564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm				       struct list_head *pagelist)
4658564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{
4668564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	struct sh_mobile_lcdc_chan *ch = info->par;
467b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg;
4688564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
4698564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	/* enable clocks before accessing hardware */
4708564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sh_mobile_lcdc_clk_on(ch->lcdc);
4718564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
4725c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	/*
4735c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * It's possible to get here without anything on the pagelist via
4745c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * sh_mobile_lcdc_deferred_io_touch() or via a userspace fsync()
4755c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * invocation. In the former case, the acceleration routines are
4765c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * stepped in to when using the framebuffer console causing the
4775c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * workqueue to be scheduled without any dirty pages on the list.
4785c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 *
4795c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * Despite this, a panel update is still needed given that the
4805c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * acceleration routines have their own methods for writing in
4815c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * that still need to be updated.
4825c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 *
4835c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * The fsync() and empty pagelist case could be optimized for,
4845c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * but we don't bother, as any application exhibiting such
4855c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * behaviour is fundamentally broken anyways.
4865c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 */
4875c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	if (!list_empty(pagelist)) {
4885c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt		unsigned int nr_pages = sh_mobile_lcdc_sginit(info, pagelist);
4895c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt
4905c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt		/* trigger panel update */
491e8363140c02c92c122210e03103aef72dd836664Laurent Pinchart		dma_map_sg(ch->lcdc->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
492afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart		if (panel->start_transfer)
493afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart			panel->start_transfer(ch, &sh_mobile_lcdc_sys_bus_ops);
494ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart		lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG);
495e8363140c02c92c122210e03103aef72dd836664Laurent Pinchart		dma_unmap_sg(ch->lcdc->dev, ch->sglist, nr_pages,
496e8363140c02c92c122210e03103aef72dd836664Laurent Pinchart			     DMA_TO_DEVICE);
497ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm	} else {
498afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart		if (panel->start_transfer)
499afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart			panel->start_transfer(ch, &sh_mobile_lcdc_sys_bus_ops);
500ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart		lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG);
501ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm	}
5028564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
5038564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
5048564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info)
5058564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{
5068564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	struct fb_deferred_io *fbdefio = info->fbdefio;
5078564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
5088564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	if (fbdefio)
5098564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		schedule_delayed_work(&info->deferred_work, fbdefio->delay);
5108564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
5118564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
51237c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchartstatic void sh_mobile_lcdc_display_on(struct sh_mobile_lcdc_chan *ch)
51337c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart{
514b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg;
51537c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart
5169a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart	if (ch->tx_dev) {
517458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart		int ret;
518458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart
519458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart		ret = ch->tx_dev->ops->display_on(ch->tx_dev);
520458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart		if (ret < 0)
5219a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart			return;
522458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart
523458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart		if (ret == SH_MOBILE_LCDC_DISPLAY_DISCONNECTED)
524458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart			ch->info->state = FBINFO_STATE_SUSPENDED;
5259a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart	}
5269a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart
52737c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart	/* HDMI must be enabled before LCDC configuration */
528afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart	if (panel->display_on)
529afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart		panel->display_on();
53037c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart}
53137c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart
53237c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchartstatic void sh_mobile_lcdc_display_off(struct sh_mobile_lcdc_chan *ch)
53337c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart{
534b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg;
53537c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart
536afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart	if (panel->display_off)
537afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart		panel->display_off();
5389a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart
5399a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart	if (ch->tx_dev)
5409a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart		ch->tx_dev->ops->display_off(ch->tx_dev);
54137c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart}
54237c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart
543ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchartstatic bool
544ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchartsh_mobile_lcdc_must_reconfigure(struct sh_mobile_lcdc_chan *ch,
545e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart				const struct fb_videomode *new_mode)
546ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart{
547ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	dev_dbg(ch->info->dev, "Old %ux%u, new %ux%u\n",
5482d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart		ch->display.mode.xres, ch->display.mode.yres,
5492d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart		new_mode->xres, new_mode->yres);
550ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
551e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart	/* It can be a different monitor with an equal video-mode */
5522d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	if (fb_mode_is_equal(&ch->display.mode, new_mode))
553ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		return false;
554ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
555ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	dev_dbg(ch->info->dev, "Switching %u -> %u lines\n",
5562d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart		ch->display.mode.yres, new_mode->yres);
5572d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	ch->display.mode = *new_mode;
558ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
559ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	return true;
560ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart}
561ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
562d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchartstatic int sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var,
563d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart				    struct fb_info *info);
564ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
565ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchartstatic int sh_mobile_lcdc_display_notify(struct sh_mobile_lcdc_chan *ch,
566ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart					 enum sh_mobile_lcdc_entity_event event,
567e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart					 const struct fb_videomode *mode,
568e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart					 const struct fb_monspecs *monspec)
569ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart{
570ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	struct fb_info *info = ch->info;
571e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart	struct fb_var_screeninfo var;
572ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	int ret = 0;
573ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
574ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	switch (event) {
575ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	case SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT:
576ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		/* HDMI plug in */
577ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		if (lock_fb_info(info)) {
578ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			console_lock();
579ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
5802d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart			ch->display.width = monspec->max_x * 10;
5812d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart			ch->display.height = monspec->max_y * 10;
582e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart
583e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart			if (!sh_mobile_lcdc_must_reconfigure(ch, mode) &&
584ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			    info->state == FBINFO_STATE_RUNNING) {
585ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				/* First activation with the default monitor.
586ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				 * Just turn on, if we run a resume here, the
587ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				 * logo disappears.
588ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				 */
589e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart				info->var.width = monspec->max_x * 10;
590e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart				info->var.height = monspec->max_y * 10;
591ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				sh_mobile_lcdc_display_on(ch);
592ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			} else {
593ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				/* New monitor or have to wake up */
594ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				fb_set_suspend(info, 0);
595ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			}
596ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
597ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			console_unlock();
598ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			unlock_fb_info(info);
599ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		}
600ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		break;
601ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
602ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	case SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT:
603ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		/* HDMI disconnect */
604ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		if (lock_fb_info(info)) {
605ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			console_lock();
606ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			fb_set_suspend(info, 1);
607ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			console_unlock();
608ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			unlock_fb_info(info);
609ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		}
610ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		break;
611ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
612ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	case SH_MOBILE_LCDC_EVENT_DISPLAY_MODE:
613ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		/* Validate a proposed new mode */
614e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart		fb_videomode_to_var(&var, mode);
615e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart		var.bits_per_pixel = info->var.bits_per_pixel;
616e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart		var.grayscale = info->var.grayscale;
617d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart		ret = sh_mobile_lcdc_check_var(&var, info);
618ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		break;
619ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	}
620ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
621ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	return ret;
622ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart}
623ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
624f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
625f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Format helpers
626f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
627f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
628105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchartstruct sh_mobile_lcdc_format_info {
629105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	u32 fourcc;
630105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	unsigned int bpp;
631105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	bool yuv;
632105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	u32 lddfr;
633105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart};
634105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart
635105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchartstatic const struct sh_mobile_lcdc_format_info sh_mobile_format_infos[] = {
636105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	{
637105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_RGB565,
638105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 16,
639105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = false,
640105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_PKF_RGB16,
641105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
642105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_BGR24,
643105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 24,
644105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = false,
645105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_PKF_RGB24,
646105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
647105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_BGR32,
648105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 32,
649105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = false,
650105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_PKF_ARGB32,
651105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
652105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_NV12,
653105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 12,
654105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = true,
655105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_CC | LDDFR_YF_420,
656105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
657105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_NV21,
658105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 12,
659105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = true,
660105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_CC | LDDFR_YF_420,
661105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
662105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_NV16,
663105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 16,
664105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = true,
665105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_CC | LDDFR_YF_422,
666105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
667105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_NV61,
668105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 16,
669105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = true,
670105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_CC | LDDFR_YF_422,
671105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
672105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_NV24,
673105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 24,
674105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = true,
675105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_CC | LDDFR_YF_444,
676105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
677105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_NV42,
678105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 24,
679105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = true,
680105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_CC | LDDFR_YF_444,
681105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	},
682105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart};
683105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart
684105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchartstatic const struct sh_mobile_lcdc_format_info *
685105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchartsh_mobile_format_info(u32 fourcc)
686105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart{
687105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	unsigned int i;
688105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart
689105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(sh_mobile_format_infos); ++i) {
690105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		if (sh_mobile_format_infos[i].fourcc == fourcc)
691105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart			return &sh_mobile_format_infos[i];
692105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}
693105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart
694105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	return NULL;
695105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart}
696105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart
697f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchartstatic int sh_mobile_format_fourcc(const struct fb_var_screeninfo *var)
698f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart{
699f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	if (var->grayscale > 1)
700f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return var->grayscale;
701f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
702f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	switch (var->bits_per_pixel) {
703f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case 16:
704f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return V4L2_PIX_FMT_RGB565;
705f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case 24:
706f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return V4L2_PIX_FMT_BGR24;
707f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case 32:
708f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return V4L2_PIX_FMT_BGR32;
709f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	default:
710f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return 0;
711f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
712f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart}
713f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
714f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchartstatic int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var)
715f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart{
716f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	return var->grayscale > 1;
717f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart}
718f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
719f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
720f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Start, stop and IRQ
721f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
722f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
7238564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
7248564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{
7258564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	struct sh_mobile_lcdc_priv *priv = data;
7262feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	struct sh_mobile_lcdc_chan *ch;
7279dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	unsigned long ldintr;
7282feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	int is_sub;
7292feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	int k;
7308564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
731dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart	/* Acknowledge interrupts and disable further VSYNC End IRQs. */
732dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart	ldintr = lcdc_read(priv, _LDINTR);
733dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart	lcdc_write(priv, _LDINTR, (ldintr ^ LDINTR_STATUS_MASK) & ~LDINTR_VEE);
7348564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
7352feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	/* figure out if this interrupt is for main or sub lcd */
736ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	is_sub = (lcdc_read(priv, _LDSR) & LDSR_MSS) ? 1 : 0;
7372feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
7389dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	/* wake up channel and disable clocks */
7392feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
7402feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		ch = &priv->ch[k];
7412feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
7422feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		if (!ch->enabled)
7432feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm			continue;
7442feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
745dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart		/* Frame End */
7469dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy		if (ldintr & LDINTR_FS) {
7479dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy			if (is_sub == lcdc_chan_is_sublcd(ch)) {
7489dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy				ch->frame_end = 1;
7499dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy				wake_up(&ch->frame_end_wait);
7502feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
7519dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy				sh_mobile_lcdc_clk_off(priv);
7529dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy			}
7539dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy		}
7549dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
7559dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy		/* VSYNC End */
75640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy		if (ldintr & LDINTR_VES)
75740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy			complete(&ch->vsync_completion);
7582feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	}
7592feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
7608564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	return IRQ_HANDLED;
7618564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
7628564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
763d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchartstatic int sh_mobile_lcdc_wait_for_vsync(struct sh_mobile_lcdc_chan *ch)
7644976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart{
7654976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	unsigned long ldintr;
7664976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	int ret;
7674976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart
7684976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	/* Enable VSync End interrupt and be careful not to acknowledge any
7694976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	 * pending interrupt.
7704976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	 */
7714976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	ldintr = lcdc_read(ch->lcdc, _LDINTR);
7724976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	ldintr |= LDINTR_VEE | LDINTR_STATUS_MASK;
7734976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	lcdc_write(ch->lcdc, _LDINTR, ldintr);
7744976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart
7754976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion,
7764976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart							msecs_to_jiffies(100));
7774976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	if (!ret)
7784976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart		return -ETIMEDOUT;
7794976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart
7804976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	return 0;
7814976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart}
7824976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart
783cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv,
784cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm				      int start)
785cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
786cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	unsigned long tmp = lcdc_read(priv, _LDCNT2R);
787cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	int k;
788cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
789cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	/* start or stop the lcdc */
790cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (start)
791ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart		lcdc_write(priv, _LDCNT2R, tmp | LDCNT2R_DO);
792cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	else
793ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart		lcdc_write(priv, _LDCNT2R, tmp & ~LDCNT2R_DO);
794cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
795cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	/* wait until power is applied/stopped on all channels */
796cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++)
797cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (lcdc_read(priv, _LDCNT2R) & priv->ch[k].enabled)
798cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			while (1) {
799ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart				tmp = lcdc_read_chan(&priv->ch[k], LDPMR)
800ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart				    & LDPMR_LPS;
801ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart				if (start && tmp == LDPMR_LPS)
802cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm					break;
803cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm				if (!start && tmp == 0)
804cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm					break;
805cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm				cpu_relax();
806cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			}
807cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
808cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (!start)
809cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		lcdc_write(priv, _LDDCKSTPR, 1); /* stop dotclock */
810cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
811cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
8126011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetskistatic void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
8136011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski{
8142d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	const struct fb_var_screeninfo *var = &ch->info->var;
8152d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	const struct fb_videomode *mode = &ch->display.mode;
8161c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski	unsigned long h_total, hsync_pos, display_h_total;
8176011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	u32 tmp;
8186011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
8196011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	tmp = ch->ldmt1r_value;
820ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	tmp |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : LDMT1R_VPOL;
821ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	tmp |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : LDMT1R_HPOL;
822b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	tmp |= (ch->cfg->flags & LCDC_FLAGS_DWPOL) ? LDMT1R_DWPOL : 0;
823b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	tmp |= (ch->cfg->flags & LCDC_FLAGS_DIPOL) ? LDMT1R_DIPOL : 0;
824b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	tmp |= (ch->cfg->flags & LCDC_FLAGS_DAPOL) ? LDMT1R_DAPOL : 0;
825b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	tmp |= (ch->cfg->flags & LCDC_FLAGS_HSCNT) ? LDMT1R_HSCNT : 0;
826b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	tmp |= (ch->cfg->flags & LCDC_FLAGS_DWCNT) ? LDMT1R_DWCNT : 0;
8276011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDMT1R, tmp);
8286011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
8296011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	/* setup SYS bus */
830b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	lcdc_write_chan(ch, LDMT2R, ch->cfg->sys_bus_cfg.ldmt2r);
831b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	lcdc_write_chan(ch, LDMT3R, ch->cfg->sys_bus_cfg.ldmt3r);
8326011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
8336011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	/* horizontal configuration */
8342d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	h_total = mode->xres + mode->hsync_len + mode->left_margin
8352d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart		+ mode->right_margin;
8366011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	tmp = h_total / 8; /* HTCN */
83758f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	tmp |= (min(mode->xres, ch->xres) / 8) << 16; /* HDCN */
8386011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDHCNR, tmp);
8396011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
8402d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	hsync_pos = mode->xres + mode->right_margin;
8416011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	tmp = hsync_pos / 8; /* HSYNP */
8422d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	tmp |= (mode->hsync_len / 8) << 16; /* HSYNW */
8436011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDHSYNR, tmp);
8446011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
8456011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	/* vertical configuration */
8462d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	tmp = mode->yres + mode->vsync_len + mode->upper_margin
8472d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	    + mode->lower_margin; /* VTLN */
84858f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	tmp |= min(mode->yres, ch->yres) << 16; /* VDLN */
8496011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDVLNR, tmp);
8506011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
8512d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	tmp = mode->yres + mode->lower_margin; /* VSYNP */
8522d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	tmp |= mode->vsync_len << 16; /* VSYNW */
8536011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDVSYNR, tmp);
8546011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
8556011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	/* Adjust horizontal synchronisation for HDMI */
8562d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	display_h_total = mode->xres + mode->hsync_len + mode->left_margin
8572d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart			+ mode->right_margin;
8582d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	tmp = ((mode->xres & 7) << 24) | ((display_h_total & 7) << 16)
8592d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	    | ((mode->hsync_len & 7) << 8) | (hsync_pos & 7);
8606011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDHAJR, tmp);
8616011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski}
8626011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
863c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic void sh_mobile_lcdc_overlay_setup(struct sh_mobile_lcdc_overlay *ovl)
864c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
865c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	u32 format = 0;
866c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
867c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (!ovl->enabled) {
868c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index));
869c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		lcdc_write_overlay(ovl, LDBnBSIFR(ovl->index), 0);
870c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		lcdc_write(ovl->channel->lcdc, LDBCR,
871c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			   LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index));
872c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return;
873c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
874c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
875c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->base_addr_y = ovl->dma_handle;
876c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->base_addr_c = ovl->base_addr_y + ovl->xres
877c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			   * ovl->yres_virtual;
878c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
879c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	switch (ovl->mode) {
880c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case LCDC_OVERLAY_BLEND:
881c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format = LDBBSIFR_EN | (ovl->alpha << LDBBSIFR_LAY_SHIFT);
882c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
883c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
884c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case LCDC_OVERLAY_ROP3:
885c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format = LDBBSIFR_EN | LDBBSIFR_BRSEL
886c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		       | (ovl->rop3 << LDBBSIFR_ROP3_SHIFT);
887c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
888c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
889c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
890c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	switch (ovl->format->fourcc) {
891c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_RGB565:
892c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV21:
893c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV61:
894c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV42:
895c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW;
896c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
897c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_BGR24:
898c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV12:
899c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV16:
900c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV24:
901c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW | LDBBSIFR_SWPB;
902c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
903c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_BGR32:
904c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	default:
905c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format |= LDBBSIFR_SWPL;
906c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
907c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
908c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
909c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	switch (ovl->format->fourcc) {
910c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_RGB565:
911c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB16;
912c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
913c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_BGR24:
914c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB24;
915c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
916c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_BGR32:
917c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format |= LDBBSIFR_AL_PK | LDBBSIFR_RY | LDDFR_PKF_ARGB32;
918c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
919c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV12:
920c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV21:
921c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_420;
922c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
923c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV16:
924c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV61:
925c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_422;
926c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
927c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV24:
928c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV42:
929c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_444;
930c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
931c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
932c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
933c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index));
934c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
935c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write_overlay(ovl, LDBnBSIFR(ovl->index), format);
936c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
937c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write_overlay(ovl, LDBnBSSZR(ovl->index),
938c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		(ovl->yres << LDBBSSZR_BVSS_SHIFT) |
939c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		(ovl->xres << LDBBSSZR_BHSS_SHIFT));
940c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write_overlay(ovl, LDBnBLOCR(ovl->index),
941c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		(ovl->pos_y << LDBBLOCR_CVLC_SHIFT) |
942c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		(ovl->pos_x << LDBBLOCR_CHLC_SHIFT));
943c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write_overlay(ovl, LDBnBSMWR(ovl->index),
944c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->pitch << LDBBSMWR_BSMW_SHIFT);
945c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
946c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write_overlay(ovl, LDBnBSAYR(ovl->index), ovl->base_addr_y);
947c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write_overlay(ovl, LDBnBSACR(ovl->index), ovl->base_addr_c);
948c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
949c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write(ovl->channel->lcdc, LDBCR,
950c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		   LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index));
951c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
952c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
9539a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart/*
954d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart * __sh_mobile_lcdc_start - Configure and start the LCDC
9559a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart * @priv: LCDC device
9569a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart *
9579a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart * Configure all enabled channels and start the LCDC device. All external
9589a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart * devices (clocks, MERAM, panels, ...) are not touched by this function.
9599a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart */
9609a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchartstatic void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
961cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
962cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	struct sh_mobile_lcdc_chan *ch;
963cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	unsigned long tmp;
9649a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	int k, m;
9658564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
9669a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Enable LCDC channels. Read data from external memory, avoid using the
9679a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	 * BEU for now.
9689a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	 */
9699a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_write(priv, _LDCNT2R, priv->ch[0].enabled | priv->ch[1].enabled);
970cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
9719a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Stop the LCDC first and disable all interrupts. */
972cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	sh_mobile_lcdc_start_stop(priv, 0);
9739a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_write(priv, _LDINTR, 0);
974cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
9759a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Configure power supply, dot clocks and start them. */
976cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	tmp = priv->lddckr;
977cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
978cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		ch = &priv->ch[k];
9799a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (!ch->enabled)
980cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			continue;
981cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
9829a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		/* Power supply */
9839a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		lcdc_write_chan(ch, LDPMR, 0);
9849a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
985b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		m = ch->cfg->clock_divider;
986cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (!m)
987cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			continue;
988cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
989505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart		/* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider
990505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart		 * denominator.
991505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart		 */
992505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart		lcdc_write_chan(ch, LDDCKPAT1R, 0);
993505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart		lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1);
994505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart
995cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (m == 1)
996ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart			m = LDDCKR_MOSEL;
997cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0);
998cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
999cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1000cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	lcdc_write(priv, _LDDCKR, tmp);
1001cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	lcdc_write(priv, _LDDCKSTPR, 0);
1002cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0);
1003cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
10049a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Setup geometry, format, frame buffer memory and operation mode. */
1005cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
1006cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		ch = &priv->ch[k];
1007cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (!ch->enabled)
1008cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			continue;
1009cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
10106011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski		sh_mobile_lcdc_geometry(ch);
1011cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1012fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart		tmp = ch->format->lddfr;
1013edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart
1014fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart		if (ch->format->yuv) {
101558f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart			switch (ch->colorspace) {
1016edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			case V4L2_COLORSPACE_REC709:
1017edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart				tmp |= LDDFR_CF1;
101853b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia				break;
1019edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			case V4L2_COLORSPACE_JPEG:
1020edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart				tmp |= LDDFR_CF0;
102153b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia				break;
102253b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia			}
1023417d48274e755e537bae60461558c1f63a4e14deMagnus Damm		}
10247caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
10259a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		lcdc_write_chan(ch, LDDFR, tmp);
102672c04af9a2d57b7945cf3de8e71461bd80695d50Laurent Pinchart		lcdc_write_chan(ch, LDMLSR, ch->line_size);
10279a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		lcdc_write_chan(ch, LDSA1R, ch->base_addr_y);
1028fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart		if (ch->format->yuv)
10299a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			lcdc_write_chan(ch, LDSA2R, ch->base_addr_c);
10307caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
10319a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		/* When using deferred I/O mode, configure the LCDC for one-shot
10329a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		 * operation and enable the frame end interrupt. Otherwise use
10339a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		 * continuous read mode.
10349a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		 */
10359a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (ch->ldmt1r_value & LDMT1R_IFM &&
1036b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		    ch->cfg->sys_bus_cfg.deferred_io_msec) {
10379a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			lcdc_write_chan(ch, LDSM1R, LDSM1R_OS);
10389a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			lcdc_write(priv, _LDINTR, LDINTR_FE);
10399a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		} else {
10409a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			lcdc_write_chan(ch, LDSM1R, 0);
10419a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		}
10429a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	}
10437caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
10449a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Word and long word swap. */
1045fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart	switch (priv->ch[0].format->fourcc) {
1046edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_RGB565:
1047edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV21:
1048edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV61:
1049edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV42:
1050edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		tmp = LDDDSR_LS | LDDDSR_WS;
1051edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		break;
1052edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_BGR24:
1053edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV12:
1054edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV16:
1055edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV24:
10569a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;
1057edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		break;
1058edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_BGR32:
1059edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	default:
1060edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		tmp = LDDDSR_LS;
1061edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		break;
10629a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	}
10639a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_write(priv, _LDDDSR, tmp);
10647caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
10659a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Enable the display output. */
10669a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_write(priv, _LDCNT1R, LDCNT1R_DE);
10679a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	sh_mobile_lcdc_start_stop(priv, 1);
10689a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	priv->started = 1;
10699a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart}
1070cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
10719a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchartstatic int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
10729a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart{
10739a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	struct sh_mobile_meram_info *mdev = priv->meram_dev;
10749a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	struct sh_mobile_lcdc_chan *ch;
10759a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	unsigned long tmp;
10769a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	int ret;
10779a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	int k;
1078cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
10799a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* enable clocks before accessing the hardware */
10809a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
10819a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (priv->ch[k].enabled)
10829a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			sh_mobile_lcdc_clk_on(priv);
10839a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	}
10848564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
10859a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* reset */
10869a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LDCNT2R_BR);
10879a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_wait_bit(priv, _LDCNT2R, LDCNT2R_BR, 0);
10888564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
10899a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
1090b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		const struct sh_mobile_lcdc_panel_cfg *panel;
10918564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
109237c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		ch = &priv->ch[k];
10939a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (!ch->enabled)
10949a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			continue;
10959a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
1096b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		panel = &ch->cfg->panel_cfg;
1097afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart		if (panel->setup_sys) {
1098afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart			ret = panel->setup_sys(ch, &sh_mobile_lcdc_sys_bus_ops);
10999a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			if (ret)
11009a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart				return ret;
11018564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		}
1102cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
1103cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
11049a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Compute frame buffer base address and pitch for each channel. */
11059a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
11069a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		int pixelformat;
11074a2371772146b30113c9c837eb32b64f18376c0dLaurent Pinchart		void *cache;
1108cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
11099a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		ch = &priv->ch[k];
11109a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (!ch->enabled)
11119a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			continue;
1112cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
111358f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		ch->base_addr_y = ch->dma_handle;
111458f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		ch->base_addr_c = ch->base_addr_y + ch->xres * ch->yres_virtual;
111572c04af9a2d57b7945cf3de8e71461bd80695d50Laurent Pinchart		ch->line_size = ch->pitch;
11169a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
11179a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		/* Enable MERAM if possible. */
11186e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart		if (mdev == NULL || ch->cfg->meram_cfg == NULL)
11199a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			continue;
11209a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
11214a2371772146b30113c9c837eb32b64f18376c0dLaurent Pinchart		/* Free the allocated MERAM cache. */
11224a2371772146b30113c9c837eb32b64f18376c0dLaurent Pinchart		if (ch->cache) {
11236e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart			sh_mobile_meram_cache_free(mdev, ch->cache);
11244a2371772146b30113c9c837eb32b64f18376c0dLaurent Pinchart			ch->cache = NULL;
11259a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		}
11269a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
1127fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart		switch (ch->format->fourcc) {
1128edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV12:
1129edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV21:
1130edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV16:
1131edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV61:
11329a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			pixelformat = SH_MOBILE_MERAM_PF_NV;
1133edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			break;
1134edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV24:
1135edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV42:
1136edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			pixelformat = SH_MOBILE_MERAM_PF_NV24;
1137edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			break;
1138edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_RGB565:
1139edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_BGR24:
1140edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_BGR32:
1141edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		default:
1142edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			pixelformat = SH_MOBILE_MERAM_PF_RGB;
1143edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			break;
1144edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		}
11459a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
11466e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart		cache = sh_mobile_meram_cache_alloc(mdev, ch->cfg->meram_cfg,
1147b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart					ch->pitch, ch->yres, pixelformat,
114872c04af9a2d57b7945cf3de8e71461bd80695d50Laurent Pinchart					&ch->line_size);
11494a2371772146b30113c9c837eb32b64f18376c0dLaurent Pinchart		if (!IS_ERR(cache)) {
11506e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart			sh_mobile_meram_cache_update(mdev, cache,
115197d16fe69b6499a14a0c85c053f7bef54ce992a4Laurent Pinchart					ch->base_addr_y, ch->base_addr_c,
115297d16fe69b6499a14a0c85c053f7bef54ce992a4Laurent Pinchart					&ch->base_addr_y, &ch->base_addr_c);
11534a2371772146b30113c9c837eb32b64f18376c0dLaurent Pinchart			ch->cache = cache;
115497d16fe69b6499a14a0c85c053f7bef54ce992a4Laurent Pinchart		}
11559a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	}
11569a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
1157c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	for (k = 0; k < ARRAY_SIZE(priv->overlays); ++k) {
1158c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[k];
1159c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		sh_mobile_lcdc_overlay_setup(ovl);
1160c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1161c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
11629a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Start the LCDC. */
11639a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	__sh_mobile_lcdc_start(priv);
11649a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
11659a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Setup deferred I/O, tell the board code to enable the panels, and
11669a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	 * turn backlight on.
11679a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	 */
1168cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
1169cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		ch = &priv->ch[k];
117021bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm		if (!ch->enabled)
117121bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm			continue;
117221bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm
1173b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		tmp = ch->cfg->sys_bus_cfg.deferred_io_msec;
11749a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (ch->ldmt1r_value & LDMT1R_IFM && tmp) {
11759a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			ch->defio.deferred_io = sh_mobile_lcdc_deferred_io;
11769a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			ch->defio.delay = msecs_to_jiffies(tmp);
11779a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			ch->info->fbdefio = &ch->defio;
11789a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			fb_deferred_io_init(ch->info);
11799a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		}
11809a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
118137c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		sh_mobile_lcdc_display_on(ch);
11823b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
11833b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		if (ch->bl) {
11843b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot			ch->bl->props.power = FB_BLANK_UNBLANK;
11853b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot			backlight_update_status(ch->bl);
11863b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		}
1187cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
1188cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1189cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	return 0;
1190cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
1191cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1192cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
1193cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
1194cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	struct sh_mobile_lcdc_chan *ch;
1195cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	int k;
1196cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
11972feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	/* clean up deferred io and ask board code to disable panel */
1198cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
1199cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		ch = &priv->ch[k];
120021bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm		if (!ch->enabled)
120121bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm			continue;
12028564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
12032feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		/* deferred io mode:
12042feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		 * flush frame, and wait for frame end interrupt
12052feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		 * clean up deferred io and enable clock
12062feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		 */
12075ef6b505d9df45558402bdb823a078840a6a26c4Guennadi Liakhovetski		if (ch->info && ch->info->fbdefio) {
12082feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm			ch->frame_end = 0;
1209e33afddca174171a68d57476ead8947476ab9240Paul Mundt			schedule_delayed_work(&ch->info->deferred_work, 0);
12102feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm			wait_event(ch->frame_end_wait, ch->frame_end);
1211e33afddca174171a68d57476ead8947476ab9240Paul Mundt			fb_deferred_io_cleanup(ch->info);
1212e33afddca174171a68d57476ead8947476ab9240Paul Mundt			ch->info->fbdefio = NULL;
12132feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm			sh_mobile_lcdc_clk_on(priv);
12148564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		}
12152feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
12163b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		if (ch->bl) {
12173b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot			ch->bl->props.power = FB_BLANK_POWERDOWN;
12183b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot			backlight_update_status(ch->bl);
12193b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		}
12203b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
122137c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		sh_mobile_lcdc_display_off(ch);
12227caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
12234a2371772146b30113c9c837eb32b64f18376c0dLaurent Pinchart		/* Free the MERAM cache. */
12244a2371772146b30113c9c837eb32b64f18376c0dLaurent Pinchart		if (ch->cache) {
12256e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart			sh_mobile_meram_cache_free(priv->meram_dev, ch->cache);
12264a2371772146b30113c9c837eb32b64f18376c0dLaurent Pinchart			ch->cache = 0;
12277caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia		}
12287caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
1229cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
1230cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1231cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	/* stop the lcdc */
12328e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm	if (priv->started) {
12338e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm		sh_mobile_lcdc_start_stop(priv, 0);
12348e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm		priv->started = 0;
12358e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm	}
1236b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm
12378564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	/* stop clocks */
12388564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++)
12398564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		if (priv->ch[k].enabled)
12408564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm			sh_mobile_lcdc_clk_off(priv);
1241cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
1242cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1243c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic int __sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var,
1244c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart				      struct fb_info *info)
1245c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1246c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (var->xres > MAX_XRES || var->yres > MAX_YRES)
1247c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1248c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1249c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Make sure the virtual resolution is at least as big as the visible
1250c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 * resolution.
1251c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 */
1252c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (var->xres_virtual < var->xres)
1253c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		var->xres_virtual = var->xres;
1254c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (var->yres_virtual < var->yres)
1255c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		var->yres_virtual = var->yres;
1256c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1257c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (sh_mobile_format_is_fourcc(var)) {
1258c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		const struct sh_mobile_lcdc_format_info *format;
1259c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1260c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format = sh_mobile_format_info(var->grayscale);
1261c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (format == NULL)
1262c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			return -EINVAL;
1263c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		var->bits_per_pixel = format->bpp;
1264c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1265c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		/* Default to RGB and JPEG color-spaces for RGB and YUV formats
1266c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		 * respectively.
1267c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		 */
1268c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (!format->yuv)
1269c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->colorspace = V4L2_COLORSPACE_SRGB;
1270c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		else if (var->colorspace != V4L2_COLORSPACE_REC709)
1271c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->colorspace = V4L2_COLORSPACE_JPEG;
1272c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	} else {
1273c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (var->bits_per_pixel <= 16) {		/* RGB 565 */
1274c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->bits_per_pixel = 16;
1275c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->red.offset = 11;
1276c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->red.length = 5;
1277c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->green.offset = 5;
1278c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->green.length = 6;
1279c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->blue.offset = 0;
1280c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->blue.length = 5;
1281c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->transp.offset = 0;
1282c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->transp.length = 0;
1283c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		} else if (var->bits_per_pixel <= 24) {		/* RGB 888 */
1284c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->bits_per_pixel = 24;
1285c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->red.offset = 16;
1286c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->red.length = 8;
1287c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->green.offset = 8;
1288c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->green.length = 8;
1289c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->blue.offset = 0;
1290c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->blue.length = 8;
1291c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->transp.offset = 0;
1292c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->transp.length = 0;
1293c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		} else if (var->bits_per_pixel <= 32) {		/* RGBA 888 */
1294c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->bits_per_pixel = 32;
1295c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->red.offset = 16;
1296c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->red.length = 8;
1297c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->green.offset = 8;
1298c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->green.length = 8;
1299c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->blue.offset = 0;
1300c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->blue.length = 8;
1301c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->transp.offset = 24;
1302c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->transp.length = 8;
1303c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		} else
1304c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			return -EINVAL;
1305c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1306c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		var->red.msb_right = 0;
1307c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		var->green.msb_right = 0;
1308c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		var->blue.msb_right = 0;
1309c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		var->transp.msb_right = 0;
1310c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1311c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1312c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Make sure we don't exceed our allocated memory. */
1313c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 >
1314c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	    info->fix.smem_len)
1315c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1316c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1317c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return 0;
1318c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1319c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1320c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart/* -----------------------------------------------------------------------------
1321c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * Frame buffer operations - Overlays
1322c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart */
1323c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1324c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic ssize_t
1325c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartoverlay_alpha_show(struct device *dev, struct device_attribute *attr, char *buf)
1326c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1327c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = dev_get_drvdata(dev);
1328c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1329c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1330c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return scnprintf(buf, PAGE_SIZE, "%u\n", ovl->alpha);
1331c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1332c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1333c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic ssize_t
1334c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartoverlay_alpha_store(struct device *dev, struct device_attribute *attr,
1335c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		    const char *buf, size_t count)
1336c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1337c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = dev_get_drvdata(dev);
1338c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1339c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned int alpha;
1340c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	char *endp;
1341c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1342c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	alpha = simple_strtoul(buf, &endp, 10);
1343c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (isspace(*endp))
1344c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		endp++;
1345c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1346c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (endp - buf != count)
1347c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1348c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1349c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (alpha > 255)
1350c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1351c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1352c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ovl->alpha != alpha) {
1353c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->alpha = alpha;
1354c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1355c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (ovl->mode == LCDC_OVERLAY_BLEND && ovl->enabled)
1356c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			sh_mobile_lcdc_overlay_setup(ovl);
1357c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1358c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1359c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return count;
1360c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1361c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1362c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic ssize_t
1363c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartoverlay_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
1364c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1365c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = dev_get_drvdata(dev);
1366c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1367c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1368c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return scnprintf(buf, PAGE_SIZE, "%u\n", ovl->mode);
1369c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1370c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1371c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic ssize_t
1372c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartoverlay_mode_store(struct device *dev, struct device_attribute *attr,
1373c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		   const char *buf, size_t count)
1374c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1375c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = dev_get_drvdata(dev);
1376c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1377c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned int mode;
1378c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	char *endp;
1379c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1380c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	mode = simple_strtoul(buf, &endp, 10);
1381c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (isspace(*endp))
1382c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		endp++;
1383c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1384c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (endp - buf != count)
1385c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1386c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1387c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (mode != LCDC_OVERLAY_BLEND && mode != LCDC_OVERLAY_ROP3)
1388c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1389c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1390c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ovl->mode != mode) {
1391c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->mode = mode;
1392c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1393c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (ovl->enabled)
1394c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			sh_mobile_lcdc_overlay_setup(ovl);
1395c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1396c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1397c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return count;
1398c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1399c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1400c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic ssize_t
1401c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartoverlay_position_show(struct device *dev, struct device_attribute *attr,
1402c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		      char *buf)
1403c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1404c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = dev_get_drvdata(dev);
1405c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1406c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1407c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return scnprintf(buf, PAGE_SIZE, "%d,%d\n", ovl->pos_x, ovl->pos_y);
1408c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1409c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1410c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic ssize_t
1411c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartoverlay_position_store(struct device *dev, struct device_attribute *attr,
1412c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		       const char *buf, size_t count)
1413c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1414c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = dev_get_drvdata(dev);
1415c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1416c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	char *endp;
1417c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	int pos_x;
1418c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	int pos_y;
1419c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1420c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	pos_x = simple_strtol(buf, &endp, 10);
1421c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (*endp != ',')
1422c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1423c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1424c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	pos_y = simple_strtol(endp + 1, &endp, 10);
1425c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (isspace(*endp))
1426c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		endp++;
1427c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1428c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (endp - buf != count)
1429c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1430c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1431c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ovl->pos_x != pos_x || ovl->pos_y != pos_y) {
1432c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->pos_x = pos_x;
1433c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->pos_y = pos_y;
1434c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1435c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (ovl->enabled)
1436c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			sh_mobile_lcdc_overlay_setup(ovl);
1437c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1438c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1439c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return count;
1440c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1441c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1442c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic ssize_t
1443c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartoverlay_rop3_show(struct device *dev, struct device_attribute *attr, char *buf)
1444c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1445c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = dev_get_drvdata(dev);
1446c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1447c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1448c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return scnprintf(buf, PAGE_SIZE, "%u\n", ovl->rop3);
1449c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1450c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1451c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic ssize_t
1452c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartoverlay_rop3_store(struct device *dev, struct device_attribute *attr,
1453c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		    const char *buf, size_t count)
1454c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1455c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = dev_get_drvdata(dev);
1456c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1457c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned int rop3;
1458c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	char *endp;
1459c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1460c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	rop3 = !!simple_strtoul(buf, &endp, 10);
1461c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (isspace(*endp))
1462c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		endp++;
1463c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1464c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (endp - buf != count)
1465c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1466c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1467c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (rop3 > 255)
1468c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1469c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1470c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ovl->rop3 != rop3) {
1471c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->rop3 = rop3;
1472c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1473c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (ovl->mode == LCDC_OVERLAY_ROP3 && ovl->enabled)
1474c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			sh_mobile_lcdc_overlay_setup(ovl);
1475c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1476c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1477c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return count;
1478c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1479c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1480c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic const struct device_attribute overlay_sysfs_attrs[] = {
1481c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	__ATTR(ovl_alpha, S_IRUGO|S_IWUSR,
1482c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	       overlay_alpha_show, overlay_alpha_store),
1483c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	__ATTR(ovl_mode, S_IRUGO|S_IWUSR,
1484c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	       overlay_mode_show, overlay_mode_store),
1485c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	__ATTR(ovl_position, S_IRUGO|S_IWUSR,
1486c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	       overlay_position_show, overlay_position_store),
1487c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	__ATTR(ovl_rop3, S_IRUGO|S_IWUSR,
1488c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	       overlay_rop3_show, overlay_rop3_store),
1489c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart};
1490c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1491c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic const struct fb_fix_screeninfo sh_mobile_lcdc_overlay_fix  = {
1492c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.id =		"SH Mobile LCDC",
1493c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.type =		FB_TYPE_PACKED_PIXELS,
1494c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.visual =	FB_VISUAL_TRUECOLOR,
1495c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.accel =	FB_ACCEL_NONE,
1496c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.xpanstep =	0,
1497c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.ypanstep =	1,
1498c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.ywrapstep =	0,
1499c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.capabilities =	FB_CAP_FOURCC,
1500c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart};
1501c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1502c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic int sh_mobile_lcdc_overlay_pan(struct fb_var_screeninfo *var,
1503c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart				    struct fb_info *info)
1504c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1505c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1506c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned long base_addr_y;
1507c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned long base_addr_c;
1508c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned long pan_offset;
1509c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned long c_offset;
1510c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1511c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (!ovl->format->yuv)
1512c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		pan_offset = var->yoffset * ovl->pitch
1513c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			   + var->xoffset * (ovl->format->bpp / 8);
1514c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	else
1515c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		pan_offset = var->yoffset * ovl->pitch + var->xoffset;
1516c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1517c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (pan_offset == ovl->pan_offset)
1518c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return 0;	/* No change, do nothing */
1519c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1520c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Set the source address for the next refresh */
1521c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	base_addr_y = ovl->dma_handle + pan_offset;
1522c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1523c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->base_addr_y = base_addr_y;
1524c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->base_addr_c = base_addr_y;
1525c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1526c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ovl->format->yuv) {
1527c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		/* Set Y offset */
1528c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		c_offset = var->yoffset * ovl->pitch
1529c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			 * (ovl->format->bpp - 8) / 8;
1530c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		base_addr_c = ovl->dma_handle
1531c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			    + ovl->xres * ovl->yres_virtual
1532c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			    + c_offset;
1533c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		/* Set X offset */
1534c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (ovl->format->fourcc == V4L2_PIX_FMT_NV24)
1535c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			base_addr_c += 2 * var->xoffset;
1536c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		else
1537c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			base_addr_c += var->xoffset;
1538c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1539c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->base_addr_c = base_addr_c;
1540c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1541c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1542c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write_overlay(ovl, LDBnBSAYR(ovl->index), ovl->base_addr_y);
1543c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write_overlay(ovl, LDBnBSACR(ovl->index), ovl->base_addr_c);
1544c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1545c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->pan_offset = pan_offset;
1546c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1547c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return 0;
1548c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1549c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1550c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic int sh_mobile_lcdc_overlay_ioctl(struct fb_info *info, unsigned int cmd,
1551c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart				      unsigned long arg)
1552c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1553c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1554c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1555c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	switch (cmd) {
1556c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case FBIO_WAITFORVSYNC:
1557c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return sh_mobile_lcdc_wait_for_vsync(ovl->channel);
1558c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1559c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	default:
1560c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -ENOIOCTLCMD;
1561c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1562c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1563c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1564c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic int sh_mobile_lcdc_overlay_check_var(struct fb_var_screeninfo *var,
1565c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart					  struct fb_info *info)
1566c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1567c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return __sh_mobile_lcdc_check_var(var, info);
1568c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1569c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1570c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic int sh_mobile_lcdc_overlay_set_par(struct fb_info *info)
1571c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1572c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1573c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1574c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->format =
1575c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		sh_mobile_format_info(sh_mobile_format_fourcc(&info->var));
1576c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1577c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->xres = info->var.xres;
1578c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->xres_virtual = info->var.xres_virtual;
1579c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->yres = info->var.yres;
1580c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->yres_virtual = info->var.yres_virtual;
1581c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1582c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ovl->format->yuv)
1583c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->pitch = info->var.xres;
1584c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	else
1585c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->pitch = info->var.xres * ovl->format->bpp / 8;
1586c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1587c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	sh_mobile_lcdc_overlay_setup(ovl);
1588c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1589c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->fix.line_length = ovl->pitch;
1590c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1591c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (sh_mobile_format_is_fourcc(&info->var)) {
1592c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		info->fix.type = FB_TYPE_FOURCC;
1593c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		info->fix.visual = FB_VISUAL_FOURCC;
1594c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	} else {
1595c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		info->fix.type = FB_TYPE_PACKED_PIXELS;
1596c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		info->fix.visual = FB_VISUAL_TRUECOLOR;
1597c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1598c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1599c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return 0;
1600c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1601c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1602c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart/* Overlay blanking. Disable the overlay when blanked. */
1603c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic int sh_mobile_lcdc_overlay_blank(int blank, struct fb_info *info)
1604c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1605c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1606c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1607c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->enabled = !blank;
1608c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	sh_mobile_lcdc_overlay_setup(ovl);
1609c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1610c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Prevent the backlight from receiving a blanking event by returning
1611c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 * a non-zero value.
1612c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 */
1613c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return 1;
1614c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1615c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1616c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic struct fb_ops sh_mobile_lcdc_overlay_ops = {
1617c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.owner          = THIS_MODULE,
1618c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_read        = fb_sys_read,
1619c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_write       = fb_sys_write,
1620c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_fillrect	= sys_fillrect,
1621c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_copyarea	= sys_copyarea,
1622c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_imageblit	= sys_imageblit,
1623c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_blank	= sh_mobile_lcdc_overlay_blank,
1624c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_pan_display = sh_mobile_lcdc_overlay_pan,
1625c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_ioctl       = sh_mobile_lcdc_overlay_ioctl,
1626c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_check_var	= sh_mobile_lcdc_overlay_check_var,
1627c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_set_par	= sh_mobile_lcdc_overlay_set_par,
1628c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart};
1629c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1630c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic void
1631c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartsh_mobile_lcdc_overlay_fb_unregister(struct sh_mobile_lcdc_overlay *ovl)
1632c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1633c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = ovl->info;
1634c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1635c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (info == NULL || info->dev == NULL)
1636c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return;
1637c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1638c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unregister_framebuffer(ovl->info);
1639c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1640c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1641c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic int __devinit
1642c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartsh_mobile_lcdc_overlay_fb_register(struct sh_mobile_lcdc_overlay *ovl)
1643c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1644c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_priv *lcdc = ovl->channel->lcdc;
1645c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = ovl->info;
1646c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned int i;
1647c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	int ret;
1648c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1649c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (info == NULL)
1650c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return 0;
1651c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1652c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ret = register_framebuffer(info);
1653c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ret < 0)
1654c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return ret;
1655c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1656c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	dev_info(lcdc->dev, "registered %s/overlay %u as %dx%d %dbpp.\n",
1657c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		 dev_name(lcdc->dev), ovl->index, info->var.xres,
1658c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		 info->var.yres, info->var.bits_per_pixel);
1659c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1660c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(overlay_sysfs_attrs); ++i) {
1661c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ret = device_create_file(info->dev, &overlay_sysfs_attrs[i]);
1662c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (ret < 0)
1663c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			return ret;
1664c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1665c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1666c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return 0;
1667c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1668c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1669c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic void
1670c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartsh_mobile_lcdc_overlay_fb_cleanup(struct sh_mobile_lcdc_overlay *ovl)
1671c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1672c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = ovl->info;
1673c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1674c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (info == NULL || info->device == NULL)
1675c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return;
1676c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1677c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	framebuffer_release(info);
1678c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1679c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1680c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic int __devinit
1681c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartsh_mobile_lcdc_overlay_fb_init(struct sh_mobile_lcdc_overlay *ovl)
1682c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1683c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_priv *priv = ovl->channel->lcdc;
1684c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_var_screeninfo *var;
1685c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info;
1686c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1687c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Allocate and initialize the frame buffer device. */
1688c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info = framebuffer_alloc(0, priv->dev);
1689c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (info == NULL) {
1690c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		dev_err(priv->dev, "unable to allocate fb_info\n");
1691c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -ENOMEM;
1692c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1693c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1694c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->info = info;
1695c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1696c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->flags = FBINFO_FLAG_DEFAULT;
1697c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->fbops = &sh_mobile_lcdc_overlay_ops;
1698c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->device = priv->dev;
1699c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->screen_base = ovl->fb_mem;
1700c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->par = ovl;
1701c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1702c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Initialize fixed screen information. Restrict pan to 2 lines steps
1703c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 * for NV12 and NV21.
1704c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 */
1705c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->fix = sh_mobile_lcdc_overlay_fix;
1706c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	snprintf(info->fix.id, sizeof(info->fix.id),
1707c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		 "SH Mobile LCDC Overlay %u", ovl->index);
1708c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->fix.smem_start = ovl->dma_handle;
1709c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->fix.smem_len = ovl->fb_size;
1710c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->fix.line_length = ovl->pitch;
1711c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1712c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ovl->format->yuv)
1713c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		info->fix.visual = FB_VISUAL_FOURCC;
1714c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	else
1715c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		info->fix.visual = FB_VISUAL_TRUECOLOR;
1716c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1717c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ovl->format->fourcc == V4L2_PIX_FMT_NV12 ||
1718c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	    ovl->format->fourcc == V4L2_PIX_FMT_NV21)
1719c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		info->fix.ypanstep = 2;
1720c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1721c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Initialize variable screen information. */
1722c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	var = &info->var;
1723c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	memset(var, 0, sizeof(*var));
1724c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	var->xres = ovl->xres;
1725c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	var->yres = ovl->yres;
1726c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	var->xres_virtual = ovl->xres_virtual;
1727c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	var->yres_virtual = ovl->yres_virtual;
1728c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	var->activate = FB_ACTIVATE_NOW;
1729c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1730c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Use the legacy API by default for RGB formats, and the FOURCC API
1731c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 * for YUV formats.
1732c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 */
1733c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (!ovl->format->yuv)
1734c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		var->bits_per_pixel = ovl->format->bpp;
1735c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	else
1736c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		var->grayscale = ovl->format->fourcc;
1737c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1738c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return sh_mobile_lcdc_overlay_check_var(var, info);
1739c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1740c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1741f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
1742c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * Frame buffer operations - main frame buffer
1743f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
1744cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1745cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_setcolreg(u_int regno,
1746cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm				    u_int red, u_int green, u_int blue,
1747cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm				    u_int transp, struct fb_info *info)
1748cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
1749cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	u32 *palette = info->pseudo_palette;
1750cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1751cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (regno >= PALETTE_NR)
1752cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		return -EINVAL;
1753cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1754cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	/* only FB_VISUAL_TRUECOLOR supported */
1755cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1756cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	red >>= 16 - info->var.red.length;
1757cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	green >>= 16 - info->var.green.length;
1758cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	blue >>= 16 - info->var.blue.length;
1759cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	transp >>= 16 - info->var.transp.length;
1760cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1761cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	palette[regno] = (red << info->var.red.offset) |
1762cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	  (green << info->var.green.offset) |
1763cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	  (blue << info->var.blue.offset) |
1764cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	  (transp << info->var.transp.offset);
1765cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1766cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	return 0;
1767cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
1768cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
17693281e54c80195b90ed12a5b6cddef4ab42e656e1Laurent Pinchartstatic const struct fb_fix_screeninfo sh_mobile_lcdc_fix  = {
1770cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.id =		"SH Mobile LCDC",
1771cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.type =		FB_TYPE_PACKED_PIXELS,
1772cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.visual =	FB_VISUAL_TRUECOLOR,
1773cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.accel =	FB_ACCEL_NONE,
17749dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	.xpanstep =	0,
17759dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	.ypanstep =	1,
17769dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	.ywrapstep =	0,
1777edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	.capabilities =	FB_CAP_FOURCC,
1778cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm};
1779cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
17808564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_fillrect(struct fb_info *info,
17818564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm				    const struct fb_fillrect *rect)
17828564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{
17838564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sys_fillrect(info, rect);
17848564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sh_mobile_lcdc_deferred_io_touch(info);
17858564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
17868564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
17878564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_copyarea(struct fb_info *info,
17888564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm				    const struct fb_copyarea *area)
17898564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{
17908564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sys_copyarea(info, area);
17918564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sh_mobile_lcdc_deferred_io_touch(info);
17928564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
17938564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
17948564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_imageblit(struct fb_info *info,
17958564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm				     const struct fb_image *image)
17968564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{
17978564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sys_imageblit(info, image);
17988564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sh_mobile_lcdc_deferred_io_touch(info);
17998564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
18008564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
1801d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchartstatic int sh_mobile_lcdc_pan(struct fb_var_screeninfo *var,
1802d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart			      struct fb_info *info)
18039dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy{
18049dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	struct sh_mobile_lcdc_chan *ch = info->par;
180592e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	struct sh_mobile_lcdc_priv *priv = ch->lcdc;
180692e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	unsigned long ldrcntr;
180792e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	unsigned long new_pan_offset;
18086e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart	unsigned long base_addr_y, base_addr_c = 0;
180953b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia	unsigned long c_offset;
181092e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy
181158f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	if (!ch->format->yuv)
181258f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		new_pan_offset = var->yoffset * ch->pitch
181358f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart			       + var->xoffset * (ch->format->bpp / 8);
181453b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia	else
181558f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		new_pan_offset = var->yoffset * ch->pitch + var->xoffset;
18169dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
181792e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	if (new_pan_offset == ch->pan_offset)
18189dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy		return 0;	/* No change, do nothing */
18199dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
182092e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	ldrcntr = lcdc_read(priv, _LDRCNTR);
18219dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
182292e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	/* Set the source address for the next refresh */
182353b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia	base_addr_y = ch->dma_handle + new_pan_offset;
182458f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	if (ch->format->yuv) {
182553b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia		/* Set y offset */
182658f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		c_offset = var->yoffset * ch->pitch
182758f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart			 * (ch->format->bpp - 8) / 8;
182858f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		base_addr_c = ch->dma_handle + ch->xres * ch->yres_virtual
1829dc1d5adab5cc57eb732407d80c9e7ae48891ffcaLaurent Pinchart			    + c_offset;
183053b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia		/* Set x offset */
1831fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart		if (ch->format->fourcc == V4L2_PIX_FMT_NV24)
183253b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia			base_addr_c += 2 * var->xoffset;
183353b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia		else
183453b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia			base_addr_c += var->xoffset;
183549d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart	}
183653b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia
18376e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart	if (ch->cache)
18386e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart		sh_mobile_meram_cache_update(priv->meram_dev, ch->cache,
18396e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart					     base_addr_y, base_addr_c,
18406e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart					     &base_addr_y, &base_addr_c);
18417caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
184249d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart	ch->base_addr_y = base_addr_y;
184349d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart	ch->base_addr_c = base_addr_c;
18447caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
184549d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart	lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);
184658f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	if (ch->format->yuv)
184749d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart		lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c);
184853b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia
184992e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	if (lcdc_chan_is_sublcd(ch))
185092e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy		lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS);
185192e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	else
185292e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy		lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_MRS);
185392e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy
185492e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	ch->pan_offset = new_pan_offset;
185592e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy
185692e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	sh_mobile_lcdc_deferred_io_touch(info);
18579dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
18589dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	return 0;
18599dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy}
18609dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
1861d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchartstatic int sh_mobile_lcdc_ioctl(struct fb_info *info, unsigned int cmd,
1862d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart				unsigned long arg)
186340331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy{
1864d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart	struct sh_mobile_lcdc_chan *ch = info->par;
186540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	int retval;
186640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy
186740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	switch (cmd) {
186840331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	case FBIO_WAITFORVSYNC:
1869d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart		retval = sh_mobile_lcdc_wait_for_vsync(ch);
187040331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy		break;
187140331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy
187240331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	default:
187340331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy		retval = -ENOIOCTLCMD;
187440331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy		break;
187540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	}
187640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	return retval;
187740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy}
187840331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy
1879dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetskistatic void sh_mobile_fb_reconfig(struct fb_info *info)
1880dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{
1881dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	struct sh_mobile_lcdc_chan *ch = info->par;
18822d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	struct fb_var_screeninfo var;
18832d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	struct fb_videomode mode;
1884dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	struct fb_event event;
1885dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	int evnt = FB_EVENT_MODE_CHANGE_ALL;
1886dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1887dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	if (ch->use_count > 1 || (ch->use_count == 1 && !info->fbcon_par))
1888dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		/* More framebuffer users are active */
1889dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		return;
1890dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
18912d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	fb_var_to_videomode(&mode, &info->var);
1892dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
18932d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	if (fb_mode_is_equal(&ch->display.mode, &mode))
1894dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		return;
1895dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1896dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	/* Display has been re-plugged, framebuffer is free now, reconfigure */
18972d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	var = info->var;
18982d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	fb_videomode_to_var(&var, &ch->display.mode);
18992d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	var.width = ch->display.width;
19002d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	var.height = ch->display.height;
19012d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	var.activate = FB_ACTIVATE_NOW;
19022d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart
19032d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	if (fb_set_var(info, &var) < 0)
1904dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		/* Couldn't reconfigure, hopefully, can continue as before */
1905dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		return;
1906dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1907dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	/*
1908dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	 * fb_set_var() calls the notifier change internally, only if
1909dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	 * FBINFO_MISC_USEREVENT flag is set. Since we do not want to fake a
1910dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	 * user event, we have to call the chain ourselves.
1911dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	 */
1912dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	event.info = info;
19132d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	event.data = &ch->display.mode;
1914dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	fb_notifier_call_chain(evnt, &event);
1915dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski}
1916dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1917dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski/*
1918dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski * Locking: both .fb_release() and .fb_open() are called with info->lock held if
1919dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski * user == 1, or with console sem held, if user == 0.
1920dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski */
1921d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchartstatic int sh_mobile_lcdc_release(struct fb_info *info, int user)
1922dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{
1923dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	struct sh_mobile_lcdc_chan *ch = info->par;
1924dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1925dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	mutex_lock(&ch->open_lock);
1926dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count);
1927dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1928dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	ch->use_count--;
1929dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1930dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	/* Nothing to reconfigure, when called from fbcon */
1931dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	if (user) {
1932ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn		console_lock();
1933dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		sh_mobile_fb_reconfig(info);
1934ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn		console_unlock();
1935dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	}
1936dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1937dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	mutex_unlock(&ch->open_lock);
1938dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1939dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	return 0;
1940dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski}
1941dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1942d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchartstatic int sh_mobile_lcdc_open(struct fb_info *info, int user)
1943dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{
1944dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	struct sh_mobile_lcdc_chan *ch = info->par;
1945dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1946dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	mutex_lock(&ch->open_lock);
1947dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	ch->use_count++;
1948dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1949dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count);
1950dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	mutex_unlock(&ch->open_lock);
1951dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1952dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	return 0;
1953dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski}
1954dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1955d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchartstatic int sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var,
1956d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart				    struct fb_info *info)
1957dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{
1958dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	struct sh_mobile_lcdc_chan *ch = info->par;
1959417d48274e755e537bae60461558c1f63a4e14deMagnus Damm	struct sh_mobile_lcdc_priv *p = ch->lcdc;
19600386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	unsigned int best_dist = (unsigned int)-1;
19610386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	unsigned int best_xres = 0;
19620386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	unsigned int best_yres = 0;
19630386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	unsigned int i;
1964c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	int ret;
19650386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
19660386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	/* If board code provides us with a list of available modes, make sure
19670386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	 * we use one of them. Find the mode closest to the requested one. The
19680386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	 * distance between two modes is defined as the size of the
19690386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	 * non-overlapping parts of the two rectangles.
19700386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	 */
1971b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	for (i = 0; i < ch->cfg->num_modes; ++i) {
1972b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		const struct fb_videomode *mode = &ch->cfg->lcd_modes[i];
19730386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		unsigned int dist;
19740386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
19750386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		/* We can only round up. */
19760386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		if (var->xres > mode->xres || var->yres > mode->yres)
19770386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			continue;
19780386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
19790386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		dist = var->xres * var->yres + mode->xres * mode->yres
19800386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		     - 2 * min(var->xres, mode->xres)
19810386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			 * min(var->yres, mode->yres);
19820386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
19830386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		if (dist < best_dist) {
19840386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			best_xres = mode->xres;
19850386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			best_yres = mode->yres;
19860386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			best_dist = dist;
19870386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		}
1988dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	}
1989417d48274e755e537bae60461558c1f63a4e14deMagnus Damm
19900386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	/* If no available mode can be used, return an error. */
1991b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	if (ch->cfg->num_modes != 0) {
19920386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		if (best_dist == (unsigned int)-1)
19930386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			return -EINVAL;
19940386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
19950386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		var->xres = best_xres;
19960386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		var->yres = best_yres;
19970386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	}
19980386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
1999c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ret = __sh_mobile_lcdc_check_var(var, info);
2000c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ret < 0)
2001c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return ret;
20020386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
2003edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	/* only accept the forced_fourcc for dual channel configurations */
2004edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	if (p->forced_fourcc &&
2005edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	    p->forced_fourcc != sh_mobile_format_fourcc(var))
2006417d48274e755e537bae60461558c1f63a4e14deMagnus Damm		return -EINVAL;
2007417d48274e755e537bae60461558c1f63a4e14deMagnus Damm
2008dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	return 0;
2009dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski}
201040331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy
2011d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchartstatic int sh_mobile_lcdc_set_par(struct fb_info *info)
2012ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart{
2013ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart	struct sh_mobile_lcdc_chan *ch = info->par;
2014ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart	int ret;
2015ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart
2016ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart	sh_mobile_lcdc_stop(ch->lcdc);
201791fba48d59666718e3d3e86964755b80d39cdbddLaurent Pinchart
2018fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart	ch->format = sh_mobile_format_info(sh_mobile_format_fourcc(&info->var));
201958f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->colorspace = info->var.colorspace;
202058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
202158f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->xres = info->var.xres;
202258f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->xres_virtual = info->var.xres_virtual;
202358f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->yres = info->var.yres;
202458f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->yres_virtual = info->var.yres_virtual;
202558f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
202658f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	if (ch->format->yuv)
202758f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		ch->pitch = info->var.xres;
202858f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	else
202958f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		ch->pitch = info->var.xres * ch->format->bpp / 8;
2030fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart
2031ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart	ret = sh_mobile_lcdc_start(ch->lcdc);
203258f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	if (ret < 0)
2033ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart		dev_err(info->dev, "%s: unable to restart LCDC\n", __func__);
203458f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
203558f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	info->fix.line_length = ch->pitch;
2036ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart
2037edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	if (sh_mobile_format_is_fourcc(&info->var)) {
2038edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		info->fix.type = FB_TYPE_FOURCC;
2039edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		info->fix.visual = FB_VISUAL_FOURCC;
2040edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	} else {
2041edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		info->fix.type = FB_TYPE_PACKED_PIXELS;
2042edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		info->fix.visual = FB_VISUAL_TRUECOLOR;
2043edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	}
2044edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart
2045ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart	return ret;
2046ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart}
2047ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart
20488857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot/*
20498857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * Screen blanking. Behavior is as follows:
20508857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_UNBLANK: screen unblanked, clocks enabled
20518857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_NORMAL: screen blanked, clocks enabled
20528857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_VSYNC,
20538857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_HSYNC,
20548857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_POWEROFF: screen blanked, clocks disabled
20558857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot */
20568857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbotstatic int sh_mobile_lcdc_blank(int blank, struct fb_info *info)
20578857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot{
20588857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	struct sh_mobile_lcdc_chan *ch = info->par;
20598857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	struct sh_mobile_lcdc_priv *p = ch->lcdc;
20608857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot
20618857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	/* blank the screen? */
20628857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	if (blank > FB_BLANK_UNBLANK && ch->blank_status == FB_BLANK_UNBLANK) {
20638857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		struct fb_fillrect rect = {
206458f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart			.width = ch->xres,
206558f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart			.height = ch->yres,
20668857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		};
20678857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		sh_mobile_lcdc_fillrect(info, &rect);
20688857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	}
20698857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	/* turn clocks on? */
20708857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	if (blank <= FB_BLANK_NORMAL && ch->blank_status > FB_BLANK_NORMAL) {
20718857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		sh_mobile_lcdc_clk_on(p);
20728857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	}
20738857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	/* turn clocks off? */
20748857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	if (blank > FB_BLANK_NORMAL && ch->blank_status <= FB_BLANK_NORMAL) {
20758857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		/* make sure the screen is updated with the black fill before
20768857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		 * switching the clocks off. one vsync is not enough since
20778857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		 * blanking may occur in the middle of a refresh. deferred io
20788857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		 * mode will reenable the clocks and update the screen in time,
20798857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		 * so it does not need this. */
20808857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		if (!info->fbdefio) {
2081d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart			sh_mobile_lcdc_wait_for_vsync(ch);
2082d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart			sh_mobile_lcdc_wait_for_vsync(ch);
20838857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		}
20848857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		sh_mobile_lcdc_clk_off(p);
20858857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	}
20868857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot
20878857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	ch->blank_status = blank;
20888857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	return 0;
20898857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot}
20908857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot
2091cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic struct fb_ops sh_mobile_lcdc_ops = {
20929dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	.owner          = THIS_MODULE,
2093cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.fb_setcolreg	= sh_mobile_lcdc_setcolreg,
20942540c111ead82cad605ec2b14a1905ad914cc124Magnus Damm	.fb_read        = fb_sys_read,
20952540c111ead82cad605ec2b14a1905ad914cc124Magnus Damm	.fb_write       = fb_sys_write,
20968564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	.fb_fillrect	= sh_mobile_lcdc_fillrect,
20978564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	.fb_copyarea	= sh_mobile_lcdc_copyarea,
20988564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	.fb_imageblit	= sh_mobile_lcdc_imageblit,
20998857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	.fb_blank	= sh_mobile_lcdc_blank,
2100d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart	.fb_pan_display = sh_mobile_lcdc_pan,
2101d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart	.fb_ioctl       = sh_mobile_lcdc_ioctl,
2102d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart	.fb_open	= sh_mobile_lcdc_open,
2103d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart	.fb_release	= sh_mobile_lcdc_release,
2104d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart	.fb_check_var	= sh_mobile_lcdc_check_var,
2105d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart	.fb_set_par	= sh_mobile_lcdc_set_par,
2106cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm};
2107cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2108a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartstatic void
2109a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartsh_mobile_lcdc_channel_fb_unregister(struct sh_mobile_lcdc_chan *ch)
2110a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart{
2111a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (ch->info && ch->info->dev)
2112a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		unregister_framebuffer(ch->info);
2113a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart}
2114a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2115a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartstatic int __devinit
2116a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartsh_mobile_lcdc_channel_fb_register(struct sh_mobile_lcdc_chan *ch)
2117a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart{
2118a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	struct fb_info *info = ch->info;
2119a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	int ret;
2120a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2121a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (info->fbdefio) {
2122a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		ch->sglist = vmalloc(sizeof(struct scatterlist) *
2123a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart				     ch->fb_size >> PAGE_SHIFT);
2124a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		if (!ch->sglist) {
2125a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart			dev_err(ch->lcdc->dev, "cannot allocate sglist\n");
2126a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart			return -ENOMEM;
2127a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		}
2128a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	}
2129a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2130a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->bl_dev = ch->bl;
2131a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2132a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ret = register_framebuffer(info);
2133a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (ret < 0)
2134a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		return ret;
2135a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2136a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	dev_info(ch->lcdc->dev, "registered %s/%s as %dx%d %dbpp.\n",
2137b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		 dev_name(ch->lcdc->dev), (ch->cfg->chan == LCDC_CHAN_MAINLCD) ?
2138a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		 "mainlcd" : "sublcd", info->var.xres, info->var.yres,
2139a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		 info->var.bits_per_pixel);
2140a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2141a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	/* deferred io mode: disable clock to save power */
2142a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED)
2143a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		sh_mobile_lcdc_clk_off(ch->lcdc);
2144a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2145a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	return ret;
2146a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart}
2147a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2148a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartstatic void
2149a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartsh_mobile_lcdc_channel_fb_cleanup(struct sh_mobile_lcdc_chan *ch)
2150a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart{
2151a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	struct fb_info *info = ch->info;
2152a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2153a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (!info || !info->device)
2154a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		return;
2155a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2156a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (ch->sglist)
2157a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		vfree(ch->sglist);
2158a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2159a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	fb_dealloc_cmap(&info->cmap);
2160a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	framebuffer_release(info);
2161a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart}
2162a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2163a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartstatic int __devinit
2164a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartsh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch,
2165a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart			       const struct fb_videomode *mode,
2166a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart			       unsigned int num_modes)
2167a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart{
2168a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	struct sh_mobile_lcdc_priv *priv = ch->lcdc;
2169a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	struct fb_var_screeninfo *var;
2170a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	struct fb_info *info;
2171a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	int ret;
2172a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2173a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	/* Allocate and initialize the frame buffer device. Create the modes
2174a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 * list and allocate the color map.
2175a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 */
2176a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info = framebuffer_alloc(0, priv->dev);
2177a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (info == NULL) {
2178a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		dev_err(priv->dev, "unable to allocate fb_info\n");
2179a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		return -ENOMEM;
2180a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	}
2181a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2182a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ch->info = info;
2183a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2184a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->flags = FBINFO_FLAG_DEFAULT;
2185a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->fbops = &sh_mobile_lcdc_ops;
2186a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->device = priv->dev;
2187a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->screen_base = ch->fb_mem;
2188a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->pseudo_palette = &ch->pseudo_palette;
2189a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->par = ch;
2190a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2191a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	fb_videomode_to_modelist(mode, num_modes, &info->modelist);
2192a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2193a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);
2194a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (ret < 0) {
2195a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		dev_err(priv->dev, "unable to allocate cmap\n");
2196a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		return ret;
2197a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	}
2198a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2199a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	/* Initialize fixed screen information. Restrict pan to 2 lines steps
2200a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 * for NV12 and NV21.
2201a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 */
2202a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->fix = sh_mobile_lcdc_fix;
2203a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->fix.smem_start = ch->dma_handle;
2204a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->fix.smem_len = ch->fb_size;
220558f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	info->fix.line_length = ch->pitch;
220658f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
220758f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	if (ch->format->yuv)
220858f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		info->fix.visual = FB_VISUAL_FOURCC;
220958f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	else
221058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		info->fix.visual = FB_VISUAL_TRUECOLOR;
221158f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
2212a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (ch->format->fourcc == V4L2_PIX_FMT_NV12 ||
2213a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	    ch->format->fourcc == V4L2_PIX_FMT_NV21)
2214a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		info->fix.ypanstep = 2;
2215a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2216a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	/* Initialize variable screen information using the first mode as
2217a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 * default. The default Y virtual resolution is twice the panel size to
2218a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 * allow for double-buffering.
2219a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 */
2220a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	var = &info->var;
2221a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	fb_videomode_to_var(var, mode);
2222b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	var->width = ch->cfg->panel_cfg.width;
2223b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	var->height = ch->cfg->panel_cfg.height;
2224a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	var->yres_virtual = var->yres * 2;
2225a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	var->activate = FB_ACTIVATE_NOW;
2226a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2227a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	/* Use the legacy API by default for RGB formats, and the FOURCC API
2228a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 * for YUV formats.
2229a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 */
2230a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (!ch->format->yuv)
2231a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		var->bits_per_pixel = ch->format->bpp;
2232a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	else
2233a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		var->grayscale = ch->format->fourcc;
2234a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2235d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart	ret = sh_mobile_lcdc_check_var(var, info);
2236a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (ret)
2237a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		return ret;
2238a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2239a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	return 0;
2240a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart}
2241a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2242f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
2243f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Backlight
2244f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
2245f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
22463b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic int sh_mobile_lcdc_update_bl(struct backlight_device *bdev)
22473b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{
22483b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev);
22493b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	int brightness = bdev->props.brightness;
22503b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
22513b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	if (bdev->props.power != FB_BLANK_UNBLANK ||
22523b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	    bdev->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
22533b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		brightness = 0;
22543b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
2255b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	return ch->cfg->bl_info.set_brightness(brightness);
22563b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot}
22573b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
22583b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic int sh_mobile_lcdc_get_brightness(struct backlight_device *bdev)
22593b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{
22603b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev);
22613b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
2262b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	return ch->cfg->bl_info.get_brightness();
22633b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot}
22643b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
22653b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic int sh_mobile_lcdc_check_fb(struct backlight_device *bdev,
22663b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot				   struct fb_info *info)
22673b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{
22683b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	return (info->bl_dev == bdev);
22693b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot}
22703b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
22713b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic struct backlight_ops sh_mobile_lcdc_bl_ops = {
22723b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	.options	= BL_CORE_SUSPENDRESUME,
22733b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	.update_status	= sh_mobile_lcdc_update_bl,
22743b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	.get_brightness	= sh_mobile_lcdc_get_brightness,
22753b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	.check_fb	= sh_mobile_lcdc_check_fb,
22763b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot};
22773b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
22783b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic struct backlight_device *sh_mobile_lcdc_bl_probe(struct device *parent,
22793b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot					       struct sh_mobile_lcdc_chan *ch)
22803b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{
22813b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	struct backlight_device *bl;
22823b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
2283b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	bl = backlight_device_register(ch->cfg->bl_info.name, parent, ch,
22843b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot				       &sh_mobile_lcdc_bl_ops, NULL);
2285beee1f20a185c7e79fd33bb83e04fe44ecd75af3Dan Carpenter	if (IS_ERR(bl)) {
2286beee1f20a185c7e79fd33bb83e04fe44ecd75af3Dan Carpenter		dev_err(parent, "unable to register backlight device: %ld\n",
2287beee1f20a185c7e79fd33bb83e04fe44ecd75af3Dan Carpenter			PTR_ERR(bl));
22883b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		return NULL;
22893b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	}
22903b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
2291b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	bl->props.max_brightness = ch->cfg->bl_info.max_brightness;
22923b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	bl->props.brightness = bl->props.max_brightness;
22933b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	backlight_update_status(bl);
22943b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
22953b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	return bl;
22963b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot}
22973b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
22983b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic void sh_mobile_lcdc_bl_remove(struct backlight_device *bdev)
22993b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{
23003b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	backlight_device_unregister(bdev);
23013b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot}
23023b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
2303f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
2304f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Power management
2305f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
2306f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
23072feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Dammstatic int sh_mobile_lcdc_suspend(struct device *dev)
23082feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm{
23092feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	struct platform_device *pdev = to_platform_device(dev);
23102feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
23112feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	sh_mobile_lcdc_stop(platform_get_drvdata(pdev));
23122feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	return 0;
23132feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm}
23142feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
23152feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Dammstatic int sh_mobile_lcdc_resume(struct device *dev)
23162feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm{
23172feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	struct platform_device *pdev = to_platform_device(dev);
23182feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
23192feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	return sh_mobile_lcdc_start(platform_get_drvdata(pdev));
23202feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm}
23212feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
23220246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic int sh_mobile_lcdc_runtime_suspend(struct device *dev)
23230246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm{
23240246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	struct platform_device *pdev = to_platform_device(dev);
23252427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart	struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
23260246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm
23270246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	/* turn off LCDC hardware */
23282427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart	lcdc_write(priv, _LDCNT1R, 0);
23292427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart
23300246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	return 0;
23310246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm}
23320246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm
23330246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic int sh_mobile_lcdc_runtime_resume(struct device *dev)
23340246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm{
23350246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	struct platform_device *pdev = to_platform_device(dev);
23362427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart	struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
23370246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm
23382427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart	__sh_mobile_lcdc_start(priv);
23390246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm
23400246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	return 0;
23410246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm}
23420246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm
2343471452104b8520337ae2fb48c4e61cd4896e025dAlexey Dobriyanstatic const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = {
23442feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	.suspend = sh_mobile_lcdc_suspend,
23452feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	.resume = sh_mobile_lcdc_resume,
23460246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	.runtime_suspend = sh_mobile_lcdc_runtime_suspend,
23470246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	.runtime_resume = sh_mobile_lcdc_runtime_resume,
23482feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm};
23492feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
2350f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
2351f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Framebuffer notifier
2352f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
2353f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
23546de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski/* locking: called with info->lock held */
23556011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetskistatic int sh_mobile_lcdc_notify(struct notifier_block *nb,
23566011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski				 unsigned long action, void *data)
23576011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski{
23586011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	struct fb_event *event = data;
23596011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	struct fb_info *info = event->info;
23606011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	struct sh_mobile_lcdc_chan *ch = info->par;
23616011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
23626011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	if (&ch->lcdc->notifier != nb)
2363baf163749952ca5e33dd2d6a74da023e385c3a00Guennadi Liakhovetski		return NOTIFY_DONE;
23646011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
23656011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	dev_dbg(info->dev, "%s(): action = %lu, data = %p\n",
23666011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski		__func__, action, event->data);
23676011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
23686011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	switch(action) {
23696011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	case FB_EVENT_SUSPEND:
237037c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		sh_mobile_lcdc_display_off(ch);
2371afe417c0355154c8b2547619771d6053b3c0aad7Guennadi Liakhovetski		sh_mobile_lcdc_stop(ch->lcdc);
23726011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski		break;
23736011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	case FB_EVENT_RESUME:
2374dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		mutex_lock(&ch->open_lock);
2375dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		sh_mobile_fb_reconfig(info);
2376dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		mutex_unlock(&ch->open_lock);
23776011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
237837c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		sh_mobile_lcdc_display_on(ch);
2379ebe5e12d00f4785092a9650845ad3451bbf4b311Guennadi Liakhovetski		sh_mobile_lcdc_start(ch->lcdc);
23806011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	}
23816011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
2382baf163749952ca5e33dd2d6a74da023e385c3a00Guennadi Liakhovetski	return NOTIFY_OK;
23836011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski}
23846011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
2385f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
2386f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Probe/remove and driver init/exit
2387f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
2388f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2389217e9c4353aa86f0c7eeb4c275bca73ea8b53be1Laurent Pinchartstatic const struct fb_videomode default_720p __devinitconst = {
2390f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.name = "HDMI 720p",
2391f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.xres = 1280,
2392f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.yres = 720,
2393f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2394f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.left_margin = 220,
2395f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.right_margin = 110,
2396f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.hsync_len = 40,
2397f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2398f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.upper_margin = 20,
2399f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.lower_margin = 5,
2400f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.vsync_len = 5,
2401f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2402f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.pixclock = 13468,
2403f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.refresh = 60,
2404f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
2405f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart};
2406f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2407b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchartstatic int sh_mobile_lcdc_remove(struct platform_device *pdev)
2408b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart{
2409b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
2410c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned int i;
2411b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
2412b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	fb_unregister_client(&priv->notifier);
2413b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
2414c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(priv->overlays); i++)
2415c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		sh_mobile_lcdc_overlay_fb_unregister(&priv->overlays[i]);
2416b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
2417a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		sh_mobile_lcdc_channel_fb_unregister(&priv->ch[i]);
2418b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
2419b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	sh_mobile_lcdc_stop(priv);
2420b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
2421c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(priv->overlays); i++) {
2422c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i];
2423c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2424c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		sh_mobile_lcdc_overlay_fb_cleanup(ovl);
2425c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2426c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (ovl->fb_mem)
2427c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			dma_free_coherent(&pdev->dev, ovl->fb_size,
2428c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart					  ovl->fb_mem, ovl->dma_handle);
2429c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
2430c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2431b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
24329a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart		struct sh_mobile_lcdc_chan *ch = &priv->ch[i];
2433b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
2434e34d0bbb062cc78802d0f0686c939ea1569889a6Laurent Pinchart		if (ch->tx_dev) {
2435e34d0bbb062cc78802d0f0686c939ea1569889a6Laurent Pinchart			ch->tx_dev->lcdc = NULL;
2436b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart			module_put(ch->cfg->tx_dev->dev.driver->owner);
2437e34d0bbb062cc78802d0f0686c939ea1569889a6Laurent Pinchart		}
24389a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart
2439a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		sh_mobile_lcdc_channel_fb_cleanup(ch);
2440b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
2441a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		if (ch->fb_mem)
2442a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart			dma_free_coherent(&pdev->dev, ch->fb_size,
2443a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart					  ch->fb_mem, ch->dma_handle);
2444b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	}
2445b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
2446b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
24470c75c4e073a8ec35bfd6c8adcceb2b896f2063e2Laurent Pinchart		struct sh_mobile_lcdc_chan *ch = &priv->ch[i];
24480c75c4e073a8ec35bfd6c8adcceb2b896f2063e2Laurent Pinchart
24490c75c4e073a8ec35bfd6c8adcceb2b896f2063e2Laurent Pinchart		if (ch->bl)
24500c75c4e073a8ec35bfd6c8adcceb2b896f2063e2Laurent Pinchart			sh_mobile_lcdc_bl_remove(ch->bl);
24510c75c4e073a8ec35bfd6c8adcceb2b896f2063e2Laurent Pinchart		mutex_destroy(&ch->open_lock);
2452b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	}
2453b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
24544774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	if (priv->dot_clk) {
24554774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart		pm_runtime_disable(&pdev->dev);
2456b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart		clk_put(priv->dot_clk);
24574774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	}
2458b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
2459b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	if (priv->base)
2460b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart		iounmap(priv->base);
2461b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
2462b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	if (priv->irq)
2463b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart		free_irq(priv->irq, priv);
2464b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	kfree(priv);
2465b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	return 0;
2466b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart}
2467cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2468217e9c4353aa86f0c7eeb4c275bca73ea8b53be1Laurent Pinchartstatic int __devinit sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
2469f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart{
2470b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	int interface_type = ch->cfg->interface_type;
2471f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2472f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	switch (interface_type) {
2473f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB8:
2474f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB9:
2475f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB12A:
2476f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB12B:
2477f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB16:
2478f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB18:
2479f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB24:
2480f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS8A:
2481f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS8B:
2482f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS8C:
2483f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS8D:
2484f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS9:
2485f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS12:
2486f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS16A:
2487f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS16B:
2488f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS16C:
2489f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS18:
2490f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS24:
2491f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		break;
2492f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	default:
2493f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return -EINVAL;
2494f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
2495f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2496f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	/* SUBLCD only supports SYS interface */
2497f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	if (lcdc_chan_is_sublcd(ch)) {
2498f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		if (!(interface_type & LDMT1R_IFM))
2499f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart			return -EINVAL;
2500f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2501f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		interface_type &= ~LDMT1R_IFM;
2502f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
2503f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2504f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	ch->ldmt1r_value = interface_type;
2505f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	return 0;
2506f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart}
2507f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
25080a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchartstatic int __devinit
2509c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartsh_mobile_lcdc_overlay_init(struct sh_mobile_lcdc_priv *priv,
2510c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			  struct sh_mobile_lcdc_overlay *ovl)
2511c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
2512c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	const struct sh_mobile_lcdc_format_info *format;
2513c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	int ret;
2514c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2515c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ovl->cfg->fourcc == 0)
2516c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return 0;
2517c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2518c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Validate the format. */
2519c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	format = sh_mobile_format_info(ovl->cfg->fourcc);
2520c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (format == NULL) {
2521c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		dev_err(priv->dev, "Invalid FOURCC %08x\n", ovl->cfg->fourcc);
2522c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
2523c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
2524c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2525c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->enabled = false;
2526c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->mode = LCDC_OVERLAY_BLEND;
2527c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->alpha = 255;
2528c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->rop3 = 0;
2529c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->pos_x = 0;
2530c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->pos_y = 0;
2531c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2532c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* The default Y virtual resolution is twice the panel size to allow for
2533c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 * double-buffering.
2534c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 */
2535c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->format = format;
2536c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->xres = ovl->cfg->max_xres;
2537c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->xres_virtual = ovl->xres;
2538c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->yres = ovl->cfg->max_yres;
2539c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->yres_virtual = ovl->yres * 2;
2540c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2541c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (!format->yuv)
2542c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->pitch = ovl->xres * format->bpp / 8;
2543c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	else
2544c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->pitch = ovl->xres;
2545c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2546c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Allocate frame buffer memory. */
2547c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->fb_size = ovl->cfg->max_xres * ovl->cfg->max_yres
2548c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		       * format->bpp / 8 * 2;
2549c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->fb_mem = dma_alloc_coherent(priv->dev, ovl->fb_size,
2550c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart					   &ovl->dma_handle, GFP_KERNEL);
2551c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (!ovl->fb_mem) {
2552c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		dev_err(priv->dev, "unable to allocate buffer\n");
2553c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -ENOMEM;
2554c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
2555c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2556c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ret = sh_mobile_lcdc_overlay_fb_init(ovl);
2557c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ret < 0)
2558c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return ret;
2559c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2560c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return 0;
2561c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
2562c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2563c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic int __devinit
25640a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchartsh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
25650a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart			    struct sh_mobile_lcdc_chan *ch)
2566cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
2567105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	const struct sh_mobile_lcdc_format_info *format;
2568b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	const struct sh_mobile_lcdc_chan_cfg *cfg = ch->cfg;
25693ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	const struct fb_videomode *max_mode;
25703ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	const struct fb_videomode *mode;
2571a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	unsigned int num_modes;
25723ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	unsigned int max_size;
2573a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	unsigned int i;
25743ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
2575a67472ad1ae040f073e45048cbc5a01195f2e3f5Laurent Pinchart	mutex_init(&ch->open_lock);
2576ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	ch->notify = sh_mobile_lcdc_display_notify;
2577a67472ad1ae040f073e45048cbc5a01195f2e3f5Laurent Pinchart
2578105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	/* Validate the format. */
2579105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	format = sh_mobile_format_info(cfg->fourcc);
2580105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	if (format == NULL) {
2581105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		dev_err(priv->dev, "Invalid FOURCC %08x.\n", cfg->fourcc);
2582105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		return -EINVAL;
2583105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}
2584105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart
25853ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	/* Iterate through the modes to validate them and find the highest
25863ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	 * resolution.
25873ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	 */
25883ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	max_mode = NULL;
25893ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	max_size = 0;
25903ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
259193ff259846a774ff37dca54792c5a3a6425882c0Laurent Pinchart	for (i = 0, mode = cfg->lcd_modes; i < cfg->num_modes; i++, mode++) {
25923ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		unsigned int size = mode->yres * mode->xres;
25933ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
2594edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		/* NV12/NV21 buffers must have even number of lines */
2595edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		if ((cfg->fourcc == V4L2_PIX_FMT_NV12 ||
2596edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		     cfg->fourcc == V4L2_PIX_FMT_NV21) && (mode->yres & 0x1)) {
25970a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart			dev_err(priv->dev, "yres must be multiple of 2 for "
25980a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart				"YCbCr420 mode.\n");
25993ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			return -EINVAL;
26003ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		}
26013ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
26023ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		if (size > max_size) {
26033ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			max_mode = mode;
26043ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			max_size = size;
26053ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		}
26063ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	}
26073ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
26083ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	if (!max_size)
26093ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		max_size = MAX_XRES * MAX_YRES;
26103ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	else
26110a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart		dev_dbg(priv->dev, "Found largest videomode %ux%u\n",
26123ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			max_mode->xres, max_mode->yres);
26133ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
261493ff259846a774ff37dca54792c5a3a6425882c0Laurent Pinchart	if (cfg->lcd_modes == NULL) {
26153ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		mode = &default_720p;
261693ff259846a774ff37dca54792c5a3a6425882c0Laurent Pinchart		num_modes = 1;
26173ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	} else {
261893ff259846a774ff37dca54792c5a3a6425882c0Laurent Pinchart		mode = cfg->lcd_modes;
261993ff259846a774ff37dca54792c5a3a6425882c0Laurent Pinchart		num_modes = cfg->num_modes;
26203ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	}
26213ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
262258f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	/* Use the first mode as default. */
262358f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->format = format;
262458f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->xres = mode->xres;
262558f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->xres_virtual = mode->xres;
262658f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->yres = mode->yres;
262758f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->yres_virtual = mode->yres * 2;
262858f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
262958f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	if (!format->yuv) {
263058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		ch->colorspace = V4L2_COLORSPACE_SRGB;
263158f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		ch->pitch = ch->xres * format->bpp / 8;
263258f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	} else {
263358f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		ch->colorspace = V4L2_COLORSPACE_REC709;
263458f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		ch->pitch = ch->xres;
263558f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	}
263658f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
2637a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ch->display.width = cfg->panel_cfg.width;
2638a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ch->display.height = cfg->panel_cfg.height;
2639a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ch->display.mode = *mode;
2640a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2641a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	/* Allocate frame buffer memory. */
2642a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ch->fb_size = max_size * format->bpp / 8 * 2;
2643a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ch->fb_mem = dma_alloc_coherent(priv->dev, ch->fb_size, &ch->dma_handle,
2644a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart					GFP_KERNEL);
2645a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (ch->fb_mem == NULL) {
2646a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		dev_err(priv->dev, "unable to allocate buffer\n");
2647a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		return -ENOMEM;
2648a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	}
26493ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
265013f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart	/* Initialize the transmitter device if present. */
265113f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart	if (cfg->tx_dev) {
265213f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart		if (!cfg->tx_dev->dev.driver ||
265313f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart		    !try_module_get(cfg->tx_dev->dev.driver->owner)) {
265413f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart			dev_warn(priv->dev,
265513f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart				 "unable to get transmitter device\n");
265613f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart			return -EINVAL;
265713f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart		}
265813f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart		ch->tx_dev = platform_get_drvdata(cfg->tx_dev);
265913f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart		ch->tx_dev->lcdc = ch;
266013f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart		ch->tx_dev->def_mode = *mode;
266113f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart	}
266213f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart
2663a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	return sh_mobile_lcdc_channel_fb_init(ch, mode, num_modes);
26643ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart}
26653ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
26663ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchartstatic int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
26673ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart{
266801ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski	struct sh_mobile_lcdc_info *pdata = pdev->dev.platform_data;
26693ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	struct sh_mobile_lcdc_priv *priv;
2670cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	struct resource *res;
26713ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	int num_channels;
2672cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	int error;
26733ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	int i;
2674cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
267501ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski	if (!pdata) {
2676cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		dev_err(&pdev->dev, "no platform data defined\n");
26778bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski		return -EINVAL;
2678cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2679cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2680cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
26818564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	i = platform_get_irq(pdev, 0);
26828564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	if (!res || i < 0) {
26838564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		dev_err(&pdev->dev, "cannot get platform resources\n");
26848bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski		return -ENOENT;
2685cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2686cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2687cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
2688cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (!priv) {
2689cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		dev_err(&pdev->dev, "cannot allocate device data\n");
26908bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski		return -ENOMEM;
2691cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2692cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
26934774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	priv->dev = &pdev->dev;
26944774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	priv->meram_dev = pdata->meram_dev;
26958bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski	platform_set_drvdata(pdev, priv);
26968bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski
2697f8798ccbefc0e4ef7438c080b7ba0410738c8cfaYong Zhang	error = request_irq(i, sh_mobile_lcdc_irq, 0,
26987ad33e74857f16f1202cbc5746faf52e88e8b376Kay Sievers			    dev_name(&pdev->dev), priv);
26998564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	if (error) {
27008564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		dev_err(&pdev->dev, "unable to request irq\n");
27018564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		goto err1;
27028564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	}
27038564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
27048564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	priv->irq = i;
27055ef6b505d9df45558402bdb823a078840a6a26c4Guennadi Liakhovetski	atomic_set(&priv->hw_usecnt, -1);
2706cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
27073ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	for (i = 0, num_channels = 0; i < ARRAY_SIZE(pdata->ch); i++) {
27083ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		struct sh_mobile_lcdc_chan *ch = priv->ch + num_channels;
2709cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
271001ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski		ch->lcdc = priv;
2711b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		ch->cfg = &pdata->ch[i];
2712cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
271301ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski		error = sh_mobile_lcdc_check_interface(ch);
2714cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (error) {
2715cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			dev_err(&pdev->dev, "unsupported interface type\n");
2716cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			goto err1;
2717cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		}
271801ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski		init_waitqueue_head(&ch->frame_end_wait);
271901ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski		init_completion(&ch->vsync_completion);
272001ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski		ch->pan_offset = 0;
2721cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
27223b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		/* probe the backlight is there is one defined */
2723b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		if (ch->cfg->bl_info.max_brightness)
27243b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot			ch->bl = sh_mobile_lcdc_bl_probe(&pdev->dev, ch);
27253b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
2726cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		switch (pdata->ch[i].chan) {
2727cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		case LCDC_CHAN_MAINLCD:
2728ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart			ch->enabled = LDCNT2R_ME;
272901ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski			ch->reg_offs = lcdc_offs_mainlcd;
27303ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			num_channels++;
2731cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			break;
2732cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		case LCDC_CHAN_SUBLCD:
2733ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart			ch->enabled = LDCNT2R_SE;
273401ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski			ch->reg_offs = lcdc_offs_sublcd;
27353ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			num_channels++;
2736cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			break;
2737cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		}
2738cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2739cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
27403ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	if (!num_channels) {
2741cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		dev_err(&pdev->dev, "no channels defined\n");
2742cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		error = -EINVAL;
2743cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		goto err1;
2744cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2745cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2746edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	/* for dual channel LCDC (MAIN + SUB) force shared format setting */
27473ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	if (num_channels == 2)
2748edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		priv->forced_fourcc = pdata->ch[0].fourcc;
2749417d48274e755e537bae60461558c1f63a4e14deMagnus Damm
2750dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski	priv->base = ioremap_nocache(res->start, resource_size(res));
2751dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski	if (!priv->base)
2752dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski		goto err1;
2753dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski
27540a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart	error = sh_mobile_lcdc_setup_clocks(priv, pdata->clock_source);
2755cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (error) {
2756cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		dev_err(&pdev->dev, "unable to setup clocks\n");
2757cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		goto err1;
2758cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2759cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
27604774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	/* Enable runtime PM. */
27614774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	pm_runtime_enable(&pdev->dev);
27627caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
27633ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	for (i = 0; i < num_channels; i++) {
276401ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski		struct sh_mobile_lcdc_chan *ch = priv->ch + i;
2765c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski
27660a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart		error = sh_mobile_lcdc_channel_init(priv, ch);
2767cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (error)
27683ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			goto err1;
2769cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2770cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2771c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(pdata->overlays); i++) {
2772c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i];
2773c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2774c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->cfg = &pdata->overlays[i];
2775c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->channel = &priv->ch[0];
2776c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2777c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		error = sh_mobile_lcdc_overlay_init(priv, ovl);
2778c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (error)
2779c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			goto err1;
2780c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
2781c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2782cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	error = sh_mobile_lcdc_start(priv);
2783cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (error) {
2784cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		dev_err(&pdev->dev, "unable to start hardware\n");
2785cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		goto err1;
2786cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2787cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
27883ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	for (i = 0; i < num_channels; i++) {
27891c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt		struct sh_mobile_lcdc_chan *ch = priv->ch + i;
27901c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt
2791a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		error = sh_mobile_lcdc_channel_fb_register(ch);
2792a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		if (error)
2793cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			goto err1;
2794cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2795cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2796c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(pdata->overlays); i++) {
2797c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i];
2798c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2799c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		error = sh_mobile_lcdc_overlay_fb_register(ovl);
2800c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (error)
2801c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			goto err1;
2802c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
2803c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
28046011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	/* Failure ignored */
28056011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	priv->notifier.notifier_call = sh_mobile_lcdc_notify;
28066011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	fb_register_client(&priv->notifier);
28076011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
2808cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	return 0;
28098bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetskierr1:
2810cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	sh_mobile_lcdc_remove(pdev);
28118bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski
2812cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	return error;
2813cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
2814cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2815cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic struct platform_driver sh_mobile_lcdc_driver = {
2816cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.driver		= {
2817cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		.name		= "sh_mobile_lcdc_fb",
2818cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		.owner		= THIS_MODULE,
28192feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		.pm		= &sh_mobile_lcdc_dev_pm_ops,
2820cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	},
2821cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.probe		= sh_mobile_lcdc_probe,
2822cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.remove		= sh_mobile_lcdc_remove,
2823cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm};
2824cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
28254277f2c4667187cbbdd3da3be31ee681bc6b8300Axel Linmodule_platform_driver(sh_mobile_lcdc_driver);
2826cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2827cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_DESCRIPTION("SuperH Mobile LCDC Framebuffer driver");
2828cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
2829cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_LICENSE("GPL v2");
2830