sh_mobile_lcdcfb.c revision 6011bdeaa6089d49c02de69f05980da7bad314ab
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/fb.h> 16cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#include <linux/clk.h> 170246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm#include <linux/pm_runtime.h> 18cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#include <linux/platform_device.h> 19cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#include <linux/dma-mapping.h> 208564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm#include <linux/interrupt.h> 211c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt#include <linux/vmalloc.h> 2240331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy#include <linux/ioctl.h> 235a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 24225c9a8d1da274bf23efec43ec28b1c9e45e12f8Paul Mundt#include <video/sh_mobile_lcdc.h> 258564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm#include <asm/atomic.h> 26cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 27cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define PALETTE_NR 16 28a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy#define SIDE_B_OFFSET 0x1000 29a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy#define MIRROR_OFFSET 0x2000 30cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 31cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm/* shared registers */ 32cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDDCKR 0x410 33cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDDCKSTPR 0x414 34cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDINTR 0x468 35cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDSR 0x46c 36cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDCNT1R 0x470 37cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDCNT2R 0x474 389dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy#define _LDRCNTR 0x478 39cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDDDSR 0x47c 40cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDDWD0R 0x800 41cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDDRDR 0x840 42cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDDWAR 0x900 43cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDDRAR 0x904 44cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 450246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm/* shared registers and their order for context save/restore */ 460246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic int lcdc_shared_regs[] = { 470246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm _LDDCKR, 480246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm _LDDCKSTPR, 490246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm _LDINTR, 500246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm _LDDDSR, 510246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm _LDCNT1R, 520246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm _LDCNT2R, 530246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm}; 540246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm#define NR_SHARED_REGS ARRAY_SIZE(lcdc_shared_regs) 550246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 56cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm/* per-channel registers */ 57cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammenum { LDDCKPAT1R, LDDCKPAT2R, LDMT1R, LDMT2R, LDMT3R, LDDFR, LDSM1R, 580246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm LDSM2R, LDSA1R, LDMLSR, LDHCNR, LDHSYNR, LDVLNR, LDVSYNR, LDPMR, 596011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski LDHAJR, 600246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm NR_CH_REGS }; 61cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 620246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = { 63cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDDCKPAT1R] = 0x400, 64cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDDCKPAT2R] = 0x404, 65cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMT1R] = 0x418, 66cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMT2R] = 0x41c, 67cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMT3R] = 0x420, 68cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDDFR] = 0x424, 69cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDSM1R] = 0x428, 708564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm [LDSM2R] = 0x42c, 71cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDSA1R] = 0x430, 72cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMLSR] = 0x438, 73cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDHCNR] = 0x448, 74cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDHSYNR] = 0x44c, 75cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDVLNR] = 0x450, 76cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDVSYNR] = 0x454, 77cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDPMR] = 0x460, 786011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski [LDHAJR] = 0x4a0, 79cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 80cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 810246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic unsigned long lcdc_offs_sublcd[NR_CH_REGS] = { 82cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDDCKPAT1R] = 0x408, 83cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDDCKPAT2R] = 0x40c, 84cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMT1R] = 0x600, 85cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMT2R] = 0x604, 86cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMT3R] = 0x608, 87cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDDFR] = 0x60c, 88cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDSM1R] = 0x610, 898564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm [LDSM2R] = 0x614, 90cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDSA1R] = 0x618, 91cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMLSR] = 0x620, 92cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDHCNR] = 0x624, 93cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDHSYNR] = 0x628, 94cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDVLNR] = 0x62c, 95cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDVSYNR] = 0x630, 96cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDPMR] = 0x63c, 97cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 98cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 99cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define START_LCDC 0x00000001 100cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define LCDC_RESET 0x00000100 101cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define DISPLAY_BEU 0x00000008 102cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define LCDC_ENABLE 0x00000001 1038564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm#define LDINTR_FE 0x00000400 1049dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy#define LDINTR_VSE 0x00000200 1059dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy#define LDINTR_VEE 0x00000100 1068564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm#define LDINTR_FS 0x00000004 1079dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy#define LDINTR_VSS 0x00000002 1089dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy#define LDINTR_VES 0x00000001 109a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy#define LDRCNTR_SRS 0x00020000 110a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy#define LDRCNTR_SRC 0x00010000 111a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy#define LDRCNTR_MRS 0x00000002 112a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy#define LDRCNTR_MRC 0x00000001 11340331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy#define LDSR_MRS 0x00000100 114cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1150246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstruct sh_mobile_lcdc_priv; 1160246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstruct sh_mobile_lcdc_chan { 1170246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct sh_mobile_lcdc_priv *lcdc; 1180246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm unsigned long *reg_offs; 1190246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm unsigned long ldmt1r_value; 1200246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm unsigned long enabled; /* ME and SE in LDCNT2R */ 1210246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct sh_mobile_lcdc_chan_cfg cfg; 1220246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm u32 pseudo_palette[PALETTE_NR]; 1230246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm unsigned long saved_ch_regs[NR_CH_REGS]; 1240246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct fb_info *info; 1250246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm dma_addr_t dma_handle; 1260246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct fb_deferred_io defio; 1270246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct scatterlist *sglist; 1280246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm unsigned long frame_end; 1299dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy unsigned long pan_offset; 1300246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm wait_queue_head_t frame_end_wait; 13140331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy struct completion vsync_completion; 1320246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm}; 1330246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 1340246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstruct sh_mobile_lcdc_priv { 1350246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm void __iomem *base; 1360246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm int irq; 1370246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm atomic_t hw_usecnt; 1380246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct device *dev; 1390246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct clk *dot_clk; 1400246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm unsigned long lddckr; 1410246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct sh_mobile_lcdc_chan ch[2]; 1426011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski struct notifier_block notifier; 1430246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm unsigned long saved_shared_regs[NR_SHARED_REGS]; 1440246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm int started; 1450246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm}; 1460246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 147a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthystatic bool banked(int reg_nr) 148a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy{ 149a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy switch (reg_nr) { 150a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDMT1R: 151a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDMT2R: 152a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDMT3R: 153a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDDFR: 154a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDSM1R: 155a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDSA1R: 156a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDMLSR: 157a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDHCNR: 158a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDHSYNR: 159a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDVLNR: 160a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy case LDVSYNR: 161a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy return true; 162a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy } 163a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy return false; 164a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy} 165a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy 166cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_write_chan(struct sh_mobile_lcdc_chan *chan, 167cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int reg_nr, unsigned long data) 168cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 169cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr]); 170a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy if (banked(reg_nr)) 171a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr] + 172a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy SIDE_B_OFFSET); 173a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy} 174a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy 175a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthystatic void lcdc_write_chan_mirror(struct sh_mobile_lcdc_chan *chan, 176a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy int reg_nr, unsigned long data) 177a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy{ 178a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr] + 179a6f15ade97989d414e9bf33874c9d5d1f39808ecPhil Edworthy MIRROR_OFFSET); 180cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 181cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 182cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic unsigned long lcdc_read_chan(struct sh_mobile_lcdc_chan *chan, 183cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int reg_nr) 184cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 185cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return ioread32(chan->lcdc->base + chan->reg_offs[reg_nr]); 186cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 187cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 188cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_write(struct sh_mobile_lcdc_priv *priv, 189cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long reg_offs, unsigned long data) 190cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 191cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm iowrite32(data, priv->base + reg_offs); 192cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 193cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 194cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic unsigned long lcdc_read(struct sh_mobile_lcdc_priv *priv, 195cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long reg_offs) 196cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 197cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return ioread32(priv->base + reg_offs); 198cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 199cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 200cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_wait_bit(struct sh_mobile_lcdc_priv *priv, 201cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long reg_offs, 202cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long mask, unsigned long until) 203cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 204cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm while ((lcdc_read(priv, reg_offs) & mask) != until) 205cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm cpu_relax(); 206cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 207cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 208cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int lcdc_chan_is_sublcd(struct sh_mobile_lcdc_chan *chan) 209cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 210cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return chan->cfg.chan == LCDC_CHAN_SUBLCD; 211cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 212cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 213cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_sys_write_index(void *handle, unsigned long data) 214cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 215cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_chan *ch = handle; 216cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 217cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(ch->lcdc, _LDDWD0R, data | 0x10000000); 218cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); 219cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(ch->lcdc, _LDDWAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0)); 220909f10de5de81668e4d0a401f3cb5ca6b8a3d20dMagnus Damm lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); 221cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 222cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 223cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_sys_write_data(void *handle, unsigned long data) 224cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 225cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_chan *ch = handle; 226cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 227cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(ch->lcdc, _LDDWD0R, data | 0x11000000); 228cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); 229cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(ch->lcdc, _LDDWAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0)); 230909f10de5de81668e4d0a401f3cb5ca6b8a3d20dMagnus Damm lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); 231cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 232cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 233cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic unsigned long lcdc_sys_read_data(void *handle) 234cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 235cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_chan *ch = handle; 236cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 237cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(ch->lcdc, _LDDRDR, 0x01000000); 238cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); 239cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(ch->lcdc, _LDDRAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0)); 240cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm udelay(1); 241909f10de5de81668e4d0a401f3cb5ca6b8a3d20dMagnus Damm lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); 242cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 243ec56b66fed526e3b7dd58dba8945c405448f48d1Magnus Damm return lcdc_read(ch->lcdc, _LDDRDR) & 0x3ffff; 244cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 245cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 246cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstruct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = { 247cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_sys_write_index, 248cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_sys_write_data, 249cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_sys_read_data, 250cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 251cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 2528564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) 2538564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 2540246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm if (atomic_inc_and_test(&priv->hw_usecnt)) { 2550246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm pm_runtime_get_sync(priv->dev); 2568564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (priv->dot_clk) 2578564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm clk_enable(priv->dot_clk); 2588564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm } 2598564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 2608564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 2618564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv) 2628564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 2630246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm if (atomic_sub_return(1, &priv->hw_usecnt) == -1) { 2648564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (priv->dot_clk) 2658564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm clk_disable(priv->dot_clk); 2660246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm pm_runtime_put(priv->dev); 2678564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm } 2688564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 2698564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 2701c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundtstatic int sh_mobile_lcdc_sginit(struct fb_info *info, 2711c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt struct list_head *pagelist) 2721c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt{ 2731c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt struct sh_mobile_lcdc_chan *ch = info->par; 2741c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt unsigned int nr_pages_max = info->fix.smem_len >> PAGE_SHIFT; 2751c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt struct page *page; 2761c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt int nr_pages = 0; 2771c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt 2781c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt sg_init_table(ch->sglist, nr_pages_max); 2791c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt 2801c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt list_for_each_entry(page, pagelist, lru) 2811c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt sg_set_page(&ch->sglist[nr_pages++], page, PAGE_SIZE, 0); 2821c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt 2831c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt return nr_pages; 2841c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt} 2851c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt 2868564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_deferred_io(struct fb_info *info, 2878564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm struct list_head *pagelist) 2888564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 2898564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm struct sh_mobile_lcdc_chan *ch = info->par; 290ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm struct sh_mobile_lcdc_board_cfg *bcfg = &ch->cfg.board_cfg; 2918564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 2928564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* enable clocks before accessing hardware */ 2938564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_clk_on(ch->lcdc); 2948564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 2955c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt /* 2965c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * It's possible to get here without anything on the pagelist via 2975c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * sh_mobile_lcdc_deferred_io_touch() or via a userspace fsync() 2985c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * invocation. In the former case, the acceleration routines are 2995c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * stepped in to when using the framebuffer console causing the 3005c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * workqueue to be scheduled without any dirty pages on the list. 3015c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * 3025c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * Despite this, a panel update is still needed given that the 3035c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * acceleration routines have their own methods for writing in 3045c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * that still need to be updated. 3055c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * 3065c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * The fsync() and empty pagelist case could be optimized for, 3075c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * but we don't bother, as any application exhibiting such 3085c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt * behaviour is fundamentally broken anyways. 3095c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt */ 3105c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt if (!list_empty(pagelist)) { 3115c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt unsigned int nr_pages = sh_mobile_lcdc_sginit(info, pagelist); 3125c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt 3135c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt /* trigger panel update */ 3145c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt dma_map_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE); 315ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm if (bcfg->start_transfer) 316ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm bcfg->start_transfer(bcfg->board_data, ch, 317ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm &sh_mobile_lcdc_sys_bus_ops); 3185c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt lcdc_write_chan(ch, LDSM2R, 1); 3195c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt dma_unmap_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE); 320ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm } else { 321ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm if (bcfg->start_transfer) 322ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm bcfg->start_transfer(bcfg->board_data, ch, 323ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm &sh_mobile_lcdc_sys_bus_ops); 3245c1a56b5f616f7063f91eb85f0ea209658f387dcPaul Mundt lcdc_write_chan(ch, LDSM2R, 1); 325ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm } 3268564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 3278564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 3288564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info) 3298564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 3308564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm struct fb_deferred_io *fbdefio = info->fbdefio; 3318564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 3328564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (fbdefio) 3338564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm schedule_delayed_work(&info->deferred_work, fbdefio->delay); 3348564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 3358564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 3368564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic irqreturn_t sh_mobile_lcdc_irq(int irq, void *data) 3378564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 3388564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm struct sh_mobile_lcdc_priv *priv = data; 3392feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm struct sh_mobile_lcdc_chan *ch; 3408564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm unsigned long tmp; 3419dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy unsigned long ldintr; 3422feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm int is_sub; 3432feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm int k; 3448564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 3458564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* acknowledge interrupt */ 3469dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy ldintr = tmp = lcdc_read(priv, _LDINTR); 3479dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy /* 3489dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy * disable further VSYNC End IRQs, preserve all other enabled IRQs, 3499dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy * write 0 to bits 0-6 to ack all triggered IRQs. 3509dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy */ 3519dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy tmp &= 0xffffff00 & ~LDINTR_VEE; 3528564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm lcdc_write(priv, _LDINTR, tmp); 3538564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 3542feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm /* figure out if this interrupt is for main or sub lcd */ 3552feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm is_sub = (lcdc_read(priv, _LDSR) & (1 << 10)) ? 1 : 0; 3562feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 3579dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy /* wake up channel and disable clocks */ 3582feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 3592feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm ch = &priv->ch[k]; 3602feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 3612feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm if (!ch->enabled) 3622feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm continue; 3632feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 3649dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy /* Frame Start */ 3659dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy if (ldintr & LDINTR_FS) { 3669dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy if (is_sub == lcdc_chan_is_sublcd(ch)) { 3679dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy ch->frame_end = 1; 3689dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy wake_up(&ch->frame_end_wait); 3692feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 3709dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy sh_mobile_lcdc_clk_off(priv); 3719dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy } 3729dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy } 3739dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy 3749dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy /* VSYNC End */ 37540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy if (ldintr & LDINTR_VES) 37640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy complete(&ch->vsync_completion); 3772feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm } 3782feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 3798564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm return IRQ_HANDLED; 3808564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 3818564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 382cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv, 383cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int start) 384cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 385cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long tmp = lcdc_read(priv, _LDCNT2R); 386cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int k; 387cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 388cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* start or stop the lcdc */ 389cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (start) 390cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDCNT2R, tmp | START_LCDC); 391cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm else 392cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDCNT2R, tmp & ~START_LCDC); 393cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 394cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* wait until power is applied/stopped on all channels */ 395cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) 396cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (lcdc_read(priv, _LDCNT2R) & priv->ch[k].enabled) 397cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm while (1) { 398cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp = lcdc_read_chan(&priv->ch[k], LDPMR) & 3; 399cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (start && tmp == 3) 400cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 401cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!start && tmp == 0) 402cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 403cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm cpu_relax(); 404cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 405cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 406cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!start) 407cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDDCKSTPR, 1); /* stop dotclock */ 408cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 409cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 4106011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetskistatic void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) 4116011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski{ 4126011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski struct fb_var_screeninfo *var = &ch->info->var; 4136011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski unsigned long h_total, hsync_pos; 4146011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski u32 tmp; 4156011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 4166011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp = ch->ldmt1r_value; 4176011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1 << 28; 4186011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1 << 27; 4196011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp |= (ch->cfg.flags & LCDC_FLAGS_DWPOL) ? 1 << 26 : 0; 4206011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp |= (ch->cfg.flags & LCDC_FLAGS_DIPOL) ? 1 << 25 : 0; 4216011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp |= (ch->cfg.flags & LCDC_FLAGS_DAPOL) ? 1 << 24 : 0; 4226011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp |= (ch->cfg.flags & LCDC_FLAGS_HSCNT) ? 1 << 17 : 0; 4236011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp |= (ch->cfg.flags & LCDC_FLAGS_DWCNT) ? 1 << 16 : 0; 4246011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDMT1R, tmp); 4256011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 4266011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski /* setup SYS bus */ 4276011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDMT2R, ch->cfg.sys_bus_cfg.ldmt2r); 4286011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDMT3R, ch->cfg.sys_bus_cfg.ldmt3r); 4296011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 4306011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski /* horizontal configuration */ 4316011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski h_total = var->xres + var->hsync_len + 4326011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski var->left_margin + var->right_margin; 4336011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp = h_total / 8; /* HTCN */ 4346011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp |= (var->xres / 8) << 16; /* HDCN */ 4356011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDHCNR, tmp); 4366011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 4376011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski hsync_pos = var->xres + var->right_margin; 4386011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp = hsync_pos / 8; /* HSYNP */ 4396011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp |= (var->hsync_len / 8) << 16; /* HSYNW */ 4406011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDHSYNR, tmp); 4416011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 4426011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski /* vertical configuration */ 4436011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp = var->yres + var->vsync_len + 4446011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski var->upper_margin + var->lower_margin; /* VTLN */ 4456011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp |= var->yres << 16; /* VDLN */ 4466011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDVLNR, tmp); 4476011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 4486011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp = var->yres + var->lower_margin; /* VSYNP */ 4496011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp |= var->vsync_len << 16; /* VSYNW */ 4506011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDVSYNR, tmp); 4516011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 4526011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski /* Adjust horizontal synchronisation for HDMI */ 4536011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp = ((var->xres & 7) << 24) | 4546011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski ((h_total & 7) << 16) | 4556011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski ((var->hsync_len & 7) << 8) | 4566011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski hsync_pos; 4576011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDHAJR, tmp); 4586011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski} 4596011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 460cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) 461cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 462cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_chan *ch; 463cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct fb_videomode *lcd_cfg; 464cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_board_cfg *board_cfg; 465cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long tmp; 466cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int k, m; 467cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int ret = 0; 468cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 4698564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* enable clocks before accessing the hardware */ 4708564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) 4718564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (priv->ch[k].enabled) 4728564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_clk_on(priv); 4738564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 474cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* reset */ 475cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LCDC_RESET); 476cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_wait_bit(priv, _LDCNT2R, LCDC_RESET, 0); 477cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 478cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* enable LCDC channels */ 479cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp = lcdc_read(priv, _LDCNT2R); 480cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp |= priv->ch[0].enabled; 481cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp |= priv->ch[1].enabled; 482cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDCNT2R, tmp); 483cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 484cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* read data from external memory, avoid using the BEU for now */ 485cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) & ~DISPLAY_BEU); 486cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 487cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* stop the lcdc first */ 488cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm sh_mobile_lcdc_start_stop(priv, 0); 489cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 490cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* configure clocks */ 491cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp = priv->lddckr; 492cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 493cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ch = &priv->ch[k]; 494cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 495cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!priv->ch[k].enabled) 496cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm continue; 497cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 498cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm m = ch->cfg.clock_divider; 499cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!m) 500cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm continue; 501cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 502cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (m == 1) 503cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm m = 1 << 6; 504cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0); 505cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 506cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write_chan(ch, LDDCKPAT1R, 0x00000000); 507cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1); 508cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 509cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 510cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDDCKR, tmp); 511cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 512cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* start dotclock again */ 513cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDDCKSTPR, 0); 514cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0); 515cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 5168564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* interrupts are disabled to begin with */ 517cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDINTR, 0); 518cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 519cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 520cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ch = &priv->ch[k]; 521cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcd_cfg = &ch->cfg.lcd_cfg; 522cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 523cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!ch->enabled) 524cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm continue; 525cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 5266011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski sh_mobile_lcdc_geometry(ch); 527cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 528cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* power supply */ 529cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write_chan(ch, LDPMR, 0); 530cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 531cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm board_cfg = &ch->cfg.board_cfg; 532cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (board_cfg->setup_sys) 533cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ret = board_cfg->setup_sys(board_cfg->board_data, ch, 534cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm &sh_mobile_lcdc_sys_bus_ops); 535cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (ret) 536cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return ret; 537cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 538cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 539cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* word and long word swap */ 540cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 6); 541cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 542cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 543cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ch = &priv->ch[k]; 544cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 545cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!priv->ch[k].enabled) 546cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm continue; 547cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 548cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* set bpp format in PKF[4:0] */ 549cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp = lcdc_read_chan(ch, LDDFR); 550cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp &= ~(0x0001001f); 551e33afddca174171a68d57476ead8947476ab9240Paul Mundt tmp |= (ch->info->var.bits_per_pixel == 16) ? 3 : 0; 552cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write_chan(ch, LDDFR, tmp); 553cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 554cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* point out our frame buffer */ 555e33afddca174171a68d57476ead8947476ab9240Paul Mundt lcdc_write_chan(ch, LDSA1R, ch->info->fix.smem_start); 556cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 557cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* set line size */ 558e33afddca174171a68d57476ead8947476ab9240Paul Mundt lcdc_write_chan(ch, LDMLSR, ch->info->fix.line_length); 559cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 5608564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* setup deferred io if SYS bus */ 5618564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm tmp = ch->cfg.sys_bus_cfg.deferred_io_msec; 5628564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (ch->ldmt1r_value & (1 << 12) && tmp) { 5638564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm ch->defio.deferred_io = sh_mobile_lcdc_deferred_io; 5648564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm ch->defio.delay = msecs_to_jiffies(tmp); 565e33afddca174171a68d57476ead8947476ab9240Paul Mundt ch->info->fbdefio = &ch->defio; 566e33afddca174171a68d57476ead8947476ab9240Paul Mundt fb_deferred_io_init(ch->info); 5678564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 5688564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* one-shot mode */ 5698564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm lcdc_write_chan(ch, LDSM1R, 1); 5708564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 5718564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* enable "Frame End Interrupt Enable" bit */ 5728564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm lcdc_write(priv, _LDINTR, LDINTR_FE); 5738564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 5748564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm } else { 5758564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* continuous read mode */ 5768564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm lcdc_write_chan(ch, LDSM1R, 0); 5778564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm } 578cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 579cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 580cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* display output */ 581cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDCNT1R, LCDC_ENABLE); 582cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 583cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* start the lcdc */ 584cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm sh_mobile_lcdc_start_stop(priv, 1); 5858e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm priv->started = 1; 586cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 587cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* tell the board code to enable the panel */ 588cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 589cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ch = &priv->ch[k]; 59021bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm if (!ch->enabled) 59121bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm continue; 59221bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm 593cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm board_cfg = &ch->cfg.board_cfg; 594cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (board_cfg->display_on) 595c2439398170be9d7af28eb3ab59593369cb303f3Guennadi Liakhovetski board_cfg->display_on(board_cfg->board_data, ch->info); 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 */ 617e33afddca174171a68d57476ead8947476ab9240Paul Mundt if (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; 6272feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm if (board_cfg->display_off) 6282feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm board_cfg->display_off(board_cfg->board_data); 629cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 630cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 631cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* stop the lcdc */ 6328e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm if (priv->started) { 6338e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm sh_mobile_lcdc_start_stop(priv, 0); 6348e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm priv->started = 0; 6358e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm } 636b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm 6378564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* stop clocks */ 6388564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) 6398564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (priv->ch[k].enabled) 6408564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_clk_off(priv); 641cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 642cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 643cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch) 644cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 645cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int ifm, miftyp; 646cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 647cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm switch (ch->cfg.interface_type) { 648cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case RGB8: ifm = 0; miftyp = 0; break; 649cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case RGB9: ifm = 0; miftyp = 4; break; 650cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case RGB12A: ifm = 0; miftyp = 5; break; 651cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case RGB12B: ifm = 0; miftyp = 6; break; 652cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case RGB16: ifm = 0; miftyp = 7; break; 653cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case RGB18: ifm = 0; miftyp = 10; break; 654cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case RGB24: ifm = 0; miftyp = 11; break; 655cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS8A: ifm = 1; miftyp = 0; break; 656cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS8B: ifm = 1; miftyp = 1; break; 657cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS8C: ifm = 1; miftyp = 2; break; 658cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS8D: ifm = 1; miftyp = 3; break; 659cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS9: ifm = 1; miftyp = 4; break; 660cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS12: ifm = 1; miftyp = 5; break; 661cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS16A: ifm = 1; miftyp = 7; break; 662cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS16B: ifm = 1; miftyp = 8; break; 663cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS16C: ifm = 1; miftyp = 9; break; 664cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS18: ifm = 1; miftyp = 10; break; 665cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS24: ifm = 1; miftyp = 11; break; 666cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm default: goto bad; 667cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 668cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 669cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* SUBLCD only supports SYS interface */ 670cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (lcdc_chan_is_sublcd(ch)) { 671cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (ifm == 0) 672cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto bad; 673cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm else 674cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ifm = 0; 675cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 676cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 677cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ch->ldmt1r_value = (ifm << 12) | miftyp; 678cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 679cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm bad: 680cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return -EINVAL; 681cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 682cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 683b51339fff240ff179730f8963a758147fd60f3ecMagnus Dammstatic int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev, 684b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm int clock_source, 685cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_priv *priv) 686cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 687cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm char *str; 688cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int icksel; 689cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 690cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm switch (clock_source) { 691cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case LCDC_CLK_BUS: str = "bus_clk"; icksel = 0; break; 692cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case LCDC_CLK_PERIPHERAL: str = "peripheral_clk"; icksel = 1; break; 693cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case LCDC_CLK_EXTERNAL: str = NULL; icksel = 2; break; 694cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm default: 695cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return -EINVAL; 696cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 697cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 698cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm priv->lddckr = icksel << 16; 699cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 700cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (str) { 701b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm priv->dot_clk = clk_get(&pdev->dev, str); 702b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm if (IS_ERR(priv->dot_clk)) { 703b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm dev_err(&pdev->dev, "cannot get dot clock %s\n", str); 704b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm return PTR_ERR(priv->dot_clk); 705cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 706cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 7070246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm atomic_set(&priv->hw_usecnt, -1); 7080246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 7090246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm /* Runtime PM support involves two step for this driver: 7100246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm * 1) Enable Runtime PM 7110246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm * 2) Force Runtime PM Resume since hardware is accessed from probe() 7120246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm */ 7138bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski priv->dev = &pdev->dev; 7140246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm pm_runtime_enable(priv->dev); 7150246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm pm_runtime_resume(priv->dev); 716cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 717cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 718cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 719cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_setcolreg(u_int regno, 720cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm u_int red, u_int green, u_int blue, 721cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm u_int transp, struct fb_info *info) 722cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 723cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm u32 *palette = info->pseudo_palette; 724cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 725cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (regno >= PALETTE_NR) 726cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return -EINVAL; 727cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 728cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* only FB_VISUAL_TRUECOLOR supported */ 729cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 730cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm red >>= 16 - info->var.red.length; 731cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm green >>= 16 - info->var.green.length; 732cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm blue >>= 16 - info->var.blue.length; 733cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm transp >>= 16 - info->var.transp.length; 734cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 735cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm palette[regno] = (red << info->var.red.offset) | 736cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm (green << info->var.green.offset) | 737cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm (blue << info->var.blue.offset) | 738cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm (transp << info->var.transp.offset); 739cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 740cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 741cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 742cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 743cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic struct fb_fix_screeninfo sh_mobile_lcdc_fix = { 744cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .id = "SH Mobile LCDC", 745cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .type = FB_TYPE_PACKED_PIXELS, 746cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .visual = FB_VISUAL_TRUECOLOR, 747cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .accel = FB_ACCEL_NONE, 7489dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy .xpanstep = 0, 7499dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy .ypanstep = 1, 7509dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy .ywrapstep = 0, 751cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 752cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 7538564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_fillrect(struct fb_info *info, 7548564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm const struct fb_fillrect *rect) 7558564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 7568564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sys_fillrect(info, rect); 7578564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_deferred_io_touch(info); 7588564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 7598564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 7608564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_copyarea(struct fb_info *info, 7618564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm const struct fb_copyarea *area) 7628564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 7638564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sys_copyarea(info, area); 7648564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_deferred_io_touch(info); 7658564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 7668564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 7678564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_imageblit(struct fb_info *info, 7688564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm const struct fb_image *image) 7698564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 7708564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sys_imageblit(info, image); 7718564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_deferred_io_touch(info); 7728564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 7738564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 7749dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthystatic int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, 7759dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy struct fb_info *info) 7769dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy{ 7779dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy struct sh_mobile_lcdc_chan *ch = info->par; 77892e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy struct sh_mobile_lcdc_priv *priv = ch->lcdc; 77992e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy unsigned long ldrcntr; 78092e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy unsigned long new_pan_offset; 78192e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy 78292e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy new_pan_offset = (var->yoffset * info->fix.line_length) + 78392e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy (var->xoffset * (info->var.bits_per_pixel / 8)); 7849dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy 78592e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy if (new_pan_offset == ch->pan_offset) 7869dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy return 0; /* No change, do nothing */ 7879dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy 78892e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy ldrcntr = lcdc_read(priv, _LDRCNTR); 7899dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy 79092e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy /* Set the source address for the next refresh */ 79192e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy lcdc_write_chan_mirror(ch, LDSA1R, ch->dma_handle + new_pan_offset); 79292e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy if (lcdc_chan_is_sublcd(ch)) 79392e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS); 79492e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy else 79592e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_MRS); 79692e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy 79792e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy ch->pan_offset = new_pan_offset; 79892e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy 79992e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy sh_mobile_lcdc_deferred_io_touch(info); 8009dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy 8019dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy return 0; 8029dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy} 8039dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy 80440331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthystatic int sh_mobile_wait_for_vsync(struct fb_info *info) 80540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy{ 80640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy struct sh_mobile_lcdc_chan *ch = info->par; 80740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy unsigned long ldintr; 80840331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy int ret; 80940331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 81040331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy /* Enable VSync End interrupt */ 81140331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy ldintr = lcdc_read(ch->lcdc, _LDINTR); 81240331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy ldintr |= LDINTR_VEE; 81340331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy lcdc_write(ch->lcdc, _LDINTR, ldintr); 81440331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 81540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion, 81640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy msecs_to_jiffies(100)); 81740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy if (!ret) 81840331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy return -ETIMEDOUT; 81940331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 82040331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy return 0; 82140331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy} 82240331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 82340331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthystatic int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd, 82440331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy unsigned long arg) 82540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy{ 82640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy int retval; 82740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 82840331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy switch (cmd) { 82940331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy case FBIO_WAITFORVSYNC: 83040331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy retval = sh_mobile_wait_for_vsync(info); 83140331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy break; 83240331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 83340331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy default: 83440331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy retval = -ENOIOCTLCMD; 83540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy break; 83640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy } 83740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy return retval; 83840331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy} 83940331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 84040331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 841cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic struct fb_ops sh_mobile_lcdc_ops = { 8429dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy .owner = THIS_MODULE, 843cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .fb_setcolreg = sh_mobile_lcdc_setcolreg, 8442540c111ead82cad605ec2b14a1905ad914cc124Magnus Damm .fb_read = fb_sys_read, 8452540c111ead82cad605ec2b14a1905ad914cc124Magnus Damm .fb_write = fb_sys_write, 8468564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm .fb_fillrect = sh_mobile_lcdc_fillrect, 8478564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm .fb_copyarea = sh_mobile_lcdc_copyarea, 8488564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm .fb_imageblit = sh_mobile_lcdc_imageblit, 8499dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy .fb_pan_display = sh_mobile_fb_pan_display, 85040331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy .fb_ioctl = sh_mobile_ioctl, 851cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 852cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 853cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp) 854cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 855cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm switch (bpp) { 856cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case 16: /* PKF[4:0] = 00011 - RGB 565 */ 857cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->red.offset = 11; 858cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->red.length = 5; 859cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->green.offset = 5; 860cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->green.length = 6; 861cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->blue.offset = 0; 862cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->blue.length = 5; 863cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->transp.offset = 0; 864cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->transp.length = 0; 865cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 866cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 867cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case 32: /* PKF[4:0] = 00000 - RGB 888 868cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm * sh7722 pdf says 00RRGGBB but reality is GGBB00RR 869cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm * this may be because LDDDSR has word swap enabled.. 870cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm */ 871cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->red.offset = 0; 872cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->red.length = 8; 873cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->green.offset = 24; 874cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->green.length = 8; 875cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->blue.offset = 16; 876cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->blue.length = 8; 877cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->transp.offset = 0; 878cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->transp.length = 0; 879cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 880cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm default: 881cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return -EINVAL; 882cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 883cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->bits_per_pixel = bpp; 884cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->red.msb_right = 0; 885cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->green.msb_right = 0; 886cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->blue.msb_right = 0; 887cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->transp.msb_right = 0; 888cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 889cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 890cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 8912feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Dammstatic int sh_mobile_lcdc_suspend(struct device *dev) 8922feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm{ 8932feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm struct platform_device *pdev = to_platform_device(dev); 8942feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 8952feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm sh_mobile_lcdc_stop(platform_get_drvdata(pdev)); 8962feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm return 0; 8972feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm} 8982feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 8992feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Dammstatic int sh_mobile_lcdc_resume(struct device *dev) 9002feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm{ 9012feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm struct platform_device *pdev = to_platform_device(dev); 9022feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 9032feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm return sh_mobile_lcdc_start(platform_get_drvdata(pdev)); 9042feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm} 9052feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 9060246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic int sh_mobile_lcdc_runtime_suspend(struct device *dev) 9070246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm{ 9080246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct platform_device *pdev = to_platform_device(dev); 9090246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct sh_mobile_lcdc_priv *p = platform_get_drvdata(pdev); 9100246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct sh_mobile_lcdc_chan *ch; 9110246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm int k, n; 9120246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 9130246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm /* save per-channel registers */ 9140246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm for (k = 0; k < ARRAY_SIZE(p->ch); k++) { 9150246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm ch = &p->ch[k]; 9160246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm if (!ch->enabled) 9170246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm continue; 9180246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm for (n = 0; n < NR_CH_REGS; n++) 9190246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm ch->saved_ch_regs[n] = lcdc_read_chan(ch, n); 9200246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm } 9210246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 9220246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm /* save shared registers */ 9230246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm for (n = 0; n < NR_SHARED_REGS; n++) 9240246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm p->saved_shared_regs[n] = lcdc_read(p, lcdc_shared_regs[n]); 9250246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 9260246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm /* turn off LCDC hardware */ 9270246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm lcdc_write(p, _LDCNT1R, 0); 9280246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm return 0; 9290246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm} 9300246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 9310246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic int sh_mobile_lcdc_runtime_resume(struct device *dev) 9320246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm{ 9330246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct platform_device *pdev = to_platform_device(dev); 9340246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct sh_mobile_lcdc_priv *p = platform_get_drvdata(pdev); 9350246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct sh_mobile_lcdc_chan *ch; 9360246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm int k, n; 9370246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 9380246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm /* restore per-channel registers */ 9390246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm for (k = 0; k < ARRAY_SIZE(p->ch); k++) { 9400246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm ch = &p->ch[k]; 9410246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm if (!ch->enabled) 9420246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm continue; 9430246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm for (n = 0; n < NR_CH_REGS; n++) 9440246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm lcdc_write_chan(ch, n, ch->saved_ch_regs[n]); 9450246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm } 9460246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 9470246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm /* restore shared registers */ 9480246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm for (n = 0; n < NR_SHARED_REGS; n++) 9490246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm lcdc_write(p, lcdc_shared_regs[n], p->saved_shared_regs[n]); 9500246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 9510246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm return 0; 9520246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm} 9530246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 954471452104b8520337ae2fb48c4e61cd4896e025dAlexey Dobriyanstatic const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = { 9552feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm .suspend = sh_mobile_lcdc_suspend, 9562feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm .resume = sh_mobile_lcdc_resume, 9570246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm .runtime_suspend = sh_mobile_lcdc_runtime_suspend, 9580246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm .runtime_resume = sh_mobile_lcdc_runtime_resume, 9592feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm}; 9602feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 9616011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetskistatic int sh_mobile_lcdc_notify(struct notifier_block *nb, 9626011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski unsigned long action, void *data) 9636011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski{ 9646011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski struct fb_event *event = data; 9656011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski struct fb_info *info = event->info; 9666011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski struct sh_mobile_lcdc_chan *ch = info->par; 9676011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg; 9686011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski struct fb_var_screeninfo *var; 9696011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 9706011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski if (&ch->lcdc->notifier != nb) 9716011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski return 0; 9726011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 9736011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski dev_dbg(info->dev, "%s(): action = %lu, data = %p\n", 9746011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski __func__, action, event->data); 9756011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 9766011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski switch(action) { 9776011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski case FB_EVENT_SUSPEND: 9786011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski if (board_cfg->display_off) 9796011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski board_cfg->display_off(board_cfg->board_data); 9806011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski pm_runtime_put(info->device); 9816011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski break; 9826011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski case FB_EVENT_RESUME: 9836011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski var = &info->var; 9846011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 9856011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski /* HDMI must be enabled before LCDC configuration */ 9866011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski if (board_cfg->display_on) 9876011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski board_cfg->display_on(board_cfg->board_data, ch->info); 9886011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 9896011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski /* Check if the new display is not in our modelist */ 9906011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski if (ch->info->modelist.next && 9916011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski !fb_match_mode(var, &ch->info->modelist)) { 9926011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski struct fb_videomode mode; 9936011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski int ret; 9946011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 9956011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski /* Can we handle this display? */ 9966011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski if (var->xres > ch->cfg.lcd_cfg.xres || 9976011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski var->yres > ch->cfg.lcd_cfg.yres) 9986011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski return -ENOMEM; 9996011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 10006011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski /* Add to the modelist */ 10016011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski fb_var_to_videomode(&mode, var); 10026011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski ret = fb_add_videomode(&mode, &ch->info->modelist); 10036011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski if (ret < 0) 10046011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski return ret; 10056011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski } 10066011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 10076011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski pm_runtime_get_sync(info->device); 10086011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 10096011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski sh_mobile_lcdc_geometry(ch); 10106011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 10116011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski break; 10126011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski } 10136011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 10146011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski return 0; 10156011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski} 10166011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 1017cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_remove(struct platform_device *pdev); 1018cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1019c2e13037e6794bd0d9de3f9ecabf5615f15c160bUwe Kleine-Königstatic int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) 1020cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 1021cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct fb_info *info; 1022cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_priv *priv; 1023cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_info *pdata; 1024cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_chan_cfg *cfg; 1025cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct resource *res; 1026cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int error; 1027cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm void *buf; 1028cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int i, j; 1029cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1030cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!pdev->dev.platform_data) { 1031cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "no platform data defined\n"); 10328bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski return -EINVAL; 1033cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1034cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1035cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 10368564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm i = platform_get_irq(pdev, 0); 10378564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (!res || i < 0) { 10388564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm dev_err(&pdev->dev, "cannot get platform resources\n"); 10398bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski return -ENOENT; 1040cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1041cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1042cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm priv = kzalloc(sizeof(*priv), GFP_KERNEL); 1043cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!priv) { 1044cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "cannot allocate device data\n"); 10458bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski return -ENOMEM; 1046cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1047cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 10488bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski platform_set_drvdata(pdev, priv); 10498bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski 10508564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm error = request_irq(i, sh_mobile_lcdc_irq, IRQF_DISABLED, 10517ad33e74857f16f1202cbc5746faf52e88e8b376Kay Sievers dev_name(&pdev->dev), priv); 10528564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (error) { 10538564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm dev_err(&pdev->dev, "unable to request irq\n"); 10548564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm goto err1; 10558564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm } 10568564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 10578564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm priv->irq = i; 1058cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm pdata = pdev->dev.platform_data; 1059cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1060cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm j = 0; 1061cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (i = 0; i < ARRAY_SIZE(pdata->ch); i++) { 1062cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm priv->ch[j].lcdc = priv; 1063cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm memcpy(&priv->ch[j].cfg, &pdata->ch[i], sizeof(pdata->ch[i])); 1064cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1065e1f42ff4f06e5feaa57a22556ad977ef62164e14Guennadi Liakhovetski error = sh_mobile_lcdc_check_interface(&priv->ch[j]); 1066cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error) { 1067cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "unsupported interface type\n"); 1068cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 1069cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1070e1f42ff4f06e5feaa57a22556ad977ef62164e14Guennadi Liakhovetski init_waitqueue_head(&priv->ch[j].frame_end_wait); 1071e1f42ff4f06e5feaa57a22556ad977ef62164e14Guennadi Liakhovetski init_completion(&priv->ch[j].vsync_completion); 10729dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy priv->ch[j].pan_offset = 0; 1073cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1074cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm switch (pdata->ch[i].chan) { 1075cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case LCDC_CHAN_MAINLCD: 1076cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm priv->ch[j].enabled = 1 << 1; 1077cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm priv->ch[j].reg_offs = lcdc_offs_mainlcd; 1078cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm j++; 1079cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 1080cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case LCDC_CHAN_SUBLCD: 1081cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm priv->ch[j].enabled = 1 << 2; 1082cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm priv->ch[j].reg_offs = lcdc_offs_sublcd; 1083cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm j++; 1084cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 1085cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1086cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1087cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1088cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!j) { 1089cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "no channels defined\n"); 1090cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm error = -EINVAL; 1091cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 1092cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1093cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1094dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski priv->base = ioremap_nocache(res->start, resource_size(res)); 1095dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski if (!priv->base) 1096dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski goto err1; 1097dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski 1098b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm error = sh_mobile_lcdc_setup_clocks(pdev, pdata->clock_source, priv); 1099cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error) { 1100cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "unable to setup clocks\n"); 1101cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 1102cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1103cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1104cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (i = 0; i < j; i++) { 11056011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski struct fb_var_screeninfo *var; 11066011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski struct fb_videomode *lcd_cfg; 1107cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm cfg = &priv->ch[i].cfg; 1108cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1109e33afddca174171a68d57476ead8947476ab9240Paul Mundt priv->ch[i].info = framebuffer_alloc(0, &pdev->dev); 1110e33afddca174171a68d57476ead8947476ab9240Paul Mundt if (!priv->ch[i].info) { 1111e33afddca174171a68d57476ead8947476ab9240Paul Mundt dev_err(&pdev->dev, "unable to allocate fb_info\n"); 1112e33afddca174171a68d57476ead8947476ab9240Paul Mundt error = -ENOMEM; 1113e33afddca174171a68d57476ead8947476ab9240Paul Mundt break; 1114e33afddca174171a68d57476ead8947476ab9240Paul Mundt } 1115e33afddca174171a68d57476ead8947476ab9240Paul Mundt 1116e33afddca174171a68d57476ead8947476ab9240Paul Mundt info = priv->ch[i].info; 11176011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski var = &info->var; 11186011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcd_cfg = &cfg->lcd_cfg; 1119cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->fbops = &sh_mobile_lcdc_ops; 11206011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski var->xres = var->xres_virtual = lcd_cfg->xres; 11216011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski var->yres = lcd_cfg->yres; 11229dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy /* Default Y virtual resolution is 2x panel size */ 11236011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski var->yres_virtual = var->yres * 2; 11246011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski var->width = cfg->lcd_size_cfg.width; 11256011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski var->height = cfg->lcd_size_cfg.height; 11266011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski var->activate = FB_ACTIVATE_NOW; 11276011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski var->left_margin = lcd_cfg->left_margin; 11286011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski var->right_margin = lcd_cfg->right_margin; 11296011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski var->upper_margin = lcd_cfg->upper_margin; 11306011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski var->lower_margin = lcd_cfg->lower_margin; 11316011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski var->hsync_len = lcd_cfg->hsync_len; 11326011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski var->vsync_len = lcd_cfg->vsync_len; 11336011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski var->sync = lcd_cfg->sync; 11346011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski var->pixclock = lcd_cfg->pixclock; 11356011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 11366011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski error = sh_mobile_lcdc_set_bpp(var, cfg->bpp); 1137cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error) 1138cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 1139cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1140cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->fix = sh_mobile_lcdc_fix; 11416011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski info->fix.line_length = lcd_cfg->xres * (cfg->bpp / 8); 11429dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy info->fix.smem_len = info->fix.line_length * 11436011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski var->yres_virtual; 1144cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1145cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm buf = dma_alloc_coherent(&pdev->dev, info->fix.smem_len, 1146cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm &priv->ch[i].dma_handle, GFP_KERNEL); 1147cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!buf) { 1148cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "unable to allocate buffer\n"); 1149cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm error = -ENOMEM; 1150cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 1151cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1152cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1153cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->pseudo_palette = &priv->ch[i].pseudo_palette; 1154cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->flags = FBINFO_FLAG_DEFAULT; 1155cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1156cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm error = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0); 1157cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error < 0) { 1158cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "unable to allocate cmap\n"); 1159cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dma_free_coherent(&pdev->dev, info->fix.smem_len, 1160cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm buf, priv->ch[i].dma_handle); 1161cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 1162cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1163cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1164cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm memset(buf, 0, info->fix.smem_len); 1165cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->fix.smem_start = priv->ch[i].dma_handle; 1166cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->screen_base = buf; 1167cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->device = &pdev->dev; 11688564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm info->par = &priv->ch[i]; 1169cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1170cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1171cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error) 1172cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 1173cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1174cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm error = sh_mobile_lcdc_start(priv); 1175cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error) { 1176cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "unable to start hardware\n"); 1177cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 1178cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1179cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1180cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (i = 0; i < j; i++) { 11811c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt struct sh_mobile_lcdc_chan *ch = priv->ch + i; 11821c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt 1183e33afddca174171a68d57476ead8947476ab9240Paul Mundt info = ch->info; 11841c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt 11851c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt if (info->fbdefio) { 11868bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski ch->sglist = vmalloc(sizeof(struct scatterlist) * 11871c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt info->fix.smem_len >> PAGE_SHIFT); 11888bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski if (!ch->sglist) { 11891c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt dev_err(&pdev->dev, "cannot allocate sglist\n"); 11901c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt goto err1; 11911c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt } 11921c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt } 11931c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt 11941c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt error = register_framebuffer(info); 1195cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error < 0) 1196cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 1197cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1198cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_info(info->dev, 1199cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm "registered %s/%s as %dx%d %dbpp.\n", 1200cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm pdev->name, 12011c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt (ch->cfg.chan == LCDC_CHAN_MAINLCD) ? 1202cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm "mainlcd" : "sublcd", 12031c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt (int) ch->cfg.lcd_cfg.xres, 12041c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt (int) ch->cfg.lcd_cfg.yres, 12051c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt ch->cfg.bpp); 12068564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 12078564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* deferred io mode: disable clock to save power */ 12086011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED) 12098564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_clk_off(priv); 1210cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1211cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 12126011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski /* Failure ignored */ 12136011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski priv->notifier.notifier_call = sh_mobile_lcdc_notify; 12146011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski fb_register_client(&priv->notifier); 12156011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 1216cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 12178bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetskierr1: 1218cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm sh_mobile_lcdc_remove(pdev); 12198bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski 1220cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return error; 1221cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 1222cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1223cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_remove(struct platform_device *pdev) 1224cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 1225cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev); 1226cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct fb_info *info; 1227cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int i; 1228cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 12296011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski fb_unregister_client(&priv->notifier); 12306011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 1231cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (i = 0; i < ARRAY_SIZE(priv->ch); i++) 12328bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski if (priv->ch[i].info && priv->ch[i].info->dev) 1233e33afddca174171a68d57476ead8947476ab9240Paul Mundt unregister_framebuffer(priv->ch[i].info); 1234cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1235cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm sh_mobile_lcdc_stop(priv); 1236cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1237cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (i = 0; i < ARRAY_SIZE(priv->ch); i++) { 1238e33afddca174171a68d57476ead8947476ab9240Paul Mundt info = priv->ch[i].info; 1239cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1240e33afddca174171a68d57476ead8947476ab9240Paul Mundt if (!info || !info->device) 1241cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm continue; 1242cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 12431c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt if (priv->ch[i].sglist) 12441c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt vfree(priv->ch[i].sglist); 12451c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt 1246cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dma_free_coherent(&pdev->dev, info->fix.smem_len, 1247cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->screen_base, priv->ch[i].dma_handle); 1248cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm fb_dealloc_cmap(&info->cmap); 1249e33afddca174171a68d57476ead8947476ab9240Paul Mundt framebuffer_release(info); 1250cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1251cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1252b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm if (priv->dot_clk) 1253b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm clk_put(priv->dot_clk); 12540246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 12558bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski if (priv->dev) 12568bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski pm_runtime_disable(priv->dev); 1257cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1258cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (priv->base) 1259cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm iounmap(priv->base); 1260cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 12618564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (priv->irq) 12628564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm free_irq(priv->irq, priv); 1263cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm kfree(priv); 1264cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 1265cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 1266cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1267cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic struct platform_driver sh_mobile_lcdc_driver = { 1268cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .driver = { 1269cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .name = "sh_mobile_lcdc_fb", 1270cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .owner = THIS_MODULE, 12712feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm .pm = &sh_mobile_lcdc_dev_pm_ops, 1272cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm }, 1273cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .probe = sh_mobile_lcdc_probe, 1274cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .remove = sh_mobile_lcdc_remove, 1275cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 1276cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1277cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int __init sh_mobile_lcdc_init(void) 1278cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 1279cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return platform_driver_register(&sh_mobile_lcdc_driver); 1280cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 1281cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1282cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void __exit sh_mobile_lcdc_exit(void) 1283cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 1284cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm platform_driver_unregister(&sh_mobile_lcdc_driver); 1285cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 1286cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1287cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammmodule_init(sh_mobile_lcdc_init); 1288cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammmodule_exit(sh_mobile_lcdc_exit); 1289cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1290cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_DESCRIPTION("SuperH Mobile LCDC Framebuffer driver"); 1291cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_AUTHOR("Magnus Damm <damm@opensource.se>"); 1292cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_LICENSE("GPL v2"); 1293