sh_mobile_lcdcfb.c revision 505c7de51fe5ebb81fac096cb8cebd7cb45b7955
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 11cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#include <linux/kernel.h> 12cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#include <linux/init.h> 13cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#include <linux/delay.h> 14cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#include <linux/mm.h> 15cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#include <linux/clk.h> 160246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm#include <linux/pm_runtime.h> 17cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#include <linux/platform_device.h> 18cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#include <linux/dma-mapping.h> 198564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm#include <linux/interrupt.h> 201c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt#include <linux/vmalloc.h> 2140331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy#include <linux/ioctl.h> 225a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 23dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski#include <linux/console.h> 243b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot#include <linux/backlight.h> 253b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot#include <linux/gpio.h> 26225c9a8d1da274bf23efec43ec28b1c9e45e12f8Paul Mundt#include <video/sh_mobile_lcdc.h> 2760063497a95e716c9a689af3be2687d261f115b4Arun Sharma#include <linux/atomic.h> 28cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 296de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski#include "sh_mobile_lcdcfb.h" 307caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia#include "sh_mobile_meram.h" 316de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski 32a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy#define SIDE_B_OFFSET 0x1000 33a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy#define MIRROR_OFFSET 0x2000 34cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 350246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm/* shared registers and their order for context save/restore */ 360246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic int lcdc_shared_regs[] = { 370246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm _LDDCKR, 380246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm _LDDCKSTPR, 390246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm _LDINTR, 400246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm _LDDDSR, 410246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm _LDCNT1R, 420246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm _LDCNT2R, 430246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm}; 440246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm#define NR_SHARED_REGS ARRAY_SIZE(lcdc_shared_regs) 450246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 46d2ecbab5960d9814a269d36723647d6ef391ba8fGuennadi Liakhovetski#define MAX_XRES 1920 47d2ecbab5960d9814a269d36723647d6ef391ba8fGuennadi Liakhovetski#define MAX_YRES 1080 48cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 490246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = { 50cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDDCKPAT1R] = 0x400, 51cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDDCKPAT2R] = 0x404, 52cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMT1R] = 0x418, 53cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMT2R] = 0x41c, 54cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMT3R] = 0x420, 55cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDDFR] = 0x424, 56cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDSM1R] = 0x428, 578564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm [LDSM2R] = 0x42c, 58cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDSA1R] = 0x430, 5953b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia [LDSA2R] = 0x434, 60cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMLSR] = 0x438, 61cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDHCNR] = 0x448, 62cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDHSYNR] = 0x44c, 63cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDVLNR] = 0x450, 64cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDVSYNR] = 0x454, 65cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDPMR] = 0x460, 666011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski [LDHAJR] = 0x4a0, 67cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 68cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 690246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic unsigned long lcdc_offs_sublcd[NR_CH_REGS] = { 70cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDDCKPAT1R] = 0x408, 71cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDDCKPAT2R] = 0x40c, 72cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMT1R] = 0x600, 73cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMT2R] = 0x604, 74cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMT3R] = 0x608, 75cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDDFR] = 0x60c, 76cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDSM1R] = 0x610, 778564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm [LDSM2R] = 0x614, 78cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDSA1R] = 0x618, 79cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMLSR] = 0x620, 80cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDHCNR] = 0x624, 81cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDHSYNR] = 0x628, 82cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDVLNR] = 0x62c, 83cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDVSYNR] = 0x630, 84cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDPMR] = 0x63c, 85cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 86cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 87c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetskistatic const struct fb_videomode default_720p = { 88c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski .name = "HDMI 720p", 89c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski .xres = 1280, 90c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski .yres = 720, 91c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski 925ae0cf82df212253857326a6706018eccb658683Guennadi Liakhovetski .left_margin = 220, 935ae0cf82df212253857326a6706018eccb658683Guennadi Liakhovetski .right_margin = 110, 945ae0cf82df212253857326a6706018eccb658683Guennadi Liakhovetski .hsync_len = 40, 95c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski 96c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski .upper_margin = 20, 97c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski .lower_margin = 5, 98c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski .vsync_len = 5, 99c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski 100c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski .pixclock = 13468, 1015ae0cf82df212253857326a6706018eccb658683Guennadi Liakhovetski .refresh = 60, 102c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT, 1030246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm}; 1040246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 1050246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstruct sh_mobile_lcdc_priv { 1060246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm void __iomem *base; 1070246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm int irq; 1080246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm atomic_t hw_usecnt; 1090246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct device *dev; 1100246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct clk *dot_clk; 1110246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm unsigned long lddckr; 1120246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct sh_mobile_lcdc_chan ch[2]; 1136011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski struct notifier_block notifier; 1140246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm unsigned long saved_shared_regs[NR_SHARED_REGS]; 1150246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm int started; 116417d48274e755e537bae60461558c1f63a4e14deMagnus Damm int forced_bpp; /* 2 channel LCDC must share bpp setting */ 1177caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia struct sh_mobile_meram_info *meram_dev; 1180246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm}; 1190246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 120a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthystatic bool banked(int reg_nr) 121a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy{ 122a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy switch (reg_nr) { 123a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDMT1R: 124a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDMT2R: 125a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDMT3R: 126a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDDFR: 127a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDSM1R: 128a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDSA1R: 12953b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia case LDSA2R: 130a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDMLSR: 131a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDHCNR: 132a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDHSYNR: 133a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDVLNR: 134a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDVSYNR: 135a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy return true; 136a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy } 137a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy return false; 138a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy} 139a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy 140cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_write_chan(struct sh_mobile_lcdc_chan *chan, 141cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int reg_nr, unsigned long data) 142cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 143cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr]); 144a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy if (banked(reg_nr)) 145a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr] + 146a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy SIDE_B_OFFSET); 147a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy} 148a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy 149a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthystatic void lcdc_write_chan_mirror(struct sh_mobile_lcdc_chan *chan, 150a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy int reg_nr, unsigned long data) 151a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy{ 152a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr] + 153a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy MIRROR_OFFSET); 154cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 155cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 156cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic unsigned long lcdc_read_chan(struct sh_mobile_lcdc_chan *chan, 157cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int reg_nr) 158cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 159cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return ioread32(chan->lcdc->base + chan->reg_offs[reg_nr]); 160cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 161cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 162cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_write(struct sh_mobile_lcdc_priv *priv, 163cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long reg_offs, unsigned long data) 164cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 165cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm iowrite32(data, priv->base + reg_offs); 166cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 167cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 168cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic unsigned long lcdc_read(struct sh_mobile_lcdc_priv *priv, 169cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long reg_offs) 170cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 171cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return ioread32(priv->base + reg_offs); 172cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 173cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 174cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_wait_bit(struct sh_mobile_lcdc_priv *priv, 175cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long reg_offs, 176cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long mask, unsigned long until) 177cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 178cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm while ((lcdc_read(priv, reg_offs) & mask) != until) 179cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm cpu_relax(); 180cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 181cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 182cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int lcdc_chan_is_sublcd(struct sh_mobile_lcdc_chan *chan) 183cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 184cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return chan->cfg.chan == LCDC_CHAN_SUBLCD; 185cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 186cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 187cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_sys_write_index(void *handle, unsigned long data) 188cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 189cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_chan *ch = handle; 190cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 191ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart lcdc_write(ch->lcdc, _LDDWD0R, data | LDDWDxR_WDACT); 192ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0); 193ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart lcdc_write(ch->lcdc, _LDDWAR, LDDWAR_WA | 194ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart (lcdc_chan_is_sublcd(ch) ? 2 : 0)); 195ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0); 196cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 197cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 198cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_sys_write_data(void *handle, unsigned long data) 199cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 200cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_chan *ch = handle; 201cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 202ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart lcdc_write(ch->lcdc, _LDDWD0R, data | LDDWDxR_WDACT | LDDWDxR_RSW); 203ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0); 204ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart lcdc_write(ch->lcdc, _LDDWAR, LDDWAR_WA | 205ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart (lcdc_chan_is_sublcd(ch) ? 2 : 0)); 206ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0); 207cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 208cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 209cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic unsigned long lcdc_sys_read_data(void *handle) 210cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 211cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_chan *ch = handle; 212cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 213ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart lcdc_write(ch->lcdc, _LDDRDR, LDDRDR_RSR); 214ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0); 215ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart lcdc_write(ch->lcdc, _LDDRAR, LDDRAR_RA | 216ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart (lcdc_chan_is_sublcd(ch) ? 2 : 0)); 217cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm udelay(1); 218ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0); 219cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 220ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart return lcdc_read(ch->lcdc, _LDDRDR) & LDDRDR_DRD_MASK; 221cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 222cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 223cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstruct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = { 224cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_sys_write_index, 225cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_sys_write_data, 226cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_sys_read_data, 227cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 228cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 2298564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) 2308564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 2310246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm if (atomic_inc_and_test(&priv->hw_usecnt)) { 2328564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (priv->dot_clk) 2338564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm clk_enable(priv->dot_clk); 234f1ad90da5c0fcb8841cc5e6d66c56f4005d8c960Laurent Pinchart pm_runtime_get_sync(priv->dev); 235ec19b9e0fa808d82ad996d73358a5b06a565b78bDamian Hobson-Garcia if (priv->meram_dev && priv->meram_dev->pdev) 236ec19b9e0fa808d82ad996d73358a5b06a565b78bDamian Hobson-Garcia pm_runtime_get_sync(&priv->meram_dev->pdev->dev); 2378564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm } 2388564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 2398564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 2408564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv) 2418564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 2420246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm if (atomic_sub_return(1, &priv->hw_usecnt) == -1) { 243ec19b9e0fa808d82ad996d73358a5b06a565b78bDamian Hobson-Garcia if (priv->meram_dev && priv->meram_dev->pdev) 244ec19b9e0fa808d82ad996d73358a5b06a565b78bDamian Hobson-Garcia pm_runtime_put_sync(&priv->meram_dev->pdev->dev); 2450246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm pm_runtime_put(priv->dev); 246f1ad90da5c0fcb8841cc5e6d66c56f4005d8c960Laurent Pinchart if (priv->dot_clk) 247f1ad90da5c0fcb8841cc5e6d66c56f4005d8c960Laurent Pinchart clk_disable(priv->dot_clk); 2488564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm } 2498564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 2508564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 2511c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundtstatic int sh_mobile_lcdc_sginit(struct fb_info *info, 2521c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt struct list_head *pagelist) 2531c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt{ 2541c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt struct sh_mobile_lcdc_chan *ch = info->par; 2551c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt unsigned int nr_pages_max = info->fix.smem_len >> PAGE_SHIFT; 2561c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt struct page *page; 2571c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt int nr_pages = 0; 2581c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt 2591c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt sg_init_table(ch->sglist, nr_pages_max); 2601c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt 2611c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt list_for_each_entry(page, pagelist, lru) 2621c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt sg_set_page(&ch->sglist[nr_pages++], page, PAGE_SIZE, 0); 2631c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt 2641c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt return nr_pages; 2651c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt} 2661c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt 2678564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_deferred_io(struct fb_info *info, 2688564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm struct list_head *pagelist) 2698564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 2708564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm struct sh_mobile_lcdc_chan *ch = info->par; 271ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm struct sh_mobile_lcdc_board_cfg *bcfg = &ch->cfg.board_cfg; 2728564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 2738564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* enable clocks before accessing hardware */ 2748564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_clk_on(ch->lcdc); 2758564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 2765c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt /* 2775c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * It's possible to get here without anything on the pagelist via 2785c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * sh_mobile_lcdc_deferred_io_touch() or via a userspace fsync() 2795c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * invocation. In the former case, the acceleration routines are 2805c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * stepped in to when using the framebuffer console causing the 2815c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * workqueue to be scheduled without any dirty pages on the list. 2825c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * 2835c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * Despite this, a panel update is still needed given that the 2845c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * acceleration routines have their own methods for writing in 2855c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * that still need to be updated. 2865c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * 2875c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * The fsync() and empty pagelist case could be optimized for, 2885c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * but we don't bother, as any application exhibiting such 2895c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * behaviour is fundamentally broken anyways. 2905c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt */ 2915c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt if (!list_empty(pagelist)) { 2925c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt unsigned int nr_pages = sh_mobile_lcdc_sginit(info, pagelist); 2935c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt 2945c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt /* trigger panel update */ 2955c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt dma_map_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE); 296ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm if (bcfg->start_transfer) 297ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm bcfg->start_transfer(bcfg->board_data, ch, 298ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm &sh_mobile_lcdc_sys_bus_ops); 299ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG); 3005c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt dma_unmap_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE); 301ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm } else { 302ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm if (bcfg->start_transfer) 303ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm bcfg->start_transfer(bcfg->board_data, ch, 304ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm &sh_mobile_lcdc_sys_bus_ops); 305ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG); 306ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm } 3078564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 3088564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 3098564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info) 3108564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 3118564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm struct fb_deferred_io *fbdefio = info->fbdefio; 3128564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 3138564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (fbdefio) 3148564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm schedule_delayed_work(&info->deferred_work, fbdefio->delay); 3158564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 3168564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 3178564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic irqreturn_t sh_mobile_lcdc_irq(int irq, void *data) 3188564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 3198564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm struct sh_mobile_lcdc_priv *priv = data; 3202feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm struct sh_mobile_lcdc_chan *ch; 3219dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy unsigned long ldintr; 3222feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm int is_sub; 3232feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm int k; 3248564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 325dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart /* Acknowledge interrupts and disable further VSYNC End IRQs. */ 326dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart ldintr = lcdc_read(priv, _LDINTR); 327dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart lcdc_write(priv, _LDINTR, (ldintr ^ LDINTR_STATUS_MASK) & ~LDINTR_VEE); 3288564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 3292feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm /* figure out if this interrupt is for main or sub lcd */ 330ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart is_sub = (lcdc_read(priv, _LDSR) & LDSR_MSS) ? 1 : 0; 3312feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 3329dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy /* wake up channel and disable clocks */ 3332feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 3342feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm ch = &priv->ch[k]; 3352feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 3362feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm if (!ch->enabled) 3372feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm continue; 3382feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 339dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart /* Frame End */ 3409dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy if (ldintr & LDINTR_FS) { 3419dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy if (is_sub == lcdc_chan_is_sublcd(ch)) { 3429dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy ch->frame_end = 1; 3439dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy wake_up(&ch->frame_end_wait); 3442feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 3459dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy sh_mobile_lcdc_clk_off(priv); 3469dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy } 3479dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy } 3489dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy 3499dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy /* VSYNC End */ 35040331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy if (ldintr & LDINTR_VES) 35140331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy complete(&ch->vsync_completion); 3522feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm } 3532feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 3548564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm return IRQ_HANDLED; 3558564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 3568564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 357cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv, 358cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int start) 359cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 360cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long tmp = lcdc_read(priv, _LDCNT2R); 361cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int k; 362cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 363cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* start or stop the lcdc */ 364cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (start) 365ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart lcdc_write(priv, _LDCNT2R, tmp | LDCNT2R_DO); 366cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm else 367ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart lcdc_write(priv, _LDCNT2R, tmp & ~LDCNT2R_DO); 368cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 369cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* wait until power is applied/stopped on all channels */ 370cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) 371cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (lcdc_read(priv, _LDCNT2R) & priv->ch[k].enabled) 372cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm while (1) { 373ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart tmp = lcdc_read_chan(&priv->ch[k], LDPMR) 374ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart & LDPMR_LPS; 375ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart if (start && tmp == LDPMR_LPS) 376cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 377cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!start && tmp == 0) 378cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 379cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm cpu_relax(); 380cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 381cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 382cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!start) 383cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDDCKSTPR, 1); /* stop dotclock */ 384cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 385cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 3866011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetskistatic void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) 3876011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski{ 3881c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski struct fb_var_screeninfo *var = &ch->info->var, *display_var = &ch->display_var; 3891c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski unsigned long h_total, hsync_pos, display_h_total; 3906011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski u32 tmp; 3916011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 3926011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp = ch->ldmt1r_value; 393ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart tmp |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : LDMT1R_VPOL; 394ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart tmp |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : LDMT1R_HPOL; 395ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart tmp |= (ch->cfg.flags & LCDC_FLAGS_DWPOL) ? LDMT1R_DWPOL : 0; 396ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart tmp |= (ch->cfg.flags & LCDC_FLAGS_DIPOL) ? LDMT1R_DIPOL : 0; 397ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart tmp |= (ch->cfg.flags & LCDC_FLAGS_DAPOL) ? LDMT1R_DAPOL : 0; 398ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart tmp |= (ch->cfg.flags & LCDC_FLAGS_HSCNT) ? LDMT1R_HSCNT : 0; 399ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart tmp |= (ch->cfg.flags & LCDC_FLAGS_DWCNT) ? LDMT1R_DWCNT : 0; 4006011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDMT1R, tmp); 4016011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 4026011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski /* setup SYS bus */ 4036011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDMT2R, ch->cfg.sys_bus_cfg.ldmt2r); 4046011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDMT3R, ch->cfg.sys_bus_cfg.ldmt3r); 4056011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 4066011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski /* horizontal configuration */ 4071c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski h_total = display_var->xres + display_var->hsync_len + 4081c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski display_var->left_margin + display_var->right_margin; 4096011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp = h_total / 8; /* HTCN */ 4101c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski tmp |= (min(display_var->xres, var->xres) / 8) << 16; /* HDCN */ 4116011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDHCNR, tmp); 4126011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 4131c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski hsync_pos = display_var->xres + display_var->right_margin; 4146011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp = hsync_pos / 8; /* HSYNP */ 4151c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski tmp |= (display_var->hsync_len / 8) << 16; /* HSYNW */ 4166011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDHSYNR, tmp); 4176011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 4186011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski /* vertical configuration */ 4191c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski tmp = display_var->yres + display_var->vsync_len + 4201c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski display_var->upper_margin + display_var->lower_margin; /* VTLN */ 4211c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski tmp |= min(display_var->yres, var->yres) << 16; /* VDLN */ 4226011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDVLNR, tmp); 4236011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 4241c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski tmp = display_var->yres + display_var->lower_margin; /* VSYNP */ 4251c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski tmp |= display_var->vsync_len << 16; /* VSYNW */ 4266011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDVSYNR, tmp); 4276011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 4286011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski /* Adjust horizontal synchronisation for HDMI */ 4291c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski display_h_total = display_var->xres + display_var->hsync_len + 4301c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski display_var->left_margin + display_var->right_margin; 4311c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski tmp = ((display_var->xres & 7) << 24) | 4321c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski ((display_h_total & 7) << 16) | 4331c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski ((display_var->hsync_len & 7) << 8) | 4346011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski hsync_pos; 4356011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDHAJR, tmp); 4366011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski} 4376011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 438cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) 439cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 440cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_chan *ch; 441cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_board_cfg *board_cfg; 442cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long tmp; 443417d48274e755e537bae60461558c1f63a4e14deMagnus Damm int bpp = 0; 44453b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia unsigned long ldddsr; 445554cc1028603587e28ae49e9594b1508df5f29aaPaul Mundt int k, m, ret; 446cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 4478564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* enable clocks before accessing the hardware */ 448417d48274e755e537bae60461558c1f63a4e14deMagnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 449417d48274e755e537bae60461558c1f63a4e14deMagnus Damm if (priv->ch[k].enabled) { 4508564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_clk_on(priv); 451417d48274e755e537bae60461558c1f63a4e14deMagnus Damm if (!bpp) 452417d48274e755e537bae60461558c1f63a4e14deMagnus Damm bpp = priv->ch[k].info->var.bits_per_pixel; 453417d48274e755e537bae60461558c1f63a4e14deMagnus Damm } 454417d48274e755e537bae60461558c1f63a4e14deMagnus Damm } 4558564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 456cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* reset */ 457ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LDCNT2R_BR); 458ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart lcdc_wait_bit(priv, _LDCNT2R, LDCNT2R_BR, 0); 459cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 460cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* enable LCDC channels */ 461cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp = lcdc_read(priv, _LDCNT2R); 462cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp |= priv->ch[0].enabled; 463cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp |= priv->ch[1].enabled; 464cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDCNT2R, tmp); 465cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 466cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* read data from external memory, avoid using the BEU for now */ 467ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) & ~LDCNT2R_MD); 468cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 469cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* stop the lcdc first */ 470cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm sh_mobile_lcdc_start_stop(priv, 0); 471cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 472cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* configure clocks */ 473cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp = priv->lddckr; 474cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 475cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ch = &priv->ch[k]; 476cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 477cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!priv->ch[k].enabled) 478cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm continue; 479cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 480cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm m = ch->cfg.clock_divider; 481cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!m) 482cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm continue; 483cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 484505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart /* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider 485505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart * denominator. 486505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart */ 487505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart lcdc_write_chan(ch, LDDCKPAT1R, 0); 488505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1); 489505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart 490cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (m == 1) 491ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart m = LDDCKR_MOSEL; 492cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0); 493cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 494cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 495cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDDCKR, tmp); 496cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 497cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* start dotclock again */ 498cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDDCKSTPR, 0); 499cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0); 500cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 5018564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* interrupts are disabled to begin with */ 502cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDINTR, 0); 503cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 504cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 505cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ch = &priv->ch[k]; 506cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 507cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!ch->enabled) 508cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm continue; 509cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 5106011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski sh_mobile_lcdc_geometry(ch); 511cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 512cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* power supply */ 513cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write_chan(ch, LDPMR, 0); 514cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 515cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm board_cfg = &ch->cfg.board_cfg; 51669843ba7f24950f8ef5dadacfbfbd08f53e3455bGuennadi Liakhovetski if (board_cfg->setup_sys) { 517554cc1028603587e28ae49e9594b1508df5f29aaPaul Mundt ret = board_cfg->setup_sys(board_cfg->board_data, 51869843ba7f24950f8ef5dadacfbfbd08f53e3455bGuennadi Liakhovetski ch, &sh_mobile_lcdc_sys_bus_ops); 51969843ba7f24950f8ef5dadacfbfbd08f53e3455bGuennadi Liakhovetski if (ret) 52069843ba7f24950f8ef5dadacfbfbd08f53e3455bGuennadi Liakhovetski return ret; 52169843ba7f24950f8ef5dadacfbfbd08f53e3455bGuennadi Liakhovetski } 522cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 523cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 524cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* word and long word swap */ 52553b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia ldddsr = lcdc_read(priv, _LDDDSR); 52653b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia if (priv->ch[0].info->var.nonstd) 527ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart ldddsr |= LDDDSR_LS | LDDDSR_WS | LDDDSR_BS; 52853b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia else { 52953b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia switch (bpp) { 53053b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia case 16: 531ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart ldddsr |= LDDDSR_LS | LDDDSR_WS; 53253b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia break; 53353b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia case 24: 534ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart ldddsr |= LDDDSR_LS | LDDDSR_WS | LDDDSR_BS; 53553b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia break; 53653b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia case 32: 537ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart ldddsr |= LDDDSR_LS; 53853b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia break; 53953b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia } 540417d48274e755e537bae60461558c1f63a4e14deMagnus Damm } 541ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart lcdc_write(priv, _LDDDSR, ldddsr); 542cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 543cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 5447caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia unsigned long base_addr_y; 5457caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia unsigned long base_addr_c = 0; 5467caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia int pitch; 547cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ch = &priv->ch[k]; 548cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 549cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!priv->ch[k].enabled) 550cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm continue; 551cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 552cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* set bpp format in PKF[4:0] */ 553cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp = lcdc_read_chan(ch, LDDFR); 554ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart tmp &= ~(LDDFR_CF0 | LDDFR_CC | LDDFR_YF_MASK | LDDFR_PKF_MASK); 55553b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia if (ch->info->var.nonstd) { 55653b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia tmp |= (ch->info->var.nonstd << 16); 55753b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia switch (ch->info->var.bits_per_pixel) { 55853b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia case 12: 55953b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia break; 56053b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia case 16: 561ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart tmp |= LDDFR_YF_422; 56253b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia break; 56353b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia case 24: 564ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart tmp |= LDDFR_YF_444; 56553b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia break; 56653b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia } 56753b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia } else { 56853b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia switch (ch->info->var.bits_per_pixel) { 56953b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia case 16: 570ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart tmp |= LDDFR_PKF_RGB16; 57153b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia break; 57253b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia case 24: 573ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart tmp |= LDDFR_PKF_RGB24; 57453b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia break; 57553b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia case 32: 576ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart tmp |= LDDFR_PKF_ARGB32; 57753b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia break; 57853b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia } 579417d48274e755e537bae60461558c1f63a4e14deMagnus Damm } 580cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write_chan(ch, LDDFR, tmp); 581cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 5827caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia base_addr_y = ch->info->fix.smem_start; 5837caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia base_addr_c = base_addr_y + 5847caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia ch->info->var.xres * 5857caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia ch->info->var.yres_virtual; 5867caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia pitch = ch->info->fix.line_length; 5877caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia 5887caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia /* test if we can enable meram */ 589eae9b85b5f65027df64130d8a3eeb2de9d094edaDamian Hobson-Garcia if (ch->cfg.meram_cfg && priv->meram_dev && 590eae9b85b5f65027df64130d8a3eeb2de9d094edaDamian Hobson-Garcia priv->meram_dev->ops) { 5917caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia struct sh_mobile_meram_cfg *cfg; 5927caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia struct sh_mobile_meram_info *mdev; 5937caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia unsigned long icb_addr_y, icb_addr_c; 5947caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia int icb_pitch; 5957caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia int pf; 5967caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia 5977caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia cfg = ch->cfg.meram_cfg; 5987caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia mdev = priv->meram_dev; 5997caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia /* we need to de-init configured ICBs before we 6007caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia * we can re-initialize them. 6017caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia */ 6027caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia if (ch->meram_enabled) 6037caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia mdev->ops->meram_unregister(mdev, cfg); 6047caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia 6057caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia ch->meram_enabled = 0; 6067caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia 6073fedd2ac7662a10ab2973d3b6f11cdce87b7171aDamian Hobson-Garcia if (ch->info->var.nonstd) { 6083fedd2ac7662a10ab2973d3b6f11cdce87b7171aDamian Hobson-Garcia if (ch->info->var.bits_per_pixel == 24) 6093fedd2ac7662a10ab2973d3b6f11cdce87b7171aDamian Hobson-Garcia pf = SH_MOBILE_MERAM_PF_NV24; 6103fedd2ac7662a10ab2973d3b6f11cdce87b7171aDamian Hobson-Garcia else 6113fedd2ac7662a10ab2973d3b6f11cdce87b7171aDamian Hobson-Garcia pf = SH_MOBILE_MERAM_PF_NV; 6123fedd2ac7662a10ab2973d3b6f11cdce87b7171aDamian Hobson-Garcia } else { 6137caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia pf = SH_MOBILE_MERAM_PF_RGB; 6143fedd2ac7662a10ab2973d3b6f11cdce87b7171aDamian Hobson-Garcia } 6157caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia 6167caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia ret = mdev->ops->meram_register(mdev, cfg, pitch, 6177caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia ch->info->var.yres, 6187caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia pf, 6197caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia base_addr_y, 6207caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia base_addr_c, 6217caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia &icb_addr_y, 6227caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia &icb_addr_c, 6237caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia &icb_pitch); 6247caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia if (!ret) { 6257caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia /* set LDSA1R value */ 6267caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia base_addr_y = icb_addr_y; 6277caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia pitch = icb_pitch; 6287caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia 6297caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia /* set LDSA2R value if required */ 6307caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia if (base_addr_c) 6317caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia base_addr_c = icb_addr_c; 6327caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia 6337caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia ch->meram_enabled = 1; 6347caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia } 6357caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia } 6367caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia 637cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* point out our frame buffer */ 6387caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia lcdc_write_chan(ch, LDSA1R, base_addr_y); 63953b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia if (ch->info->var.nonstd) 6407caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia lcdc_write_chan(ch, LDSA2R, base_addr_c); 641cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 642cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* set line size */ 6437caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia lcdc_write_chan(ch, LDMLSR, pitch); 644cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 6458564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* setup deferred io if SYS bus */ 6468564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm tmp = ch->cfg.sys_bus_cfg.deferred_io_msec; 647ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart if (ch->ldmt1r_value & LDMT1R_IFM && tmp) { 6488564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm ch->defio.deferred_io = sh_mobile_lcdc_deferred_io; 6498564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm ch->defio.delay = msecs_to_jiffies(tmp); 650e33afddca174171a68d57476ead8947476ab9240Paul Mundt ch->info->fbdefio = &ch->defio; 651e33afddca174171a68d57476ead8947476ab9240Paul Mundt fb_deferred_io_init(ch->info); 6528564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 6538564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* one-shot mode */ 654ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart lcdc_write_chan(ch, LDSM1R, LDSM1R_OS); 6558564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 6568564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* enable "Frame End Interrupt Enable" bit */ 6578564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm lcdc_write(priv, _LDINTR, LDINTR_FE); 6588564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 6598564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm } else { 6608564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* continuous read mode */ 6618564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm lcdc_write_chan(ch, LDSM1R, 0); 6628564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm } 663cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 664cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 665cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* display output */ 666ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart lcdc_write(priv, _LDCNT1R, LDCNT1R_DE); 667cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 668cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* start the lcdc */ 669cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm sh_mobile_lcdc_start_stop(priv, 1); 6708e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm priv->started = 1; 671cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 672cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* tell the board code to enable the panel */ 673cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 674cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ch = &priv->ch[k]; 67521bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm if (!ch->enabled) 67621bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm continue; 67721bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm 678cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm board_cfg = &ch->cfg.board_cfg; 679247f99386100d1d1c369ba98120d2edebf5426fcAlexandre Courbot if (board_cfg->display_on && try_module_get(board_cfg->owner)) { 680c2439398170be9d7af28eb3ab59593369cb303f3Guennadi Liakhovetski board_cfg->display_on(board_cfg->board_data, ch->info); 6816de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski module_put(board_cfg->owner); 6826de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski } 6833b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 6843b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot if (ch->bl) { 6853b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot ch->bl->props.power = FB_BLANK_UNBLANK; 6863b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot backlight_update_status(ch->bl); 6873b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot } 688cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 689cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 690cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 691cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 692cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 693cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) 694cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 695cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_chan *ch; 696cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_board_cfg *board_cfg; 697cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int k; 698cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 6992feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm /* clean up deferred io and ask board code to disable panel */ 700cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 701cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ch = &priv->ch[k]; 70221bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm if (!ch->enabled) 70321bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm continue; 7048564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 7052feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm /* deferred io mode: 7062feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm * flush frame, and wait for frame end interrupt 7072feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm * clean up deferred io and enable clock 7082feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm */ 7095ef6b505d9df45558402bdb823a078840a6a26c4Guennadi Liakhovetski if (ch->info && ch->info->fbdefio) { 7102feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm ch->frame_end = 0; 711e33afddca174171a68d57476ead8947476ab9240Paul Mundt schedule_delayed_work(&ch->info->deferred_work, 0); 7122feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm wait_event(ch->frame_end_wait, ch->frame_end); 713e33afddca174171a68d57476ead8947476ab9240Paul Mundt fb_deferred_io_cleanup(ch->info); 714e33afddca174171a68d57476ead8947476ab9240Paul Mundt ch->info->fbdefio = NULL; 7152feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm sh_mobile_lcdc_clk_on(priv); 7168564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm } 7172feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 7183b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot if (ch->bl) { 7193b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot ch->bl->props.power = FB_BLANK_POWERDOWN; 7203b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot backlight_update_status(ch->bl); 7213b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot } 7223b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 7232feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm board_cfg = &ch->cfg.board_cfg; 724247f99386100d1d1c369ba98120d2edebf5426fcAlexandre Courbot if (board_cfg->display_off && try_module_get(board_cfg->owner)) { 7252feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm board_cfg->display_off(board_cfg->board_data); 7266de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski module_put(board_cfg->owner); 7276de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski } 7287caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia 7297caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia /* disable the meram */ 7307caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia if (ch->meram_enabled) { 7317caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia struct sh_mobile_meram_cfg *cfg; 7327caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia struct sh_mobile_meram_info *mdev; 7337caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia cfg = ch->cfg.meram_cfg; 7347caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia mdev = priv->meram_dev; 7357caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia mdev->ops->meram_unregister(mdev, cfg); 7367caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia ch->meram_enabled = 0; 7377caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia } 7387caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia 739cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 740cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 741cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* stop the lcdc */ 7428e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm if (priv->started) { 7438e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm sh_mobile_lcdc_start_stop(priv, 0); 7448e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm priv->started = 0; 7458e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm } 746b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm 7478564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* stop clocks */ 7488564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) 7498564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (priv->ch[k].enabled) 7508564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_clk_off(priv); 751cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 752cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 753cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch) 754cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 755ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart int interface_type = ch->cfg.interface_type; 756ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart 757ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart switch (interface_type) { 758ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart case RGB8: 759ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart case RGB9: 760ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart case RGB12A: 761ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart case RGB12B: 762ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart case RGB16: 763ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart case RGB18: 764ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart case RGB24: 765ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart case SYS8A: 766ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart case SYS8B: 767ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart case SYS8C: 768ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart case SYS8D: 769ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart case SYS9: 770ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart case SYS12: 771ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart case SYS16A: 772ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart case SYS16B: 773ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart case SYS16C: 774ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart case SYS18: 775ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart case SYS24: 776ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart break; 777ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart default: 778ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart return -EINVAL; 779cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 780cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 781cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* SUBLCD only supports SYS interface */ 782cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (lcdc_chan_is_sublcd(ch)) { 783ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart if (!(interface_type & LDMT1R_IFM)) 784ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart return -EINVAL; 785ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart 786ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart interface_type &= ~LDMT1R_IFM; 787cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 788cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 789ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart ch->ldmt1r_value = interface_type; 790cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 791cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 792cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 793b51339fff240ff179730f8963a758147fd60f3ecMagnus Dammstatic int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev, 794b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm int clock_source, 795cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_priv *priv) 796cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 797cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm char *str; 798cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 799cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm switch (clock_source) { 800ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart case LCDC_CLK_BUS: 801ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart str = "bus_clk"; 802ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart priv->lddckr = LDDCKR_ICKSEL_BUS; 803ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart break; 804ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart case LCDC_CLK_PERIPHERAL: 805ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart str = "peripheral_clk"; 806ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart priv->lddckr = LDDCKR_ICKSEL_MIPI; 807ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart break; 808ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart case LCDC_CLK_EXTERNAL: 809ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart str = NULL; 810ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart priv->lddckr = LDDCKR_ICKSEL_HDMI; 811ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart break; 812cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm default: 813cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return -EINVAL; 814cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 815cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 816cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (str) { 817b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm priv->dot_clk = clk_get(&pdev->dev, str); 818b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm if (IS_ERR(priv->dot_clk)) { 819b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm dev_err(&pdev->dev, "cannot get dot clock %s\n", str); 820b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm return PTR_ERR(priv->dot_clk); 821cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 822cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 8230246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 8240246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm /* Runtime PM support involves two step for this driver: 8250246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm * 1) Enable Runtime PM 8260246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm * 2) Force Runtime PM Resume since hardware is accessed from probe() 8270246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm */ 8288bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski priv->dev = &pdev->dev; 8290246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm pm_runtime_enable(priv->dev); 8300246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm pm_runtime_resume(priv->dev); 831cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 832cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 833cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 834cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_setcolreg(u_int regno, 835cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm u_int red, u_int green, u_int blue, 836cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm u_int transp, struct fb_info *info) 837cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 838cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm u32 *palette = info->pseudo_palette; 839cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 840cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (regno >= PALETTE_NR) 841cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return -EINVAL; 842cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 843cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* only FB_VISUAL_TRUECOLOR supported */ 844cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 845cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm red >>= 16 - info->var.red.length; 846cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm green >>= 16 - info->var.green.length; 847cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm blue >>= 16 - info->var.blue.length; 848cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm transp >>= 16 - info->var.transp.length; 849cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 850cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm palette[regno] = (red << info->var.red.offset) | 851cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm (green << info->var.green.offset) | 852cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm (blue << info->var.blue.offset) | 853cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm (transp << info->var.transp.offset); 854cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 855cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 856cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 857cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 858cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic struct fb_fix_screeninfo sh_mobile_lcdc_fix = { 859cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .id = "SH Mobile LCDC", 860cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .type = FB_TYPE_PACKED_PIXELS, 861cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .visual = FB_VISUAL_TRUECOLOR, 862cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .accel = FB_ACCEL_NONE, 8639dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy .xpanstep = 0, 8649dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy .ypanstep = 1, 8659dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy .ywrapstep = 0, 866cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 867cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 8688564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_fillrect(struct fb_info *info, 8698564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm const struct fb_fillrect *rect) 8708564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 8718564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sys_fillrect(info, rect); 8728564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_deferred_io_touch(info); 8738564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 8748564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 8758564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_copyarea(struct fb_info *info, 8768564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm const struct fb_copyarea *area) 8778564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 8788564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sys_copyarea(info, area); 8798564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_deferred_io_touch(info); 8808564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 8818564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 8828564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_imageblit(struct fb_info *info, 8838564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm const struct fb_image *image) 8848564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 8858564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sys_imageblit(info, image); 8868564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_deferred_io_touch(info); 8878564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 8888564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 8899dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthystatic int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, 8909dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy struct fb_info *info) 8919dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy{ 8929dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy struct sh_mobile_lcdc_chan *ch = info->par; 89392e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy struct sh_mobile_lcdc_priv *priv = ch->lcdc; 89492e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy unsigned long ldrcntr; 89592e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy unsigned long new_pan_offset; 89653b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia unsigned long base_addr_y, base_addr_c; 89753b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia unsigned long c_offset; 89892e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy 89953b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia if (!var->nonstd) 90053b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia new_pan_offset = (var->yoffset * info->fix.line_length) + 90153b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia (var->xoffset * (info->var.bits_per_pixel / 8)); 90253b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia else 90353b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia new_pan_offset = (var->yoffset * info->fix.line_length) + 90453b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia (var->xoffset); 9059dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy 90692e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy if (new_pan_offset == ch->pan_offset) 9079dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy return 0; /* No change, do nothing */ 9089dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy 90992e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy ldrcntr = lcdc_read(priv, _LDRCNTR); 9109dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy 91192e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy /* Set the source address for the next refresh */ 91253b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia base_addr_y = ch->dma_handle + new_pan_offset; 91353b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia if (var->nonstd) { 91453b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia /* Set y offset */ 91553b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia c_offset = (var->yoffset * 91653b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia info->fix.line_length * 91753b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia (info->var.bits_per_pixel - 8)) / 8; 91853b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia base_addr_c = ch->dma_handle + var->xres * var->yres_virtual + 91953b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia c_offset; 92053b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia /* Set x offset */ 92153b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia if (info->var.bits_per_pixel == 24) 92253b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia base_addr_c += 2 * var->xoffset; 92353b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia else 92453b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia base_addr_c += var->xoffset; 92553b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia } else 92653b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia base_addr_c = 0; 92753b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia 9287caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia if (!ch->meram_enabled) { 9297caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y); 9307caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia if (base_addr_c) 9317caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c); 9327caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia } else { 9337caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia struct sh_mobile_meram_cfg *cfg; 9347caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia struct sh_mobile_meram_info *mdev; 9357caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia unsigned long icb_addr_y, icb_addr_c; 9367caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia int ret; 9377caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia 9387caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia cfg = ch->cfg.meram_cfg; 9397caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia mdev = priv->meram_dev; 9407caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia ret = mdev->ops->meram_update(mdev, cfg, 9417caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia base_addr_y, base_addr_c, 9427caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia &icb_addr_y, &icb_addr_c); 9437caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia if (ret) 9447caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia return ret; 9457caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia 9467caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia lcdc_write_chan_mirror(ch, LDSA1R, icb_addr_y); 9477caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia if (icb_addr_c) 9487caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia lcdc_write_chan_mirror(ch, LDSA2R, icb_addr_c); 9497caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia 9507caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia } 95153b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia 95292e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy if (lcdc_chan_is_sublcd(ch)) 95392e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS); 95492e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy else 95592e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_MRS); 95692e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy 95792e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy ch->pan_offset = new_pan_offset; 95892e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy 95992e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy sh_mobile_lcdc_deferred_io_touch(info); 9609dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy 9619dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy return 0; 9629dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy} 9639dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy 96440331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthystatic int sh_mobile_wait_for_vsync(struct fb_info *info) 96540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy{ 96640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy struct sh_mobile_lcdc_chan *ch = info->par; 96740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy unsigned long ldintr; 96840331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy int ret; 96940331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 970dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart /* Enable VSync End interrupt and be careful not to acknowledge any 971dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart * pending interrupt. 972dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart */ 97340331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy ldintr = lcdc_read(ch->lcdc, _LDINTR); 974dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart ldintr |= LDINTR_VEE | LDINTR_STATUS_MASK; 97540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy lcdc_write(ch->lcdc, _LDINTR, ldintr); 97640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 97740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion, 97840331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy msecs_to_jiffies(100)); 97940331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy if (!ret) 98040331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy return -ETIMEDOUT; 98140331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 98240331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy return 0; 98340331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy} 98440331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 98540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthystatic int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd, 98640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy unsigned long arg) 98740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy{ 98840331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy int retval; 98940331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 99040331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy switch (cmd) { 99140331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy case FBIO_WAITFORVSYNC: 99240331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy retval = sh_mobile_wait_for_vsync(info); 99340331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy break; 99440331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 99540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy default: 99640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy retval = -ENOIOCTLCMD; 99740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy break; 99840331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy } 99940331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy return retval; 100040331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy} 100140331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 1002dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetskistatic void sh_mobile_fb_reconfig(struct fb_info *info) 1003dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{ 1004dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski struct sh_mobile_lcdc_chan *ch = info->par; 1005dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski struct fb_videomode mode1, mode2; 1006dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski struct fb_event event; 1007dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski int evnt = FB_EVENT_MODE_CHANGE_ALL; 1008dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1009dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski if (ch->use_count > 1 || (ch->use_count == 1 && !info->fbcon_par)) 1010dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski /* More framebuffer users are active */ 1011dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski return; 1012dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1013dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski fb_var_to_videomode(&mode1, &ch->display_var); 1014dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski fb_var_to_videomode(&mode2, &info->var); 1015dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1016dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski if (fb_mode_is_equal(&mode1, &mode2)) 1017dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski return; 1018dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1019dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski /* Display has been re-plugged, framebuffer is free now, reconfigure */ 1020dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski if (fb_set_var(info, &ch->display_var) < 0) 1021dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski /* Couldn't reconfigure, hopefully, can continue as before */ 1022dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski return; 1023dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 102453b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia if (info->var.nonstd) 102553b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia info->fix.line_length = mode1.xres; 102653b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia else 102753b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia info->fix.line_length = mode1.xres * (ch->cfg.bpp / 8); 1028dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1029dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski /* 1030dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski * fb_set_var() calls the notifier change internally, only if 1031dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski * FBINFO_MISC_USEREVENT flag is set. Since we do not want to fake a 1032dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski * user event, we have to call the chain ourselves. 1033dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski */ 1034dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski event.info = info; 1035cc267ec5dfa29eba34cbf4eae3e5db9ca499c179Arnd Hannemann event.data = &mode1; 1036dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski fb_notifier_call_chain(evnt, &event); 1037dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski} 1038dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1039dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski/* 1040dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski * Locking: both .fb_release() and .fb_open() are called with info->lock held if 1041dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski * user == 1, or with console sem held, if user == 0. 1042dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski */ 1043dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetskistatic int sh_mobile_release(struct fb_info *info, int user) 1044dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{ 1045dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski struct sh_mobile_lcdc_chan *ch = info->par; 1046dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1047dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski mutex_lock(&ch->open_lock); 1048dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count); 1049dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1050dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski ch->use_count--; 1051dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1052dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski /* Nothing to reconfigure, when called from fbcon */ 1053dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski if (user) { 1054ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_lock(); 1055dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski sh_mobile_fb_reconfig(info); 1056ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_unlock(); 1057dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski } 1058dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1059dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski mutex_unlock(&ch->open_lock); 1060dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1061dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski return 0; 1062dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski} 1063dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1064dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetskistatic int sh_mobile_open(struct fb_info *info, int user) 1065dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{ 1066dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski struct sh_mobile_lcdc_chan *ch = info->par; 1067dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1068dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski mutex_lock(&ch->open_lock); 1069dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski ch->use_count++; 1070dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1071dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count); 1072dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski mutex_unlock(&ch->open_lock); 1073dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1074dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski return 0; 1075dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski} 1076dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1077dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetskistatic int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 1078dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{ 1079dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski struct sh_mobile_lcdc_chan *ch = info->par; 1080417d48274e755e537bae60461558c1f63a4e14deMagnus Damm struct sh_mobile_lcdc_priv *p = ch->lcdc; 1081dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1082d2ecbab5960d9814a269d36723647d6ef391ba8fGuennadi Liakhovetski if (var->xres > MAX_XRES || var->yres > MAX_YRES || 1083dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski var->xres * var->yres * (ch->cfg.bpp / 8) * 2 > info->fix.smem_len) { 1084830539d14379d0f5cb07832a3e4466418011f843Paul Mundt dev_warn(info->dev, "Invalid info: %u-%u-%u-%u x %u-%u-%u-%u @ %lukHz!\n", 1085d2ecbab5960d9814a269d36723647d6ef391ba8fGuennadi Liakhovetski var->left_margin, var->xres, var->right_margin, var->hsync_len, 1086d2ecbab5960d9814a269d36723647d6ef391ba8fGuennadi Liakhovetski var->upper_margin, var->yres, var->lower_margin, var->vsync_len, 1087d2ecbab5960d9814a269d36723647d6ef391ba8fGuennadi Liakhovetski PICOS2KHZ(var->pixclock)); 1088dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski return -EINVAL; 1089dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski } 1090417d48274e755e537bae60461558c1f63a4e14deMagnus Damm 1091417d48274e755e537bae60461558c1f63a4e14deMagnus Damm /* only accept the forced_bpp for dual channel configurations */ 1092417d48274e755e537bae60461558c1f63a4e14deMagnus Damm if (p->forced_bpp && p->forced_bpp != var->bits_per_pixel) 1093417d48274e755e537bae60461558c1f63a4e14deMagnus Damm return -EINVAL; 1094417d48274e755e537bae60461558c1f63a4e14deMagnus Damm 1095417d48274e755e537bae60461558c1f63a4e14deMagnus Damm switch (var->bits_per_pixel) { 1096417d48274e755e537bae60461558c1f63a4e14deMagnus Damm case 16: /* PKF[4:0] = 00011 - RGB 565 */ 1097417d48274e755e537bae60461558c1f63a4e14deMagnus Damm case 24: /* PKF[4:0] = 01011 - RGB 888 */ 1098417d48274e755e537bae60461558c1f63a4e14deMagnus Damm case 32: /* PKF[4:0] = 00000 - RGBA 888 */ 1099417d48274e755e537bae60461558c1f63a4e14deMagnus Damm break; 1100417d48274e755e537bae60461558c1f63a4e14deMagnus Damm default: 1101417d48274e755e537bae60461558c1f63a4e14deMagnus Damm return -EINVAL; 1102417d48274e755e537bae60461558c1f63a4e14deMagnus Damm } 1103417d48274e755e537bae60461558c1f63a4e14deMagnus Damm 1104dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski return 0; 1105dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski} 110640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 11078857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot/* 11088857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * Screen blanking. Behavior is as follows: 11098857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_UNBLANK: screen unblanked, clocks enabled 11108857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_NORMAL: screen blanked, clocks enabled 11118857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_VSYNC, 11128857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_HSYNC, 11138857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_POWEROFF: screen blanked, clocks disabled 11148857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot */ 11158857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbotstatic int sh_mobile_lcdc_blank(int blank, struct fb_info *info) 11168857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot{ 11178857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot struct sh_mobile_lcdc_chan *ch = info->par; 11188857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot struct sh_mobile_lcdc_priv *p = ch->lcdc; 11198857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot 11208857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot /* blank the screen? */ 11218857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot if (blank > FB_BLANK_UNBLANK && ch->blank_status == FB_BLANK_UNBLANK) { 11228857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot struct fb_fillrect rect = { 11238857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot .width = info->var.xres, 11248857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot .height = info->var.yres, 11258857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot }; 11268857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot sh_mobile_lcdc_fillrect(info, &rect); 11278857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot } 11288857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot /* turn clocks on? */ 11298857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot if (blank <= FB_BLANK_NORMAL && ch->blank_status > FB_BLANK_NORMAL) { 11308857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot sh_mobile_lcdc_clk_on(p); 11318857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot } 11328857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot /* turn clocks off? */ 11338857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot if (blank > FB_BLANK_NORMAL && ch->blank_status <= FB_BLANK_NORMAL) { 11348857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot /* make sure the screen is updated with the black fill before 11358857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * switching the clocks off. one vsync is not enough since 11368857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * blanking may occur in the middle of a refresh. deferred io 11378857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * mode will reenable the clocks and update the screen in time, 11388857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * so it does not need this. */ 11398857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot if (!info->fbdefio) { 11408857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot sh_mobile_wait_for_vsync(info); 11418857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot sh_mobile_wait_for_vsync(info); 11428857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot } 11438857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot sh_mobile_lcdc_clk_off(p); 11448857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot } 11458857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot 11468857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot ch->blank_status = blank; 11478857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot return 0; 11488857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot} 11498857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot 1150cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic struct fb_ops sh_mobile_lcdc_ops = { 11519dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy .owner = THIS_MODULE, 1152cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .fb_setcolreg = sh_mobile_lcdc_setcolreg, 11532540c111ead82cad605ec2b14a1905ad914cc124Magnus Damm .fb_read = fb_sys_read, 11542540c111ead82cad605ec2b14a1905ad914cc124Magnus Damm .fb_write = fb_sys_write, 11558564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm .fb_fillrect = sh_mobile_lcdc_fillrect, 11568564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm .fb_copyarea = sh_mobile_lcdc_copyarea, 11578564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm .fb_imageblit = sh_mobile_lcdc_imageblit, 11588857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot .fb_blank = sh_mobile_lcdc_blank, 11599dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy .fb_pan_display = sh_mobile_fb_pan_display, 116040331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy .fb_ioctl = sh_mobile_ioctl, 1161dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski .fb_open = sh_mobile_open, 1162dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski .fb_release = sh_mobile_release, 1163dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski .fb_check_var = sh_mobile_check_var, 1164cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 1165cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 11663b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic int sh_mobile_lcdc_update_bl(struct backlight_device *bdev) 11673b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{ 11683b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev); 11693b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot struct sh_mobile_lcdc_board_cfg *cfg = &ch->cfg.board_cfg; 11703b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot int brightness = bdev->props.brightness; 11713b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 11723b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot if (bdev->props.power != FB_BLANK_UNBLANK || 11733b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot bdev->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK)) 11743b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot brightness = 0; 11753b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 11763b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot return cfg->set_brightness(cfg->board_data, brightness); 11773b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot} 11783b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 11793b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic int sh_mobile_lcdc_get_brightness(struct backlight_device *bdev) 11803b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{ 11813b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev); 11823b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot struct sh_mobile_lcdc_board_cfg *cfg = &ch->cfg.board_cfg; 11833b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 11843b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot return cfg->get_brightness(cfg->board_data); 11853b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot} 11863b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 11873b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic int sh_mobile_lcdc_check_fb(struct backlight_device *bdev, 11883b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot struct fb_info *info) 11893b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{ 11903b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot return (info->bl_dev == bdev); 11913b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot} 11923b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 11933b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic struct backlight_ops sh_mobile_lcdc_bl_ops = { 11943b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot .options = BL_CORE_SUSPENDRESUME, 11953b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot .update_status = sh_mobile_lcdc_update_bl, 11963b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot .get_brightness = sh_mobile_lcdc_get_brightness, 11973b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot .check_fb = sh_mobile_lcdc_check_fb, 11983b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot}; 11993b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 12003b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic struct backlight_device *sh_mobile_lcdc_bl_probe(struct device *parent, 12013b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot struct sh_mobile_lcdc_chan *ch) 12023b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{ 12033b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot struct backlight_device *bl; 12043b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 12053b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot bl = backlight_device_register(ch->cfg.bl_info.name, parent, ch, 12063b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot &sh_mobile_lcdc_bl_ops, NULL); 1207beee1f20a185c7e79fd33bb83e04fe44ecd75af3Dan Carpenter if (IS_ERR(bl)) { 1208beee1f20a185c7e79fd33bb83e04fe44ecd75af3Dan Carpenter dev_err(parent, "unable to register backlight device: %ld\n", 1209beee1f20a185c7e79fd33bb83e04fe44ecd75af3Dan Carpenter PTR_ERR(bl)); 12103b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot return NULL; 12113b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot } 12123b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 12133b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot bl->props.max_brightness = ch->cfg.bl_info.max_brightness; 12143b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot bl->props.brightness = bl->props.max_brightness; 12153b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot backlight_update_status(bl); 12163b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 12173b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot return bl; 12183b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot} 12193b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 12203b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic void sh_mobile_lcdc_bl_remove(struct backlight_device *bdev) 12213b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{ 12223b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot backlight_device_unregister(bdev); 12233b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot} 12243b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 122553b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garciastatic int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp, 122653b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia int nonstd) 1227cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 122853b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia if (nonstd) { 122953b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia switch (bpp) { 123053b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia case 12: 123153b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia case 16: 123253b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia case 24: 123353b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia var->bits_per_pixel = bpp; 123453b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia var->nonstd = nonstd; 123553b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia return 0; 123653b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia default: 123753b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia return -EINVAL; 123853b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia } 123953b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia } 124053b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia 1241cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm switch (bpp) { 1242cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case 16: /* PKF[4:0] = 00011 - RGB 565 */ 1243cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->red.offset = 11; 1244cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->red.length = 5; 1245cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->green.offset = 5; 1246cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->green.length = 6; 1247cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->blue.offset = 0; 1248cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->blue.length = 5; 1249cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->transp.offset = 0; 1250cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->transp.length = 0; 1251cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 1252cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1253417d48274e755e537bae60461558c1f63a4e14deMagnus Damm case 24: /* PKF[4:0] = 01011 - RGB 888 */ 1254417d48274e755e537bae60461558c1f63a4e14deMagnus Damm var->red.offset = 16; 1255cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->red.length = 8; 1256417d48274e755e537bae60461558c1f63a4e14deMagnus Damm var->green.offset = 8; 1257cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->green.length = 8; 1258417d48274e755e537bae60461558c1f63a4e14deMagnus Damm var->blue.offset = 0; 1259cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->blue.length = 8; 1260cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->transp.offset = 0; 1261cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->transp.length = 0; 1262cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 1263417d48274e755e537bae60461558c1f63a4e14deMagnus Damm 1264417d48274e755e537bae60461558c1f63a4e14deMagnus Damm case 32: /* PKF[4:0] = 00000 - RGBA 888 */ 1265417d48274e755e537bae60461558c1f63a4e14deMagnus Damm var->red.offset = 16; 1266417d48274e755e537bae60461558c1f63a4e14deMagnus Damm var->red.length = 8; 1267417d48274e755e537bae60461558c1f63a4e14deMagnus Damm var->green.offset = 8; 1268417d48274e755e537bae60461558c1f63a4e14deMagnus Damm var->green.length = 8; 1269417d48274e755e537bae60461558c1f63a4e14deMagnus Damm var->blue.offset = 0; 1270417d48274e755e537bae60461558c1f63a4e14deMagnus Damm var->blue.length = 8; 1271417d48274e755e537bae60461558c1f63a4e14deMagnus Damm var->transp.offset = 24; 1272417d48274e755e537bae60461558c1f63a4e14deMagnus Damm var->transp.length = 8; 1273417d48274e755e537bae60461558c1f63a4e14deMagnus Damm break; 1274cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm default: 1275cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return -EINVAL; 1276cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1277cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->bits_per_pixel = bpp; 1278cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->red.msb_right = 0; 1279cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->green.msb_right = 0; 1280cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->blue.msb_right = 0; 1281cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->transp.msb_right = 0; 1282cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 1283cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 1284cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 12852feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Dammstatic int sh_mobile_lcdc_suspend(struct device *dev) 12862feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm{ 12872feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm struct platform_device *pdev = to_platform_device(dev); 12882feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 12892feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm sh_mobile_lcdc_stop(platform_get_drvdata(pdev)); 12902feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm return 0; 12912feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm} 12922feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 12932feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Dammstatic int sh_mobile_lcdc_resume(struct device *dev) 12942feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm{ 12952feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm struct platform_device *pdev = to_platform_device(dev); 12962feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 12972feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm return sh_mobile_lcdc_start(platform_get_drvdata(pdev)); 12982feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm} 12992feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 13000246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic int sh_mobile_lcdc_runtime_suspend(struct device *dev) 13010246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm{ 13020246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct platform_device *pdev = to_platform_device(dev); 13030246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct sh_mobile_lcdc_priv *p = platform_get_drvdata(pdev); 13040246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct sh_mobile_lcdc_chan *ch; 13050246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm int k, n; 13060246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 13070246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm /* save per-channel registers */ 13080246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm for (k = 0; k < ARRAY_SIZE(p->ch); k++) { 13090246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm ch = &p->ch[k]; 13100246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm if (!ch->enabled) 13110246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm continue; 13120246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm for (n = 0; n < NR_CH_REGS; n++) 13130246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm ch->saved_ch_regs[n] = lcdc_read_chan(ch, n); 13140246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm } 13150246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 13160246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm /* save shared registers */ 13170246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm for (n = 0; n < NR_SHARED_REGS; n++) 13180246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm p->saved_shared_regs[n] = lcdc_read(p, lcdc_shared_regs[n]); 13190246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 13200246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm /* turn off LCDC hardware */ 13210246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm lcdc_write(p, _LDCNT1R, 0); 13220246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm return 0; 13230246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm} 13240246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 13250246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic int sh_mobile_lcdc_runtime_resume(struct device *dev) 13260246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm{ 13270246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct platform_device *pdev = to_platform_device(dev); 13280246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct sh_mobile_lcdc_priv *p = platform_get_drvdata(pdev); 13290246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct sh_mobile_lcdc_chan *ch; 13300246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm int k, n; 13310246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 13320246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm /* restore per-channel registers */ 13330246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm for (k = 0; k < ARRAY_SIZE(p->ch); k++) { 13340246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm ch = &p->ch[k]; 13350246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm if (!ch->enabled) 13360246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm continue; 13370246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm for (n = 0; n < NR_CH_REGS; n++) 13380246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm lcdc_write_chan(ch, n, ch->saved_ch_regs[n]); 13390246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm } 13400246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 13410246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm /* restore shared registers */ 13420246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm for (n = 0; n < NR_SHARED_REGS; n++) 13430246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm lcdc_write(p, lcdc_shared_regs[n], p->saved_shared_regs[n]); 13440246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 13450246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm return 0; 13460246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm} 13470246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 1348471452104b8520337ae2fb48c4e61cd4896e025dAlexey Dobriyanstatic const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = { 13492feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm .suspend = sh_mobile_lcdc_suspend, 13502feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm .resume = sh_mobile_lcdc_resume, 13510246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm .runtime_suspend = sh_mobile_lcdc_runtime_suspend, 13520246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm .runtime_resume = sh_mobile_lcdc_runtime_resume, 13532feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm}; 13542feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 13556de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski/* locking: called with info->lock held */ 13566011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetskistatic int sh_mobile_lcdc_notify(struct notifier_block *nb, 13576011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski unsigned long action, void *data) 13586011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski{ 13596011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski struct fb_event *event = data; 13606011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski struct fb_info *info = event->info; 13616011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski struct sh_mobile_lcdc_chan *ch = info->par; 13626011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg; 13636011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 13646011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski if (&ch->lcdc->notifier != nb) 1365baf163749952ca5e33dd2d6a74da023e385c3a00Guennadi Liakhovetski return NOTIFY_DONE; 13666011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 13676011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski dev_dbg(info->dev, "%s(): action = %lu, data = %p\n", 13686011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski __func__, action, event->data); 13696011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 13706011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski switch(action) { 13716011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski case FB_EVENT_SUSPEND: 1372247f99386100d1d1c369ba98120d2edebf5426fcAlexandre Courbot if (board_cfg->display_off && try_module_get(board_cfg->owner)) { 13736011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski board_cfg->display_off(board_cfg->board_data); 13746de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski module_put(board_cfg->owner); 13756de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski } 1376afe417c0355154c8b2547619771d6053b3c0aad7Guennadi Liakhovetski sh_mobile_lcdc_stop(ch->lcdc); 13776011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski break; 13786011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski case FB_EVENT_RESUME: 1379dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski mutex_lock(&ch->open_lock); 1380dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski sh_mobile_fb_reconfig(info); 1381dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski mutex_unlock(&ch->open_lock); 13826011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 13836011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski /* HDMI must be enabled before LCDC configuration */ 1384247f99386100d1d1c369ba98120d2edebf5426fcAlexandre Courbot if (board_cfg->display_on && try_module_get(board_cfg->owner)) { 1385dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski board_cfg->display_on(board_cfg->board_data, info); 13866de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski module_put(board_cfg->owner); 13876011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski } 13886011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 1389ebe5e12d00f4785092a9650845ad3451bbf4b311Guennadi Liakhovetski sh_mobile_lcdc_start(ch->lcdc); 13906011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski } 13916011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 1392baf163749952ca5e33dd2d6a74da023e385c3a00Guennadi Liakhovetski return NOTIFY_OK; 13936011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski} 13946011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 1395cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_remove(struct platform_device *pdev); 1396cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1397c2e13037e6794bd0d9de3f9ecabf5615f15c160bUwe Kleine-Königstatic int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) 1398cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 1399cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct fb_info *info; 1400cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_priv *priv; 140101ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski struct sh_mobile_lcdc_info *pdata = pdev->dev.platform_data; 1402cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct resource *res; 1403cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int error; 1404cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm void *buf; 1405cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int i, j; 1406cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 140701ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski if (!pdata) { 1408cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "no platform data defined\n"); 14098bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski return -EINVAL; 1410cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1411cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1412cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 14138564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm i = platform_get_irq(pdev, 0); 14148564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (!res || i < 0) { 14158564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm dev_err(&pdev->dev, "cannot get platform resources\n"); 14168bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski return -ENOENT; 1417cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1418cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1419cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm priv = kzalloc(sizeof(*priv), GFP_KERNEL); 1420cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!priv) { 1421cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "cannot allocate device data\n"); 14228bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski return -ENOMEM; 1423cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1424cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 14258bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski platform_set_drvdata(pdev, priv); 14268bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski 14278564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm error = request_irq(i, sh_mobile_lcdc_irq, IRQF_DISABLED, 14287ad33e74857f16f1202cbc5746faf52e88e8b376Kay Sievers dev_name(&pdev->dev), priv); 14298564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (error) { 14308564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm dev_err(&pdev->dev, "unable to request irq\n"); 14318564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm goto err1; 14328564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm } 14338564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 14348564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm priv->irq = i; 14355ef6b505d9df45558402bdb823a078840a6a26c4Guennadi Liakhovetski atomic_set(&priv->hw_usecnt, -1); 1436cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1437cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm j = 0; 1438cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (i = 0; i < ARRAY_SIZE(pdata->ch); i++) { 143901ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski struct sh_mobile_lcdc_chan *ch = priv->ch + j; 1440cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 144101ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski ch->lcdc = priv; 144201ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski memcpy(&ch->cfg, &pdata->ch[i], sizeof(pdata->ch[i])); 1443cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 144401ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski error = sh_mobile_lcdc_check_interface(ch); 1445cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error) { 1446cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "unsupported interface type\n"); 1447cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 1448cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 144901ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski init_waitqueue_head(&ch->frame_end_wait); 145001ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski init_completion(&ch->vsync_completion); 145101ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski ch->pan_offset = 0; 1452cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 14533b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot /* probe the backlight is there is one defined */ 14543b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot if (ch->cfg.bl_info.max_brightness) 14553b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot ch->bl = sh_mobile_lcdc_bl_probe(&pdev->dev, ch); 14563b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 1457cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm switch (pdata->ch[i].chan) { 1458cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case LCDC_CHAN_MAINLCD: 1459ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart ch->enabled = LDCNT2R_ME; 146001ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski ch->reg_offs = lcdc_offs_mainlcd; 1461cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm j++; 1462cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 1463cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case LCDC_CHAN_SUBLCD: 1464ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart ch->enabled = LDCNT2R_SE; 146501ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski ch->reg_offs = lcdc_offs_sublcd; 1466cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm j++; 1467cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 1468cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1469cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1470cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1471cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!j) { 1472cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "no channels defined\n"); 1473cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm error = -EINVAL; 1474cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 1475cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1476cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1477417d48274e755e537bae60461558c1f63a4e14deMagnus Damm /* for dual channel LCDC (MAIN + SUB) force shared bpp setting */ 1478417d48274e755e537bae60461558c1f63a4e14deMagnus Damm if (j == 2) 1479417d48274e755e537bae60461558c1f63a4e14deMagnus Damm priv->forced_bpp = pdata->ch[0].bpp; 1480417d48274e755e537bae60461558c1f63a4e14deMagnus Damm 1481dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski priv->base = ioremap_nocache(res->start, resource_size(res)); 1482dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski if (!priv->base) 1483dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski goto err1; 1484dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski 1485b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm error = sh_mobile_lcdc_setup_clocks(pdev, pdata->clock_source, priv); 1486cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error) { 1487cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "unable to setup clocks\n"); 1488cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 1489cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1490cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 14917caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia priv->meram_dev = pdata->meram_dev; 14927caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia 1493cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (i = 0; i < j; i++) { 14946011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski struct fb_var_screeninfo *var; 149571d3b0fcadf70d0de1ad334f48c9a4060209091aGuennadi Liakhovetski const struct fb_videomode *lcd_cfg, *max_cfg = NULL; 149601ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski struct sh_mobile_lcdc_chan *ch = priv->ch + i; 1497c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski struct sh_mobile_lcdc_chan_cfg *cfg = &ch->cfg; 1498c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski const struct fb_videomode *mode = cfg->lcd_cfg; 149971d3b0fcadf70d0de1ad334f48c9a4060209091aGuennadi Liakhovetski unsigned long max_size = 0; 150071d3b0fcadf70d0de1ad334f48c9a4060209091aGuennadi Liakhovetski int k; 15015fd284e6cd39f731db86dfd2440553365d5fad4dGuennadi Liakhovetski int num_cfg; 1502cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 150301ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski ch->info = framebuffer_alloc(0, &pdev->dev); 150401ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski if (!ch->info) { 1505e33afddca174171a68d57476ead8947476ab9240Paul Mundt dev_err(&pdev->dev, "unable to allocate fb_info\n"); 1506e33afddca174171a68d57476ead8947476ab9240Paul Mundt error = -ENOMEM; 1507e33afddca174171a68d57476ead8947476ab9240Paul Mundt break; 1508e33afddca174171a68d57476ead8947476ab9240Paul Mundt } 1509e33afddca174171a68d57476ead8947476ab9240Paul Mundt 151001ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski info = ch->info; 15116011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski var = &info->var; 1512cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->fbops = &sh_mobile_lcdc_ops; 1513c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski info->par = ch; 1514dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1515dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski mutex_init(&ch->open_lock); 1516dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1517c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski for (k = 0, lcd_cfg = mode; 1518c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski k < cfg->num_cfg && lcd_cfg; 151971d3b0fcadf70d0de1ad334f48c9a4060209091aGuennadi Liakhovetski k++, lcd_cfg++) { 152071d3b0fcadf70d0de1ad334f48c9a4060209091aGuennadi Liakhovetski unsigned long size = lcd_cfg->yres * lcd_cfg->xres; 152153b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia /* NV12 buffers must have even number of lines */ 152253b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia if ((cfg->nonstd) && cfg->bpp == 12 && 152353b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia (lcd_cfg->yres & 0x1)) { 152453b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia dev_err(&pdev->dev, "yres must be multiple of 2" 152553b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia " for YCbCr420 mode.\n"); 152653b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia error = -EINVAL; 152753b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia goto err1; 152853b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia } 152971d3b0fcadf70d0de1ad334f48c9a4060209091aGuennadi Liakhovetski 153071d3b0fcadf70d0de1ad334f48c9a4060209091aGuennadi Liakhovetski if (size > max_size) { 153171d3b0fcadf70d0de1ad334f48c9a4060209091aGuennadi Liakhovetski max_cfg = lcd_cfg; 153271d3b0fcadf70d0de1ad334f48c9a4060209091aGuennadi Liakhovetski max_size = size; 153371d3b0fcadf70d0de1ad334f48c9a4060209091aGuennadi Liakhovetski } 153471d3b0fcadf70d0de1ad334f48c9a4060209091aGuennadi Liakhovetski } 153571d3b0fcadf70d0de1ad334f48c9a4060209091aGuennadi Liakhovetski 1536c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski if (!mode) 1537d2ecbab5960d9814a269d36723647d6ef391ba8fGuennadi Liakhovetski max_size = MAX_XRES * MAX_YRES; 1538c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski else if (max_cfg) 1539c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski dev_dbg(&pdev->dev, "Found largest videomode %ux%u\n", 1540c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski max_cfg->xres, max_cfg->yres); 154171d3b0fcadf70d0de1ad334f48c9a4060209091aGuennadi Liakhovetski 1542cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->fix = sh_mobile_lcdc_fix; 154353b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia info->fix.smem_len = max_size * 2 * cfg->bpp / 8; 154453b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia 154553b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia /* Only pan in 2 line steps for NV12 */ 154653b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia if (cfg->nonstd && cfg->bpp == 12) 154753b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia info->fix.ypanstep = 2; 1548cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 15495fd284e6cd39f731db86dfd2440553365d5fad4dGuennadi Liakhovetski if (!mode) { 1550c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski mode = &default_720p; 15515fd284e6cd39f731db86dfd2440553365d5fad4dGuennadi Liakhovetski num_cfg = 1; 15525fd284e6cd39f731db86dfd2440553365d5fad4dGuennadi Liakhovetski } else { 1553e0b9fb26266778cc749365b98041c5b7ef6f10f8Guennadi Liakhovetski num_cfg = cfg->num_cfg; 15545fd284e6cd39f731db86dfd2440553365d5fad4dGuennadi Liakhovetski } 15555fd284e6cd39f731db86dfd2440553365d5fad4dGuennadi Liakhovetski 15565fd284e6cd39f731db86dfd2440553365d5fad4dGuennadi Liakhovetski fb_videomode_to_modelist(mode, num_cfg, &info->modelist); 1557c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski 1558c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski fb_videomode_to_var(var, mode); 1559e0b9fb26266778cc749365b98041c5b7ef6f10f8Guennadi Liakhovetski var->width = cfg->lcd_size_cfg.width; 1560e0b9fb26266778cc749365b98041c5b7ef6f10f8Guennadi Liakhovetski var->height = cfg->lcd_size_cfg.height; 15619dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy /* Default Y virtual resolution is 2x panel size */ 15626011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski var->yres_virtual = var->yres * 2; 15636011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski var->activate = FB_ACTIVATE_NOW; 15646011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 156553b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia error = sh_mobile_lcdc_set_bpp(var, cfg->bpp, cfg->nonstd); 1566cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error) 1567cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 1568cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1569cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm buf = dma_alloc_coherent(&pdev->dev, info->fix.smem_len, 157001ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski &ch->dma_handle, GFP_KERNEL); 1571cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!buf) { 1572cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "unable to allocate buffer\n"); 1573cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm error = -ENOMEM; 1574cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 1575cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1576cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 157701ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski info->pseudo_palette = &ch->pseudo_palette; 1578cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->flags = FBINFO_FLAG_DEFAULT; 1579cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1580cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm error = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0); 1581cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error < 0) { 1582cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "unable to allocate cmap\n"); 1583cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dma_free_coherent(&pdev->dev, info->fix.smem_len, 158401ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski buf, ch->dma_handle); 1585cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 1586cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1587cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 158801ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski info->fix.smem_start = ch->dma_handle; 158953b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia if (var->nonstd) 159053b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia info->fix.line_length = var->xres; 159153b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia else 159253b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia info->fix.line_length = var->xres * (cfg->bpp / 8); 159353b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia 1594cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->screen_base = buf; 1595cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->device = &pdev->dev; 15961c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski ch->display_var = *var; 1597cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1598cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1599cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error) 1600cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 1601cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1602cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm error = sh_mobile_lcdc_start(priv); 1603cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error) { 1604cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "unable to start hardware\n"); 1605cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 1606cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1607cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1608cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (i = 0; i < j; i++) { 16091c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt struct sh_mobile_lcdc_chan *ch = priv->ch + i; 16101c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt 1611e33afddca174171a68d57476ead8947476ab9240Paul Mundt info = ch->info; 16121c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt 16131c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt if (info->fbdefio) { 16148bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski ch->sglist = vmalloc(sizeof(struct scatterlist) * 16151c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt info->fix.smem_len >> PAGE_SHIFT); 16168bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski if (!ch->sglist) { 16171c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt dev_err(&pdev->dev, "cannot allocate sglist\n"); 16181c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt goto err1; 16191c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt } 16201c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt } 16211c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt 16223b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot info->bl_dev = ch->bl; 16233b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 16241c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt error = register_framebuffer(info); 1625cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error < 0) 1626cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 1627cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1628cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_info(info->dev, 1629cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm "registered %s/%s as %dx%d %dbpp.\n", 1630cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm pdev->name, 16311c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt (ch->cfg.chan == LCDC_CHAN_MAINLCD) ? 1632cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm "mainlcd" : "sublcd", 1633c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski info->var.xres, info->var.yres, 16341c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt ch->cfg.bpp); 16358564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 16368564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* deferred io mode: disable clock to save power */ 16376011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED) 16388564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_clk_off(priv); 1639cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1640cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 16416011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski /* Failure ignored */ 16426011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski priv->notifier.notifier_call = sh_mobile_lcdc_notify; 16436011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski fb_register_client(&priv->notifier); 16446011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 1645cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 16468bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetskierr1: 1647cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm sh_mobile_lcdc_remove(pdev); 16488bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski 1649cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return error; 1650cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 1651cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1652cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_remove(struct platform_device *pdev) 1653cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 1654cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev); 1655cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct fb_info *info; 1656cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int i; 1657cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 16586011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski fb_unregister_client(&priv->notifier); 16596011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 1660cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (i = 0; i < ARRAY_SIZE(priv->ch); i++) 16618bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski if (priv->ch[i].info && priv->ch[i].info->dev) 1662e33afddca174171a68d57476ead8947476ab9240Paul Mundt unregister_framebuffer(priv->ch[i].info); 1663cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1664cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm sh_mobile_lcdc_stop(priv); 1665cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1666cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (i = 0; i < ARRAY_SIZE(priv->ch); i++) { 1667e33afddca174171a68d57476ead8947476ab9240Paul Mundt info = priv->ch[i].info; 1668cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1669e33afddca174171a68d57476ead8947476ab9240Paul Mundt if (!info || !info->device) 1670cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm continue; 1671cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 16721c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt if (priv->ch[i].sglist) 16731c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt vfree(priv->ch[i].sglist); 16741c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt 16751ffbb037d8e81ba4f09901451b39c8f178b05559Magnus Damm if (info->screen_base) 16761ffbb037d8e81ba4f09901451b39c8f178b05559Magnus Damm dma_free_coherent(&pdev->dev, info->fix.smem_len, 16771ffbb037d8e81ba4f09901451b39c8f178b05559Magnus Damm info->screen_base, 16781ffbb037d8e81ba4f09901451b39c8f178b05559Magnus Damm priv->ch[i].dma_handle); 1679cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm fb_dealloc_cmap(&info->cmap); 1680e33afddca174171a68d57476ead8947476ab9240Paul Mundt framebuffer_release(info); 1681cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1682cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 16833b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot for (i = 0; i < ARRAY_SIZE(priv->ch); i++) { 16843b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot if (priv->ch[i].bl) 16853b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot sh_mobile_lcdc_bl_remove(priv->ch[i].bl); 16863b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot } 16873b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 1688b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm if (priv->dot_clk) 1689b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm clk_put(priv->dot_clk); 16900246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 16918bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski if (priv->dev) 16928bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski pm_runtime_disable(priv->dev); 1693cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1694cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (priv->base) 1695cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm iounmap(priv->base); 1696cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 16978564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (priv->irq) 16988564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm free_irq(priv->irq, priv); 1699cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm kfree(priv); 1700cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 1701cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 1702cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1703cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic struct platform_driver sh_mobile_lcdc_driver = { 1704cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .driver = { 1705cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .name = "sh_mobile_lcdc_fb", 1706cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .owner = THIS_MODULE, 17072feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm .pm = &sh_mobile_lcdc_dev_pm_ops, 1708cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm }, 1709cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .probe = sh_mobile_lcdc_probe, 1710cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .remove = sh_mobile_lcdc_remove, 1711cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 1712cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1713cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int __init sh_mobile_lcdc_init(void) 1714cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 1715cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return platform_driver_register(&sh_mobile_lcdc_driver); 1716cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 1717cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1718cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void __exit sh_mobile_lcdc_exit(void) 1719cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 1720cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm platform_driver_unregister(&sh_mobile_lcdc_driver); 1721cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 1722cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1723cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammmodule_init(sh_mobile_lcdc_init); 1724cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammmodule_exit(sh_mobile_lcdc_exit); 1725cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1726cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_DESCRIPTION("SuperH Mobile LCDC Framebuffer driver"); 1727cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_AUTHOR("Magnus Damm <damm@opensource.se>"); 1728cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_LICENSE("GPL v2"); 1729