sh_mobile_lcdcfb.c revision 72c04af9a2d57b7945cf3de8e71461bd80695d50
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>
15cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#include <linux/dma-mapping.h>
16f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart#include <linux/delay.h>
17f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart#include <linux/gpio.h>
18f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart#include <linux/init.h>
198564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm#include <linux/interrupt.h>
2040331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy#include <linux/ioctl.h>
21f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart#include <linux/kernel.h>
22f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart#include <linux/mm.h>
23355b200bacdb6017669cdc5bc9e7b1037aac42a2Paul Gortmaker#include <linux/module.h>
24f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart#include <linux/platform_device.h>
25f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart#include <linux/pm_runtime.h>
26f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart#include <linux/slab.h>
27f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart#include <linux/videodev2.h>
28f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart#include <linux/vmalloc.h>
29f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
30225c9a8d1da274bf23efec43ec28b1c9e45e12f8Paul Mundt#include <video/sh_mobile_lcdc.h>
318a20974f0370fe1b924704399e7ba327d894ef72Laurent Pinchart#include <video/sh_mobile_meram.h>
32cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
336de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski#include "sh_mobile_lcdcfb.h"
346de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski
35a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy#define SIDE_B_OFFSET 0x1000
36a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy#define MIRROR_OFFSET 0x2000
37cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
38d2ecbab5960d9814a269d36723647d6ef391ba8fGuennadi Liakhovetski#define MAX_XRES 1920
39d2ecbab5960d9814a269d36723647d6ef391ba8fGuennadi Liakhovetski#define MAX_YRES 1080
40cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
41f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchartstruct sh_mobile_lcdc_priv {
42f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	void __iomem *base;
43f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	int irq;
44f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	atomic_t hw_usecnt;
45f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	struct device *dev;
46f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	struct clk *dot_clk;
47f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	unsigned long lddckr;
48f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	struct sh_mobile_lcdc_chan ch[2];
49f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	struct notifier_block notifier;
50f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	int started;
51f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	int forced_fourcc; /* 2 channel LCDC must share fourcc setting */
52f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	struct sh_mobile_meram_info *meram_dev;
53f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart};
54f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
55f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
56f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Registers access
57f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
58f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
590246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = {
60cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDDCKPAT1R] = 0x400,
61cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDDCKPAT2R] = 0x404,
62cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDMT1R] = 0x418,
63cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDMT2R] = 0x41c,
64cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDMT3R] = 0x420,
65cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDDFR] = 0x424,
66cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDSM1R] = 0x428,
678564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	[LDSM2R] = 0x42c,
68cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDSA1R] = 0x430,
6953b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia	[LDSA2R] = 0x434,
70cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDMLSR] = 0x438,
71cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDHCNR] = 0x448,
72cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDHSYNR] = 0x44c,
73cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDVLNR] = 0x450,
74cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDVSYNR] = 0x454,
75cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDPMR] = 0x460,
766011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	[LDHAJR] = 0x4a0,
77cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm};
78cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
790246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic unsigned long lcdc_offs_sublcd[NR_CH_REGS] = {
80cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDDCKPAT1R] = 0x408,
81cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDDCKPAT2R] = 0x40c,
82cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDMT1R] = 0x600,
83cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDMT2R] = 0x604,
84cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDMT3R] = 0x608,
85cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDDFR] = 0x60c,
86cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDSM1R] = 0x610,
878564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	[LDSM2R] = 0x614,
88cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDSA1R] = 0x618,
89cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDMLSR] = 0x620,
90cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDHCNR] = 0x624,
91cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDHSYNR] = 0x628,
92cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDVLNR] = 0x62c,
93cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDVSYNR] = 0x630,
94cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	[LDPMR] = 0x63c,
95cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm};
96cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
97a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthystatic bool banked(int reg_nr)
98a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy{
99a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	switch (reg_nr) {
100a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	case LDMT1R:
101a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	case LDMT2R:
102a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	case LDMT3R:
103a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	case LDDFR:
104a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	case LDSM1R:
105a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	case LDSA1R:
10653b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia	case LDSA2R:
107a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	case LDMLSR:
108a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	case LDHCNR:
109a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	case LDHSYNR:
110a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	case LDVLNR:
111a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	case LDVSYNR:
112a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy		return true;
113a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	}
114a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	return false;
115a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy}
116a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy
117f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchartstatic int lcdc_chan_is_sublcd(struct sh_mobile_lcdc_chan *chan)
118f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart{
119b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	return chan->cfg->chan == LCDC_CHAN_SUBLCD;
120f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart}
121f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
122cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_write_chan(struct sh_mobile_lcdc_chan *chan,
123cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			    int reg_nr, unsigned long data)
124cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
125cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr]);
126a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	if (banked(reg_nr))
127a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy		iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr] +
128a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy			  SIDE_B_OFFSET);
129a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy}
130a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy
131a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthystatic void lcdc_write_chan_mirror(struct sh_mobile_lcdc_chan *chan,
132a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy			    int reg_nr, unsigned long data)
133a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy{
134a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy	iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr] +
135a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy		  MIRROR_OFFSET);
136cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
137cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
138cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic unsigned long lcdc_read_chan(struct sh_mobile_lcdc_chan *chan,
139cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm				    int reg_nr)
140cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
141cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	return ioread32(chan->lcdc->base + chan->reg_offs[reg_nr]);
142cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
143cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
144cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_write(struct sh_mobile_lcdc_priv *priv,
145cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		       unsigned long reg_offs, unsigned long data)
146cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
147cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	iowrite32(data, priv->base + reg_offs);
148cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
149cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
150cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic unsigned long lcdc_read(struct sh_mobile_lcdc_priv *priv,
151cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			       unsigned long reg_offs)
152cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
153cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	return ioread32(priv->base + reg_offs);
154cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
155cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
156cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_wait_bit(struct sh_mobile_lcdc_priv *priv,
157cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			  unsigned long reg_offs,
158cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			  unsigned long mask, unsigned long until)
159cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
160cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	while ((lcdc_read(priv, reg_offs) & mask) != until)
161cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		cpu_relax();
162cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
163cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
164f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
165f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Clock management
166f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
167f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
168f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchartstatic void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv)
169cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
170f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	if (atomic_inc_and_test(&priv->hw_usecnt)) {
171f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		if (priv->dot_clk)
172f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart			clk_enable(priv->dot_clk);
173f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		pm_runtime_get_sync(priv->dev);
174f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		if (priv->meram_dev && priv->meram_dev->pdev)
175f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart			pm_runtime_get_sync(&priv->meram_dev->pdev->dev);
176f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
177cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
178cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
179f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchartstatic void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv)
180f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart{
181f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	if (atomic_sub_return(1, &priv->hw_usecnt) == -1) {
182f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		if (priv->meram_dev && priv->meram_dev->pdev)
183f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart			pm_runtime_put_sync(&priv->meram_dev->pdev->dev);
184f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		pm_runtime_put(priv->dev);
185f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		if (priv->dot_clk)
186f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart			clk_disable(priv->dot_clk);
187f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
188f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart}
189f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
1900a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchartstatic int sh_mobile_lcdc_setup_clocks(struct sh_mobile_lcdc_priv *priv,
1910a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart				       int clock_source)
192f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart{
1934774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	struct clk *clk;
194f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	char *str;
195f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
196f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	switch (clock_source) {
197f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case LCDC_CLK_BUS:
198f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		str = "bus_clk";
199f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		priv->lddckr = LDDCKR_ICKSEL_BUS;
200f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		break;
201f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case LCDC_CLK_PERIPHERAL:
202f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		str = "peripheral_clk";
203f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		priv->lddckr = LDDCKR_ICKSEL_MIPI;
204f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		break;
205f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case LCDC_CLK_EXTERNAL:
206f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		str = NULL;
207f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		priv->lddckr = LDDCKR_ICKSEL_HDMI;
208f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		break;
209f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	default:
210f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return -EINVAL;
211f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
212f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2134774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	if (str == NULL)
2144774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart		return 0;
2154774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart
2160a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart	clk = clk_get(priv->dev, str);
2174774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	if (IS_ERR(clk)) {
2180a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart		dev_err(priv->dev, "cannot get dot clock %s\n", str);
2194774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart		return PTR_ERR(clk);
220f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
221f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
2224774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	priv->dot_clk = clk;
223f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	return 0;
224f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart}
225f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
226f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
22737c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart * Display, panel and deferred I/O
228f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
229f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
230cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_sys_write_index(void *handle, unsigned long data)
231cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
232cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	struct sh_mobile_lcdc_chan *ch = handle;
233cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
234ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_write(ch->lcdc, _LDDWD0R, data | LDDWDxR_WDACT);
235ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
236ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_write(ch->lcdc, _LDDWAR, LDDWAR_WA |
237ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart		   (lcdc_chan_is_sublcd(ch) ? 2 : 0));
238ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
239cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
240cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
241cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_sys_write_data(void *handle, unsigned long data)
242cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
243cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	struct sh_mobile_lcdc_chan *ch = handle;
244cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
245ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_write(ch->lcdc, _LDDWD0R, data | LDDWDxR_WDACT | LDDWDxR_RSW);
246ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
247ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_write(ch->lcdc, _LDDWAR, LDDWAR_WA |
248ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart		   (lcdc_chan_is_sublcd(ch) ? 2 : 0));
249ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
250cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
251cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
252cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic unsigned long lcdc_sys_read_data(void *handle)
253cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
254cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	struct sh_mobile_lcdc_chan *ch = handle;
255cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
256ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_write(ch->lcdc, _LDDRDR, LDDRDR_RSR);
257ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
258ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_write(ch->lcdc, _LDDRAR, LDDRAR_RA |
259ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart		   (lcdc_chan_is_sublcd(ch) ? 2 : 0));
260cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	udelay(1);
261ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
262cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
263ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	return lcdc_read(ch->lcdc, _LDDRDR) & LDDRDR_DRD_MASK;
264cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
265cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
266cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstruct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = {
267cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	lcdc_sys_write_index,
268cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	lcdc_sys_write_data,
269cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	lcdc_sys_read_data,
270cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm};
271cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2721c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundtstatic int sh_mobile_lcdc_sginit(struct fb_info *info,
2731c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt				  struct list_head *pagelist)
2741c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt{
2751c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt	struct sh_mobile_lcdc_chan *ch = info->par;
27658f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	unsigned int nr_pages_max = ch->fb_size >> PAGE_SHIFT;
2771c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt	struct page *page;
2781c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt	int nr_pages = 0;
2791c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt
2801c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt	sg_init_table(ch->sglist, nr_pages_max);
2811c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt
2821c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt	list_for_each_entry(page, pagelist, lru)
2831c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt		sg_set_page(&ch->sglist[nr_pages++], page, PAGE_SIZE, 0);
2841c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt
2851c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt	return nr_pages;
2861c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt}
2871c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt
2888564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_deferred_io(struct fb_info *info,
2898564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm				       struct list_head *pagelist)
2908564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{
2918564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	struct sh_mobile_lcdc_chan *ch = info->par;
292b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg;
2938564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
2948564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	/* enable clocks before accessing hardware */
2958564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sh_mobile_lcdc_clk_on(ch->lcdc);
2968564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
2975c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	/*
2985c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * It's possible to get here without anything on the pagelist via
2995c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * sh_mobile_lcdc_deferred_io_touch() or via a userspace fsync()
3005c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * invocation. In the former case, the acceleration routines are
3015c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * stepped in to when using the framebuffer console causing the
3025c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * workqueue to be scheduled without any dirty pages on the list.
3035c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 *
3045c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * Despite this, a panel update is still needed given that the
3055c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * acceleration routines have their own methods for writing in
3065c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * that still need to be updated.
3075c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 *
3085c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * The fsync() and empty pagelist case could be optimized for,
3095c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * but we don't bother, as any application exhibiting such
3105c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 * behaviour is fundamentally broken anyways.
3115c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	 */
3125c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt	if (!list_empty(pagelist)) {
3135c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt		unsigned int nr_pages = sh_mobile_lcdc_sginit(info, pagelist);
3145c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt
3155c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt		/* trigger panel update */
316e8363140c02c92c122210e03103aef72dd836664Laurent Pinchart		dma_map_sg(ch->lcdc->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
317afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart		if (panel->start_transfer)
318afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart			panel->start_transfer(ch, &sh_mobile_lcdc_sys_bus_ops);
319ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart		lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG);
320e8363140c02c92c122210e03103aef72dd836664Laurent Pinchart		dma_unmap_sg(ch->lcdc->dev, ch->sglist, nr_pages,
321e8363140c02c92c122210e03103aef72dd836664Laurent Pinchart			     DMA_TO_DEVICE);
322ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm	} else {
323afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart		if (panel->start_transfer)
324afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart			panel->start_transfer(ch, &sh_mobile_lcdc_sys_bus_ops);
325ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart		lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG);
326ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm	}
3278564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
3288564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
3298564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info)
3308564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{
3318564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	struct fb_deferred_io *fbdefio = info->fbdefio;
3328564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
3338564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	if (fbdefio)
3348564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		schedule_delayed_work(&info->deferred_work, fbdefio->delay);
3358564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
3368564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
33737c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchartstatic void sh_mobile_lcdc_display_on(struct sh_mobile_lcdc_chan *ch)
33837c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart{
339b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg;
34037c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart
3419a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart	if (ch->tx_dev) {
342458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart		int ret;
343458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart
344458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart		ret = ch->tx_dev->ops->display_on(ch->tx_dev);
345458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart		if (ret < 0)
3469a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart			return;
347458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart
348458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart		if (ret == SH_MOBILE_LCDC_DISPLAY_DISCONNECTED)
349458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart			ch->info->state = FBINFO_STATE_SUSPENDED;
3509a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart	}
3519a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart
35237c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart	/* HDMI must be enabled before LCDC configuration */
353afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart	if (panel->display_on)
354afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart		panel->display_on();
35537c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart}
35637c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart
35737c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchartstatic void sh_mobile_lcdc_display_off(struct sh_mobile_lcdc_chan *ch)
35837c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart{
359b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg;
36037c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart
361afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart	if (panel->display_off)
362afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart		panel->display_off();
3639a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart
3649a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart	if (ch->tx_dev)
3659a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart		ch->tx_dev->ops->display_off(ch->tx_dev);
36637c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart}
36737c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart
368ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchartstatic bool
369ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchartsh_mobile_lcdc_must_reconfigure(struct sh_mobile_lcdc_chan *ch,
370e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart				const struct fb_videomode *new_mode)
371ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart{
372ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	dev_dbg(ch->info->dev, "Old %ux%u, new %ux%u\n",
3732d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart		ch->display.mode.xres, ch->display.mode.yres,
3742d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart		new_mode->xres, new_mode->yres);
375ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
376e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart	/* It can be a different monitor with an equal video-mode */
3772d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	if (fb_mode_is_equal(&ch->display.mode, new_mode))
378ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		return false;
379ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
380ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	dev_dbg(ch->info->dev, "Switching %u -> %u lines\n",
3812d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart		ch->display.mode.yres, new_mode->yres);
3822d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	ch->display.mode = *new_mode;
383ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
384ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	return true;
385ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart}
386ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
387ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchartstatic int sh_mobile_check_var(struct fb_var_screeninfo *var,
388ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			       struct fb_info *info);
389ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
390ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchartstatic int sh_mobile_lcdc_display_notify(struct sh_mobile_lcdc_chan *ch,
391ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart					 enum sh_mobile_lcdc_entity_event event,
392e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart					 const struct fb_videomode *mode,
393e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart					 const struct fb_monspecs *monspec)
394ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart{
395ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	struct fb_info *info = ch->info;
396e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart	struct fb_var_screeninfo var;
397ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	int ret = 0;
398ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
399ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	switch (event) {
400ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	case SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT:
401ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		/* HDMI plug in */
402ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		if (lock_fb_info(info)) {
403ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			console_lock();
404ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
4052d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart			ch->display.width = monspec->max_x * 10;
4062d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart			ch->display.height = monspec->max_y * 10;
407e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart
408e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart			if (!sh_mobile_lcdc_must_reconfigure(ch, mode) &&
409ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			    info->state == FBINFO_STATE_RUNNING) {
410ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				/* First activation with the default monitor.
411ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				 * Just turn on, if we run a resume here, the
412ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				 * logo disappears.
413ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				 */
414e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart				info->var.width = monspec->max_x * 10;
415e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart				info->var.height = monspec->max_y * 10;
416ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				sh_mobile_lcdc_display_on(ch);
417ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			} else {
418ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				/* New monitor or have to wake up */
419ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart				fb_set_suspend(info, 0);
420ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			}
421ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
422ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			console_unlock();
423ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			unlock_fb_info(info);
424ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		}
425ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		break;
426ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
427ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	case SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT:
428ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		/* HDMI disconnect */
429ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		if (lock_fb_info(info)) {
430ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			console_lock();
431ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			fb_set_suspend(info, 1);
432ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			console_unlock();
433ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart			unlock_fb_info(info);
434ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		}
435ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		break;
436ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
437ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	case SH_MOBILE_LCDC_EVENT_DISPLAY_MODE:
438ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		/* Validate a proposed new mode */
439e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart		fb_videomode_to_var(&var, mode);
440e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart		var.bits_per_pixel = info->var.bits_per_pixel;
441e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart		var.grayscale = info->var.grayscale;
442e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart		ret = sh_mobile_check_var(&var, info);
443ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart		break;
444ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	}
445ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
446ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	return ret;
447ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart}
448ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart
449f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
450f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Format helpers
451f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
452f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
453105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchartstruct sh_mobile_lcdc_format_info {
454105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	u32 fourcc;
455105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	unsigned int bpp;
456105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	bool yuv;
457105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	u32 lddfr;
458105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart};
459105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart
460105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchartstatic const struct sh_mobile_lcdc_format_info sh_mobile_format_infos[] = {
461105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	{
462105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_RGB565,
463105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 16,
464105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = false,
465105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_PKF_RGB16,
466105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
467105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_BGR24,
468105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 24,
469105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = false,
470105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_PKF_RGB24,
471105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
472105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_BGR32,
473105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 32,
474105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = false,
475105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_PKF_ARGB32,
476105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
477105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_NV12,
478105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 12,
479105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = true,
480105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_CC | LDDFR_YF_420,
481105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
482105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_NV21,
483105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 12,
484105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = true,
485105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_CC | LDDFR_YF_420,
486105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
487105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_NV16,
488105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 16,
489105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = true,
490105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_CC | LDDFR_YF_422,
491105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
492105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_NV61,
493105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 16,
494105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = true,
495105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_CC | LDDFR_YF_422,
496105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
497105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_NV24,
498105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 24,
499105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = true,
500105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_CC | LDDFR_YF_444,
501105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}, {
502105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.fourcc = V4L2_PIX_FMT_NV42,
503105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.bpp = 24,
504105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.yuv = true,
505105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		.lddfr = LDDFR_CC | LDDFR_YF_444,
506105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	},
507105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart};
508105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart
509105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchartstatic const struct sh_mobile_lcdc_format_info *
510105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchartsh_mobile_format_info(u32 fourcc)
511105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart{
512105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	unsigned int i;
513105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart
514105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(sh_mobile_format_infos); ++i) {
515105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		if (sh_mobile_format_infos[i].fourcc == fourcc)
516105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart			return &sh_mobile_format_infos[i];
517105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}
518105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart
519105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	return NULL;
520105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart}
521105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart
522f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchartstatic int sh_mobile_format_fourcc(const struct fb_var_screeninfo *var)
523f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart{
524f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	if (var->grayscale > 1)
525f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return var->grayscale;
526f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
527f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	switch (var->bits_per_pixel) {
528f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case 16:
529f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return V4L2_PIX_FMT_RGB565;
530f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case 24:
531f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return V4L2_PIX_FMT_BGR24;
532f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case 32:
533f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return V4L2_PIX_FMT_BGR32;
534f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	default:
535f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return 0;
536f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
537f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart}
538f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
539f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchartstatic int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var)
540f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart{
541f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	return var->grayscale > 1;
542f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart}
543f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
544f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
545f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Start, stop and IRQ
546f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
547f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
5488564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
5498564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{
5508564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	struct sh_mobile_lcdc_priv *priv = data;
5512feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	struct sh_mobile_lcdc_chan *ch;
5529dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	unsigned long ldintr;
5532feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	int is_sub;
5542feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	int k;
5558564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
556dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart	/* Acknowledge interrupts and disable further VSYNC End IRQs. */
557dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart	ldintr = lcdc_read(priv, _LDINTR);
558dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart	lcdc_write(priv, _LDINTR, (ldintr ^ LDINTR_STATUS_MASK) & ~LDINTR_VEE);
5598564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
5602feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	/* figure out if this interrupt is for main or sub lcd */
561ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	is_sub = (lcdc_read(priv, _LDSR) & LDSR_MSS) ? 1 : 0;
5622feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
5639dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	/* wake up channel and disable clocks */
5642feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
5652feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		ch = &priv->ch[k];
5662feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
5672feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		if (!ch->enabled)
5682feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm			continue;
5692feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
570dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart		/* Frame End */
5719dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy		if (ldintr & LDINTR_FS) {
5729dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy			if (is_sub == lcdc_chan_is_sublcd(ch)) {
5739dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy				ch->frame_end = 1;
5749dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy				wake_up(&ch->frame_end_wait);
5752feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
5769dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy				sh_mobile_lcdc_clk_off(priv);
5779dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy			}
5789dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy		}
5799dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
5809dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy		/* VSYNC End */
58140331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy		if (ldintr & LDINTR_VES)
58240331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy			complete(&ch->vsync_completion);
5832feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	}
5842feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
5858564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	return IRQ_HANDLED;
5868564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
5878564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
5884976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchartstatic int sh_mobile_wait_for_vsync(struct sh_mobile_lcdc_chan *ch)
5894976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart{
5904976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	unsigned long ldintr;
5914976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	int ret;
5924976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart
5934976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	/* Enable VSync End interrupt and be careful not to acknowledge any
5944976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	 * pending interrupt.
5954976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	 */
5964976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	ldintr = lcdc_read(ch->lcdc, _LDINTR);
5974976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	ldintr |= LDINTR_VEE | LDINTR_STATUS_MASK;
5984976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	lcdc_write(ch->lcdc, _LDINTR, ldintr);
5994976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart
6004976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion,
6014976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart							msecs_to_jiffies(100));
6024976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	if (!ret)
6034976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart		return -ETIMEDOUT;
6044976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart
6054976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart	return 0;
6064976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart}
6074976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart
608cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv,
609cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm				      int start)
610cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
611cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	unsigned long tmp = lcdc_read(priv, _LDCNT2R);
612cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	int k;
613cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
614cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	/* start or stop the lcdc */
615cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (start)
616ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart		lcdc_write(priv, _LDCNT2R, tmp | LDCNT2R_DO);
617cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	else
618ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart		lcdc_write(priv, _LDCNT2R, tmp & ~LDCNT2R_DO);
619cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
620cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	/* wait until power is applied/stopped on all channels */
621cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++)
622cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (lcdc_read(priv, _LDCNT2R) & priv->ch[k].enabled)
623cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			while (1) {
624ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart				tmp = lcdc_read_chan(&priv->ch[k], LDPMR)
625ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart				    & LDPMR_LPS;
626ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart				if (start && tmp == LDPMR_LPS)
627cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm					break;
628cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm				if (!start && tmp == 0)
629cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm					break;
630cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm				cpu_relax();
631cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			}
632cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
633cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (!start)
634cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		lcdc_write(priv, _LDDCKSTPR, 1); /* stop dotclock */
635cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
636cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
6376011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetskistatic void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
6386011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski{
6392d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	const struct fb_var_screeninfo *var = &ch->info->var;
6402d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	const struct fb_videomode *mode = &ch->display.mode;
6411c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski	unsigned long h_total, hsync_pos, display_h_total;
6426011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	u32 tmp;
6436011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
6446011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	tmp = ch->ldmt1r_value;
645ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	tmp |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : LDMT1R_VPOL;
646ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	tmp |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : LDMT1R_HPOL;
647b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	tmp |= (ch->cfg->flags & LCDC_FLAGS_DWPOL) ? LDMT1R_DWPOL : 0;
648b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	tmp |= (ch->cfg->flags & LCDC_FLAGS_DIPOL) ? LDMT1R_DIPOL : 0;
649b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	tmp |= (ch->cfg->flags & LCDC_FLAGS_DAPOL) ? LDMT1R_DAPOL : 0;
650b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	tmp |= (ch->cfg->flags & LCDC_FLAGS_HSCNT) ? LDMT1R_HSCNT : 0;
651b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	tmp |= (ch->cfg->flags & LCDC_FLAGS_DWCNT) ? LDMT1R_DWCNT : 0;
6526011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDMT1R, tmp);
6536011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
6546011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	/* setup SYS bus */
655b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	lcdc_write_chan(ch, LDMT2R, ch->cfg->sys_bus_cfg.ldmt2r);
656b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	lcdc_write_chan(ch, LDMT3R, ch->cfg->sys_bus_cfg.ldmt3r);
6576011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
6586011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	/* horizontal configuration */
6592d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	h_total = mode->xres + mode->hsync_len + mode->left_margin
6602d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart		+ mode->right_margin;
6616011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	tmp = h_total / 8; /* HTCN */
66258f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	tmp |= (min(mode->xres, ch->xres) / 8) << 16; /* HDCN */
6636011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDHCNR, tmp);
6646011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
6652d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	hsync_pos = mode->xres + mode->right_margin;
6666011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	tmp = hsync_pos / 8; /* HSYNP */
6672d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	tmp |= (mode->hsync_len / 8) << 16; /* HSYNW */
6686011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDHSYNR, tmp);
6696011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
6706011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	/* vertical configuration */
6712d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	tmp = mode->yres + mode->vsync_len + mode->upper_margin
6722d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	    + mode->lower_margin; /* VTLN */
67358f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	tmp |= min(mode->yres, ch->yres) << 16; /* VDLN */
6746011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDVLNR, tmp);
6756011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
6762d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	tmp = mode->yres + mode->lower_margin; /* VSYNP */
6772d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	tmp |= mode->vsync_len << 16; /* VSYNW */
6786011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDVSYNR, tmp);
6796011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
6806011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	/* Adjust horizontal synchronisation for HDMI */
6812d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	display_h_total = mode->xres + mode->hsync_len + mode->left_margin
6822d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart			+ mode->right_margin;
6832d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	tmp = ((mode->xres & 7) << 24) | ((display_h_total & 7) << 16)
6842d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	    | ((mode->hsync_len & 7) << 8) | (hsync_pos & 7);
6856011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDHAJR, tmp);
6866011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski}
6876011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
6889a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart/*
6899a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart * __sh_mobile_lcdc_start - Configure and tart the LCDC
6909a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart * @priv: LCDC device
6919a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart *
6929a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart * Configure all enabled channels and start the LCDC device. All external
6939a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart * devices (clocks, MERAM, panels, ...) are not touched by this function.
6949a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart */
6959a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchartstatic void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
696cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
697cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	struct sh_mobile_lcdc_chan *ch;
698cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	unsigned long tmp;
6999a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	int k, m;
7008564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
7019a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Enable LCDC channels. Read data from external memory, avoid using the
7029a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	 * BEU for now.
7039a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	 */
7049a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_write(priv, _LDCNT2R, priv->ch[0].enabled | priv->ch[1].enabled);
705cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
7069a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Stop the LCDC first and disable all interrupts. */
707cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	sh_mobile_lcdc_start_stop(priv, 0);
7089a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_write(priv, _LDINTR, 0);
709cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
7109a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Configure power supply, dot clocks and start them. */
711cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	tmp = priv->lddckr;
712cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
713cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		ch = &priv->ch[k];
7149a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (!ch->enabled)
715cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			continue;
716cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
7179a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		/* Power supply */
7189a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		lcdc_write_chan(ch, LDPMR, 0);
7199a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
720b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		m = ch->cfg->clock_divider;
721cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (!m)
722cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			continue;
723cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
724505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart		/* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider
725505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart		 * denominator.
726505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart		 */
727505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart		lcdc_write_chan(ch, LDDCKPAT1R, 0);
728505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart		lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1);
729505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart
730cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (m == 1)
731ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart			m = LDDCKR_MOSEL;
732cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0);
733cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
734cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
735cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	lcdc_write(priv, _LDDCKR, tmp);
736cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	lcdc_write(priv, _LDDCKSTPR, 0);
737cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0);
738cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
7399a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Setup geometry, format, frame buffer memory and operation mode. */
740cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
741cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		ch = &priv->ch[k];
742cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (!ch->enabled)
743cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			continue;
744cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
7456011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski		sh_mobile_lcdc_geometry(ch);
746cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
747fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart		tmp = ch->format->lddfr;
748edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart
749fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart		if (ch->format->yuv) {
75058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart			switch (ch->colorspace) {
751edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			case V4L2_COLORSPACE_REC709:
752edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart				tmp |= LDDFR_CF1;
75353b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia				break;
754edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			case V4L2_COLORSPACE_JPEG:
755edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart				tmp |= LDDFR_CF0;
75653b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia				break;
75753b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia			}
758417d48274e755e537bae60461558c1f63a4e14deMagnus Damm		}
7597caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
7609a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		lcdc_write_chan(ch, LDDFR, tmp);
76172c04af9a2d57b7945cf3de8e71461bd80695d50Laurent Pinchart		lcdc_write_chan(ch, LDMLSR, ch->line_size);
7629a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		lcdc_write_chan(ch, LDSA1R, ch->base_addr_y);
763fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart		if (ch->format->yuv)
7649a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			lcdc_write_chan(ch, LDSA2R, ch->base_addr_c);
7657caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
7669a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		/* When using deferred I/O mode, configure the LCDC for one-shot
7679a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		 * operation and enable the frame end interrupt. Otherwise use
7689a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		 * continuous read mode.
7699a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		 */
7709a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (ch->ldmt1r_value & LDMT1R_IFM &&
771b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		    ch->cfg->sys_bus_cfg.deferred_io_msec) {
7729a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			lcdc_write_chan(ch, LDSM1R, LDSM1R_OS);
7739a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			lcdc_write(priv, _LDINTR, LDINTR_FE);
7749a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		} else {
7759a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			lcdc_write_chan(ch, LDSM1R, 0);
7769a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		}
7779a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	}
7787caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
7799a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Word and long word swap. */
780fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart	switch (priv->ch[0].format->fourcc) {
781edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_RGB565:
782edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV21:
783edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV61:
784edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV42:
785edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		tmp = LDDDSR_LS | LDDDSR_WS;
786edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		break;
787edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_BGR24:
788edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV12:
789edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV16:
790edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV24:
7919a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;
792edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		break;
793edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_BGR32:
794edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	default:
795edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		tmp = LDDDSR_LS;
796edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		break;
7979a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	}
7989a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_write(priv, _LDDDSR, tmp);
7997caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
8009a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Enable the display output. */
8019a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_write(priv, _LDCNT1R, LDCNT1R_DE);
8029a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	sh_mobile_lcdc_start_stop(priv, 1);
8039a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	priv->started = 1;
8049a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart}
805cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
8069a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchartstatic int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
8079a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart{
8089a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	struct sh_mobile_meram_info *mdev = priv->meram_dev;
8099a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	struct sh_mobile_lcdc_chan *ch;
8109a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	unsigned long tmp;
8119a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	int ret;
8129a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	int k;
813cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
8149a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* enable clocks before accessing the hardware */
8159a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
8169a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (priv->ch[k].enabled)
8179a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			sh_mobile_lcdc_clk_on(priv);
8189a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	}
8198564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
8209a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* reset */
8219a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LDCNT2R_BR);
8229a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_wait_bit(priv, _LDCNT2R, LDCNT2R_BR, 0);
8238564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
8249a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
825b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		const struct sh_mobile_lcdc_panel_cfg *panel;
8268564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
82737c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		ch = &priv->ch[k];
8289a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (!ch->enabled)
8299a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			continue;
8309a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
831b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		panel = &ch->cfg->panel_cfg;
832afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart		if (panel->setup_sys) {
833afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart			ret = panel->setup_sys(ch, &sh_mobile_lcdc_sys_bus_ops);
8349a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			if (ret)
8359a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart				return ret;
8368564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		}
837cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
838cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
8399a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Compute frame buffer base address and pitch for each channel. */
8409a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
8419a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		int pixelformat;
842481100506b34d666243832c3f2aee905c03cb8e7Laurent Pinchart		void *meram;
843cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
8449a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		ch = &priv->ch[k];
8459a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (!ch->enabled)
8469a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			continue;
847cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
84858f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		ch->base_addr_y = ch->dma_handle;
84958f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		ch->base_addr_c = ch->base_addr_y + ch->xres * ch->yres_virtual;
85072c04af9a2d57b7945cf3de8e71461bd80695d50Laurent Pinchart		ch->line_size = ch->pitch;
8519a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
8529a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		/* Enable MERAM if possible. */
853b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		if (mdev == NULL || mdev->ops == NULL ||
854b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		    ch->cfg->meram_cfg == NULL)
8559a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			continue;
8569a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
8579a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		/* we need to de-init configured ICBs before we can
8589a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		 * re-initialize them.
8599a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		 */
860481100506b34d666243832c3f2aee905c03cb8e7Laurent Pinchart		if (ch->meram) {
861481100506b34d666243832c3f2aee905c03cb8e7Laurent Pinchart			mdev->ops->meram_unregister(mdev, ch->meram);
862481100506b34d666243832c3f2aee905c03cb8e7Laurent Pinchart			ch->meram = NULL;
8639a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		}
8649a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
865fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart		switch (ch->format->fourcc) {
866edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV12:
867edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV21:
868edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV16:
869edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV61:
8709a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			pixelformat = SH_MOBILE_MERAM_PF_NV;
871edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			break;
872edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV24:
873edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV42:
874edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			pixelformat = SH_MOBILE_MERAM_PF_NV24;
875edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			break;
876edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_RGB565:
877edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_BGR24:
878edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_BGR32:
879edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		default:
880edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			pixelformat = SH_MOBILE_MERAM_PF_RGB;
881edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			break;
882edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		}
8839a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
884b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		meram = mdev->ops->meram_register(mdev, ch->cfg->meram_cfg,
885b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart					ch->pitch, ch->yres, pixelformat,
88672c04af9a2d57b7945cf3de8e71461bd80695d50Laurent Pinchart					&ch->line_size);
88797d16fe69b6499a14a0c85c053f7bef54ce992a4Laurent Pinchart		if (!IS_ERR(meram)) {
88897d16fe69b6499a14a0c85c053f7bef54ce992a4Laurent Pinchart			mdev->ops->meram_update(mdev, meram,
88997d16fe69b6499a14a0c85c053f7bef54ce992a4Laurent Pinchart					ch->base_addr_y, ch->base_addr_c,
89097d16fe69b6499a14a0c85c053f7bef54ce992a4Laurent Pinchart					&ch->base_addr_y, &ch->base_addr_c);
891481100506b34d666243832c3f2aee905c03cb8e7Laurent Pinchart			ch->meram = meram;
89297d16fe69b6499a14a0c85c053f7bef54ce992a4Laurent Pinchart		}
8939a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	}
8949a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
8959a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Start the LCDC. */
8969a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	__sh_mobile_lcdc_start(priv);
8979a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
8989a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Setup deferred I/O, tell the board code to enable the panels, and
8999a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	 * turn backlight on.
9009a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	 */
901cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
902cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		ch = &priv->ch[k];
90321bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm		if (!ch->enabled)
90421bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm			continue;
90521bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm
906b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		tmp = ch->cfg->sys_bus_cfg.deferred_io_msec;
9079a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (ch->ldmt1r_value & LDMT1R_IFM && tmp) {
9089a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			ch->defio.deferred_io = sh_mobile_lcdc_deferred_io;
9099a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			ch->defio.delay = msecs_to_jiffies(tmp);
9109a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			ch->info->fbdefio = &ch->defio;
9119a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			fb_deferred_io_init(ch->info);
9129a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		}
9139a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
91437c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		sh_mobile_lcdc_display_on(ch);
9153b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
9163b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		if (ch->bl) {
9173b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot			ch->bl->props.power = FB_BLANK_UNBLANK;
9183b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot			backlight_update_status(ch->bl);
9193b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		}
920cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
921cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
922cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	return 0;
923cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
924cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
925cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
926cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
927cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	struct sh_mobile_lcdc_chan *ch;
928cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	int k;
929cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
9302feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	/* clean up deferred io and ask board code to disable panel */
931cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
932cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		ch = &priv->ch[k];
93321bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm		if (!ch->enabled)
93421bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm			continue;
9358564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
9362feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		/* deferred io mode:
9372feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		 * flush frame, and wait for frame end interrupt
9382feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		 * clean up deferred io and enable clock
9392feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		 */
9405ef6b505d9df45558402bdb823a078840a6a26c4Guennadi Liakhovetski		if (ch->info && ch->info->fbdefio) {
9412feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm			ch->frame_end = 0;
942e33afddca174171a68d57476ead8947476ab9240Paul Mundt			schedule_delayed_work(&ch->info->deferred_work, 0);
9432feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm			wait_event(ch->frame_end_wait, ch->frame_end);
944e33afddca174171a68d57476ead8947476ab9240Paul Mundt			fb_deferred_io_cleanup(ch->info);
945e33afddca174171a68d57476ead8947476ab9240Paul Mundt			ch->info->fbdefio = NULL;
9462feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm			sh_mobile_lcdc_clk_on(priv);
9478564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		}
9482feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
9493b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		if (ch->bl) {
9503b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot			ch->bl->props.power = FB_BLANK_POWERDOWN;
9513b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot			backlight_update_status(ch->bl);
9523b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		}
9533b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
95437c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		sh_mobile_lcdc_display_off(ch);
9557caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
9567caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia		/* disable the meram */
957481100506b34d666243832c3f2aee905c03cb8e7Laurent Pinchart		if (ch->meram) {
9587caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia			struct sh_mobile_meram_info *mdev;
9597caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia			mdev = priv->meram_dev;
960481100506b34d666243832c3f2aee905c03cb8e7Laurent Pinchart			mdev->ops->meram_unregister(mdev, ch->meram);
961481100506b34d666243832c3f2aee905c03cb8e7Laurent Pinchart			ch->meram = 0;
9627caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia		}
9637caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
964cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
965cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
966cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	/* stop the lcdc */
9678e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm	if (priv->started) {
9688e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm		sh_mobile_lcdc_start_stop(priv, 0);
9698e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm		priv->started = 0;
9708e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm	}
971b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm
9728564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	/* stop clocks */
9738564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++)
9748564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		if (priv->ch[k].enabled)
9758564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm			sh_mobile_lcdc_clk_off(priv);
976cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
977cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
978f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
979f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Frame buffer operations
980f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
981cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
982cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_setcolreg(u_int regno,
983cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm				    u_int red, u_int green, u_int blue,
984cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm				    u_int transp, struct fb_info *info)
985cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
986cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	u32 *palette = info->pseudo_palette;
987cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
988cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (regno >= PALETTE_NR)
989cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		return -EINVAL;
990cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
991cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	/* only FB_VISUAL_TRUECOLOR supported */
992cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
993cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	red >>= 16 - info->var.red.length;
994cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	green >>= 16 - info->var.green.length;
995cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	blue >>= 16 - info->var.blue.length;
996cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	transp >>= 16 - info->var.transp.length;
997cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
998cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	palette[regno] = (red << info->var.red.offset) |
999cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	  (green << info->var.green.offset) |
1000cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	  (blue << info->var.blue.offset) |
1001cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	  (transp << info->var.transp.offset);
1002cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1003cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	return 0;
1004cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
1005cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1006cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic struct fb_fix_screeninfo sh_mobile_lcdc_fix  = {
1007cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.id =		"SH Mobile LCDC",
1008cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.type =		FB_TYPE_PACKED_PIXELS,
1009cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.visual =	FB_VISUAL_TRUECOLOR,
1010cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.accel =	FB_ACCEL_NONE,
10119dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	.xpanstep =	0,
10129dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	.ypanstep =	1,
10139dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	.ywrapstep =	0,
1014edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	.capabilities =	FB_CAP_FOURCC,
1015cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm};
1016cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
10178564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_fillrect(struct fb_info *info,
10188564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm				    const struct fb_fillrect *rect)
10198564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{
10208564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sys_fillrect(info, rect);
10218564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sh_mobile_lcdc_deferred_io_touch(info);
10228564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
10238564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
10248564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_copyarea(struct fb_info *info,
10258564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm				    const struct fb_copyarea *area)
10268564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{
10278564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sys_copyarea(info, area);
10288564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sh_mobile_lcdc_deferred_io_touch(info);
10298564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
10308564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
10318564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_imageblit(struct fb_info *info,
10328564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm				     const struct fb_image *image)
10338564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{
10348564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sys_imageblit(info, image);
10358564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sh_mobile_lcdc_deferred_io_touch(info);
10368564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
10378564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
10389dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthystatic int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
10399dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy				     struct fb_info *info)
10409dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy{
10419dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	struct sh_mobile_lcdc_chan *ch = info->par;
104292e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	struct sh_mobile_lcdc_priv *priv = ch->lcdc;
104392e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	unsigned long ldrcntr;
104492e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	unsigned long new_pan_offset;
104553b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia	unsigned long base_addr_y, base_addr_c;
104653b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia	unsigned long c_offset;
104792e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy
104858f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	if (!ch->format->yuv)
104958f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		new_pan_offset = var->yoffset * ch->pitch
105058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart			       + var->xoffset * (ch->format->bpp / 8);
105153b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia	else
105258f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		new_pan_offset = var->yoffset * ch->pitch + var->xoffset;
10539dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
105492e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	if (new_pan_offset == ch->pan_offset)
10559dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy		return 0;	/* No change, do nothing */
10569dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
105792e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	ldrcntr = lcdc_read(priv, _LDRCNTR);
10589dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
105992e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	/* Set the source address for the next refresh */
106053b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia	base_addr_y = ch->dma_handle + new_pan_offset;
106158f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	if (ch->format->yuv) {
106253b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia		/* Set y offset */
106358f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		c_offset = var->yoffset * ch->pitch
106458f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart			 * (ch->format->bpp - 8) / 8;
106558f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		base_addr_c = ch->dma_handle + ch->xres * ch->yres_virtual
1066dc1d5adab5cc57eb732407d80c9e7ae48891ffcaLaurent Pinchart			    + c_offset;
106753b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia		/* Set x offset */
1068fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart		if (ch->format->fourcc == V4L2_PIX_FMT_NV24)
106953b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia			base_addr_c += 2 * var->xoffset;
107053b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia		else
107153b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia			base_addr_c += var->xoffset;
107249d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart	}
107353b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia
1074481100506b34d666243832c3f2aee905c03cb8e7Laurent Pinchart	if (ch->meram) {
10757caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia		struct sh_mobile_meram_info *mdev;
10767caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
10777caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia		mdev = priv->meram_dev;
1078cdf88b9072a86545611b9c3f5597ebc47e50ffc1Laurent Pinchart		mdev->ops->meram_update(mdev, ch->meram,
10797caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia					base_addr_y, base_addr_c,
108049d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart					&base_addr_y, &base_addr_c);
108149d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart	}
10827caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
108349d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart	ch->base_addr_y = base_addr_y;
108449d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart	ch->base_addr_c = base_addr_c;
10857caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
108649d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart	lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);
108758f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	if (ch->format->yuv)
108849d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart		lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c);
108953b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia
109092e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	if (lcdc_chan_is_sublcd(ch))
109192e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy		lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS);
109292e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	else
109392e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy		lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_MRS);
109492e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy
109592e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	ch->pan_offset = new_pan_offset;
109692e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy
109792e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	sh_mobile_lcdc_deferred_io_touch(info);
10989dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
10999dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	return 0;
11009dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy}
11019dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
110240331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthystatic int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd,
110340331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy		       unsigned long arg)
110440331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy{
110540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	int retval;
110640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy
110740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	switch (cmd) {
110840331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	case FBIO_WAITFORVSYNC:
11094976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart		retval = sh_mobile_wait_for_vsync(info->par);
111040331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy		break;
111140331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy
111240331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	default:
111340331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy		retval = -ENOIOCTLCMD;
111440331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy		break;
111540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	}
111640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	return retval;
111740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy}
111840331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy
1119dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetskistatic void sh_mobile_fb_reconfig(struct fb_info *info)
1120dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{
1121dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	struct sh_mobile_lcdc_chan *ch = info->par;
11222d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	struct fb_var_screeninfo var;
11232d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	struct fb_videomode mode;
1124dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	struct fb_event event;
1125dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	int evnt = FB_EVENT_MODE_CHANGE_ALL;
1126dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1127dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	if (ch->use_count > 1 || (ch->use_count == 1 && !info->fbcon_par))
1128dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		/* More framebuffer users are active */
1129dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		return;
1130dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
11312d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	fb_var_to_videomode(&mode, &info->var);
1132dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
11332d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	if (fb_mode_is_equal(&ch->display.mode, &mode))
1134dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		return;
1135dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1136dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	/* Display has been re-plugged, framebuffer is free now, reconfigure */
11372d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	var = info->var;
11382d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	fb_videomode_to_var(&var, &ch->display.mode);
11392d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	var.width = ch->display.width;
11402d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	var.height = ch->display.height;
11412d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	var.activate = FB_ACTIVATE_NOW;
11422d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart
11432d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	if (fb_set_var(info, &var) < 0)
1144dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		/* Couldn't reconfigure, hopefully, can continue as before */
1145dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		return;
1146dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1147dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	/*
1148dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	 * fb_set_var() calls the notifier change internally, only if
1149dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	 * FBINFO_MISC_USEREVENT flag is set. Since we do not want to fake a
1150dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	 * user event, we have to call the chain ourselves.
1151dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	 */
1152dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	event.info = info;
11532d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart	event.data = &ch->display.mode;
1154dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	fb_notifier_call_chain(evnt, &event);
1155dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski}
1156dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1157dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski/*
1158dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski * Locking: both .fb_release() and .fb_open() are called with info->lock held if
1159dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski * user == 1, or with console sem held, if user == 0.
1160dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski */
1161dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetskistatic int sh_mobile_release(struct fb_info *info, int user)
1162dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{
1163dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	struct sh_mobile_lcdc_chan *ch = info->par;
1164dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1165dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	mutex_lock(&ch->open_lock);
1166dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count);
1167dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1168dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	ch->use_count--;
1169dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1170dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	/* Nothing to reconfigure, when called from fbcon */
1171dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	if (user) {
1172ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn		console_lock();
1173dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		sh_mobile_fb_reconfig(info);
1174ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn		console_unlock();
1175dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	}
1176dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1177dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	mutex_unlock(&ch->open_lock);
1178dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1179dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	return 0;
1180dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski}
1181dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1182dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetskistatic int sh_mobile_open(struct fb_info *info, int user)
1183dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{
1184dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	struct sh_mobile_lcdc_chan *ch = info->par;
1185dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1186dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	mutex_lock(&ch->open_lock);
1187dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	ch->use_count++;
1188dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1189dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count);
1190dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	mutex_unlock(&ch->open_lock);
1191dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1192dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	return 0;
1193dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski}
1194dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1195dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetskistatic int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1196dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{
1197dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	struct sh_mobile_lcdc_chan *ch = info->par;
1198417d48274e755e537bae60461558c1f63a4e14deMagnus Damm	struct sh_mobile_lcdc_priv *p = ch->lcdc;
11990386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	unsigned int best_dist = (unsigned int)-1;
12000386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	unsigned int best_xres = 0;
12010386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	unsigned int best_yres = 0;
12020386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	unsigned int i;
1203dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
12040386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	if (var->xres > MAX_XRES || var->yres > MAX_YRES)
1205dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		return -EINVAL;
12060386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
12070386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	/* If board code provides us with a list of available modes, make sure
12080386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	 * we use one of them. Find the mode closest to the requested one. The
12090386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	 * distance between two modes is defined as the size of the
12100386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	 * non-overlapping parts of the two rectangles.
12110386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	 */
1212b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	for (i = 0; i < ch->cfg->num_modes; ++i) {
1213b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		const struct fb_videomode *mode = &ch->cfg->lcd_modes[i];
12140386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		unsigned int dist;
12150386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
12160386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		/* We can only round up. */
12170386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		if (var->xres > mode->xres || var->yres > mode->yres)
12180386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			continue;
12190386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
12200386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		dist = var->xres * var->yres + mode->xres * mode->yres
12210386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		     - 2 * min(var->xres, mode->xres)
12220386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			 * min(var->yres, mode->yres);
12230386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
12240386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		if (dist < best_dist) {
12250386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			best_xres = mode->xres;
12260386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			best_yres = mode->yres;
12270386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			best_dist = dist;
12280386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		}
1229dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	}
1230417d48274e755e537bae60461558c1f63a4e14deMagnus Damm
12310386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	/* If no available mode can be used, return an error. */
1232b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	if (ch->cfg->num_modes != 0) {
12330386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		if (best_dist == (unsigned int)-1)
12340386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			return -EINVAL;
12350386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
12360386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		var->xres = best_xres;
12370386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		var->yres = best_yres;
12380386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	}
12390386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
12400386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	/* Make sure the virtual resolution is at least as big as the visible
12410386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	 * resolution.
12420386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	 */
12430386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	if (var->xres_virtual < var->xres)
12440386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		var->xres_virtual = var->xres;
12450386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	if (var->yres_virtual < var->yres)
12460386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		var->yres_virtual = var->yres;
12470386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
1248edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	if (sh_mobile_format_is_fourcc(var)) {
1249105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		const struct sh_mobile_lcdc_format_info *format;
1250105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart
1251105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		format = sh_mobile_format_info(var->grayscale);
1252105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		if (format == NULL)
1253edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			return -EINVAL;
1254105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		var->bits_per_pixel = format->bpp;
1255edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart
1256edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		/* Default to RGB and JPEG color-spaces for RGB and YUV formats
1257edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		 * respectively.
1258edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		 */
1259105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		if (!format->yuv)
1260edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->colorspace = V4L2_COLORSPACE_SRGB;
1261edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		else if (var->colorspace != V4L2_COLORSPACE_REC709)
1262edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->colorspace = V4L2_COLORSPACE_JPEG;
1263edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	} else {
1264edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		if (var->bits_per_pixel <= 16) {		/* RGB 565 */
1265edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->bits_per_pixel = 16;
1266edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->red.offset = 11;
1267edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->red.length = 5;
1268edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->green.offset = 5;
1269edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->green.length = 6;
1270edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->blue.offset = 0;
1271edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->blue.length = 5;
1272edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->transp.offset = 0;
1273edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->transp.length = 0;
1274edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		} else if (var->bits_per_pixel <= 24) {		/* RGB 888 */
1275edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->bits_per_pixel = 24;
1276edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->red.offset = 16;
1277edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->red.length = 8;
1278edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->green.offset = 8;
1279edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->green.length = 8;
1280edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->blue.offset = 0;
1281edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->blue.length = 8;
1282edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->transp.offset = 0;
1283edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->transp.length = 0;
1284edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		} else if (var->bits_per_pixel <= 32) {		/* RGBA 888 */
1285edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->bits_per_pixel = 32;
1286edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->red.offset = 16;
1287edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->red.length = 8;
1288edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->green.offset = 8;
1289edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->green.length = 8;
1290edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->blue.offset = 0;
1291edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->blue.length = 8;
1292edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->transp.offset = 24;
1293edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->transp.length = 8;
1294edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		} else
1295edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			return -EINVAL;
1296417d48274e755e537bae60461558c1f63a4e14deMagnus Damm
1297edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		var->red.msb_right = 0;
1298edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		var->green.msb_right = 0;
1299edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		var->blue.msb_right = 0;
1300edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		var->transp.msb_right = 0;
1301edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	}
13020386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
13030386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	/* Make sure we don't exceed our allocated memory. */
13040386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 >
13050386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	    info->fix.smem_len)
13060386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		return -EINVAL;
13070386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
1308edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	/* only accept the forced_fourcc for dual channel configurations */
1309edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	if (p->forced_fourcc &&
1310edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	    p->forced_fourcc != sh_mobile_format_fourcc(var))
1311417d48274e755e537bae60461558c1f63a4e14deMagnus Damm		return -EINVAL;
1312417d48274e755e537bae60461558c1f63a4e14deMagnus Damm
1313dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	return 0;
1314dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski}
131540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy
1316ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchartstatic int sh_mobile_set_par(struct fb_info *info)
1317ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart{
1318ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart	struct sh_mobile_lcdc_chan *ch = info->par;
1319ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart	int ret;
1320ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart
1321ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart	sh_mobile_lcdc_stop(ch->lcdc);
132291fba48d59666718e3d3e86964755b80d39cdbddLaurent Pinchart
1323fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart	ch->format = sh_mobile_format_info(sh_mobile_format_fourcc(&info->var));
132458f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->colorspace = info->var.colorspace;
132558f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
132658f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->xres = info->var.xres;
132758f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->xres_virtual = info->var.xres_virtual;
132858f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->yres = info->var.yres;
132958f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->yres_virtual = info->var.yres_virtual;
133058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
133158f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	if (ch->format->yuv)
133258f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		ch->pitch = info->var.xres;
133358f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	else
133458f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		ch->pitch = info->var.xres * ch->format->bpp / 8;
1335fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart
1336ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart	ret = sh_mobile_lcdc_start(ch->lcdc);
133758f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	if (ret < 0)
1338ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart		dev_err(info->dev, "%s: unable to restart LCDC\n", __func__);
133958f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
134058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	info->fix.line_length = ch->pitch;
1341ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart
1342edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	if (sh_mobile_format_is_fourcc(&info->var)) {
1343edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		info->fix.type = FB_TYPE_FOURCC;
1344edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		info->fix.visual = FB_VISUAL_FOURCC;
1345edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	} else {
1346edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		info->fix.type = FB_TYPE_PACKED_PIXELS;
1347edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		info->fix.visual = FB_VISUAL_TRUECOLOR;
1348edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	}
1349edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart
1350ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart	return ret;
1351ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart}
1352ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart
13538857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot/*
13548857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * Screen blanking. Behavior is as follows:
13558857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_UNBLANK: screen unblanked, clocks enabled
13568857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_NORMAL: screen blanked, clocks enabled
13578857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_VSYNC,
13588857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_HSYNC,
13598857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_POWEROFF: screen blanked, clocks disabled
13608857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot */
13618857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbotstatic int sh_mobile_lcdc_blank(int blank, struct fb_info *info)
13628857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot{
13638857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	struct sh_mobile_lcdc_chan *ch = info->par;
13648857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	struct sh_mobile_lcdc_priv *p = ch->lcdc;
13658857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot
13668857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	/* blank the screen? */
13678857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	if (blank > FB_BLANK_UNBLANK && ch->blank_status == FB_BLANK_UNBLANK) {
13688857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		struct fb_fillrect rect = {
136958f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart			.width = ch->xres,
137058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart			.height = ch->yres,
13718857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		};
13728857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		sh_mobile_lcdc_fillrect(info, &rect);
13738857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	}
13748857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	/* turn clocks on? */
13758857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	if (blank <= FB_BLANK_NORMAL && ch->blank_status > FB_BLANK_NORMAL) {
13768857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		sh_mobile_lcdc_clk_on(p);
13778857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	}
13788857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	/* turn clocks off? */
13798857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	if (blank > FB_BLANK_NORMAL && ch->blank_status <= FB_BLANK_NORMAL) {
13808857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		/* make sure the screen is updated with the black fill before
13818857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		 * switching the clocks off. one vsync is not enough since
13828857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		 * blanking may occur in the middle of a refresh. deferred io
13838857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		 * mode will reenable the clocks and update the screen in time,
13848857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		 * so it does not need this. */
13858857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		if (!info->fbdefio) {
13864976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart			sh_mobile_wait_for_vsync(ch);
13874976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart			sh_mobile_wait_for_vsync(ch);
13888857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		}
13898857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		sh_mobile_lcdc_clk_off(p);
13908857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	}
13918857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot
13928857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	ch->blank_status = blank;
13938857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	return 0;
13948857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot}
13958857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot
1396cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic struct fb_ops sh_mobile_lcdc_ops = {
13979dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	.owner          = THIS_MODULE,
1398cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.fb_setcolreg	= sh_mobile_lcdc_setcolreg,
13992540c111ead82cad605ec2b14a1905ad914cc124Magnus Damm	.fb_read        = fb_sys_read,
14002540c111ead82cad605ec2b14a1905ad914cc124Magnus Damm	.fb_write       = fb_sys_write,
14018564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	.fb_fillrect	= sh_mobile_lcdc_fillrect,
14028564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	.fb_copyarea	= sh_mobile_lcdc_copyarea,
14038564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	.fb_imageblit	= sh_mobile_lcdc_imageblit,
14048857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	.fb_blank	= sh_mobile_lcdc_blank,
14059dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	.fb_pan_display = sh_mobile_fb_pan_display,
140640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	.fb_ioctl       = sh_mobile_ioctl,
1407dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	.fb_open	= sh_mobile_open,
1408dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	.fb_release	= sh_mobile_release,
1409dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	.fb_check_var	= sh_mobile_check_var,
1410ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart	.fb_set_par	= sh_mobile_set_par,
1411cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm};
1412cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1413a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartstatic void
1414a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartsh_mobile_lcdc_channel_fb_unregister(struct sh_mobile_lcdc_chan *ch)
1415a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart{
1416a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (ch->info && ch->info->dev)
1417a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		unregister_framebuffer(ch->info);
1418a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart}
1419a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
1420a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartstatic int __devinit
1421a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartsh_mobile_lcdc_channel_fb_register(struct sh_mobile_lcdc_chan *ch)
1422a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart{
1423a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	struct fb_info *info = ch->info;
1424a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	int ret;
1425a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
1426a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (info->fbdefio) {
1427a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		ch->sglist = vmalloc(sizeof(struct scatterlist) *
1428a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart				     ch->fb_size >> PAGE_SHIFT);
1429a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		if (!ch->sglist) {
1430a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart			dev_err(ch->lcdc->dev, "cannot allocate sglist\n");
1431a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart			return -ENOMEM;
1432a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		}
1433a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	}
1434a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
1435a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->bl_dev = ch->bl;
1436a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
1437a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ret = register_framebuffer(info);
1438a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (ret < 0)
1439a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		return ret;
1440a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
1441a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	dev_info(ch->lcdc->dev, "registered %s/%s as %dx%d %dbpp.\n",
1442b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		 dev_name(ch->lcdc->dev), (ch->cfg->chan == LCDC_CHAN_MAINLCD) ?
1443a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		 "mainlcd" : "sublcd", info->var.xres, info->var.yres,
1444a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		 info->var.bits_per_pixel);
1445a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
1446a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	/* deferred io mode: disable clock to save power */
1447a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED)
1448a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		sh_mobile_lcdc_clk_off(ch->lcdc);
1449a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
1450a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	return ret;
1451a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart}
1452a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
1453a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartstatic void
1454a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartsh_mobile_lcdc_channel_fb_cleanup(struct sh_mobile_lcdc_chan *ch)
1455a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart{
1456a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	struct fb_info *info = ch->info;
1457a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
1458a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (!info || !info->device)
1459a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		return;
1460a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
1461a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (ch->sglist)
1462a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		vfree(ch->sglist);
1463a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
1464a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	fb_dealloc_cmap(&info->cmap);
1465a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	framebuffer_release(info);
1466a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart}
1467a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
1468a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartstatic int __devinit
1469a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartsh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch,
1470a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart			       const struct fb_videomode *mode,
1471a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart			       unsigned int num_modes)
1472a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart{
1473a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	struct sh_mobile_lcdc_priv *priv = ch->lcdc;
1474a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	struct fb_var_screeninfo *var;
1475a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	struct fb_info *info;
1476a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	int ret;
1477a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
1478a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	/* Allocate and initialize the frame buffer device. Create the modes
1479a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 * list and allocate the color map.
1480a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 */
1481a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info = framebuffer_alloc(0, priv->dev);
1482a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (info == NULL) {
1483a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		dev_err(priv->dev, "unable to allocate fb_info\n");
1484a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		return -ENOMEM;
1485a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	}
1486a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
1487a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ch->info = info;
1488a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
1489a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->flags = FBINFO_FLAG_DEFAULT;
1490a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->fbops = &sh_mobile_lcdc_ops;
1491a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->device = priv->dev;
1492a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->screen_base = ch->fb_mem;
1493a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->pseudo_palette = &ch->pseudo_palette;
1494a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->par = ch;
1495a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
1496a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	fb_videomode_to_modelist(mode, num_modes, &info->modelist);
1497a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
1498a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);
1499a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (ret < 0) {
1500a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		dev_err(priv->dev, "unable to allocate cmap\n");
1501a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		return ret;
1502a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	}
1503a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
1504a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	/* Initialize fixed screen information. Restrict pan to 2 lines steps
1505a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 * for NV12 and NV21.
1506a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 */
1507a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->fix = sh_mobile_lcdc_fix;
1508a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->fix.smem_start = ch->dma_handle;
1509a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	info->fix.smem_len = ch->fb_size;
151058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	info->fix.line_length = ch->pitch;
151158f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
151258f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	if (ch->format->yuv)
151358f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		info->fix.visual = FB_VISUAL_FOURCC;
151458f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	else
151558f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		info->fix.visual = FB_VISUAL_TRUECOLOR;
151658f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
1517a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (ch->format->fourcc == V4L2_PIX_FMT_NV12 ||
1518a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	    ch->format->fourcc == V4L2_PIX_FMT_NV21)
1519a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		info->fix.ypanstep = 2;
1520a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
1521a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	/* Initialize variable screen information using the first mode as
1522a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 * default. The default Y virtual resolution is twice the panel size to
1523a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 * allow for double-buffering.
1524a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 */
1525a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	var = &info->var;
1526a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	fb_videomode_to_var(var, mode);
1527b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	var->width = ch->cfg->panel_cfg.width;
1528b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	var->height = ch->cfg->panel_cfg.height;
1529a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	var->yres_virtual = var->yres * 2;
1530a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	var->activate = FB_ACTIVATE_NOW;
1531a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
1532a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	/* Use the legacy API by default for RGB formats, and the FOURCC API
1533a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 * for YUV formats.
1534a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	 */
1535a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (!ch->format->yuv)
1536a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		var->bits_per_pixel = ch->format->bpp;
1537a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	else
1538a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		var->grayscale = ch->format->fourcc;
1539a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
1540a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ret = sh_mobile_check_var(var, info);
1541a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (ret)
1542a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		return ret;
1543a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
1544a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	return 0;
1545a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart}
1546a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
1547f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
1548f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Backlight
1549f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
1550f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
15513b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic int sh_mobile_lcdc_update_bl(struct backlight_device *bdev)
15523b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{
15533b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev);
15543b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	int brightness = bdev->props.brightness;
15553b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
15563b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	if (bdev->props.power != FB_BLANK_UNBLANK ||
15573b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	    bdev->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
15583b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		brightness = 0;
15593b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
1560b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	return ch->cfg->bl_info.set_brightness(brightness);
15613b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot}
15623b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
15633b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic int sh_mobile_lcdc_get_brightness(struct backlight_device *bdev)
15643b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{
15653b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev);
15663b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
1567b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	return ch->cfg->bl_info.get_brightness();
15683b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot}
15693b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
15703b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic int sh_mobile_lcdc_check_fb(struct backlight_device *bdev,
15713b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot				   struct fb_info *info)
15723b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{
15733b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	return (info->bl_dev == bdev);
15743b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot}
15753b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
15763b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic struct backlight_ops sh_mobile_lcdc_bl_ops = {
15773b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	.options	= BL_CORE_SUSPENDRESUME,
15783b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	.update_status	= sh_mobile_lcdc_update_bl,
15793b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	.get_brightness	= sh_mobile_lcdc_get_brightness,
15803b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	.check_fb	= sh_mobile_lcdc_check_fb,
15813b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot};
15823b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
15833b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic struct backlight_device *sh_mobile_lcdc_bl_probe(struct device *parent,
15843b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot					       struct sh_mobile_lcdc_chan *ch)
15853b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{
15863b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	struct backlight_device *bl;
15873b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
1588b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	bl = backlight_device_register(ch->cfg->bl_info.name, parent, ch,
15893b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot				       &sh_mobile_lcdc_bl_ops, NULL);
1590beee1f20a185c7e79fd33bb83e04fe44ecd75af3Dan Carpenter	if (IS_ERR(bl)) {
1591beee1f20a185c7e79fd33bb83e04fe44ecd75af3Dan Carpenter		dev_err(parent, "unable to register backlight device: %ld\n",
1592beee1f20a185c7e79fd33bb83e04fe44ecd75af3Dan Carpenter			PTR_ERR(bl));
15933b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		return NULL;
15943b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	}
15953b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
1596b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	bl->props.max_brightness = ch->cfg->bl_info.max_brightness;
15973b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	bl->props.brightness = bl->props.max_brightness;
15983b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	backlight_update_status(bl);
15993b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
16003b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	return bl;
16013b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot}
16023b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
16033b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic void sh_mobile_lcdc_bl_remove(struct backlight_device *bdev)
16043b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{
16053b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	backlight_device_unregister(bdev);
16063b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot}
16073b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
1608f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
1609f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Power management
1610f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
1611f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
16122feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Dammstatic int sh_mobile_lcdc_suspend(struct device *dev)
16132feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm{
16142feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	struct platform_device *pdev = to_platform_device(dev);
16152feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
16162feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	sh_mobile_lcdc_stop(platform_get_drvdata(pdev));
16172feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	return 0;
16182feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm}
16192feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
16202feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Dammstatic int sh_mobile_lcdc_resume(struct device *dev)
16212feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm{
16222feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	struct platform_device *pdev = to_platform_device(dev);
16232feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
16242feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	return sh_mobile_lcdc_start(platform_get_drvdata(pdev));
16252feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm}
16262feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
16270246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic int sh_mobile_lcdc_runtime_suspend(struct device *dev)
16280246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm{
16290246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	struct platform_device *pdev = to_platform_device(dev);
16302427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart	struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
16310246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm
16320246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	/* turn off LCDC hardware */
16332427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart	lcdc_write(priv, _LDCNT1R, 0);
16342427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart
16350246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	return 0;
16360246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm}
16370246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm
16380246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic int sh_mobile_lcdc_runtime_resume(struct device *dev)
16390246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm{
16400246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	struct platform_device *pdev = to_platform_device(dev);
16412427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart	struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
16420246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm
16432427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart	__sh_mobile_lcdc_start(priv);
16440246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm
16450246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	return 0;
16460246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm}
16470246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm
1648471452104b8520337ae2fb48c4e61cd4896e025dAlexey Dobriyanstatic const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = {
16492feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	.suspend = sh_mobile_lcdc_suspend,
16502feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	.resume = sh_mobile_lcdc_resume,
16510246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	.runtime_suspend = sh_mobile_lcdc_runtime_suspend,
16520246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	.runtime_resume = sh_mobile_lcdc_runtime_resume,
16532feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm};
16542feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
1655f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
1656f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Framebuffer notifier
1657f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
1658f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
16596de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski/* locking: called with info->lock held */
16606011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetskistatic int sh_mobile_lcdc_notify(struct notifier_block *nb,
16616011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski				 unsigned long action, void *data)
16626011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski{
16636011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	struct fb_event *event = data;
16646011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	struct fb_info *info = event->info;
16656011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	struct sh_mobile_lcdc_chan *ch = info->par;
16666011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
16676011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	if (&ch->lcdc->notifier != nb)
1668baf163749952ca5e33dd2d6a74da023e385c3a00Guennadi Liakhovetski		return NOTIFY_DONE;
16696011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
16706011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	dev_dbg(info->dev, "%s(): action = %lu, data = %p\n",
16716011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski		__func__, action, event->data);
16726011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
16736011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	switch(action) {
16746011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	case FB_EVENT_SUSPEND:
167537c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		sh_mobile_lcdc_display_off(ch);
1676afe417c0355154c8b2547619771d6053b3c0aad7Guennadi Liakhovetski		sh_mobile_lcdc_stop(ch->lcdc);
16776011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski		break;
16786011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	case FB_EVENT_RESUME:
1679dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		mutex_lock(&ch->open_lock);
1680dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		sh_mobile_fb_reconfig(info);
1681dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		mutex_unlock(&ch->open_lock);
16826011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
168337c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		sh_mobile_lcdc_display_on(ch);
1684ebe5e12d00f4785092a9650845ad3451bbf4b311Guennadi Liakhovetski		sh_mobile_lcdc_start(ch->lcdc);
16856011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	}
16866011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
1687baf163749952ca5e33dd2d6a74da023e385c3a00Guennadi Liakhovetski	return NOTIFY_OK;
16886011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski}
16896011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
1690f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
1691f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Probe/remove and driver init/exit
1692f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
1693f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
1694217e9c4353aa86f0c7eeb4c275bca73ea8b53be1Laurent Pinchartstatic const struct fb_videomode default_720p __devinitconst = {
1695f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.name = "HDMI 720p",
1696f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.xres = 1280,
1697f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.yres = 720,
1698f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
1699f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.left_margin = 220,
1700f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.right_margin = 110,
1701f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.hsync_len = 40,
1702f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
1703f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.upper_margin = 20,
1704f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.lower_margin = 5,
1705f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.vsync_len = 5,
1706f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
1707f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.pixclock = 13468,
1708f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.refresh = 60,
1709f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
1710f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart};
1711f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
1712b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchartstatic int sh_mobile_lcdc_remove(struct platform_device *pdev)
1713b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart{
1714b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
1715b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	int i;
1716b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
1717b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	fb_unregister_client(&priv->notifier);
1718b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
1719b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
1720a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		sh_mobile_lcdc_channel_fb_unregister(&priv->ch[i]);
1721b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
1722b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	sh_mobile_lcdc_stop(priv);
1723b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
1724b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
17259a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart		struct sh_mobile_lcdc_chan *ch = &priv->ch[i];
1726b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
1727e34d0bbb062cc78802d0f0686c939ea1569889a6Laurent Pinchart		if (ch->tx_dev) {
1728e34d0bbb062cc78802d0f0686c939ea1569889a6Laurent Pinchart			ch->tx_dev->lcdc = NULL;
1729b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart			module_put(ch->cfg->tx_dev->dev.driver->owner);
1730e34d0bbb062cc78802d0f0686c939ea1569889a6Laurent Pinchart		}
17319a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart
1732a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		sh_mobile_lcdc_channel_fb_cleanup(ch);
1733b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
1734a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		if (ch->fb_mem)
1735a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart			dma_free_coherent(&pdev->dev, ch->fb_size,
1736a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart					  ch->fb_mem, ch->dma_handle);
1737b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	}
1738b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
1739b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
1740b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart		if (priv->ch[i].bl)
1741b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart			sh_mobile_lcdc_bl_remove(priv->ch[i].bl);
1742b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	}
1743b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
17444774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	if (priv->dot_clk) {
17454774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart		pm_runtime_disable(&pdev->dev);
1746b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart		clk_put(priv->dot_clk);
17474774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	}
1748b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
1749b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	if (priv->base)
1750b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart		iounmap(priv->base);
1751b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
1752b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	if (priv->irq)
1753b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart		free_irq(priv->irq, priv);
1754b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	kfree(priv);
1755b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	return 0;
1756b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart}
1757cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1758217e9c4353aa86f0c7eeb4c275bca73ea8b53be1Laurent Pinchartstatic int __devinit sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
1759f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart{
1760b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	int interface_type = ch->cfg->interface_type;
1761f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
1762f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	switch (interface_type) {
1763f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB8:
1764f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB9:
1765f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB12A:
1766f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB12B:
1767f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB16:
1768f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB18:
1769f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB24:
1770f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS8A:
1771f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS8B:
1772f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS8C:
1773f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS8D:
1774f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS9:
1775f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS12:
1776f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS16A:
1777f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS16B:
1778f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS16C:
1779f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS18:
1780f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS24:
1781f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		break;
1782f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	default:
1783f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return -EINVAL;
1784f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
1785f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
1786f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	/* SUBLCD only supports SYS interface */
1787f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	if (lcdc_chan_is_sublcd(ch)) {
1788f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		if (!(interface_type & LDMT1R_IFM))
1789f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart			return -EINVAL;
1790f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
1791f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		interface_type &= ~LDMT1R_IFM;
1792f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
1793f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
1794f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	ch->ldmt1r_value = interface_type;
1795f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	return 0;
1796f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart}
1797f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
17980a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchartstatic int __devinit
17990a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchartsh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
18000a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart			    struct sh_mobile_lcdc_chan *ch)
1801cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
1802105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	const struct sh_mobile_lcdc_format_info *format;
1803b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart	const struct sh_mobile_lcdc_chan_cfg *cfg = ch->cfg;
18043ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	const struct fb_videomode *max_mode;
18053ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	const struct fb_videomode *mode;
1806a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	unsigned int num_modes;
18073ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	unsigned int max_size;
1808a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	unsigned int i;
18093ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
1810a67472ad1ae040f073e45048cbc5a01195f2e3f5Laurent Pinchart	mutex_init(&ch->open_lock);
1811ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart	ch->notify = sh_mobile_lcdc_display_notify;
1812a67472ad1ae040f073e45048cbc5a01195f2e3f5Laurent Pinchart
1813105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	/* Validate the format. */
1814105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	format = sh_mobile_format_info(cfg->fourcc);
1815105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	if (format == NULL) {
1816105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		dev_err(priv->dev, "Invalid FOURCC %08x.\n", cfg->fourcc);
1817105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart		return -EINVAL;
1818105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart	}
1819105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart
18203ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	/* Iterate through the modes to validate them and find the highest
18213ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	 * resolution.
18223ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	 */
18233ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	max_mode = NULL;
18243ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	max_size = 0;
18253ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
182693ff259846a774ff37dca54792c5a3a6425882c0Laurent Pinchart	for (i = 0, mode = cfg->lcd_modes; i < cfg->num_modes; i++, mode++) {
18273ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		unsigned int size = mode->yres * mode->xres;
18283ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
1829edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		/* NV12/NV21 buffers must have even number of lines */
1830edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		if ((cfg->fourcc == V4L2_PIX_FMT_NV12 ||
1831edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		     cfg->fourcc == V4L2_PIX_FMT_NV21) && (mode->yres & 0x1)) {
18320a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart			dev_err(priv->dev, "yres must be multiple of 2 for "
18330a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart				"YCbCr420 mode.\n");
18343ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			return -EINVAL;
18353ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		}
18363ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
18373ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		if (size > max_size) {
18383ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			max_mode = mode;
18393ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			max_size = size;
18403ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		}
18413ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	}
18423ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
18433ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	if (!max_size)
18443ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		max_size = MAX_XRES * MAX_YRES;
18453ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	else
18460a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart		dev_dbg(priv->dev, "Found largest videomode %ux%u\n",
18473ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			max_mode->xres, max_mode->yres);
18483ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
184993ff259846a774ff37dca54792c5a3a6425882c0Laurent Pinchart	if (cfg->lcd_modes == NULL) {
18503ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		mode = &default_720p;
185193ff259846a774ff37dca54792c5a3a6425882c0Laurent Pinchart		num_modes = 1;
18523ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	} else {
185393ff259846a774ff37dca54792c5a3a6425882c0Laurent Pinchart		mode = cfg->lcd_modes;
185493ff259846a774ff37dca54792c5a3a6425882c0Laurent Pinchart		num_modes = cfg->num_modes;
18553ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	}
18563ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
185758f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	/* Use the first mode as default. */
185858f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->format = format;
185958f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->xres = mode->xres;
186058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->xres_virtual = mode->xres;
186158f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->yres = mode->yres;
186258f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	ch->yres_virtual = mode->yres * 2;
186358f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
186458f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	if (!format->yuv) {
186558f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		ch->colorspace = V4L2_COLORSPACE_SRGB;
186658f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		ch->pitch = ch->xres * format->bpp / 8;
186758f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	} else {
186858f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		ch->colorspace = V4L2_COLORSPACE_REC709;
186958f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart		ch->pitch = ch->xres;
187058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart	}
187158f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart
1872a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ch->display.width = cfg->panel_cfg.width;
1873a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ch->display.height = cfg->panel_cfg.height;
1874a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ch->display.mode = *mode;
1875a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart
1876a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	/* Allocate frame buffer memory. */
1877a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ch->fb_size = max_size * format->bpp / 8 * 2;
1878a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	ch->fb_mem = dma_alloc_coherent(priv->dev, ch->fb_size, &ch->dma_handle,
1879a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart					GFP_KERNEL);
1880a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	if (ch->fb_mem == NULL) {
1881a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		dev_err(priv->dev, "unable to allocate buffer\n");
1882a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		return -ENOMEM;
1883a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	}
18843ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
188513f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart	/* Initialize the transmitter device if present. */
188613f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart	if (cfg->tx_dev) {
188713f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart		if (!cfg->tx_dev->dev.driver ||
188813f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart		    !try_module_get(cfg->tx_dev->dev.driver->owner)) {
188913f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart			dev_warn(priv->dev,
189013f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart				 "unable to get transmitter device\n");
189113f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart			return -EINVAL;
189213f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart		}
189313f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart		ch->tx_dev = platform_get_drvdata(cfg->tx_dev);
189413f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart		ch->tx_dev->lcdc = ch;
189513f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart		ch->tx_dev->def_mode = *mode;
189613f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart	}
189713f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart
1898a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart	return sh_mobile_lcdc_channel_fb_init(ch, mode, num_modes);
18993ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart}
19003ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
19013ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchartstatic int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
19023ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart{
190301ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski	struct sh_mobile_lcdc_info *pdata = pdev->dev.platform_data;
19043ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	struct sh_mobile_lcdc_priv *priv;
1905cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	struct resource *res;
19063ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	int num_channels;
1907cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	int error;
19083ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	int i;
1909cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
191001ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski	if (!pdata) {
1911cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		dev_err(&pdev->dev, "no platform data defined\n");
19128bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski		return -EINVAL;
1913cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
1914cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1915cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
19168564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	i = platform_get_irq(pdev, 0);
19178564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	if (!res || i < 0) {
19188564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		dev_err(&pdev->dev, "cannot get platform resources\n");
19198bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski		return -ENOENT;
1920cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
1921cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1922cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
1923cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (!priv) {
1924cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		dev_err(&pdev->dev, "cannot allocate device data\n");
19258bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski		return -ENOMEM;
1926cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
1927cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
19284774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	priv->dev = &pdev->dev;
19294774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	priv->meram_dev = pdata->meram_dev;
19308bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski	platform_set_drvdata(pdev, priv);
19318bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski
1932f8798ccbefc0e4ef7438c080b7ba0410738c8cfaYong Zhang	error = request_irq(i, sh_mobile_lcdc_irq, 0,
19337ad33e74857f16f1202cbc5746faf52e88e8b376Kay Sievers			    dev_name(&pdev->dev), priv);
19348564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	if (error) {
19358564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		dev_err(&pdev->dev, "unable to request irq\n");
19368564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		goto err1;
19378564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	}
19388564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
19398564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	priv->irq = i;
19405ef6b505d9df45558402bdb823a078840a6a26c4Guennadi Liakhovetski	atomic_set(&priv->hw_usecnt, -1);
1941cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
19423ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	for (i = 0, num_channels = 0; i < ARRAY_SIZE(pdata->ch); i++) {
19433ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		struct sh_mobile_lcdc_chan *ch = priv->ch + num_channels;
1944cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
194501ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski		ch->lcdc = priv;
1946b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		ch->cfg = &pdata->ch[i];
1947cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
194801ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski		error = sh_mobile_lcdc_check_interface(ch);
1949cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (error) {
1950cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			dev_err(&pdev->dev, "unsupported interface type\n");
1951cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			goto err1;
1952cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		}
195301ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski		init_waitqueue_head(&ch->frame_end_wait);
195401ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski		init_completion(&ch->vsync_completion);
195501ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski		ch->pan_offset = 0;
1956cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
19573b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		/* probe the backlight is there is one defined */
1958b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart		if (ch->cfg->bl_info.max_brightness)
19593b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot			ch->bl = sh_mobile_lcdc_bl_probe(&pdev->dev, ch);
19603b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
1961cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		switch (pdata->ch[i].chan) {
1962cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		case LCDC_CHAN_MAINLCD:
1963ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart			ch->enabled = LDCNT2R_ME;
196401ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski			ch->reg_offs = lcdc_offs_mainlcd;
19653ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			num_channels++;
1966cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			break;
1967cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		case LCDC_CHAN_SUBLCD:
1968ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart			ch->enabled = LDCNT2R_SE;
196901ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski			ch->reg_offs = lcdc_offs_sublcd;
19703ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			num_channels++;
1971cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			break;
1972cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		}
1973cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
1974cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
19753ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	if (!num_channels) {
1976cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		dev_err(&pdev->dev, "no channels defined\n");
1977cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		error = -EINVAL;
1978cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		goto err1;
1979cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
1980cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1981edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	/* for dual channel LCDC (MAIN + SUB) force shared format setting */
19823ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	if (num_channels == 2)
1983edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		priv->forced_fourcc = pdata->ch[0].fourcc;
1984417d48274e755e537bae60461558c1f63a4e14deMagnus Damm
1985dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski	priv->base = ioremap_nocache(res->start, resource_size(res));
1986dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski	if (!priv->base)
1987dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski		goto err1;
1988dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski
19890a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart	error = sh_mobile_lcdc_setup_clocks(priv, pdata->clock_source);
1990cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (error) {
1991cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		dev_err(&pdev->dev, "unable to setup clocks\n");
1992cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		goto err1;
1993cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
1994cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
19954774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	/* Enable runtime PM. */
19964774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	pm_runtime_enable(&pdev->dev);
19977caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
19983ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	for (i = 0; i < num_channels; i++) {
199901ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski		struct sh_mobile_lcdc_chan *ch = priv->ch + i;
2000c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski
20010a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart		error = sh_mobile_lcdc_channel_init(priv, ch);
2002cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (error)
20033ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			goto err1;
2004cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2005cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2006cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	error = sh_mobile_lcdc_start(priv);
2007cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (error) {
2008cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		dev_err(&pdev->dev, "unable to start hardware\n");
2009cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		goto err1;
2010cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2011cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
20123ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	for (i = 0; i < num_channels; i++) {
20131c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt		struct sh_mobile_lcdc_chan *ch = priv->ch + i;
20141c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt
2015a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		error = sh_mobile_lcdc_channel_fb_register(ch);
2016a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart		if (error)
2017cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			goto err1;
2018cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
2019cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
20206011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	/* Failure ignored */
20216011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	priv->notifier.notifier_call = sh_mobile_lcdc_notify;
20226011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	fb_register_client(&priv->notifier);
20236011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
2024cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	return 0;
20258bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetskierr1:
2026cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	sh_mobile_lcdc_remove(pdev);
20278bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski
2028cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	return error;
2029cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
2030cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2031cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic struct platform_driver sh_mobile_lcdc_driver = {
2032cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.driver		= {
2033cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		.name		= "sh_mobile_lcdc_fb",
2034cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		.owner		= THIS_MODULE,
20352feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		.pm		= &sh_mobile_lcdc_dev_pm_ops,
2036cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	},
2037cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.probe		= sh_mobile_lcdc_probe,
2038cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.remove		= sh_mobile_lcdc_remove,
2039cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm};
2040cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
20414277f2c4667187cbbdd3da3be31ee681bc6b8300Axel Linmodule_platform_driver(sh_mobile_lcdc_driver);
2042cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
2043cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_DESCRIPTION("SuperH Mobile LCDC Framebuffer driver");
2044cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
2045cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_LICENSE("GPL v2");
2046