sh_mobile_lcdcfb.c revision d2ecbab5960d9814a269d36723647d6ef391ba8f
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> 24225c9a8d1da274bf23efec43ec28b1c9e45e12f8Paul Mundt#include <video/sh_mobile_lcdc.h> 258564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm#include <asm/atomic.h> 26cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 276de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski#include "sh_mobile_lcdcfb.h" 286de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski 29a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy#define SIDE_B_OFFSET 0x1000 30a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy#define MIRROR_OFFSET 0x2000 31cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 32cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm/* shared registers */ 33cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDDCKR 0x410 34cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDDCKSTPR 0x414 35cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDINTR 0x468 36cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDSR 0x46c 37cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDCNT1R 0x470 38cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDCNT2R 0x474 399dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy#define _LDRCNTR 0x478 40cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDDDSR 0x47c 41cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDDWD0R 0x800 42cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDDRDR 0x840 43cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDDWAR 0x900 44cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDDRAR 0x904 45cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 460246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm/* shared registers and their order for context save/restore */ 470246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic int lcdc_shared_regs[] = { 480246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm _LDDCKR, 490246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm _LDDCKSTPR, 500246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm _LDINTR, 510246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm _LDDDSR, 520246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm _LDCNT1R, 530246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm _LDCNT2R, 540246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm}; 550246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm#define NR_SHARED_REGS ARRAY_SIZE(lcdc_shared_regs) 560246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 57d2ecbab5960d9814a269d36723647d6ef391ba8fGuennadi Liakhovetski#define MAX_XRES 1920 58d2ecbab5960d9814a269d36723647d6ef391ba8fGuennadi Liakhovetski#define MAX_YRES 1080 59cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 600246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = { 61cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDDCKPAT1R] = 0x400, 62cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDDCKPAT2R] = 0x404, 63cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMT1R] = 0x418, 64cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMT2R] = 0x41c, 65cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMT3R] = 0x420, 66cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDDFR] = 0x424, 67cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDSM1R] = 0x428, 688564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm [LDSM2R] = 0x42c, 69cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDSA1R] = 0x430, 70cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMLSR] = 0x438, 71cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDHCNR] = 0x448, 72cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDHSYNR] = 0x44c, 73cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDVLNR] = 0x450, 74cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDVSYNR] = 0x454, 75cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDPMR] = 0x460, 766011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski [LDHAJR] = 0x4a0, 77cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 78cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 790246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic unsigned long lcdc_offs_sublcd[NR_CH_REGS] = { 80cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDDCKPAT1R] = 0x408, 81cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDDCKPAT2R] = 0x40c, 82cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMT1R] = 0x600, 83cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMT2R] = 0x604, 84cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMT3R] = 0x608, 85cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDDFR] = 0x60c, 86cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDSM1R] = 0x610, 878564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm [LDSM2R] = 0x614, 88cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDSA1R] = 0x618, 89cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMLSR] = 0x620, 90cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDHCNR] = 0x624, 91cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDHSYNR] = 0x628, 92cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDVLNR] = 0x62c, 93cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDVSYNR] = 0x630, 94cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDPMR] = 0x63c, 95cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 96cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 97cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define START_LCDC 0x00000001 98cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define LCDC_RESET 0x00000100 99cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define DISPLAY_BEU 0x00000008 100cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define LCDC_ENABLE 0x00000001 1018564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm#define LDINTR_FE 0x00000400 1029dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy#define LDINTR_VSE 0x00000200 1039dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy#define LDINTR_VEE 0x00000100 1048564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm#define LDINTR_FS 0x00000004 1059dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy#define LDINTR_VSS 0x00000002 1069dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy#define LDINTR_VES 0x00000001 107a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy#define LDRCNTR_SRS 0x00020000 108a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy#define LDRCNTR_SRC 0x00010000 109a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy#define LDRCNTR_MRS 0x00000002 110a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy#define LDRCNTR_MRC 0x00000001 11140331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy#define LDSR_MRS 0x00000100 112cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 113c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetskistatic const struct fb_videomode default_720p = { 114c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski .name = "HDMI 720p", 115c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski .xres = 1280, 116c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski .yres = 720, 117c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski 1185ae0cf82df212253857326a6706018eccb658683Guennadi Liakhovetski .left_margin = 220, 1195ae0cf82df212253857326a6706018eccb658683Guennadi Liakhovetski .right_margin = 110, 1205ae0cf82df212253857326a6706018eccb658683Guennadi Liakhovetski .hsync_len = 40, 121c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski 122c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski .upper_margin = 20, 123c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski .lower_margin = 5, 124c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski .vsync_len = 5, 125c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski 126c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski .pixclock = 13468, 1275ae0cf82df212253857326a6706018eccb658683Guennadi Liakhovetski .refresh = 60, 128c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT, 1290246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm}; 1300246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 1310246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstruct sh_mobile_lcdc_priv { 1320246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm void __iomem *base; 1330246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm int irq; 1340246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm atomic_t hw_usecnt; 1350246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct device *dev; 1360246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct clk *dot_clk; 1370246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm unsigned long lddckr; 1380246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct sh_mobile_lcdc_chan ch[2]; 1396011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski struct notifier_block notifier; 1400246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm unsigned long saved_shared_regs[NR_SHARED_REGS]; 1410246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm int started; 1420246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm}; 1430246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 144a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthystatic bool banked(int reg_nr) 145a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy{ 146a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy switch (reg_nr) { 147a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDMT1R: 148a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDMT2R: 149a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDMT3R: 150a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDDFR: 151a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDSM1R: 152a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDSA1R: 153a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDMLSR: 154a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDHCNR: 155a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDHSYNR: 156a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDVLNR: 157a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDVSYNR: 158a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy return true; 159a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy } 160a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy return false; 161a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy} 162a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy 163cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_write_chan(struct sh_mobile_lcdc_chan *chan, 164cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int reg_nr, unsigned long data) 165cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 166cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr]); 167a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy if (banked(reg_nr)) 168a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr] + 169a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy SIDE_B_OFFSET); 170a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy} 171a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy 172a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthystatic void lcdc_write_chan_mirror(struct sh_mobile_lcdc_chan *chan, 173a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy int reg_nr, unsigned long data) 174a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy{ 175a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr] + 176a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy MIRROR_OFFSET); 177cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 178cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 179cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic unsigned long lcdc_read_chan(struct sh_mobile_lcdc_chan *chan, 180cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int reg_nr) 181cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 182cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return ioread32(chan->lcdc->base + chan->reg_offs[reg_nr]); 183cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 184cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 185cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_write(struct sh_mobile_lcdc_priv *priv, 186cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long reg_offs, unsigned long data) 187cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 188cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm iowrite32(data, priv->base + reg_offs); 189cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 190cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 191cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic unsigned long lcdc_read(struct sh_mobile_lcdc_priv *priv, 192cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long reg_offs) 193cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 194cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return ioread32(priv->base + reg_offs); 195cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 196cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 197cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_wait_bit(struct sh_mobile_lcdc_priv *priv, 198cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long reg_offs, 199cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long mask, unsigned long until) 200cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 201cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm while ((lcdc_read(priv, reg_offs) & mask) != until) 202cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm cpu_relax(); 203cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 204cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 205cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int lcdc_chan_is_sublcd(struct sh_mobile_lcdc_chan *chan) 206cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 207cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return chan->cfg.chan == LCDC_CHAN_SUBLCD; 208cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 209cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 210cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_sys_write_index(void *handle, unsigned long data) 211cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 212cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_chan *ch = handle; 213cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 214cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(ch->lcdc, _LDDWD0R, data | 0x10000000); 215cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); 216cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(ch->lcdc, _LDDWAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0)); 217909f10de5de81668e4d0a401f3cb5ca6b8a3d20dMagnus Damm lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); 218cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 219cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 220cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_sys_write_data(void *handle, unsigned long data) 221cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 222cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_chan *ch = handle; 223cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 224cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(ch->lcdc, _LDDWD0R, data | 0x11000000); 225cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); 226cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(ch->lcdc, _LDDWAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0)); 227909f10de5de81668e4d0a401f3cb5ca6b8a3d20dMagnus Damm lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); 228cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 229cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 230cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic unsigned long lcdc_sys_read_data(void *handle) 231cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 232cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_chan *ch = handle; 233cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 234cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(ch->lcdc, _LDDRDR, 0x01000000); 235cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); 236cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(ch->lcdc, _LDDRAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0)); 237cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm udelay(1); 238909f10de5de81668e4d0a401f3cb5ca6b8a3d20dMagnus Damm lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); 239cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 240ec56b66fed526e3b7dd58dba8945c405448f48d1Magnus Damm return lcdc_read(ch->lcdc, _LDDRDR) & 0x3ffff; 241cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 242cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 243cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstruct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = { 244cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_sys_write_index, 245cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_sys_write_data, 246cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_sys_read_data, 247cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 248cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 2498564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) 2508564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 2510246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm if (atomic_inc_and_test(&priv->hw_usecnt)) { 2520246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm pm_runtime_get_sync(priv->dev); 2538564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (priv->dot_clk) 2548564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm clk_enable(priv->dot_clk); 2558564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm } 2568564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 2578564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 2588564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv) 2598564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 2600246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm if (atomic_sub_return(1, &priv->hw_usecnt) == -1) { 2618564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (priv->dot_clk) 2628564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm clk_disable(priv->dot_clk); 2630246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm pm_runtime_put(priv->dev); 2648564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm } 2658564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 2668564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 2671c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundtstatic int sh_mobile_lcdc_sginit(struct fb_info *info, 2681c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt struct list_head *pagelist) 2691c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt{ 2701c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt struct sh_mobile_lcdc_chan *ch = info->par; 2711c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt unsigned int nr_pages_max = info->fix.smem_len >> PAGE_SHIFT; 2721c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt struct page *page; 2731c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt int nr_pages = 0; 2741c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt 2751c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt sg_init_table(ch->sglist, nr_pages_max); 2761c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt 2771c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt list_for_each_entry(page, pagelist, lru) 2781c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt sg_set_page(&ch->sglist[nr_pages++], page, PAGE_SIZE, 0); 2791c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt 2801c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt return nr_pages; 2811c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt} 2821c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt 2838564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_deferred_io(struct fb_info *info, 2848564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm struct list_head *pagelist) 2858564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 2868564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm struct sh_mobile_lcdc_chan *ch = info->par; 287ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm struct sh_mobile_lcdc_board_cfg *bcfg = &ch->cfg.board_cfg; 2888564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 2898564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* enable clocks before accessing hardware */ 2908564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_clk_on(ch->lcdc); 2918564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 2925c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt /* 2935c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * It's possible to get here without anything on the pagelist via 2945c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * sh_mobile_lcdc_deferred_io_touch() or via a userspace fsync() 2955c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * invocation. In the former case, the acceleration routines are 2965c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * stepped in to when using the framebuffer console causing the 2975c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * workqueue to be scheduled without any dirty pages on the list. 2985c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * 2995c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * Despite this, a panel update is still needed given that the 3005c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * acceleration routines have their own methods for writing in 3015c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * that still need to be updated. 3025c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * 3035c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * The fsync() and empty pagelist case could be optimized for, 3045c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * but we don't bother, as any application exhibiting such 3055c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * behaviour is fundamentally broken anyways. 3065c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt */ 3075c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt if (!list_empty(pagelist)) { 3085c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt unsigned int nr_pages = sh_mobile_lcdc_sginit(info, pagelist); 3095c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt 3105c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt /* trigger panel update */ 3115c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt dma_map_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE); 312ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm if (bcfg->start_transfer) 313ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm bcfg->start_transfer(bcfg->board_data, ch, 314ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm &sh_mobile_lcdc_sys_bus_ops); 3155c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt lcdc_write_chan(ch, LDSM2R, 1); 3165c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt dma_unmap_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE); 317ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm } else { 318ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm if (bcfg->start_transfer) 319ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm bcfg->start_transfer(bcfg->board_data, ch, 320ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm &sh_mobile_lcdc_sys_bus_ops); 3215c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt lcdc_write_chan(ch, LDSM2R, 1); 322ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm } 3238564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 3248564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 3258564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info) 3268564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 3278564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm struct fb_deferred_io *fbdefio = info->fbdefio; 3288564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 3298564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (fbdefio) 3308564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm schedule_delayed_work(&info->deferred_work, fbdefio->delay); 3318564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 3328564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 3338564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic irqreturn_t sh_mobile_lcdc_irq(int irq, void *data) 3348564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 3358564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm struct sh_mobile_lcdc_priv *priv = data; 3362feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm struct sh_mobile_lcdc_chan *ch; 3378564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm unsigned long tmp; 3389dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy unsigned long ldintr; 3392feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm int is_sub; 3402feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm int k; 3418564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 3428564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* acknowledge interrupt */ 3439dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy ldintr = tmp = lcdc_read(priv, _LDINTR); 3449dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy /* 3459dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy * disable further VSYNC End IRQs, preserve all other enabled IRQs, 3469dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy * write 0 to bits 0-6 to ack all triggered IRQs. 3479dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy */ 3489dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy tmp &= 0xffffff00 & ~LDINTR_VEE; 3498564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm lcdc_write(priv, _LDINTR, tmp); 3508564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 3512feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm /* figure out if this interrupt is for main or sub lcd */ 3522feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm is_sub = (lcdc_read(priv, _LDSR) & (1 << 10)) ? 1 : 0; 3532feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 3549dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy /* wake up channel and disable clocks */ 3552feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 3562feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm ch = &priv->ch[k]; 3572feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 3582feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm if (!ch->enabled) 3592feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm continue; 3602feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 3619dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy /* Frame Start */ 3629dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy if (ldintr & LDINTR_FS) { 3639dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy if (is_sub == lcdc_chan_is_sublcd(ch)) { 3649dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy ch->frame_end = 1; 3659dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy wake_up(&ch->frame_end_wait); 3662feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 3679dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy sh_mobile_lcdc_clk_off(priv); 3689dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy } 3699dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy } 3709dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy 3719dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy /* VSYNC End */ 37240331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy if (ldintr & LDINTR_VES) 37340331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy complete(&ch->vsync_completion); 3742feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm } 3752feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 3768564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm return IRQ_HANDLED; 3778564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 3788564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 379cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv, 380cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int start) 381cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 382cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long tmp = lcdc_read(priv, _LDCNT2R); 383cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int k; 384cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 385cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* start or stop the lcdc */ 386cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (start) 387cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDCNT2R, tmp | START_LCDC); 388cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm else 389cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDCNT2R, tmp & ~START_LCDC); 390cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 391cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* wait until power is applied/stopped on all channels */ 392cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) 393cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (lcdc_read(priv, _LDCNT2R) & priv->ch[k].enabled) 394cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm while (1) { 395cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp = lcdc_read_chan(&priv->ch[k], LDPMR) & 3; 396cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (start && tmp == 3) 397cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 398cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!start && tmp == 0) 399cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 400cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm cpu_relax(); 401cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 402cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 403cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!start) 404cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDDCKSTPR, 1); /* stop dotclock */ 405cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 406cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 4076011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetskistatic void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) 4086011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski{ 4091c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski struct fb_var_screeninfo *var = &ch->info->var, *display_var = &ch->display_var; 4101c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski unsigned long h_total, hsync_pos, display_h_total; 4116011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski u32 tmp; 4126011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 4136011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp = ch->ldmt1r_value; 4146011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1 << 28; 4156011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1 << 27; 4166011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp |= (ch->cfg.flags & LCDC_FLAGS_DWPOL) ? 1 << 26 : 0; 4176011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp |= (ch->cfg.flags & LCDC_FLAGS_DIPOL) ? 1 << 25 : 0; 4186011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp |= (ch->cfg.flags & LCDC_FLAGS_DAPOL) ? 1 << 24 : 0; 4196011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp |= (ch->cfg.flags & LCDC_FLAGS_HSCNT) ? 1 << 17 : 0; 4206011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp |= (ch->cfg.flags & LCDC_FLAGS_DWCNT) ? 1 << 16 : 0; 4216011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDMT1R, tmp); 4226011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 4236011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski /* setup SYS bus */ 4246011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDMT2R, ch->cfg.sys_bus_cfg.ldmt2r); 4256011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDMT3R, ch->cfg.sys_bus_cfg.ldmt3r); 4266011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 4276011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski /* horizontal configuration */ 4281c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski h_total = display_var->xres + display_var->hsync_len + 4291c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski display_var->left_margin + display_var->right_margin; 4306011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp = h_total / 8; /* HTCN */ 4311c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski tmp |= (min(display_var->xres, var->xres) / 8) << 16; /* HDCN */ 4326011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDHCNR, tmp); 4336011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 4341c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski hsync_pos = display_var->xres + display_var->right_margin; 4356011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp = hsync_pos / 8; /* HSYNP */ 4361c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski tmp |= (display_var->hsync_len / 8) << 16; /* HSYNW */ 4376011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDHSYNR, tmp); 4386011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 4396011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski /* vertical configuration */ 4401c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski tmp = display_var->yres + display_var->vsync_len + 4411c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski display_var->upper_margin + display_var->lower_margin; /* VTLN */ 4421c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski tmp |= min(display_var->yres, var->yres) << 16; /* VDLN */ 4436011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDVLNR, tmp); 4446011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 4451c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski tmp = display_var->yres + display_var->lower_margin; /* VSYNP */ 4461c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski tmp |= display_var->vsync_len << 16; /* VSYNW */ 4476011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDVSYNR, tmp); 4486011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 4496011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski /* Adjust horizontal synchronisation for HDMI */ 4501c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski display_h_total = display_var->xres + display_var->hsync_len + 4511c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski display_var->left_margin + display_var->right_margin; 4521c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski tmp = ((display_var->xres & 7) << 24) | 4531c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski ((display_h_total & 7) << 16) | 4541c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski ((display_var->hsync_len & 7) << 8) | 4556011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski hsync_pos; 4566011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDHAJR, tmp); 4576011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski} 4586011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 459cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) 460cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 461cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_chan *ch; 462cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_board_cfg *board_cfg; 463cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long tmp; 464cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int k, m; 465cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int ret = 0; 466cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 4678564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* enable clocks before accessing the hardware */ 4688564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) 4698564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (priv->ch[k].enabled) 4708564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_clk_on(priv); 4718564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 472cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* reset */ 473cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LCDC_RESET); 474cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_wait_bit(priv, _LDCNT2R, LCDC_RESET, 0); 475cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 476cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* enable LCDC channels */ 477cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp = lcdc_read(priv, _LDCNT2R); 478cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp |= priv->ch[0].enabled; 479cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp |= priv->ch[1].enabled; 480cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDCNT2R, tmp); 481cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 482cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* read data from external memory, avoid using the BEU for now */ 483cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) & ~DISPLAY_BEU); 484cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 485cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* stop the lcdc first */ 486cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm sh_mobile_lcdc_start_stop(priv, 0); 487cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 488cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* configure clocks */ 489cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp = priv->lddckr; 490cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 491cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ch = &priv->ch[k]; 492cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 493cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!priv->ch[k].enabled) 494cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm continue; 495cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 496cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm m = ch->cfg.clock_divider; 497cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!m) 498cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm continue; 499cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 500cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (m == 1) 501cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm m = 1 << 6; 502cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0); 503cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 504dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski /* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider denominator */ 5051c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski lcdc_write_chan(ch, LDDCKPAT1R, 0); 506cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1); 507cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 508cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 509cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDDCKR, tmp); 510cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 511cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* start dotclock again */ 512cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDDCKSTPR, 0); 513cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0); 514cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 5158564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* interrupts are disabled to begin with */ 516cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDINTR, 0); 517cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 518cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 519cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ch = &priv->ch[k]; 520cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 521cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!ch->enabled) 522cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm continue; 523cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 5246011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski sh_mobile_lcdc_geometry(ch); 525cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 526cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* power supply */ 527cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write_chan(ch, LDPMR, 0); 528cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 529cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm board_cfg = &ch->cfg.board_cfg; 530cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (board_cfg->setup_sys) 531cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ret = board_cfg->setup_sys(board_cfg->board_data, ch, 532cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm &sh_mobile_lcdc_sys_bus_ops); 533cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (ret) 534cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return ret; 535cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 536cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 537cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* word and long word swap */ 538cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 6); 539cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 540cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 541cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ch = &priv->ch[k]; 542cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 543cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!priv->ch[k].enabled) 544cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm continue; 545cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 546cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* set bpp format in PKF[4:0] */ 547cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp = lcdc_read_chan(ch, LDDFR); 5481c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski tmp &= ~0x0001001f; 549e33afddca174171a68d57476ead8947476ab9240Paul Mundt tmp |= (ch->info->var.bits_per_pixel == 16) ? 3 : 0; 550cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write_chan(ch, LDDFR, tmp); 551cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 552cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* point out our frame buffer */ 553e33afddca174171a68d57476ead8947476ab9240Paul Mundt lcdc_write_chan(ch, LDSA1R, ch->info->fix.smem_start); 554cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 555cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* set line size */ 556e33afddca174171a68d57476ead8947476ab9240Paul Mundt lcdc_write_chan(ch, LDMLSR, ch->info->fix.line_length); 557cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 5588564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* setup deferred io if SYS bus */ 5598564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm tmp = ch->cfg.sys_bus_cfg.deferred_io_msec; 5608564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (ch->ldmt1r_value & (1 << 12) && tmp) { 5618564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm ch->defio.deferred_io = sh_mobile_lcdc_deferred_io; 5628564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm ch->defio.delay = msecs_to_jiffies(tmp); 563e33afddca174171a68d57476ead8947476ab9240Paul Mundt ch->info->fbdefio = &ch->defio; 564e33afddca174171a68d57476ead8947476ab9240Paul Mundt fb_deferred_io_init(ch->info); 5658564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 5668564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* one-shot mode */ 5678564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm lcdc_write_chan(ch, LDSM1R, 1); 5688564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 5698564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* enable "Frame End Interrupt Enable" bit */ 5708564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm lcdc_write(priv, _LDINTR, LDINTR_FE); 5718564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 5728564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm } else { 5738564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* continuous read mode */ 5748564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm lcdc_write_chan(ch, LDSM1R, 0); 5758564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm } 576cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 577cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 578cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* display output */ 579cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDCNT1R, LCDC_ENABLE); 580cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 581cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* start the lcdc */ 582cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm sh_mobile_lcdc_start_stop(priv, 1); 5838e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm priv->started = 1; 584cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 585cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* tell the board code to enable the panel */ 586cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 587cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ch = &priv->ch[k]; 58821bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm if (!ch->enabled) 58921bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm continue; 59021bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm 591cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm board_cfg = &ch->cfg.board_cfg; 5926de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski if (try_module_get(board_cfg->owner) && board_cfg->display_on) { 593c2439398170be9d7af28eb3ab59593369cb303f3Guennadi Liakhovetski board_cfg->display_on(board_cfg->board_data, ch->info); 5946de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski module_put(board_cfg->owner); 5956de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski } 596cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 597cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 598cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 599cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 600cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 601cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) 602cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 603cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_chan *ch; 604cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_board_cfg *board_cfg; 605cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int k; 606cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 6072feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm /* clean up deferred io and ask board code to disable panel */ 608cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 609cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ch = &priv->ch[k]; 61021bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm if (!ch->enabled) 61121bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm continue; 6128564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 6132feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm /* deferred io mode: 6142feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm * flush frame, and wait for frame end interrupt 6152feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm * clean up deferred io and enable clock 6162feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm */ 6175ef6b505d9df45558402bdb823a078840a6a26c4Guennadi Liakhovetski if (ch->info && ch->info->fbdefio) { 6182feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm ch->frame_end = 0; 619e33afddca174171a68d57476ead8947476ab9240Paul Mundt schedule_delayed_work(&ch->info->deferred_work, 0); 6202feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm wait_event(ch->frame_end_wait, ch->frame_end); 621e33afddca174171a68d57476ead8947476ab9240Paul Mundt fb_deferred_io_cleanup(ch->info); 622e33afddca174171a68d57476ead8947476ab9240Paul Mundt ch->info->fbdefio = NULL; 6232feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm sh_mobile_lcdc_clk_on(priv); 6248564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm } 6252feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 6262feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm board_cfg = &ch->cfg.board_cfg; 6276de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski if (try_module_get(board_cfg->owner) && board_cfg->display_off) { 6282feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm board_cfg->display_off(board_cfg->board_data); 6296de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski module_put(board_cfg->owner); 6306de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski } 631cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 632cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 633cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* stop the lcdc */ 6348e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm if (priv->started) { 6358e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm sh_mobile_lcdc_start_stop(priv, 0); 6368e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm priv->started = 0; 6378e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm } 638b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm 6398564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* stop clocks */ 6408564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) 6418564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (priv->ch[k].enabled) 6428564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_clk_off(priv); 643cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 644cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 645cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch) 646cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 647cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int ifm, miftyp; 648cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 649cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm switch (ch->cfg.interface_type) { 650cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case RGB8: ifm = 0; miftyp = 0; break; 651cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case RGB9: ifm = 0; miftyp = 4; break; 652cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case RGB12A: ifm = 0; miftyp = 5; break; 653cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case RGB12B: ifm = 0; miftyp = 6; break; 654cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case RGB16: ifm = 0; miftyp = 7; break; 655cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case RGB18: ifm = 0; miftyp = 10; break; 656cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case RGB24: ifm = 0; miftyp = 11; break; 657cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS8A: ifm = 1; miftyp = 0; break; 658cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS8B: ifm = 1; miftyp = 1; break; 659cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS8C: ifm = 1; miftyp = 2; break; 660cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS8D: ifm = 1; miftyp = 3; break; 661cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS9: ifm = 1; miftyp = 4; break; 662cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS12: ifm = 1; miftyp = 5; break; 663cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS16A: ifm = 1; miftyp = 7; break; 664cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS16B: ifm = 1; miftyp = 8; break; 665cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS16C: ifm = 1; miftyp = 9; break; 666cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS18: ifm = 1; miftyp = 10; break; 667cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS24: ifm = 1; miftyp = 11; break; 668cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm default: goto bad; 669cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 670cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 671cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* SUBLCD only supports SYS interface */ 672cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (lcdc_chan_is_sublcd(ch)) { 673cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (ifm == 0) 674cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto bad; 675cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm else 676cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ifm = 0; 677cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 678cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 679cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ch->ldmt1r_value = (ifm << 12) | miftyp; 680cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 681cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm bad: 682cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return -EINVAL; 683cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 684cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 685b51339fff240ff179730f8963a758147fd60f3ecMagnus Dammstatic int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev, 686b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm int clock_source, 687cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_priv *priv) 688cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 689cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm char *str; 690cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int icksel; 691cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 692cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm switch (clock_source) { 693cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case LCDC_CLK_BUS: str = "bus_clk"; icksel = 0; break; 694cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case LCDC_CLK_PERIPHERAL: str = "peripheral_clk"; icksel = 1; break; 695cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case LCDC_CLK_EXTERNAL: str = NULL; icksel = 2; break; 696cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm default: 697cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return -EINVAL; 698cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 699cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 700cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm priv->lddckr = icksel << 16; 701cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 702cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (str) { 703b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm priv->dot_clk = clk_get(&pdev->dev, str); 704b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm if (IS_ERR(priv->dot_clk)) { 705b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm dev_err(&pdev->dev, "cannot get dot clock %s\n", str); 706b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm return PTR_ERR(priv->dot_clk); 707cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 708cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 7090246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 7100246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm /* Runtime PM support involves two step for this driver: 7110246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm * 1) Enable Runtime PM 7120246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm * 2) Force Runtime PM Resume since hardware is accessed from probe() 7130246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm */ 7148bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski priv->dev = &pdev->dev; 7150246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm pm_runtime_enable(priv->dev); 7160246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm pm_runtime_resume(priv->dev); 717cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 718cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 719cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 720cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_setcolreg(u_int regno, 721cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm u_int red, u_int green, u_int blue, 722cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm u_int transp, struct fb_info *info) 723cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 724cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm u32 *palette = info->pseudo_palette; 725cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 726cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (regno >= PALETTE_NR) 727cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return -EINVAL; 728cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 729cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* only FB_VISUAL_TRUECOLOR supported */ 730cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 731cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm red >>= 16 - info->var.red.length; 732cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm green >>= 16 - info->var.green.length; 733cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm blue >>= 16 - info->var.blue.length; 734cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm transp >>= 16 - info->var.transp.length; 735cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 736cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm palette[regno] = (red << info->var.red.offset) | 737cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm (green << info->var.green.offset) | 738cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm (blue << info->var.blue.offset) | 739cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm (transp << info->var.transp.offset); 740cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 741cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 742cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 743cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 744cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic struct fb_fix_screeninfo sh_mobile_lcdc_fix = { 745cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .id = "SH Mobile LCDC", 746cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .type = FB_TYPE_PACKED_PIXELS, 747cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .visual = FB_VISUAL_TRUECOLOR, 748cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .accel = FB_ACCEL_NONE, 7499dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy .xpanstep = 0, 7509dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy .ypanstep = 1, 7519dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy .ywrapstep = 0, 752cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 753cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 7548564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_fillrect(struct fb_info *info, 7558564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm const struct fb_fillrect *rect) 7568564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 7578564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sys_fillrect(info, rect); 7588564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_deferred_io_touch(info); 7598564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 7608564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 7618564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_copyarea(struct fb_info *info, 7628564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm const struct fb_copyarea *area) 7638564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 7648564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sys_copyarea(info, area); 7658564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_deferred_io_touch(info); 7668564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 7678564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 7688564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_imageblit(struct fb_info *info, 7698564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm const struct fb_image *image) 7708564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 7718564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sys_imageblit(info, image); 7728564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_deferred_io_touch(info); 7738564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 7748564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 7759dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthystatic int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, 7769dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy struct fb_info *info) 7779dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy{ 7789dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy struct sh_mobile_lcdc_chan *ch = info->par; 77992e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy struct sh_mobile_lcdc_priv *priv = ch->lcdc; 78092e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy unsigned long ldrcntr; 78192e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy unsigned long new_pan_offset; 78292e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy 78392e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy new_pan_offset = (var->yoffset * info->fix.line_length) + 78492e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy (var->xoffset * (info->var.bits_per_pixel / 8)); 7859dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy 78692e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy if (new_pan_offset == ch->pan_offset) 7879dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy return 0; /* No change, do nothing */ 7889dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy 78992e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy ldrcntr = lcdc_read(priv, _LDRCNTR); 7909dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy 79192e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy /* Set the source address for the next refresh */ 79292e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy lcdc_write_chan_mirror(ch, LDSA1R, ch->dma_handle + new_pan_offset); 79392e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy if (lcdc_chan_is_sublcd(ch)) 79492e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS); 79592e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy else 79692e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_MRS); 79792e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy 79892e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy ch->pan_offset = new_pan_offset; 79992e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy 80092e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy sh_mobile_lcdc_deferred_io_touch(info); 8019dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy 8029dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy return 0; 8039dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy} 8049dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy 80540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthystatic int sh_mobile_wait_for_vsync(struct fb_info *info) 80640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy{ 80740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy struct sh_mobile_lcdc_chan *ch = info->par; 80840331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy unsigned long ldintr; 80940331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy int ret; 81040331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 81140331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy /* Enable VSync End interrupt */ 81240331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy ldintr = lcdc_read(ch->lcdc, _LDINTR); 81340331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy ldintr |= LDINTR_VEE; 81440331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy lcdc_write(ch->lcdc, _LDINTR, ldintr); 81540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 81640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion, 81740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy msecs_to_jiffies(100)); 81840331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy if (!ret) 81940331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy return -ETIMEDOUT; 82040331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 82140331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy return 0; 82240331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy} 82340331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 82440331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthystatic int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd, 82540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy unsigned long arg) 82640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy{ 82740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy int retval; 82840331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 82940331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy switch (cmd) { 83040331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy case FBIO_WAITFORVSYNC: 83140331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy retval = sh_mobile_wait_for_vsync(info); 83240331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy break; 83340331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 83440331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy default: 83540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy retval = -ENOIOCTLCMD; 83640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy break; 83740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy } 83840331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy return retval; 83940331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy} 84040331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 841dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetskistatic void sh_mobile_fb_reconfig(struct fb_info *info) 842dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{ 843dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski struct sh_mobile_lcdc_chan *ch = info->par; 844dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski struct fb_videomode mode1, mode2; 845dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski struct fb_event event; 846dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski int evnt = FB_EVENT_MODE_CHANGE_ALL; 847dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 848dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski if (ch->use_count > 1 || (ch->use_count == 1 && !info->fbcon_par)) 849dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski /* More framebuffer users are active */ 850dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski return; 851dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 852dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski fb_var_to_videomode(&mode1, &ch->display_var); 853dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski fb_var_to_videomode(&mode2, &info->var); 854dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 855dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski if (fb_mode_is_equal(&mode1, &mode2)) 856dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski return; 857dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 858dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski /* Display has been re-plugged, framebuffer is free now, reconfigure */ 859dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski if (fb_set_var(info, &ch->display_var) < 0) 860dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski /* Couldn't reconfigure, hopefully, can continue as before */ 861dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski return; 862dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 863dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski info->fix.line_length = mode2.xres * (ch->cfg.bpp / 8); 864dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 865dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski /* 866dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski * fb_set_var() calls the notifier change internally, only if 867dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski * FBINFO_MISC_USEREVENT flag is set. Since we do not want to fake a 868dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski * user event, we have to call the chain ourselves. 869dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski */ 870dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski event.info = info; 871dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski event.data = &mode2; 872dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski fb_notifier_call_chain(evnt, &event); 873dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski} 874dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 875dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski/* 876dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski * Locking: both .fb_release() and .fb_open() are called with info->lock held if 877dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski * user == 1, or with console sem held, if user == 0. 878dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski */ 879dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetskistatic int sh_mobile_release(struct fb_info *info, int user) 880dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{ 881dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski struct sh_mobile_lcdc_chan *ch = info->par; 882dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 883dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski mutex_lock(&ch->open_lock); 884dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count); 885dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 886dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski ch->use_count--; 887dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 888dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski /* Nothing to reconfigure, when called from fbcon */ 889dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski if (user) { 890dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski acquire_console_sem(); 891dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski sh_mobile_fb_reconfig(info); 892dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski release_console_sem(); 893dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski } 894dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 895dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski mutex_unlock(&ch->open_lock); 896dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 897dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski return 0; 898dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski} 899dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 900dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetskistatic int sh_mobile_open(struct fb_info *info, int user) 901dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{ 902dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski struct sh_mobile_lcdc_chan *ch = info->par; 903dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 904dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski mutex_lock(&ch->open_lock); 905dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski ch->use_count++; 906dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 907dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count); 908dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski mutex_unlock(&ch->open_lock); 909dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 910dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski return 0; 911dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski} 912dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 913dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetskistatic int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 914dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{ 915dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski struct sh_mobile_lcdc_chan *ch = info->par; 916dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 917d2ecbab5960d9814a269d36723647d6ef391ba8fGuennadi Liakhovetski if (var->xres > MAX_XRES || var->yres > MAX_YRES || 918dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski var->xres * var->yres * (ch->cfg.bpp / 8) * 2 > info->fix.smem_len) { 919d2ecbab5960d9814a269d36723647d6ef391ba8fGuennadi Liakhovetski dev_warn(info->dev, "Invalid info: %u-%u-%u-%u x %u-%u-%u-%u @ %ukHz!\n", 920d2ecbab5960d9814a269d36723647d6ef391ba8fGuennadi Liakhovetski var->left_margin, var->xres, var->right_margin, var->hsync_len, 921d2ecbab5960d9814a269d36723647d6ef391ba8fGuennadi Liakhovetski var->upper_margin, var->yres, var->lower_margin, var->vsync_len, 922d2ecbab5960d9814a269d36723647d6ef391ba8fGuennadi Liakhovetski PICOS2KHZ(var->pixclock)); 923dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski return -EINVAL; 924dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski } 925dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski return 0; 926dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski} 92740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 928cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic struct fb_ops sh_mobile_lcdc_ops = { 9299dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy .owner = THIS_MODULE, 930cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .fb_setcolreg = sh_mobile_lcdc_setcolreg, 9312540c111ead82cad605ec2b14a1905ad914cc124Magnus Damm .fb_read = fb_sys_read, 9322540c111ead82cad605ec2b14a1905ad914cc124Magnus Damm .fb_write = fb_sys_write, 9338564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm .fb_fillrect = sh_mobile_lcdc_fillrect, 9348564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm .fb_copyarea = sh_mobile_lcdc_copyarea, 9358564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm .fb_imageblit = sh_mobile_lcdc_imageblit, 9369dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy .fb_pan_display = sh_mobile_fb_pan_display, 93740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy .fb_ioctl = sh_mobile_ioctl, 938dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski .fb_open = sh_mobile_open, 939dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski .fb_release = sh_mobile_release, 940dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski .fb_check_var = sh_mobile_check_var, 941cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 942cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 943cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp) 944cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 945cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm switch (bpp) { 946cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case 16: /* PKF[4:0] = 00011 - RGB 565 */ 947cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->red.offset = 11; 948cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->red.length = 5; 949cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->green.offset = 5; 950cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->green.length = 6; 951cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->blue.offset = 0; 952cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->blue.length = 5; 953cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->transp.offset = 0; 954cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->transp.length = 0; 955cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 956cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 957cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case 32: /* PKF[4:0] = 00000 - RGB 888 958cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm * sh7722 pdf says 00RRGGBB but reality is GGBB00RR 959cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm * this may be because LDDDSR has word swap enabled.. 960cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm */ 961cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->red.offset = 0; 962cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->red.length = 8; 963cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->green.offset = 24; 964cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->green.length = 8; 965cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->blue.offset = 16; 966cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->blue.length = 8; 967cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->transp.offset = 0; 968cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->transp.length = 0; 969cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 970cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm default: 971cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return -EINVAL; 972cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 973cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->bits_per_pixel = bpp; 974cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->red.msb_right = 0; 975cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->green.msb_right = 0; 976cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->blue.msb_right = 0; 977cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->transp.msb_right = 0; 978cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 979cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 980cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 9812feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Dammstatic int sh_mobile_lcdc_suspend(struct device *dev) 9822feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm{ 9832feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm struct platform_device *pdev = to_platform_device(dev); 9842feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 9852feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm sh_mobile_lcdc_stop(platform_get_drvdata(pdev)); 9862feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm return 0; 9872feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm} 9882feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 9892feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Dammstatic int sh_mobile_lcdc_resume(struct device *dev) 9902feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm{ 9912feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm struct platform_device *pdev = to_platform_device(dev); 9922feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 9932feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm return sh_mobile_lcdc_start(platform_get_drvdata(pdev)); 9942feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm} 9952feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 9960246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic int sh_mobile_lcdc_runtime_suspend(struct device *dev) 9970246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm{ 9980246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct platform_device *pdev = to_platform_device(dev); 9990246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct sh_mobile_lcdc_priv *p = platform_get_drvdata(pdev); 10000246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct sh_mobile_lcdc_chan *ch; 10010246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm int k, n; 10020246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 10030246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm /* save per-channel registers */ 10040246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm for (k = 0; k < ARRAY_SIZE(p->ch); k++) { 10050246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm ch = &p->ch[k]; 10060246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm if (!ch->enabled) 10070246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm continue; 10080246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm for (n = 0; n < NR_CH_REGS; n++) 10090246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm ch->saved_ch_regs[n] = lcdc_read_chan(ch, n); 10100246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm } 10110246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 10120246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm /* save shared registers */ 10130246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm for (n = 0; n < NR_SHARED_REGS; n++) 10140246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm p->saved_shared_regs[n] = lcdc_read(p, lcdc_shared_regs[n]); 10150246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 10160246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm /* turn off LCDC hardware */ 10170246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm lcdc_write(p, _LDCNT1R, 0); 10180246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm return 0; 10190246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm} 10200246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 10210246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic int sh_mobile_lcdc_runtime_resume(struct device *dev) 10220246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm{ 10230246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct platform_device *pdev = to_platform_device(dev); 10240246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct sh_mobile_lcdc_priv *p = platform_get_drvdata(pdev); 10250246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct sh_mobile_lcdc_chan *ch; 10260246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm int k, n; 10270246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 10280246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm /* restore per-channel registers */ 10290246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm for (k = 0; k < ARRAY_SIZE(p->ch); k++) { 10300246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm ch = &p->ch[k]; 10310246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm if (!ch->enabled) 10320246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm continue; 10330246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm for (n = 0; n < NR_CH_REGS; n++) 10340246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm lcdc_write_chan(ch, n, ch->saved_ch_regs[n]); 10350246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm } 10360246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 10370246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm /* restore shared registers */ 10380246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm for (n = 0; n < NR_SHARED_REGS; n++) 10390246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm lcdc_write(p, lcdc_shared_regs[n], p->saved_shared_regs[n]); 10400246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 10410246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm return 0; 10420246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm} 10430246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 1044471452104b8520337ae2fb48c4e61cd4896e025dAlexey Dobriyanstatic const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = { 10452feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm .suspend = sh_mobile_lcdc_suspend, 10462feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm .resume = sh_mobile_lcdc_resume, 10470246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm .runtime_suspend = sh_mobile_lcdc_runtime_suspend, 10480246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm .runtime_resume = sh_mobile_lcdc_runtime_resume, 10492feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm}; 10502feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 10516de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski/* locking: called with info->lock held */ 10526011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetskistatic int sh_mobile_lcdc_notify(struct notifier_block *nb, 10536011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski unsigned long action, void *data) 10546011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski{ 10556011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski struct fb_event *event = data; 10566011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski struct fb_info *info = event->info; 10576011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski struct sh_mobile_lcdc_chan *ch = info->par; 10586011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg; 1059afe417c0355154c8b2547619771d6053b3c0aad7Guennadi Liakhovetski int ret; 10606011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 10616011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski if (&ch->lcdc->notifier != nb) 1062baf163749952ca5e33dd2d6a74da023e385c3a00Guennadi Liakhovetski return NOTIFY_DONE; 10636011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 10646011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski dev_dbg(info->dev, "%s(): action = %lu, data = %p\n", 10656011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski __func__, action, event->data); 10666011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 10676011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski switch(action) { 10686011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski case FB_EVENT_SUSPEND: 10696de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski if (try_module_get(board_cfg->owner) && board_cfg->display_off) { 10706011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski board_cfg->display_off(board_cfg->board_data); 10716de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski module_put(board_cfg->owner); 10726de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski } 10736011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski pm_runtime_put(info->device); 1074afe417c0355154c8b2547619771d6053b3c0aad7Guennadi Liakhovetski sh_mobile_lcdc_stop(ch->lcdc); 10756011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski break; 10766011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski case FB_EVENT_RESUME: 1077dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski mutex_lock(&ch->open_lock); 1078dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski sh_mobile_fb_reconfig(info); 1079dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski mutex_unlock(&ch->open_lock); 10806011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 10816011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski /* HDMI must be enabled before LCDC configuration */ 10826de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski if (try_module_get(board_cfg->owner) && board_cfg->display_on) { 1083dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski board_cfg->display_on(board_cfg->board_data, info); 10846de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski module_put(board_cfg->owner); 10856011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski } 10866011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 1087afe417c0355154c8b2547619771d6053b3c0aad7Guennadi Liakhovetski ret = sh_mobile_lcdc_start(ch->lcdc); 1088afe417c0355154c8b2547619771d6053b3c0aad7Guennadi Liakhovetski if (!ret) 1089afe417c0355154c8b2547619771d6053b3c0aad7Guennadi Liakhovetski pm_runtime_get_sync(info->device); 10906011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski } 10916011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 1092baf163749952ca5e33dd2d6a74da023e385c3a00Guennadi Liakhovetski return NOTIFY_OK; 10936011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski} 10946011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 1095cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_remove(struct platform_device *pdev); 1096cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1097c2e13037e6794bd0d9de3f9ecabf5615f15c160bUwe Kleine-Königstatic int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) 1098cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 1099cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct fb_info *info; 1100cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_priv *priv; 110101ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski struct sh_mobile_lcdc_info *pdata = pdev->dev.platform_data; 1102cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct resource *res; 1103cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int error; 1104cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm void *buf; 1105cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int i, j; 1106cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 110701ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski if (!pdata) { 1108cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "no platform data defined\n"); 11098bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski return -EINVAL; 1110cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1111cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1112cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 11138564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm i = platform_get_irq(pdev, 0); 11148564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (!res || i < 0) { 11158564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm dev_err(&pdev->dev, "cannot get platform resources\n"); 11168bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski return -ENOENT; 1117cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1118cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1119cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm priv = kzalloc(sizeof(*priv), GFP_KERNEL); 1120cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!priv) { 1121cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "cannot allocate device data\n"); 11228bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski return -ENOMEM; 1123cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1124cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 11258bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski platform_set_drvdata(pdev, priv); 11268bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski 11278564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm error = request_irq(i, sh_mobile_lcdc_irq, IRQF_DISABLED, 11287ad33e74857f16f1202cbc5746faf52e88e8b376Kay Sievers dev_name(&pdev->dev), priv); 11298564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (error) { 11308564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm dev_err(&pdev->dev, "unable to request irq\n"); 11318564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm goto err1; 11328564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm } 11338564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 11348564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm priv->irq = i; 11355ef6b505d9df45558402bdb823a078840a6a26c4Guennadi Liakhovetski atomic_set(&priv->hw_usecnt, -1); 1136cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1137cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm j = 0; 1138cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (i = 0; i < ARRAY_SIZE(pdata->ch); i++) { 113901ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski struct sh_mobile_lcdc_chan *ch = priv->ch + j; 1140cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 114101ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski ch->lcdc = priv; 114201ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski memcpy(&ch->cfg, &pdata->ch[i], sizeof(pdata->ch[i])); 1143cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 114401ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski error = sh_mobile_lcdc_check_interface(ch); 1145cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error) { 1146cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "unsupported interface type\n"); 1147cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 1148cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 114901ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski init_waitqueue_head(&ch->frame_end_wait); 115001ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski init_completion(&ch->vsync_completion); 115101ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski ch->pan_offset = 0; 1152cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1153cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm switch (pdata->ch[i].chan) { 1154cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case LCDC_CHAN_MAINLCD: 115501ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski ch->enabled = 1 << 1; 115601ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski ch->reg_offs = lcdc_offs_mainlcd; 1157cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm j++; 1158cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 1159cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case LCDC_CHAN_SUBLCD: 116001ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski ch->enabled = 1 << 2; 116101ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski ch->reg_offs = lcdc_offs_sublcd; 1162cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm j++; 1163cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 1164cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1165cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1166cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1167cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!j) { 1168cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "no channels defined\n"); 1169cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm error = -EINVAL; 1170cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 1171cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1172cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1173dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski priv->base = ioremap_nocache(res->start, resource_size(res)); 1174dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski if (!priv->base) 1175dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski goto err1; 1176dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski 1177b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm error = sh_mobile_lcdc_setup_clocks(pdev, pdata->clock_source, priv); 1178cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error) { 1179cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "unable to setup clocks\n"); 1180cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 1181cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1182cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1183cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (i = 0; i < j; i++) { 11846011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski struct fb_var_screeninfo *var; 118571d3b0fcadf70d0de1ad334f48c9a4060209091aGuennadi Liakhovetski const struct fb_videomode *lcd_cfg, *max_cfg = NULL; 118601ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski struct sh_mobile_lcdc_chan *ch = priv->ch + i; 1187c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski struct sh_mobile_lcdc_chan_cfg *cfg = &ch->cfg; 1188c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski const struct fb_videomode *mode = cfg->lcd_cfg; 118971d3b0fcadf70d0de1ad334f48c9a4060209091aGuennadi Liakhovetski unsigned long max_size = 0; 119071d3b0fcadf70d0de1ad334f48c9a4060209091aGuennadi Liakhovetski int k; 11915fd284e6cd39f731db86dfd2440553365d5fad4dGuennadi Liakhovetski int num_cfg; 1192cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 119301ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski ch->info = framebuffer_alloc(0, &pdev->dev); 119401ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski if (!ch->info) { 1195e33afddca174171a68d57476ead8947476ab9240Paul Mundt dev_err(&pdev->dev, "unable to allocate fb_info\n"); 1196e33afddca174171a68d57476ead8947476ab9240Paul Mundt error = -ENOMEM; 1197e33afddca174171a68d57476ead8947476ab9240Paul Mundt break; 1198e33afddca174171a68d57476ead8947476ab9240Paul Mundt } 1199e33afddca174171a68d57476ead8947476ab9240Paul Mundt 120001ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski info = ch->info; 12016011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski var = &info->var; 1202cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->fbops = &sh_mobile_lcdc_ops; 1203c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski info->par = ch; 1204dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1205dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski mutex_init(&ch->open_lock); 1206dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1207c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski for (k = 0, lcd_cfg = mode; 1208c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski k < cfg->num_cfg && lcd_cfg; 120971d3b0fcadf70d0de1ad334f48c9a4060209091aGuennadi Liakhovetski k++, lcd_cfg++) { 121071d3b0fcadf70d0de1ad334f48c9a4060209091aGuennadi Liakhovetski unsigned long size = lcd_cfg->yres * lcd_cfg->xres; 121171d3b0fcadf70d0de1ad334f48c9a4060209091aGuennadi Liakhovetski 121271d3b0fcadf70d0de1ad334f48c9a4060209091aGuennadi Liakhovetski if (size > max_size) { 121371d3b0fcadf70d0de1ad334f48c9a4060209091aGuennadi Liakhovetski max_cfg = lcd_cfg; 121471d3b0fcadf70d0de1ad334f48c9a4060209091aGuennadi Liakhovetski max_size = size; 121571d3b0fcadf70d0de1ad334f48c9a4060209091aGuennadi Liakhovetski } 121671d3b0fcadf70d0de1ad334f48c9a4060209091aGuennadi Liakhovetski } 121771d3b0fcadf70d0de1ad334f48c9a4060209091aGuennadi Liakhovetski 1218c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski if (!mode) 1219d2ecbab5960d9814a269d36723647d6ef391ba8fGuennadi Liakhovetski max_size = MAX_XRES * MAX_YRES; 1220c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski else if (max_cfg) 1221c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski dev_dbg(&pdev->dev, "Found largest videomode %ux%u\n", 1222c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski max_cfg->xres, max_cfg->yres); 122371d3b0fcadf70d0de1ad334f48c9a4060209091aGuennadi Liakhovetski 1224cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->fix = sh_mobile_lcdc_fix; 122571d3b0fcadf70d0de1ad334f48c9a4060209091aGuennadi Liakhovetski info->fix.smem_len = max_size * (cfg->bpp / 8) * 2; 1226cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 12275fd284e6cd39f731db86dfd2440553365d5fad4dGuennadi Liakhovetski if (!mode) { 1228c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski mode = &default_720p; 12295fd284e6cd39f731db86dfd2440553365d5fad4dGuennadi Liakhovetski num_cfg = 1; 12305fd284e6cd39f731db86dfd2440553365d5fad4dGuennadi Liakhovetski } else { 12315fd284e6cd39f731db86dfd2440553365d5fad4dGuennadi Liakhovetski num_cfg = ch->cfg.num_cfg; 12325fd284e6cd39f731db86dfd2440553365d5fad4dGuennadi Liakhovetski } 12335fd284e6cd39f731db86dfd2440553365d5fad4dGuennadi Liakhovetski 12345fd284e6cd39f731db86dfd2440553365d5fad4dGuennadi Liakhovetski fb_videomode_to_modelist(mode, num_cfg, &info->modelist); 1235c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski 1236c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski fb_videomode_to_var(var, mode); 12379dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy /* Default Y virtual resolution is 2x panel size */ 12386011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski var->yres_virtual = var->yres * 2; 12396011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski var->activate = FB_ACTIVATE_NOW; 12406011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 12416011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski error = sh_mobile_lcdc_set_bpp(var, cfg->bpp); 1242cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error) 1243cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 1244cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1245cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm buf = dma_alloc_coherent(&pdev->dev, info->fix.smem_len, 124601ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski &ch->dma_handle, GFP_KERNEL); 1247cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!buf) { 1248cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "unable to allocate buffer\n"); 1249cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm error = -ENOMEM; 1250cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 1251cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1252cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 125301ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski info->pseudo_palette = &ch->pseudo_palette; 1254cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->flags = FBINFO_FLAG_DEFAULT; 1255cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1256cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm error = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0); 1257cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error < 0) { 1258cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "unable to allocate cmap\n"); 1259cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dma_free_coherent(&pdev->dev, info->fix.smem_len, 126001ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski buf, ch->dma_handle); 1261cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 1262cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1263cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 126401ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski info->fix.smem_start = ch->dma_handle; 1265c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski info->fix.line_length = var->xres * (cfg->bpp / 8); 1266cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->screen_base = buf; 1267cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->device = &pdev->dev; 12681c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski ch->display_var = *var; 1269cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1270cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1271cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error) 1272cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 1273cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1274cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm error = sh_mobile_lcdc_start(priv); 1275cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error) { 1276cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "unable to start hardware\n"); 1277cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 1278cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1279cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1280cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (i = 0; i < j; i++) { 12811c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt struct sh_mobile_lcdc_chan *ch = priv->ch + i; 12821c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt 1283e33afddca174171a68d57476ead8947476ab9240Paul Mundt info = ch->info; 12841c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt 12851c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt if (info->fbdefio) { 12868bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski ch->sglist = vmalloc(sizeof(struct scatterlist) * 12871c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt info->fix.smem_len >> PAGE_SHIFT); 12888bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski if (!ch->sglist) { 12891c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt dev_err(&pdev->dev, "cannot allocate sglist\n"); 12901c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt goto err1; 12911c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt } 12921c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt } 12931c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt 12941c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt error = register_framebuffer(info); 1295cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error < 0) 1296cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 1297cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1298cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_info(info->dev, 1299cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm "registered %s/%s as %dx%d %dbpp.\n", 1300cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm pdev->name, 13011c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt (ch->cfg.chan == LCDC_CHAN_MAINLCD) ? 1302cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm "mainlcd" : "sublcd", 1303c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski info->var.xres, info->var.yres, 13041c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt ch->cfg.bpp); 13058564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 13068564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* deferred io mode: disable clock to save power */ 13076011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED) 13088564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_clk_off(priv); 1309cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1310cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 13116011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski /* Failure ignored */ 13126011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski priv->notifier.notifier_call = sh_mobile_lcdc_notify; 13136011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski fb_register_client(&priv->notifier); 13146011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 1315cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 13168bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetskierr1: 1317cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm sh_mobile_lcdc_remove(pdev); 13188bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski 1319cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return error; 1320cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 1321cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1322cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_remove(struct platform_device *pdev) 1323cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 1324cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev); 1325cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct fb_info *info; 1326cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int i; 1327cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 13286011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski fb_unregister_client(&priv->notifier); 13296011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 1330cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (i = 0; i < ARRAY_SIZE(priv->ch); i++) 13318bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski if (priv->ch[i].info && priv->ch[i].info->dev) 1332e33afddca174171a68d57476ead8947476ab9240Paul Mundt unregister_framebuffer(priv->ch[i].info); 1333cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1334cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm sh_mobile_lcdc_stop(priv); 1335cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1336cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (i = 0; i < ARRAY_SIZE(priv->ch); i++) { 1337e33afddca174171a68d57476ead8947476ab9240Paul Mundt info = priv->ch[i].info; 1338cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1339e33afddca174171a68d57476ead8947476ab9240Paul Mundt if (!info || !info->device) 1340cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm continue; 1341cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 13421c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt if (priv->ch[i].sglist) 13431c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt vfree(priv->ch[i].sglist); 13441c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt 13451ffbb037d8e81ba4f09901451b39c8f178b05559Magnus Damm if (info->screen_base) 13461ffbb037d8e81ba4f09901451b39c8f178b05559Magnus Damm dma_free_coherent(&pdev->dev, info->fix.smem_len, 13471ffbb037d8e81ba4f09901451b39c8f178b05559Magnus Damm info->screen_base, 13481ffbb037d8e81ba4f09901451b39c8f178b05559Magnus Damm priv->ch[i].dma_handle); 1349cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm fb_dealloc_cmap(&info->cmap); 1350e33afddca174171a68d57476ead8947476ab9240Paul Mundt framebuffer_release(info); 1351cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1352cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1353b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm if (priv->dot_clk) 1354b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm clk_put(priv->dot_clk); 13550246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 13568bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski if (priv->dev) 13578bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski pm_runtime_disable(priv->dev); 1358cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1359cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (priv->base) 1360cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm iounmap(priv->base); 1361cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 13628564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (priv->irq) 13638564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm free_irq(priv->irq, priv); 1364cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm kfree(priv); 1365cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 1366cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 1367cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1368cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic struct platform_driver sh_mobile_lcdc_driver = { 1369cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .driver = { 1370cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .name = "sh_mobile_lcdc_fb", 1371cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .owner = THIS_MODULE, 13722feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm .pm = &sh_mobile_lcdc_dev_pm_ops, 1373cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm }, 1374cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .probe = sh_mobile_lcdc_probe, 1375cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .remove = sh_mobile_lcdc_remove, 1376cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 1377cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1378cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int __init sh_mobile_lcdc_init(void) 1379cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 1380cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return platform_driver_register(&sh_mobile_lcdc_driver); 1381cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 1382cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1383cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void __exit sh_mobile_lcdc_exit(void) 1384cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 1385cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm platform_driver_unregister(&sh_mobile_lcdc_driver); 1386cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 1387cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1388cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammmodule_init(sh_mobile_lcdc_init); 1389cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammmodule_exit(sh_mobile_lcdc_exit); 1390cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1391cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_DESCRIPTION("SuperH Mobile LCDC Framebuffer driver"); 1392cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_AUTHOR("Magnus Damm <damm@opensource.se>"); 1393cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_LICENSE("GPL v2"); 1394