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)
164a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart * @pan_y_offset: Panning linear offset in bytes (luma component)
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;
194a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	unsigned long pan_y_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)
347deccd24f9077ccabc6b34f2e6d2f75c98b528fa1Laurent Pinchart			clk_prepare_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)
361deccd24f9077ccabc6b34f2e6d2f75c98b528fa1Laurent Pinchart			clk_disable_unprepare(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
441d38d840ac61fdd5fe86b3b5925f538b0a26ed85bLaurent Pinchartstatic struct 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 */
5773a41c5dbe8bc396a7fb16ca8739e945bb003342eGu Zheng		console_lock();
578ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		if (lock_fb_info(info)) {
5793a41c5dbe8bc396a7fb16ca8739e945bb003342eGu Zheng
580ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
5812d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart			ch->display.width = monspec->max_x * 10;
5822d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart			ch->display.height = monspec->max_y * 10;
583e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart
584e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart			if (!sh_mobile_lcdc_must_reconfigure(ch, mode) &&
585ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			    info->state == FBINFO_STATE_RUNNING) {
586ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				/* First activation with the default monitor.
587ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				 * Just turn on, if we run a resume here, the
588ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				 * logo disappears.
589ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				 */
590856e8dfe6efed7cf35bc6bf827f030a164bee083Laurent Pinchart				info->var.width = ch->display.width;
591856e8dfe6efed7cf35bc6bf827f030a164bee083Laurent Pinchart				info->var.height = ch->display.height;
592ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				sh_mobile_lcdc_display_on(ch);
593ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			} else {
594ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				/* New monitor or have to wake up */
595ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				fb_set_suspend(info, 0);
596ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			}
597ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
5983a41c5dbe8bc396a7fb16ca8739e945bb003342eGu Zheng
599ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			unlock_fb_info(info);
600ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		}
6013a41c5dbe8bc396a7fb16ca8739e945bb003342eGu Zheng		console_unlock();
602ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		break;
603ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
604ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	case SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT:
605ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		/* HDMI disconnect */
6063a41c5dbe8bc396a7fb16ca8739e945bb003342eGu Zheng		console_lock();
607ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		if (lock_fb_info(info)) {
608ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			fb_set_suspend(info, 1);
609ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			unlock_fb_info(info);
610ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		}
6113a41c5dbe8bc396a7fb16ca8739e945bb003342eGu Zheng		console_unlock();
612ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		break;
613ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
614ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	case SH_MOBILE_LCDC_EVENT_DISPLAY_MODE:
615ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		/* Validate a proposed new mode */
616e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart		fb_videomode_to_var(&var, mode);
617e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart		var.bits_per_pixel = info->var.bits_per_pixel;
618e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart		var.grayscale = info->var.grayscale;
619d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart		ret = sh_mobile_lcdc_check_var(&var, info);
620ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		break;
621ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	}
622ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
623ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	return ret;
624ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart}
625ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
626f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
627f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Format helpers
628f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
629f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
630105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchartstruct sh_mobile_lcdc_format_info {
631105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	u32 fourcc;
632105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	unsigned int bpp;
633105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	bool yuv;
634105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	u32 lddfr;
635105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart};
636105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart
637105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchartstatic const struct sh_mobile_lcdc_format_info sh_mobile_format_infos[] = {
638105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	{
639105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_RGB565,
640105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 16,
641105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = false,
642105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_PKF_RGB16,
643105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
644105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_BGR24,
645105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 24,
646105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = false,
647105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_PKF_RGB24,
648105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
649105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_BGR32,
650105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 32,
651105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = false,
652105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_PKF_ARGB32,
653105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
654105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_NV12,
655105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 12,
656105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = true,
657105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_CC | LDDFR_YF_420,
658105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
659105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_NV21,
660105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 12,
661105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = true,
662105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_CC | LDDFR_YF_420,
663105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
664105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_NV16,
665105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 16,
666105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = true,
667105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_CC | LDDFR_YF_422,
668105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
669105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_NV61,
670105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 16,
671105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = true,
672105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_CC | LDDFR_YF_422,
673105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
674105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_NV24,
675105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 24,
676105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = true,
677105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_CC | LDDFR_YF_444,
678105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
679105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_NV42,
680105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 24,
681105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = true,
682105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_CC | LDDFR_YF_444,
683105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	},
684105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart};
685105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart
686105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchartstatic const struct sh_mobile_lcdc_format_info *
687105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchartsh_mobile_format_info(u32 fourcc)
688105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart{
689105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	unsigned int i;
690105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart
691105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(sh_mobile_format_infos); ++i) {
692105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		if (sh_mobile_format_infos[i].fourcc == fourcc)
693105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart			return &sh_mobile_format_infos[i];
694105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}
695105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart
696105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	return NULL;
697105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart}
698105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart
699f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchartstatic int sh_mobile_format_fourcc(const struct fb_var_screeninfo *var)
700f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart{
701f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	if (var->grayscale > 1)
702f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return var->grayscale;
703f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
704f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	switch (var->bits_per_pixel) {
705f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case 16:
706f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return V4L2_PIX_FMT_RGB565;
707f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case 24:
708f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return V4L2_PIX_FMT_BGR24;
709f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case 32:
710f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return V4L2_PIX_FMT_BGR32;
711f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	default:
712f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return 0;
713f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
714f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart}
715f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
716f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchartstatic int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var)
717f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart{
718f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	return var->grayscale > 1;
719f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart}
720f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
721f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
722f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Start, stop and IRQ
723f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
724f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
7258564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
7268564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{
7278564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	struct sh_mobile_lcdc_priv *priv = data;
7282feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	struct sh_mobile_lcdc_chan *ch;
7299dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	unsigned long ldintr;
7302feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	int is_sub;
7312feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	int k;
7328564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
733dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart	/* Acknowledge interrupts and disable further VSYNC End IRQs. */
734dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart	ldintr = lcdc_read(priv, _LDINTR);
735dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart	lcdc_write(priv, _LDINTR, (ldintr ^ LDINTR_STATUS_MASK) & ~LDINTR_VEE);
7368564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
7372feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	/* figure out if this interrupt is for main or sub lcd */
738ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	is_sub = (lcdc_read(priv, _LDSR) & LDSR_MSS) ? 1 : 0;
7392feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
7409dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	/* wake up channel and disable clocks */
7412feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
7422feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		ch = &priv->ch[k];
7432feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
7442feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		if (!ch->enabled)
7452feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm			continue;
7462feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
747dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart		/* Frame End */
7489dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy		if (ldintr & LDINTR_FS) {
7499dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy			if (is_sub == lcdc_chan_is_sublcd(ch)) {
7509dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy				ch->frame_end = 1;
7519dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy				wake_up(&ch->frame_end_wait);
7522feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
7539dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy				sh_mobile_lcdc_clk_off(priv);
7549dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy			}
7559dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy		}
7569dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
7579dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy		/* VSYNC End */
75840331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy		if (ldintr & LDINTR_VES)
75940331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy			complete(&ch->vsync_completion);
7602feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	}
7612feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
7628564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	return IRQ_HANDLED;
7638564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
7648564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
765d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchartstatic int sh_mobile_lcdc_wait_for_vsync(struct sh_mobile_lcdc_chan *ch)
7664976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart{
7674976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	unsigned long ldintr;
7684976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	int ret;
7694976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart
7704976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	/* Enable VSync End interrupt and be careful not to acknowledge any
7714976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	 * pending interrupt.
7724976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	 */
7734976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	ldintr = lcdc_read(ch->lcdc, _LDINTR);
7744976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	ldintr |= LDINTR_VEE | LDINTR_STATUS_MASK;
7754976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	lcdc_write(ch->lcdc, _LDINTR, ldintr);
7764976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart
7774976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion,
7784976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart							msecs_to_jiffies(100));
7794976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	if (!ret)
7804976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart		return -ETIMEDOUT;
7814976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart
7824976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	return 0;
7834976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart}
7844976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart
785cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv,
786cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm				      int start)
787cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
788cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	unsigned long tmp = lcdc_read(priv, _LDCNT2R);
789cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	int k;
790cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
791cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	/* start or stop the lcdc */
792cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (start)
793ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart		lcdc_write(priv, _LDCNT2R, tmp | LDCNT2R_DO);
794cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	else
795ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart		lcdc_write(priv, _LDCNT2R, tmp & ~LDCNT2R_DO);
796cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
797cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	/* wait until power is applied/stopped on all channels */
798cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++)
799cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (lcdc_read(priv, _LDCNT2R) & priv->ch[k].enabled)
800cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			while (1) {
801ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart				tmp = lcdc_read_chan(&priv->ch[k], LDPMR)
802ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart				    & LDPMR_LPS;
803ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart				if (start && tmp == LDPMR_LPS)
804cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm					break;
805cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm				if (!start && tmp == 0)
806cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm					break;
807cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm				cpu_relax();
808cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			}
809cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
810cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (!start)
811cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		lcdc_write(priv, _LDDCKSTPR, 1); /* stop dotclock */
812cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
813cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
8146011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetskistatic void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
8156011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski{
8162d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	const struct fb_var_screeninfo *var = &ch->info->var;
8172d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	const struct fb_videomode *mode = &ch->display.mode;
8181c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski	unsigned long h_total, hsync_pos, display_h_total;
8196011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	u32 tmp;
8206011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
8216011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	tmp = ch->ldmt1r_value;
822ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	tmp |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : LDMT1R_VPOL;
823ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	tmp |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : LDMT1R_HPOL;
824b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	tmp |= (ch->cfg->flags & LCDC_FLAGS_DWPOL) ? LDMT1R_DWPOL : 0;
825b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	tmp |= (ch->cfg->flags & LCDC_FLAGS_DIPOL) ? LDMT1R_DIPOL : 0;
826b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	tmp |= (ch->cfg->flags & LCDC_FLAGS_DAPOL) ? LDMT1R_DAPOL : 0;
827b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	tmp |= (ch->cfg->flags & LCDC_FLAGS_HSCNT) ? LDMT1R_HSCNT : 0;
828b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	tmp |= (ch->cfg->flags & LCDC_FLAGS_DWCNT) ? LDMT1R_DWCNT : 0;
8296011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDMT1R, tmp);
8306011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
8316011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	/* setup SYS bus */
832b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	lcdc_write_chan(ch, LDMT2R, ch->cfg->sys_bus_cfg.ldmt2r);
833b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	lcdc_write_chan(ch, LDMT3R, ch->cfg->sys_bus_cfg.ldmt3r);
8346011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
8356011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	/* horizontal configuration */
8362d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	h_total = mode->xres + mode->hsync_len + mode->left_margin
8372d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart		+ mode->right_margin;
8386011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	tmp = h_total / 8; /* HTCN */
83958f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	tmp |= (min(mode->xres, ch->xres) / 8) << 16; /* HDCN */
8406011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDHCNR, tmp);
8416011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
8422d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	hsync_pos = mode->xres + mode->right_margin;
8436011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	tmp = hsync_pos / 8; /* HSYNP */
8442d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	tmp |= (mode->hsync_len / 8) << 16; /* HSYNW */
8456011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDHSYNR, tmp);
8466011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
8476011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	/* vertical configuration */
8482d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	tmp = mode->yres + mode->vsync_len + mode->upper_margin
8492d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	    + mode->lower_margin; /* VTLN */
85058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	tmp |= min(mode->yres, ch->yres) << 16; /* VDLN */
8516011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDVLNR, tmp);
8526011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
8532d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	tmp = mode->yres + mode->lower_margin; /* VSYNP */
8542d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	tmp |= mode->vsync_len << 16; /* VSYNW */
8556011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDVSYNR, tmp);
8566011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
8576011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	/* Adjust horizontal synchronisation for HDMI */
8582d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	display_h_total = mode->xres + mode->hsync_len + mode->left_margin
8592d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart			+ mode->right_margin;
8602d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	tmp = ((mode->xres & 7) << 24) | ((display_h_total & 7) << 16)
8612d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	    | ((mode->hsync_len & 7) << 8) | (hsync_pos & 7);
8626011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDHAJR, tmp);
8639beb09f1cadf33145c307c504f844ae24686c872Kuninori Morimoto	lcdc_write_chan_mirror(ch, LDHAJR, tmp);
8646011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski}
8656011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
866c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic void sh_mobile_lcdc_overlay_setup(struct sh_mobile_lcdc_overlay *ovl)
867c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
868c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	u32 format = 0;
869c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
870c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (!ovl->enabled) {
871c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index));
872c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		lcdc_write_overlay(ovl, LDBnBSIFR(ovl->index), 0);
873c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		lcdc_write(ovl->channel->lcdc, LDBCR,
874c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			   LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index));
875c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return;
876c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
877c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
878c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->base_addr_y = ovl->dma_handle;
879a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	ovl->base_addr_c = ovl->dma_handle
880a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart			 + ovl->xres_virtual * ovl->yres_virtual;
881c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
882c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	switch (ovl->mode) {
883c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case LCDC_OVERLAY_BLEND:
884c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format = LDBBSIFR_EN | (ovl->alpha << LDBBSIFR_LAY_SHIFT);
885c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
886c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
887c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case LCDC_OVERLAY_ROP3:
888c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format = LDBBSIFR_EN | LDBBSIFR_BRSEL
889c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		       | (ovl->rop3 << LDBBSIFR_ROP3_SHIFT);
890c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
891c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
892c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
893c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	switch (ovl->format->fourcc) {
894c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_RGB565:
895c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV21:
896c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV61:
897c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV42:
898c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW;
899c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
900c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_BGR24:
901c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV12:
902c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV16:
903c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV24:
904c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW | LDBBSIFR_SWPB;
905c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
906c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_BGR32:
907c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	default:
908c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format |= LDBBSIFR_SWPL;
909c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
910c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
911c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
912c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	switch (ovl->format->fourcc) {
913c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_RGB565:
914c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB16;
915c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
916c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_BGR24:
917c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB24;
918c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
919c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_BGR32:
920c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format |= LDBBSIFR_AL_PK | LDBBSIFR_RY | LDDFR_PKF_ARGB32;
921c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
922c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV12:
923c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV21:
924c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_420;
925c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
926c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV16:
927c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV61:
928c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_422;
929c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
930c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV24:
931c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV42:
932c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_444;
933c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
934c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
935c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
936c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index));
937c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
938c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write_overlay(ovl, LDBnBSIFR(ovl->index), format);
939c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
940c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write_overlay(ovl, LDBnBSSZR(ovl->index),
941c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		(ovl->yres << LDBBSSZR_BVSS_SHIFT) |
942c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		(ovl->xres << LDBBSSZR_BHSS_SHIFT));
943c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write_overlay(ovl, LDBnBLOCR(ovl->index),
944c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		(ovl->pos_y << LDBBLOCR_CVLC_SHIFT) |
945c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		(ovl->pos_x << LDBBLOCR_CHLC_SHIFT));
946c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write_overlay(ovl, LDBnBSMWR(ovl->index),
947c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->pitch << LDBBSMWR_BSMW_SHIFT);
948c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
949c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write_overlay(ovl, LDBnBSAYR(ovl->index), ovl->base_addr_y);
950c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write_overlay(ovl, LDBnBSACR(ovl->index), ovl->base_addr_c);
951c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
952c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write(ovl->channel->lcdc, LDBCR,
953c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		   LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index));
954c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
955c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
9569a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart/*
957d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart * __sh_mobile_lcdc_start - Configure and start the LCDC
9589a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart * @priv: LCDC device
9599a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart *
9609a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart * Configure all enabled channels and start the LCDC device. All external
9619a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart * devices (clocks, MERAM, panels, ...) are not touched by this function.
9629a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart */
9639a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchartstatic void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
964cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
965cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	struct sh_mobile_lcdc_chan *ch;
966cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	unsigned long tmp;
9679a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	int k, m;
9688564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
9699a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Enable LCDC channels. Read data from external memory, avoid using the
9709a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	 * BEU for now.
9719a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	 */
9729a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_write(priv, _LDCNT2R, priv->ch[0].enabled | priv->ch[1].enabled);
973cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
9749a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Stop the LCDC first and disable all interrupts. */
975cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	sh_mobile_lcdc_start_stop(priv, 0);
9769a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_write(priv, _LDINTR, 0);
977cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
9789a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Configure power supply, dot clocks and start them. */
979cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	tmp = priv->lddckr;
980cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
981cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		ch = &priv->ch[k];
9829a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (!ch->enabled)
983cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			continue;
984cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
9859a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		/* Power supply */
9869a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		lcdc_write_chan(ch, LDPMR, 0);
9879a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
988b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		m = ch->cfg->clock_divider;
989cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (!m)
990cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			continue;
991cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
992505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart		/* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider
993505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart		 * denominator.
994505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart		 */
995505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart		lcdc_write_chan(ch, LDDCKPAT1R, 0);
996505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart		lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1);
997505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart
998cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (m == 1)
999ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart			m = LDDCKR_MOSEL;
1000cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0);
1001cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
1002cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1003cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	lcdc_write(priv, _LDDCKR, tmp);
1004cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	lcdc_write(priv, _LDDCKSTPR, 0);
1005cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0);
1006cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
10079a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Setup geometry, format, frame buffer memory and operation mode. */
1008cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
1009cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		ch = &priv->ch[k];
1010cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (!ch->enabled)
1011cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			continue;
1012cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
10136011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski		sh_mobile_lcdc_geometry(ch);
1014cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1015fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart		tmp = ch->format->lddfr;
1016edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart
1017fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart		if (ch->format->yuv) {
101858f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart			switch (ch->colorspace) {
1019edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			case V4L2_COLORSPACE_REC709:
1020edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart				tmp |= LDDFR_CF1;
102153b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia				break;
1022edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			case V4L2_COLORSPACE_JPEG:
1023edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart				tmp |= LDDFR_CF0;
102453b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia				break;
102553b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia			}
1026417d48274e755e537bae60461558c1f63a4e14deMagnus Damm		}
10277caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
10289a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		lcdc_write_chan(ch, LDDFR, tmp);
102972c04af9a2d57b7945cf3de8e71461bd80695d50Laurent Pinchart		lcdc_write_chan(ch, LDMLSR, ch->line_size);
10309a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		lcdc_write_chan(ch, LDSA1R, ch->base_addr_y);
1031fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart		if (ch->format->yuv)
10329a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			lcdc_write_chan(ch, LDSA2R, ch->base_addr_c);
10337caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
10349a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		/* When using deferred I/O mode, configure the LCDC for one-shot
10359a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		 * operation and enable the frame end interrupt. Otherwise use
10369a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		 * continuous read mode.
10379a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		 */
10389a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (ch->ldmt1r_value & LDMT1R_IFM &&
1039b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		    ch->cfg->sys_bus_cfg.deferred_io_msec) {
10409a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			lcdc_write_chan(ch, LDSM1R, LDSM1R_OS);
10419a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			lcdc_write(priv, _LDINTR, LDINTR_FE);
10429a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		} else {
10439a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			lcdc_write_chan(ch, LDSM1R, 0);
10449a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		}
10459a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	}
10467caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
10479a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Word and long word swap. */
1048fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart	switch (priv->ch[0].format->fourcc) {
1049edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_RGB565:
1050edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV21:
1051edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV61:
1052edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV42:
1053edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		tmp = LDDDSR_LS | LDDDSR_WS;
1054edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		break;
1055edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_BGR24:
1056edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV12:
1057edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV16:
1058edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV24:
10599a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;
1060edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		break;
1061edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_BGR32:
1062edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	default:
1063edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		tmp = LDDDSR_LS;
1064edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		break;
10659a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	}
10669a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_write(priv, _LDDDSR, tmp);
10677caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
10689a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Enable the display output. */
10699a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_write(priv, _LDCNT1R, LDCNT1R_DE);
10709a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	sh_mobile_lcdc_start_stop(priv, 1);
10719a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	priv->started = 1;
10729a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart}
1073cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
10749a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchartstatic int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
10759a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart{
10769a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	struct sh_mobile_meram_info *mdev = priv->meram_dev;
10779a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	struct sh_mobile_lcdc_chan *ch;
10789a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	unsigned long tmp;
10799a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	int ret;
10809a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	int k;
1081cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
10829a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* enable clocks before accessing the hardware */
10839a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
10849a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (priv->ch[k].enabled)
10859a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			sh_mobile_lcdc_clk_on(priv);
10869a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	}
10878564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
10889a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* reset */
10899a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LDCNT2R_BR);
10909a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_wait_bit(priv, _LDCNT2R, LDCNT2R_BR, 0);
10918564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
10929a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
1093b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		const struct sh_mobile_lcdc_panel_cfg *panel;
10948564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
109537c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		ch = &priv->ch[k];
10969a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (!ch->enabled)
10979a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			continue;
10989a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
1099b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		panel = &ch->cfg->panel_cfg;
1100afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart		if (panel->setup_sys) {
1101afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart			ret = panel->setup_sys(ch, &sh_mobile_lcdc_sys_bus_ops);
11029a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			if (ret)
11039a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart				return ret;
11048564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		}
1105cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
1106cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
11079a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Compute frame buffer base address and pitch for each channel. */
11089a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
11099a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		int pixelformat;
11104a2371772146b30113c9c837eb32b64f18376c0dLaurent Pinchart		void *cache;
1111cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
11129a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		ch = &priv->ch[k];
11139a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (!ch->enabled)
11149a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			continue;
1115cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
111658f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		ch->base_addr_y = ch->dma_handle;
1117a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		ch->base_addr_c = ch->dma_handle
1118a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart				+ ch->xres_virtual * ch->yres_virtual;
111972c04af9a2d57b7945cf3de8e71461bd80695d50Laurent Pinchart		ch->line_size = ch->pitch;
11209a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
11219a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		/* Enable MERAM if possible. */
11226e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart		if (mdev == NULL || ch->cfg->meram_cfg == NULL)
11239a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			continue;
11249a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
11254a2371772146b30113c9c837eb32b64f18376c0dLaurent Pinchart		/* Free the allocated MERAM cache. */
11264a2371772146b30113c9c837eb32b64f18376c0dLaurent Pinchart		if (ch->cache) {
11276e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart			sh_mobile_meram_cache_free(mdev, ch->cache);
11284a2371772146b30113c9c837eb32b64f18376c0dLaurent Pinchart			ch->cache = NULL;
11299a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		}
11309a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
1131fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart		switch (ch->format->fourcc) {
1132edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV12:
1133edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV21:
1134edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV16:
1135edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV61:
11369a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			pixelformat = SH_MOBILE_MERAM_PF_NV;
1137edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			break;
1138edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV24:
1139edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV42:
1140edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			pixelformat = SH_MOBILE_MERAM_PF_NV24;
1141edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			break;
1142edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_RGB565:
1143edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_BGR24:
1144edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_BGR32:
1145edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		default:
1146edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			pixelformat = SH_MOBILE_MERAM_PF_RGB;
1147edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			break;
1148edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		}
11499a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
11506e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart		cache = sh_mobile_meram_cache_alloc(mdev, ch->cfg->meram_cfg,
1151b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart					ch->pitch, ch->yres, pixelformat,
115272c04af9a2d57b7945cf3de8e71461bd80695d50Laurent Pinchart					&ch->line_size);
11534a2371772146b30113c9c837eb32b64f18376c0dLaurent Pinchart		if (!IS_ERR(cache)) {
11546e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart			sh_mobile_meram_cache_update(mdev, cache,
115597d16fe69b6499a14a0c85c053f7bef54ce992a4Laurent Pinchart					ch->base_addr_y, ch->base_addr_c,
115697d16fe69b6499a14a0c85c053f7bef54ce992a4Laurent Pinchart					&ch->base_addr_y, &ch->base_addr_c);
11574a2371772146b30113c9c837eb32b64f18376c0dLaurent Pinchart			ch->cache = cache;
115897d16fe69b6499a14a0c85c053f7bef54ce992a4Laurent Pinchart		}
11599a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	}
11609a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
1161c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	for (k = 0; k < ARRAY_SIZE(priv->overlays); ++k) {
1162c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[k];
1163c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		sh_mobile_lcdc_overlay_setup(ovl);
1164c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1165c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
11669a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Start the LCDC. */
11679a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	__sh_mobile_lcdc_start(priv);
11689a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
11699a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Setup deferred I/O, tell the board code to enable the panels, and
11709a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	 * turn backlight on.
11719a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	 */
1172cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
1173cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		ch = &priv->ch[k];
117421bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm		if (!ch->enabled)
117521bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm			continue;
117621bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm
1177b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		tmp = ch->cfg->sys_bus_cfg.deferred_io_msec;
11789a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (ch->ldmt1r_value & LDMT1R_IFM && tmp) {
11799a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			ch->defio.deferred_io = sh_mobile_lcdc_deferred_io;
11809a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			ch->defio.delay = msecs_to_jiffies(tmp);
11819a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			ch->info->fbdefio = &ch->defio;
11829a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			fb_deferred_io_init(ch->info);
11839a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		}
11849a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
118537c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		sh_mobile_lcdc_display_on(ch);
11863b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
11873b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		if (ch->bl) {
11883b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot			ch->bl->props.power = FB_BLANK_UNBLANK;
11893b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot			backlight_update_status(ch->bl);
11903b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		}
1191cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
1192cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1193cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	return 0;
1194cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
1195cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1196cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
1197cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
1198cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	struct sh_mobile_lcdc_chan *ch;
1199cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	int k;
1200cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
12012feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	/* clean up deferred io and ask board code to disable panel */
1202cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
1203cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		ch = &priv->ch[k];
120421bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm		if (!ch->enabled)
120521bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm			continue;
12068564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
12072feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		/* deferred io mode:
12082feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		 * flush frame, and wait for frame end interrupt
12092feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		 * clean up deferred io and enable clock
12102feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		 */
12115ef6b505d9df45558402bdb823a078840a6a26c4Guennadi Liakhovetski		if (ch->info && ch->info->fbdefio) {
12122feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm			ch->frame_end = 0;
1213e33afddca174171a68d57476ead8947476ab9240Paul Mundt			schedule_delayed_work(&ch->info->deferred_work, 0);
12142feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm			wait_event(ch->frame_end_wait, ch->frame_end);
1215e33afddca174171a68d57476ead8947476ab9240Paul Mundt			fb_deferred_io_cleanup(ch->info);
1216e33afddca174171a68d57476ead8947476ab9240Paul Mundt			ch->info->fbdefio = NULL;
12172feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm			sh_mobile_lcdc_clk_on(priv);
12188564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		}
12192feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
12203b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		if (ch->bl) {
12213b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot			ch->bl->props.power = FB_BLANK_POWERDOWN;
12223b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot			backlight_update_status(ch->bl);
12233b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		}
12243b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
122537c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		sh_mobile_lcdc_display_off(ch);
12267caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
12274a2371772146b30113c9c837eb32b64f18376c0dLaurent Pinchart		/* Free the MERAM cache. */
12284a2371772146b30113c9c837eb32b64f18376c0dLaurent Pinchart		if (ch->cache) {
12296e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart			sh_mobile_meram_cache_free(priv->meram_dev, ch->cache);
123040af1eb5a73c16fc8270d45b8c37e3c75f107eb4Laurent Pinchart			ch->cache = NULL;
12317caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia		}
12327caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
1233cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
1234cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1235cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	/* stop the lcdc */
12368e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm	if (priv->started) {
12378e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm		sh_mobile_lcdc_start_stop(priv, 0);
12388e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm		priv->started = 0;
12398e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm	}
1240b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm
12418564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	/* stop clocks */
12428564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++)
12438564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		if (priv->ch[k].enabled)
12448564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm			sh_mobile_lcdc_clk_off(priv);
1245cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
1246cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1247c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic int __sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var,
1248c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart				      struct fb_info *info)
1249c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1250c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (var->xres > MAX_XRES || var->yres > MAX_YRES)
1251c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1252c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1253c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Make sure the virtual resolution is at least as big as the visible
1254c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 * resolution.
1255c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 */
1256c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (var->xres_virtual < var->xres)
1257c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		var->xres_virtual = var->xres;
1258c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (var->yres_virtual < var->yres)
1259c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		var->yres_virtual = var->yres;
1260c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1261c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (sh_mobile_format_is_fourcc(var)) {
1262c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		const struct sh_mobile_lcdc_format_info *format;
1263c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1264c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format = sh_mobile_format_info(var->grayscale);
1265c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (format == NULL)
1266c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			return -EINVAL;
1267c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		var->bits_per_pixel = format->bpp;
1268c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1269c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		/* Default to RGB and JPEG color-spaces for RGB and YUV formats
1270c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		 * respectively.
1271c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		 */
1272c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (!format->yuv)
1273c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->colorspace = V4L2_COLORSPACE_SRGB;
1274c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		else if (var->colorspace != V4L2_COLORSPACE_REC709)
1275c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->colorspace = V4L2_COLORSPACE_JPEG;
1276c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	} else {
1277c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (var->bits_per_pixel <= 16) {		/* RGB 565 */
1278c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->bits_per_pixel = 16;
1279c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->red.offset = 11;
1280c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->red.length = 5;
1281c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->green.offset = 5;
1282c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->green.length = 6;
1283c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->blue.offset = 0;
1284c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->blue.length = 5;
1285c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->transp.offset = 0;
1286c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->transp.length = 0;
1287c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		} else if (var->bits_per_pixel <= 24) {		/* RGB 888 */
1288c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->bits_per_pixel = 24;
1289c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->red.offset = 16;
1290c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->red.length = 8;
1291c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->green.offset = 8;
1292c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->green.length = 8;
1293c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->blue.offset = 0;
1294c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->blue.length = 8;
1295c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->transp.offset = 0;
1296c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->transp.length = 0;
1297c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		} else if (var->bits_per_pixel <= 32) {		/* RGBA 888 */
1298c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->bits_per_pixel = 32;
1299c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->red.offset = 16;
1300c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->red.length = 8;
1301c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->green.offset = 8;
1302c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->green.length = 8;
1303c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->blue.offset = 0;
1304c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->blue.length = 8;
1305c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->transp.offset = 24;
1306c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->transp.length = 8;
1307c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		} else
1308c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			return -EINVAL;
1309c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1310c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		var->red.msb_right = 0;
1311c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		var->green.msb_right = 0;
1312c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		var->blue.msb_right = 0;
1313c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		var->transp.msb_right = 0;
1314c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1315c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1316c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Make sure we don't exceed our allocated memory. */
1317c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 >
1318c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	    info->fix.smem_len)
1319c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1320c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1321c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return 0;
1322c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1323c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1324c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart/* -----------------------------------------------------------------------------
1325c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * Frame buffer operations - Overlays
1326c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart */
1327c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1328c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic ssize_t
1329c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartoverlay_alpha_show(struct device *dev, struct device_attribute *attr, char *buf)
1330c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1331c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = dev_get_drvdata(dev);
1332c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1333c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1334c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return scnprintf(buf, PAGE_SIZE, "%u\n", ovl->alpha);
1335c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1336c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1337c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic ssize_t
1338c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartoverlay_alpha_store(struct device *dev, struct device_attribute *attr,
1339c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		    const char *buf, size_t count)
1340c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1341c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = dev_get_drvdata(dev);
1342c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1343c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned int alpha;
1344c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	char *endp;
1345c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1346c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	alpha = simple_strtoul(buf, &endp, 10);
1347c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (isspace(*endp))
1348c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		endp++;
1349c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1350c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (endp - buf != count)
1351c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1352c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1353c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (alpha > 255)
1354c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1355c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1356c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ovl->alpha != alpha) {
1357c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->alpha = alpha;
1358c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1359c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (ovl->mode == LCDC_OVERLAY_BLEND && ovl->enabled)
1360c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			sh_mobile_lcdc_overlay_setup(ovl);
1361c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1362c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1363c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return count;
1364c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1365c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1366c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic ssize_t
1367c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartoverlay_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
1368c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1369c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = dev_get_drvdata(dev);
1370c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1371c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1372c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return scnprintf(buf, PAGE_SIZE, "%u\n", ovl->mode);
1373c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1374c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1375c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic ssize_t
1376c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartoverlay_mode_store(struct device *dev, struct device_attribute *attr,
1377c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		   const char *buf, size_t count)
1378c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1379c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = dev_get_drvdata(dev);
1380c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1381c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned int mode;
1382c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	char *endp;
1383c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1384c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	mode = simple_strtoul(buf, &endp, 10);
1385c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (isspace(*endp))
1386c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		endp++;
1387c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1388c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (endp - buf != count)
1389c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1390c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1391c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (mode != LCDC_OVERLAY_BLEND && mode != LCDC_OVERLAY_ROP3)
1392c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1393c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1394c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ovl->mode != mode) {
1395c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->mode = mode;
1396c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1397c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (ovl->enabled)
1398c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			sh_mobile_lcdc_overlay_setup(ovl);
1399c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1400c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1401c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return count;
1402c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1403c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1404c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic ssize_t
1405c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartoverlay_position_show(struct device *dev, struct device_attribute *attr,
1406c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		      char *buf)
1407c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1408c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = dev_get_drvdata(dev);
1409c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1410c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1411c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return scnprintf(buf, PAGE_SIZE, "%d,%d\n", ovl->pos_x, ovl->pos_y);
1412c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1413c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1414c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic ssize_t
1415c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartoverlay_position_store(struct device *dev, struct device_attribute *attr,
1416c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		       const char *buf, size_t count)
1417c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1418c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = dev_get_drvdata(dev);
1419c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1420c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	char *endp;
1421c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	int pos_x;
1422c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	int pos_y;
1423c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1424c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	pos_x = simple_strtol(buf, &endp, 10);
1425c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (*endp != ',')
1426c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1427c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1428c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	pos_y = simple_strtol(endp + 1, &endp, 10);
1429c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (isspace(*endp))
1430c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		endp++;
1431c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1432c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (endp - buf != count)
1433c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1434c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1435c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ovl->pos_x != pos_x || ovl->pos_y != pos_y) {
1436c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->pos_x = pos_x;
1437c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->pos_y = pos_y;
1438c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1439c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (ovl->enabled)
1440c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			sh_mobile_lcdc_overlay_setup(ovl);
1441c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1442c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1443c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return count;
1444c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1445c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1446c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic ssize_t
1447c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartoverlay_rop3_show(struct device *dev, struct device_attribute *attr, char *buf)
1448c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1449c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = dev_get_drvdata(dev);
1450c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1451c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1452c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return scnprintf(buf, PAGE_SIZE, "%u\n", ovl->rop3);
1453c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1454c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1455c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic ssize_t
1456c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartoverlay_rop3_store(struct device *dev, struct device_attribute *attr,
1457c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		    const char *buf, size_t count)
1458c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1459c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = dev_get_drvdata(dev);
1460c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1461c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned int rop3;
1462c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	char *endp;
1463c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1464c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	rop3 = !!simple_strtoul(buf, &endp, 10);
1465c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (isspace(*endp))
1466c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		endp++;
1467c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1468c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (endp - buf != count)
1469c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1470c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1471c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (rop3 > 255)
1472c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1473c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1474c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ovl->rop3 != rop3) {
1475c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->rop3 = rop3;
1476c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1477c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (ovl->mode == LCDC_OVERLAY_ROP3 && ovl->enabled)
1478c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			sh_mobile_lcdc_overlay_setup(ovl);
1479c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1480c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1481c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return count;
1482c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1483c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1484c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic const struct device_attribute overlay_sysfs_attrs[] = {
1485c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	__ATTR(ovl_alpha, S_IRUGO|S_IWUSR,
1486c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	       overlay_alpha_show, overlay_alpha_store),
1487c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	__ATTR(ovl_mode, S_IRUGO|S_IWUSR,
1488c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	       overlay_mode_show, overlay_mode_store),
1489c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	__ATTR(ovl_position, S_IRUGO|S_IWUSR,
1490c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	       overlay_position_show, overlay_position_store),
1491c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	__ATTR(ovl_rop3, S_IRUGO|S_IWUSR,
1492c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	       overlay_rop3_show, overlay_rop3_store),
1493c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart};
1494c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1495c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic const struct fb_fix_screeninfo sh_mobile_lcdc_overlay_fix  = {
1496c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.id =		"SH Mobile LCDC",
1497c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.type =		FB_TYPE_PACKED_PIXELS,
1498c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.visual =	FB_VISUAL_TRUECOLOR,
1499c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.accel =	FB_ACCEL_NONE,
150015dede882e564601947f2ce4b647742c0351be6dLaurent Pinchart	.xpanstep =	1,
1501c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.ypanstep =	1,
1502c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.ywrapstep =	0,
1503c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.capabilities =	FB_CAP_FOURCC,
1504c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart};
1505c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1506c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic int sh_mobile_lcdc_overlay_pan(struct fb_var_screeninfo *var,
1507c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart				    struct fb_info *info)
1508c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1509c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1510c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned long base_addr_y;
1511c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned long base_addr_c;
1512a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	unsigned long y_offset;
1513c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned long c_offset;
1514c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1515a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	if (!ovl->format->yuv) {
1516a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		y_offset = (var->yoffset * ovl->xres_virtual + var->xoffset)
1517a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart			 * ovl->format->bpp / 8;
1518a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		c_offset = 0;
1519a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	} else {
1520a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		unsigned int xsub = ovl->format->bpp < 24 ? 2 : 1;
1521a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		unsigned int ysub = ovl->format->bpp < 16 ? 2 : 1;
1522a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart
1523a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		y_offset = var->yoffset * ovl->xres_virtual + var->xoffset;
1524a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		c_offset = var->yoffset / ysub * ovl->xres_virtual * 2 / xsub
1525a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart			 + var->xoffset * 2 / xsub;
1526a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	}
1527c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1528a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	/* If the Y offset hasn't changed, the C offset hasn't either. There's
1529a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	 * nothing to do in that case.
1530a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	 */
1531a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	if (y_offset == ovl->pan_y_offset)
1532a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		return 0;
1533c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1534c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Set the source address for the next refresh */
1535a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	base_addr_y = ovl->dma_handle + y_offset;
1536a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	base_addr_c = ovl->dma_handle + ovl->xres_virtual * ovl->yres_virtual
1537a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		    + c_offset;
1538c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1539c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->base_addr_y = base_addr_y;
1540a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	ovl->base_addr_c = base_addr_c;
1541a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	ovl->pan_y_offset = y_offset;
1542c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
15438be7c66995bf06769dc4c5f7a62f3cd62a627e7eLaurent Pinchart	lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index));
15448be7c66995bf06769dc4c5f7a62f3cd62a627e7eLaurent Pinchart
1545c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write_overlay(ovl, LDBnBSAYR(ovl->index), ovl->base_addr_y);
1546c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write_overlay(ovl, LDBnBSACR(ovl->index), ovl->base_addr_c);
1547c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
15488be7c66995bf06769dc4c5f7a62f3cd62a627e7eLaurent Pinchart	lcdc_write(ovl->channel->lcdc, LDBCR,
15498be7c66995bf06769dc4c5f7a62f3cd62a627e7eLaurent Pinchart		   LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index));
15508be7c66995bf06769dc4c5f7a62f3cd62a627e7eLaurent Pinchart
1551c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return 0;
1552c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1553c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1554c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic int sh_mobile_lcdc_overlay_ioctl(struct fb_info *info, unsigned int cmd,
1555c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart				      unsigned long arg)
1556c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1557c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1558c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1559c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	switch (cmd) {
1560c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case FBIO_WAITFORVSYNC:
1561c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return sh_mobile_lcdc_wait_for_vsync(ovl->channel);
1562c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1563c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	default:
1564c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -ENOIOCTLCMD;
1565c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1566c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1567c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1568c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic int sh_mobile_lcdc_overlay_check_var(struct fb_var_screeninfo *var,
1569c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart					  struct fb_info *info)
1570c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1571c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return __sh_mobile_lcdc_check_var(var, info);
1572c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1573c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1574c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic int sh_mobile_lcdc_overlay_set_par(struct fb_info *info)
1575c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1576c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1577c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1578c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->format =
1579c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		sh_mobile_format_info(sh_mobile_format_fourcc(&info->var));
1580c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1581c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->xres = info->var.xres;
1582c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->xres_virtual = info->var.xres_virtual;
1583c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->yres = info->var.yres;
1584c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->yres_virtual = info->var.yres_virtual;
1585c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1586c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ovl->format->yuv)
158716ca21c9a9f64577221c47d8d2f00d13b880aefaLaurent Pinchart		ovl->pitch = info->var.xres_virtual;
1588c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	else
158916ca21c9a9f64577221c47d8d2f00d13b880aefaLaurent Pinchart		ovl->pitch = info->var.xres_virtual * ovl->format->bpp / 8;
1590c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1591c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	sh_mobile_lcdc_overlay_setup(ovl);
1592c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1593c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->fix.line_length = ovl->pitch;
1594c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1595c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (sh_mobile_format_is_fourcc(&info->var)) {
1596c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		info->fix.type = FB_TYPE_FOURCC;
1597c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		info->fix.visual = FB_VISUAL_FOURCC;
1598c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	} else {
1599c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		info->fix.type = FB_TYPE_PACKED_PIXELS;
1600c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		info->fix.visual = FB_VISUAL_TRUECOLOR;
1601c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1602c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1603c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return 0;
1604c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1605c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1606c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart/* Overlay blanking. Disable the overlay when blanked. */
1607c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic int sh_mobile_lcdc_overlay_blank(int blank, struct fb_info *info)
1608c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1609c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1610c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1611c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->enabled = !blank;
1612c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	sh_mobile_lcdc_overlay_setup(ovl);
1613c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1614c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Prevent the backlight from receiving a blanking event by returning
1615c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 * a non-zero value.
1616c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 */
1617c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return 1;
1618c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1619c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1620bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKUstatic int
1621bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKUsh_mobile_lcdc_overlay_mmap(struct fb_info *info, struct vm_area_struct *vma)
1622bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU{
1623bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU	struct sh_mobile_lcdc_overlay *ovl = info->par;
1624bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU
1625bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU	return dma_mmap_coherent(ovl->channel->lcdc->dev, vma, ovl->fb_mem,
1626bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU				 ovl->dma_handle, ovl->fb_size);
1627bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU}
1628bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU
1629c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic struct fb_ops sh_mobile_lcdc_overlay_ops = {
1630c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.owner          = THIS_MODULE,
1631c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_read        = fb_sys_read,
1632c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_write       = fb_sys_write,
1633c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_fillrect	= sys_fillrect,
1634c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_copyarea	= sys_copyarea,
1635c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_imageblit	= sys_imageblit,
1636c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_blank	= sh_mobile_lcdc_overlay_blank,
1637c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_pan_display = sh_mobile_lcdc_overlay_pan,
1638c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_ioctl       = sh_mobile_lcdc_overlay_ioctl,
1639c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_check_var	= sh_mobile_lcdc_overlay_check_var,
1640c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_set_par	= sh_mobile_lcdc_overlay_set_par,
1641bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU	.fb_mmap	= sh_mobile_lcdc_overlay_mmap,
1642c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart};
1643c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1644c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic void
1645c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartsh_mobile_lcdc_overlay_fb_unregister(struct sh_mobile_lcdc_overlay *ovl)
1646c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1647c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = ovl->info;
1648c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1649c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (info == NULL || info->dev == NULL)
1650c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return;
1651c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1652c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unregister_framebuffer(ovl->info);
1653c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1654c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
165548c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartmanstatic int
1656c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartsh_mobile_lcdc_overlay_fb_register(struct sh_mobile_lcdc_overlay *ovl)
1657c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1658c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_priv *lcdc = ovl->channel->lcdc;
1659c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = ovl->info;
1660c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned int i;
1661c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	int ret;
1662c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1663c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (info == NULL)
1664c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return 0;
1665c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1666c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ret = register_framebuffer(info);
1667c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ret < 0)
1668c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return ret;
1669c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1670c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	dev_info(lcdc->dev, "registered %s/overlay %u as %dx%d %dbpp.\n",
1671c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		 dev_name(lcdc->dev), ovl->index, info->var.xres,
1672c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		 info->var.yres, info->var.bits_per_pixel);
1673c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1674c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(overlay_sysfs_attrs); ++i) {
1675c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ret = device_create_file(info->dev, &overlay_sysfs_attrs[i]);
1676c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (ret < 0)
1677c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			return ret;
1678c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1679c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1680c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return 0;
1681c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1682c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1683c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic void
1684c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartsh_mobile_lcdc_overlay_fb_cleanup(struct sh_mobile_lcdc_overlay *ovl)
1685c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1686c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = ovl->info;
1687c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1688c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (info == NULL || info->device == NULL)
1689c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return;
1690c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1691c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	framebuffer_release(info);
1692c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1693c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
169448c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartmanstatic int
1695c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartsh_mobile_lcdc_overlay_fb_init(struct sh_mobile_lcdc_overlay *ovl)
1696c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1697c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_priv *priv = ovl->channel->lcdc;
1698c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_var_screeninfo *var;
1699c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info;
1700c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1701c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Allocate and initialize the frame buffer device. */
1702c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info = framebuffer_alloc(0, priv->dev);
1703c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (info == NULL) {
1704c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		dev_err(priv->dev, "unable to allocate fb_info\n");
1705c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -ENOMEM;
1706c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1707c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1708c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->info = info;
1709c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1710c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->flags = FBINFO_FLAG_DEFAULT;
1711c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->fbops = &sh_mobile_lcdc_overlay_ops;
1712c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->device = priv->dev;
1713c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->screen_base = ovl->fb_mem;
1714c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->par = ovl;
1715c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1716c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Initialize fixed screen information. Restrict pan to 2 lines steps
1717c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 * for NV12 and NV21.
1718c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 */
1719c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->fix = sh_mobile_lcdc_overlay_fix;
1720c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	snprintf(info->fix.id, sizeof(info->fix.id),
1721c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		 "SH Mobile LCDC Overlay %u", ovl->index);
1722c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->fix.smem_start = ovl->dma_handle;
1723c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->fix.smem_len = ovl->fb_size;
1724c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->fix.line_length = ovl->pitch;
1725c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1726c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ovl->format->yuv)
1727c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		info->fix.visual = FB_VISUAL_FOURCC;
1728c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	else
1729c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		info->fix.visual = FB_VISUAL_TRUECOLOR;
1730c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
173115dede882e564601947f2ce4b647742c0351be6dLaurent Pinchart	switch (ovl->format->fourcc) {
173215dede882e564601947f2ce4b647742c0351be6dLaurent Pinchart	case V4L2_PIX_FMT_NV12:
173315dede882e564601947f2ce4b647742c0351be6dLaurent Pinchart	case V4L2_PIX_FMT_NV21:
1734ac33a207b13a70bbca6e58094e28bd92b9fc1ff3Laurent Pinchart		info->fix.ypanstep = 2;
1735ac33a207b13a70bbca6e58094e28bd92b9fc1ff3Laurent Pinchart	case V4L2_PIX_FMT_NV16:
1736ac33a207b13a70bbca6e58094e28bd92b9fc1ff3Laurent Pinchart	case V4L2_PIX_FMT_NV61:
173715dede882e564601947f2ce4b647742c0351be6dLaurent Pinchart		info->fix.xpanstep = 2;
173815dede882e564601947f2ce4b647742c0351be6dLaurent Pinchart	}
1739c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1740c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Initialize variable screen information. */
1741c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	var = &info->var;
1742c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	memset(var, 0, sizeof(*var));
1743c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	var->xres = ovl->xres;
1744c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	var->yres = ovl->yres;
1745c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	var->xres_virtual = ovl->xres_virtual;
1746c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	var->yres_virtual = ovl->yres_virtual;
1747c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	var->activate = FB_ACTIVATE_NOW;
1748c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1749c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Use the legacy API by default for RGB formats, and the FOURCC API
1750c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 * for YUV formats.
1751c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 */
1752c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (!ovl->format->yuv)
1753c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		var->bits_per_pixel = ovl->format->bpp;
1754c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	else
1755c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		var->grayscale = ovl->format->fourcc;
1756c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1757c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return sh_mobile_lcdc_overlay_check_var(var, info);
1758c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1759c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1760f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
1761c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * Frame buffer operations - main frame buffer
1762f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
1763cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1764cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_setcolreg(u_int regno,
1765cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm				    u_int red, u_int green, u_int blue,
1766cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm				    u_int transp, struct fb_info *info)
1767cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
1768cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	u32 *palette = info->pseudo_palette;
1769cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1770cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (regno >= PALETTE_NR)
1771cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		return -EINVAL;
1772cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1773cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	/* only FB_VISUAL_TRUECOLOR supported */
1774cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1775cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	red >>= 16 - info->var.red.length;
1776cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	green >>= 16 - info->var.green.length;
1777cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	blue >>= 16 - info->var.blue.length;
1778cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	transp >>= 16 - info->var.transp.length;
1779cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1780cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	palette[regno] = (red << info->var.red.offset) |
1781cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	  (green << info->var.green.offset) |
1782cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	  (blue << info->var.blue.offset) |
1783cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	  (transp << info->var.transp.offset);
1784cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1785cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	return 0;
1786cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
1787cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
17883281e54c80195b90ed12a5b6cddef4ab42e656e1Laurent Pinchartstatic const struct fb_fix_screeninfo sh_mobile_lcdc_fix  = {
1789cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.id =		"SH Mobile LCDC",
1790cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.type =		FB_TYPE_PACKED_PIXELS,
1791cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.visual =	FB_VISUAL_TRUECOLOR,
1792cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.accel =	FB_ACCEL_NONE,
179315dede882e564601947f2ce4b647742c0351be6dLaurent Pinchart	.xpanstep =	1,
17949dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	.ypanstep =	1,
17959dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	.ywrapstep =	0,
1796edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	.capabilities =	FB_CAP_FOURCC,
1797cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm};
1798cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
17998564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_fillrect(struct fb_info *info,
18008564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm				    const struct fb_fillrect *rect)
18018564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{
18028564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sys_fillrect(info, rect);
18038564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sh_mobile_lcdc_deferred_io_touch(info);
18048564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
18058564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
18068564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_copyarea(struct fb_info *info,
18078564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm				    const struct fb_copyarea *area)
18088564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{
18098564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sys_copyarea(info, area);
18108564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sh_mobile_lcdc_deferred_io_touch(info);
18118564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
18128564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
18138564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_imageblit(struct fb_info *info,
18148564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm				     const struct fb_image *image)
18158564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{
18168564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sys_imageblit(info, image);
18178564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sh_mobile_lcdc_deferred_io_touch(info);
18188564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
18198564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
1820d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchartstatic int sh_mobile_lcdc_pan(struct fb_var_screeninfo *var,
1821d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart			      struct fb_info *info)
18229dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy{
18239dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	struct sh_mobile_lcdc_chan *ch = info->par;
182492e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	struct sh_mobile_lcdc_priv *priv = ch->lcdc;
182592e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	unsigned long ldrcntr;
1826a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	unsigned long base_addr_y, base_addr_c;
1827a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	unsigned long y_offset;
182853b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia	unsigned long c_offset;
182992e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy
1830a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	if (!ch->format->yuv) {
1831a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		y_offset = (var->yoffset * ch->xres_virtual + var->xoffset)
1832a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart			 * ch->format->bpp / 8;
1833a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		c_offset = 0;
1834a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	} else {
1835a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		unsigned int xsub = ch->format->bpp < 24 ? 2 : 1;
1836a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		unsigned int ysub = ch->format->bpp < 16 ? 2 : 1;
18379dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
1838a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		y_offset = var->yoffset * ch->xres_virtual + var->xoffset;
1839a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		c_offset = var->yoffset / ysub * ch->xres_virtual * 2 / xsub
1840a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart			 + var->xoffset * 2 / xsub;
1841a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	}
18429dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
1843a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	/* If the Y offset hasn't changed, the C offset hasn't either. There's
1844a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	 * nothing to do in that case.
1845a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	 */
1846a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	if (y_offset == ch->pan_y_offset)
1847a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		return 0;
18489dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
184992e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	/* Set the source address for the next refresh */
1850a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	base_addr_y = ch->dma_handle + y_offset;
1851a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	base_addr_c = ch->dma_handle + ch->xres_virtual * ch->yres_virtual
1852a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		    + c_offset;
185353b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia
18546e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart	if (ch->cache)
18556e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart		sh_mobile_meram_cache_update(priv->meram_dev, ch->cache,
18566e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart					     base_addr_y, base_addr_c,
18576e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart					     &base_addr_y, &base_addr_c);
18587caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
185949d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart	ch->base_addr_y = base_addr_y;
186049d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart	ch->base_addr_c = base_addr_c;
1861a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	ch->pan_y_offset = y_offset;
18627caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
186349d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart	lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);
186458f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	if (ch->format->yuv)
186549d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart		lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c);
186653b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia
1867a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	ldrcntr = lcdc_read(priv, _LDRCNTR);
186892e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	if (lcdc_chan_is_sublcd(ch))
186992e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy		lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS);
187092e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	else
187192e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy		lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_MRS);
187292e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy
187392e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy
187492e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	sh_mobile_lcdc_deferred_io_touch(info);
18759dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
18769dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	return 0;
18779dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy}
18789dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
1879d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchartstatic int sh_mobile_lcdc_ioctl(struct fb_info *info, unsigned int cmd,
1880d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart				unsigned long arg)
188140331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy{
1882d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart	struct sh_mobile_lcdc_chan *ch = info->par;
188340331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	int retval;
188440331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy
188540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	switch (cmd) {
188640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	case FBIO_WAITFORVSYNC:
1887d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart		retval = sh_mobile_lcdc_wait_for_vsync(ch);
188840331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy		break;
188940331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy
189040331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	default:
189140331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy		retval = -ENOIOCTLCMD;
189240331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy		break;
189340331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	}
189440331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	return retval;
189540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy}
189640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy
1897dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetskistatic void sh_mobile_fb_reconfig(struct fb_info *info)
1898dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{
1899dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	struct sh_mobile_lcdc_chan *ch = info->par;
19002d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	struct fb_var_screeninfo var;
19012d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	struct fb_videomode mode;
1902dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	struct fb_event event;
1903dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	int evnt = FB_EVENT_MODE_CHANGE_ALL;
1904dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1905dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	if (ch->use_count > 1 || (ch->use_count == 1 && !info->fbcon_par))
1906dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		/* More framebuffer users are active */
1907dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		return;
1908dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
19092d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	fb_var_to_videomode(&mode, &info->var);
1910dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
19112d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	if (fb_mode_is_equal(&ch->display.mode, &mode))
1912dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		return;
1913dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1914dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	/* Display has been re-plugged, framebuffer is free now, reconfigure */
19152d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	var = info->var;
19162d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	fb_videomode_to_var(&var, &ch->display.mode);
19172d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	var.width = ch->display.width;
19182d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	var.height = ch->display.height;
19192d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	var.activate = FB_ACTIVATE_NOW;
19202d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart
19212d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	if (fb_set_var(info, &var) < 0)
1922dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		/* Couldn't reconfigure, hopefully, can continue as before */
1923dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		return;
1924dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1925dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	/*
1926dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	 * fb_set_var() calls the notifier change internally, only if
1927dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	 * FBINFO_MISC_USEREVENT flag is set. Since we do not want to fake a
1928dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	 * user event, we have to call the chain ourselves.
1929dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	 */
1930dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	event.info = info;
19312d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	event.data = &ch->display.mode;
1932dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	fb_notifier_call_chain(evnt, &event);
1933dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski}
1934dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1935dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski/*
1936dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski * Locking: both .fb_release() and .fb_open() are called with info->lock held if
1937dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski * user == 1, or with console sem held, if user == 0.
1938dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski */
1939d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchartstatic int sh_mobile_lcdc_release(struct fb_info *info, int user)
1940dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{
1941dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	struct sh_mobile_lcdc_chan *ch = info->par;
1942dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1943dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	mutex_lock(&ch->open_lock);
1944dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count);
1945dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1946dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	ch->use_count--;
1947dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1948dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	/* Nothing to reconfigure, when called from fbcon */
1949dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	if (user) {
1950ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn		console_lock();
1951dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		sh_mobile_fb_reconfig(info);
1952ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn		console_unlock();
1953dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	}
1954dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1955dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	mutex_unlock(&ch->open_lock);
1956dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1957dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	return 0;
1958dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski}
1959dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1960d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchartstatic int sh_mobile_lcdc_open(struct fb_info *info, int user)
1961dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{
1962dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	struct sh_mobile_lcdc_chan *ch = info->par;
1963dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1964dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	mutex_lock(&ch->open_lock);
1965dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	ch->use_count++;
1966dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1967dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count);
1968dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	mutex_unlock(&ch->open_lock);
1969dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1970dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	return 0;
1971dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski}
1972dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1973d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchartstatic int sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var,
1974d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart				    struct fb_info *info)
1975dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{
1976dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	struct sh_mobile_lcdc_chan *ch = info->par;
1977417d48274e755e537bae60461558c1f63a4e14deMagnus Damm	struct sh_mobile_lcdc_priv *p = ch->lcdc;
19780386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	unsigned int best_dist = (unsigned int)-1;
19790386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	unsigned int best_xres = 0;
19800386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	unsigned int best_yres = 0;
19810386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	unsigned int i;
1982c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	int ret;
19830386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
19840386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	/* If board code provides us with a list of available modes, make sure
19850386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	 * we use one of them. Find the mode closest to the requested one. The
19860386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	 * distance between two modes is defined as the size of the
19870386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	 * non-overlapping parts of the two rectangles.
19880386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	 */
1989b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	for (i = 0; i < ch->cfg->num_modes; ++i) {
1990b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		const struct fb_videomode *mode = &ch->cfg->lcd_modes[i];
19910386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		unsigned int dist;
19920386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
19930386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		/* We can only round up. */
19940386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		if (var->xres > mode->xres || var->yres > mode->yres)
19950386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			continue;
19960386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
19970386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		dist = var->xres * var->yres + mode->xres * mode->yres
19980386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		     - 2 * min(var->xres, mode->xres)
19990386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			 * min(var->yres, mode->yres);
20000386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
20010386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		if (dist < best_dist) {
20020386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			best_xres = mode->xres;
20030386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			best_yres = mode->yres;
20040386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			best_dist = dist;
20050386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		}
2006dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	}
2007417d48274e755e537bae60461558c1f63a4e14deMagnus Damm
20080386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	/* If no available mode can be used, return an error. */
2009b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	if (ch->cfg->num_modes != 0) {
20100386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		if (best_dist == (unsigned int)-1)
20110386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			return -EINVAL;
20120386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
20130386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		var->xres = best_xres;
20140386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		var->yres = best_yres;
20150386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	}
20160386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
2017c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ret = __sh_mobile_lcdc_check_var(var, info);
2018c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ret < 0)
2019c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return ret;
20200386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
2021edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	/* only accept the forced_fourcc for dual channel configurations */
2022edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	if (p->forced_fourcc &&
2023edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	    p->forced_fourcc != sh_mobile_format_fourcc(var))
2024417d48274e755e537bae60461558c1f63a4e14deMagnus Damm		return -EINVAL;
2025417d48274e755e537bae60461558c1f63a4e14deMagnus Damm
2026dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	return 0;
2027dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski}
202840331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy
2029d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchartstatic int sh_mobile_lcdc_set_par(struct fb_info *info)
2030ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart{
2031ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart	struct sh_mobile_lcdc_chan *ch = info->par;
2032ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart	int ret;
2033ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart
2034ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart	sh_mobile_lcdc_stop(ch->lcdc);
203591fba48d59666718e3d3e86964755b80d39cdbddLaurent Pinchart
2036fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart	ch->format = sh_mobile_format_info(sh_mobile_format_fourcc(&info->var));
203758f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->colorspace = info->var.colorspace;
203858f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
203958f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->xres = info->var.xres;
204058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->xres_virtual = info->var.xres_virtual;
204158f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->yres = info->var.yres;
204258f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->yres_virtual = info->var.yres_virtual;
204358f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
204458f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	if (ch->format->yuv)
204516ca21c9a9f64577221c47d8d2f00d13b880aefaLaurent Pinchart		ch->pitch = info->var.xres_virtual;
204658f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	else
204716ca21c9a9f64577221c47d8d2f00d13b880aefaLaurent Pinchart		ch->pitch = info->var.xres_virtual * ch->format->bpp / 8;
2048fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart
2049ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart	ret = sh_mobile_lcdc_start(ch->lcdc);
205058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	if (ret < 0)
2051ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart		dev_err(info->dev, "%s: unable to restart LCDC\n", __func__);
205258f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
205358f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	info->fix.line_length = ch->pitch;
2054ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart
2055edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	if (sh_mobile_format_is_fourcc(&info->var)) {
2056edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		info->fix.type = FB_TYPE_FOURCC;
2057edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		info->fix.visual = FB_VISUAL_FOURCC;
2058edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	} else {
2059edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		info->fix.type = FB_TYPE_PACKED_PIXELS;
2060edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		info->fix.visual = FB_VISUAL_TRUECOLOR;
2061edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	}
2062edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart
2063ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart	return ret;
2064ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart}
2065ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart
20668857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot/*
20678857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * Screen blanking. Behavior is as follows:
20688857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_UNBLANK: screen unblanked, clocks enabled
20698857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_NORMAL: screen blanked, clocks enabled
20708857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_VSYNC,
20718857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_HSYNC,
20728857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_POWEROFF: screen blanked, clocks disabled
20738857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot */
20748857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbotstatic int sh_mobile_lcdc_blank(int blank, struct fb_info *info)
20758857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot{
20768857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	struct sh_mobile_lcdc_chan *ch = info->par;
20778857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	struct sh_mobile_lcdc_priv *p = ch->lcdc;
20788857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot
20798857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	/* blank the screen? */
20808857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	if (blank > FB_BLANK_UNBLANK && ch->blank_status == FB_BLANK_UNBLANK) {
20818857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		struct fb_fillrect rect = {
208258f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart			.width = ch->xres,
208358f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart			.height = ch->yres,
20848857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		};
20858857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		sh_mobile_lcdc_fillrect(info, &rect);
20868857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	}
20878857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	/* turn clocks on? */
20888857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	if (blank <= FB_BLANK_NORMAL && ch->blank_status > FB_BLANK_NORMAL) {
20898857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		sh_mobile_lcdc_clk_on(p);
20908857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	}
20918857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	/* turn clocks off? */
20928857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	if (blank > FB_BLANK_NORMAL && ch->blank_status <= FB_BLANK_NORMAL) {
20938857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		/* make sure the screen is updated with the black fill before
20948857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		 * switching the clocks off. one vsync is not enough since
20958857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		 * blanking may occur in the middle of a refresh. deferred io
20968857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		 * mode will reenable the clocks and update the screen in time,
20978857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		 * so it does not need this. */
20988857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		if (!info->fbdefio) {
2099d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart			sh_mobile_lcdc_wait_for_vsync(ch);
2100d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart			sh_mobile_lcdc_wait_for_vsync(ch);
21018857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		}
21028857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		sh_mobile_lcdc_clk_off(p);
21038857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	}
21048857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot
21058857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	ch->blank_status = blank;
21068857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	return 0;
21078857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot}
21088857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot
2109bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKUstatic int
2110bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKUsh_mobile_lcdc_mmap(struct fb_info *info, struct vm_area_struct *vma)
2111bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU{
2112bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU	struct sh_mobile_lcdc_chan *ch = info->par;
2113bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU
2114bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU	return dma_mmap_coherent(ch->lcdc->dev, vma, ch->fb_mem,
2115bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU				 ch->dma_handle, ch->fb_size);
2116bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU}
2117bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU
2118cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic struct fb_ops sh_mobile_lcdc_ops = {
21199dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	.owner          = THIS_MODULE,
2120cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.fb_setcolreg	= sh_mobile_lcdc_setcolreg,
21212540c111ead82cad605ec2b14a1905ad914cc124Magnus Damm	.fb_read        = fb_sys_read,
21222540c111ead82cad605ec2b14a1905ad914cc124Magnus Damm	.fb_write       = fb_sys_write,
21238564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	.fb_fillrect	= sh_mobile_lcdc_fillrect,
21248564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	.fb_copyarea	= sh_mobile_lcdc_copyarea,
21258564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	.fb_imageblit	= sh_mobile_lcdc_imageblit,
21268857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	.fb_blank	= sh_mobile_lcdc_blank,
2127d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart	.fb_pan_display = sh_mobile_lcdc_pan,
2128d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart	.fb_ioctl       = sh_mobile_lcdc_ioctl,
2129d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart	.fb_open	= sh_mobile_lcdc_open,
2130d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart	.fb_release	= sh_mobile_lcdc_release,
2131d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart	.fb_check_var	= sh_mobile_lcdc_check_var,
2132d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart	.fb_set_par	= sh_mobile_lcdc_set_par,
2133bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU	.fb_mmap	= sh_mobile_lcdc_mmap,
2134cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm};
2135cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2136a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartstatic void
2137a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartsh_mobile_lcdc_channel_fb_unregister(struct sh_mobile_lcdc_chan *ch)
2138a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart{
2139a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (ch->info && ch->info->dev)
2140a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		unregister_framebuffer(ch->info);
2141a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart}
2142a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
214348c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartmanstatic int
2144a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartsh_mobile_lcdc_channel_fb_register(struct sh_mobile_lcdc_chan *ch)
2145a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart{
2146a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	struct fb_info *info = ch->info;
2147a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	int ret;
2148a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2149a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (info->fbdefio) {
2150a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		ch->sglist = vmalloc(sizeof(struct scatterlist) *
2151a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart				     ch->fb_size >> PAGE_SHIFT);
2152a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		if (!ch->sglist) {
2153a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart			dev_err(ch->lcdc->dev, "cannot allocate sglist\n");
2154a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart			return -ENOMEM;
2155a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		}
2156a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	}
2157a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2158a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->bl_dev = ch->bl;
2159a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2160a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ret = register_framebuffer(info);
2161a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (ret < 0)
2162a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		return ret;
2163a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2164a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	dev_info(ch->lcdc->dev, "registered %s/%s as %dx%d %dbpp.\n",
2165b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		 dev_name(ch->lcdc->dev), (ch->cfg->chan == LCDC_CHAN_MAINLCD) ?
2166a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		 "mainlcd" : "sublcd", info->var.xres, info->var.yres,
2167a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		 info->var.bits_per_pixel);
2168a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2169a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	/* deferred io mode: disable clock to save power */
2170a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED)
2171a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		sh_mobile_lcdc_clk_off(ch->lcdc);
2172a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2173a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	return ret;
2174a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart}
2175a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2176a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartstatic void
2177a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartsh_mobile_lcdc_channel_fb_cleanup(struct sh_mobile_lcdc_chan *ch)
2178a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart{
2179a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	struct fb_info *info = ch->info;
2180a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2181a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (!info || !info->device)
2182a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		return;
2183a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2184a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (ch->sglist)
2185a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		vfree(ch->sglist);
2186a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2187a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	fb_dealloc_cmap(&info->cmap);
2188a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	framebuffer_release(info);
2189a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart}
2190a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
219148c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartmanstatic int
2192a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartsh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch,
2193352d6138779e22c5340803d5a32fc332ad2e5e1dLaurent Pinchart			       const struct fb_videomode *modes,
2194a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart			       unsigned int num_modes)
2195a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart{
2196a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	struct sh_mobile_lcdc_priv *priv = ch->lcdc;
2197a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	struct fb_var_screeninfo *var;
2198a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	struct fb_info *info;
2199a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	int ret;
2200a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2201a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	/* Allocate and initialize the frame buffer device. Create the modes
2202a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 * list and allocate the color map.
2203a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 */
2204a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info = framebuffer_alloc(0, priv->dev);
2205a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (info == NULL) {
2206a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		dev_err(priv->dev, "unable to allocate fb_info\n");
2207a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		return -ENOMEM;
2208a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	}
2209a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2210a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ch->info = info;
2211a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2212a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->flags = FBINFO_FLAG_DEFAULT;
2213a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->fbops = &sh_mobile_lcdc_ops;
2214a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->device = priv->dev;
2215a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->screen_base = ch->fb_mem;
2216a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->pseudo_palette = &ch->pseudo_palette;
2217a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->par = ch;
2218a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2219352d6138779e22c5340803d5a32fc332ad2e5e1dLaurent Pinchart	fb_videomode_to_modelist(modes, num_modes, &info->modelist);
2220a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2221a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);
2222a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (ret < 0) {
2223a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		dev_err(priv->dev, "unable to allocate cmap\n");
2224a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		return ret;
2225a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	}
2226a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2227a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	/* Initialize fixed screen information. Restrict pan to 2 lines steps
2228a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 * for NV12 and NV21.
2229a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 */
2230a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->fix = sh_mobile_lcdc_fix;
2231a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->fix.smem_start = ch->dma_handle;
2232a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->fix.smem_len = ch->fb_size;
223358f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	info->fix.line_length = ch->pitch;
223458f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
223558f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	if (ch->format->yuv)
223658f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		info->fix.visual = FB_VISUAL_FOURCC;
223758f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	else
223858f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		info->fix.visual = FB_VISUAL_TRUECOLOR;
223958f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
224015dede882e564601947f2ce4b647742c0351be6dLaurent Pinchart	switch (ch->format->fourcc) {
224115dede882e564601947f2ce4b647742c0351be6dLaurent Pinchart	case V4L2_PIX_FMT_NV12:
224215dede882e564601947f2ce4b647742c0351be6dLaurent Pinchart	case V4L2_PIX_FMT_NV21:
2243ac33a207b13a70bbca6e58094e28bd92b9fc1ff3Laurent Pinchart		info->fix.ypanstep = 2;
2244ac33a207b13a70bbca6e58094e28bd92b9fc1ff3Laurent Pinchart	case V4L2_PIX_FMT_NV16:
2245ac33a207b13a70bbca6e58094e28bd92b9fc1ff3Laurent Pinchart	case V4L2_PIX_FMT_NV61:
224615dede882e564601947f2ce4b647742c0351be6dLaurent Pinchart		info->fix.xpanstep = 2;
224715dede882e564601947f2ce4b647742c0351be6dLaurent Pinchart	}
2248a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2249a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	/* Initialize variable screen information using the first mode as
2250bd5f2c6911c210af52fa4dc4cf504043ff8a4971Laurent Pinchart	 * default.
2251a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 */
2252a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	var = &info->var;
2253352d6138779e22c5340803d5a32fc332ad2e5e1dLaurent Pinchart	fb_videomode_to_var(var, modes);
2254856e8dfe6efed7cf35bc6bf827f030a164bee083Laurent Pinchart	var->width = ch->display.width;
2255856e8dfe6efed7cf35bc6bf827f030a164bee083Laurent Pinchart	var->height = ch->display.height;
2256bd5f2c6911c210af52fa4dc4cf504043ff8a4971Laurent Pinchart	var->xres_virtual = ch->xres_virtual;
2257bd5f2c6911c210af52fa4dc4cf504043ff8a4971Laurent Pinchart	var->yres_virtual = ch->yres_virtual;
2258a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	var->activate = FB_ACTIVATE_NOW;
2259a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2260a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	/* Use the legacy API by default for RGB formats, and the FOURCC API
2261a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 * for YUV formats.
2262a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 */
2263a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (!ch->format->yuv)
2264a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		var->bits_per_pixel = ch->format->bpp;
2265a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	else
2266a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		var->grayscale = ch->format->fourcc;
2267a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2268d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart	ret = sh_mobile_lcdc_check_var(var, info);
2269a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (ret)
2270a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		return ret;
2271a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2272a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	return 0;
2273a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart}
2274a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2275f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
2276f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Backlight
2277f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
2278f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
22793b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic int sh_mobile_lcdc_update_bl(struct backlight_device *bdev)
22803b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{
22813b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev);
22823b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	int brightness = bdev->props.brightness;
22833b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
22843b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	if (bdev->props.power != FB_BLANK_UNBLANK ||
22853b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	    bdev->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
22863b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		brightness = 0;
22873b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
2288656d4f332c02b14e62fe3f4247a1dcdc33961de6Laurent Pinchart	ch->bl_brightness = brightness;
2289b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	return ch->cfg->bl_info.set_brightness(brightness);
22903b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot}
22913b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
22923b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic int sh_mobile_lcdc_get_brightness(struct backlight_device *bdev)
22933b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{
22943b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev);
22953b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
2296656d4f332c02b14e62fe3f4247a1dcdc33961de6Laurent Pinchart	return ch->bl_brightness;
22973b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot}
22983b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
22993b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic int sh_mobile_lcdc_check_fb(struct backlight_device *bdev,
23003b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot				   struct fb_info *info)
23013b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{
23023b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	return (info->bl_dev == bdev);
23033b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot}
23043b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
23053b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic struct backlight_ops sh_mobile_lcdc_bl_ops = {
23063b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	.options	= BL_CORE_SUSPENDRESUME,
23073b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	.update_status	= sh_mobile_lcdc_update_bl,
23083b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	.get_brightness	= sh_mobile_lcdc_get_brightness,
23093b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	.check_fb	= sh_mobile_lcdc_check_fb,
23103b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot};
23113b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
23123b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic struct backlight_device *sh_mobile_lcdc_bl_probe(struct device *parent,
23133b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot					       struct sh_mobile_lcdc_chan *ch)
23143b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{
23153b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	struct backlight_device *bl;
23163b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
2317b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	bl = backlight_device_register(ch->cfg->bl_info.name, parent, ch,
23183b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot				       &sh_mobile_lcdc_bl_ops, NULL);
2319beee1f20a185c7e79fd33bb83e04fe44ecd75af3Dan Carpenter	if (IS_ERR(bl)) {
2320beee1f20a185c7e79fd33bb83e04fe44ecd75af3Dan Carpenter		dev_err(parent, "unable to register backlight device: %ld\n",
2321beee1f20a185c7e79fd33bb83e04fe44ecd75af3Dan Carpenter			PTR_ERR(bl));
23223b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		return NULL;
23233b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	}
23243b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
2325b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	bl->props.max_brightness = ch->cfg->bl_info.max_brightness;
23263b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	bl->props.brightness = bl->props.max_brightness;
23273b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	backlight_update_status(bl);
23283b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
23293b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	return bl;
23303b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot}
23313b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
23323b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic void sh_mobile_lcdc_bl_remove(struct backlight_device *bdev)
23333b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{
23343b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	backlight_device_unregister(bdev);
23353b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot}
23363b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
2337f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
2338f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Power management
2339f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
2340f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
23412feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Dammstatic int sh_mobile_lcdc_suspend(struct device *dev)
23422feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm{
23432feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	struct platform_device *pdev = to_platform_device(dev);
23442feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
23452feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	sh_mobile_lcdc_stop(platform_get_drvdata(pdev));
23462feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	return 0;
23472feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm}
23482feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
23492feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Dammstatic int sh_mobile_lcdc_resume(struct device *dev)
23502feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm{
23512feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	struct platform_device *pdev = to_platform_device(dev);
23522feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
23532feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	return sh_mobile_lcdc_start(platform_get_drvdata(pdev));
23542feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm}
23552feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
23560246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic int sh_mobile_lcdc_runtime_suspend(struct device *dev)
23570246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm{
23580246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	struct platform_device *pdev = to_platform_device(dev);
23592427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart	struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
23600246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm
23610246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	/* turn off LCDC hardware */
23622427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart	lcdc_write(priv, _LDCNT1R, 0);
23632427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart
23640246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	return 0;
23650246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm}
23660246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm
23670246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic int sh_mobile_lcdc_runtime_resume(struct device *dev)
23680246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm{
23690246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	struct platform_device *pdev = to_platform_device(dev);
23702427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart	struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
23710246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm
23722427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart	__sh_mobile_lcdc_start(priv);
23730246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm
23740246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	return 0;
23750246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm}
23760246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm
2377471452104b8520337ae2fb48c4e61cd4896e025dAlexey Dobriyanstatic const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = {
23782feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	.suspend = sh_mobile_lcdc_suspend,
23792feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	.resume = sh_mobile_lcdc_resume,
23800246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	.runtime_suspend = sh_mobile_lcdc_runtime_suspend,
23810246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	.runtime_resume = sh_mobile_lcdc_runtime_resume,
23822feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm};
23832feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
2384f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
2385f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Framebuffer notifier
2386f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
2387f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
23886de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski/* locking: called with info->lock held */
23896011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetskistatic int sh_mobile_lcdc_notify(struct notifier_block *nb,
23906011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski				 unsigned long action, void *data)
23916011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski{
23926011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	struct fb_event *event = data;
23936011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	struct fb_info *info = event->info;
23946011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	struct sh_mobile_lcdc_chan *ch = info->par;
23956011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
23966011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	if (&ch->lcdc->notifier != nb)
2397baf163749952ca5e33dd2d6a74da023e385c3a00Guennadi Liakhovetski		return NOTIFY_DONE;
23986011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
23996011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	dev_dbg(info->dev, "%s(): action = %lu, data = %p\n",
24006011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski		__func__, action, event->data);
24016011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
24026011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	switch(action) {
24036011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	case FB_EVENT_SUSPEND:
240437c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		sh_mobile_lcdc_display_off(ch);
2405afe417c0355154c8b2547619771d6053b3c0aad7Guennadi Liakhovetski		sh_mobile_lcdc_stop(ch->lcdc);
24066011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski		break;
24076011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	case FB_EVENT_RESUME:
2408dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		mutex_lock(&ch->open_lock);
2409dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		sh_mobile_fb_reconfig(info);
2410dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		mutex_unlock(&ch->open_lock);
24116011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
241237c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		sh_mobile_lcdc_display_on(ch);
2413ebe5e12d00f4785092a9650845ad3451bbf4b311Guennadi Liakhovetski		sh_mobile_lcdc_start(ch->lcdc);
24146011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	}
24156011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
2416baf163749952ca5e33dd2d6a74da023e385c3a00Guennadi Liakhovetski	return NOTIFY_OK;
24176011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski}
24186011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
2419f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
2420f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Probe/remove and driver init/exit
2421f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
2422f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
242348c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartmanstatic const struct fb_videomode default_720p = {
2424f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.name = "HDMI 720p",
2425f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.xres = 1280,
2426f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.yres = 720,
2427f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2428f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.left_margin = 220,
2429f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.right_margin = 110,
2430f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.hsync_len = 40,
2431f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2432f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.upper_margin = 20,
2433f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.lower_margin = 5,
2434f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.vsync_len = 5,
2435f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2436f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.pixclock = 13468,
2437f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.refresh = 60,
2438f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
2439f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart};
2440f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2441b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchartstatic int sh_mobile_lcdc_remove(struct platform_device *pdev)
2442b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart{
2443b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
2444c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned int i;
2445b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
2446b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	fb_unregister_client(&priv->notifier);
2447b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
2448c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(priv->overlays); i++)
2449c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		sh_mobile_lcdc_overlay_fb_unregister(&priv->overlays[i]);
2450b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
2451a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		sh_mobile_lcdc_channel_fb_unregister(&priv->ch[i]);
2452b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
2453b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	sh_mobile_lcdc_stop(priv);
2454b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
2455c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(priv->overlays); i++) {
2456c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i];
2457c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2458c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		sh_mobile_lcdc_overlay_fb_cleanup(ovl);
2459c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2460c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (ovl->fb_mem)
2461c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			dma_free_coherent(&pdev->dev, ovl->fb_size,
2462c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart					  ovl->fb_mem, ovl->dma_handle);
2463c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
2464c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2465b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
24669a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart		struct sh_mobile_lcdc_chan *ch = &priv->ch[i];
2467b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
2468e34d0bbb062cc78802d0f0686c939ea1569889a6Laurent Pinchart		if (ch->tx_dev) {
2469e34d0bbb062cc78802d0f0686c939ea1569889a6Laurent Pinchart			ch->tx_dev->lcdc = NULL;
2470b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart			module_put(ch->cfg->tx_dev->dev.driver->owner);
2471e34d0bbb062cc78802d0f0686c939ea1569889a6Laurent Pinchart		}
24729a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart
2473a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		sh_mobile_lcdc_channel_fb_cleanup(ch);
2474b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
2475a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		if (ch->fb_mem)
2476a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart			dma_free_coherent(&pdev->dev, ch->fb_size,
2477a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart					  ch->fb_mem, ch->dma_handle);
2478b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	}
2479b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
2480b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
24810c75c4e073a8ec35bfd6c8adcceb2b896f2063e2Laurent Pinchart		struct sh_mobile_lcdc_chan *ch = &priv->ch[i];
24820c75c4e073a8ec35bfd6c8adcceb2b896f2063e2Laurent Pinchart
24830c75c4e073a8ec35bfd6c8adcceb2b896f2063e2Laurent Pinchart		if (ch->bl)
24840c75c4e073a8ec35bfd6c8adcceb2b896f2063e2Laurent Pinchart			sh_mobile_lcdc_bl_remove(ch->bl);
24850c75c4e073a8ec35bfd6c8adcceb2b896f2063e2Laurent Pinchart		mutex_destroy(&ch->open_lock);
2486b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	}
2487b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
24884774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	if (priv->dot_clk) {
24894774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart		pm_runtime_disable(&pdev->dev);
2490b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart		clk_put(priv->dot_clk);
24914774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	}
2492b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
2493b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	if (priv->base)
2494b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart		iounmap(priv->base);
2495b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
2496b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	if (priv->irq)
2497b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart		free_irq(priv->irq, priv);
2498b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	kfree(priv);
2499b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	return 0;
2500b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart}
2501cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
250248c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartmanstatic int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
2503f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart{
2504b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	int interface_type = ch->cfg->interface_type;
2505f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2506f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	switch (interface_type) {
2507f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB8:
2508f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB9:
2509f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB12A:
2510f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB12B:
2511f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB16:
2512f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB18:
2513f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB24:
2514f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS8A:
2515f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS8B:
2516f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS8C:
2517f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS8D:
2518f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS9:
2519f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS12:
2520f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS16A:
2521f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS16B:
2522f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS16C:
2523f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS18:
2524f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS24:
2525f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		break;
2526f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	default:
2527f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return -EINVAL;
2528f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
2529f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2530f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	/* SUBLCD only supports SYS interface */
2531f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	if (lcdc_chan_is_sublcd(ch)) {
2532f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		if (!(interface_type & LDMT1R_IFM))
2533f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart			return -EINVAL;
2534f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2535f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		interface_type &= ~LDMT1R_IFM;
2536f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
2537f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2538f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	ch->ldmt1r_value = interface_type;
2539f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	return 0;
2540f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart}
2541f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
254248c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartmanstatic int
25430707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchartsh_mobile_lcdc_overlay_init(struct sh_mobile_lcdc_overlay *ovl)
2544c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
2545c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	const struct sh_mobile_lcdc_format_info *format;
25460707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart	struct device *dev = ovl->channel->lcdc->dev;
2547c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	int ret;
2548c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2549c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ovl->cfg->fourcc == 0)
2550c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return 0;
2551c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2552c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Validate the format. */
2553c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	format = sh_mobile_format_info(ovl->cfg->fourcc);
2554c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (format == NULL) {
25550707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart		dev_err(dev, "Invalid FOURCC %08x\n", ovl->cfg->fourcc);
2556c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
2557c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
2558c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2559c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->enabled = false;
2560c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->mode = LCDC_OVERLAY_BLEND;
2561c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->alpha = 255;
2562c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->rop3 = 0;
2563c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->pos_x = 0;
2564c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->pos_y = 0;
2565c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2566c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* The default Y virtual resolution is twice the panel size to allow for
2567c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 * double-buffering.
2568c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 */
2569c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->format = format;
2570c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->xres = ovl->cfg->max_xres;
2571c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->xres_virtual = ovl->xres;
2572c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->yres = ovl->cfg->max_yres;
2573c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->yres_virtual = ovl->yres * 2;
2574c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2575c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (!format->yuv)
257616ca21c9a9f64577221c47d8d2f00d13b880aefaLaurent Pinchart		ovl->pitch = ovl->xres_virtual * format->bpp / 8;
2577c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	else
257816ca21c9a9f64577221c47d8d2f00d13b880aefaLaurent Pinchart		ovl->pitch = ovl->xres_virtual;
2579c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2580c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Allocate frame buffer memory. */
2581c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->fb_size = ovl->cfg->max_xres * ovl->cfg->max_yres
2582c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		       * format->bpp / 8 * 2;
25830707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart	ovl->fb_mem = dma_alloc_coherent(dev, ovl->fb_size, &ovl->dma_handle,
25840707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart					 GFP_KERNEL);
2585c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (!ovl->fb_mem) {
25860707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart		dev_err(dev, "unable to allocate buffer\n");
2587c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -ENOMEM;
2588c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
2589c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2590c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ret = sh_mobile_lcdc_overlay_fb_init(ovl);
2591c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ret < 0)
2592c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return ret;
2593c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2594c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return 0;
2595c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
2596c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
259748c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartmanstatic int
25980707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchartsh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch)
2599cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
2600105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	const struct sh_mobile_lcdc_format_info *format;
2601b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	const struct sh_mobile_lcdc_chan_cfg *cfg = ch->cfg;
26020707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart	struct device *dev = ch->lcdc->dev;
26033ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	const struct fb_videomode *max_mode;
26043ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	const struct fb_videomode *mode;
2605a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	unsigned int num_modes;
26063ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	unsigned int max_size;
2607a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	unsigned int i;
26083ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
2609a67472ad1ae040f073e45048cbc5a01195f2e3f5Laurent Pinchart	mutex_init(&ch->open_lock);
2610ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	ch->notify = sh_mobile_lcdc_display_notify;
2611a67472ad1ae040f073e45048cbc5a01195f2e3f5Laurent Pinchart
2612105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	/* Validate the format. */
2613105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	format = sh_mobile_format_info(cfg->fourcc);
2614105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	if (format == NULL) {
26150707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart		dev_err(dev, "Invalid FOURCC %08x.\n", cfg->fourcc);
2616105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		return -EINVAL;
2617105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}
2618105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart
26193ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	/* Iterate through the modes to validate them and find the highest
26203ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	 * resolution.
26213ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	 */
26223ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	max_mode = NULL;
26233ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	max_size = 0;
26243ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
262593ff259846a774ff37dca54792c5a3a6425882c0Laurent Pinchart	for (i = 0, mode = cfg->lcd_modes; i < cfg->num_modes; i++, mode++) {
26263ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		unsigned int size = mode->yres * mode->xres;
26273ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
2628edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		/* NV12/NV21 buffers must have even number of lines */
2629edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		if ((cfg->fourcc == V4L2_PIX_FMT_NV12 ||
2630edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		     cfg->fourcc == V4L2_PIX_FMT_NV21) && (mode->yres & 0x1)) {
26310707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart			dev_err(dev, "yres must be multiple of 2 for "
26320a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart				"YCbCr420 mode.\n");
26333ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			return -EINVAL;
26343ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		}
26353ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
26363ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		if (size > max_size) {
26373ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			max_mode = mode;
26383ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			max_size = size;
26393ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		}
26403ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	}
26413ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
26423ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	if (!max_size)
26433ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		max_size = MAX_XRES * MAX_YRES;
26443ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	else
26450707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart		dev_dbg(dev, "Found largest videomode %ux%u\n",
26463ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			max_mode->xres, max_mode->yres);
26473ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
264893ff259846a774ff37dca54792c5a3a6425882c0Laurent Pinchart	if (cfg->lcd_modes == NULL) {
26493ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		mode = &default_720p;
265093ff259846a774ff37dca54792c5a3a6425882c0Laurent Pinchart		num_modes = 1;
26513ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	} else {
265293ff259846a774ff37dca54792c5a3a6425882c0Laurent Pinchart		mode = cfg->lcd_modes;
265393ff259846a774ff37dca54792c5a3a6425882c0Laurent Pinchart		num_modes = cfg->num_modes;
26543ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	}
26553ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
2656bd5f2c6911c210af52fa4dc4cf504043ff8a4971Laurent Pinchart	/* Use the first mode as default. The default Y virtual resolution is
2657bd5f2c6911c210af52fa4dc4cf504043ff8a4971Laurent Pinchart	 * twice the panel size to allow for double-buffering.
2658bd5f2c6911c210af52fa4dc4cf504043ff8a4971Laurent Pinchart	 */
265958f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->format = format;
266058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->xres = mode->xres;
266158f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->xres_virtual = mode->xres;
266258f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->yres = mode->yres;
266358f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->yres_virtual = mode->yres * 2;
266458f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
266558f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	if (!format->yuv) {
266658f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		ch->colorspace = V4L2_COLORSPACE_SRGB;
266716ca21c9a9f64577221c47d8d2f00d13b880aefaLaurent Pinchart		ch->pitch = ch->xres_virtual * format->bpp / 8;
266858f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	} else {
266958f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		ch->colorspace = V4L2_COLORSPACE_REC709;
267016ca21c9a9f64577221c47d8d2f00d13b880aefaLaurent Pinchart		ch->pitch = ch->xres_virtual;
267158f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	}
267258f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
2673a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ch->display.width = cfg->panel_cfg.width;
2674a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ch->display.height = cfg->panel_cfg.height;
2675a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ch->display.mode = *mode;
2676a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2677a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	/* Allocate frame buffer memory. */
2678a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ch->fb_size = max_size * format->bpp / 8 * 2;
26790707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart	ch->fb_mem = dma_alloc_coherent(dev, ch->fb_size, &ch->dma_handle,
2680a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart					GFP_KERNEL);
2681a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (ch->fb_mem == NULL) {
26820707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart		dev_err(dev, "unable to allocate buffer\n");
2683a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		return -ENOMEM;
2684a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	}
26853ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
268613f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart	/* Initialize the transmitter device if present. */
268713f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart	if (cfg->tx_dev) {
268813f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart		if (!cfg->tx_dev->dev.driver ||
268913f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart		    !try_module_get(cfg->tx_dev->dev.driver->owner)) {
26900707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart			dev_warn(dev, "unable to get transmitter device\n");
269113f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart			return -EINVAL;
269213f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart		}
269313f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart		ch->tx_dev = platform_get_drvdata(cfg->tx_dev);
269413f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart		ch->tx_dev->lcdc = ch;
269513f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart		ch->tx_dev->def_mode = *mode;
269613f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart	}
269713f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart
2698a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	return sh_mobile_lcdc_channel_fb_init(ch, mode, num_modes);
26993ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart}
27003ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
270148c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartmanstatic int sh_mobile_lcdc_probe(struct platform_device *pdev)
27023ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart{
270301ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski	struct sh_mobile_lcdc_info *pdata = pdev->dev.platform_data;
27043ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	struct sh_mobile_lcdc_priv *priv;
2705cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	struct resource *res;
27063ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	int num_channels;
2707cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	int error;
27083ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	int i;
2709cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
271001ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski	if (!pdata) {
2711cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		dev_err(&pdev->dev, "no platform data defined\n");
27128bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski		return -EINVAL;
2713cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2714cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2715cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
27168564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	i = platform_get_irq(pdev, 0);
27178564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	if (!res || i < 0) {
27188564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		dev_err(&pdev->dev, "cannot get platform resources\n");
27198bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski		return -ENOENT;
2720cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2721cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2722cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
2723cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (!priv) {
2724cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		dev_err(&pdev->dev, "cannot allocate device data\n");
27258bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski		return -ENOMEM;
2726cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2727cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
27284774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	priv->dev = &pdev->dev;
27294774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	priv->meram_dev = pdata->meram_dev;
27308bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski	platform_set_drvdata(pdev, priv);
27318bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski
2732f8798ccbefc0e4ef7438c080b7ba0410738c8cfaYong Zhang	error = request_irq(i, sh_mobile_lcdc_irq, 0,
27337ad33e74857f16f1202cbc5746faf52e88e8b376Kay Sievers			    dev_name(&pdev->dev), priv);
27348564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	if (error) {
27358564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		dev_err(&pdev->dev, "unable to request irq\n");
27368564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		goto err1;
27378564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	}
27388564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
27398564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	priv->irq = i;
27405ef6b505d9df45558402bdb823a078840a6a26c4Guennadi Liakhovetski	atomic_set(&priv->hw_usecnt, -1);
2741cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
27423ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	for (i = 0, num_channels = 0; i < ARRAY_SIZE(pdata->ch); i++) {
27433ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		struct sh_mobile_lcdc_chan *ch = priv->ch + num_channels;
2744cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
274501ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski		ch->lcdc = priv;
2746b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		ch->cfg = &pdata->ch[i];
2747cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
274801ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski		error = sh_mobile_lcdc_check_interface(ch);
2749cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (error) {
2750cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			dev_err(&pdev->dev, "unsupported interface type\n");
2751cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			goto err1;
2752cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		}
275301ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski		init_waitqueue_head(&ch->frame_end_wait);
275401ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski		init_completion(&ch->vsync_completion);
2755cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
27563b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		/* probe the backlight is there is one defined */
2757b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		if (ch->cfg->bl_info.max_brightness)
27583b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot			ch->bl = sh_mobile_lcdc_bl_probe(&pdev->dev, ch);
27593b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
2760cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		switch (pdata->ch[i].chan) {
2761cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		case LCDC_CHAN_MAINLCD:
2762ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart			ch->enabled = LDCNT2R_ME;
276301ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski			ch->reg_offs = lcdc_offs_mainlcd;
27643ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			num_channels++;
2765cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			break;
2766cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		case LCDC_CHAN_SUBLCD:
2767ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart			ch->enabled = LDCNT2R_SE;
276801ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski			ch->reg_offs = lcdc_offs_sublcd;
27693ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			num_channels++;
2770cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			break;
2771cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		}
2772cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2773cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
27743ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	if (!num_channels) {
2775cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		dev_err(&pdev->dev, "no channels defined\n");
2776cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		error = -EINVAL;
2777cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		goto err1;
2778cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2779cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2780edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	/* for dual channel LCDC (MAIN + SUB) force shared format setting */
27813ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	if (num_channels == 2)
2782edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		priv->forced_fourcc = pdata->ch[0].fourcc;
2783417d48274e755e537bae60461558c1f63a4e14deMagnus Damm
2784dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski	priv->base = ioremap_nocache(res->start, resource_size(res));
2785dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski	if (!priv->base)
2786dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski		goto err1;
2787dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski
27880a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart	error = sh_mobile_lcdc_setup_clocks(priv, pdata->clock_source);
2789cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (error) {
2790cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		dev_err(&pdev->dev, "unable to setup clocks\n");
2791cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		goto err1;
2792cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2793cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
27944774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	/* Enable runtime PM. */
27954774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	pm_runtime_enable(&pdev->dev);
27967caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
27973ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	for (i = 0; i < num_channels; i++) {
27980707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart		struct sh_mobile_lcdc_chan *ch = &priv->ch[i];
2799c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski
28000707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart		error = sh_mobile_lcdc_channel_init(ch);
2801cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (error)
28023ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			goto err1;
2803cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2804cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2805c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(pdata->overlays); i++) {
2806c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i];
2807c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2808c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->cfg = &pdata->overlays[i];
2809c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->channel = &priv->ch[0];
2810c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
28110707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart		error = sh_mobile_lcdc_overlay_init(ovl);
2812c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (error)
2813c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			goto err1;
2814c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
2815c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2816cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	error = sh_mobile_lcdc_start(priv);
2817cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (error) {
2818cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		dev_err(&pdev->dev, "unable to start hardware\n");
2819cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		goto err1;
2820cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2821cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
28223ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	for (i = 0; i < num_channels; i++) {
28231c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt		struct sh_mobile_lcdc_chan *ch = priv->ch + i;
28241c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt
2825a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		error = sh_mobile_lcdc_channel_fb_register(ch);
2826a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		if (error)
2827cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			goto err1;
2828cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2829cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2830c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(pdata->overlays); i++) {
2831c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i];
2832c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2833c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		error = sh_mobile_lcdc_overlay_fb_register(ovl);
2834c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (error)
2835c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			goto err1;
2836c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
2837c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
28386011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	/* Failure ignored */
28396011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	priv->notifier.notifier_call = sh_mobile_lcdc_notify;
28406011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	fb_register_client(&priv->notifier);
28416011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
2842cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	return 0;
28438bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetskierr1:
2844cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	sh_mobile_lcdc_remove(pdev);
28458bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski
2846cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	return error;
2847cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
2848cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2849cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic struct platform_driver sh_mobile_lcdc_driver = {
2850cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.driver		= {
2851cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		.name		= "sh_mobile_lcdc_fb",
2852cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		.owner		= THIS_MODULE,
28532feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		.pm		= &sh_mobile_lcdc_dev_pm_ops,
2854cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	},
2855cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.probe		= sh_mobile_lcdc_probe,
2856cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.remove		= sh_mobile_lcdc_remove,
2857cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm};
2858cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
28594277f2c4667187cbbdd3da3be31ee681bc6b8300Axel Linmodule_platform_driver(sh_mobile_lcdc_driver);
2860cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2861cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_DESCRIPTION("SuperH Mobile LCDC Framebuffer driver");
2862cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
2863cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_LICENSE("GPL v2");
2864