sh_mobile_lcdcfb.c revision 0707330b337cec85d7b393303e82f0fad5dc4c00
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)
347f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart			clk_enable(priv->dot_clk);
348f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		pm_runtime_get_sync(priv->dev);
349f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		if (priv->meram_dev && priv->meram_dev->pdev)
350f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart			pm_runtime_get_sync(&priv->meram_dev->pdev->dev);
351f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
352cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
353cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
354f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchartstatic void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv)
355f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart{
356f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	if (atomic_sub_return(1, &priv->hw_usecnt) == -1) {
357f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		if (priv->meram_dev && priv->meram_dev->pdev)
358f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart			pm_runtime_put_sync(&priv->meram_dev->pdev->dev);
359f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		pm_runtime_put(priv->dev);
360f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		if (priv->dot_clk)
361f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart			clk_disable(priv->dot_clk);
362f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
363f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart}
364f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
3650a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchartstatic int sh_mobile_lcdc_setup_clocks(struct sh_mobile_lcdc_priv *priv,
3660a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart				       int clock_source)
367f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart{
3684774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	struct clk *clk;
369f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	char *str;
370f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
371f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	switch (clock_source) {
372f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case LCDC_CLK_BUS:
373f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		str = "bus_clk";
374f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		priv->lddckr = LDDCKR_ICKSEL_BUS;
375f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		break;
376f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case LCDC_CLK_PERIPHERAL:
377f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		str = "peripheral_clk";
378f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		priv->lddckr = LDDCKR_ICKSEL_MIPI;
379f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		break;
380f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case LCDC_CLK_EXTERNAL:
381f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		str = NULL;
382f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		priv->lddckr = LDDCKR_ICKSEL_HDMI;
383f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		break;
384f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	default:
385f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return -EINVAL;
386f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
387f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
3884774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	if (str == NULL)
3894774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart		return 0;
3904774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart
3910a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart	clk = clk_get(priv->dev, str);
3924774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	if (IS_ERR(clk)) {
3930a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart		dev_err(priv->dev, "cannot get dot clock %s\n", str);
3944774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart		return PTR_ERR(clk);
395f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
396f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
3974774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	priv->dot_clk = clk;
398f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	return 0;
399f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart}
400f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
401f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
40237c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart * Display, panel and deferred I/O
403f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
404f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
405cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_sys_write_index(void *handle, unsigned long data)
406cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
407cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	struct sh_mobile_lcdc_chan *ch = handle;
408cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
409ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_write(ch->lcdc, _LDDWD0R, data | LDDWDxR_WDACT);
410ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
411ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_write(ch->lcdc, _LDDWAR, LDDWAR_WA |
412ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart		   (lcdc_chan_is_sublcd(ch) ? 2 : 0));
413ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
414cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
415cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
416cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_sys_write_data(void *handle, unsigned long data)
417cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
418cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	struct sh_mobile_lcdc_chan *ch = handle;
419cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
420ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_write(ch->lcdc, _LDDWD0R, data | LDDWDxR_WDACT | LDDWDxR_RSW);
421ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
422ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_write(ch->lcdc, _LDDWAR, LDDWAR_WA |
423ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart		   (lcdc_chan_is_sublcd(ch) ? 2 : 0));
424ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
425cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
426cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
427cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic unsigned long lcdc_sys_read_data(void *handle)
428cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
429cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	struct sh_mobile_lcdc_chan *ch = handle;
430cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
431ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_write(ch->lcdc, _LDDRDR, LDDRDR_RSR);
432ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
433ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_write(ch->lcdc, _LDDRAR, LDDRAR_RA |
434ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart		   (lcdc_chan_is_sublcd(ch) ? 2 : 0));
435cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	udelay(1);
436ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
437cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
438ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	return lcdc_read(ch->lcdc, _LDDRDR) & LDDRDR_DRD_MASK;
439cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
440cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
441cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstruct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = {
442cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	lcdc_sys_write_index,
443cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	lcdc_sys_write_data,
444cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	lcdc_sys_read_data,
445cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm};
446cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
4471c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundtstatic int sh_mobile_lcdc_sginit(struct fb_info *info,
4481c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt				  struct list_head *pagelist)
4491c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt{
4501c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt	struct sh_mobile_lcdc_chan *ch = info->par;
45158f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	unsigned int nr_pages_max = ch->fb_size >> PAGE_SHIFT;
4521c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt	struct page *page;
4531c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt	int nr_pages = 0;
4541c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt
4551c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt	sg_init_table(ch->sglist, nr_pages_max);
4561c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt
4571c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt	list_for_each_entry(page, pagelist, lru)
4581c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt		sg_set_page(&ch->sglist[nr_pages++], page, PAGE_SIZE, 0);
4591c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt
4601c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt	return nr_pages;
4611c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt}
4621c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt
4638564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_deferred_io(struct fb_info *info,
4648564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm				       struct list_head *pagelist)
4658564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{
4668564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	struct sh_mobile_lcdc_chan *ch = info->par;
467b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg;
4688564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
4698564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	/* enable clocks before accessing hardware */
4708564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sh_mobile_lcdc_clk_on(ch->lcdc);
4718564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
4725c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	/*
4735c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * It's possible to get here without anything on the pagelist via
4745c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * sh_mobile_lcdc_deferred_io_touch() or via a userspace fsync()
4755c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * invocation. In the former case, the acceleration routines are
4765c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * stepped in to when using the framebuffer console causing the
4775c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * workqueue to be scheduled without any dirty pages on the list.
4785c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 *
4795c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * Despite this, a panel update is still needed given that the
4805c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * acceleration routines have their own methods for writing in
4815c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * that still need to be updated.
4825c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 *
4835c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * The fsync() and empty pagelist case could be optimized for,
4845c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * but we don't bother, as any application exhibiting such
4855c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * behaviour is fundamentally broken anyways.
4865c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 */
4875c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	if (!list_empty(pagelist)) {
4885c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt		unsigned int nr_pages = sh_mobile_lcdc_sginit(info, pagelist);
4895c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt
4905c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt		/* trigger panel update */
491e8363140c02c92c122210e03103aef72dd836664Laurent Pinchart		dma_map_sg(ch->lcdc->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
492afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart		if (panel->start_transfer)
493afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart			panel->start_transfer(ch, &sh_mobile_lcdc_sys_bus_ops);
494ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart		lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG);
495e8363140c02c92c122210e03103aef72dd836664Laurent Pinchart		dma_unmap_sg(ch->lcdc->dev, ch->sglist, nr_pages,
496e8363140c02c92c122210e03103aef72dd836664Laurent Pinchart			     DMA_TO_DEVICE);
497ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm	} else {
498afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart		if (panel->start_transfer)
499afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart			panel->start_transfer(ch, &sh_mobile_lcdc_sys_bus_ops);
500ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart		lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG);
501ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm	}
5028564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
5038564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
5048564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info)
5058564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{
5068564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	struct fb_deferred_io *fbdefio = info->fbdefio;
5078564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
5088564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	if (fbdefio)
5098564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		schedule_delayed_work(&info->deferred_work, fbdefio->delay);
5108564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
5118564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
51237c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchartstatic void sh_mobile_lcdc_display_on(struct sh_mobile_lcdc_chan *ch)
51337c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart{
514b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg;
51537c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart
5169a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart	if (ch->tx_dev) {
517458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart		int ret;
518458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart
519458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart		ret = ch->tx_dev->ops->display_on(ch->tx_dev);
520458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart		if (ret < 0)
5219a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart			return;
522458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart
523458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart		if (ret == SH_MOBILE_LCDC_DISPLAY_DISCONNECTED)
524458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart			ch->info->state = FBINFO_STATE_SUSPENDED;
5259a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart	}
5269a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart
52737c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart	/* HDMI must be enabled before LCDC configuration */
528afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart	if (panel->display_on)
529afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart		panel->display_on();
53037c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart}
53137c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart
53237c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchartstatic void sh_mobile_lcdc_display_off(struct sh_mobile_lcdc_chan *ch)
53337c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart{
534b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg;
53537c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart
536afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart	if (panel->display_off)
537afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart		panel->display_off();
5389a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart
5399a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart	if (ch->tx_dev)
5409a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart		ch->tx_dev->ops->display_off(ch->tx_dev);
54137c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart}
54237c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart
543ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchartstatic bool
544ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchartsh_mobile_lcdc_must_reconfigure(struct sh_mobile_lcdc_chan *ch,
545e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart				const struct fb_videomode *new_mode)
546ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart{
547ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	dev_dbg(ch->info->dev, "Old %ux%u, new %ux%u\n",
5482d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart		ch->display.mode.xres, ch->display.mode.yres,
5492d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart		new_mode->xres, new_mode->yres);
550ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
551e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart	/* It can be a different monitor with an equal video-mode */
5522d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	if (fb_mode_is_equal(&ch->display.mode, new_mode))
553ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		return false;
554ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
555ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	dev_dbg(ch->info->dev, "Switching %u -> %u lines\n",
5562d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart		ch->display.mode.yres, new_mode->yres);
5572d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	ch->display.mode = *new_mode;
558ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
559ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	return true;
560ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart}
561ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
562d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchartstatic int sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var,
563d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart				    struct fb_info *info);
564ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
565ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchartstatic int sh_mobile_lcdc_display_notify(struct sh_mobile_lcdc_chan *ch,
566ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart					 enum sh_mobile_lcdc_entity_event event,
567e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart					 const struct fb_videomode *mode,
568e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart					 const struct fb_monspecs *monspec)
569ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart{
570ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	struct fb_info *info = ch->info;
571e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart	struct fb_var_screeninfo var;
572ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	int ret = 0;
573ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
574ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	switch (event) {
575ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	case SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT:
576ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		/* HDMI plug in */
577ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		if (lock_fb_info(info)) {
578ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			console_lock();
579ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
5802d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart			ch->display.width = monspec->max_x * 10;
5812d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart			ch->display.height = monspec->max_y * 10;
582e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart
583e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart			if (!sh_mobile_lcdc_must_reconfigure(ch, mode) &&
584ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			    info->state == FBINFO_STATE_RUNNING) {
585ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				/* First activation with the default monitor.
586ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				 * Just turn on, if we run a resume here, the
587ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				 * logo disappears.
588ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				 */
589856e8dfe6efed7cf35bc6bf827f030a164bee083Laurent Pinchart				info->var.width = ch->display.width;
590856e8dfe6efed7cf35bc6bf827f030a164bee083Laurent Pinchart				info->var.height = ch->display.height;
591ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				sh_mobile_lcdc_display_on(ch);
592ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			} else {
593ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				/* New monitor or have to wake up */
594ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				fb_set_suspend(info, 0);
595ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			}
596ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
597ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			console_unlock();
598ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			unlock_fb_info(info);
599ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		}
600ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		break;
601ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
602ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	case SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT:
603ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		/* HDMI disconnect */
604ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		if (lock_fb_info(info)) {
605ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			console_lock();
606ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			fb_set_suspend(info, 1);
607ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			console_unlock();
608ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			unlock_fb_info(info);
609ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		}
610ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		break;
611ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
612ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	case SH_MOBILE_LCDC_EVENT_DISPLAY_MODE:
613ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		/* Validate a proposed new mode */
614e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart		fb_videomode_to_var(&var, mode);
615e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart		var.bits_per_pixel = info->var.bits_per_pixel;
616e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart		var.grayscale = info->var.grayscale;
617d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart		ret = sh_mobile_lcdc_check_var(&var, info);
618ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		break;
619ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	}
620ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
621ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	return ret;
622ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart}
623ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
624f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
625f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Format helpers
626f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
627f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
628105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchartstruct sh_mobile_lcdc_format_info {
629105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	u32 fourcc;
630105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	unsigned int bpp;
631105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	bool yuv;
632105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	u32 lddfr;
633105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart};
634105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart
635105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchartstatic const struct sh_mobile_lcdc_format_info sh_mobile_format_infos[] = {
636105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	{
637105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_RGB565,
638105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 16,
639105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = false,
640105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_PKF_RGB16,
641105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
642105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_BGR24,
643105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 24,
644105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = false,
645105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_PKF_RGB24,
646105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
647105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_BGR32,
648105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 32,
649105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = false,
650105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_PKF_ARGB32,
651105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
652105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_NV12,
653105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 12,
654105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = true,
655105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_CC | LDDFR_YF_420,
656105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
657105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_NV21,
658105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 12,
659105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = true,
660105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_CC | LDDFR_YF_420,
661105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
662105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_NV16,
663105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 16,
664105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = true,
665105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_CC | LDDFR_YF_422,
666105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
667105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_NV61,
668105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 16,
669105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = true,
670105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_CC | LDDFR_YF_422,
671105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
672105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_NV24,
673105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 24,
674105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = true,
675105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_CC | LDDFR_YF_444,
676105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
677105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_NV42,
678105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 24,
679105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = true,
680105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_CC | LDDFR_YF_444,
681105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	},
682105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart};
683105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart
684105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchartstatic const struct sh_mobile_lcdc_format_info *
685105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchartsh_mobile_format_info(u32 fourcc)
686105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart{
687105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	unsigned int i;
688105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart
689105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(sh_mobile_format_infos); ++i) {
690105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		if (sh_mobile_format_infos[i].fourcc == fourcc)
691105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart			return &sh_mobile_format_infos[i];
692105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}
693105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart
694105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	return NULL;
695105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart}
696105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart
697f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchartstatic int sh_mobile_format_fourcc(const struct fb_var_screeninfo *var)
698f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart{
699f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	if (var->grayscale > 1)
700f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return var->grayscale;
701f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
702f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	switch (var->bits_per_pixel) {
703f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case 16:
704f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return V4L2_PIX_FMT_RGB565;
705f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case 24:
706f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return V4L2_PIX_FMT_BGR24;
707f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case 32:
708f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return V4L2_PIX_FMT_BGR32;
709f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	default:
710f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return 0;
711f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
712f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart}
713f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
714f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchartstatic int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var)
715f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart{
716f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	return var->grayscale > 1;
717f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart}
718f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
719f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
720f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Start, stop and IRQ
721f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
722f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
7238564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
7248564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{
7258564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	struct sh_mobile_lcdc_priv *priv = data;
7262feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	struct sh_mobile_lcdc_chan *ch;
7279dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	unsigned long ldintr;
7282feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	int is_sub;
7292feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	int k;
7308564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
731dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart	/* Acknowledge interrupts and disable further VSYNC End IRQs. */
732dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart	ldintr = lcdc_read(priv, _LDINTR);
733dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart	lcdc_write(priv, _LDINTR, (ldintr ^ LDINTR_STATUS_MASK) & ~LDINTR_VEE);
7348564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
7352feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	/* figure out if this interrupt is for main or sub lcd */
736ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	is_sub = (lcdc_read(priv, _LDSR) & LDSR_MSS) ? 1 : 0;
7372feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
7389dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	/* wake up channel and disable clocks */
7392feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
7402feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		ch = &priv->ch[k];
7412feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
7422feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		if (!ch->enabled)
7432feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm			continue;
7442feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
745dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart		/* Frame End */
7469dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy		if (ldintr & LDINTR_FS) {
7479dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy			if (is_sub == lcdc_chan_is_sublcd(ch)) {
7489dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy				ch->frame_end = 1;
7499dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy				wake_up(&ch->frame_end_wait);
7502feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
7519dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy				sh_mobile_lcdc_clk_off(priv);
7529dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy			}
7539dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy		}
7549dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
7559dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy		/* VSYNC End */
75640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy		if (ldintr & LDINTR_VES)
75740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy			complete(&ch->vsync_completion);
7582feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	}
7592feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
7608564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	return IRQ_HANDLED;
7618564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
7628564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
763d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchartstatic int sh_mobile_lcdc_wait_for_vsync(struct sh_mobile_lcdc_chan *ch)
7644976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart{
7654976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	unsigned long ldintr;
7664976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	int ret;
7674976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart
7684976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	/* Enable VSync End interrupt and be careful not to acknowledge any
7694976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	 * pending interrupt.
7704976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	 */
7714976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	ldintr = lcdc_read(ch->lcdc, _LDINTR);
7724976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	ldintr |= LDINTR_VEE | LDINTR_STATUS_MASK;
7734976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	lcdc_write(ch->lcdc, _LDINTR, ldintr);
7744976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart
7754976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion,
7764976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart							msecs_to_jiffies(100));
7774976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	if (!ret)
7784976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart		return -ETIMEDOUT;
7794976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart
7804976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	return 0;
7814976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart}
7824976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart
783cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv,
784cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm				      int start)
785cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
786cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	unsigned long tmp = lcdc_read(priv, _LDCNT2R);
787cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	int k;
788cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
789cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	/* start or stop the lcdc */
790cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (start)
791ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart		lcdc_write(priv, _LDCNT2R, tmp | LDCNT2R_DO);
792cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	else
793ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart		lcdc_write(priv, _LDCNT2R, tmp & ~LDCNT2R_DO);
794cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
795cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	/* wait until power is applied/stopped on all channels */
796cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++)
797cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (lcdc_read(priv, _LDCNT2R) & priv->ch[k].enabled)
798cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			while (1) {
799ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart				tmp = lcdc_read_chan(&priv->ch[k], LDPMR)
800ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart				    & LDPMR_LPS;
801ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart				if (start && tmp == LDPMR_LPS)
802cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm					break;
803cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm				if (!start && tmp == 0)
804cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm					break;
805cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm				cpu_relax();
806cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			}
807cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
808cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (!start)
809cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		lcdc_write(priv, _LDDCKSTPR, 1); /* stop dotclock */
810cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
811cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
8126011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetskistatic void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
8136011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski{
8142d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	const struct fb_var_screeninfo *var = &ch->info->var;
8152d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	const struct fb_videomode *mode = &ch->display.mode;
8161c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski	unsigned long h_total, hsync_pos, display_h_total;
8176011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	u32 tmp;
8186011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
8196011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	tmp = ch->ldmt1r_value;
820ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	tmp |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : LDMT1R_VPOL;
821ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	tmp |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : LDMT1R_HPOL;
822b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	tmp |= (ch->cfg->flags & LCDC_FLAGS_DWPOL) ? LDMT1R_DWPOL : 0;
823b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	tmp |= (ch->cfg->flags & LCDC_FLAGS_DIPOL) ? LDMT1R_DIPOL : 0;
824b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	tmp |= (ch->cfg->flags & LCDC_FLAGS_DAPOL) ? LDMT1R_DAPOL : 0;
825b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	tmp |= (ch->cfg->flags & LCDC_FLAGS_HSCNT) ? LDMT1R_HSCNT : 0;
826b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	tmp |= (ch->cfg->flags & LCDC_FLAGS_DWCNT) ? LDMT1R_DWCNT : 0;
8276011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDMT1R, tmp);
8286011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
8296011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	/* setup SYS bus */
830b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	lcdc_write_chan(ch, LDMT2R, ch->cfg->sys_bus_cfg.ldmt2r);
831b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	lcdc_write_chan(ch, LDMT3R, ch->cfg->sys_bus_cfg.ldmt3r);
8326011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
8336011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	/* horizontal configuration */
8342d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	h_total = mode->xres + mode->hsync_len + mode->left_margin
8352d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart		+ mode->right_margin;
8366011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	tmp = h_total / 8; /* HTCN */
83758f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	tmp |= (min(mode->xres, ch->xres) / 8) << 16; /* HDCN */
8386011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDHCNR, tmp);
8396011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
8402d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	hsync_pos = mode->xres + mode->right_margin;
8416011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	tmp = hsync_pos / 8; /* HSYNP */
8422d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	tmp |= (mode->hsync_len / 8) << 16; /* HSYNW */
8436011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDHSYNR, tmp);
8446011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
8456011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	/* vertical configuration */
8462d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	tmp = mode->yres + mode->vsync_len + mode->upper_margin
8472d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	    + mode->lower_margin; /* VTLN */
84858f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	tmp |= min(mode->yres, ch->yres) << 16; /* VDLN */
8496011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDVLNR, tmp);
8506011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
8512d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	tmp = mode->yres + mode->lower_margin; /* VSYNP */
8522d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	tmp |= mode->vsync_len << 16; /* VSYNW */
8536011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDVSYNR, tmp);
8546011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
8556011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	/* Adjust horizontal synchronisation for HDMI */
8562d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	display_h_total = mode->xres + mode->hsync_len + mode->left_margin
8572d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart			+ mode->right_margin;
8582d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	tmp = ((mode->xres & 7) << 24) | ((display_h_total & 7) << 16)
8592d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	    | ((mode->hsync_len & 7) << 8) | (hsync_pos & 7);
8606011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDHAJR, tmp);
8616011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski}
8626011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
863c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic void sh_mobile_lcdc_overlay_setup(struct sh_mobile_lcdc_overlay *ovl)
864c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
865c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	u32 format = 0;
866c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
867c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (!ovl->enabled) {
868c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index));
869c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		lcdc_write_overlay(ovl, LDBnBSIFR(ovl->index), 0);
870c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		lcdc_write(ovl->channel->lcdc, LDBCR,
871c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			   LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index));
872c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return;
873c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
874c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
875c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->base_addr_y = ovl->dma_handle;
876a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	ovl->base_addr_c = ovl->dma_handle
877a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart			 + ovl->xres_virtual * ovl->yres_virtual;
878c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
879c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	switch (ovl->mode) {
880c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case LCDC_OVERLAY_BLEND:
881c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format = LDBBSIFR_EN | (ovl->alpha << LDBBSIFR_LAY_SHIFT);
882c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
883c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
884c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case LCDC_OVERLAY_ROP3:
885c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format = LDBBSIFR_EN | LDBBSIFR_BRSEL
886c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		       | (ovl->rop3 << LDBBSIFR_ROP3_SHIFT);
887c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
888c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
889c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
890c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	switch (ovl->format->fourcc) {
891c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_RGB565:
892c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV21:
893c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV61:
894c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV42:
895c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW;
896c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
897c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_BGR24:
898c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV12:
899c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV16:
900c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV24:
901c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW | LDBBSIFR_SWPB;
902c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
903c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_BGR32:
904c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	default:
905c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format |= LDBBSIFR_SWPL;
906c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
907c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
908c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
909c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	switch (ovl->format->fourcc) {
910c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_RGB565:
911c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB16;
912c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
913c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_BGR24:
914c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB24;
915c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
916c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_BGR32:
917c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format |= LDBBSIFR_AL_PK | LDBBSIFR_RY | LDDFR_PKF_ARGB32;
918c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
919c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV12:
920c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV21:
921c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_420;
922c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
923c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV16:
924c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV61:
925c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_422;
926c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
927c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV24:
928c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case V4L2_PIX_FMT_NV42:
929c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_444;
930c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		break;
931c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
932c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
933c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index));
934c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
935c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write_overlay(ovl, LDBnBSIFR(ovl->index), format);
936c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
937c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write_overlay(ovl, LDBnBSSZR(ovl->index),
938c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		(ovl->yres << LDBBSSZR_BVSS_SHIFT) |
939c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		(ovl->xres << LDBBSSZR_BHSS_SHIFT));
940c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write_overlay(ovl, LDBnBLOCR(ovl->index),
941c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		(ovl->pos_y << LDBBLOCR_CVLC_SHIFT) |
942c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		(ovl->pos_x << LDBBLOCR_CHLC_SHIFT));
943c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write_overlay(ovl, LDBnBSMWR(ovl->index),
944c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->pitch << LDBBSMWR_BSMW_SHIFT);
945c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
946c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write_overlay(ovl, LDBnBSAYR(ovl->index), ovl->base_addr_y);
947c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write_overlay(ovl, LDBnBSACR(ovl->index), ovl->base_addr_c);
948c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
949c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write(ovl->channel->lcdc, LDBCR,
950c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		   LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index));
951c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
952c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
9539a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart/*
954d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart * __sh_mobile_lcdc_start - Configure and start the LCDC
9559a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart * @priv: LCDC device
9569a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart *
9579a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart * Configure all enabled channels and start the LCDC device. All external
9589a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart * devices (clocks, MERAM, panels, ...) are not touched by this function.
9599a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart */
9609a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchartstatic void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
961cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
962cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	struct sh_mobile_lcdc_chan *ch;
963cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	unsigned long tmp;
9649a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	int k, m;
9658564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
9669a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Enable LCDC channels. Read data from external memory, avoid using the
9679a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	 * BEU for now.
9689a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	 */
9699a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_write(priv, _LDCNT2R, priv->ch[0].enabled | priv->ch[1].enabled);
970cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
9719a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Stop the LCDC first and disable all interrupts. */
972cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	sh_mobile_lcdc_start_stop(priv, 0);
9739a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_write(priv, _LDINTR, 0);
974cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
9759a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Configure power supply, dot clocks and start them. */
976cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	tmp = priv->lddckr;
977cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
978cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		ch = &priv->ch[k];
9799a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (!ch->enabled)
980cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			continue;
981cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
9829a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		/* Power supply */
9839a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		lcdc_write_chan(ch, LDPMR, 0);
9849a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
985b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		m = ch->cfg->clock_divider;
986cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (!m)
987cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			continue;
988cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
989505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart		/* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider
990505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart		 * denominator.
991505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart		 */
992505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart		lcdc_write_chan(ch, LDDCKPAT1R, 0);
993505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart		lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1);
994505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart
995cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (m == 1)
996ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart			m = LDDCKR_MOSEL;
997cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0);
998cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
999cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1000cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	lcdc_write(priv, _LDDCKR, tmp);
1001cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	lcdc_write(priv, _LDDCKSTPR, 0);
1002cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0);
1003cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
10049a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Setup geometry, format, frame buffer memory and operation mode. */
1005cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
1006cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		ch = &priv->ch[k];
1007cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (!ch->enabled)
1008cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			continue;
1009cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
10106011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski		sh_mobile_lcdc_geometry(ch);
1011cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1012fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart		tmp = ch->format->lddfr;
1013edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart
1014fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart		if (ch->format->yuv) {
101558f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart			switch (ch->colorspace) {
1016edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			case V4L2_COLORSPACE_REC709:
1017edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart				tmp |= LDDFR_CF1;
101853b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia				break;
1019edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			case V4L2_COLORSPACE_JPEG:
1020edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart				tmp |= LDDFR_CF0;
102153b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia				break;
102253b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia			}
1023417d48274e755e537bae60461558c1f63a4e14deMagnus Damm		}
10247caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
10259a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		lcdc_write_chan(ch, LDDFR, tmp);
102672c04af9a2d57b7945cf3de8e71461bd80695d50Laurent Pinchart		lcdc_write_chan(ch, LDMLSR, ch->line_size);
10279a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		lcdc_write_chan(ch, LDSA1R, ch->base_addr_y);
1028fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart		if (ch->format->yuv)
10299a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			lcdc_write_chan(ch, LDSA2R, ch->base_addr_c);
10307caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
10319a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		/* When using deferred I/O mode, configure the LCDC for one-shot
10329a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		 * operation and enable the frame end interrupt. Otherwise use
10339a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		 * continuous read mode.
10349a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		 */
10359a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (ch->ldmt1r_value & LDMT1R_IFM &&
1036b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		    ch->cfg->sys_bus_cfg.deferred_io_msec) {
10379a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			lcdc_write_chan(ch, LDSM1R, LDSM1R_OS);
10389a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			lcdc_write(priv, _LDINTR, LDINTR_FE);
10399a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		} else {
10409a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			lcdc_write_chan(ch, LDSM1R, 0);
10419a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		}
10429a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	}
10437caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
10449a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Word and long word swap. */
1045fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart	switch (priv->ch[0].format->fourcc) {
1046edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_RGB565:
1047edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV21:
1048edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV61:
1049edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV42:
1050edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		tmp = LDDDSR_LS | LDDDSR_WS;
1051edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		break;
1052edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_BGR24:
1053edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV12:
1054edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV16:
1055edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV24:
10569a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;
1057edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		break;
1058edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_BGR32:
1059edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	default:
1060edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		tmp = LDDDSR_LS;
1061edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		break;
10629a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	}
10639a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_write(priv, _LDDDSR, tmp);
10647caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
10659a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Enable the display output. */
10669a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_write(priv, _LDCNT1R, LDCNT1R_DE);
10679a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	sh_mobile_lcdc_start_stop(priv, 1);
10689a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	priv->started = 1;
10699a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart}
1070cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
10719a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchartstatic int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
10729a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart{
10739a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	struct sh_mobile_meram_info *mdev = priv->meram_dev;
10749a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	struct sh_mobile_lcdc_chan *ch;
10759a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	unsigned long tmp;
10769a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	int ret;
10779a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	int k;
1078cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
10799a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* enable clocks before accessing the hardware */
10809a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
10819a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (priv->ch[k].enabled)
10829a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			sh_mobile_lcdc_clk_on(priv);
10839a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	}
10848564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
10859a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* reset */
10869a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LDCNT2R_BR);
10879a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_wait_bit(priv, _LDCNT2R, LDCNT2R_BR, 0);
10888564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
10899a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
1090b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		const struct sh_mobile_lcdc_panel_cfg *panel;
10918564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
109237c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		ch = &priv->ch[k];
10939a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (!ch->enabled)
10949a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			continue;
10959a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
1096b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		panel = &ch->cfg->panel_cfg;
1097afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart		if (panel->setup_sys) {
1098afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart			ret = panel->setup_sys(ch, &sh_mobile_lcdc_sys_bus_ops);
10999a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			if (ret)
11009a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart				return ret;
11018564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		}
1102cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
1103cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
11049a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Compute frame buffer base address and pitch for each channel. */
11059a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
11069a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		int pixelformat;
11074a2371772146b30113c9c837eb32b64f18376c0dLaurent Pinchart		void *cache;
1108cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
11099a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		ch = &priv->ch[k];
11109a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (!ch->enabled)
11119a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			continue;
1112cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
111358f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		ch->base_addr_y = ch->dma_handle;
1114a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		ch->base_addr_c = ch->dma_handle
1115a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart				+ ch->xres_virtual * ch->yres_virtual;
111672c04af9a2d57b7945cf3de8e71461bd80695d50Laurent Pinchart		ch->line_size = ch->pitch;
11179a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
11189a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		/* Enable MERAM if possible. */
11196e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart		if (mdev == NULL || ch->cfg->meram_cfg == NULL)
11209a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			continue;
11219a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
11224a2371772146b30113c9c837eb32b64f18376c0dLaurent Pinchart		/* Free the allocated MERAM cache. */
11234a2371772146b30113c9c837eb32b64f18376c0dLaurent Pinchart		if (ch->cache) {
11246e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart			sh_mobile_meram_cache_free(mdev, ch->cache);
11254a2371772146b30113c9c837eb32b64f18376c0dLaurent Pinchart			ch->cache = NULL;
11269a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		}
11279a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
1128fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart		switch (ch->format->fourcc) {
1129edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV12:
1130edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV21:
1131edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV16:
1132edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV61:
11339a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			pixelformat = SH_MOBILE_MERAM_PF_NV;
1134edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			break;
1135edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV24:
1136edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV42:
1137edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			pixelformat = SH_MOBILE_MERAM_PF_NV24;
1138edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			break;
1139edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_RGB565:
1140edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_BGR24:
1141edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_BGR32:
1142edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		default:
1143edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			pixelformat = SH_MOBILE_MERAM_PF_RGB;
1144edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			break;
1145edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		}
11469a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
11476e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart		cache = sh_mobile_meram_cache_alloc(mdev, ch->cfg->meram_cfg,
1148b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart					ch->pitch, ch->yres, pixelformat,
114972c04af9a2d57b7945cf3de8e71461bd80695d50Laurent Pinchart					&ch->line_size);
11504a2371772146b30113c9c837eb32b64f18376c0dLaurent Pinchart		if (!IS_ERR(cache)) {
11516e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart			sh_mobile_meram_cache_update(mdev, cache,
115297d16fe69b6499a14a0c85c053f7bef54ce992a4Laurent Pinchart					ch->base_addr_y, ch->base_addr_c,
115397d16fe69b6499a14a0c85c053f7bef54ce992a4Laurent Pinchart					&ch->base_addr_y, &ch->base_addr_c);
11544a2371772146b30113c9c837eb32b64f18376c0dLaurent Pinchart			ch->cache = cache;
115597d16fe69b6499a14a0c85c053f7bef54ce992a4Laurent Pinchart		}
11569a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	}
11579a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
1158c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	for (k = 0; k < ARRAY_SIZE(priv->overlays); ++k) {
1159c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[k];
1160c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		sh_mobile_lcdc_overlay_setup(ovl);
1161c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1162c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
11639a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Start the LCDC. */
11649a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	__sh_mobile_lcdc_start(priv);
11659a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
11669a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Setup deferred I/O, tell the board code to enable the panels, and
11679a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	 * turn backlight on.
11689a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	 */
1169cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
1170cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		ch = &priv->ch[k];
117121bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm		if (!ch->enabled)
117221bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm			continue;
117321bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm
1174b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		tmp = ch->cfg->sys_bus_cfg.deferred_io_msec;
11759a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (ch->ldmt1r_value & LDMT1R_IFM && tmp) {
11769a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			ch->defio.deferred_io = sh_mobile_lcdc_deferred_io;
11779a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			ch->defio.delay = msecs_to_jiffies(tmp);
11789a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			ch->info->fbdefio = &ch->defio;
11799a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			fb_deferred_io_init(ch->info);
11809a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		}
11819a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
118237c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		sh_mobile_lcdc_display_on(ch);
11833b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
11843b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		if (ch->bl) {
11853b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot			ch->bl->props.power = FB_BLANK_UNBLANK;
11863b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot			backlight_update_status(ch->bl);
11873b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		}
1188cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
1189cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1190cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	return 0;
1191cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
1192cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1193cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
1194cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
1195cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	struct sh_mobile_lcdc_chan *ch;
1196cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	int k;
1197cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
11982feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	/* clean up deferred io and ask board code to disable panel */
1199cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
1200cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		ch = &priv->ch[k];
120121bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm		if (!ch->enabled)
120221bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm			continue;
12038564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
12042feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		/* deferred io mode:
12052feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		 * flush frame, and wait for frame end interrupt
12062feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		 * clean up deferred io and enable clock
12072feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		 */
12085ef6b505d9df45558402bdb823a078840a6a26c4Guennadi Liakhovetski		if (ch->info && ch->info->fbdefio) {
12092feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm			ch->frame_end = 0;
1210e33afddca174171a68d57476ead8947476ab9240Paul Mundt			schedule_delayed_work(&ch->info->deferred_work, 0);
12112feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm			wait_event(ch->frame_end_wait, ch->frame_end);
1212e33afddca174171a68d57476ead8947476ab9240Paul Mundt			fb_deferred_io_cleanup(ch->info);
1213e33afddca174171a68d57476ead8947476ab9240Paul Mundt			ch->info->fbdefio = NULL;
12142feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm			sh_mobile_lcdc_clk_on(priv);
12158564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		}
12162feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
12173b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		if (ch->bl) {
12183b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot			ch->bl->props.power = FB_BLANK_POWERDOWN;
12193b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot			backlight_update_status(ch->bl);
12203b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		}
12213b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
122237c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		sh_mobile_lcdc_display_off(ch);
12237caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
12244a2371772146b30113c9c837eb32b64f18376c0dLaurent Pinchart		/* Free the MERAM cache. */
12254a2371772146b30113c9c837eb32b64f18376c0dLaurent Pinchart		if (ch->cache) {
12266e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart			sh_mobile_meram_cache_free(priv->meram_dev, ch->cache);
12274a2371772146b30113c9c837eb32b64f18376c0dLaurent Pinchart			ch->cache = 0;
12287caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia		}
12297caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
1230cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
1231cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1232cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	/* stop the lcdc */
12338e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm	if (priv->started) {
12348e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm		sh_mobile_lcdc_start_stop(priv, 0);
12358e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm		priv->started = 0;
12368e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm	}
1237b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm
12388564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	/* stop clocks */
12398564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++)
12408564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		if (priv->ch[k].enabled)
12418564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm			sh_mobile_lcdc_clk_off(priv);
1242cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
1243cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1244c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic int __sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var,
1245c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart				      struct fb_info *info)
1246c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1247c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (var->xres > MAX_XRES || var->yres > MAX_YRES)
1248c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1249c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1250c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Make sure the virtual resolution is at least as big as the visible
1251c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 * resolution.
1252c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 */
1253c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (var->xres_virtual < var->xres)
1254c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		var->xres_virtual = var->xres;
1255c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (var->yres_virtual < var->yres)
1256c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		var->yres_virtual = var->yres;
1257c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1258c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (sh_mobile_format_is_fourcc(var)) {
1259c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		const struct sh_mobile_lcdc_format_info *format;
1260c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1261c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		format = sh_mobile_format_info(var->grayscale);
1262c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (format == NULL)
1263c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			return -EINVAL;
1264c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		var->bits_per_pixel = format->bpp;
1265c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1266c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		/* Default to RGB and JPEG color-spaces for RGB and YUV formats
1267c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		 * respectively.
1268c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		 */
1269c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (!format->yuv)
1270c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->colorspace = V4L2_COLORSPACE_SRGB;
1271c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		else if (var->colorspace != V4L2_COLORSPACE_REC709)
1272c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->colorspace = V4L2_COLORSPACE_JPEG;
1273c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	} else {
1274c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (var->bits_per_pixel <= 16) {		/* RGB 565 */
1275c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->bits_per_pixel = 16;
1276c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->red.offset = 11;
1277c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->red.length = 5;
1278c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->green.offset = 5;
1279c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->green.length = 6;
1280c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->blue.offset = 0;
1281c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->blue.length = 5;
1282c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->transp.offset = 0;
1283c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->transp.length = 0;
1284c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		} else if (var->bits_per_pixel <= 24) {		/* RGB 888 */
1285c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->bits_per_pixel = 24;
1286c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->red.offset = 16;
1287c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->red.length = 8;
1288c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->green.offset = 8;
1289c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->green.length = 8;
1290c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->blue.offset = 0;
1291c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->blue.length = 8;
1292c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->transp.offset = 0;
1293c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->transp.length = 0;
1294c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		} else if (var->bits_per_pixel <= 32) {		/* RGBA 888 */
1295c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->bits_per_pixel = 32;
1296c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->red.offset = 16;
1297c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->red.length = 8;
1298c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->green.offset = 8;
1299c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->green.length = 8;
1300c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->blue.offset = 0;
1301c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->blue.length = 8;
1302c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->transp.offset = 24;
1303c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			var->transp.length = 8;
1304c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		} else
1305c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			return -EINVAL;
1306c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1307c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		var->red.msb_right = 0;
1308c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		var->green.msb_right = 0;
1309c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		var->blue.msb_right = 0;
1310c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		var->transp.msb_right = 0;
1311c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1312c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1313c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Make sure we don't exceed our allocated memory. */
1314c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 >
1315c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	    info->fix.smem_len)
1316c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1317c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1318c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return 0;
1319c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1320c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1321c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart/* -----------------------------------------------------------------------------
1322c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * Frame buffer operations - Overlays
1323c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart */
1324c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1325c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic ssize_t
1326c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartoverlay_alpha_show(struct device *dev, struct device_attribute *attr, char *buf)
1327c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1328c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = dev_get_drvdata(dev);
1329c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1330c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1331c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return scnprintf(buf, PAGE_SIZE, "%u\n", ovl->alpha);
1332c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1333c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1334c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic ssize_t
1335c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartoverlay_alpha_store(struct device *dev, struct device_attribute *attr,
1336c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		    const char *buf, size_t count)
1337c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1338c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = dev_get_drvdata(dev);
1339c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1340c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned int alpha;
1341c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	char *endp;
1342c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1343c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	alpha = simple_strtoul(buf, &endp, 10);
1344c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (isspace(*endp))
1345c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		endp++;
1346c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1347c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (endp - buf != count)
1348c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1349c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1350c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (alpha > 255)
1351c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1352c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1353c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ovl->alpha != alpha) {
1354c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->alpha = alpha;
1355c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1356c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (ovl->mode == LCDC_OVERLAY_BLEND && ovl->enabled)
1357c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			sh_mobile_lcdc_overlay_setup(ovl);
1358c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1359c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1360c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return count;
1361c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1362c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1363c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic ssize_t
1364c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartoverlay_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
1365c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1366c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = dev_get_drvdata(dev);
1367c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1368c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1369c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return scnprintf(buf, PAGE_SIZE, "%u\n", ovl->mode);
1370c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1371c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1372c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic ssize_t
1373c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartoverlay_mode_store(struct device *dev, struct device_attribute *attr,
1374c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		   const char *buf, size_t count)
1375c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1376c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = dev_get_drvdata(dev);
1377c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1378c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned int mode;
1379c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	char *endp;
1380c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1381c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	mode = simple_strtoul(buf, &endp, 10);
1382c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (isspace(*endp))
1383c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		endp++;
1384c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1385c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (endp - buf != count)
1386c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1387c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1388c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (mode != LCDC_OVERLAY_BLEND && mode != LCDC_OVERLAY_ROP3)
1389c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1390c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1391c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ovl->mode != mode) {
1392c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->mode = mode;
1393c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1394c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (ovl->enabled)
1395c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			sh_mobile_lcdc_overlay_setup(ovl);
1396c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1397c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1398c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return count;
1399c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1400c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1401c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic ssize_t
1402c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartoverlay_position_show(struct device *dev, struct device_attribute *attr,
1403c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		      char *buf)
1404c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1405c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = dev_get_drvdata(dev);
1406c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1407c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1408c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return scnprintf(buf, PAGE_SIZE, "%d,%d\n", ovl->pos_x, ovl->pos_y);
1409c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1410c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1411c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic ssize_t
1412c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartoverlay_position_store(struct device *dev, struct device_attribute *attr,
1413c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		       const char *buf, size_t count)
1414c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1415c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = dev_get_drvdata(dev);
1416c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1417c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	char *endp;
1418c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	int pos_x;
1419c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	int pos_y;
1420c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1421c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	pos_x = simple_strtol(buf, &endp, 10);
1422c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (*endp != ',')
1423c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1424c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1425c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	pos_y = simple_strtol(endp + 1, &endp, 10);
1426c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (isspace(*endp))
1427c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		endp++;
1428c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1429c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (endp - buf != count)
1430c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1431c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1432c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ovl->pos_x != pos_x || ovl->pos_y != pos_y) {
1433c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->pos_x = pos_x;
1434c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->pos_y = pos_y;
1435c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1436c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (ovl->enabled)
1437c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			sh_mobile_lcdc_overlay_setup(ovl);
1438c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1439c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1440c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return count;
1441c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1442c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1443c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic ssize_t
1444c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartoverlay_rop3_show(struct device *dev, struct device_attribute *attr, char *buf)
1445c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1446c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = dev_get_drvdata(dev);
1447c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1448c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1449c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return scnprintf(buf, PAGE_SIZE, "%u\n", ovl->rop3);
1450c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1451c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1452c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic ssize_t
1453c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartoverlay_rop3_store(struct device *dev, struct device_attribute *attr,
1454c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		    const char *buf, size_t count)
1455c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1456c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = dev_get_drvdata(dev);
1457c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1458c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned int rop3;
1459c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	char *endp;
1460c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1461c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	rop3 = !!simple_strtoul(buf, &endp, 10);
1462c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (isspace(*endp))
1463c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		endp++;
1464c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1465c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (endp - buf != count)
1466c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1467c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1468c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (rop3 > 255)
1469c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
1470c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1471c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ovl->rop3 != rop3) {
1472c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->rop3 = rop3;
1473c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1474c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (ovl->mode == LCDC_OVERLAY_ROP3 && ovl->enabled)
1475c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			sh_mobile_lcdc_overlay_setup(ovl);
1476c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1477c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1478c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return count;
1479c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1480c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1481c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic const struct device_attribute overlay_sysfs_attrs[] = {
1482c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	__ATTR(ovl_alpha, S_IRUGO|S_IWUSR,
1483c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	       overlay_alpha_show, overlay_alpha_store),
1484c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	__ATTR(ovl_mode, S_IRUGO|S_IWUSR,
1485c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	       overlay_mode_show, overlay_mode_store),
1486c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	__ATTR(ovl_position, S_IRUGO|S_IWUSR,
1487c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	       overlay_position_show, overlay_position_store),
1488c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	__ATTR(ovl_rop3, S_IRUGO|S_IWUSR,
1489c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	       overlay_rop3_show, overlay_rop3_store),
1490c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart};
1491c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1492c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic const struct fb_fix_screeninfo sh_mobile_lcdc_overlay_fix  = {
1493c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.id =		"SH Mobile LCDC",
1494c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.type =		FB_TYPE_PACKED_PIXELS,
1495c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.visual =	FB_VISUAL_TRUECOLOR,
1496c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.accel =	FB_ACCEL_NONE,
149715dede882e564601947f2ce4b647742c0351be6dLaurent Pinchart	.xpanstep =	1,
1498c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.ypanstep =	1,
1499c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.ywrapstep =	0,
1500c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.capabilities =	FB_CAP_FOURCC,
1501c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart};
1502c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1503c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic int sh_mobile_lcdc_overlay_pan(struct fb_var_screeninfo *var,
1504c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart				    struct fb_info *info)
1505c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1506c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1507c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned long base_addr_y;
1508c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned long base_addr_c;
1509a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	unsigned long y_offset;
1510c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned long c_offset;
1511c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1512a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	if (!ovl->format->yuv) {
1513a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		y_offset = (var->yoffset * ovl->xres_virtual + var->xoffset)
1514a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart			 * ovl->format->bpp / 8;
1515a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		c_offset = 0;
1516a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	} else {
1517a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		unsigned int xsub = ovl->format->bpp < 24 ? 2 : 1;
1518a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		unsigned int ysub = ovl->format->bpp < 16 ? 2 : 1;
1519a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart
1520a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		y_offset = var->yoffset * ovl->xres_virtual + var->xoffset;
1521a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		c_offset = var->yoffset / ysub * ovl->xres_virtual * 2 / xsub
1522a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart			 + var->xoffset * 2 / xsub;
1523a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	}
1524c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1525a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	/* If the Y offset hasn't changed, the C offset hasn't either. There's
1526a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	 * nothing to do in that case.
1527a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	 */
1528a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	if (y_offset == ovl->pan_y_offset)
1529a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		return 0;
1530c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1531c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Set the source address for the next refresh */
1532a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	base_addr_y = ovl->dma_handle + y_offset;
1533a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	base_addr_c = ovl->dma_handle + ovl->xres_virtual * ovl->yres_virtual
1534a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		    + c_offset;
1535c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1536c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->base_addr_y = base_addr_y;
1537a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	ovl->base_addr_c = base_addr_c;
1538a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	ovl->pan_y_offset = y_offset;
1539c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
15408be7c66995bf06769dc4c5f7a62f3cd62a627e7eLaurent Pinchart	lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index));
15418be7c66995bf06769dc4c5f7a62f3cd62a627e7eLaurent Pinchart
1542c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write_overlay(ovl, LDBnBSAYR(ovl->index), ovl->base_addr_y);
1543c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	lcdc_write_overlay(ovl, LDBnBSACR(ovl->index), ovl->base_addr_c);
1544c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
15458be7c66995bf06769dc4c5f7a62f3cd62a627e7eLaurent Pinchart	lcdc_write(ovl->channel->lcdc, LDBCR,
15468be7c66995bf06769dc4c5f7a62f3cd62a627e7eLaurent Pinchart		   LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index));
15478be7c66995bf06769dc4c5f7a62f3cd62a627e7eLaurent Pinchart
1548c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return 0;
1549c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1550c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1551c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic int sh_mobile_lcdc_overlay_ioctl(struct fb_info *info, unsigned int cmd,
1552c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart				      unsigned long arg)
1553c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1554c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1555c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1556c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	switch (cmd) {
1557c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	case FBIO_WAITFORVSYNC:
1558c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return sh_mobile_lcdc_wait_for_vsync(ovl->channel);
1559c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1560c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	default:
1561c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -ENOIOCTLCMD;
1562c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1563c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1564c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1565c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic int sh_mobile_lcdc_overlay_check_var(struct fb_var_screeninfo *var,
1566c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart					  struct fb_info *info)
1567c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1568c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return __sh_mobile_lcdc_check_var(var, info);
1569c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1570c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1571c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic int sh_mobile_lcdc_overlay_set_par(struct fb_info *info)
1572c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1573c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1574c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1575c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->format =
1576c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		sh_mobile_format_info(sh_mobile_format_fourcc(&info->var));
1577c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1578c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->xres = info->var.xres;
1579c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->xres_virtual = info->var.xres_virtual;
1580c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->yres = info->var.yres;
1581c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->yres_virtual = info->var.yres_virtual;
1582c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1583c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ovl->format->yuv)
158416ca21c9a9f64577221c47d8d2f00d13b880aefaLaurent Pinchart		ovl->pitch = info->var.xres_virtual;
1585c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	else
158616ca21c9a9f64577221c47d8d2f00d13b880aefaLaurent Pinchart		ovl->pitch = info->var.xres_virtual * ovl->format->bpp / 8;
1587c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1588c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	sh_mobile_lcdc_overlay_setup(ovl);
1589c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1590c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->fix.line_length = ovl->pitch;
1591c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1592c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (sh_mobile_format_is_fourcc(&info->var)) {
1593c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		info->fix.type = FB_TYPE_FOURCC;
1594c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		info->fix.visual = FB_VISUAL_FOURCC;
1595c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	} else {
1596c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		info->fix.type = FB_TYPE_PACKED_PIXELS;
1597c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		info->fix.visual = FB_VISUAL_TRUECOLOR;
1598c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1599c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1600c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return 0;
1601c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1602c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1603c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart/* Overlay blanking. Disable the overlay when blanked. */
1604c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic int sh_mobile_lcdc_overlay_blank(int blank, struct fb_info *info)
1605c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1606c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_overlay *ovl = info->par;
1607c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1608c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->enabled = !blank;
1609c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	sh_mobile_lcdc_overlay_setup(ovl);
1610c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1611c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Prevent the backlight from receiving a blanking event by returning
1612c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 * a non-zero value.
1613c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 */
1614c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return 1;
1615c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1616c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1617bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKUstatic int
1618bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKUsh_mobile_lcdc_overlay_mmap(struct fb_info *info, struct vm_area_struct *vma)
1619bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU{
1620bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU	struct sh_mobile_lcdc_overlay *ovl = info->par;
1621bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU
1622bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU	return dma_mmap_coherent(ovl->channel->lcdc->dev, vma, ovl->fb_mem,
1623bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU				 ovl->dma_handle, ovl->fb_size);
1624bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU}
1625bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU
1626c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic struct fb_ops sh_mobile_lcdc_overlay_ops = {
1627c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.owner          = THIS_MODULE,
1628c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_read        = fb_sys_read,
1629c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_write       = fb_sys_write,
1630c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_fillrect	= sys_fillrect,
1631c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_copyarea	= sys_copyarea,
1632c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_imageblit	= sys_imageblit,
1633c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_blank	= sh_mobile_lcdc_overlay_blank,
1634c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_pan_display = sh_mobile_lcdc_overlay_pan,
1635c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_ioctl       = sh_mobile_lcdc_overlay_ioctl,
1636c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_check_var	= sh_mobile_lcdc_overlay_check_var,
1637c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	.fb_set_par	= sh_mobile_lcdc_overlay_set_par,
1638bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU	.fb_mmap	= sh_mobile_lcdc_overlay_mmap,
1639c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart};
1640c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1641c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic void
1642c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartsh_mobile_lcdc_overlay_fb_unregister(struct sh_mobile_lcdc_overlay *ovl)
1643c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1644c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = ovl->info;
1645c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1646c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (info == NULL || info->dev == NULL)
1647c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return;
1648c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1649c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unregister_framebuffer(ovl->info);
1650c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1651c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1652c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic int __devinit
1653c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartsh_mobile_lcdc_overlay_fb_register(struct sh_mobile_lcdc_overlay *ovl)
1654c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1655c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_priv *lcdc = ovl->channel->lcdc;
1656c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = ovl->info;
1657c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned int i;
1658c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	int ret;
1659c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1660c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (info == NULL)
1661c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return 0;
1662c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1663c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ret = register_framebuffer(info);
1664c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ret < 0)
1665c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return ret;
1666c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1667c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	dev_info(lcdc->dev, "registered %s/overlay %u as %dx%d %dbpp.\n",
1668c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		 dev_name(lcdc->dev), ovl->index, info->var.xres,
1669c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		 info->var.yres, info->var.bits_per_pixel);
1670c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1671c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(overlay_sysfs_attrs); ++i) {
1672c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ret = device_create_file(info->dev, &overlay_sysfs_attrs[i]);
1673c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (ret < 0)
1674c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			return ret;
1675c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1676c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1677c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return 0;
1678c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1679c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1680c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic void
1681c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartsh_mobile_lcdc_overlay_fb_cleanup(struct sh_mobile_lcdc_overlay *ovl)
1682c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1683c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info = ovl->info;
1684c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1685c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (info == NULL || info->device == NULL)
1686c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return;
1687c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1688c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	framebuffer_release(info);
1689c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1690c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1691c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic int __devinit
1692c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartsh_mobile_lcdc_overlay_fb_init(struct sh_mobile_lcdc_overlay *ovl)
1693c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
1694c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct sh_mobile_lcdc_priv *priv = ovl->channel->lcdc;
1695c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_var_screeninfo *var;
1696c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	struct fb_info *info;
1697c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1698c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Allocate and initialize the frame buffer device. */
1699c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info = framebuffer_alloc(0, priv->dev);
1700c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (info == NULL) {
1701c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		dev_err(priv->dev, "unable to allocate fb_info\n");
1702c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -ENOMEM;
1703c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
1704c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1705c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->info = info;
1706c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1707c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->flags = FBINFO_FLAG_DEFAULT;
1708c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->fbops = &sh_mobile_lcdc_overlay_ops;
1709c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->device = priv->dev;
1710c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->screen_base = ovl->fb_mem;
1711c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->par = ovl;
1712c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1713c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Initialize fixed screen information. Restrict pan to 2 lines steps
1714c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 * for NV12 and NV21.
1715c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 */
1716c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->fix = sh_mobile_lcdc_overlay_fix;
1717c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	snprintf(info->fix.id, sizeof(info->fix.id),
1718c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		 "SH Mobile LCDC Overlay %u", ovl->index);
1719c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->fix.smem_start = ovl->dma_handle;
1720c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->fix.smem_len = ovl->fb_size;
1721c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	info->fix.line_length = ovl->pitch;
1722c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1723c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ovl->format->yuv)
1724c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		info->fix.visual = FB_VISUAL_FOURCC;
1725c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	else
1726c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		info->fix.visual = FB_VISUAL_TRUECOLOR;
1727c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
172815dede882e564601947f2ce4b647742c0351be6dLaurent Pinchart	switch (ovl->format->fourcc) {
172915dede882e564601947f2ce4b647742c0351be6dLaurent Pinchart	case V4L2_PIX_FMT_NV12:
173015dede882e564601947f2ce4b647742c0351be6dLaurent Pinchart	case V4L2_PIX_FMT_NV21:
1731ac33a207b13a70bbca6e58094e28bd92b9fc1ff3Laurent Pinchart		info->fix.ypanstep = 2;
1732ac33a207b13a70bbca6e58094e28bd92b9fc1ff3Laurent Pinchart	case V4L2_PIX_FMT_NV16:
1733ac33a207b13a70bbca6e58094e28bd92b9fc1ff3Laurent Pinchart	case V4L2_PIX_FMT_NV61:
173415dede882e564601947f2ce4b647742c0351be6dLaurent Pinchart		info->fix.xpanstep = 2;
173515dede882e564601947f2ce4b647742c0351be6dLaurent Pinchart	}
1736c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1737c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Initialize variable screen information. */
1738c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	var = &info->var;
1739c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	memset(var, 0, sizeof(*var));
1740c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	var->xres = ovl->xres;
1741c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	var->yres = ovl->yres;
1742c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	var->xres_virtual = ovl->xres_virtual;
1743c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	var->yres_virtual = ovl->yres_virtual;
1744c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	var->activate = FB_ACTIVATE_NOW;
1745c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1746c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Use the legacy API by default for RGB formats, and the FOURCC API
1747c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 * for YUV formats.
1748c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 */
1749c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (!ovl->format->yuv)
1750c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		var->bits_per_pixel = ovl->format->bpp;
1751c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	else
1752c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		var->grayscale = ovl->format->fourcc;
1753c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1754c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return sh_mobile_lcdc_overlay_check_var(var, info);
1755c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
1756c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
1757f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
1758c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart * Frame buffer operations - main frame buffer
1759f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
1760cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1761cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_setcolreg(u_int regno,
1762cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm				    u_int red, u_int green, u_int blue,
1763cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm				    u_int transp, struct fb_info *info)
1764cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
1765cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	u32 *palette = info->pseudo_palette;
1766cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1767cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (regno >= PALETTE_NR)
1768cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		return -EINVAL;
1769cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1770cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	/* only FB_VISUAL_TRUECOLOR supported */
1771cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1772cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	red >>= 16 - info->var.red.length;
1773cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	green >>= 16 - info->var.green.length;
1774cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	blue >>= 16 - info->var.blue.length;
1775cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	transp >>= 16 - info->var.transp.length;
1776cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1777cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	palette[regno] = (red << info->var.red.offset) |
1778cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	  (green << info->var.green.offset) |
1779cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	  (blue << info->var.blue.offset) |
1780cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	  (transp << info->var.transp.offset);
1781cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1782cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	return 0;
1783cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
1784cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
17853281e54c80195b90ed12a5b6cddef4ab42e656e1Laurent Pinchartstatic const struct fb_fix_screeninfo sh_mobile_lcdc_fix  = {
1786cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.id =		"SH Mobile LCDC",
1787cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.type =		FB_TYPE_PACKED_PIXELS,
1788cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.visual =	FB_VISUAL_TRUECOLOR,
1789cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.accel =	FB_ACCEL_NONE,
179015dede882e564601947f2ce4b647742c0351be6dLaurent Pinchart	.xpanstep =	1,
17919dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	.ypanstep =	1,
17929dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	.ywrapstep =	0,
1793edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	.capabilities =	FB_CAP_FOURCC,
1794cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm};
1795cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
17968564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_fillrect(struct fb_info *info,
17978564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm				    const struct fb_fillrect *rect)
17988564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{
17998564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sys_fillrect(info, rect);
18008564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sh_mobile_lcdc_deferred_io_touch(info);
18018564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
18028564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
18038564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_copyarea(struct fb_info *info,
18048564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm				    const struct fb_copyarea *area)
18058564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{
18068564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sys_copyarea(info, area);
18078564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sh_mobile_lcdc_deferred_io_touch(info);
18088564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
18098564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
18108564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_imageblit(struct fb_info *info,
18118564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm				     const struct fb_image *image)
18128564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{
18138564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sys_imageblit(info, image);
18148564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sh_mobile_lcdc_deferred_io_touch(info);
18158564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
18168564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
1817d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchartstatic int sh_mobile_lcdc_pan(struct fb_var_screeninfo *var,
1818d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart			      struct fb_info *info)
18199dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy{
18209dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	struct sh_mobile_lcdc_chan *ch = info->par;
182192e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	struct sh_mobile_lcdc_priv *priv = ch->lcdc;
182292e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	unsigned long ldrcntr;
1823a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	unsigned long base_addr_y, base_addr_c;
1824a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	unsigned long y_offset;
182553b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia	unsigned long c_offset;
182692e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy
1827a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	if (!ch->format->yuv) {
1828a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		y_offset = (var->yoffset * ch->xres_virtual + var->xoffset)
1829a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart			 * ch->format->bpp / 8;
1830a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		c_offset = 0;
1831a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	} else {
1832a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		unsigned int xsub = ch->format->bpp < 24 ? 2 : 1;
1833a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		unsigned int ysub = ch->format->bpp < 16 ? 2 : 1;
18349dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
1835a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		y_offset = var->yoffset * ch->xres_virtual + var->xoffset;
1836a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		c_offset = var->yoffset / ysub * ch->xres_virtual * 2 / xsub
1837a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart			 + var->xoffset * 2 / xsub;
1838a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	}
18399dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
1840a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	/* If the Y offset hasn't changed, the C offset hasn't either. There's
1841a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	 * nothing to do in that case.
1842a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	 */
1843a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	if (y_offset == ch->pan_y_offset)
1844a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		return 0;
18459dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
184692e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	/* Set the source address for the next refresh */
1847a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	base_addr_y = ch->dma_handle + y_offset;
1848a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	base_addr_c = ch->dma_handle + ch->xres_virtual * ch->yres_virtual
1849a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart		    + c_offset;
185053b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia
18516e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart	if (ch->cache)
18526e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart		sh_mobile_meram_cache_update(priv->meram_dev, ch->cache,
18536e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart					     base_addr_y, base_addr_c,
18546e729b416b44296f5ed503b40ac58c2bffb43cafLaurent Pinchart					     &base_addr_y, &base_addr_c);
18557caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
185649d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart	ch->base_addr_y = base_addr_y;
185749d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart	ch->base_addr_c = base_addr_c;
1858a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	ch->pan_y_offset = y_offset;
18597caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
186049d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart	lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);
186158f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	if (ch->format->yuv)
186249d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart		lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c);
186353b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia
1864a4aa25f6e7885a42c90fe5f0a965403df6cbc943Laurent Pinchart	ldrcntr = lcdc_read(priv, _LDRCNTR);
186592e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	if (lcdc_chan_is_sublcd(ch))
186692e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy		lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS);
186792e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	else
186892e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy		lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_MRS);
186992e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy
187092e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy
187192e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	sh_mobile_lcdc_deferred_io_touch(info);
18729dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
18739dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	return 0;
18749dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy}
18759dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
1876d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchartstatic int sh_mobile_lcdc_ioctl(struct fb_info *info, unsigned int cmd,
1877d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart				unsigned long arg)
187840331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy{
1879d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart	struct sh_mobile_lcdc_chan *ch = info->par;
188040331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	int retval;
188140331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy
188240331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	switch (cmd) {
188340331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	case FBIO_WAITFORVSYNC:
1884d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart		retval = sh_mobile_lcdc_wait_for_vsync(ch);
188540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy		break;
188640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy
188740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	default:
188840331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy		retval = -ENOIOCTLCMD;
188940331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy		break;
189040331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	}
189140331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	return retval;
189240331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy}
189340331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy
1894dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetskistatic void sh_mobile_fb_reconfig(struct fb_info *info)
1895dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{
1896dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	struct sh_mobile_lcdc_chan *ch = info->par;
18972d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	struct fb_var_screeninfo var;
18982d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	struct fb_videomode mode;
1899dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	struct fb_event event;
1900dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	int evnt = FB_EVENT_MODE_CHANGE_ALL;
1901dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1902dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	if (ch->use_count > 1 || (ch->use_count == 1 && !info->fbcon_par))
1903dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		/* More framebuffer users are active */
1904dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		return;
1905dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
19062d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	fb_var_to_videomode(&mode, &info->var);
1907dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
19082d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	if (fb_mode_is_equal(&ch->display.mode, &mode))
1909dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		return;
1910dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1911dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	/* Display has been re-plugged, framebuffer is free now, reconfigure */
19122d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	var = info->var;
19132d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	fb_videomode_to_var(&var, &ch->display.mode);
19142d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	var.width = ch->display.width;
19152d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	var.height = ch->display.height;
19162d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	var.activate = FB_ACTIVATE_NOW;
19172d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart
19182d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	if (fb_set_var(info, &var) < 0)
1919dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		/* Couldn't reconfigure, hopefully, can continue as before */
1920dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		return;
1921dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1922dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	/*
1923dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	 * fb_set_var() calls the notifier change internally, only if
1924dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	 * FBINFO_MISC_USEREVENT flag is set. Since we do not want to fake a
1925dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	 * user event, we have to call the chain ourselves.
1926dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	 */
1927dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	event.info = info;
19282d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	event.data = &ch->display.mode;
1929dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	fb_notifier_call_chain(evnt, &event);
1930dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski}
1931dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1932dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski/*
1933dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski * Locking: both .fb_release() and .fb_open() are called with info->lock held if
1934dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski * user == 1, or with console sem held, if user == 0.
1935dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski */
1936d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchartstatic int sh_mobile_lcdc_release(struct fb_info *info, int user)
1937dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{
1938dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	struct sh_mobile_lcdc_chan *ch = info->par;
1939dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1940dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	mutex_lock(&ch->open_lock);
1941dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count);
1942dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1943dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	ch->use_count--;
1944dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1945dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	/* Nothing to reconfigure, when called from fbcon */
1946dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	if (user) {
1947ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn		console_lock();
1948dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		sh_mobile_fb_reconfig(info);
1949ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn		console_unlock();
1950dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	}
1951dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1952dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	mutex_unlock(&ch->open_lock);
1953dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1954dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	return 0;
1955dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski}
1956dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1957d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchartstatic int sh_mobile_lcdc_open(struct fb_info *info, int user)
1958dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{
1959dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	struct sh_mobile_lcdc_chan *ch = info->par;
1960dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1961dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	mutex_lock(&ch->open_lock);
1962dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	ch->use_count++;
1963dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1964dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count);
1965dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	mutex_unlock(&ch->open_lock);
1966dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1967dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	return 0;
1968dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski}
1969dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1970d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchartstatic int sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var,
1971d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart				    struct fb_info *info)
1972dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{
1973dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	struct sh_mobile_lcdc_chan *ch = info->par;
1974417d48274e755e537bae60461558c1f63a4e14deMagnus Damm	struct sh_mobile_lcdc_priv *p = ch->lcdc;
19750386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	unsigned int best_dist = (unsigned int)-1;
19760386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	unsigned int best_xres = 0;
19770386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	unsigned int best_yres = 0;
19780386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	unsigned int i;
1979c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	int ret;
19800386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
19810386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	/* If board code provides us with a list of available modes, make sure
19820386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	 * we use one of them. Find the mode closest to the requested one. The
19830386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	 * distance between two modes is defined as the size of the
19840386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	 * non-overlapping parts of the two rectangles.
19850386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	 */
1986b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	for (i = 0; i < ch->cfg->num_modes; ++i) {
1987b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		const struct fb_videomode *mode = &ch->cfg->lcd_modes[i];
19880386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		unsigned int dist;
19890386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
19900386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		/* We can only round up. */
19910386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		if (var->xres > mode->xres || var->yres > mode->yres)
19920386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			continue;
19930386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
19940386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		dist = var->xres * var->yres + mode->xres * mode->yres
19950386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		     - 2 * min(var->xres, mode->xres)
19960386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			 * min(var->yres, mode->yres);
19970386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
19980386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		if (dist < best_dist) {
19990386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			best_xres = mode->xres;
20000386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			best_yres = mode->yres;
20010386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			best_dist = dist;
20020386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		}
2003dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	}
2004417d48274e755e537bae60461558c1f63a4e14deMagnus Damm
20050386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	/* If no available mode can be used, return an error. */
2006b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	if (ch->cfg->num_modes != 0) {
20070386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		if (best_dist == (unsigned int)-1)
20080386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			return -EINVAL;
20090386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
20100386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		var->xres = best_xres;
20110386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		var->yres = best_yres;
20120386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	}
20130386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
2014c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ret = __sh_mobile_lcdc_check_var(var, info);
2015c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ret < 0)
2016c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return ret;
20170386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
2018edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	/* only accept the forced_fourcc for dual channel configurations */
2019edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	if (p->forced_fourcc &&
2020edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	    p->forced_fourcc != sh_mobile_format_fourcc(var))
2021417d48274e755e537bae60461558c1f63a4e14deMagnus Damm		return -EINVAL;
2022417d48274e755e537bae60461558c1f63a4e14deMagnus Damm
2023dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	return 0;
2024dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski}
202540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy
2026d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchartstatic int sh_mobile_lcdc_set_par(struct fb_info *info)
2027ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart{
2028ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart	struct sh_mobile_lcdc_chan *ch = info->par;
2029ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart	int ret;
2030ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart
2031ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart	sh_mobile_lcdc_stop(ch->lcdc);
203291fba48d59666718e3d3e86964755b80d39cdbddLaurent Pinchart
2033fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart	ch->format = sh_mobile_format_info(sh_mobile_format_fourcc(&info->var));
203458f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->colorspace = info->var.colorspace;
203558f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
203658f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->xres = info->var.xres;
203758f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->xres_virtual = info->var.xres_virtual;
203858f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->yres = info->var.yres;
203958f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->yres_virtual = info->var.yres_virtual;
204058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
204158f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	if (ch->format->yuv)
204216ca21c9a9f64577221c47d8d2f00d13b880aefaLaurent Pinchart		ch->pitch = info->var.xres_virtual;
204358f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	else
204416ca21c9a9f64577221c47d8d2f00d13b880aefaLaurent Pinchart		ch->pitch = info->var.xres_virtual * ch->format->bpp / 8;
2045fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart
2046ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart	ret = sh_mobile_lcdc_start(ch->lcdc);
204758f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	if (ret < 0)
2048ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart		dev_err(info->dev, "%s: unable to restart LCDC\n", __func__);
204958f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
205058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	info->fix.line_length = ch->pitch;
2051ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart
2052edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	if (sh_mobile_format_is_fourcc(&info->var)) {
2053edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		info->fix.type = FB_TYPE_FOURCC;
2054edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		info->fix.visual = FB_VISUAL_FOURCC;
2055edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	} else {
2056edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		info->fix.type = FB_TYPE_PACKED_PIXELS;
2057edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		info->fix.visual = FB_VISUAL_TRUECOLOR;
2058edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	}
2059edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart
2060ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart	return ret;
2061ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart}
2062ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart
20638857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot/*
20648857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * Screen blanking. Behavior is as follows:
20658857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_UNBLANK: screen unblanked, clocks enabled
20668857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_NORMAL: screen blanked, clocks enabled
20678857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_VSYNC,
20688857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_HSYNC,
20698857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_POWEROFF: screen blanked, clocks disabled
20708857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot */
20718857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbotstatic int sh_mobile_lcdc_blank(int blank, struct fb_info *info)
20728857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot{
20738857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	struct sh_mobile_lcdc_chan *ch = info->par;
20748857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	struct sh_mobile_lcdc_priv *p = ch->lcdc;
20758857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot
20768857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	/* blank the screen? */
20778857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	if (blank > FB_BLANK_UNBLANK && ch->blank_status == FB_BLANK_UNBLANK) {
20788857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		struct fb_fillrect rect = {
207958f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart			.width = ch->xres,
208058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart			.height = ch->yres,
20818857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		};
20828857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		sh_mobile_lcdc_fillrect(info, &rect);
20838857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	}
20848857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	/* turn clocks on? */
20858857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	if (blank <= FB_BLANK_NORMAL && ch->blank_status > FB_BLANK_NORMAL) {
20868857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		sh_mobile_lcdc_clk_on(p);
20878857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	}
20888857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	/* turn clocks off? */
20898857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	if (blank > FB_BLANK_NORMAL && ch->blank_status <= FB_BLANK_NORMAL) {
20908857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		/* make sure the screen is updated with the black fill before
20918857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		 * switching the clocks off. one vsync is not enough since
20928857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		 * blanking may occur in the middle of a refresh. deferred io
20938857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		 * mode will reenable the clocks and update the screen in time,
20948857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		 * so it does not need this. */
20958857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		if (!info->fbdefio) {
2096d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart			sh_mobile_lcdc_wait_for_vsync(ch);
2097d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart			sh_mobile_lcdc_wait_for_vsync(ch);
20988857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		}
20998857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		sh_mobile_lcdc_clk_off(p);
21008857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	}
21018857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot
21028857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	ch->blank_status = blank;
21038857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	return 0;
21048857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot}
21058857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot
2106bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKUstatic int
2107bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKUsh_mobile_lcdc_mmap(struct fb_info *info, struct vm_area_struct *vma)
2108bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU{
2109bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU	struct sh_mobile_lcdc_chan *ch = info->par;
2110bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU
2111bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU	return dma_mmap_coherent(ch->lcdc->dev, vma, ch->fb_mem,
2112bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU				 ch->dma_handle, ch->fb_size);
2113bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU}
2114bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU
2115cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic struct fb_ops sh_mobile_lcdc_ops = {
21169dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	.owner          = THIS_MODULE,
2117cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.fb_setcolreg	= sh_mobile_lcdc_setcolreg,
21182540c111ead82cad605ec2b14a1905ad914cc124Magnus Damm	.fb_read        = fb_sys_read,
21192540c111ead82cad605ec2b14a1905ad914cc124Magnus Damm	.fb_write       = fb_sys_write,
21208564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	.fb_fillrect	= sh_mobile_lcdc_fillrect,
21218564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	.fb_copyarea	= sh_mobile_lcdc_copyarea,
21228564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	.fb_imageblit	= sh_mobile_lcdc_imageblit,
21238857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	.fb_blank	= sh_mobile_lcdc_blank,
2124d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart	.fb_pan_display = sh_mobile_lcdc_pan,
2125d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart	.fb_ioctl       = sh_mobile_lcdc_ioctl,
2126d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart	.fb_open	= sh_mobile_lcdc_open,
2127d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart	.fb_release	= sh_mobile_lcdc_release,
2128d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart	.fb_check_var	= sh_mobile_lcdc_check_var,
2129d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart	.fb_set_par	= sh_mobile_lcdc_set_par,
2130bf10a53765b4435a5349a92a5a51753902ed86f1Hideki EIRAKU	.fb_mmap	= sh_mobile_lcdc_mmap,
2131cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm};
2132cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2133a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartstatic void
2134a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartsh_mobile_lcdc_channel_fb_unregister(struct sh_mobile_lcdc_chan *ch)
2135a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart{
2136a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (ch->info && ch->info->dev)
2137a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		unregister_framebuffer(ch->info);
2138a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart}
2139a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2140a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartstatic int __devinit
2141a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartsh_mobile_lcdc_channel_fb_register(struct sh_mobile_lcdc_chan *ch)
2142a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart{
2143a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	struct fb_info *info = ch->info;
2144a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	int ret;
2145a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2146a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (info->fbdefio) {
2147a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		ch->sglist = vmalloc(sizeof(struct scatterlist) *
2148a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart				     ch->fb_size >> PAGE_SHIFT);
2149a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		if (!ch->sglist) {
2150a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart			dev_err(ch->lcdc->dev, "cannot allocate sglist\n");
2151a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart			return -ENOMEM;
2152a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		}
2153a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	}
2154a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2155a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->bl_dev = ch->bl;
2156a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2157a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ret = register_framebuffer(info);
2158a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (ret < 0)
2159a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		return ret;
2160a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2161a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	dev_info(ch->lcdc->dev, "registered %s/%s as %dx%d %dbpp.\n",
2162b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		 dev_name(ch->lcdc->dev), (ch->cfg->chan == LCDC_CHAN_MAINLCD) ?
2163a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		 "mainlcd" : "sublcd", info->var.xres, info->var.yres,
2164a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		 info->var.bits_per_pixel);
2165a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2166a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	/* deferred io mode: disable clock to save power */
2167a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED)
2168a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		sh_mobile_lcdc_clk_off(ch->lcdc);
2169a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2170a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	return ret;
2171a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart}
2172a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2173a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartstatic void
2174a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartsh_mobile_lcdc_channel_fb_cleanup(struct sh_mobile_lcdc_chan *ch)
2175a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart{
2176a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	struct fb_info *info = ch->info;
2177a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2178a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (!info || !info->device)
2179a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		return;
2180a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2181a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (ch->sglist)
2182a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		vfree(ch->sglist);
2183a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2184a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	fb_dealloc_cmap(&info->cmap);
2185a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	framebuffer_release(info);
2186a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart}
2187a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2188a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartstatic int __devinit
2189a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartsh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch,
2190352d6138779e22c5340803d5a32fc332ad2e5e1dLaurent Pinchart			       const struct fb_videomode *modes,
2191a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart			       unsigned int num_modes)
2192a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart{
2193a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	struct sh_mobile_lcdc_priv *priv = ch->lcdc;
2194a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	struct fb_var_screeninfo *var;
2195a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	struct fb_info *info;
2196a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	int ret;
2197a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2198a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	/* Allocate and initialize the frame buffer device. Create the modes
2199a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 * list and allocate the color map.
2200a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 */
2201a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info = framebuffer_alloc(0, priv->dev);
2202a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (info == NULL) {
2203a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		dev_err(priv->dev, "unable to allocate fb_info\n");
2204a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		return -ENOMEM;
2205a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	}
2206a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2207a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ch->info = info;
2208a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2209a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->flags = FBINFO_FLAG_DEFAULT;
2210a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->fbops = &sh_mobile_lcdc_ops;
2211a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->device = priv->dev;
2212a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->screen_base = ch->fb_mem;
2213a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->pseudo_palette = &ch->pseudo_palette;
2214a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->par = ch;
2215a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2216352d6138779e22c5340803d5a32fc332ad2e5e1dLaurent Pinchart	fb_videomode_to_modelist(modes, num_modes, &info->modelist);
2217a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2218a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);
2219a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (ret < 0) {
2220a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		dev_err(priv->dev, "unable to allocate cmap\n");
2221a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		return ret;
2222a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	}
2223a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2224a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	/* Initialize fixed screen information. Restrict pan to 2 lines steps
2225a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 * for NV12 and NV21.
2226a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 */
2227a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->fix = sh_mobile_lcdc_fix;
2228a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->fix.smem_start = ch->dma_handle;
2229a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->fix.smem_len = ch->fb_size;
223058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	info->fix.line_length = ch->pitch;
223158f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
223258f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	if (ch->format->yuv)
223358f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		info->fix.visual = FB_VISUAL_FOURCC;
223458f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	else
223558f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		info->fix.visual = FB_VISUAL_TRUECOLOR;
223658f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
223715dede882e564601947f2ce4b647742c0351be6dLaurent Pinchart	switch (ch->format->fourcc) {
223815dede882e564601947f2ce4b647742c0351be6dLaurent Pinchart	case V4L2_PIX_FMT_NV12:
223915dede882e564601947f2ce4b647742c0351be6dLaurent Pinchart	case V4L2_PIX_FMT_NV21:
2240ac33a207b13a70bbca6e58094e28bd92b9fc1ff3Laurent Pinchart		info->fix.ypanstep = 2;
2241ac33a207b13a70bbca6e58094e28bd92b9fc1ff3Laurent Pinchart	case V4L2_PIX_FMT_NV16:
2242ac33a207b13a70bbca6e58094e28bd92b9fc1ff3Laurent Pinchart	case V4L2_PIX_FMT_NV61:
224315dede882e564601947f2ce4b647742c0351be6dLaurent Pinchart		info->fix.xpanstep = 2;
224415dede882e564601947f2ce4b647742c0351be6dLaurent Pinchart	}
2245a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2246a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	/* Initialize variable screen information using the first mode as
2247bd5f2c6911c210af52fa4dc4cf504043ff8a4971Laurent Pinchart	 * default.
2248a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 */
2249a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	var = &info->var;
2250352d6138779e22c5340803d5a32fc332ad2e5e1dLaurent Pinchart	fb_videomode_to_var(var, modes);
2251856e8dfe6efed7cf35bc6bf827f030a164bee083Laurent Pinchart	var->width = ch->display.width;
2252856e8dfe6efed7cf35bc6bf827f030a164bee083Laurent Pinchart	var->height = ch->display.height;
2253bd5f2c6911c210af52fa4dc4cf504043ff8a4971Laurent Pinchart	var->xres_virtual = ch->xres_virtual;
2254bd5f2c6911c210af52fa4dc4cf504043ff8a4971Laurent Pinchart	var->yres_virtual = ch->yres_virtual;
2255a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	var->activate = FB_ACTIVATE_NOW;
2256a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2257a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	/* Use the legacy API by default for RGB formats, and the FOURCC API
2258a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 * for YUV formats.
2259a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 */
2260a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (!ch->format->yuv)
2261a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		var->bits_per_pixel = ch->format->bpp;
2262a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	else
2263a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		var->grayscale = ch->format->fourcc;
2264a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2265d7ad33421863308fe7ddf865737d4d83b64e5b81Laurent Pinchart	ret = sh_mobile_lcdc_check_var(var, info);
2266a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (ret)
2267a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		return ret;
2268a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2269a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	return 0;
2270a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart}
2271a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2272f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
2273f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Backlight
2274f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
2275f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
22763b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic int sh_mobile_lcdc_update_bl(struct backlight_device *bdev)
22773b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{
22783b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev);
22793b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	int brightness = bdev->props.brightness;
22803b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
22813b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	if (bdev->props.power != FB_BLANK_UNBLANK ||
22823b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	    bdev->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
22833b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		brightness = 0;
22843b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
2285b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	return ch->cfg->bl_info.set_brightness(brightness);
22863b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot}
22873b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
22883b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic int sh_mobile_lcdc_get_brightness(struct backlight_device *bdev)
22893b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{
22903b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev);
22913b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
2292b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	return ch->cfg->bl_info.get_brightness();
22933b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot}
22943b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
22953b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic int sh_mobile_lcdc_check_fb(struct backlight_device *bdev,
22963b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot				   struct fb_info *info)
22973b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{
22983b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	return (info->bl_dev == bdev);
22993b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot}
23003b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
23013b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic struct backlight_ops sh_mobile_lcdc_bl_ops = {
23023b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	.options	= BL_CORE_SUSPENDRESUME,
23033b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	.update_status	= sh_mobile_lcdc_update_bl,
23043b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	.get_brightness	= sh_mobile_lcdc_get_brightness,
23053b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	.check_fb	= sh_mobile_lcdc_check_fb,
23063b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot};
23073b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
23083b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic struct backlight_device *sh_mobile_lcdc_bl_probe(struct device *parent,
23093b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot					       struct sh_mobile_lcdc_chan *ch)
23103b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{
23113b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	struct backlight_device *bl;
23123b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
2313b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	bl = backlight_device_register(ch->cfg->bl_info.name, parent, ch,
23143b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot				       &sh_mobile_lcdc_bl_ops, NULL);
2315beee1f20a185c7e79fd33bb83e04fe44ecd75af3Dan Carpenter	if (IS_ERR(bl)) {
2316beee1f20a185c7e79fd33bb83e04fe44ecd75af3Dan Carpenter		dev_err(parent, "unable to register backlight device: %ld\n",
2317beee1f20a185c7e79fd33bb83e04fe44ecd75af3Dan Carpenter			PTR_ERR(bl));
23183b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		return NULL;
23193b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	}
23203b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
2321b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	bl->props.max_brightness = ch->cfg->bl_info.max_brightness;
23223b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	bl->props.brightness = bl->props.max_brightness;
23233b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	backlight_update_status(bl);
23243b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
23253b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	return bl;
23263b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot}
23273b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
23283b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic void sh_mobile_lcdc_bl_remove(struct backlight_device *bdev)
23293b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{
23303b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	backlight_device_unregister(bdev);
23313b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot}
23323b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
2333f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
2334f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Power management
2335f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
2336f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
23372feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Dammstatic int sh_mobile_lcdc_suspend(struct device *dev)
23382feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm{
23392feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	struct platform_device *pdev = to_platform_device(dev);
23402feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
23412feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	sh_mobile_lcdc_stop(platform_get_drvdata(pdev));
23422feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	return 0;
23432feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm}
23442feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
23452feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Dammstatic int sh_mobile_lcdc_resume(struct device *dev)
23462feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm{
23472feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	struct platform_device *pdev = to_platform_device(dev);
23482feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
23492feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	return sh_mobile_lcdc_start(platform_get_drvdata(pdev));
23502feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm}
23512feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
23520246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic int sh_mobile_lcdc_runtime_suspend(struct device *dev)
23530246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm{
23540246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	struct platform_device *pdev = to_platform_device(dev);
23552427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart	struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
23560246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm
23570246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	/* turn off LCDC hardware */
23582427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart	lcdc_write(priv, _LDCNT1R, 0);
23592427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart
23600246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	return 0;
23610246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm}
23620246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm
23630246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic int sh_mobile_lcdc_runtime_resume(struct device *dev)
23640246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm{
23650246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	struct platform_device *pdev = to_platform_device(dev);
23662427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart	struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
23670246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm
23682427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart	__sh_mobile_lcdc_start(priv);
23690246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm
23700246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	return 0;
23710246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm}
23720246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm
2373471452104b8520337ae2fb48c4e61cd4896e025dAlexey Dobriyanstatic const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = {
23742feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	.suspend = sh_mobile_lcdc_suspend,
23752feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	.resume = sh_mobile_lcdc_resume,
23760246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	.runtime_suspend = sh_mobile_lcdc_runtime_suspend,
23770246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	.runtime_resume = sh_mobile_lcdc_runtime_resume,
23782feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm};
23792feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
2380f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
2381f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Framebuffer notifier
2382f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
2383f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
23846de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski/* locking: called with info->lock held */
23856011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetskistatic int sh_mobile_lcdc_notify(struct notifier_block *nb,
23866011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski				 unsigned long action, void *data)
23876011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski{
23886011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	struct fb_event *event = data;
23896011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	struct fb_info *info = event->info;
23906011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	struct sh_mobile_lcdc_chan *ch = info->par;
23916011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
23926011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	if (&ch->lcdc->notifier != nb)
2393baf163749952ca5e33dd2d6a74da023e385c3a00Guennadi Liakhovetski		return NOTIFY_DONE;
23946011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
23956011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	dev_dbg(info->dev, "%s(): action = %lu, data = %p\n",
23966011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski		__func__, action, event->data);
23976011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
23986011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	switch(action) {
23996011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	case FB_EVENT_SUSPEND:
240037c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		sh_mobile_lcdc_display_off(ch);
2401afe417c0355154c8b2547619771d6053b3c0aad7Guennadi Liakhovetski		sh_mobile_lcdc_stop(ch->lcdc);
24026011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski		break;
24036011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	case FB_EVENT_RESUME:
2404dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		mutex_lock(&ch->open_lock);
2405dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		sh_mobile_fb_reconfig(info);
2406dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		mutex_unlock(&ch->open_lock);
24076011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
240837c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		sh_mobile_lcdc_display_on(ch);
2409ebe5e12d00f4785092a9650845ad3451bbf4b311Guennadi Liakhovetski		sh_mobile_lcdc_start(ch->lcdc);
24106011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	}
24116011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
2412baf163749952ca5e33dd2d6a74da023e385c3a00Guennadi Liakhovetski	return NOTIFY_OK;
24136011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski}
24146011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
2415f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
2416f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Probe/remove and driver init/exit
2417f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
2418f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2419217e9c4353aa86f0c7eeb4c275bca73ea8b53be1Laurent Pinchartstatic const struct fb_videomode default_720p __devinitconst = {
2420f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.name = "HDMI 720p",
2421f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.xres = 1280,
2422f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.yres = 720,
2423f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2424f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.left_margin = 220,
2425f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.right_margin = 110,
2426f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.hsync_len = 40,
2427f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2428f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.upper_margin = 20,
2429f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.lower_margin = 5,
2430f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.vsync_len = 5,
2431f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2432f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.pixclock = 13468,
2433f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.refresh = 60,
2434f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
2435f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart};
2436f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2437b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchartstatic int sh_mobile_lcdc_remove(struct platform_device *pdev)
2438b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart{
2439b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
2440c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	unsigned int i;
2441b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
2442b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	fb_unregister_client(&priv->notifier);
2443b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
2444c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(priv->overlays); i++)
2445c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		sh_mobile_lcdc_overlay_fb_unregister(&priv->overlays[i]);
2446b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
2447a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		sh_mobile_lcdc_channel_fb_unregister(&priv->ch[i]);
2448b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
2449b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	sh_mobile_lcdc_stop(priv);
2450b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
2451c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(priv->overlays); i++) {
2452c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i];
2453c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2454c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		sh_mobile_lcdc_overlay_fb_cleanup(ovl);
2455c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2456c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (ovl->fb_mem)
2457c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			dma_free_coherent(&pdev->dev, ovl->fb_size,
2458c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart					  ovl->fb_mem, ovl->dma_handle);
2459c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
2460c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2461b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
24629a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart		struct sh_mobile_lcdc_chan *ch = &priv->ch[i];
2463b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
2464e34d0bbb062cc78802d0f0686c939ea1569889a6Laurent Pinchart		if (ch->tx_dev) {
2465e34d0bbb062cc78802d0f0686c939ea1569889a6Laurent Pinchart			ch->tx_dev->lcdc = NULL;
2466b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart			module_put(ch->cfg->tx_dev->dev.driver->owner);
2467e34d0bbb062cc78802d0f0686c939ea1569889a6Laurent Pinchart		}
24689a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart
2469a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		sh_mobile_lcdc_channel_fb_cleanup(ch);
2470b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
2471a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		if (ch->fb_mem)
2472a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart			dma_free_coherent(&pdev->dev, ch->fb_size,
2473a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart					  ch->fb_mem, ch->dma_handle);
2474b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	}
2475b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
2476b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
24770c75c4e073a8ec35bfd6c8adcceb2b896f2063e2Laurent Pinchart		struct sh_mobile_lcdc_chan *ch = &priv->ch[i];
24780c75c4e073a8ec35bfd6c8adcceb2b896f2063e2Laurent Pinchart
24790c75c4e073a8ec35bfd6c8adcceb2b896f2063e2Laurent Pinchart		if (ch->bl)
24800c75c4e073a8ec35bfd6c8adcceb2b896f2063e2Laurent Pinchart			sh_mobile_lcdc_bl_remove(ch->bl);
24810c75c4e073a8ec35bfd6c8adcceb2b896f2063e2Laurent Pinchart		mutex_destroy(&ch->open_lock);
2482b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	}
2483b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
24844774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	if (priv->dot_clk) {
24854774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart		pm_runtime_disable(&pdev->dev);
2486b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart		clk_put(priv->dot_clk);
24874774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	}
2488b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
2489b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	if (priv->base)
2490b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart		iounmap(priv->base);
2491b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
2492b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	if (priv->irq)
2493b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart		free_irq(priv->irq, priv);
2494b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	kfree(priv);
2495b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	return 0;
2496b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart}
2497cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2498217e9c4353aa86f0c7eeb4c275bca73ea8b53be1Laurent Pinchartstatic int __devinit sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
2499f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart{
2500b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	int interface_type = ch->cfg->interface_type;
2501f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2502f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	switch (interface_type) {
2503f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB8:
2504f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB9:
2505f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB12A:
2506f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB12B:
2507f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB16:
2508f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB18:
2509f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB24:
2510f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS8A:
2511f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS8B:
2512f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS8C:
2513f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS8D:
2514f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS9:
2515f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS12:
2516f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS16A:
2517f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS16B:
2518f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS16C:
2519f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS18:
2520f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS24:
2521f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		break;
2522f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	default:
2523f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return -EINVAL;
2524f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
2525f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2526f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	/* SUBLCD only supports SYS interface */
2527f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	if (lcdc_chan_is_sublcd(ch)) {
2528f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		if (!(interface_type & LDMT1R_IFM))
2529f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart			return -EINVAL;
2530f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2531f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		interface_type &= ~LDMT1R_IFM;
2532f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
2533f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2534f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	ch->ldmt1r_value = interface_type;
2535f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	return 0;
2536f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart}
2537f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
25380a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchartstatic int __devinit
25390707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchartsh_mobile_lcdc_overlay_init(struct sh_mobile_lcdc_overlay *ovl)
2540c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart{
2541c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	const struct sh_mobile_lcdc_format_info *format;
25420707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart	struct device *dev = ovl->channel->lcdc->dev;
2543c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	int ret;
2544c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2545c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ovl->cfg->fourcc == 0)
2546c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return 0;
2547c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2548c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Validate the format. */
2549c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	format = sh_mobile_format_info(ovl->cfg->fourcc);
2550c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (format == NULL) {
25510707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart		dev_err(dev, "Invalid FOURCC %08x\n", ovl->cfg->fourcc);
2552c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -EINVAL;
2553c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
2554c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2555c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->enabled = false;
2556c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->mode = LCDC_OVERLAY_BLEND;
2557c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->alpha = 255;
2558c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->rop3 = 0;
2559c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->pos_x = 0;
2560c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->pos_y = 0;
2561c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2562c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* The default Y virtual resolution is twice the panel size to allow for
2563c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 * double-buffering.
2564c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	 */
2565c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->format = format;
2566c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->xres = ovl->cfg->max_xres;
2567c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->xres_virtual = ovl->xres;
2568c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->yres = ovl->cfg->max_yres;
2569c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->yres_virtual = ovl->yres * 2;
2570c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2571c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (!format->yuv)
257216ca21c9a9f64577221c47d8d2f00d13b880aefaLaurent Pinchart		ovl->pitch = ovl->xres_virtual * format->bpp / 8;
2573c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	else
257416ca21c9a9f64577221c47d8d2f00d13b880aefaLaurent Pinchart		ovl->pitch = ovl->xres_virtual;
2575c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2576c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	/* Allocate frame buffer memory. */
2577c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ovl->fb_size = ovl->cfg->max_xres * ovl->cfg->max_yres
2578c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		       * format->bpp / 8 * 2;
25790707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart	ovl->fb_mem = dma_alloc_coherent(dev, ovl->fb_size, &ovl->dma_handle,
25800707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart					 GFP_KERNEL);
2581c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (!ovl->fb_mem) {
25820707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart		dev_err(dev, "unable to allocate buffer\n");
2583c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return -ENOMEM;
2584c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
2585c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2586c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	ret = sh_mobile_lcdc_overlay_fb_init(ovl);
2587c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	if (ret < 0)
2588c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		return ret;
2589c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2590c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	return 0;
2591c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart}
2592c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2593c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchartstatic int __devinit
25940707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchartsh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch)
2595cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
2596105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	const struct sh_mobile_lcdc_format_info *format;
2597b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	const struct sh_mobile_lcdc_chan_cfg *cfg = ch->cfg;
25980707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart	struct device *dev = ch->lcdc->dev;
25993ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	const struct fb_videomode *max_mode;
26003ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	const struct fb_videomode *mode;
2601a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	unsigned int num_modes;
26023ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	unsigned int max_size;
2603a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	unsigned int i;
26043ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
2605a67472ad1ae040f073e45048cbc5a01195f2e3f5Laurent Pinchart	mutex_init(&ch->open_lock);
2606ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	ch->notify = sh_mobile_lcdc_display_notify;
2607a67472ad1ae040f073e45048cbc5a01195f2e3f5Laurent Pinchart
2608105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	/* Validate the format. */
2609105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	format = sh_mobile_format_info(cfg->fourcc);
2610105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	if (format == NULL) {
26110707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart		dev_err(dev, "Invalid FOURCC %08x.\n", cfg->fourcc);
2612105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		return -EINVAL;
2613105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}
2614105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart
26153ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	/* Iterate through the modes to validate them and find the highest
26163ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	 * resolution.
26173ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	 */
26183ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	max_mode = NULL;
26193ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	max_size = 0;
26203ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
262193ff259846a774ff37dca54792c5a3a6425882c0Laurent Pinchart	for (i = 0, mode = cfg->lcd_modes; i < cfg->num_modes; i++, mode++) {
26223ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		unsigned int size = mode->yres * mode->xres;
26233ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
2624edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		/* NV12/NV21 buffers must have even number of lines */
2625edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		if ((cfg->fourcc == V4L2_PIX_FMT_NV12 ||
2626edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		     cfg->fourcc == V4L2_PIX_FMT_NV21) && (mode->yres & 0x1)) {
26270707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart			dev_err(dev, "yres must be multiple of 2 for "
26280a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart				"YCbCr420 mode.\n");
26293ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			return -EINVAL;
26303ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		}
26313ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
26323ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		if (size > max_size) {
26333ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			max_mode = mode;
26343ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			max_size = size;
26353ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		}
26363ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	}
26373ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
26383ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	if (!max_size)
26393ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		max_size = MAX_XRES * MAX_YRES;
26403ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	else
26410707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart		dev_dbg(dev, "Found largest videomode %ux%u\n",
26423ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			max_mode->xres, max_mode->yres);
26433ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
264493ff259846a774ff37dca54792c5a3a6425882c0Laurent Pinchart	if (cfg->lcd_modes == NULL) {
26453ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		mode = &default_720p;
264693ff259846a774ff37dca54792c5a3a6425882c0Laurent Pinchart		num_modes = 1;
26473ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	} else {
264893ff259846a774ff37dca54792c5a3a6425882c0Laurent Pinchart		mode = cfg->lcd_modes;
264993ff259846a774ff37dca54792c5a3a6425882c0Laurent Pinchart		num_modes = cfg->num_modes;
26503ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	}
26513ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
2652bd5f2c6911c210af52fa4dc4cf504043ff8a4971Laurent Pinchart	/* Use the first mode as default. The default Y virtual resolution is
2653bd5f2c6911c210af52fa4dc4cf504043ff8a4971Laurent Pinchart	 * twice the panel size to allow for double-buffering.
2654bd5f2c6911c210af52fa4dc4cf504043ff8a4971Laurent Pinchart	 */
265558f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->format = format;
265658f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->xres = mode->xres;
265758f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->xres_virtual = mode->xres;
265858f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->yres = mode->yres;
265958f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->yres_virtual = mode->yres * 2;
266058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
266158f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	if (!format->yuv) {
266258f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		ch->colorspace = V4L2_COLORSPACE_SRGB;
266316ca21c9a9f64577221c47d8d2f00d13b880aefaLaurent Pinchart		ch->pitch = ch->xres_virtual * format->bpp / 8;
266458f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	} else {
266558f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		ch->colorspace = V4L2_COLORSPACE_REC709;
266616ca21c9a9f64577221c47d8d2f00d13b880aefaLaurent Pinchart		ch->pitch = ch->xres_virtual;
266758f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	}
266858f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
2669a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ch->display.width = cfg->panel_cfg.width;
2670a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ch->display.height = cfg->panel_cfg.height;
2671a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ch->display.mode = *mode;
2672a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
2673a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	/* Allocate frame buffer memory. */
2674a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ch->fb_size = max_size * format->bpp / 8 * 2;
26750707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart	ch->fb_mem = dma_alloc_coherent(dev, ch->fb_size, &ch->dma_handle,
2676a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart					GFP_KERNEL);
2677a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (ch->fb_mem == NULL) {
26780707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart		dev_err(dev, "unable to allocate buffer\n");
2679a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		return -ENOMEM;
2680a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	}
26813ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
268213f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart	/* Initialize the transmitter device if present. */
268313f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart	if (cfg->tx_dev) {
268413f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart		if (!cfg->tx_dev->dev.driver ||
268513f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart		    !try_module_get(cfg->tx_dev->dev.driver->owner)) {
26860707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart			dev_warn(dev, "unable to get transmitter device\n");
268713f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart			return -EINVAL;
268813f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart		}
268913f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart		ch->tx_dev = platform_get_drvdata(cfg->tx_dev);
269013f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart		ch->tx_dev->lcdc = ch;
269113f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart		ch->tx_dev->def_mode = *mode;
269213f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart	}
269313f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart
2694a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	return sh_mobile_lcdc_channel_fb_init(ch, mode, num_modes);
26953ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart}
26963ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
26973ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchartstatic int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
26983ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart{
269901ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski	struct sh_mobile_lcdc_info *pdata = pdev->dev.platform_data;
27003ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	struct sh_mobile_lcdc_priv *priv;
2701cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	struct resource *res;
27023ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	int num_channels;
2703cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	int error;
27043ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	int i;
2705cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
270601ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski	if (!pdata) {
2707cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		dev_err(&pdev->dev, "no platform data defined\n");
27088bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski		return -EINVAL;
2709cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2710cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2711cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
27128564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	i = platform_get_irq(pdev, 0);
27138564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	if (!res || i < 0) {
27148564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		dev_err(&pdev->dev, "cannot get platform resources\n");
27158bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski		return -ENOENT;
2716cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2717cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2718cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
2719cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (!priv) {
2720cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		dev_err(&pdev->dev, "cannot allocate device data\n");
27218bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski		return -ENOMEM;
2722cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2723cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
27244774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	priv->dev = &pdev->dev;
27254774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	priv->meram_dev = pdata->meram_dev;
27268bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski	platform_set_drvdata(pdev, priv);
27278bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski
2728f8798ccbefc0e4ef7438c080b7ba0410738c8cfaYong Zhang	error = request_irq(i, sh_mobile_lcdc_irq, 0,
27297ad33e74857f16f1202cbc5746faf52e88e8b376Kay Sievers			    dev_name(&pdev->dev), priv);
27308564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	if (error) {
27318564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		dev_err(&pdev->dev, "unable to request irq\n");
27328564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		goto err1;
27338564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	}
27348564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
27358564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	priv->irq = i;
27365ef6b505d9df45558402bdb823a078840a6a26c4Guennadi Liakhovetski	atomic_set(&priv->hw_usecnt, -1);
2737cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
27383ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	for (i = 0, num_channels = 0; i < ARRAY_SIZE(pdata->ch); i++) {
27393ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		struct sh_mobile_lcdc_chan *ch = priv->ch + num_channels;
2740cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
274101ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski		ch->lcdc = priv;
2742b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		ch->cfg = &pdata->ch[i];
2743cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
274401ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski		error = sh_mobile_lcdc_check_interface(ch);
2745cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (error) {
2746cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			dev_err(&pdev->dev, "unsupported interface type\n");
2747cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			goto err1;
2748cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		}
274901ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski		init_waitqueue_head(&ch->frame_end_wait);
275001ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski		init_completion(&ch->vsync_completion);
2751cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
27523b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		/* probe the backlight is there is one defined */
2753b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		if (ch->cfg->bl_info.max_brightness)
27543b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot			ch->bl = sh_mobile_lcdc_bl_probe(&pdev->dev, ch);
27553b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
2756cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		switch (pdata->ch[i].chan) {
2757cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		case LCDC_CHAN_MAINLCD:
2758ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart			ch->enabled = LDCNT2R_ME;
275901ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski			ch->reg_offs = lcdc_offs_mainlcd;
27603ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			num_channels++;
2761cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			break;
2762cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		case LCDC_CHAN_SUBLCD:
2763ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart			ch->enabled = LDCNT2R_SE;
276401ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski			ch->reg_offs = lcdc_offs_sublcd;
27653ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			num_channels++;
2766cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			break;
2767cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		}
2768cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2769cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
27703ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	if (!num_channels) {
2771cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		dev_err(&pdev->dev, "no channels defined\n");
2772cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		error = -EINVAL;
2773cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		goto err1;
2774cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2775cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2776edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	/* for dual channel LCDC (MAIN + SUB) force shared format setting */
27773ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	if (num_channels == 2)
2778edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		priv->forced_fourcc = pdata->ch[0].fourcc;
2779417d48274e755e537bae60461558c1f63a4e14deMagnus Damm
2780dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski	priv->base = ioremap_nocache(res->start, resource_size(res));
2781dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski	if (!priv->base)
2782dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski		goto err1;
2783dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski
27840a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart	error = sh_mobile_lcdc_setup_clocks(priv, pdata->clock_source);
2785cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (error) {
2786cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		dev_err(&pdev->dev, "unable to setup clocks\n");
2787cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		goto err1;
2788cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2789cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
27904774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	/* Enable runtime PM. */
27914774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	pm_runtime_enable(&pdev->dev);
27927caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
27933ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	for (i = 0; i < num_channels; i++) {
27940707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart		struct sh_mobile_lcdc_chan *ch = &priv->ch[i];
2795c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski
27960707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart		error = sh_mobile_lcdc_channel_init(ch);
2797cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (error)
27983ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			goto err1;
2799cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2800cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2801c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(pdata->overlays); i++) {
2802c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i];
2803c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2804c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->cfg = &pdata->overlays[i];
2805c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		ovl->channel = &priv->ch[0];
2806c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
28070707330b337cec85d7b393303e82f0fad5dc4c00Laurent Pinchart		error = sh_mobile_lcdc_overlay_init(ovl);
2808c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (error)
2809c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			goto err1;
2810c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
2811c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2812cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	error = sh_mobile_lcdc_start(priv);
2813cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (error) {
2814cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		dev_err(&pdev->dev, "unable to start hardware\n");
2815cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		goto err1;
2816cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2817cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
28183ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	for (i = 0; i < num_channels; i++) {
28191c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt		struct sh_mobile_lcdc_chan *ch = priv->ch + i;
28201c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt
2821a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		error = sh_mobile_lcdc_channel_fb_register(ch);
2822a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		if (error)
2823cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			goto err1;
2824cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2825cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2826c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(pdata->overlays); i++) {
2827c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i];
2828c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
2829c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		error = sh_mobile_lcdc_overlay_fb_register(ovl);
2830c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart		if (error)
2831c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart			goto err1;
2832c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart	}
2833c5deac3c9b2284a64326e8799dfe7416bc619c02Laurent Pinchart
28346011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	/* Failure ignored */
28356011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	priv->notifier.notifier_call = sh_mobile_lcdc_notify;
28366011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	fb_register_client(&priv->notifier);
28376011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
2838cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	return 0;
28398bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetskierr1:
2840cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	sh_mobile_lcdc_remove(pdev);
28418bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski
2842cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	return error;
2843cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
2844cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2845cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic struct platform_driver sh_mobile_lcdc_driver = {
2846cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.driver		= {
2847cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		.name		= "sh_mobile_lcdc_fb",
2848cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		.owner		= THIS_MODULE,
28492feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		.pm		= &sh_mobile_lcdc_dev_pm_ops,
2850cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	},
2851cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.probe		= sh_mobile_lcdc_probe,
2852cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.remove		= sh_mobile_lcdc_remove,
2853cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm};
2854cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
28554277f2c4667187cbbdd3da3be31ee681bc6b8300Axel Linmodule_platform_driver(sh_mobile_lcdc_driver);
2856cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2857cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_DESCRIPTION("SuperH Mobile LCDC Framebuffer driver");
2858cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
2859cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_LICENSE("GPL v2");
2860