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