brintos

brintos / linux-shallow public Read only

0
0
Text · 65.7 KiB · 6b37b18 Raw
2659 lines · c
1/*2 * SuperH Mobile LCDC Framebuffer3 *4 * Copyright (c) 2008 Magnus Damm5 *6 * This file is subject to the terms and conditions of the GNU General Public7 * License.  See the file "COPYING" in the main directory of this archive8 * for more details.9 */10 11#include <linux/atomic.h>12#include <linux/backlight.h>13#include <linux/clk.h>14#include <linux/console.h>15#include <linux/ctype.h>16#include <linux/dma-mapping.h>17#include <linux/delay.h>18#include <linux/fbcon.h>19#include <linux/init.h>20#include <linux/interrupt.h>21#include <linux/ioctl.h>22#include <linux/kernel.h>23#include <linux/mm.h>24#include <linux/module.h>25#include <linux/platform_device.h>26#include <linux/pm_runtime.h>27#include <linux/slab.h>28#include <linux/videodev2.h>29#include <linux/vmalloc.h>30 31#include <video/sh_mobile_lcdc.h>32 33#include "sh_mobile_lcdcfb.h"34 35/* ----------------------------------------------------------------------------36 * Overlay register definitions37 */38 39#define LDBCR			0xb0040#define LDBCR_UPC(n)		(1 << ((n) + 16))41#define LDBCR_UPF(n)		(1 << ((n) + 8))42#define LDBCR_UPD(n)		(1 << ((n) + 0))43#define LDBnBSIFR(n)		(0xb20 + (n) * 0x20 + 0x00)44#define LDBBSIFR_EN		(1 << 31)45#define LDBBSIFR_VS		(1 << 29)46#define LDBBSIFR_BRSEL		(1 << 28)47#define LDBBSIFR_MX		(1 << 27)48#define LDBBSIFR_MY		(1 << 26)49#define LDBBSIFR_CV3		(3 << 24)50#define LDBBSIFR_CV2		(2 << 24)51#define LDBBSIFR_CV1		(1 << 24)52#define LDBBSIFR_CV0		(0 << 24)53#define LDBBSIFR_CV_MASK	(3 << 24)54#define LDBBSIFR_LAY_MASK	(0xff << 16)55#define LDBBSIFR_LAY_SHIFT	1656#define LDBBSIFR_ROP3_MASK	(0xff << 16)57#define LDBBSIFR_ROP3_SHIFT	1658#define LDBBSIFR_AL_PL8		(3 << 14)59#define LDBBSIFR_AL_PL1		(2 << 14)60#define LDBBSIFR_AL_PK		(1 << 14)61#define LDBBSIFR_AL_1		(0 << 14)62#define LDBBSIFR_AL_MASK	(3 << 14)63#define LDBBSIFR_SWPL		(1 << 10)64#define LDBBSIFR_SWPW		(1 << 9)65#define LDBBSIFR_SWPB		(1 << 8)66#define LDBBSIFR_RY		(1 << 7)67#define LDBBSIFR_CHRR_420	(2 << 0)68#define LDBBSIFR_CHRR_422	(1 << 0)69#define LDBBSIFR_CHRR_444	(0 << 0)70#define LDBBSIFR_RPKF_ARGB32	(0x00 << 0)71#define LDBBSIFR_RPKF_RGB16	(0x03 << 0)72#define LDBBSIFR_RPKF_RGB24	(0x0b << 0)73#define LDBBSIFR_RPKF_MASK	(0x1f << 0)74#define LDBnBSSZR(n)		(0xb20 + (n) * 0x20 + 0x04)75#define LDBBSSZR_BVSS_MASK	(0xfff << 16)76#define LDBBSSZR_BVSS_SHIFT	1677#define LDBBSSZR_BHSS_MASK	(0xfff << 0)78#define LDBBSSZR_BHSS_SHIFT	079#define LDBnBLOCR(n)		(0xb20 + (n) * 0x20 + 0x08)80#define LDBBLOCR_CVLC_MASK	(0xfff << 16)81#define LDBBLOCR_CVLC_SHIFT	1682#define LDBBLOCR_CHLC_MASK	(0xfff << 0)83#define LDBBLOCR_CHLC_SHIFT	084#define LDBnBSMWR(n)		(0xb20 + (n) * 0x20 + 0x0c)85#define LDBBSMWR_BSMWA_MASK	(0xffff << 16)86#define LDBBSMWR_BSMWA_SHIFT	1687#define LDBBSMWR_BSMW_MASK	(0xffff << 0)88#define LDBBSMWR_BSMW_SHIFT	089#define LDBnBSAYR(n)		(0xb20 + (n) * 0x20 + 0x10)90#define LDBBSAYR_FG1A_MASK	(0xff << 24)91#define LDBBSAYR_FG1A_SHIFT	2492#define LDBBSAYR_FG1R_MASK	(0xff << 16)93#define LDBBSAYR_FG1R_SHIFT	1694#define LDBBSAYR_FG1G_MASK	(0xff << 8)95#define LDBBSAYR_FG1G_SHIFT	896#define LDBBSAYR_FG1B_MASK	(0xff << 0)97#define LDBBSAYR_FG1B_SHIFT	098#define LDBnBSACR(n)		(0xb20 + (n) * 0x20 + 0x14)99#define LDBBSACR_FG2A_MASK	(0xff << 24)100#define LDBBSACR_FG2A_SHIFT	24101#define LDBBSACR_FG2R_MASK	(0xff << 16)102#define LDBBSACR_FG2R_SHIFT	16103#define LDBBSACR_FG2G_MASK	(0xff << 8)104#define LDBBSACR_FG2G_SHIFT	8105#define LDBBSACR_FG2B_MASK	(0xff << 0)106#define LDBBSACR_FG2B_SHIFT	0107#define LDBnBSAAR(n)		(0xb20 + (n) * 0x20 + 0x18)108#define LDBBSAAR_AP_MASK	(0xff << 24)109#define LDBBSAAR_AP_SHIFT	24110#define LDBBSAAR_R_MASK		(0xff << 16)111#define LDBBSAAR_R_SHIFT	16112#define LDBBSAAR_GY_MASK	(0xff << 8)113#define LDBBSAAR_GY_SHIFT	8114#define LDBBSAAR_B_MASK		(0xff << 0)115#define LDBBSAAR_B_SHIFT	0116#define LDBnBPPCR(n)		(0xb20 + (n) * 0x20 + 0x1c)117#define LDBBPPCR_AP_MASK	(0xff << 24)118#define LDBBPPCR_AP_SHIFT	24119#define LDBBPPCR_R_MASK		(0xff << 16)120#define LDBBPPCR_R_SHIFT	16121#define LDBBPPCR_GY_MASK	(0xff << 8)122#define LDBBPPCR_GY_SHIFT	8123#define LDBBPPCR_B_MASK		(0xff << 0)124#define LDBBPPCR_B_SHIFT	0125#define LDBnBBGCL(n)		(0xb10 + (n) * 0x04)126#define LDBBBGCL_BGA_MASK	(0xff << 24)127#define LDBBBGCL_BGA_SHIFT	24128#define LDBBBGCL_BGR_MASK	(0xff << 16)129#define LDBBBGCL_BGR_SHIFT	16130#define LDBBBGCL_BGG_MASK	(0xff << 8)131#define LDBBBGCL_BGG_SHIFT	8132#define LDBBBGCL_BGB_MASK	(0xff << 0)133#define LDBBBGCL_BGB_SHIFT	0134 135#define SIDE_B_OFFSET 0x1000136#define MIRROR_OFFSET 0x2000137 138#define MAX_XRES 1920139#define MAX_YRES 1080140 141enum sh_mobile_lcdc_overlay_mode {142	LCDC_OVERLAY_BLEND,143	LCDC_OVERLAY_ROP3,144};145 146/*147 * struct sh_mobile_lcdc_overlay - LCDC display overlay148 *149 * @channel: LCDC channel this overlay belongs to150 * @cfg: Overlay configuration151 * @info: Frame buffer device152 * @index: Overlay index (0-3)153 * @base: Overlay registers base address154 * @enabled: True if the overlay is enabled155 * @mode: Overlay blending mode (alpha blend or ROP3)156 * @alpha: Global alpha blending value (0-255, for alpha blending mode)157 * @rop3: Raster operation (for ROP3 mode)158 * @fb_mem: Frame buffer virtual memory address159 * @fb_size: Frame buffer size in bytes160 * @dma_handle: Frame buffer DMA address161 * @base_addr_y: Overlay base address (RGB or luma component)162 * @base_addr_c: Overlay base address (chroma component)163 * @pan_y_offset: Panning linear offset in bytes (luma component)164 * @format: Current pixelf format165 * @xres: Horizontal visible resolution166 * @xres_virtual: Horizontal total resolution167 * @yres: Vertical visible resolution168 * @yres_virtual: Vertical total resolution169 * @pitch: Overlay line pitch170 * @pos_x: Horizontal overlay position171 * @pos_y: Vertical overlay position172 */173struct sh_mobile_lcdc_overlay {174	struct sh_mobile_lcdc_chan *channel;175 176	const struct sh_mobile_lcdc_overlay_cfg *cfg;177	struct fb_info *info;178 179	unsigned int index;180	unsigned long base;181 182	bool enabled;183	enum sh_mobile_lcdc_overlay_mode mode;184	unsigned int alpha;185	unsigned int rop3;186 187	void *fb_mem;188	unsigned long fb_size;189 190	dma_addr_t dma_handle;191	unsigned long base_addr_y;192	unsigned long base_addr_c;193	unsigned long pan_y_offset;194 195	const struct sh_mobile_lcdc_format_info *format;196	unsigned int xres;197	unsigned int xres_virtual;198	unsigned int yres;199	unsigned int yres_virtual;200	unsigned int pitch;201	int pos_x;202	int pos_y;203};204 205struct sh_mobile_lcdc_priv {206	void __iomem *base;207	int irq;208	atomic_t hw_usecnt;209	struct device *dev;210	struct clk *dot_clk;211	unsigned long lddckr;212 213	struct sh_mobile_lcdc_chan ch[2];214	struct sh_mobile_lcdc_overlay overlays[4];215 216	int started;217	int forced_fourcc; /* 2 channel LCDC must share fourcc setting */218};219 220/* -----------------------------------------------------------------------------221 * Registers access222 */223 224static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = {225	[LDDCKPAT1R] = 0x400,226	[LDDCKPAT2R] = 0x404,227	[LDMT1R] = 0x418,228	[LDMT2R] = 0x41c,229	[LDMT3R] = 0x420,230	[LDDFR] = 0x424,231	[LDSM1R] = 0x428,232	[LDSM2R] = 0x42c,233	[LDSA1R] = 0x430,234	[LDSA2R] = 0x434,235	[LDMLSR] = 0x438,236	[LDHCNR] = 0x448,237	[LDHSYNR] = 0x44c,238	[LDVLNR] = 0x450,239	[LDVSYNR] = 0x454,240	[LDPMR] = 0x460,241	[LDHAJR] = 0x4a0,242};243 244static unsigned long lcdc_offs_sublcd[NR_CH_REGS] = {245	[LDDCKPAT1R] = 0x408,246	[LDDCKPAT2R] = 0x40c,247	[LDMT1R] = 0x600,248	[LDMT2R] = 0x604,249	[LDMT3R] = 0x608,250	[LDDFR] = 0x60c,251	[LDSM1R] = 0x610,252	[LDSM2R] = 0x614,253	[LDSA1R] = 0x618,254	[LDMLSR] = 0x620,255	[LDHCNR] = 0x624,256	[LDHSYNR] = 0x628,257	[LDVLNR] = 0x62c,258	[LDVSYNR] = 0x630,259	[LDPMR] = 0x63c,260};261 262static bool banked(int reg_nr)263{264	switch (reg_nr) {265	case LDMT1R:266	case LDMT2R:267	case LDMT3R:268	case LDDFR:269	case LDSM1R:270	case LDSA1R:271	case LDSA2R:272	case LDMLSR:273	case LDHCNR:274	case LDHSYNR:275	case LDVLNR:276	case LDVSYNR:277		return true;278	}279	return false;280}281 282static int lcdc_chan_is_sublcd(struct sh_mobile_lcdc_chan *chan)283{284	return chan->cfg->chan == LCDC_CHAN_SUBLCD;285}286 287static void lcdc_write_chan(struct sh_mobile_lcdc_chan *chan,288			    int reg_nr, unsigned long data)289{290	iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr]);291	if (banked(reg_nr))292		iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr] +293			  SIDE_B_OFFSET);294}295 296static void lcdc_write_chan_mirror(struct sh_mobile_lcdc_chan *chan,297			    int reg_nr, unsigned long data)298{299	iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr] +300		  MIRROR_OFFSET);301}302 303static unsigned long lcdc_read_chan(struct sh_mobile_lcdc_chan *chan,304				    int reg_nr)305{306	return ioread32(chan->lcdc->base + chan->reg_offs[reg_nr]);307}308 309static void lcdc_write_overlay(struct sh_mobile_lcdc_overlay *ovl,310			       int reg, unsigned long data)311{312	iowrite32(data, ovl->channel->lcdc->base + reg);313	iowrite32(data, ovl->channel->lcdc->base + reg + SIDE_B_OFFSET);314}315 316static void lcdc_write(struct sh_mobile_lcdc_priv *priv,317		       unsigned long reg_offs, unsigned long data)318{319	iowrite32(data, priv->base + reg_offs);320}321 322static unsigned long lcdc_read(struct sh_mobile_lcdc_priv *priv,323			       unsigned long reg_offs)324{325	return ioread32(priv->base + reg_offs);326}327 328static void lcdc_wait_bit(struct sh_mobile_lcdc_priv *priv,329			  unsigned long reg_offs,330			  unsigned long mask, unsigned long until)331{332	while ((lcdc_read(priv, reg_offs) & mask) != until)333		cpu_relax();334}335 336/* -----------------------------------------------------------------------------337 * Clock management338 */339 340static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv)341{342	if (atomic_inc_and_test(&priv->hw_usecnt)) {343		clk_prepare_enable(priv->dot_clk);344		pm_runtime_get_sync(priv->dev);345	}346}347 348static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv)349{350	if (atomic_sub_return(1, &priv->hw_usecnt) == -1) {351		pm_runtime_put(priv->dev);352		clk_disable_unprepare(priv->dot_clk);353	}354}355 356static int sh_mobile_lcdc_setup_clocks(struct sh_mobile_lcdc_priv *priv,357				       int clock_source)358{359	struct clk *clk;360	char *str;361 362	switch (clock_source) {363	case LCDC_CLK_BUS:364		str = "bus_clk";365		priv->lddckr = LDDCKR_ICKSEL_BUS;366		break;367	case LCDC_CLK_PERIPHERAL:368		str = "peripheral_clk";369		priv->lddckr = LDDCKR_ICKSEL_MIPI;370		break;371	case LCDC_CLK_EXTERNAL:372		str = NULL;373		priv->lddckr = LDDCKR_ICKSEL_HDMI;374		break;375	default:376		return -EINVAL;377	}378 379	if (str == NULL)380		return 0;381 382	clk = clk_get(priv->dev, str);383	if (IS_ERR(clk)) {384		dev_err(priv->dev, "cannot get dot clock %s\n", str);385		return PTR_ERR(clk);386	}387 388	priv->dot_clk = clk;389	return 0;390}391 392/* -----------------------------------------------------------------------------393 * Display, panel and deferred I/O394 */395 396static void lcdc_sys_write_index(void *handle, unsigned long data)397{398	struct sh_mobile_lcdc_chan *ch = handle;399 400	lcdc_write(ch->lcdc, _LDDWD0R, data | LDDWDxR_WDACT);401	lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);402	lcdc_write(ch->lcdc, _LDDWAR, LDDWAR_WA |403		   (lcdc_chan_is_sublcd(ch) ? 2 : 0));404	lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);405}406 407static void lcdc_sys_write_data(void *handle, unsigned long data)408{409	struct sh_mobile_lcdc_chan *ch = handle;410 411	lcdc_write(ch->lcdc, _LDDWD0R, data | LDDWDxR_WDACT | LDDWDxR_RSW);412	lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);413	lcdc_write(ch->lcdc, _LDDWAR, LDDWAR_WA |414		   (lcdc_chan_is_sublcd(ch) ? 2 : 0));415	lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);416}417 418static unsigned long lcdc_sys_read_data(void *handle)419{420	struct sh_mobile_lcdc_chan *ch = handle;421 422	lcdc_write(ch->lcdc, _LDDRDR, LDDRDR_RSR);423	lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);424	lcdc_write(ch->lcdc, _LDDRAR, LDDRAR_RA |425		   (lcdc_chan_is_sublcd(ch) ? 2 : 0));426	udelay(1);427	lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);428 429	return lcdc_read(ch->lcdc, _LDDRDR) & LDDRDR_DRD_MASK;430}431 432static struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = {433	.write_index	= lcdc_sys_write_index,434	.write_data	= lcdc_sys_write_data,435	.read_data	= lcdc_sys_read_data,436};437 438static int sh_mobile_lcdc_sginit(struct fb_info *info, struct list_head *pagereflist)439{440	struct sh_mobile_lcdc_chan *ch = info->par;441	unsigned int nr_pages_max = ch->fb_size >> PAGE_SHIFT;442	struct fb_deferred_io_pageref *pageref;443	int nr_pages = 0;444 445	sg_init_table(ch->sglist, nr_pages_max);446 447	list_for_each_entry(pageref, pagereflist, list) {448		sg_set_page(&ch->sglist[nr_pages++], pageref->page, PAGE_SIZE, 0);449	}450 451	return nr_pages;452}453 454static void sh_mobile_lcdc_deferred_io(struct fb_info *info, struct list_head *pagereflist)455{456	struct sh_mobile_lcdc_chan *ch = info->par;457	const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg;458 459	/* enable clocks before accessing hardware */460	sh_mobile_lcdc_clk_on(ch->lcdc);461 462	/*463	 * It's possible to get here without anything on the pagereflist via464	 * sh_mobile_lcdc_deferred_io_touch() or via a userspace fsync()465	 * invocation. In the former case, the acceleration routines are466	 * stepped in to when using the framebuffer console causing the467	 * workqueue to be scheduled without any dirty pages on the list.468	 *469	 * Despite this, a panel update is still needed given that the470	 * acceleration routines have their own methods for writing in471	 * that still need to be updated.472	 *473	 * The fsync() and empty pagereflist case could be optimized for,474	 * but we don't bother, as any application exhibiting such475	 * behaviour is fundamentally broken anyways.476	 */477	if (!list_empty(pagereflist)) {478		unsigned int nr_pages = sh_mobile_lcdc_sginit(info, pagereflist);479 480		/* trigger panel update */481		dma_map_sg(ch->lcdc->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);482		if (panel->start_transfer)483			panel->start_transfer(ch, &sh_mobile_lcdc_sys_bus_ops);484		lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG);485		dma_unmap_sg(ch->lcdc->dev, ch->sglist, nr_pages,486			     DMA_TO_DEVICE);487	} else {488		if (panel->start_transfer)489			panel->start_transfer(ch, &sh_mobile_lcdc_sys_bus_ops);490		lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG);491	}492}493 494static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info)495{496	struct fb_deferred_io *fbdefio = info->fbdefio;497 498	if (fbdefio)499		schedule_delayed_work(&info->deferred_work, fbdefio->delay);500}501 502static void sh_mobile_lcdc_display_on(struct sh_mobile_lcdc_chan *ch)503{504	const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg;505 506	if (ch->tx_dev) {507		int ret;508 509		ret = ch->tx_dev->ops->display_on(ch->tx_dev);510		if (ret < 0)511			return;512 513		if (ret == SH_MOBILE_LCDC_DISPLAY_DISCONNECTED)514			ch->info->state = FBINFO_STATE_SUSPENDED;515	}516 517	/* HDMI must be enabled before LCDC configuration */518	if (panel->display_on)519		panel->display_on();520}521 522static void sh_mobile_lcdc_display_off(struct sh_mobile_lcdc_chan *ch)523{524	const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg;525 526	if (panel->display_off)527		panel->display_off();528 529	if (ch->tx_dev)530		ch->tx_dev->ops->display_off(ch->tx_dev);531}532 533/* -----------------------------------------------------------------------------534 * Format helpers535 */536 537struct sh_mobile_lcdc_format_info {538	u32 fourcc;539	unsigned int bpp;540	bool yuv;541	u32 lddfr;542};543 544static const struct sh_mobile_lcdc_format_info sh_mobile_format_infos[] = {545	{546		.fourcc = V4L2_PIX_FMT_RGB565,547		.bpp = 16,548		.yuv = false,549		.lddfr = LDDFR_PKF_RGB16,550	}, {551		.fourcc = V4L2_PIX_FMT_BGR24,552		.bpp = 24,553		.yuv = false,554		.lddfr = LDDFR_PKF_RGB24,555	}, {556		.fourcc = V4L2_PIX_FMT_BGR32,557		.bpp = 32,558		.yuv = false,559		.lddfr = LDDFR_PKF_ARGB32,560	}, {561		.fourcc = V4L2_PIX_FMT_NV12,562		.bpp = 12,563		.yuv = true,564		.lddfr = LDDFR_CC | LDDFR_YF_420,565	}, {566		.fourcc = V4L2_PIX_FMT_NV21,567		.bpp = 12,568		.yuv = true,569		.lddfr = LDDFR_CC | LDDFR_YF_420,570	}, {571		.fourcc = V4L2_PIX_FMT_NV16,572		.bpp = 16,573		.yuv = true,574		.lddfr = LDDFR_CC | LDDFR_YF_422,575	}, {576		.fourcc = V4L2_PIX_FMT_NV61,577		.bpp = 16,578		.yuv = true,579		.lddfr = LDDFR_CC | LDDFR_YF_422,580	}, {581		.fourcc = V4L2_PIX_FMT_NV24,582		.bpp = 24,583		.yuv = true,584		.lddfr = LDDFR_CC | LDDFR_YF_444,585	}, {586		.fourcc = V4L2_PIX_FMT_NV42,587		.bpp = 24,588		.yuv = true,589		.lddfr = LDDFR_CC | LDDFR_YF_444,590	},591};592 593static const struct sh_mobile_lcdc_format_info *594sh_mobile_format_info(u32 fourcc)595{596	unsigned int i;597 598	for (i = 0; i < ARRAY_SIZE(sh_mobile_format_infos); ++i) {599		if (sh_mobile_format_infos[i].fourcc == fourcc)600			return &sh_mobile_format_infos[i];601	}602 603	return NULL;604}605 606static int sh_mobile_format_fourcc(const struct fb_var_screeninfo *var)607{608	if (var->grayscale > 1)609		return var->grayscale;610 611	switch (var->bits_per_pixel) {612	case 16:613		return V4L2_PIX_FMT_RGB565;614	case 24:615		return V4L2_PIX_FMT_BGR24;616	case 32:617		return V4L2_PIX_FMT_BGR32;618	default:619		return 0;620	}621}622 623static int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var)624{625	return var->grayscale > 1;626}627 628/* -----------------------------------------------------------------------------629 * Start, stop and IRQ630 */631 632static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)633{634	struct sh_mobile_lcdc_priv *priv = data;635	struct sh_mobile_lcdc_chan *ch;636	unsigned long ldintr;637	int is_sub;638	int k;639 640	/* Acknowledge interrupts and disable further VSYNC End IRQs. */641	ldintr = lcdc_read(priv, _LDINTR);642	lcdc_write(priv, _LDINTR, (ldintr ^ LDINTR_STATUS_MASK) & ~LDINTR_VEE);643 644	/* figure out if this interrupt is for main or sub lcd */645	is_sub = (lcdc_read(priv, _LDSR) & LDSR_MSS) ? 1 : 0;646 647	/* wake up channel and disable clocks */648	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {649		ch = &priv->ch[k];650 651		if (!ch->enabled)652			continue;653 654		/* Frame End */655		if (ldintr & LDINTR_FS) {656			if (is_sub == lcdc_chan_is_sublcd(ch)) {657				ch->frame_end = 1;658				wake_up(&ch->frame_end_wait);659 660				sh_mobile_lcdc_clk_off(priv);661			}662		}663 664		/* VSYNC End */665		if (ldintr & LDINTR_VES)666			complete(&ch->vsync_completion);667	}668 669	return IRQ_HANDLED;670}671 672static int sh_mobile_lcdc_wait_for_vsync(struct sh_mobile_lcdc_chan *ch)673{674	unsigned long ldintr;675	int ret;676 677	/* Enable VSync End interrupt and be careful not to acknowledge any678	 * pending interrupt.679	 */680	ldintr = lcdc_read(ch->lcdc, _LDINTR);681	ldintr |= LDINTR_VEE | LDINTR_STATUS_MASK;682	lcdc_write(ch->lcdc, _LDINTR, ldintr);683 684	ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion,685							msecs_to_jiffies(100));686	if (!ret)687		return -ETIMEDOUT;688 689	return 0;690}691 692static void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv,693				      int start)694{695	unsigned long tmp = lcdc_read(priv, _LDCNT2R);696	int k;697 698	/* start or stop the lcdc */699	if (start)700		lcdc_write(priv, _LDCNT2R, tmp | LDCNT2R_DO);701	else702		lcdc_write(priv, _LDCNT2R, tmp & ~LDCNT2R_DO);703 704	/* wait until power is applied/stopped on all channels */705	for (k = 0; k < ARRAY_SIZE(priv->ch); k++)706		if (lcdc_read(priv, _LDCNT2R) & priv->ch[k].enabled)707			while (1) {708				tmp = lcdc_read_chan(&priv->ch[k], LDPMR)709				    & LDPMR_LPS;710				if (start && tmp == LDPMR_LPS)711					break;712				if (!start && tmp == 0)713					break;714				cpu_relax();715			}716 717	if (!start)718		lcdc_write(priv, _LDDCKSTPR, 1); /* stop dotclock */719}720 721static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)722{723	const struct fb_var_screeninfo *var = &ch->info->var;724	const struct fb_videomode *mode = &ch->display.mode;725	unsigned long h_total, hsync_pos, display_h_total;726	u32 tmp;727 728	tmp = ch->ldmt1r_value;729	tmp |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : LDMT1R_VPOL;730	tmp |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : LDMT1R_HPOL;731	tmp |= (ch->cfg->flags & LCDC_FLAGS_DWPOL) ? LDMT1R_DWPOL : 0;732	tmp |= (ch->cfg->flags & LCDC_FLAGS_DIPOL) ? LDMT1R_DIPOL : 0;733	tmp |= (ch->cfg->flags & LCDC_FLAGS_DAPOL) ? LDMT1R_DAPOL : 0;734	tmp |= (ch->cfg->flags & LCDC_FLAGS_HSCNT) ? LDMT1R_HSCNT : 0;735	tmp |= (ch->cfg->flags & LCDC_FLAGS_DWCNT) ? LDMT1R_DWCNT : 0;736	lcdc_write_chan(ch, LDMT1R, tmp);737 738	/* setup SYS bus */739	lcdc_write_chan(ch, LDMT2R, ch->cfg->sys_bus_cfg.ldmt2r);740	lcdc_write_chan(ch, LDMT3R, ch->cfg->sys_bus_cfg.ldmt3r);741 742	/* horizontal configuration */743	h_total = mode->xres + mode->hsync_len + mode->left_margin744		+ mode->right_margin;745	tmp = h_total / 8; /* HTCN */746	tmp |= (min(mode->xres, ch->xres) / 8) << 16; /* HDCN */747	lcdc_write_chan(ch, LDHCNR, tmp);748 749	hsync_pos = mode->xres + mode->right_margin;750	tmp = hsync_pos / 8; /* HSYNP */751	tmp |= (mode->hsync_len / 8) << 16; /* HSYNW */752	lcdc_write_chan(ch, LDHSYNR, tmp);753 754	/* vertical configuration */755	tmp = mode->yres + mode->vsync_len + mode->upper_margin756	    + mode->lower_margin; /* VTLN */757	tmp |= min(mode->yres, ch->yres) << 16; /* VDLN */758	lcdc_write_chan(ch, LDVLNR, tmp);759 760	tmp = mode->yres + mode->lower_margin; /* VSYNP */761	tmp |= mode->vsync_len << 16; /* VSYNW */762	lcdc_write_chan(ch, LDVSYNR, tmp);763 764	/* Adjust horizontal synchronisation for HDMI */765	display_h_total = mode->xres + mode->hsync_len + mode->left_margin766			+ mode->right_margin;767	tmp = ((mode->xres & 7) << 24) | ((display_h_total & 7) << 16)768	    | ((mode->hsync_len & 7) << 8) | (hsync_pos & 7);769	lcdc_write_chan(ch, LDHAJR, tmp);770	lcdc_write_chan_mirror(ch, LDHAJR, tmp);771}772 773static void sh_mobile_lcdc_overlay_setup(struct sh_mobile_lcdc_overlay *ovl)774{775	u32 format = 0;776 777	if (!ovl->enabled) {778		lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index));779		lcdc_write_overlay(ovl, LDBnBSIFR(ovl->index), 0);780		lcdc_write(ovl->channel->lcdc, LDBCR,781			   LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index));782		return;783	}784 785	ovl->base_addr_y = ovl->dma_handle;786	ovl->base_addr_c = ovl->dma_handle787			 + ovl->xres_virtual * ovl->yres_virtual;788 789	switch (ovl->mode) {790	case LCDC_OVERLAY_BLEND:791		format = LDBBSIFR_EN | (ovl->alpha << LDBBSIFR_LAY_SHIFT);792		break;793 794	case LCDC_OVERLAY_ROP3:795		format = LDBBSIFR_EN | LDBBSIFR_BRSEL796		       | (ovl->rop3 << LDBBSIFR_ROP3_SHIFT);797		break;798	}799 800	switch (ovl->format->fourcc) {801	case V4L2_PIX_FMT_RGB565:802	case V4L2_PIX_FMT_NV21:803	case V4L2_PIX_FMT_NV61:804	case V4L2_PIX_FMT_NV42:805		format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW;806		break;807	case V4L2_PIX_FMT_BGR24:808	case V4L2_PIX_FMT_NV12:809	case V4L2_PIX_FMT_NV16:810	case V4L2_PIX_FMT_NV24:811		format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW | LDBBSIFR_SWPB;812		break;813	case V4L2_PIX_FMT_BGR32:814	default:815		format |= LDBBSIFR_SWPL;816		break;817	}818 819	switch (ovl->format->fourcc) {820	case V4L2_PIX_FMT_RGB565:821		format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB16;822		break;823	case V4L2_PIX_FMT_BGR24:824		format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB24;825		break;826	case V4L2_PIX_FMT_BGR32:827		format |= LDBBSIFR_AL_PK | LDBBSIFR_RY | LDBBSIFR_RPKF_ARGB32;828		break;829	case V4L2_PIX_FMT_NV12:830	case V4L2_PIX_FMT_NV21:831		format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_420;832		break;833	case V4L2_PIX_FMT_NV16:834	case V4L2_PIX_FMT_NV61:835		format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_422;836		break;837	case V4L2_PIX_FMT_NV24:838	case V4L2_PIX_FMT_NV42:839		format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_444;840		break;841	}842 843	lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index));844 845	lcdc_write_overlay(ovl, LDBnBSIFR(ovl->index), format);846 847	lcdc_write_overlay(ovl, LDBnBSSZR(ovl->index),848		(ovl->yres << LDBBSSZR_BVSS_SHIFT) |849		(ovl->xres << LDBBSSZR_BHSS_SHIFT));850	lcdc_write_overlay(ovl, LDBnBLOCR(ovl->index),851		(ovl->pos_y << LDBBLOCR_CVLC_SHIFT) |852		(ovl->pos_x << LDBBLOCR_CHLC_SHIFT));853	lcdc_write_overlay(ovl, LDBnBSMWR(ovl->index),854		ovl->pitch << LDBBSMWR_BSMW_SHIFT);855 856	lcdc_write_overlay(ovl, LDBnBSAYR(ovl->index), ovl->base_addr_y);857	lcdc_write_overlay(ovl, LDBnBSACR(ovl->index), ovl->base_addr_c);858 859	lcdc_write(ovl->channel->lcdc, LDBCR,860		   LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index));861}862 863/*864 * __sh_mobile_lcdc_start - Configure and start the LCDC865 * @priv: LCDC device866 *867 * Configure all enabled channels and start the LCDC device. All external868 * devices (clocks, MERAM, panels, ...) are not touched by this function.869 */870static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)871{872	struct sh_mobile_lcdc_chan *ch;873	unsigned long tmp;874	int k, m;875 876	/* Enable LCDC channels. Read data from external memory, avoid using the877	 * BEU for now.878	 */879	lcdc_write(priv, _LDCNT2R, priv->ch[0].enabled | priv->ch[1].enabled);880 881	/* Stop the LCDC first and disable all interrupts. */882	sh_mobile_lcdc_start_stop(priv, 0);883	lcdc_write(priv, _LDINTR, 0);884 885	/* Configure power supply, dot clocks and start them. */886	tmp = priv->lddckr;887	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {888		ch = &priv->ch[k];889		if (!ch->enabled)890			continue;891 892		/* Power supply */893		lcdc_write_chan(ch, LDPMR, 0);894 895		m = ch->cfg->clock_divider;896		if (!m)897			continue;898 899		/* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider900		 * denominator.901		 */902		lcdc_write_chan(ch, LDDCKPAT1R, 0);903		lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1);904 905		if (m == 1)906			m = LDDCKR_MOSEL;907		tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0);908	}909 910	lcdc_write(priv, _LDDCKR, tmp);911	lcdc_write(priv, _LDDCKSTPR, 0);912	lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0);913 914	/* Setup geometry, format, frame buffer memory and operation mode. */915	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {916		ch = &priv->ch[k];917		if (!ch->enabled)918			continue;919 920		sh_mobile_lcdc_geometry(ch);921 922		tmp = ch->format->lddfr;923 924		if (ch->format->yuv) {925			switch (ch->colorspace) {926			case V4L2_COLORSPACE_REC709:927				tmp |= LDDFR_CF1;928				break;929			case V4L2_COLORSPACE_JPEG:930				tmp |= LDDFR_CF0;931				break;932			}933		}934 935		lcdc_write_chan(ch, LDDFR, tmp);936		lcdc_write_chan(ch, LDMLSR, ch->line_size);937		lcdc_write_chan(ch, LDSA1R, ch->base_addr_y);938		if (ch->format->yuv)939			lcdc_write_chan(ch, LDSA2R, ch->base_addr_c);940 941		/* When using deferred I/O mode, configure the LCDC for one-shot942		 * operation and enable the frame end interrupt. Otherwise use943		 * continuous read mode.944		 */945		if (ch->ldmt1r_value & LDMT1R_IFM &&946		    ch->cfg->sys_bus_cfg.deferred_io_msec) {947			lcdc_write_chan(ch, LDSM1R, LDSM1R_OS);948			lcdc_write(priv, _LDINTR, LDINTR_FE);949		} else {950			lcdc_write_chan(ch, LDSM1R, 0);951		}952	}953 954	/* Word and long word swap. */955	switch (priv->ch[0].format->fourcc) {956	case V4L2_PIX_FMT_RGB565:957	case V4L2_PIX_FMT_NV21:958	case V4L2_PIX_FMT_NV61:959	case V4L2_PIX_FMT_NV42:960		tmp = LDDDSR_LS | LDDDSR_WS;961		break;962	case V4L2_PIX_FMT_BGR24:963	case V4L2_PIX_FMT_NV12:964	case V4L2_PIX_FMT_NV16:965	case V4L2_PIX_FMT_NV24:966		tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;967		break;968	case V4L2_PIX_FMT_BGR32:969	default:970		tmp = LDDDSR_LS;971		break;972	}973	lcdc_write(priv, _LDDDSR, tmp);974 975	/* Enable the display output. */976	lcdc_write(priv, _LDCNT1R, LDCNT1R_DE);977	sh_mobile_lcdc_start_stop(priv, 1);978	priv->started = 1;979}980 981static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)982{983	struct sh_mobile_lcdc_chan *ch;984	unsigned long tmp;985	int ret;986	int k;987 988	/* enable clocks before accessing the hardware */989	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {990		if (priv->ch[k].enabled)991			sh_mobile_lcdc_clk_on(priv);992	}993 994	/* reset */995	lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LDCNT2R_BR);996	lcdc_wait_bit(priv, _LDCNT2R, LDCNT2R_BR, 0);997 998	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {999		const struct sh_mobile_lcdc_panel_cfg *panel;1000 1001		ch = &priv->ch[k];1002		if (!ch->enabled)1003			continue;1004 1005		panel = &ch->cfg->panel_cfg;1006		if (panel->setup_sys) {1007			ret = panel->setup_sys(ch, &sh_mobile_lcdc_sys_bus_ops);1008			if (ret)1009				return ret;1010		}1011	}1012 1013	/* Compute frame buffer base address and pitch for each channel. */1014	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {1015		ch = &priv->ch[k];1016		if (!ch->enabled)1017			continue;1018 1019		ch->base_addr_y = ch->dma_handle;1020		ch->base_addr_c = ch->dma_handle1021				+ ch->xres_virtual * ch->yres_virtual;1022		ch->line_size = ch->pitch;1023	}1024 1025	for (k = 0; k < ARRAY_SIZE(priv->overlays); ++k) {1026		struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[k];1027		sh_mobile_lcdc_overlay_setup(ovl);1028	}1029 1030	/* Start the LCDC. */1031	__sh_mobile_lcdc_start(priv);1032 1033	/* Setup deferred I/O, tell the board code to enable the panels, and1034	 * turn backlight on.1035	 */1036	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {1037		ch = &priv->ch[k];1038		if (!ch->enabled)1039			continue;1040 1041		tmp = ch->cfg->sys_bus_cfg.deferred_io_msec;1042		if (ch->ldmt1r_value & LDMT1R_IFM && tmp) {1043			ch->defio.deferred_io = sh_mobile_lcdc_deferred_io;1044			ch->defio.delay = msecs_to_jiffies(tmp);1045			ch->info->fbdefio = &ch->defio;1046			fb_deferred_io_init(ch->info);1047		}1048 1049		sh_mobile_lcdc_display_on(ch);1050 1051		if (ch->bl) {1052			ch->bl->props.power = FB_BLANK_UNBLANK;1053			backlight_update_status(ch->bl);1054		}1055	}1056 1057	return 0;1058}1059 1060static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)1061{1062	struct sh_mobile_lcdc_chan *ch;1063	int k;1064 1065	/* clean up deferred io and ask board code to disable panel */1066	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {1067		ch = &priv->ch[k];1068		if (!ch->enabled)1069			continue;1070 1071		/* deferred io mode:1072		 * flush frame, and wait for frame end interrupt1073		 * clean up deferred io and enable clock1074		 */1075		if (ch->info && ch->info->fbdefio) {1076			ch->frame_end = 0;1077			schedule_delayed_work(&ch->info->deferred_work, 0);1078			wait_event(ch->frame_end_wait, ch->frame_end);1079			fb_deferred_io_cleanup(ch->info);1080			ch->info->fbdefio = NULL;1081			sh_mobile_lcdc_clk_on(priv);1082		}1083 1084		if (ch->bl) {1085			ch->bl->props.power = FB_BLANK_POWERDOWN;1086			backlight_update_status(ch->bl);1087		}1088 1089		sh_mobile_lcdc_display_off(ch);1090	}1091 1092	/* stop the lcdc */1093	if (priv->started) {1094		sh_mobile_lcdc_start_stop(priv, 0);1095		priv->started = 0;1096	}1097 1098	/* stop clocks */1099	for (k = 0; k < ARRAY_SIZE(priv->ch); k++)1100		if (priv->ch[k].enabled)1101			sh_mobile_lcdc_clk_off(priv);1102}1103 1104static int __sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var,1105				      struct fb_info *info)1106{1107	if (var->xres > MAX_XRES || var->yres > MAX_YRES)1108		return -EINVAL;1109 1110	/* Make sure the virtual resolution is at least as big as the visible1111	 * resolution.1112	 */1113	if (var->xres_virtual < var->xres)1114		var->xres_virtual = var->xres;1115	if (var->yres_virtual < var->yres)1116		var->yres_virtual = var->yres;1117 1118	if (sh_mobile_format_is_fourcc(var)) {1119		const struct sh_mobile_lcdc_format_info *format;1120 1121		format = sh_mobile_format_info(var->grayscale);1122		if (format == NULL)1123			return -EINVAL;1124		var->bits_per_pixel = format->bpp;1125 1126		/* Default to RGB and JPEG color-spaces for RGB and YUV formats1127		 * respectively.1128		 */1129		if (!format->yuv)1130			var->colorspace = V4L2_COLORSPACE_SRGB;1131		else if (var->colorspace != V4L2_COLORSPACE_REC709)1132			var->colorspace = V4L2_COLORSPACE_JPEG;1133	} else {1134		if (var->bits_per_pixel <= 16) {		/* RGB 565 */1135			var->bits_per_pixel = 16;1136			var->red.offset = 11;1137			var->red.length = 5;1138			var->green.offset = 5;1139			var->green.length = 6;1140			var->blue.offset = 0;1141			var->blue.length = 5;1142			var->transp.offset = 0;1143			var->transp.length = 0;1144		} else if (var->bits_per_pixel <= 24) {		/* RGB 888 */1145			var->bits_per_pixel = 24;1146			var->red.offset = 16;1147			var->red.length = 8;1148			var->green.offset = 8;1149			var->green.length = 8;1150			var->blue.offset = 0;1151			var->blue.length = 8;1152			var->transp.offset = 0;1153			var->transp.length = 0;1154		} else if (var->bits_per_pixel <= 32) {		/* RGBA 888 */1155			var->bits_per_pixel = 32;1156			var->red.offset = 16;1157			var->red.length = 8;1158			var->green.offset = 8;1159			var->green.length = 8;1160			var->blue.offset = 0;1161			var->blue.length = 8;1162			var->transp.offset = 24;1163			var->transp.length = 8;1164		} else1165			return -EINVAL;1166 1167		var->red.msb_right = 0;1168		var->green.msb_right = 0;1169		var->blue.msb_right = 0;1170		var->transp.msb_right = 0;1171	}1172 1173	/* Make sure we don't exceed our allocated memory. */1174	if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 >1175	    info->fix.smem_len)1176		return -EINVAL;1177 1178	return 0;1179}1180 1181/* -----------------------------------------------------------------------------1182 * Frame buffer operations - Overlays1183 */1184 1185static ssize_t1186overlay_alpha_show(struct device *dev, struct device_attribute *attr, char *buf)1187{1188	struct fb_info *info = dev_get_drvdata(dev);1189	struct sh_mobile_lcdc_overlay *ovl = info->par;1190 1191	return sysfs_emit(buf, "%u\n", ovl->alpha);1192}1193 1194static ssize_t1195overlay_alpha_store(struct device *dev, struct device_attribute *attr,1196		    const char *buf, size_t count)1197{1198	struct fb_info *info = dev_get_drvdata(dev);1199	struct sh_mobile_lcdc_overlay *ovl = info->par;1200	unsigned int alpha;1201	char *endp;1202 1203	alpha = simple_strtoul(buf, &endp, 10);1204	if (isspace(*endp))1205		endp++;1206 1207	if (endp - buf != count)1208		return -EINVAL;1209 1210	if (alpha > 255)1211		return -EINVAL;1212 1213	if (ovl->alpha != alpha) {1214		ovl->alpha = alpha;1215 1216		if (ovl->mode == LCDC_OVERLAY_BLEND && ovl->enabled)1217			sh_mobile_lcdc_overlay_setup(ovl);1218	}1219 1220	return count;1221}1222 1223static ssize_t1224overlay_mode_show(struct device *dev, struct device_attribute *attr, char *buf)1225{1226	struct fb_info *info = dev_get_drvdata(dev);1227	struct sh_mobile_lcdc_overlay *ovl = info->par;1228 1229	return sysfs_emit(buf, "%u\n", ovl->mode);1230}1231 1232static ssize_t1233overlay_mode_store(struct device *dev, struct device_attribute *attr,1234		   const char *buf, size_t count)1235{1236	struct fb_info *info = dev_get_drvdata(dev);1237	struct sh_mobile_lcdc_overlay *ovl = info->par;1238	unsigned int mode;1239	char *endp;1240 1241	mode = simple_strtoul(buf, &endp, 10);1242	if (isspace(*endp))1243		endp++;1244 1245	if (endp - buf != count)1246		return -EINVAL;1247 1248	if (mode != LCDC_OVERLAY_BLEND && mode != LCDC_OVERLAY_ROP3)1249		return -EINVAL;1250 1251	if (ovl->mode != mode) {1252		ovl->mode = mode;1253 1254		if (ovl->enabled)1255			sh_mobile_lcdc_overlay_setup(ovl);1256	}1257 1258	return count;1259}1260 1261static ssize_t1262overlay_position_show(struct device *dev, struct device_attribute *attr,1263		      char *buf)1264{1265	struct fb_info *info = dev_get_drvdata(dev);1266	struct sh_mobile_lcdc_overlay *ovl = info->par;1267 1268	return sysfs_emit(buf, "%d,%d\n", ovl->pos_x, ovl->pos_y);1269}1270 1271static ssize_t1272overlay_position_store(struct device *dev, struct device_attribute *attr,1273		       const char *buf, size_t count)1274{1275	struct fb_info *info = dev_get_drvdata(dev);1276	struct sh_mobile_lcdc_overlay *ovl = info->par;1277	char *endp;1278	int pos_x;1279	int pos_y;1280 1281	pos_x = simple_strtol(buf, &endp, 10);1282	if (*endp != ',')1283		return -EINVAL;1284 1285	pos_y = simple_strtol(endp + 1, &endp, 10);1286	if (isspace(*endp))1287		endp++;1288 1289	if (endp - buf != count)1290		return -EINVAL;1291 1292	if (ovl->pos_x != pos_x || ovl->pos_y != pos_y) {1293		ovl->pos_x = pos_x;1294		ovl->pos_y = pos_y;1295 1296		if (ovl->enabled)1297			sh_mobile_lcdc_overlay_setup(ovl);1298	}1299 1300	return count;1301}1302 1303static ssize_t1304overlay_rop3_show(struct device *dev, struct device_attribute *attr, char *buf)1305{1306	struct fb_info *info = dev_get_drvdata(dev);1307	struct sh_mobile_lcdc_overlay *ovl = info->par;1308 1309	return sysfs_emit(buf, "%u\n", ovl->rop3);1310}1311 1312static ssize_t1313overlay_rop3_store(struct device *dev, struct device_attribute *attr,1314		    const char *buf, size_t count)1315{1316	struct fb_info *info = dev_get_drvdata(dev);1317	struct sh_mobile_lcdc_overlay *ovl = info->par;1318	unsigned int rop3;1319	char *endp;1320 1321	rop3 = simple_strtoul(buf, &endp, 10);1322	if (isspace(*endp))1323		endp++;1324 1325	if (endp - buf != count)1326		return -EINVAL;1327 1328	if (rop3 > 255)1329		return -EINVAL;1330 1331	if (ovl->rop3 != rop3) {1332		ovl->rop3 = rop3;1333 1334		if (ovl->mode == LCDC_OVERLAY_ROP3 && ovl->enabled)1335			sh_mobile_lcdc_overlay_setup(ovl);1336	}1337 1338	return count;1339}1340 1341static const struct device_attribute overlay_sysfs_attrs[] = {1342	__ATTR(ovl_alpha, S_IRUGO|S_IWUSR,1343	       overlay_alpha_show, overlay_alpha_store),1344	__ATTR(ovl_mode, S_IRUGO|S_IWUSR,1345	       overlay_mode_show, overlay_mode_store),1346	__ATTR(ovl_position, S_IRUGO|S_IWUSR,1347	       overlay_position_show, overlay_position_store),1348	__ATTR(ovl_rop3, S_IRUGO|S_IWUSR,1349	       overlay_rop3_show, overlay_rop3_store),1350};1351 1352static const struct fb_fix_screeninfo sh_mobile_lcdc_overlay_fix  = {1353	.id =		"SH Mobile LCDC",1354	.type =		FB_TYPE_PACKED_PIXELS,1355	.visual =	FB_VISUAL_TRUECOLOR,1356	.accel =	FB_ACCEL_NONE,1357	.xpanstep =	1,1358	.ypanstep =	1,1359	.ywrapstep =	0,1360	.capabilities =	FB_CAP_FOURCC,1361};1362 1363static int sh_mobile_lcdc_overlay_pan(struct fb_var_screeninfo *var,1364				    struct fb_info *info)1365{1366	struct sh_mobile_lcdc_overlay *ovl = info->par;1367	unsigned long base_addr_y;1368	unsigned long base_addr_c;1369	unsigned long y_offset;1370	unsigned long c_offset;1371 1372	if (!ovl->format->yuv) {1373		y_offset = (var->yoffset * ovl->xres_virtual + var->xoffset)1374			 * ovl->format->bpp / 8;1375		c_offset = 0;1376	} else {1377		unsigned int xsub = ovl->format->bpp < 24 ? 2 : 1;1378		unsigned int ysub = ovl->format->bpp < 16 ? 2 : 1;1379 1380		y_offset = var->yoffset * ovl->xres_virtual + var->xoffset;1381		c_offset = var->yoffset / ysub * ovl->xres_virtual * 2 / xsub1382			 + var->xoffset * 2 / xsub;1383	}1384 1385	/* If the Y offset hasn't changed, the C offset hasn't either. There's1386	 * nothing to do in that case.1387	 */1388	if (y_offset == ovl->pan_y_offset)1389		return 0;1390 1391	/* Set the source address for the next refresh */1392	base_addr_y = ovl->dma_handle + y_offset;1393	base_addr_c = ovl->dma_handle + ovl->xres_virtual * ovl->yres_virtual1394		    + c_offset;1395 1396	ovl->base_addr_y = base_addr_y;1397	ovl->base_addr_c = base_addr_c;1398	ovl->pan_y_offset = y_offset;1399 1400	lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index));1401 1402	lcdc_write_overlay(ovl, LDBnBSAYR(ovl->index), ovl->base_addr_y);1403	lcdc_write_overlay(ovl, LDBnBSACR(ovl->index), ovl->base_addr_c);1404 1405	lcdc_write(ovl->channel->lcdc, LDBCR,1406		   LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index));1407 1408	return 0;1409}1410 1411static int sh_mobile_lcdc_overlay_ioctl(struct fb_info *info, unsigned int cmd,1412				      unsigned long arg)1413{1414	struct sh_mobile_lcdc_overlay *ovl = info->par;1415 1416	switch (cmd) {1417	case FBIO_WAITFORVSYNC:1418		return sh_mobile_lcdc_wait_for_vsync(ovl->channel);1419 1420	default:1421		return -ENOIOCTLCMD;1422	}1423}1424 1425static int sh_mobile_lcdc_overlay_check_var(struct fb_var_screeninfo *var,1426					  struct fb_info *info)1427{1428	return __sh_mobile_lcdc_check_var(var, info);1429}1430 1431static int sh_mobile_lcdc_overlay_set_par(struct fb_info *info)1432{1433	struct sh_mobile_lcdc_overlay *ovl = info->par;1434 1435	ovl->format =1436		sh_mobile_format_info(sh_mobile_format_fourcc(&info->var));1437 1438	ovl->xres = info->var.xres;1439	ovl->xres_virtual = info->var.xres_virtual;1440	ovl->yres = info->var.yres;1441	ovl->yres_virtual = info->var.yres_virtual;1442 1443	if (ovl->format->yuv)1444		ovl->pitch = info->var.xres_virtual;1445	else1446		ovl->pitch = info->var.xres_virtual * ovl->format->bpp / 8;1447 1448	sh_mobile_lcdc_overlay_setup(ovl);1449 1450	info->fix.line_length = ovl->pitch;1451 1452	if (sh_mobile_format_is_fourcc(&info->var)) {1453		info->fix.type = FB_TYPE_FOURCC;1454		info->fix.visual = FB_VISUAL_FOURCC;1455	} else {1456		info->fix.type = FB_TYPE_PACKED_PIXELS;1457		info->fix.visual = FB_VISUAL_TRUECOLOR;1458	}1459 1460	return 0;1461}1462 1463/* Overlay blanking. Disable the overlay when blanked. */1464static int sh_mobile_lcdc_overlay_blank(int blank, struct fb_info *info)1465{1466	struct sh_mobile_lcdc_overlay *ovl = info->par;1467 1468	ovl->enabled = !blank;1469	sh_mobile_lcdc_overlay_setup(ovl);1470 1471	/* Prevent the backlight from receiving a blanking event by returning1472	 * a non-zero value.1473	 */1474	return 1;1475}1476 1477static int1478sh_mobile_lcdc_overlay_mmap(struct fb_info *info, struct vm_area_struct *vma)1479{1480	struct sh_mobile_lcdc_overlay *ovl = info->par;1481 1482	if (info->fbdefio)1483		return fb_deferred_io_mmap(info, vma);1484 1485	vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);1486 1487	return dma_mmap_coherent(ovl->channel->lcdc->dev, vma, ovl->fb_mem,1488				 ovl->dma_handle, ovl->fb_size);1489}1490 1491static const struct fb_ops sh_mobile_lcdc_overlay_ops = {1492	.owner          = THIS_MODULE,1493	__FB_DEFAULT_DMAMEM_OPS_RDWR,1494	.fb_blank	= sh_mobile_lcdc_overlay_blank,1495	.fb_pan_display = sh_mobile_lcdc_overlay_pan,1496	__FB_DEFAULT_DMAMEM_OPS_DRAW,1497	.fb_ioctl       = sh_mobile_lcdc_overlay_ioctl,1498	.fb_check_var	= sh_mobile_lcdc_overlay_check_var,1499	.fb_set_par	= sh_mobile_lcdc_overlay_set_par,1500	.fb_mmap	= sh_mobile_lcdc_overlay_mmap,1501};1502 1503static void1504sh_mobile_lcdc_overlay_fb_unregister(struct sh_mobile_lcdc_overlay *ovl)1505{1506	struct fb_info *info = ovl->info;1507 1508	if (info == NULL || info->dev == NULL)1509		return;1510 1511	unregister_framebuffer(ovl->info);1512}1513 1514static int1515sh_mobile_lcdc_overlay_fb_register(struct sh_mobile_lcdc_overlay *ovl)1516{1517	struct sh_mobile_lcdc_priv *lcdc = ovl->channel->lcdc;1518	struct fb_info *info = ovl->info;1519	unsigned int i;1520	int ret;1521 1522	if (info == NULL)1523		return 0;1524 1525	ret = register_framebuffer(info);1526	if (ret < 0)1527		return ret;1528 1529	dev_info(lcdc->dev, "registered %s/overlay %u as %dx%d %dbpp.\n",1530		 dev_name(lcdc->dev), ovl->index, info->var.xres,1531		 info->var.yres, info->var.bits_per_pixel);1532 1533	for (i = 0; i < ARRAY_SIZE(overlay_sysfs_attrs); ++i) {1534		ret = device_create_file(info->dev, &overlay_sysfs_attrs[i]);1535		if (ret < 0)1536			return ret;1537	}1538 1539	return 0;1540}1541 1542static void1543sh_mobile_lcdc_overlay_fb_cleanup(struct sh_mobile_lcdc_overlay *ovl)1544{1545	struct fb_info *info = ovl->info;1546 1547	if (info == NULL || info->device == NULL)1548		return;1549 1550	framebuffer_release(info);1551}1552 1553static int1554sh_mobile_lcdc_overlay_fb_init(struct sh_mobile_lcdc_overlay *ovl)1555{1556	struct sh_mobile_lcdc_priv *priv = ovl->channel->lcdc;1557	struct fb_var_screeninfo *var;1558	struct fb_info *info;1559 1560	/* Allocate and initialize the frame buffer device. */1561	info = framebuffer_alloc(0, priv->dev);1562	if (!info)1563		return -ENOMEM;1564 1565	ovl->info = info;1566 1567	info->fbops = &sh_mobile_lcdc_overlay_ops;1568	info->device = priv->dev;1569	info->flags |= FBINFO_VIRTFB;1570	info->screen_buffer = ovl->fb_mem;1571	info->par = ovl;1572 1573	/* Initialize fixed screen information. Restrict pan to 2 lines steps1574	 * for NV12 and NV21.1575	 */1576	info->fix = sh_mobile_lcdc_overlay_fix;1577	snprintf(info->fix.id, sizeof(info->fix.id),1578		 "SHMobile ovl %u", ovl->index);1579	info->fix.smem_start = ovl->dma_handle;1580	info->fix.smem_len = ovl->fb_size;1581	info->fix.line_length = ovl->pitch;1582 1583	if (ovl->format->yuv)1584		info->fix.visual = FB_VISUAL_FOURCC;1585	else1586		info->fix.visual = FB_VISUAL_TRUECOLOR;1587 1588	switch (ovl->format->fourcc) {1589	case V4L2_PIX_FMT_NV12:1590	case V4L2_PIX_FMT_NV21:1591		info->fix.ypanstep = 2;1592		fallthrough;1593	case V4L2_PIX_FMT_NV16:1594	case V4L2_PIX_FMT_NV61:1595		info->fix.xpanstep = 2;1596	}1597 1598	/* Initialize variable screen information. */1599	var = &info->var;1600	memset(var, 0, sizeof(*var));1601	var->xres = ovl->xres;1602	var->yres = ovl->yres;1603	var->xres_virtual = ovl->xres_virtual;1604	var->yres_virtual = ovl->yres_virtual;1605	var->activate = FB_ACTIVATE_NOW;1606 1607	/* Use the legacy API by default for RGB formats, and the FOURCC API1608	 * for YUV formats.1609	 */1610	if (!ovl->format->yuv)1611		var->bits_per_pixel = ovl->format->bpp;1612	else1613		var->grayscale = ovl->format->fourcc;1614 1615	return sh_mobile_lcdc_overlay_check_var(var, info);1616}1617 1618/* -----------------------------------------------------------------------------1619 * Frame buffer operations - main frame buffer1620 */1621 1622static int sh_mobile_lcdc_setcolreg(u_int regno,1623				    u_int red, u_int green, u_int blue,1624				    u_int transp, struct fb_info *info)1625{1626	u32 *palette = info->pseudo_palette;1627 1628	if (regno >= PALETTE_NR)1629		return -EINVAL;1630 1631	/* only FB_VISUAL_TRUECOLOR supported */1632 1633	red >>= 16 - info->var.red.length;1634	green >>= 16 - info->var.green.length;1635	blue >>= 16 - info->var.blue.length;1636	transp >>= 16 - info->var.transp.length;1637 1638	palette[regno] = (red << info->var.red.offset) |1639	  (green << info->var.green.offset) |1640	  (blue << info->var.blue.offset) |1641	  (transp << info->var.transp.offset);1642 1643	return 0;1644}1645 1646static const struct fb_fix_screeninfo sh_mobile_lcdc_fix  = {1647	.id =		"SH Mobile LCDC",1648	.type =		FB_TYPE_PACKED_PIXELS,1649	.visual =	FB_VISUAL_TRUECOLOR,1650	.accel =	FB_ACCEL_NONE,1651	.xpanstep =	1,1652	.ypanstep =	1,1653	.ywrapstep =	0,1654	.capabilities =	FB_CAP_FOURCC,1655};1656 1657static void sh_mobile_lcdc_fillrect(struct fb_info *info,1658				    const struct fb_fillrect *rect)1659{1660	sys_fillrect(info, rect);1661	sh_mobile_lcdc_deferred_io_touch(info);1662}1663 1664static void sh_mobile_lcdc_copyarea(struct fb_info *info,1665				    const struct fb_copyarea *area)1666{1667	sys_copyarea(info, area);1668	sh_mobile_lcdc_deferred_io_touch(info);1669}1670 1671static void sh_mobile_lcdc_imageblit(struct fb_info *info,1672				     const struct fb_image *image)1673{1674	sys_imageblit(info, image);1675	sh_mobile_lcdc_deferred_io_touch(info);1676}1677 1678static int sh_mobile_lcdc_pan(struct fb_var_screeninfo *var,1679			      struct fb_info *info)1680{1681	struct sh_mobile_lcdc_chan *ch = info->par;1682	struct sh_mobile_lcdc_priv *priv = ch->lcdc;1683	unsigned long ldrcntr;1684	unsigned long base_addr_y, base_addr_c;1685	unsigned long y_offset;1686	unsigned long c_offset;1687 1688	if (!ch->format->yuv) {1689		y_offset = (var->yoffset * ch->xres_virtual + var->xoffset)1690			 * ch->format->bpp / 8;1691		c_offset = 0;1692	} else {1693		unsigned int xsub = ch->format->bpp < 24 ? 2 : 1;1694		unsigned int ysub = ch->format->bpp < 16 ? 2 : 1;1695 1696		y_offset = var->yoffset * ch->xres_virtual + var->xoffset;1697		c_offset = var->yoffset / ysub * ch->xres_virtual * 2 / xsub1698			 + var->xoffset * 2 / xsub;1699	}1700 1701	/* If the Y offset hasn't changed, the C offset hasn't either. There's1702	 * nothing to do in that case.1703	 */1704	if (y_offset == ch->pan_y_offset)1705		return 0;1706 1707	/* Set the source address for the next refresh */1708	base_addr_y = ch->dma_handle + y_offset;1709	base_addr_c = ch->dma_handle + ch->xres_virtual * ch->yres_virtual1710		    + c_offset;1711 1712	ch->base_addr_y = base_addr_y;1713	ch->base_addr_c = base_addr_c;1714	ch->pan_y_offset = y_offset;1715 1716	lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);1717	if (ch->format->yuv)1718		lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c);1719 1720	ldrcntr = lcdc_read(priv, _LDRCNTR);1721	if (lcdc_chan_is_sublcd(ch))1722		lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS);1723	else1724		lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_MRS);1725 1726 1727	sh_mobile_lcdc_deferred_io_touch(info);1728 1729	return 0;1730}1731 1732static int sh_mobile_lcdc_ioctl(struct fb_info *info, unsigned int cmd,1733				unsigned long arg)1734{1735	struct sh_mobile_lcdc_chan *ch = info->par;1736	int retval;1737 1738	switch (cmd) {1739	case FBIO_WAITFORVSYNC:1740		retval = sh_mobile_lcdc_wait_for_vsync(ch);1741		break;1742 1743	default:1744		retval = -ENOIOCTLCMD;1745		break;1746	}1747	return retval;1748}1749 1750static void sh_mobile_fb_reconfig(struct fb_info *info)1751{1752	struct sh_mobile_lcdc_chan *ch = info->par;1753	struct fb_var_screeninfo var;1754	struct fb_videomode mode;1755 1756	if (ch->use_count > 1 || (ch->use_count == 1 && !info->fbcon_par))1757		/* More framebuffer users are active */1758		return;1759 1760	fb_var_to_videomode(&mode, &info->var);1761 1762	if (fb_mode_is_equal(&ch->display.mode, &mode))1763		return;1764 1765	/* Display has been re-plugged, framebuffer is free now, reconfigure */1766	var = info->var;1767	fb_videomode_to_var(&var, &ch->display.mode);1768	var.width = ch->display.width;1769	var.height = ch->display.height;1770	var.activate = FB_ACTIVATE_NOW;1771 1772	if (fb_set_var(info, &var) < 0)1773		/* Couldn't reconfigure, hopefully, can continue as before */1774		return;1775 1776	fbcon_update_vcs(info, true);1777}1778 1779/*1780 * Locking: both .fb_release() and .fb_open() are called with info->lock held if1781 * user == 1, or with console sem held, if user == 0.1782 */1783static int sh_mobile_lcdc_release(struct fb_info *info, int user)1784{1785	struct sh_mobile_lcdc_chan *ch = info->par;1786 1787	mutex_lock(&ch->open_lock);1788	dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count);1789 1790	ch->use_count--;1791 1792	/* Nothing to reconfigure, when called from fbcon */1793	if (user) {1794		console_lock();1795		sh_mobile_fb_reconfig(info);1796		console_unlock();1797	}1798 1799	mutex_unlock(&ch->open_lock);1800 1801	return 0;1802}1803 1804static int sh_mobile_lcdc_open(struct fb_info *info, int user)1805{1806	struct sh_mobile_lcdc_chan *ch = info->par;1807 1808	mutex_lock(&ch->open_lock);1809	ch->use_count++;1810 1811	dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count);1812	mutex_unlock(&ch->open_lock);1813 1814	return 0;1815}1816 1817static int sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var,1818				    struct fb_info *info)1819{1820	struct sh_mobile_lcdc_chan *ch = info->par;1821	struct sh_mobile_lcdc_priv *p = ch->lcdc;1822	unsigned int best_dist = (unsigned int)-1;1823	unsigned int best_xres = 0;1824	unsigned int best_yres = 0;1825	unsigned int i;1826	int ret;1827 1828	/* If board code provides us with a list of available modes, make sure1829	 * we use one of them. Find the mode closest to the requested one. The1830	 * distance between two modes is defined as the size of the1831	 * non-overlapping parts of the two rectangles.1832	 */1833	for (i = 0; i < ch->cfg->num_modes; ++i) {1834		const struct fb_videomode *mode = &ch->cfg->lcd_modes[i];1835		unsigned int dist;1836 1837		/* We can only round up. */1838		if (var->xres > mode->xres || var->yres > mode->yres)1839			continue;1840 1841		dist = var->xres * var->yres + mode->xres * mode->yres1842		     - 2 * min(var->xres, mode->xres)1843			 * min(var->yres, mode->yres);1844 1845		if (dist < best_dist) {1846			best_xres = mode->xres;1847			best_yres = mode->yres;1848			best_dist = dist;1849		}1850	}1851 1852	/* If no available mode can be used, return an error. */1853	if (ch->cfg->num_modes != 0) {1854		if (best_dist == (unsigned int)-1)1855			return -EINVAL;1856 1857		var->xres = best_xres;1858		var->yres = best_yres;1859	}1860 1861	ret = __sh_mobile_lcdc_check_var(var, info);1862	if (ret < 0)1863		return ret;1864 1865	/* only accept the forced_fourcc for dual channel configurations */1866	if (p->forced_fourcc &&1867	    p->forced_fourcc != sh_mobile_format_fourcc(var))1868		return -EINVAL;1869 1870	return 0;1871}1872 1873static int sh_mobile_lcdc_set_par(struct fb_info *info)1874{1875	struct sh_mobile_lcdc_chan *ch = info->par;1876	int ret;1877 1878	sh_mobile_lcdc_stop(ch->lcdc);1879 1880	ch->format = sh_mobile_format_info(sh_mobile_format_fourcc(&info->var));1881	ch->colorspace = info->var.colorspace;1882 1883	ch->xres = info->var.xres;1884	ch->xres_virtual = info->var.xres_virtual;1885	ch->yres = info->var.yres;1886	ch->yres_virtual = info->var.yres_virtual;1887 1888	if (ch->format->yuv)1889		ch->pitch = info->var.xres_virtual;1890	else1891		ch->pitch = info->var.xres_virtual * ch->format->bpp / 8;1892 1893	ret = sh_mobile_lcdc_start(ch->lcdc);1894	if (ret < 0)1895		dev_err(info->dev, "%s: unable to restart LCDC\n", __func__);1896 1897	info->fix.line_length = ch->pitch;1898 1899	if (sh_mobile_format_is_fourcc(&info->var)) {1900		info->fix.type = FB_TYPE_FOURCC;1901		info->fix.visual = FB_VISUAL_FOURCC;1902	} else {1903		info->fix.type = FB_TYPE_PACKED_PIXELS;1904		info->fix.visual = FB_VISUAL_TRUECOLOR;1905	}1906 1907	return ret;1908}1909 1910/*1911 * Screen blanking. Behavior is as follows:1912 * FB_BLANK_UNBLANK: screen unblanked, clocks enabled1913 * FB_BLANK_NORMAL: screen blanked, clocks enabled1914 * FB_BLANK_VSYNC,1915 * FB_BLANK_HSYNC,1916 * FB_BLANK_POWEROFF: screen blanked, clocks disabled1917 */1918static int sh_mobile_lcdc_blank(int blank, struct fb_info *info)1919{1920	struct sh_mobile_lcdc_chan *ch = info->par;1921	struct sh_mobile_lcdc_priv *p = ch->lcdc;1922 1923	/* blank the screen? */1924	if (blank > FB_BLANK_UNBLANK && ch->blank_status == FB_BLANK_UNBLANK) {1925		struct fb_fillrect rect = {1926			.width = ch->xres,1927			.height = ch->yres,1928		};1929		sh_mobile_lcdc_fillrect(info, &rect);1930	}1931	/* turn clocks on? */1932	if (blank <= FB_BLANK_NORMAL && ch->blank_status > FB_BLANK_NORMAL) {1933		sh_mobile_lcdc_clk_on(p);1934	}1935	/* turn clocks off? */1936	if (blank > FB_BLANK_NORMAL && ch->blank_status <= FB_BLANK_NORMAL) {1937		/* make sure the screen is updated with the black fill before1938		 * switching the clocks off. one vsync is not enough since1939		 * blanking may occur in the middle of a refresh. deferred io1940		 * mode will reenable the clocks and update the screen in time,1941		 * so it does not need this. */1942		if (!info->fbdefio) {1943			sh_mobile_lcdc_wait_for_vsync(ch);1944			sh_mobile_lcdc_wait_for_vsync(ch);1945		}1946		sh_mobile_lcdc_clk_off(p);1947	}1948 1949	ch->blank_status = blank;1950	return 0;1951}1952 1953static int1954sh_mobile_lcdc_mmap(struct fb_info *info, struct vm_area_struct *vma)1955{1956	struct sh_mobile_lcdc_chan *ch = info->par;1957 1958	if (info->fbdefio)1959		return fb_deferred_io_mmap(info, vma);1960 1961	vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);1962 1963	return dma_mmap_coherent(ch->lcdc->dev, vma, ch->fb_mem,1964				 ch->dma_handle, ch->fb_size);1965}1966 1967static const struct fb_ops sh_mobile_lcdc_ops = {1968	.owner          = THIS_MODULE,1969	.fb_setcolreg	= sh_mobile_lcdc_setcolreg,1970	__FB_DEFAULT_DMAMEM_OPS_RDWR,1971	.fb_fillrect	= sh_mobile_lcdc_fillrect,1972	.fb_copyarea	= sh_mobile_lcdc_copyarea,1973	.fb_imageblit	= sh_mobile_lcdc_imageblit,1974	.fb_blank	= sh_mobile_lcdc_blank,1975	.fb_pan_display = sh_mobile_lcdc_pan,1976	.fb_ioctl       = sh_mobile_lcdc_ioctl,1977	.fb_open	= sh_mobile_lcdc_open,1978	.fb_release	= sh_mobile_lcdc_release,1979	.fb_check_var	= sh_mobile_lcdc_check_var,1980	.fb_set_par	= sh_mobile_lcdc_set_par,1981	.fb_mmap	= sh_mobile_lcdc_mmap,1982};1983 1984static void1985sh_mobile_lcdc_channel_fb_unregister(struct sh_mobile_lcdc_chan *ch)1986{1987	if (ch->info && ch->info->dev)1988		unregister_framebuffer(ch->info);1989}1990 1991static int1992sh_mobile_lcdc_channel_fb_register(struct sh_mobile_lcdc_chan *ch)1993{1994	struct fb_info *info = ch->info;1995	int ret;1996 1997	if (info->fbdefio) {1998		ch->sglist = vmalloc(sizeof(struct scatterlist) *1999				     ch->fb_size >> PAGE_SHIFT);2000		if (!ch->sglist)2001			return -ENOMEM;2002	}2003 2004	info->bl_dev = ch->bl;2005 2006	ret = register_framebuffer(info);2007	if (ret < 0)2008		return ret;2009 2010	dev_info(ch->lcdc->dev, "registered %s/%s as %dx%d %dbpp.\n",2011		 dev_name(ch->lcdc->dev), (ch->cfg->chan == LCDC_CHAN_MAINLCD) ?2012		 "mainlcd" : "sublcd", info->var.xres, info->var.yres,2013		 info->var.bits_per_pixel);2014 2015	/* deferred io mode: disable clock to save power */2016	if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED)2017		sh_mobile_lcdc_clk_off(ch->lcdc);2018 2019	return ret;2020}2021 2022static void2023sh_mobile_lcdc_channel_fb_cleanup(struct sh_mobile_lcdc_chan *ch)2024{2025	struct fb_info *info = ch->info;2026 2027	if (!info || !info->device)2028		return;2029 2030	vfree(ch->sglist);2031 2032	fb_dealloc_cmap(&info->cmap);2033	framebuffer_release(info);2034}2035 2036static int2037sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch,2038			       const struct fb_videomode *modes,2039			       unsigned int num_modes)2040{2041	struct sh_mobile_lcdc_priv *priv = ch->lcdc;2042	struct fb_var_screeninfo *var;2043	struct fb_info *info;2044	int ret;2045 2046	/* Allocate and initialize the frame buffer device. Create the modes2047	 * list and allocate the color map.2048	 */2049	info = framebuffer_alloc(0, priv->dev);2050	if (!info)2051		return -ENOMEM;2052 2053	ch->info = info;2054 2055	info->fbops = &sh_mobile_lcdc_ops;2056	info->device = priv->dev;2057	info->flags |= FBINFO_VIRTFB;2058	info->screen_buffer = ch->fb_mem;2059	info->pseudo_palette = &ch->pseudo_palette;2060	info->par = ch;2061 2062	fb_videomode_to_modelist(modes, num_modes, &info->modelist);2063 2064	ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);2065	if (ret < 0) {2066		dev_err(priv->dev, "unable to allocate cmap\n");2067		return ret;2068	}2069 2070	/* Initialize fixed screen information. Restrict pan to 2 lines steps2071	 * for NV12 and NV21.2072	 */2073	info->fix = sh_mobile_lcdc_fix;2074	info->fix.smem_start = ch->dma_handle;2075	info->fix.smem_len = ch->fb_size;2076	info->fix.line_length = ch->pitch;2077 2078	if (ch->format->yuv)2079		info->fix.visual = FB_VISUAL_FOURCC;2080	else2081		info->fix.visual = FB_VISUAL_TRUECOLOR;2082 2083	switch (ch->format->fourcc) {2084	case V4L2_PIX_FMT_NV12:2085	case V4L2_PIX_FMT_NV21:2086		info->fix.ypanstep = 2;2087		fallthrough;2088	case V4L2_PIX_FMT_NV16:2089	case V4L2_PIX_FMT_NV61:2090		info->fix.xpanstep = 2;2091	}2092 2093	/* Initialize variable screen information using the first mode as2094	 * default.2095	 */2096	var = &info->var;2097	fb_videomode_to_var(var, modes);2098	var->width = ch->display.width;2099	var->height = ch->display.height;2100	var->xres_virtual = ch->xres_virtual;2101	var->yres_virtual = ch->yres_virtual;2102	var->activate = FB_ACTIVATE_NOW;2103 2104	/* Use the legacy API by default for RGB formats, and the FOURCC API2105	 * for YUV formats.2106	 */2107	if (!ch->format->yuv)2108		var->bits_per_pixel = ch->format->bpp;2109	else2110		var->grayscale = ch->format->fourcc;2111 2112	ret = sh_mobile_lcdc_check_var(var, info);2113	if (ret)2114		return ret;2115 2116	return 0;2117}2118 2119/* -----------------------------------------------------------------------------2120 * Backlight2121 */2122 2123static int sh_mobile_lcdc_update_bl(struct backlight_device *bdev)2124{2125	struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev);2126	int brightness = bdev->props.brightness;2127 2128	if (bdev->props.power != FB_BLANK_UNBLANK ||2129	    bdev->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))2130		brightness = 0;2131 2132	ch->bl_brightness = brightness;2133	return ch->cfg->bl_info.set_brightness(brightness);2134}2135 2136static int sh_mobile_lcdc_get_brightness(struct backlight_device *bdev)2137{2138	struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev);2139 2140	return ch->bl_brightness;2141}2142 2143static const struct backlight_ops sh_mobile_lcdc_bl_ops = {2144	.options	= BL_CORE_SUSPENDRESUME,2145	.update_status	= sh_mobile_lcdc_update_bl,2146	.get_brightness	= sh_mobile_lcdc_get_brightness,2147};2148 2149static struct backlight_device *sh_mobile_lcdc_bl_probe(struct device *parent,2150					       struct sh_mobile_lcdc_chan *ch)2151{2152	struct backlight_device *bl;2153 2154	bl = backlight_device_register(ch->cfg->bl_info.name, parent, ch,2155				       &sh_mobile_lcdc_bl_ops, NULL);2156	if (IS_ERR(bl)) {2157		dev_err(parent, "unable to register backlight device: %ld\n",2158			PTR_ERR(bl));2159		return NULL;2160	}2161 2162	bl->props.max_brightness = ch->cfg->bl_info.max_brightness;2163	bl->props.brightness = bl->props.max_brightness;2164	backlight_update_status(bl);2165 2166	return bl;2167}2168 2169static void sh_mobile_lcdc_bl_remove(struct backlight_device *bdev)2170{2171	backlight_device_unregister(bdev);2172}2173 2174/* -----------------------------------------------------------------------------2175 * Power management2176 */2177 2178static int sh_mobile_lcdc_suspend(struct device *dev)2179{2180	struct platform_device *pdev = to_platform_device(dev);2181 2182	sh_mobile_lcdc_stop(platform_get_drvdata(pdev));2183	return 0;2184}2185 2186static int sh_mobile_lcdc_resume(struct device *dev)2187{2188	struct platform_device *pdev = to_platform_device(dev);2189 2190	return sh_mobile_lcdc_start(platform_get_drvdata(pdev));2191}2192 2193static int sh_mobile_lcdc_runtime_suspend(struct device *dev)2194{2195	struct sh_mobile_lcdc_priv *priv = dev_get_drvdata(dev);2196 2197	/* turn off LCDC hardware */2198	lcdc_write(priv, _LDCNT1R, 0);2199 2200	return 0;2201}2202 2203static int sh_mobile_lcdc_runtime_resume(struct device *dev)2204{2205	struct sh_mobile_lcdc_priv *priv = dev_get_drvdata(dev);2206 2207	__sh_mobile_lcdc_start(priv);2208 2209	return 0;2210}2211 2212static const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = {2213	.suspend = sh_mobile_lcdc_suspend,2214	.resume = sh_mobile_lcdc_resume,2215	.runtime_suspend = sh_mobile_lcdc_runtime_suspend,2216	.runtime_resume = sh_mobile_lcdc_runtime_resume,2217};2218 2219/* -----------------------------------------------------------------------------2220 * Framebuffer notifier2221 */2222 2223/* -----------------------------------------------------------------------------2224 * Probe/remove and driver init/exit2225 */2226 2227static const struct fb_videomode default_720p = {2228	.name = "HDMI 720p",2229	.xres = 1280,2230	.yres = 720,2231 2232	.left_margin = 220,2233	.right_margin = 110,2234	.hsync_len = 40,2235 2236	.upper_margin = 20,2237	.lower_margin = 5,2238	.vsync_len = 5,2239 2240	.pixclock = 13468,2241	.refresh = 60,2242	.sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,2243};2244 2245static void sh_mobile_lcdc_remove(struct platform_device *pdev)2246{2247	struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);2248	unsigned int i;2249 2250	for (i = 0; i < ARRAY_SIZE(priv->overlays); i++)2251		sh_mobile_lcdc_overlay_fb_unregister(&priv->overlays[i]);2252	for (i = 0; i < ARRAY_SIZE(priv->ch); i++)2253		sh_mobile_lcdc_channel_fb_unregister(&priv->ch[i]);2254 2255	sh_mobile_lcdc_stop(priv);2256 2257	for (i = 0; i < ARRAY_SIZE(priv->overlays); i++) {2258		struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i];2259 2260		sh_mobile_lcdc_overlay_fb_cleanup(ovl);2261 2262		if (ovl->fb_mem)2263			dma_free_coherent(&pdev->dev, ovl->fb_size,2264					  ovl->fb_mem, ovl->dma_handle);2265	}2266 2267	for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {2268		struct sh_mobile_lcdc_chan *ch = &priv->ch[i];2269 2270		if (ch->tx_dev) {2271			ch->tx_dev->lcdc = NULL;2272			module_put(ch->cfg->tx_dev->dev.driver->owner);2273		}2274 2275		sh_mobile_lcdc_channel_fb_cleanup(ch);2276 2277		if (ch->fb_mem)2278			dma_free_coherent(&pdev->dev, ch->fb_size,2279					  ch->fb_mem, ch->dma_handle);2280	}2281 2282	for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {2283		struct sh_mobile_lcdc_chan *ch = &priv->ch[i];2284 2285		if (ch->bl)2286			sh_mobile_lcdc_bl_remove(ch->bl);2287		mutex_destroy(&ch->open_lock);2288	}2289 2290	if (priv->dot_clk) {2291		pm_runtime_disable(&pdev->dev);2292		clk_put(priv->dot_clk);2293	}2294 2295	if (priv->base)2296		iounmap(priv->base);2297 2298	if (priv->irq)2299		free_irq(priv->irq, priv);2300	kfree(priv);2301}2302 2303static int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)2304{2305	int interface_type = ch->cfg->interface_type;2306 2307	switch (interface_type) {2308	case RGB8:2309	case RGB9:2310	case RGB12A:2311	case RGB12B:2312	case RGB16:2313	case RGB18:2314	case RGB24:2315	case SYS8A:2316	case SYS8B:2317	case SYS8C:2318	case SYS8D:2319	case SYS9:2320	case SYS12:2321	case SYS16A:2322	case SYS16B:2323	case SYS16C:2324	case SYS18:2325	case SYS24:2326		break;2327	default:2328		return -EINVAL;2329	}2330 2331	/* SUBLCD only supports SYS interface */2332	if (lcdc_chan_is_sublcd(ch)) {2333		if (!(interface_type & LDMT1R_IFM))2334			return -EINVAL;2335 2336		interface_type &= ~LDMT1R_IFM;2337	}2338 2339	ch->ldmt1r_value = interface_type;2340	return 0;2341}2342 2343static int2344sh_mobile_lcdc_overlay_init(struct sh_mobile_lcdc_overlay *ovl)2345{2346	const struct sh_mobile_lcdc_format_info *format;2347	struct device *dev = ovl->channel->lcdc->dev;2348	int ret;2349 2350	if (ovl->cfg->fourcc == 0)2351		return 0;2352 2353	/* Validate the format. */2354	format = sh_mobile_format_info(ovl->cfg->fourcc);2355	if (format == NULL) {2356		dev_err(dev, "Invalid FOURCC %08x\n", ovl->cfg->fourcc);2357		return -EINVAL;2358	}2359 2360	ovl->enabled = false;2361	ovl->mode = LCDC_OVERLAY_BLEND;2362	ovl->alpha = 255;2363	ovl->rop3 = 0;2364	ovl->pos_x = 0;2365	ovl->pos_y = 0;2366 2367	/* The default Y virtual resolution is twice the panel size to allow for2368	 * double-buffering.2369	 */2370	ovl->format = format;2371	ovl->xres = ovl->cfg->max_xres;2372	ovl->xres_virtual = ovl->xres;2373	ovl->yres = ovl->cfg->max_yres;2374	ovl->yres_virtual = ovl->yres * 2;2375 2376	if (!format->yuv)2377		ovl->pitch = ovl->xres_virtual * format->bpp / 8;2378	else2379		ovl->pitch = ovl->xres_virtual;2380 2381	/* Allocate frame buffer memory. */2382	ovl->fb_size = ovl->cfg->max_xres * ovl->cfg->max_yres2383		       * format->bpp / 8 * 2;2384	ovl->fb_mem = dma_alloc_coherent(dev, ovl->fb_size, &ovl->dma_handle,2385					 GFP_KERNEL);2386	if (!ovl->fb_mem) {2387		dev_err(dev, "unable to allocate buffer\n");2388		return -ENOMEM;2389	}2390 2391	ret = sh_mobile_lcdc_overlay_fb_init(ovl);2392	if (ret < 0)2393		return ret;2394 2395	return 0;2396}2397 2398static int2399sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch)2400{2401	const struct sh_mobile_lcdc_format_info *format;2402	const struct sh_mobile_lcdc_chan_cfg *cfg = ch->cfg;2403	struct device *dev = ch->lcdc->dev;2404	const struct fb_videomode *max_mode;2405	const struct fb_videomode *mode;2406	unsigned int num_modes;2407	unsigned int max_size;2408	unsigned int i;2409 2410	/* Validate the format. */2411	format = sh_mobile_format_info(cfg->fourcc);2412	if (format == NULL) {2413		dev_err(dev, "Invalid FOURCC %08x.\n", cfg->fourcc);2414		return -EINVAL;2415	}2416 2417	/* Iterate through the modes to validate them and find the highest2418	 * resolution.2419	 */2420	max_mode = NULL;2421	max_size = 0;2422 2423	for (i = 0, mode = cfg->lcd_modes; i < cfg->num_modes; i++, mode++) {2424		unsigned int size = mode->yres * mode->xres;2425 2426		/* NV12/NV21 buffers must have even number of lines */2427		if ((cfg->fourcc == V4L2_PIX_FMT_NV12 ||2428		     cfg->fourcc == V4L2_PIX_FMT_NV21) && (mode->yres & 0x1)) {2429			dev_err(dev, "yres must be multiple of 2 for "2430				"YCbCr420 mode.\n");2431			return -EINVAL;2432		}2433 2434		if (size > max_size) {2435			max_mode = mode;2436			max_size = size;2437		}2438	}2439 2440	if (!max_size)2441		max_size = MAX_XRES * MAX_YRES;2442	else2443		dev_dbg(dev, "Found largest videomode %ux%u\n",2444			max_mode->xres, max_mode->yres);2445 2446	if (cfg->lcd_modes == NULL) {2447		mode = &default_720p;2448		num_modes = 1;2449	} else {2450		mode = cfg->lcd_modes;2451		num_modes = cfg->num_modes;2452	}2453 2454	/* Use the first mode as default. The default Y virtual resolution is2455	 * twice the panel size to allow for double-buffering.2456	 */2457	ch->format = format;2458	ch->xres = mode->xres;2459	ch->xres_virtual = mode->xres;2460	ch->yres = mode->yres;2461	ch->yres_virtual = mode->yres * 2;2462 2463	if (!format->yuv) {2464		ch->colorspace = V4L2_COLORSPACE_SRGB;2465		ch->pitch = ch->xres_virtual * format->bpp / 8;2466	} else {2467		ch->colorspace = V4L2_COLORSPACE_REC709;2468		ch->pitch = ch->xres_virtual;2469	}2470 2471	ch->display.width = cfg->panel_cfg.width;2472	ch->display.height = cfg->panel_cfg.height;2473	ch->display.mode = *mode;2474 2475	/* Allocate frame buffer memory. */2476	ch->fb_size = max_size * format->bpp / 8 * 2;2477	ch->fb_mem = dma_alloc_coherent(dev, ch->fb_size, &ch->dma_handle,2478					GFP_KERNEL);2479	if (ch->fb_mem == NULL) {2480		dev_err(dev, "unable to allocate buffer\n");2481		return -ENOMEM;2482	}2483 2484	/* Initialize the transmitter device if present. */2485	if (cfg->tx_dev) {2486		if (!cfg->tx_dev->dev.driver ||2487		    !try_module_get(cfg->tx_dev->dev.driver->owner)) {2488			dev_warn(dev, "unable to get transmitter device\n");2489			return -EINVAL;2490		}2491		ch->tx_dev = platform_get_drvdata(cfg->tx_dev);2492		ch->tx_dev->lcdc = ch;2493		ch->tx_dev->def_mode = *mode;2494	}2495 2496	return sh_mobile_lcdc_channel_fb_init(ch, mode, num_modes);2497}2498 2499static int sh_mobile_lcdc_probe(struct platform_device *pdev)2500{2501	struct sh_mobile_lcdc_info *pdata = pdev->dev.platform_data;2502	struct sh_mobile_lcdc_priv *priv;2503	struct resource *res;2504	int num_channels;2505	int error;2506	int irq, i;2507 2508	if (!pdata) {2509		dev_err(&pdev->dev, "no platform data defined\n");2510		return -EINVAL;2511	}2512 2513	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);2514	irq = platform_get_irq(pdev, 0);2515	if (!res || irq < 0) {2516		dev_err(&pdev->dev, "cannot get platform resources\n");2517		return -ENOENT;2518	}2519 2520	priv = kzalloc(sizeof(*priv), GFP_KERNEL);2521	if (!priv)2522		return -ENOMEM;2523 2524	priv->dev = &pdev->dev;2525 2526	for (i = 0; i < ARRAY_SIZE(priv->ch); i++)2527		mutex_init(&priv->ch[i].open_lock);2528	platform_set_drvdata(pdev, priv);2529 2530	error = request_irq(irq, sh_mobile_lcdc_irq, 0,2531			    dev_name(&pdev->dev), priv);2532	if (error) {2533		dev_err(&pdev->dev, "unable to request irq\n");2534		goto err1;2535	}2536 2537	priv->irq = irq;2538	atomic_set(&priv->hw_usecnt, -1);2539 2540	for (i = 0, num_channels = 0; i < ARRAY_SIZE(pdata->ch); i++) {2541		struct sh_mobile_lcdc_chan *ch = priv->ch + num_channels;2542 2543		ch->lcdc = priv;2544		ch->cfg = &pdata->ch[i];2545 2546		error = sh_mobile_lcdc_check_interface(ch);2547		if (error) {2548			dev_err(&pdev->dev, "unsupported interface type\n");2549			goto err1;2550		}2551		init_waitqueue_head(&ch->frame_end_wait);2552		init_completion(&ch->vsync_completion);2553 2554		/* probe the backlight is there is one defined */2555		if (ch->cfg->bl_info.max_brightness)2556			ch->bl = sh_mobile_lcdc_bl_probe(&pdev->dev, ch);2557 2558		switch (pdata->ch[i].chan) {2559		case LCDC_CHAN_MAINLCD:2560			ch->enabled = LDCNT2R_ME;2561			ch->reg_offs = lcdc_offs_mainlcd;2562			num_channels++;2563			break;2564		case LCDC_CHAN_SUBLCD:2565			ch->enabled = LDCNT2R_SE;2566			ch->reg_offs = lcdc_offs_sublcd;2567			num_channels++;2568			break;2569		}2570	}2571 2572	if (!num_channels) {2573		dev_err(&pdev->dev, "no channels defined\n");2574		error = -EINVAL;2575		goto err1;2576	}2577 2578	/* for dual channel LCDC (MAIN + SUB) force shared format setting */2579	if (num_channels == 2)2580		priv->forced_fourcc = pdata->ch[0].fourcc;2581 2582	priv->base = ioremap(res->start, resource_size(res));2583	if (!priv->base) {2584		error = -ENOMEM;2585		goto err1;2586	}2587 2588	error = sh_mobile_lcdc_setup_clocks(priv, pdata->clock_source);2589	if (error) {2590		dev_err(&pdev->dev, "unable to setup clocks\n");2591		goto err1;2592	}2593 2594	/* Enable runtime PM. */2595	pm_runtime_enable(&pdev->dev);2596 2597	for (i = 0; i < num_channels; i++) {2598		struct sh_mobile_lcdc_chan *ch = &priv->ch[i];2599 2600		error = sh_mobile_lcdc_channel_init(ch);2601		if (error)2602			goto err1;2603	}2604 2605	for (i = 0; i < ARRAY_SIZE(pdata->overlays); i++) {2606		struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i];2607 2608		ovl->cfg = &pdata->overlays[i];2609		ovl->channel = &priv->ch[0];2610 2611		error = sh_mobile_lcdc_overlay_init(ovl);2612		if (error)2613			goto err1;2614	}2615 2616	error = sh_mobile_lcdc_start(priv);2617	if (error) {2618		dev_err(&pdev->dev, "unable to start hardware\n");2619		goto err1;2620	}2621 2622	for (i = 0; i < num_channels; i++) {2623		struct sh_mobile_lcdc_chan *ch = priv->ch + i;2624 2625		error = sh_mobile_lcdc_channel_fb_register(ch);2626		if (error)2627			goto err1;2628	}2629 2630	for (i = 0; i < ARRAY_SIZE(pdata->overlays); i++) {2631		struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i];2632 2633		error = sh_mobile_lcdc_overlay_fb_register(ovl);2634		if (error)2635			goto err1;2636	}2637 2638	return 0;2639err1:2640	sh_mobile_lcdc_remove(pdev);2641 2642	return error;2643}2644 2645static struct platform_driver sh_mobile_lcdc_driver = {2646	.driver		= {2647		.name		= "sh_mobile_lcdc_fb",2648		.pm		= &sh_mobile_lcdc_dev_pm_ops,2649	},2650	.probe		= sh_mobile_lcdc_probe,2651	.remove		= sh_mobile_lcdc_remove,2652};2653 2654module_platform_driver(sh_mobile_lcdc_driver);2655 2656MODULE_DESCRIPTION("SuperH Mobile LCDC Framebuffer driver");2657MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");2658MODULE_LICENSE("GPL v2");2659