sh_mobile_lcdcfb.c revision 9a2985e7f943678154f5761dad753f1987c2fdd0
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{
119f1f60b5f55099a658a5f79cc453b371a439864e6Laurent 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;
2761c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt	unsigned int nr_pages_max = info->fix.smem_len >> 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;
292ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm	struct sh_mobile_lcdc_board_cfg	*bcfg = &ch->cfg.board_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 */
3165c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt		dma_map_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
317ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm		if (bcfg->start_transfer)
318ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm			bcfg->start_transfer(bcfg->board_data, ch,
319ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm					     &sh_mobile_lcdc_sys_bus_ops);
320ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart		lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG);
3215c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt		dma_unmap_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
322ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm	} else {
323ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm		if (bcfg->start_transfer)
324ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm			bcfg->start_transfer(bcfg->board_data, ch,
325ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm					     &sh_mobile_lcdc_sys_bus_ops);
326ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart		lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG);
327ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm	}
3288564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
3298564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
3308564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info)
3318564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{
3328564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	struct fb_deferred_io *fbdefio = info->fbdefio;
3338564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
3348564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	if (fbdefio)
3358564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		schedule_delayed_work(&info->deferred_work, fbdefio->delay);
3368564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
3378564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
33837c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchartstatic void sh_mobile_lcdc_display_on(struct sh_mobile_lcdc_chan *ch)
33937c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart{
34037c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart	struct sh_mobile_lcdc_board_cfg	*board_cfg = &ch->cfg.board_cfg;
34137c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart
3429a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart	if (ch->tx_dev) {
3439a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart		if (ch->tx_dev->ops->display_on(ch->tx_dev, ch->info) < 0)
3449a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart			return;
3459a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart	}
3469a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart
34737c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart	/* HDMI must be enabled before LCDC configuration */
34837c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart	if (board_cfg->display_on && try_module_get(board_cfg->owner)) {
34937c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		board_cfg->display_on(board_cfg->board_data, ch->info);
35037c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		module_put(board_cfg->owner);
35137c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart	}
35237c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart}
35337c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart
35437c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchartstatic void sh_mobile_lcdc_display_off(struct sh_mobile_lcdc_chan *ch)
35537c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart{
35637c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart	struct sh_mobile_lcdc_board_cfg	*board_cfg = &ch->cfg.board_cfg;
35737c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart
35837c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart	if (board_cfg->display_off && try_module_get(board_cfg->owner)) {
35937c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		board_cfg->display_off(board_cfg->board_data);
36037c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		module_put(board_cfg->owner);
36137c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart	}
3629a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart
3639a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart	if (ch->tx_dev)
3649a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart		ch->tx_dev->ops->display_off(ch->tx_dev);
36537c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart}
36637c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart
367f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
368f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Format helpers
369f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
370f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
371f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchartstatic int sh_mobile_format_fourcc(const struct fb_var_screeninfo *var)
372f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart{
373f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	if (var->grayscale > 1)
374f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return var->grayscale;
375f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
376f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	switch (var->bits_per_pixel) {
377f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case 16:
378f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return V4L2_PIX_FMT_RGB565;
379f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case 24:
380f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return V4L2_PIX_FMT_BGR24;
381f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case 32:
382f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return V4L2_PIX_FMT_BGR32;
383f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	default:
384f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return 0;
385f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
386f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart}
387f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
388f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchartstatic int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var)
389f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart{
390f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	return var->grayscale > 1;
391f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart}
392f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
393f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchartstatic bool sh_mobile_format_is_yuv(const struct fb_var_screeninfo *var)
394f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart{
395f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	if (var->grayscale <= 1)
396f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return false;
397f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
398f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	switch (var->grayscale) {
399f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case V4L2_PIX_FMT_NV12:
400f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case V4L2_PIX_FMT_NV21:
401f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case V4L2_PIX_FMT_NV16:
402f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case V4L2_PIX_FMT_NV61:
403f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case V4L2_PIX_FMT_NV24:
404f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case V4L2_PIX_FMT_NV42:
405f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return true;
406f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
407f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	default:
408f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return false;
409f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
410f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart}
411f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
412f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
413f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Start, stop and IRQ
414f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
415f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
4168564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
4178564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{
4188564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	struct sh_mobile_lcdc_priv *priv = data;
4192feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	struct sh_mobile_lcdc_chan *ch;
4209dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	unsigned long ldintr;
4212feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	int is_sub;
4222feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	int k;
4238564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
424dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart	/* Acknowledge interrupts and disable further VSYNC End IRQs. */
425dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart	ldintr = lcdc_read(priv, _LDINTR);
426dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart	lcdc_write(priv, _LDINTR, (ldintr ^ LDINTR_STATUS_MASK) & ~LDINTR_VEE);
4278564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
4282feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	/* figure out if this interrupt is for main or sub lcd */
429ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	is_sub = (lcdc_read(priv, _LDSR) & LDSR_MSS) ? 1 : 0;
4302feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
4319dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	/* wake up channel and disable clocks */
4322feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
4332feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		ch = &priv->ch[k];
4342feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
4352feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		if (!ch->enabled)
4362feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm			continue;
4372feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
438dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart		/* Frame End */
4399dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy		if (ldintr & LDINTR_FS) {
4409dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy			if (is_sub == lcdc_chan_is_sublcd(ch)) {
4419dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy				ch->frame_end = 1;
4429dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy				wake_up(&ch->frame_end_wait);
4432feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
4449dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy				sh_mobile_lcdc_clk_off(priv);
4459dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy			}
4469dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy		}
4479dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
4489dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy		/* VSYNC End */
44940331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy		if (ldintr & LDINTR_VES)
45040331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy			complete(&ch->vsync_completion);
4512feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	}
4522feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
4538564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	return IRQ_HANDLED;
4548564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
4558564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
456cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv,
457cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm				      int start)
458cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
459cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	unsigned long tmp = lcdc_read(priv, _LDCNT2R);
460cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	int k;
461cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
462cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	/* start or stop the lcdc */
463cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (start)
464ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart		lcdc_write(priv, _LDCNT2R, tmp | LDCNT2R_DO);
465cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	else
466ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart		lcdc_write(priv, _LDCNT2R, tmp & ~LDCNT2R_DO);
467cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
468cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	/* wait until power is applied/stopped on all channels */
469cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++)
470cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (lcdc_read(priv, _LDCNT2R) & priv->ch[k].enabled)
471cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			while (1) {
472ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart				tmp = lcdc_read_chan(&priv->ch[k], LDPMR)
473ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart				    & LDPMR_LPS;
474ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart				if (start && tmp == LDPMR_LPS)
475cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm					break;
476cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm				if (!start && tmp == 0)
477cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm					break;
478cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm				cpu_relax();
479cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			}
480cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
481cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (!start)
482cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		lcdc_write(priv, _LDDCKSTPR, 1); /* stop dotclock */
483cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
484cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
4856011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetskistatic void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
4866011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski{
4871c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski	struct fb_var_screeninfo *var = &ch->info->var, *display_var = &ch->display_var;
4881c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski	unsigned long h_total, hsync_pos, display_h_total;
4896011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	u32 tmp;
4906011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
4916011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	tmp = ch->ldmt1r_value;
492ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	tmp |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : LDMT1R_VPOL;
493ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	tmp |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : LDMT1R_HPOL;
494ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	tmp |= (ch->cfg.flags & LCDC_FLAGS_DWPOL) ? LDMT1R_DWPOL : 0;
495ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	tmp |= (ch->cfg.flags & LCDC_FLAGS_DIPOL) ? LDMT1R_DIPOL : 0;
496ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	tmp |= (ch->cfg.flags & LCDC_FLAGS_DAPOL) ? LDMT1R_DAPOL : 0;
497ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	tmp |= (ch->cfg.flags & LCDC_FLAGS_HSCNT) ? LDMT1R_HSCNT : 0;
498ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart	tmp |= (ch->cfg.flags & LCDC_FLAGS_DWCNT) ? LDMT1R_DWCNT : 0;
4996011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDMT1R, tmp);
5006011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
5016011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	/* setup SYS bus */
5026011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDMT2R, ch->cfg.sys_bus_cfg.ldmt2r);
5036011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDMT3R, ch->cfg.sys_bus_cfg.ldmt3r);
5046011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
5056011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	/* horizontal configuration */
5061c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski	h_total = display_var->xres + display_var->hsync_len +
5071c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski		display_var->left_margin + display_var->right_margin;
5086011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	tmp = h_total / 8; /* HTCN */
5091c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski	tmp |= (min(display_var->xres, var->xres) / 8) << 16; /* HDCN */
5106011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDHCNR, tmp);
5116011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
5121c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski	hsync_pos = display_var->xres + display_var->right_margin;
5136011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	tmp = hsync_pos / 8; /* HSYNP */
5141c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski	tmp |= (display_var->hsync_len / 8) << 16; /* HSYNW */
5156011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDHSYNR, tmp);
5166011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
5176011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	/* vertical configuration */
5181c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski	tmp = display_var->yres + display_var->vsync_len +
5191c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski		display_var->upper_margin + display_var->lower_margin; /* VTLN */
5201c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski	tmp |= min(display_var->yres, var->yres) << 16; /* VDLN */
5216011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDVLNR, tmp);
5226011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
5231c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski	tmp = display_var->yres + display_var->lower_margin; /* VSYNP */
5241c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski	tmp |= display_var->vsync_len << 16; /* VSYNW */
5256011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDVSYNR, tmp);
5266011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
5276011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	/* Adjust horizontal synchronisation for HDMI */
5281c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski	display_h_total = display_var->xres + display_var->hsync_len +
5291c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski		display_var->left_margin + display_var->right_margin;
5301c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski	tmp = ((display_var->xres & 7) << 24) |
5311c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski		((display_h_total & 7) << 16) |
5321c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski		((display_var->hsync_len & 7) << 8) |
53341e583c22c3f907e46e329764b4606117040a1aeKuninori Morimoto		(hsync_pos & 7);
5346011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	lcdc_write_chan(ch, LDHAJR, tmp);
5356011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski}
5366011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
5379a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart/*
5389a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart * __sh_mobile_lcdc_start - Configure and tart the LCDC
5399a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart * @priv: LCDC device
5409a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart *
5419a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart * Configure all enabled channels and start the LCDC device. All external
5429a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart * devices (clocks, MERAM, panels, ...) are not touched by this function.
5439a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart */
5449a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchartstatic void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
545cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
546cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	struct sh_mobile_lcdc_chan *ch;
547cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	unsigned long tmp;
5489a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	int k, m;
5498564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
5509a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Enable LCDC channels. Read data from external memory, avoid using the
5519a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	 * BEU for now.
5529a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	 */
5539a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_write(priv, _LDCNT2R, priv->ch[0].enabled | priv->ch[1].enabled);
554cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
5559a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Stop the LCDC first and disable all interrupts. */
556cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	sh_mobile_lcdc_start_stop(priv, 0);
5579a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_write(priv, _LDINTR, 0);
558cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
5599a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Configure power supply, dot clocks and start them. */
560cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	tmp = priv->lddckr;
561cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
562cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		ch = &priv->ch[k];
5639a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (!ch->enabled)
564cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			continue;
565cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
5669a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		/* Power supply */
5679a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		lcdc_write_chan(ch, LDPMR, 0);
5689a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
569cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		m = ch->cfg.clock_divider;
570cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (!m)
571cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			continue;
572cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
573505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart		/* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider
574505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart		 * denominator.
575505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart		 */
576505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart		lcdc_write_chan(ch, LDDCKPAT1R, 0);
577505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart		lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1);
578505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart
579cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (m == 1)
580ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart			m = LDDCKR_MOSEL;
581cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0);
582cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
583cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
584cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	lcdc_write(priv, _LDDCKR, tmp);
585cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	lcdc_write(priv, _LDDCKSTPR, 0);
586cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0);
587cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
5889a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Setup geometry, format, frame buffer memory and operation mode. */
589cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
590cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		ch = &priv->ch[k];
591cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (!ch->enabled)
592cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			continue;
593cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
5946011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski		sh_mobile_lcdc_geometry(ch);
595cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
596edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		switch (sh_mobile_format_fourcc(&ch->info->var)) {
597edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_RGB565:
598edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			tmp = LDDFR_PKF_RGB16;
599edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			break;
600edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_BGR24:
601edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			tmp = LDDFR_PKF_RGB24;
602edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			break;
603edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_BGR32:
604edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			tmp = LDDFR_PKF_ARGB32;
605edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			break;
606edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV12:
607edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV21:
608edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			tmp = LDDFR_CC | LDDFR_YF_420;
609edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			break;
610edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV16:
611edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV61:
612edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			tmp = LDDFR_CC | LDDFR_YF_422;
613edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			break;
614edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV24:
615edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV42:
616edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			tmp = LDDFR_CC | LDDFR_YF_444;
617edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			break;
618edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		}
619edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart
620edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		if (sh_mobile_format_is_yuv(&ch->info->var)) {
621edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			switch (ch->info->var.colorspace) {
622edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			case V4L2_COLORSPACE_REC709:
623edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart				tmp |= LDDFR_CF1;
62453b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia				break;
625edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			case V4L2_COLORSPACE_JPEG:
626edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart				tmp |= LDDFR_CF0;
62753b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia				break;
62853b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia			}
629417d48274e755e537bae60461558c1f63a4e14deMagnus Damm		}
6307caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
6319a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		lcdc_write_chan(ch, LDDFR, tmp);
6329a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		lcdc_write_chan(ch, LDMLSR, ch->pitch);
6339a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		lcdc_write_chan(ch, LDSA1R, ch->base_addr_y);
634edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		if (sh_mobile_format_is_yuv(&ch->info->var))
6359a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			lcdc_write_chan(ch, LDSA2R, ch->base_addr_c);
6367caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
6379a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		/* When using deferred I/O mode, configure the LCDC for one-shot
6389a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		 * operation and enable the frame end interrupt. Otherwise use
6399a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		 * continuous read mode.
6409a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		 */
6419a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (ch->ldmt1r_value & LDMT1R_IFM &&
6429a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		    ch->cfg.sys_bus_cfg.deferred_io_msec) {
6439a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			lcdc_write_chan(ch, LDSM1R, LDSM1R_OS);
6449a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			lcdc_write(priv, _LDINTR, LDINTR_FE);
6459a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		} else {
6469a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			lcdc_write_chan(ch, LDSM1R, 0);
6479a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		}
6489a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	}
6497caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
6509a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Word and long word swap. */
651edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	switch (sh_mobile_format_fourcc(&priv->ch[0].info->var)) {
652edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_RGB565:
653edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV21:
654edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV61:
655edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV42:
656edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		tmp = LDDDSR_LS | LDDDSR_WS;
657edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		break;
658edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_BGR24:
659edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV12:
660edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV16:
661edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_NV24:
6629a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;
663edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		break;
664edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_BGR32:
665edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	default:
666edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		tmp = LDDDSR_LS;
667edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		break;
6689a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	}
6699a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_write(priv, _LDDDSR, tmp);
6707caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
6719a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Enable the display output. */
6729a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_write(priv, _LDCNT1R, LDCNT1R_DE);
6739a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	sh_mobile_lcdc_start_stop(priv, 1);
6749a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	priv->started = 1;
6759a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart}
676cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
6779a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchartstatic int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
6789a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart{
6799a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	struct sh_mobile_meram_info *mdev = priv->meram_dev;
6809a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	struct sh_mobile_lcdc_chan *ch;
6819a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	unsigned long tmp;
6829a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	int ret;
6839a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	int k;
684cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
6859a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* enable clocks before accessing the hardware */
6869a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
6879a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (priv->ch[k].enabled)
6889a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			sh_mobile_lcdc_clk_on(priv);
6899a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	}
6908564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
6919a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* reset */
6929a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LDCNT2R_BR);
6939a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	lcdc_wait_bit(priv, _LDCNT2R, LDCNT2R_BR, 0);
6948564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
6959a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
69637c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		struct sh_mobile_lcdc_board_cfg	*board_cfg;
6978564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
69837c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		ch = &priv->ch[k];
6999a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (!ch->enabled)
7009a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			continue;
7019a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
7029a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		board_cfg = &ch->cfg.board_cfg;
7039a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (board_cfg->setup_sys) {
7049a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			ret = board_cfg->setup_sys(board_cfg->board_data, ch,
7059a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart						   &sh_mobile_lcdc_sys_bus_ops);
7069a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			if (ret)
7079a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart				return ret;
7088564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		}
709cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
710cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
7119a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Compute frame buffer base address and pitch for each channel. */
7129a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
7139a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		struct sh_mobile_meram_cfg *cfg;
7149a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		int pixelformat;
715cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
7169a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		ch = &priv->ch[k];
7179a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (!ch->enabled)
7189a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			continue;
719cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
7209a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		ch->base_addr_y = ch->info->fix.smem_start;
7219a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		ch->base_addr_c = ch->base_addr_y
7229a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart				+ ch->info->var.xres
7239a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart				* ch->info->var.yres_virtual;
7249a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		ch->pitch = ch->info->fix.line_length;
7259a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
7269a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		/* Enable MERAM if possible. */
7279a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		cfg = ch->cfg.meram_cfg;
7289a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (mdev == NULL || mdev->ops == NULL || cfg == NULL)
7299a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			continue;
7309a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
7319a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		/* we need to de-init configured ICBs before we can
7329a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		 * re-initialize them.
7339a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		 */
7349a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (ch->meram_enabled) {
7359a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			mdev->ops->meram_unregister(mdev, cfg);
7369a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			ch->meram_enabled = 0;
7379a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		}
7389a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
739edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		switch (sh_mobile_format_fourcc(&ch->info->var)) {
740edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV12:
741edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV21:
742edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV16:
743edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV61:
7449a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			pixelformat = SH_MOBILE_MERAM_PF_NV;
745edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			break;
746edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV24:
747edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV42:
748edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			pixelformat = SH_MOBILE_MERAM_PF_NV24;
749edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			break;
750edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_RGB565:
751edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_BGR24:
752edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_BGR32:
753edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		default:
754edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			pixelformat = SH_MOBILE_MERAM_PF_RGB;
755edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			break;
756edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		}
7579a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
7589a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		ret = mdev->ops->meram_register(mdev, cfg, ch->pitch,
7599a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart					ch->info->var.yres, pixelformat,
7609a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart					ch->base_addr_y, ch->base_addr_c,
7619a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart					&ch->base_addr_y, &ch->base_addr_c,
7629a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart					&ch->pitch);
7639a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (!ret)
7649a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			ch->meram_enabled = 1;
7659a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	}
7669a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
7679a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Start the LCDC. */
7689a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	__sh_mobile_lcdc_start(priv);
7699a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
7709a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	/* Setup deferred I/O, tell the board code to enable the panels, and
7719a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	 * turn backlight on.
7729a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart	 */
773cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
774cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		ch = &priv->ch[k];
77521bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm		if (!ch->enabled)
77621bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm			continue;
77721bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm
7789a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		tmp = ch->cfg.sys_bus_cfg.deferred_io_msec;
7799a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		if (ch->ldmt1r_value & LDMT1R_IFM && tmp) {
7809a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			ch->defio.deferred_io = sh_mobile_lcdc_deferred_io;
7819a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			ch->defio.delay = msecs_to_jiffies(tmp);
7829a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			ch->info->fbdefio = &ch->defio;
7839a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart			fb_deferred_io_init(ch->info);
7849a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart		}
7859a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart
78637c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		sh_mobile_lcdc_display_on(ch);
7873b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
7883b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		if (ch->bl) {
7893b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot			ch->bl->props.power = FB_BLANK_UNBLANK;
7903b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot			backlight_update_status(ch->bl);
7913b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		}
792cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
793cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
794cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	return 0;
795cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
796cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
797cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
798cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
799cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	struct sh_mobile_lcdc_chan *ch;
800cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	int k;
801cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
8022feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	/* clean up deferred io and ask board code to disable panel */
803cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
804cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		ch = &priv->ch[k];
80521bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm		if (!ch->enabled)
80621bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm			continue;
8078564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
8082feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		/* deferred io mode:
8092feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		 * flush frame, and wait for frame end interrupt
8102feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		 * clean up deferred io and enable clock
8112feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		 */
8125ef6b505d9df45558402bdb823a078840a6a26c4Guennadi Liakhovetski		if (ch->info && ch->info->fbdefio) {
8132feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm			ch->frame_end = 0;
814e33afddca174171a68d57476ead8947476ab9240Paul Mundt			schedule_delayed_work(&ch->info->deferred_work, 0);
8152feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm			wait_event(ch->frame_end_wait, ch->frame_end);
816e33afddca174171a68d57476ead8947476ab9240Paul Mundt			fb_deferred_io_cleanup(ch->info);
817e33afddca174171a68d57476ead8947476ab9240Paul Mundt			ch->info->fbdefio = NULL;
8182feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm			sh_mobile_lcdc_clk_on(priv);
8198564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		}
8202feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
8213b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		if (ch->bl) {
8223b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot			ch->bl->props.power = FB_BLANK_POWERDOWN;
8233b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot			backlight_update_status(ch->bl);
8243b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		}
8253b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
82637c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		sh_mobile_lcdc_display_off(ch);
8277caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
8287caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia		/* disable the meram */
8297caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia		if (ch->meram_enabled) {
8307caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia			struct sh_mobile_meram_cfg *cfg;
8317caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia			struct sh_mobile_meram_info *mdev;
8327caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia			cfg = ch->cfg.meram_cfg;
8337caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia			mdev = priv->meram_dev;
8347caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia			mdev->ops->meram_unregister(mdev, cfg);
8357caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia			ch->meram_enabled = 0;
8367caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia		}
8377caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
838cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
839cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
840cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	/* stop the lcdc */
8418e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm	if (priv->started) {
8428e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm		sh_mobile_lcdc_start_stop(priv, 0);
8438e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm		priv->started = 0;
8448e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm	}
845b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm
8468564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	/* stop clocks */
8478564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	for (k = 0; k < ARRAY_SIZE(priv->ch); k++)
8488564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		if (priv->ch[k].enabled)
8498564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm			sh_mobile_lcdc_clk_off(priv);
850cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
851cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
852f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
853f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Frame buffer operations
854f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
855cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
856cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_setcolreg(u_int regno,
857cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm				    u_int red, u_int green, u_int blue,
858cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm				    u_int transp, struct fb_info *info)
859cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
860cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	u32 *palette = info->pseudo_palette;
861cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
862cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (regno >= PALETTE_NR)
863cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		return -EINVAL;
864cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
865cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	/* only FB_VISUAL_TRUECOLOR supported */
866cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
867cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	red >>= 16 - info->var.red.length;
868cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	green >>= 16 - info->var.green.length;
869cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	blue >>= 16 - info->var.blue.length;
870cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	transp >>= 16 - info->var.transp.length;
871cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
872cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	palette[regno] = (red << info->var.red.offset) |
873cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	  (green << info->var.green.offset) |
874cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	  (blue << info->var.blue.offset) |
875cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	  (transp << info->var.transp.offset);
876cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
877cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	return 0;
878cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
879cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
880cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic struct fb_fix_screeninfo sh_mobile_lcdc_fix  = {
881cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.id =		"SH Mobile LCDC",
882cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.type =		FB_TYPE_PACKED_PIXELS,
883cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.visual =	FB_VISUAL_TRUECOLOR,
884cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.accel =	FB_ACCEL_NONE,
8859dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	.xpanstep =	0,
8869dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	.ypanstep =	1,
8879dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	.ywrapstep =	0,
888edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	.capabilities =	FB_CAP_FOURCC,
889cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm};
890cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
8918564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_fillrect(struct fb_info *info,
8928564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm				    const struct fb_fillrect *rect)
8938564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{
8948564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sys_fillrect(info, rect);
8958564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sh_mobile_lcdc_deferred_io_touch(info);
8968564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
8978564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
8988564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_copyarea(struct fb_info *info,
8998564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm				    const struct fb_copyarea *area)
9008564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{
9018564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sys_copyarea(info, area);
9028564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sh_mobile_lcdc_deferred_io_touch(info);
9038564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
9048564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
9058564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_imageblit(struct fb_info *info,
9068564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm				     const struct fb_image *image)
9078564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{
9088564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sys_imageblit(info, image);
9098564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	sh_mobile_lcdc_deferred_io_touch(info);
9108564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm}
9118564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
9129dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthystatic int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
9139dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy				     struct fb_info *info)
9149dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy{
9159dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	struct sh_mobile_lcdc_chan *ch = info->par;
91692e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	struct sh_mobile_lcdc_priv *priv = ch->lcdc;
91792e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	unsigned long ldrcntr;
91892e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	unsigned long new_pan_offset;
91953b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia	unsigned long base_addr_y, base_addr_c;
92053b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia	unsigned long c_offset;
921edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	bool yuv = sh_mobile_format_is_yuv(&info->var);
92292e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy
923edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	if (!yuv)
924dc1d5adab5cc57eb732407d80c9e7ae48891ffcaLaurent Pinchart		new_pan_offset = var->yoffset * info->fix.line_length
925dc1d5adab5cc57eb732407d80c9e7ae48891ffcaLaurent Pinchart			       + var->xoffset * (info->var.bits_per_pixel / 8);
92653b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia	else
927dc1d5adab5cc57eb732407d80c9e7ae48891ffcaLaurent Pinchart		new_pan_offset = var->yoffset * info->fix.line_length
928dc1d5adab5cc57eb732407d80c9e7ae48891ffcaLaurent Pinchart			       + var->xoffset;
9299dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
93092e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	if (new_pan_offset == ch->pan_offset)
9319dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy		return 0;	/* No change, do nothing */
9329dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
93392e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	ldrcntr = lcdc_read(priv, _LDRCNTR);
9349dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
93592e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	/* Set the source address for the next refresh */
93653b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia	base_addr_y = ch->dma_handle + new_pan_offset;
937edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	if (yuv) {
93853b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia		/* Set y offset */
939dc1d5adab5cc57eb732407d80c9e7ae48891ffcaLaurent Pinchart		c_offset = var->yoffset * info->fix.line_length
940dc1d5adab5cc57eb732407d80c9e7ae48891ffcaLaurent Pinchart			 * (info->var.bits_per_pixel - 8) / 8;
941dc1d5adab5cc57eb732407d80c9e7ae48891ffcaLaurent Pinchart		base_addr_c = ch->dma_handle
942dc1d5adab5cc57eb732407d80c9e7ae48891ffcaLaurent Pinchart			    + info->var.xres * info->var.yres_virtual
943dc1d5adab5cc57eb732407d80c9e7ae48891ffcaLaurent Pinchart			    + c_offset;
94453b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia		/* Set x offset */
945edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		if (sh_mobile_format_fourcc(&info->var) == V4L2_PIX_FMT_NV24)
94653b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia			base_addr_c += 2 * var->xoffset;
94753b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia		else
94853b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia			base_addr_c += var->xoffset;
94949d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart	}
95053b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia
95149d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart	if (ch->meram_enabled) {
9527caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia		struct sh_mobile_meram_cfg *cfg;
9537caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia		struct sh_mobile_meram_info *mdev;
9547caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia		int ret;
9557caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
9567caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia		cfg = ch->cfg.meram_cfg;
9577caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia		mdev = priv->meram_dev;
9587caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia		ret = mdev->ops->meram_update(mdev, cfg,
9597caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia					base_addr_y, base_addr_c,
96049d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart					&base_addr_y, &base_addr_c);
9617caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia		if (ret)
9627caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia			return ret;
96349d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart	}
9647caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
96549d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart	ch->base_addr_y = base_addr_y;
96649d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart	ch->base_addr_c = base_addr_c;
9677caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
96849d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart	lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);
969edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	if (yuv)
97049d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart		lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c);
97153b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia
97292e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	if (lcdc_chan_is_sublcd(ch))
97392e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy		lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS);
97492e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	else
97592e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy		lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_MRS);
97692e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy
97792e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	ch->pan_offset = new_pan_offset;
97892e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy
97992e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy	sh_mobile_lcdc_deferred_io_touch(info);
9809dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
9819dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	return 0;
9829dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy}
9839dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy
98440331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthystatic int sh_mobile_wait_for_vsync(struct fb_info *info)
98540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy{
98640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	struct sh_mobile_lcdc_chan *ch = info->par;
98740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	unsigned long ldintr;
98840331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	int ret;
98940331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy
990dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart	/* Enable VSync End interrupt and be careful not to acknowledge any
991dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart	 * pending interrupt.
992dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart	 */
99340331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	ldintr = lcdc_read(ch->lcdc, _LDINTR);
994dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart	ldintr |= LDINTR_VEE | LDINTR_STATUS_MASK;
99540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	lcdc_write(ch->lcdc, _LDINTR, ldintr);
99640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy
99740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion,
99840331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy							msecs_to_jiffies(100));
99940331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	if (!ret)
100040331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy		return -ETIMEDOUT;
100140331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy
100240331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	return 0;
100340331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy}
100440331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy
100540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthystatic int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd,
100640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy		       unsigned long arg)
100740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy{
100840331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	int retval;
100940331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy
101040331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	switch (cmd) {
101140331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	case FBIO_WAITFORVSYNC:
101240331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy		retval = sh_mobile_wait_for_vsync(info);
101340331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy		break;
101440331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy
101540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	default:
101640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy		retval = -ENOIOCTLCMD;
101740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy		break;
101840331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	}
101940331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	return retval;
102040331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy}
102140331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy
1022dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetskistatic void sh_mobile_fb_reconfig(struct fb_info *info)
1023dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{
1024dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	struct sh_mobile_lcdc_chan *ch = info->par;
1025dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	struct fb_videomode mode1, mode2;
1026dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	struct fb_event event;
1027dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	int evnt = FB_EVENT_MODE_CHANGE_ALL;
1028dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1029dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	if (ch->use_count > 1 || (ch->use_count == 1 && !info->fbcon_par))
1030dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		/* More framebuffer users are active */
1031dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		return;
1032dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1033dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	fb_var_to_videomode(&mode1, &ch->display_var);
1034dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	fb_var_to_videomode(&mode2, &info->var);
1035dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1036dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	if (fb_mode_is_equal(&mode1, &mode2))
1037dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		return;
1038dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1039dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	/* Display has been re-plugged, framebuffer is free now, reconfigure */
1040dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	if (fb_set_var(info, &ch->display_var) < 0)
1041dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		/* Couldn't reconfigure, hopefully, can continue as before */
1042dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		return;
1043dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1044dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	/*
1045dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	 * fb_set_var() calls the notifier change internally, only if
1046dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	 * FBINFO_MISC_USEREVENT flag is set. Since we do not want to fake a
1047dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	 * user event, we have to call the chain ourselves.
1048dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	 */
1049dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	event.info = info;
1050cc267ec5dfa29eba34cbf4eae3e5db9ca499c179Arnd Hannemann	event.data = &mode1;
1051dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	fb_notifier_call_chain(evnt, &event);
1052dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski}
1053dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1054dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski/*
1055dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski * Locking: both .fb_release() and .fb_open() are called with info->lock held if
1056dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski * user == 1, or with console sem held, if user == 0.
1057dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski */
1058dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetskistatic int sh_mobile_release(struct fb_info *info, int user)
1059dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{
1060dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	struct sh_mobile_lcdc_chan *ch = info->par;
1061dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1062dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	mutex_lock(&ch->open_lock);
1063dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count);
1064dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1065dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	ch->use_count--;
1066dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1067dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	/* Nothing to reconfigure, when called from fbcon */
1068dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	if (user) {
1069ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn		console_lock();
1070dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		sh_mobile_fb_reconfig(info);
1071ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn		console_unlock();
1072dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	}
1073dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1074dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	mutex_unlock(&ch->open_lock);
1075dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1076dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	return 0;
1077dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski}
1078dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1079dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetskistatic int sh_mobile_open(struct fb_info *info, int user)
1080dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{
1081dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	struct sh_mobile_lcdc_chan *ch = info->par;
1082dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1083dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	mutex_lock(&ch->open_lock);
1084dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	ch->use_count++;
1085dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1086dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count);
1087dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	mutex_unlock(&ch->open_lock);
1088dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1089dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	return 0;
1090dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski}
1091dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
1092dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetskistatic int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1093dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{
1094dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	struct sh_mobile_lcdc_chan *ch = info->par;
1095417d48274e755e537bae60461558c1f63a4e14deMagnus Damm	struct sh_mobile_lcdc_priv *p = ch->lcdc;
10960386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	unsigned int best_dist = (unsigned int)-1;
10970386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	unsigned int best_xres = 0;
10980386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	unsigned int best_yres = 0;
10990386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	unsigned int i;
1100dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski
11010386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	if (var->xres > MAX_XRES || var->yres > MAX_YRES)
1102dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		return -EINVAL;
11030386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
11040386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	/* If board code provides us with a list of available modes, make sure
11050386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	 * we use one of them. Find the mode closest to the requested one. The
11060386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	 * distance between two modes is defined as the size of the
11070386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	 * non-overlapping parts of the two rectangles.
11080386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	 */
11090386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	for (i = 0; i < ch->cfg.num_cfg; ++i) {
11100386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		const struct fb_videomode *mode = &ch->cfg.lcd_cfg[i];
11110386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		unsigned int dist;
11120386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
11130386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		/* We can only round up. */
11140386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		if (var->xres > mode->xres || var->yres > mode->yres)
11150386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			continue;
11160386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
11170386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		dist = var->xres * var->yres + mode->xres * mode->yres
11180386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		     - 2 * min(var->xres, mode->xres)
11190386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			 * min(var->yres, mode->yres);
11200386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
11210386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		if (dist < best_dist) {
11220386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			best_xres = mode->xres;
11230386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			best_yres = mode->yres;
11240386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			best_dist = dist;
11250386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		}
1126dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	}
1127417d48274e755e537bae60461558c1f63a4e14deMagnus Damm
11280386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	/* If no available mode can be used, return an error. */
11290386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	if (ch->cfg.num_cfg != 0) {
11300386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		if (best_dist == (unsigned int)-1)
11310386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart			return -EINVAL;
11320386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
11330386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		var->xres = best_xres;
11340386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		var->yres = best_yres;
11350386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	}
11360386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
11370386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	/* Make sure the virtual resolution is at least as big as the visible
11380386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	 * resolution.
11390386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	 */
11400386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	if (var->xres_virtual < var->xres)
11410386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		var->xres_virtual = var->xres;
11420386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	if (var->yres_virtual < var->yres)
11430386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		var->yres_virtual = var->yres;
11440386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
1145edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	if (sh_mobile_format_is_fourcc(var)) {
1146edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		switch (var->grayscale) {
1147edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV12:
1148edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV21:
1149edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->bits_per_pixel = 12;
1150edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			break;
1151edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_RGB565:
1152edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV16:
1153edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV61:
1154edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->bits_per_pixel = 16;
1155edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			break;
1156edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_BGR24:
1157edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV24:
1158edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_NV42:
1159edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->bits_per_pixel = 24;
1160edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			break;
1161edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		case V4L2_PIX_FMT_BGR32:
1162edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->bits_per_pixel = 32;
1163edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			break;
1164edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		default:
1165edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			return -EINVAL;
1166edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		}
1167edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart
1168edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		/* Default to RGB and JPEG color-spaces for RGB and YUV formats
1169edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		 * respectively.
1170edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		 */
1171edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		if (!sh_mobile_format_is_yuv(var))
1172edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->colorspace = V4L2_COLORSPACE_SRGB;
1173edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		else if (var->colorspace != V4L2_COLORSPACE_REC709)
1174edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->colorspace = V4L2_COLORSPACE_JPEG;
1175edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	} else {
1176edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		if (var->bits_per_pixel <= 16) {		/* RGB 565 */
1177edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->bits_per_pixel = 16;
1178edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->red.offset = 11;
1179edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->red.length = 5;
1180edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->green.offset = 5;
1181edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->green.length = 6;
1182edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->blue.offset = 0;
1183edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->blue.length = 5;
1184edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->transp.offset = 0;
1185edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->transp.length = 0;
1186edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		} else if (var->bits_per_pixel <= 24) {		/* RGB 888 */
1187edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->bits_per_pixel = 24;
1188edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->red.offset = 16;
1189edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->red.length = 8;
1190edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->green.offset = 8;
1191edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->green.length = 8;
1192edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->blue.offset = 0;
1193edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->blue.length = 8;
1194edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->transp.offset = 0;
1195edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->transp.length = 0;
1196edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		} else if (var->bits_per_pixel <= 32) {		/* RGBA 888 */
1197edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->bits_per_pixel = 32;
1198edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->red.offset = 16;
1199edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->red.length = 8;
1200edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->green.offset = 8;
1201edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->green.length = 8;
1202edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->blue.offset = 0;
1203edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->blue.length = 8;
1204edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->transp.offset = 24;
1205edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			var->transp.length = 8;
1206edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		} else
1207edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			return -EINVAL;
1208417d48274e755e537bae60461558c1f63a4e14deMagnus Damm
1209edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		var->red.msb_right = 0;
1210edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		var->green.msb_right = 0;
1211edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		var->blue.msb_right = 0;
1212edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		var->transp.msb_right = 0;
1213edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	}
12140386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
12150386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	/* Make sure we don't exceed our allocated memory. */
12160386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 >
12170386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart	    info->fix.smem_len)
12180386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart		return -EINVAL;
12190386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart
1220edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	/* only accept the forced_fourcc for dual channel configurations */
1221edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	if (p->forced_fourcc &&
1222edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	    p->forced_fourcc != sh_mobile_format_fourcc(var))
1223417d48274e755e537bae60461558c1f63a4e14deMagnus Damm		return -EINVAL;
1224417d48274e755e537bae60461558c1f63a4e14deMagnus Damm
1225dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	return 0;
1226dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski}
122740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy
1228ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchartstatic int sh_mobile_set_par(struct fb_info *info)
1229ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart{
1230ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart	struct sh_mobile_lcdc_chan *ch = info->par;
123191fba48d59666718e3d3e86964755b80d39cdbddLaurent Pinchart	u32 line_length = info->fix.line_length;
1232ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart	int ret;
1233ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart
1234ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart	sh_mobile_lcdc_stop(ch->lcdc);
123591fba48d59666718e3d3e86964755b80d39cdbddLaurent Pinchart
1236edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	if (sh_mobile_format_is_yuv(&info->var))
123791fba48d59666718e3d3e86964755b80d39cdbddLaurent Pinchart		info->fix.line_length = info->var.xres;
123891fba48d59666718e3d3e86964755b80d39cdbddLaurent Pinchart	else
123991fba48d59666718e3d3e86964755b80d39cdbddLaurent Pinchart		info->fix.line_length = info->var.xres
124091fba48d59666718e3d3e86964755b80d39cdbddLaurent Pinchart				      * info->var.bits_per_pixel / 8;
124191fba48d59666718e3d3e86964755b80d39cdbddLaurent Pinchart
1242ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart	ret = sh_mobile_lcdc_start(ch->lcdc);
124391fba48d59666718e3d3e86964755b80d39cdbddLaurent Pinchart	if (ret < 0) {
1244ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart		dev_err(info->dev, "%s: unable to restart LCDC\n", __func__);
124591fba48d59666718e3d3e86964755b80d39cdbddLaurent Pinchart		info->fix.line_length = line_length;
124691fba48d59666718e3d3e86964755b80d39cdbddLaurent Pinchart	}
1247ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart
1248edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	if (sh_mobile_format_is_fourcc(&info->var)) {
1249edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		info->fix.type = FB_TYPE_FOURCC;
1250edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		info->fix.visual = FB_VISUAL_FOURCC;
1251edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	} else {
1252edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		info->fix.type = FB_TYPE_PACKED_PIXELS;
1253edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		info->fix.visual = FB_VISUAL_TRUECOLOR;
1254edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	}
1255edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart
1256ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart	return ret;
1257ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart}
1258ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart
12598857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot/*
12608857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * Screen blanking. Behavior is as follows:
12618857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_UNBLANK: screen unblanked, clocks enabled
12628857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_NORMAL: screen blanked, clocks enabled
12638857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_VSYNC,
12648857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_HSYNC,
12658857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_POWEROFF: screen blanked, clocks disabled
12668857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot */
12678857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbotstatic int sh_mobile_lcdc_blank(int blank, struct fb_info *info)
12688857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot{
12698857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	struct sh_mobile_lcdc_chan *ch = info->par;
12708857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	struct sh_mobile_lcdc_priv *p = ch->lcdc;
12718857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot
12728857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	/* blank the screen? */
12738857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	if (blank > FB_BLANK_UNBLANK && ch->blank_status == FB_BLANK_UNBLANK) {
12748857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		struct fb_fillrect rect = {
12758857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot			.width = info->var.xres,
12768857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot			.height = info->var.yres,
12778857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		};
12788857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		sh_mobile_lcdc_fillrect(info, &rect);
12798857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	}
12808857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	/* turn clocks on? */
12818857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	if (blank <= FB_BLANK_NORMAL && ch->blank_status > FB_BLANK_NORMAL) {
12828857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		sh_mobile_lcdc_clk_on(p);
12838857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	}
12848857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	/* turn clocks off? */
12858857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	if (blank > FB_BLANK_NORMAL && ch->blank_status <= FB_BLANK_NORMAL) {
12868857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		/* make sure the screen is updated with the black fill before
12878857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		 * switching the clocks off. one vsync is not enough since
12888857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		 * blanking may occur in the middle of a refresh. deferred io
12898857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		 * mode will reenable the clocks and update the screen in time,
12908857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		 * so it does not need this. */
12918857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		if (!info->fbdefio) {
12928857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot			sh_mobile_wait_for_vsync(info);
12938857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot			sh_mobile_wait_for_vsync(info);
12948857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		}
12958857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot		sh_mobile_lcdc_clk_off(p);
12968857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	}
12978857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot
12988857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	ch->blank_status = blank;
12998857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	return 0;
13008857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot}
13018857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot
1302cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic struct fb_ops sh_mobile_lcdc_ops = {
13039dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	.owner          = THIS_MODULE,
1304cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.fb_setcolreg	= sh_mobile_lcdc_setcolreg,
13052540c111ead82cad605ec2b14a1905ad914cc124Magnus Damm	.fb_read        = fb_sys_read,
13062540c111ead82cad605ec2b14a1905ad914cc124Magnus Damm	.fb_write       = fb_sys_write,
13078564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	.fb_fillrect	= sh_mobile_lcdc_fillrect,
13088564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	.fb_copyarea	= sh_mobile_lcdc_copyarea,
13098564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	.fb_imageblit	= sh_mobile_lcdc_imageblit,
13108857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot	.fb_blank	= sh_mobile_lcdc_blank,
13119dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy	.fb_pan_display = sh_mobile_fb_pan_display,
131240331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy	.fb_ioctl       = sh_mobile_ioctl,
1313dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	.fb_open	= sh_mobile_open,
1314dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	.fb_release	= sh_mobile_release,
1315dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski	.fb_check_var	= sh_mobile_check_var,
1316ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart	.fb_set_par	= sh_mobile_set_par,
1317cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm};
1318cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1319f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
1320f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Backlight
1321f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
1322f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
13233b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic int sh_mobile_lcdc_update_bl(struct backlight_device *bdev)
13243b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{
13253b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev);
13263b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	struct sh_mobile_lcdc_board_cfg *cfg = &ch->cfg.board_cfg;
13273b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	int brightness = bdev->props.brightness;
13283b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
13293b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	if (bdev->props.power != FB_BLANK_UNBLANK ||
13303b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	    bdev->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
13313b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		brightness = 0;
13323b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
13333b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	return cfg->set_brightness(cfg->board_data, brightness);
13343b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot}
13353b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
13363b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic int sh_mobile_lcdc_get_brightness(struct backlight_device *bdev)
13373b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{
13383b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev);
13393b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	struct sh_mobile_lcdc_board_cfg *cfg = &ch->cfg.board_cfg;
13403b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
13413b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	return cfg->get_brightness(cfg->board_data);
13423b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot}
13433b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
13443b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic int sh_mobile_lcdc_check_fb(struct backlight_device *bdev,
13453b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot				   struct fb_info *info)
13463b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{
13473b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	return (info->bl_dev == bdev);
13483b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot}
13493b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
13503b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic struct backlight_ops sh_mobile_lcdc_bl_ops = {
13513b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	.options	= BL_CORE_SUSPENDRESUME,
13523b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	.update_status	= sh_mobile_lcdc_update_bl,
13533b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	.get_brightness	= sh_mobile_lcdc_get_brightness,
13543b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	.check_fb	= sh_mobile_lcdc_check_fb,
13553b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot};
13563b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
13573b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic struct backlight_device *sh_mobile_lcdc_bl_probe(struct device *parent,
13583b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot					       struct sh_mobile_lcdc_chan *ch)
13593b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{
13603b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	struct backlight_device *bl;
13613b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
13623b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	bl = backlight_device_register(ch->cfg.bl_info.name, parent, ch,
13633b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot				       &sh_mobile_lcdc_bl_ops, NULL);
1364beee1f20a185c7e79fd33bb83e04fe44ecd75af3Dan Carpenter	if (IS_ERR(bl)) {
1365beee1f20a185c7e79fd33bb83e04fe44ecd75af3Dan Carpenter		dev_err(parent, "unable to register backlight device: %ld\n",
1366beee1f20a185c7e79fd33bb83e04fe44ecd75af3Dan Carpenter			PTR_ERR(bl));
13673b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		return NULL;
13683b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	}
13693b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
13703b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	bl->props.max_brightness = ch->cfg.bl_info.max_brightness;
13713b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	bl->props.brightness = bl->props.max_brightness;
13723b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	backlight_update_status(bl);
13733b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
13743b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	return bl;
13753b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot}
13763b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
13773b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic void sh_mobile_lcdc_bl_remove(struct backlight_device *bdev)
13783b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{
13793b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot	backlight_device_unregister(bdev);
13803b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot}
13813b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
1382f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
1383f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Power management
1384f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
1385f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
13862feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Dammstatic int sh_mobile_lcdc_suspend(struct device *dev)
13872feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm{
13882feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	struct platform_device *pdev = to_platform_device(dev);
13892feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
13902feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	sh_mobile_lcdc_stop(platform_get_drvdata(pdev));
13912feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	return 0;
13922feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm}
13932feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
13942feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Dammstatic int sh_mobile_lcdc_resume(struct device *dev)
13952feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm{
13962feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	struct platform_device *pdev = to_platform_device(dev);
13972feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
13982feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	return sh_mobile_lcdc_start(platform_get_drvdata(pdev));
13992feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm}
14002feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
14010246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic int sh_mobile_lcdc_runtime_suspend(struct device *dev)
14020246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm{
14030246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	struct platform_device *pdev = to_platform_device(dev);
14042427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart	struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
14050246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm
14060246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	/* turn off LCDC hardware */
14072427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart	lcdc_write(priv, _LDCNT1R, 0);
14082427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart
14090246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	return 0;
14100246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm}
14110246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm
14120246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic int sh_mobile_lcdc_runtime_resume(struct device *dev)
14130246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm{
14140246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	struct platform_device *pdev = to_platform_device(dev);
14152427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart	struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
14160246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm
14172427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart	__sh_mobile_lcdc_start(priv);
14180246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm
14190246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	return 0;
14200246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm}
14210246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm
1422471452104b8520337ae2fb48c4e61cd4896e025dAlexey Dobriyanstatic const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = {
14232feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	.suspend = sh_mobile_lcdc_suspend,
14242feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm	.resume = sh_mobile_lcdc_resume,
14250246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	.runtime_suspend = sh_mobile_lcdc_runtime_suspend,
14260246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm	.runtime_resume = sh_mobile_lcdc_runtime_resume,
14272feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm};
14282feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm
1429f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
1430f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Framebuffer notifier
1431f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
1432f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
14336de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski/* locking: called with info->lock held */
14346011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetskistatic int sh_mobile_lcdc_notify(struct notifier_block *nb,
14356011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski				 unsigned long action, void *data)
14366011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski{
14376011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	struct fb_event *event = data;
14386011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	struct fb_info *info = event->info;
14396011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	struct sh_mobile_lcdc_chan *ch = info->par;
14406011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
14416011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	if (&ch->lcdc->notifier != nb)
1442baf163749952ca5e33dd2d6a74da023e385c3a00Guennadi Liakhovetski		return NOTIFY_DONE;
14436011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
14446011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	dev_dbg(info->dev, "%s(): action = %lu, data = %p\n",
14456011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski		__func__, action, event->data);
14466011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
14476011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	switch(action) {
14486011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	case FB_EVENT_SUSPEND:
144937c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		sh_mobile_lcdc_display_off(ch);
1450afe417c0355154c8b2547619771d6053b3c0aad7Guennadi Liakhovetski		sh_mobile_lcdc_stop(ch->lcdc);
14516011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski		break;
14526011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	case FB_EVENT_RESUME:
1453dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		mutex_lock(&ch->open_lock);
1454dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		sh_mobile_fb_reconfig(info);
1455dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski		mutex_unlock(&ch->open_lock);
14566011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
145737c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart		sh_mobile_lcdc_display_on(ch);
1458ebe5e12d00f4785092a9650845ad3451bbf4b311Guennadi Liakhovetski		sh_mobile_lcdc_start(ch->lcdc);
14596011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	}
14606011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
1461baf163749952ca5e33dd2d6a74da023e385c3a00Guennadi Liakhovetski	return NOTIFY_OK;
14626011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski}
14636011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
1464f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* -----------------------------------------------------------------------------
1465f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Probe/remove and driver init/exit
1466f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */
1467f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
1468217e9c4353aa86f0c7eeb4c275bca73ea8b53be1Laurent Pinchartstatic const struct fb_videomode default_720p __devinitconst = {
1469f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.name = "HDMI 720p",
1470f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.xres = 1280,
1471f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.yres = 720,
1472f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
1473f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.left_margin = 220,
1474f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.right_margin = 110,
1475f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.hsync_len = 40,
1476f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
1477f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.upper_margin = 20,
1478f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.lower_margin = 5,
1479f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.vsync_len = 5,
1480f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
1481f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.pixclock = 13468,
1482f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.refresh = 60,
1483f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	.sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
1484f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart};
1485f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
1486b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchartstatic int sh_mobile_lcdc_remove(struct platform_device *pdev)
1487b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart{
1488b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
1489b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	struct fb_info *info;
1490b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	int i;
1491b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
1492b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	fb_unregister_client(&priv->notifier);
1493b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
1494b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
1495b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart		if (priv->ch[i].info && priv->ch[i].info->dev)
1496b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart			unregister_framebuffer(priv->ch[i].info);
1497b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
1498b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	sh_mobile_lcdc_stop(priv);
1499b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
1500b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
15019a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart		struct sh_mobile_lcdc_chan *ch = &priv->ch[i];
1502b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
15039a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart		info = ch->info;
1504b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart		if (!info || !info->device)
1505b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart			continue;
1506b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
15079a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart		if (ch->tx_dev)
15089a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart			module_put(ch->cfg.tx_dev->dev.driver->owner);
15099a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart
15109a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart		if (ch->sglist)
15119a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart			vfree(ch->sglist);
1512b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
1513b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart		if (info->screen_base)
1514b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart			dma_free_coherent(&pdev->dev, info->fix.smem_len,
15159a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart					  info->screen_base, ch->dma_handle);
1516b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart		fb_dealloc_cmap(&info->cmap);
1517b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart		framebuffer_release(info);
1518b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	}
1519b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
1520b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
1521b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart		if (priv->ch[i].bl)
1522b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart			sh_mobile_lcdc_bl_remove(priv->ch[i].bl);
1523b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	}
1524b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
15254774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	if (priv->dot_clk) {
15264774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart		pm_runtime_disable(&pdev->dev);
1527b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart		clk_put(priv->dot_clk);
15284774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	}
1529b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
1530b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	if (priv->base)
1531b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart		iounmap(priv->base);
1532b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart
1533b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	if (priv->irq)
1534b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart		free_irq(priv->irq, priv);
1535b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	kfree(priv);
1536b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart	return 0;
1537b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart}
1538cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1539217e9c4353aa86f0c7eeb4c275bca73ea8b53be1Laurent Pinchartstatic int __devinit sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
1540f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart{
1541f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	int interface_type = ch->cfg.interface_type;
1542f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
1543f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	switch (interface_type) {
1544f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB8:
1545f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB9:
1546f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB12A:
1547f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB12B:
1548f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB16:
1549f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB18:
1550f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case RGB24:
1551f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS8A:
1552f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS8B:
1553f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS8C:
1554f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS8D:
1555f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS9:
1556f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS12:
1557f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS16A:
1558f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS16B:
1559f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS16C:
1560f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS18:
1561f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	case SYS24:
1562f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		break;
1563f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	default:
1564f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		return -EINVAL;
1565f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
1566f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
1567f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	/* SUBLCD only supports SYS interface */
1568f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	if (lcdc_chan_is_sublcd(ch)) {
1569f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		if (!(interface_type & LDMT1R_IFM))
1570f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart			return -EINVAL;
1571f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
1572f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart		interface_type &= ~LDMT1R_IFM;
1573f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	}
1574f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
1575f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	ch->ldmt1r_value = interface_type;
1576f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart	return 0;
1577f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart}
1578f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart
15790a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchartstatic int __devinit
15800a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchartsh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
15810a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart			    struct sh_mobile_lcdc_chan *ch)
1582cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{
15833ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	struct sh_mobile_lcdc_chan_cfg *cfg = &ch->cfg;
15843ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	const struct fb_videomode *max_mode;
15853ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	const struct fb_videomode *mode;
15863ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	struct fb_var_screeninfo *var;
1587cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	struct fb_info *info;
15883ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	unsigned int max_size;
15893ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	int num_cfg;
15903ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	void *buf;
15913ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	int ret;
15923ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	int i;
15933ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
1594a67472ad1ae040f073e45048cbc5a01195f2e3f5Laurent Pinchart	mutex_init(&ch->open_lock);
1595a67472ad1ae040f073e45048cbc5a01195f2e3f5Laurent Pinchart
1596a67472ad1ae040f073e45048cbc5a01195f2e3f5Laurent Pinchart	/* Allocate the frame buffer device. */
15970a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart	ch->info = framebuffer_alloc(0, priv->dev);
15983ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	if (!ch->info) {
15990a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart		dev_err(priv->dev, "unable to allocate fb_info\n");
16003ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		return -ENOMEM;
16013ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	}
16023ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
16033ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	info = ch->info;
16043ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	info->fbops = &sh_mobile_lcdc_ops;
16053ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	info->par = ch;
1606a67472ad1ae040f073e45048cbc5a01195f2e3f5Laurent Pinchart	info->pseudo_palette = &ch->pseudo_palette;
1607a67472ad1ae040f073e45048cbc5a01195f2e3f5Laurent Pinchart	info->flags = FBINFO_FLAG_DEFAULT;
16083ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
16099a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart	if (cfg->tx_dev) {
16109a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart		if (!cfg->tx_dev->dev.driver ||
16119a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart		    !try_module_get(cfg->tx_dev->dev.driver->owner)) {
16129a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart			dev_warn(priv->dev,
16139a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart				 "unable to get transmitter device\n");
16149a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart			return -EINVAL;
16159a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart		}
16169a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart		ch->tx_dev = platform_get_drvdata(cfg->tx_dev);
16179a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart	}
16189a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart
16193ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	/* Iterate through the modes to validate them and find the highest
16203ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	 * resolution.
16213ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	 */
16223ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	max_mode = NULL;
16233ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	max_size = 0;
16243ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
16253ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	for (i = 0, mode = cfg->lcd_cfg; i < cfg->num_cfg; i++, mode++) {
16263ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		unsigned int size = mode->yres * mode->xres;
16273ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
1628edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		/* NV12/NV21 buffers must have even number of lines */
1629edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		if ((cfg->fourcc == V4L2_PIX_FMT_NV12 ||
1630edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		     cfg->fourcc == V4L2_PIX_FMT_NV21) && (mode->yres & 0x1)) {
16310a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart			dev_err(priv->dev, "yres must be multiple of 2 for "
16320a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart				"YCbCr420 mode.\n");
16333ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			return -EINVAL;
16343ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		}
16353ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
16363ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		if (size > max_size) {
16373ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			max_mode = mode;
16383ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			max_size = size;
16393ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		}
16403ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	}
16413ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
16423ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	if (!max_size)
16433ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		max_size = MAX_XRES * MAX_YRES;
16443ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	else
16450a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart		dev_dbg(priv->dev, "Found largest videomode %ux%u\n",
16463ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			max_mode->xres, max_mode->yres);
16473ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
1648a67472ad1ae040f073e45048cbc5a01195f2e3f5Laurent Pinchart	/* Create the mode list. */
16493ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	if (cfg->lcd_cfg == NULL) {
16503ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		mode = &default_720p;
16513ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		num_cfg = 1;
16523ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	} else {
16533ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		mode = cfg->lcd_cfg;
16543ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		num_cfg = cfg->num_cfg;
16553ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	}
16563ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
16573ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	fb_videomode_to_modelist(mode, num_cfg, &info->modelist);
16583ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
1659a67472ad1ae040f073e45048cbc5a01195f2e3f5Laurent Pinchart	/* Initialize variable screen information using the first mode as
1660a67472ad1ae040f073e45048cbc5a01195f2e3f5Laurent Pinchart	 * default. The default Y virtual resolution is twice the panel size to
1661a67472ad1ae040f073e45048cbc5a01195f2e3f5Laurent Pinchart	 * allow for double-buffering.
1662a67472ad1ae040f073e45048cbc5a01195f2e3f5Laurent Pinchart	 */
1663a67472ad1ae040f073e45048cbc5a01195f2e3f5Laurent Pinchart	var = &info->var;
16643ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	fb_videomode_to_var(var, mode);
16653ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	var->width = cfg->lcd_size_cfg.width;
16663ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	var->height = cfg->lcd_size_cfg.height;
16673ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	var->yres_virtual = var->yres * 2;
16683ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	var->activate = FB_ACTIVATE_NOW;
16693ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
1670edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	switch (cfg->fourcc) {
1671edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_RGB565:
1672edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		var->bits_per_pixel = 16;
1673edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		break;
1674edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_BGR24:
1675edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		var->bits_per_pixel = 24;
1676edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		break;
1677edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	case V4L2_PIX_FMT_BGR32:
1678edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		var->bits_per_pixel = 32;
1679edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		break;
1680edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	default:
1681edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		var->grayscale = cfg->fourcc;
1682edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		break;
1683edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	}
1684edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart
1685edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	/* Make sure the memory size check won't fail. smem_len is initialized
1686edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	 * later based on var.
1687edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	 */
1688edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	info->fix.smem_len = UINT_MAX;
1689a67472ad1ae040f073e45048cbc5a01195f2e3f5Laurent Pinchart	ret = sh_mobile_check_var(var, info);
16903ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	if (ret)
16913ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		return ret;
16923ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
1693edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	max_size = max_size * var->bits_per_pixel / 8 * 2;
1694edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart
1695a67472ad1ae040f073e45048cbc5a01195f2e3f5Laurent Pinchart	/* Allocate frame buffer memory and color map. */
16960a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart	buf = dma_alloc_coherent(priv->dev, max_size, &ch->dma_handle,
16970a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart				 GFP_KERNEL);
16983ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	if (!buf) {
16990a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart		dev_err(priv->dev, "unable to allocate buffer\n");
17003ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		return -ENOMEM;
17013ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	}
17023ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
17033ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);
17043ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	if (ret < 0) {
17050a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart		dev_err(priv->dev, "unable to allocate cmap\n");
17060a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart		dma_free_coherent(priv->dev, max_size, buf, ch->dma_handle);
17073ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		return ret;
17083ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	}
17093ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
1710edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	/* Initialize fixed screen information. Restrict pan to 2 lines steps
1711edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	 * for NV12 and NV21.
1712edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	 */
1713edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	info->fix = sh_mobile_lcdc_fix;
17143ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	info->fix.smem_start = ch->dma_handle;
1715edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	info->fix.smem_len = max_size;
1716edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	if (cfg->fourcc == V4L2_PIX_FMT_NV12 ||
1717edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	    cfg->fourcc == V4L2_PIX_FMT_NV21)
1718edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		info->fix.ypanstep = 2;
1719edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart
1720edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	if (sh_mobile_format_is_yuv(var)) {
17213ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		info->fix.line_length = var->xres;
1722edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		info->fix.visual = FB_VISUAL_FOURCC;
1723edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	} else {
1724edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		info->fix.line_length = var->xres * var->bits_per_pixel / 8;
1725edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		info->fix.visual = FB_VISUAL_TRUECOLOR;
1726edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	}
17273ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
17283ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	info->screen_base = buf;
17290a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart	info->device = priv->dev;
17303ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	ch->display_var = *var;
17313ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
17323ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	return 0;
17333ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart}
17343ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart
17353ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchartstatic int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
17363ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart{
173701ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski	struct sh_mobile_lcdc_info *pdata = pdev->dev.platform_data;
17383ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	struct sh_mobile_lcdc_priv *priv;
1739cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	struct resource *res;
17403ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	int num_channels;
1741cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	int error;
17423ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	int i;
1743cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
174401ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski	if (!pdata) {
1745cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		dev_err(&pdev->dev, "no platform data defined\n");
17468bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski		return -EINVAL;
1747cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
1748cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1749cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
17508564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	i = platform_get_irq(pdev, 0);
17518564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	if (!res || i < 0) {
17528564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		dev_err(&pdev->dev, "cannot get platform resources\n");
17538bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski		return -ENOENT;
1754cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
1755cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1756cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
1757cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (!priv) {
1758cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		dev_err(&pdev->dev, "cannot allocate device data\n");
17598bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski		return -ENOMEM;
1760cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
1761cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
17624774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	priv->dev = &pdev->dev;
17634774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	priv->meram_dev = pdata->meram_dev;
17648bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski	platform_set_drvdata(pdev, priv);
17658bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski
1766f8798ccbefc0e4ef7438c080b7ba0410738c8cfaYong Zhang	error = request_irq(i, sh_mobile_lcdc_irq, 0,
17677ad33e74857f16f1202cbc5746faf52e88e8b376Kay Sievers			    dev_name(&pdev->dev), priv);
17688564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	if (error) {
17698564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		dev_err(&pdev->dev, "unable to request irq\n");
17708564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		goto err1;
17718564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	}
17728564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
17738564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm	priv->irq = i;
17745ef6b505d9df45558402bdb823a078840a6a26c4Guennadi Liakhovetski	atomic_set(&priv->hw_usecnt, -1);
1775cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
17763ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	for (i = 0, num_channels = 0; i < ARRAY_SIZE(pdata->ch); i++) {
17773ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		struct sh_mobile_lcdc_chan *ch = priv->ch + num_channels;
1778cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
177901ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski		ch->lcdc = priv;
178001ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski		memcpy(&ch->cfg, &pdata->ch[i], sizeof(pdata->ch[i]));
1781cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
178201ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski		error = sh_mobile_lcdc_check_interface(ch);
1783cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (error) {
1784cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			dev_err(&pdev->dev, "unsupported interface type\n");
1785cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			goto err1;
1786cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		}
178701ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski		init_waitqueue_head(&ch->frame_end_wait);
178801ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski		init_completion(&ch->vsync_completion);
178901ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski		ch->pan_offset = 0;
1790cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
17913b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		/* probe the backlight is there is one defined */
17923b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		if (ch->cfg.bl_info.max_brightness)
17933b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot			ch->bl = sh_mobile_lcdc_bl_probe(&pdev->dev, ch);
17943b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
1795cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		switch (pdata->ch[i].chan) {
1796cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		case LCDC_CHAN_MAINLCD:
1797ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart			ch->enabled = LDCNT2R_ME;
179801ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski			ch->reg_offs = lcdc_offs_mainlcd;
17993ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			num_channels++;
1800cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			break;
1801cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		case LCDC_CHAN_SUBLCD:
1802ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart			ch->enabled = LDCNT2R_SE;
180301ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski			ch->reg_offs = lcdc_offs_sublcd;
18043ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			num_channels++;
1805cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			break;
1806cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		}
1807cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
1808cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
18093ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	if (!num_channels) {
1810cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		dev_err(&pdev->dev, "no channels defined\n");
1811cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		error = -EINVAL;
1812cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		goto err1;
1813cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
1814cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1815edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart	/* for dual channel LCDC (MAIN + SUB) force shared format setting */
18163ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	if (num_channels == 2)
1817edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart		priv->forced_fourcc = pdata->ch[0].fourcc;
1818417d48274e755e537bae60461558c1f63a4e14deMagnus Damm
1819dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski	priv->base = ioremap_nocache(res->start, resource_size(res));
1820dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski	if (!priv->base)
1821dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski		goto err1;
1822dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski
18230a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart	error = sh_mobile_lcdc_setup_clocks(priv, pdata->clock_source);
1824cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (error) {
1825cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		dev_err(&pdev->dev, "unable to setup clocks\n");
1826cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		goto err1;
1827cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
1828cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
18294774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	/* Enable runtime PM. */
18304774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart	pm_runtime_enable(&pdev->dev);
18317caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia
18323ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	for (i = 0; i < num_channels; i++) {
183301ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski		struct sh_mobile_lcdc_chan *ch = priv->ch + i;
1834c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski
18350a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart		error = sh_mobile_lcdc_channel_init(priv, ch);
1836cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (error)
18373ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart			goto err1;
1838cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
1839cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1840cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	error = sh_mobile_lcdc_start(priv);
1841cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	if (error) {
1842cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		dev_err(&pdev->dev, "unable to start hardware\n");
1843cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		goto err1;
1844cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
1845cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
18463ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart	for (i = 0; i < num_channels; i++) {
18471c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt		struct sh_mobile_lcdc_chan *ch = priv->ch + i;
18483ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart		struct fb_info *info = ch->info;
18491c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt
18501c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt		if (info->fbdefio) {
18518bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski			ch->sglist = vmalloc(sizeof(struct scatterlist) *
18521c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt					info->fix.smem_len >> PAGE_SHIFT);
18538bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski			if (!ch->sglist) {
18541c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt				dev_err(&pdev->dev, "cannot allocate sglist\n");
18551c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt				goto err1;
18561c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt			}
18571c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt		}
18581c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt
18593b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot		info->bl_dev = ch->bl;
18603b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot
18611c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt		error = register_framebuffer(info);
1862cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		if (error < 0)
1863cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm			goto err1;
1864cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
18650a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart		dev_info(&pdev->dev, "registered %s/%s as %dx%d %dbpp.\n",
1866edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			 pdev->name, (ch->cfg.chan == LCDC_CHAN_MAINLCD) ?
1867edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			 "mainlcd" : "sublcd", info->var.xres, info->var.yres,
1868edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart			 info->var.bits_per_pixel);
18698564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm
18708564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm		/* deferred io mode: disable clock to save power */
18716011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski		if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED)
18728564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm			sh_mobile_lcdc_clk_off(priv);
1873cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	}
1874cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
18756011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	/* Failure ignored */
18766011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	priv->notifier.notifier_call = sh_mobile_lcdc_notify;
18776011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski	fb_register_client(&priv->notifier);
18786011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski
1879cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	return 0;
18808bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetskierr1:
1881cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	sh_mobile_lcdc_remove(pdev);
18828bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski
1883cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	return error;
1884cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}
1885cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1886cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic struct platform_driver sh_mobile_lcdc_driver = {
1887cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.driver		= {
1888cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		.name		= "sh_mobile_lcdc_fb",
1889cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm		.owner		= THIS_MODULE,
18902feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm		.pm		= &sh_mobile_lcdc_dev_pm_ops,
1891cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	},
1892cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.probe		= sh_mobile_lcdc_probe,
1893cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm	.remove		= sh_mobile_lcdc_remove,
1894cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm};
1895cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
18964277f2c4667187cbbdd3da3be31ee681bc6b8300Axel Linmodule_platform_driver(sh_mobile_lcdc_driver);
1897cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm
1898cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_DESCRIPTION("SuperH Mobile LCDC Framebuffer driver");
1899cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
1900cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_LICENSE("GPL v2");
1901