sh_mobile_lcdcfb.c revision 72c04af9a2d57b7945cf3de8e71461bd80695d50
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{ 119b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent 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; 27658f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart unsigned int nr_pages_max = ch->fb_size >> 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; 292b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_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 */ 316e8363140c02c92c122210e03103aef72dd836664Laurent Pinchart dma_map_sg(ch->lcdc->dev, ch->sglist, nr_pages, DMA_TO_DEVICE); 317afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart if (panel->start_transfer) 318afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart panel->start_transfer(ch, &sh_mobile_lcdc_sys_bus_ops); 319ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG); 320e8363140c02c92c122210e03103aef72dd836664Laurent Pinchart dma_unmap_sg(ch->lcdc->dev, ch->sglist, nr_pages, 321e8363140c02c92c122210e03103aef72dd836664Laurent Pinchart DMA_TO_DEVICE); 322ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm } else { 323afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart if (panel->start_transfer) 324afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart panel->start_transfer(ch, &sh_mobile_lcdc_sys_bus_ops); 325ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG); 326ef61aae4ddf1dbd0e9b6ad21e2e57632a8fe76f6Magnus Damm } 3278564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 3288564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 3298564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info) 3308564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 3318564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm struct fb_deferred_io *fbdefio = info->fbdefio; 3328564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 3338564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (fbdefio) 3348564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm schedule_delayed_work(&info->deferred_work, fbdefio->delay); 3358564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 3368564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 33737c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchartstatic void sh_mobile_lcdc_display_on(struct sh_mobile_lcdc_chan *ch) 33837c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart{ 339b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg; 34037c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart 3419a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart if (ch->tx_dev) { 342458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart int ret; 343458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart 344458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart ret = ch->tx_dev->ops->display_on(ch->tx_dev); 345458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart if (ret < 0) 3469a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart return; 347458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart 348458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart if (ret == SH_MOBILE_LCDC_DISPLAY_DISCONNECTED) 349458981c3886133667e020900f53538f1fbc3ea1dLaurent Pinchart ch->info->state = FBINFO_STATE_SUSPENDED; 3509a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart } 3519a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart 35237c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart /* HDMI must be enabled before LCDC configuration */ 353afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart if (panel->display_on) 354afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart panel->display_on(); 35537c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart} 35637c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart 35737c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchartstatic void sh_mobile_lcdc_display_off(struct sh_mobile_lcdc_chan *ch) 35837c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart{ 359b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg; 36037c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart 361afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart if (panel->display_off) 362afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart panel->display_off(); 3639a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart 3649a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart if (ch->tx_dev) 3659a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart ch->tx_dev->ops->display_off(ch->tx_dev); 36637c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart} 36737c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart 368ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchartstatic bool 369ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchartsh_mobile_lcdc_must_reconfigure(struct sh_mobile_lcdc_chan *ch, 370e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart const struct fb_videomode *new_mode) 371ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart{ 372ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart dev_dbg(ch->info->dev, "Old %ux%u, new %ux%u\n", 3732d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart ch->display.mode.xres, ch->display.mode.yres, 3742d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart new_mode->xres, new_mode->yres); 375ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart 376e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart /* It can be a different monitor with an equal video-mode */ 3772d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart if (fb_mode_is_equal(&ch->display.mode, new_mode)) 378ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart return false; 379ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart 380ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart dev_dbg(ch->info->dev, "Switching %u -> %u lines\n", 3812d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart ch->display.mode.yres, new_mode->yres); 3822d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart ch->display.mode = *new_mode; 383ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart 384ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart return true; 385ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart} 386ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart 387ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchartstatic int sh_mobile_check_var(struct fb_var_screeninfo *var, 388ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart struct fb_info *info); 389ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart 390ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchartstatic int sh_mobile_lcdc_display_notify(struct sh_mobile_lcdc_chan *ch, 391ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart enum sh_mobile_lcdc_entity_event event, 392e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart const struct fb_videomode *mode, 393e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart const struct fb_monspecs *monspec) 394ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart{ 395ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart struct fb_info *info = ch->info; 396e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart struct fb_var_screeninfo var; 397ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart int ret = 0; 398ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart 399ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart switch (event) { 400ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart case SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT: 401ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart /* HDMI plug in */ 402ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart if (lock_fb_info(info)) { 403ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart console_lock(); 404ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart 4052d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart ch->display.width = monspec->max_x * 10; 4062d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart ch->display.height = monspec->max_y * 10; 407e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart 408e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart if (!sh_mobile_lcdc_must_reconfigure(ch, mode) && 409ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart info->state == FBINFO_STATE_RUNNING) { 410ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart /* First activation with the default monitor. 411ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart * Just turn on, if we run a resume here, the 412ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart * logo disappears. 413ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart */ 414e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart info->var.width = monspec->max_x * 10; 415e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart info->var.height = monspec->max_y * 10; 416ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart sh_mobile_lcdc_display_on(ch); 417ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart } else { 418ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart /* New monitor or have to wake up */ 419ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart fb_set_suspend(info, 0); 420ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart } 421ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart 422ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart console_unlock(); 423ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart unlock_fb_info(info); 424ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart } 425ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart break; 426ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart 427ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart case SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT: 428ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart /* HDMI disconnect */ 429ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart if (lock_fb_info(info)) { 430ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart console_lock(); 431ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart fb_set_suspend(info, 1); 432ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart console_unlock(); 433ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart unlock_fb_info(info); 434ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart } 435ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart break; 436ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart 437ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart case SH_MOBILE_LCDC_EVENT_DISPLAY_MODE: 438ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart /* Validate a proposed new mode */ 439e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart fb_videomode_to_var(&var, mode); 440e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart var.bits_per_pixel = info->var.bits_per_pixel; 441e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart var.grayscale = info->var.grayscale; 442e0c8601a18969229eb63065e5c3176319c785288Laurent Pinchart ret = sh_mobile_check_var(&var, info); 443ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart break; 444ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart } 445ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart 446ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart return ret; 447ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart} 448ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart 449f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* ----------------------------------------------------------------------------- 450f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Format helpers 451f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */ 452f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart 453105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchartstruct sh_mobile_lcdc_format_info { 454105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart u32 fourcc; 455105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart unsigned int bpp; 456105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart bool yuv; 457105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart u32 lddfr; 458105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart}; 459105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart 460105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchartstatic const struct sh_mobile_lcdc_format_info sh_mobile_format_infos[] = { 461105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart { 462105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .fourcc = V4L2_PIX_FMT_RGB565, 463105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .bpp = 16, 464105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .yuv = false, 465105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .lddfr = LDDFR_PKF_RGB16, 466105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart }, { 467105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .fourcc = V4L2_PIX_FMT_BGR24, 468105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .bpp = 24, 469105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .yuv = false, 470105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .lddfr = LDDFR_PKF_RGB24, 471105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart }, { 472105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .fourcc = V4L2_PIX_FMT_BGR32, 473105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .bpp = 32, 474105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .yuv = false, 475105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .lddfr = LDDFR_PKF_ARGB32, 476105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart }, { 477105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .fourcc = V4L2_PIX_FMT_NV12, 478105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .bpp = 12, 479105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .yuv = true, 480105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .lddfr = LDDFR_CC | LDDFR_YF_420, 481105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart }, { 482105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .fourcc = V4L2_PIX_FMT_NV21, 483105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .bpp = 12, 484105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .yuv = true, 485105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .lddfr = LDDFR_CC | LDDFR_YF_420, 486105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart }, { 487105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .fourcc = V4L2_PIX_FMT_NV16, 488105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .bpp = 16, 489105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .yuv = true, 490105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .lddfr = LDDFR_CC | LDDFR_YF_422, 491105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart }, { 492105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .fourcc = V4L2_PIX_FMT_NV61, 493105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .bpp = 16, 494105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .yuv = true, 495105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .lddfr = LDDFR_CC | LDDFR_YF_422, 496105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart }, { 497105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .fourcc = V4L2_PIX_FMT_NV24, 498105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .bpp = 24, 499105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .yuv = true, 500105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .lddfr = LDDFR_CC | LDDFR_YF_444, 501105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart }, { 502105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .fourcc = V4L2_PIX_FMT_NV42, 503105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .bpp = 24, 504105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .yuv = true, 505105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart .lddfr = LDDFR_CC | LDDFR_YF_444, 506105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart }, 507105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart}; 508105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart 509105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchartstatic const struct sh_mobile_lcdc_format_info * 510105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchartsh_mobile_format_info(u32 fourcc) 511105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart{ 512105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart unsigned int i; 513105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart 514105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart for (i = 0; i < ARRAY_SIZE(sh_mobile_format_infos); ++i) { 515105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart if (sh_mobile_format_infos[i].fourcc == fourcc) 516105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart return &sh_mobile_format_infos[i]; 517105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart } 518105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart 519105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart return NULL; 520105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart} 521105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart 522f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchartstatic int sh_mobile_format_fourcc(const struct fb_var_screeninfo *var) 523f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart{ 524f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart if (var->grayscale > 1) 525f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart return var->grayscale; 526f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart 527f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart switch (var->bits_per_pixel) { 528f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart case 16: 529f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart return V4L2_PIX_FMT_RGB565; 530f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart case 24: 531f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart return V4L2_PIX_FMT_BGR24; 532f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart case 32: 533f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart return V4L2_PIX_FMT_BGR32; 534f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart default: 535f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart return 0; 536f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart } 537f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart} 538f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart 539f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchartstatic int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var) 540f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart{ 541f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart return var->grayscale > 1; 542f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart} 543f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart 544f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* ----------------------------------------------------------------------------- 545f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Start, stop and IRQ 546f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */ 547f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart 5488564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic irqreturn_t sh_mobile_lcdc_irq(int irq, void *data) 5498564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 5508564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm struct sh_mobile_lcdc_priv *priv = data; 5512feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm struct sh_mobile_lcdc_chan *ch; 5529dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy unsigned long ldintr; 5532feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm int is_sub; 5542feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm int k; 5558564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 556dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart /* Acknowledge interrupts and disable further VSYNC End IRQs. */ 557dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart ldintr = lcdc_read(priv, _LDINTR); 558dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart lcdc_write(priv, _LDINTR, (ldintr ^ LDINTR_STATUS_MASK) & ~LDINTR_VEE); 5598564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 5602feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm /* figure out if this interrupt is for main or sub lcd */ 561ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart is_sub = (lcdc_read(priv, _LDSR) & LDSR_MSS) ? 1 : 0; 5622feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 5639dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy /* wake up channel and disable clocks */ 5642feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 5652feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm ch = &priv->ch[k]; 5662feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 5672feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm if (!ch->enabled) 5682feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm continue; 5692feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 570dc48665fae5aa360e80dfdb2d6cab4fa58b27ee4Laurent Pinchart /* Frame End */ 5719dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy if (ldintr & LDINTR_FS) { 5729dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy if (is_sub == lcdc_chan_is_sublcd(ch)) { 5739dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy ch->frame_end = 1; 5749dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy wake_up(&ch->frame_end_wait); 5752feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 5769dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy sh_mobile_lcdc_clk_off(priv); 5779dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy } 5789dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy } 5799dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy 5809dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy /* VSYNC End */ 58140331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy if (ldintr & LDINTR_VES) 58240331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy complete(&ch->vsync_completion); 5832feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm } 5842feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 5858564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm return IRQ_HANDLED; 5868564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 5878564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 5884976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchartstatic int sh_mobile_wait_for_vsync(struct sh_mobile_lcdc_chan *ch) 5894976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart{ 5904976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart unsigned long ldintr; 5914976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart int ret; 5924976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart 5934976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart /* Enable VSync End interrupt and be careful not to acknowledge any 5944976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart * pending interrupt. 5954976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart */ 5964976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart ldintr = lcdc_read(ch->lcdc, _LDINTR); 5974976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart ldintr |= LDINTR_VEE | LDINTR_STATUS_MASK; 5984976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart lcdc_write(ch->lcdc, _LDINTR, ldintr); 5994976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart 6004976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion, 6014976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart msecs_to_jiffies(100)); 6024976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart if (!ret) 6034976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart return -ETIMEDOUT; 6044976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart 6054976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart return 0; 6064976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart} 6074976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart 608cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv, 609cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int start) 610cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 611cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long tmp = lcdc_read(priv, _LDCNT2R); 612cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int k; 613cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 614cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* start or stop the lcdc */ 615cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (start) 616ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart lcdc_write(priv, _LDCNT2R, tmp | LDCNT2R_DO); 617cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm else 618ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart lcdc_write(priv, _LDCNT2R, tmp & ~LDCNT2R_DO); 619cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 620cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* wait until power is applied/stopped on all channels */ 621cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) 622cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (lcdc_read(priv, _LDCNT2R) & priv->ch[k].enabled) 623cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm while (1) { 624ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart tmp = lcdc_read_chan(&priv->ch[k], LDPMR) 625ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart & LDPMR_LPS; 626ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart if (start && tmp == LDPMR_LPS) 627cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 628cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!start && tmp == 0) 629cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 630cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm cpu_relax(); 631cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 632cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 633cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!start) 634cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDDCKSTPR, 1); /* stop dotclock */ 635cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 636cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 6376011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetskistatic void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) 6386011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski{ 6392d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart const struct fb_var_screeninfo *var = &ch->info->var; 6402d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart const struct fb_videomode *mode = &ch->display.mode; 6411c120deb60edd4c19a2109daa98f65f2ad3b9c06Guennadi Liakhovetski unsigned long h_total, hsync_pos, display_h_total; 6426011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski u32 tmp; 6436011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 6446011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp = ch->ldmt1r_value; 645ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart tmp |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : LDMT1R_VPOL; 646ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart tmp |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : LDMT1R_HPOL; 647b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart tmp |= (ch->cfg->flags & LCDC_FLAGS_DWPOL) ? LDMT1R_DWPOL : 0; 648b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart tmp |= (ch->cfg->flags & LCDC_FLAGS_DIPOL) ? LDMT1R_DIPOL : 0; 649b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart tmp |= (ch->cfg->flags & LCDC_FLAGS_DAPOL) ? LDMT1R_DAPOL : 0; 650b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart tmp |= (ch->cfg->flags & LCDC_FLAGS_HSCNT) ? LDMT1R_HSCNT : 0; 651b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart tmp |= (ch->cfg->flags & LCDC_FLAGS_DWCNT) ? LDMT1R_DWCNT : 0; 6526011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDMT1R, tmp); 6536011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 6546011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski /* setup SYS bus */ 655b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart lcdc_write_chan(ch, LDMT2R, ch->cfg->sys_bus_cfg.ldmt2r); 656b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart lcdc_write_chan(ch, LDMT3R, ch->cfg->sys_bus_cfg.ldmt3r); 6576011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 6586011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski /* horizontal configuration */ 6592d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart h_total = mode->xres + mode->hsync_len + mode->left_margin 6602d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart + mode->right_margin; 6616011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp = h_total / 8; /* HTCN */ 66258f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart tmp |= (min(mode->xres, ch->xres) / 8) << 16; /* HDCN */ 6636011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDHCNR, tmp); 6646011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 6652d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart hsync_pos = mode->xres + mode->right_margin; 6666011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski tmp = hsync_pos / 8; /* HSYNP */ 6672d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart tmp |= (mode->hsync_len / 8) << 16; /* HSYNW */ 6686011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDHSYNR, tmp); 6696011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 6706011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski /* vertical configuration */ 6712d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart tmp = mode->yres + mode->vsync_len + mode->upper_margin 6722d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart + mode->lower_margin; /* VTLN */ 67358f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart tmp |= min(mode->yres, ch->yres) << 16; /* VDLN */ 6746011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDVLNR, tmp); 6756011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 6762d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart tmp = mode->yres + mode->lower_margin; /* VSYNP */ 6772d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart tmp |= mode->vsync_len << 16; /* VSYNW */ 6786011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDVSYNR, tmp); 6796011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 6806011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski /* Adjust horizontal synchronisation for HDMI */ 6812d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart display_h_total = mode->xres + mode->hsync_len + mode->left_margin 6822d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart + mode->right_margin; 6832d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart tmp = ((mode->xres & 7) << 24) | ((display_h_total & 7) << 16) 6842d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart | ((mode->hsync_len & 7) << 8) | (hsync_pos & 7); 6856011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski lcdc_write_chan(ch, LDHAJR, tmp); 6866011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski} 6876011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 6889a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart/* 6899a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart * __sh_mobile_lcdc_start - Configure and tart the LCDC 6909a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart * @priv: LCDC device 6919a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart * 6929a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart * Configure all enabled channels and start the LCDC device. All external 6939a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart * devices (clocks, MERAM, panels, ...) are not touched by this function. 6949a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart */ 6959a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchartstatic void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) 696cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 697cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_chan *ch; 698cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long tmp; 6999a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart int k, m; 7008564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 7019a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart /* Enable LCDC channels. Read data from external memory, avoid using the 7029a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart * BEU for now. 7039a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart */ 7049a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart lcdc_write(priv, _LDCNT2R, priv->ch[0].enabled | priv->ch[1].enabled); 705cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 7069a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart /* Stop the LCDC first and disable all interrupts. */ 707cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm sh_mobile_lcdc_start_stop(priv, 0); 7089a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart lcdc_write(priv, _LDINTR, 0); 709cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 7109a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart /* Configure power supply, dot clocks and start them. */ 711cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp = priv->lddckr; 712cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 713cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ch = &priv->ch[k]; 7149a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart if (!ch->enabled) 715cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm continue; 716cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 7179a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart /* Power supply */ 7189a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart lcdc_write_chan(ch, LDPMR, 0); 7199a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart 720b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart m = ch->cfg->clock_divider; 721cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!m) 722cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm continue; 723cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 724505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart /* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider 725505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart * denominator. 726505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart */ 727505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart lcdc_write_chan(ch, LDDCKPAT1R, 0); 728505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1); 729505c7de51fe5ebb81fac096cb8cebd7cb45b7955Laurent Pinchart 730cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (m == 1) 731ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart m = LDDCKR_MOSEL; 732cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0); 733cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 734cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 735cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDDCKR, tmp); 736cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDDCKSTPR, 0); 737cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0); 738cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 7399a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart /* Setup geometry, format, frame buffer memory and operation mode. */ 740cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 741cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ch = &priv->ch[k]; 742cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!ch->enabled) 743cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm continue; 744cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 7456011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski sh_mobile_lcdc_geometry(ch); 746cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 747fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart tmp = ch->format->lddfr; 748edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart 749fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart if (ch->format->yuv) { 75058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart switch (ch->colorspace) { 751edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart case V4L2_COLORSPACE_REC709: 752edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart tmp |= LDDFR_CF1; 75353b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia break; 754edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart case V4L2_COLORSPACE_JPEG: 755edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart tmp |= LDDFR_CF0; 75653b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia break; 75753b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia } 758417d48274e755e537bae60461558c1f63a4e14deMagnus Damm } 7597caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia 7609a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart lcdc_write_chan(ch, LDDFR, tmp); 76172c04af9a2d57b7945cf3de8e71461bd80695d50Laurent Pinchart lcdc_write_chan(ch, LDMLSR, ch->line_size); 7629a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart lcdc_write_chan(ch, LDSA1R, ch->base_addr_y); 763fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart if (ch->format->yuv) 7649a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart lcdc_write_chan(ch, LDSA2R, ch->base_addr_c); 7657caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia 7669a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart /* When using deferred I/O mode, configure the LCDC for one-shot 7679a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart * operation and enable the frame end interrupt. Otherwise use 7689a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart * continuous read mode. 7699a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart */ 7709a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart if (ch->ldmt1r_value & LDMT1R_IFM && 771b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart ch->cfg->sys_bus_cfg.deferred_io_msec) { 7729a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart lcdc_write_chan(ch, LDSM1R, LDSM1R_OS); 7739a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart lcdc_write(priv, _LDINTR, LDINTR_FE); 7749a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart } else { 7759a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart lcdc_write_chan(ch, LDSM1R, 0); 7769a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart } 7779a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart } 7787caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia 7799a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart /* Word and long word swap. */ 780fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart switch (priv->ch[0].format->fourcc) { 781edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart case V4L2_PIX_FMT_RGB565: 782edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart case V4L2_PIX_FMT_NV21: 783edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart case V4L2_PIX_FMT_NV61: 784edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart case V4L2_PIX_FMT_NV42: 785edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart tmp = LDDDSR_LS | LDDDSR_WS; 786edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart break; 787edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart case V4L2_PIX_FMT_BGR24: 788edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart case V4L2_PIX_FMT_NV12: 789edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart case V4L2_PIX_FMT_NV16: 790edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart case V4L2_PIX_FMT_NV24: 7919a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS; 792edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart break; 793edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart case V4L2_PIX_FMT_BGR32: 794edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart default: 795edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart tmp = LDDDSR_LS; 796edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart break; 7979a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart } 7989a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart lcdc_write(priv, _LDDDSR, tmp); 7997caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia 8009a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart /* Enable the display output. */ 8019a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart lcdc_write(priv, _LDCNT1R, LDCNT1R_DE); 8029a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart sh_mobile_lcdc_start_stop(priv, 1); 8039a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart priv->started = 1; 8049a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart} 805cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 8069a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchartstatic int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) 8079a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart{ 8089a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart struct sh_mobile_meram_info *mdev = priv->meram_dev; 8099a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart struct sh_mobile_lcdc_chan *ch; 8109a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart unsigned long tmp; 8119a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart int ret; 8129a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart int k; 813cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 8149a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart /* enable clocks before accessing the hardware */ 8159a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 8169a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart if (priv->ch[k].enabled) 8179a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart sh_mobile_lcdc_clk_on(priv); 8189a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart } 8198564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 8209a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart /* reset */ 8219a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LDCNT2R_BR); 8229a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart lcdc_wait_bit(priv, _LDCNT2R, LDCNT2R_BR, 0); 8238564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 8249a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 825b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart const struct sh_mobile_lcdc_panel_cfg *panel; 8268564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 82737c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart ch = &priv->ch[k]; 8289a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart if (!ch->enabled) 8299a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart continue; 8309a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart 831b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart panel = &ch->cfg->panel_cfg; 832afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart if (panel->setup_sys) { 833afaad83b9c0d24eac88535cc5a8c6019f0c45bcbLaurent Pinchart ret = panel->setup_sys(ch, &sh_mobile_lcdc_sys_bus_ops); 8349a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart if (ret) 8359a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart return ret; 8368564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm } 837cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 838cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 8399a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart /* Compute frame buffer base address and pitch for each channel. */ 8409a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 8419a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart int pixelformat; 842481100506b34d666243832c3f2aee905c03cb8e7Laurent Pinchart void *meram; 843cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 8449a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart ch = &priv->ch[k]; 8459a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart if (!ch->enabled) 8469a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart continue; 847cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 84858f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart ch->base_addr_y = ch->dma_handle; 84958f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart ch->base_addr_c = ch->base_addr_y + ch->xres * ch->yres_virtual; 85072c04af9a2d57b7945cf3de8e71461bd80695d50Laurent Pinchart ch->line_size = ch->pitch; 8519a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart 8529a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart /* Enable MERAM if possible. */ 853b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart if (mdev == NULL || mdev->ops == NULL || 854b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart ch->cfg->meram_cfg == NULL) 8559a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart continue; 8569a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart 8579a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart /* we need to de-init configured ICBs before we can 8589a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart * re-initialize them. 8599a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart */ 860481100506b34d666243832c3f2aee905c03cb8e7Laurent Pinchart if (ch->meram) { 861481100506b34d666243832c3f2aee905c03cb8e7Laurent Pinchart mdev->ops->meram_unregister(mdev, ch->meram); 862481100506b34d666243832c3f2aee905c03cb8e7Laurent Pinchart ch->meram = NULL; 8639a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart } 8649a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart 865fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart switch (ch->format->fourcc) { 866edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart case V4L2_PIX_FMT_NV12: 867edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart case V4L2_PIX_FMT_NV21: 868edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart case V4L2_PIX_FMT_NV16: 869edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart case V4L2_PIX_FMT_NV61: 8709a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart pixelformat = SH_MOBILE_MERAM_PF_NV; 871edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart break; 872edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart case V4L2_PIX_FMT_NV24: 873edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart case V4L2_PIX_FMT_NV42: 874edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart pixelformat = SH_MOBILE_MERAM_PF_NV24; 875edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart break; 876edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart case V4L2_PIX_FMT_RGB565: 877edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart case V4L2_PIX_FMT_BGR24: 878edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart case V4L2_PIX_FMT_BGR32: 879edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart default: 880edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart pixelformat = SH_MOBILE_MERAM_PF_RGB; 881edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart break; 882edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart } 8839a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart 884b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart meram = mdev->ops->meram_register(mdev, ch->cfg->meram_cfg, 885b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart ch->pitch, ch->yres, pixelformat, 88672c04af9a2d57b7945cf3de8e71461bd80695d50Laurent Pinchart &ch->line_size); 88797d16fe69b6499a14a0c85c053f7bef54ce992a4Laurent Pinchart if (!IS_ERR(meram)) { 88897d16fe69b6499a14a0c85c053f7bef54ce992a4Laurent Pinchart mdev->ops->meram_update(mdev, meram, 88997d16fe69b6499a14a0c85c053f7bef54ce992a4Laurent Pinchart ch->base_addr_y, ch->base_addr_c, 89097d16fe69b6499a14a0c85c053f7bef54ce992a4Laurent Pinchart &ch->base_addr_y, &ch->base_addr_c); 891481100506b34d666243832c3f2aee905c03cb8e7Laurent Pinchart ch->meram = meram; 89297d16fe69b6499a14a0c85c053f7bef54ce992a4Laurent Pinchart } 8939a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart } 8949a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart 8959a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart /* Start the LCDC. */ 8969a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart __sh_mobile_lcdc_start(priv); 8979a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart 8989a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart /* Setup deferred I/O, tell the board code to enable the panels, and 8999a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart * turn backlight on. 9009a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart */ 901cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 902cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ch = &priv->ch[k]; 90321bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm if (!ch->enabled) 90421bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm continue; 90521bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm 906b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart tmp = ch->cfg->sys_bus_cfg.deferred_io_msec; 9079a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart if (ch->ldmt1r_value & LDMT1R_IFM && tmp) { 9089a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart ch->defio.deferred_io = sh_mobile_lcdc_deferred_io; 9099a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart ch->defio.delay = msecs_to_jiffies(tmp); 9109a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart ch->info->fbdefio = &ch->defio; 9119a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart fb_deferred_io_init(ch->info); 9129a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart } 9139a217e3444ec0c3a0dba35f7b4221af6671da67bLaurent Pinchart 91437c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart sh_mobile_lcdc_display_on(ch); 9153b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 9163b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot if (ch->bl) { 9173b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot ch->bl->props.power = FB_BLANK_UNBLANK; 9183b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot backlight_update_status(ch->bl); 9193b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot } 920cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 921cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 922cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 923cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 924cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 925cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) 926cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 927cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_chan *ch; 928cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int k; 929cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 9302feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm /* clean up deferred io and ask board code to disable panel */ 931cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 932cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ch = &priv->ch[k]; 93321bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm if (!ch->enabled) 93421bc1f024d0d4ea43fc0f2a43504e759261c7b18Magnus Damm continue; 9358564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 9362feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm /* deferred io mode: 9372feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm * flush frame, and wait for frame end interrupt 9382feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm * clean up deferred io and enable clock 9392feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm */ 9405ef6b505d9df45558402bdb823a078840a6a26c4Guennadi Liakhovetski if (ch->info && ch->info->fbdefio) { 9412feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm ch->frame_end = 0; 942e33afddca174171a68d57476ead8947476ab9240Paul Mundt schedule_delayed_work(&ch->info->deferred_work, 0); 9432feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm wait_event(ch->frame_end_wait, ch->frame_end); 944e33afddca174171a68d57476ead8947476ab9240Paul Mundt fb_deferred_io_cleanup(ch->info); 945e33afddca174171a68d57476ead8947476ab9240Paul Mundt ch->info->fbdefio = NULL; 9462feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm sh_mobile_lcdc_clk_on(priv); 9478564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm } 9482feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 9493b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot if (ch->bl) { 9503b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot ch->bl->props.power = FB_BLANK_POWERDOWN; 9513b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot backlight_update_status(ch->bl); 9523b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot } 9533b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 95437c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart sh_mobile_lcdc_display_off(ch); 9557caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia 9567caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia /* disable the meram */ 957481100506b34d666243832c3f2aee905c03cb8e7Laurent Pinchart if (ch->meram) { 9587caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia struct sh_mobile_meram_info *mdev; 9597caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia mdev = priv->meram_dev; 960481100506b34d666243832c3f2aee905c03cb8e7Laurent Pinchart mdev->ops->meram_unregister(mdev, ch->meram); 961481100506b34d666243832c3f2aee905c03cb8e7Laurent Pinchart ch->meram = 0; 9627caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia } 9637caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia 964cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 965cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 966cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* stop the lcdc */ 9678e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm if (priv->started) { 9688e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm sh_mobile_lcdc_start_stop(priv, 0); 9698e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm priv->started = 0; 9708e9bb19ef97d6594e735bee64b6d72103e350854Magnus Damm } 971b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm 9728564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* stop clocks */ 9738564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) 9748564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (priv->ch[k].enabled) 9758564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_clk_off(priv); 976cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 977cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 978f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* ----------------------------------------------------------------------------- 979f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Frame buffer operations 980f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */ 981cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 982cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_setcolreg(u_int regno, 983cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm u_int red, u_int green, u_int blue, 984cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm u_int transp, struct fb_info *info) 985cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 986cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm u32 *palette = info->pseudo_palette; 987cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 988cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (regno >= PALETTE_NR) 989cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return -EINVAL; 990cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 991cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* only FB_VISUAL_TRUECOLOR supported */ 992cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 993cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm red >>= 16 - info->var.red.length; 994cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm green >>= 16 - info->var.green.length; 995cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm blue >>= 16 - info->var.blue.length; 996cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm transp >>= 16 - info->var.transp.length; 997cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 998cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm palette[regno] = (red << info->var.red.offset) | 999cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm (green << info->var.green.offset) | 1000cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm (blue << info->var.blue.offset) | 1001cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm (transp << info->var.transp.offset); 1002cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1003cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 1004cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 1005cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1006cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic struct fb_fix_screeninfo sh_mobile_lcdc_fix = { 1007cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .id = "SH Mobile LCDC", 1008cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .type = FB_TYPE_PACKED_PIXELS, 1009cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .visual = FB_VISUAL_TRUECOLOR, 1010cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .accel = FB_ACCEL_NONE, 10119dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy .xpanstep = 0, 10129dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy .ypanstep = 1, 10139dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy .ywrapstep = 0, 1014edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart .capabilities = FB_CAP_FOURCC, 1015cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 1016cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 10178564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_fillrect(struct fb_info *info, 10188564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm const struct fb_fillrect *rect) 10198564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 10208564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sys_fillrect(info, rect); 10218564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_deferred_io_touch(info); 10228564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 10238564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 10248564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_copyarea(struct fb_info *info, 10258564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm const struct fb_copyarea *area) 10268564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 10278564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sys_copyarea(info, area); 10288564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_deferred_io_touch(info); 10298564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 10308564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 10318564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_imageblit(struct fb_info *info, 10328564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm const struct fb_image *image) 10338564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 10348564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sys_imageblit(info, image); 10358564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_deferred_io_touch(info); 10368564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 10378564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 10389dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthystatic int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, 10399dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy struct fb_info *info) 10409dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy{ 10419dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy struct sh_mobile_lcdc_chan *ch = info->par; 104292e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy struct sh_mobile_lcdc_priv *priv = ch->lcdc; 104392e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy unsigned long ldrcntr; 104492e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy unsigned long new_pan_offset; 104553b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia unsigned long base_addr_y, base_addr_c; 104653b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia unsigned long c_offset; 104792e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy 104858f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart if (!ch->format->yuv) 104958f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart new_pan_offset = var->yoffset * ch->pitch 105058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart + var->xoffset * (ch->format->bpp / 8); 105153b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia else 105258f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart new_pan_offset = var->yoffset * ch->pitch + var->xoffset; 10539dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy 105492e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy if (new_pan_offset == ch->pan_offset) 10559dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy return 0; /* No change, do nothing */ 10569dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy 105792e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy ldrcntr = lcdc_read(priv, _LDRCNTR); 10589dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy 105992e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy /* Set the source address for the next refresh */ 106053b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia base_addr_y = ch->dma_handle + new_pan_offset; 106158f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart if (ch->format->yuv) { 106253b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia /* Set y offset */ 106358f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart c_offset = var->yoffset * ch->pitch 106458f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart * (ch->format->bpp - 8) / 8; 106558f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart base_addr_c = ch->dma_handle + ch->xres * ch->yres_virtual 1066dc1d5adab5cc57eb732407d80c9e7ae48891ffcaLaurent Pinchart + c_offset; 106753b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia /* Set x offset */ 1068fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart if (ch->format->fourcc == V4L2_PIX_FMT_NV24) 106953b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia base_addr_c += 2 * var->xoffset; 107053b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia else 107153b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia base_addr_c += var->xoffset; 107249d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart } 107353b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia 1074481100506b34d666243832c3f2aee905c03cb8e7Laurent Pinchart if (ch->meram) { 10757caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia struct sh_mobile_meram_info *mdev; 10767caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia 10777caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia mdev = priv->meram_dev; 1078cdf88b9072a86545611b9c3f5597ebc47e50ffc1Laurent Pinchart mdev->ops->meram_update(mdev, ch->meram, 10797caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia base_addr_y, base_addr_c, 108049d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart &base_addr_y, &base_addr_c); 108149d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart } 10827caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia 108349d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart ch->base_addr_y = base_addr_y; 108449d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart ch->base_addr_c = base_addr_c; 10857caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia 108649d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y); 108758f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart if (ch->format->yuv) 108849d79ba2e39b5d3346e9e3ddf894eda72c743c85Laurent Pinchart lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c); 108953b5031430bb3a7941b340b453afe4eabeb5340cDamian Hobson-Garcia 109092e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy if (lcdc_chan_is_sublcd(ch)) 109192e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS); 109292e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy else 109392e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_MRS); 109492e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy 109592e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy ch->pan_offset = new_pan_offset; 109692e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy 109792e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1Phil Edworthy sh_mobile_lcdc_deferred_io_touch(info); 10989dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy 10999dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy return 0; 11009dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy} 11019dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy 110240331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthystatic int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd, 110340331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy unsigned long arg) 110440331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy{ 110540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy int retval; 110640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 110740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy switch (cmd) { 110840331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy case FBIO_WAITFORVSYNC: 11094976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart retval = sh_mobile_wait_for_vsync(info->par); 111040331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy break; 111140331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 111240331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy default: 111340331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy retval = -ENOIOCTLCMD; 111440331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy break; 111540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy } 111640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy return retval; 111740331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy} 111840331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 1119dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetskistatic void sh_mobile_fb_reconfig(struct fb_info *info) 1120dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{ 1121dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski struct sh_mobile_lcdc_chan *ch = info->par; 11222d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart struct fb_var_screeninfo var; 11232d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart struct fb_videomode mode; 1124dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski struct fb_event event; 1125dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski int evnt = FB_EVENT_MODE_CHANGE_ALL; 1126dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1127dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski if (ch->use_count > 1 || (ch->use_count == 1 && !info->fbcon_par)) 1128dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski /* More framebuffer users are active */ 1129dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski return; 1130dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 11312d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart fb_var_to_videomode(&mode, &info->var); 1132dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 11332d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart if (fb_mode_is_equal(&ch->display.mode, &mode)) 1134dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski return; 1135dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1136dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski /* Display has been re-plugged, framebuffer is free now, reconfigure */ 11372d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart var = info->var; 11382d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart fb_videomode_to_var(&var, &ch->display.mode); 11392d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart var.width = ch->display.width; 11402d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart var.height = ch->display.height; 11412d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart var.activate = FB_ACTIVATE_NOW; 11422d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart 11432d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart if (fb_set_var(info, &var) < 0) 1144dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski /* Couldn't reconfigure, hopefully, can continue as before */ 1145dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski return; 1146dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1147dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski /* 1148dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski * fb_set_var() calls the notifier change internally, only if 1149dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski * FBINFO_MISC_USEREVENT flag is set. Since we do not want to fake a 1150dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski * user event, we have to call the chain ourselves. 1151dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski */ 1152dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski event.info = info; 11532d04559dc23bed905ed2904f2bbcbcc3f1a7fd91Laurent Pinchart event.data = &ch->display.mode; 1154dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski fb_notifier_call_chain(evnt, &event); 1155dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski} 1156dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1157dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski/* 1158dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski * Locking: both .fb_release() and .fb_open() are called with info->lock held if 1159dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski * user == 1, or with console sem held, if user == 0. 1160dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski */ 1161dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetskistatic int sh_mobile_release(struct fb_info *info, int user) 1162dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{ 1163dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski struct sh_mobile_lcdc_chan *ch = info->par; 1164dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1165dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski mutex_lock(&ch->open_lock); 1166dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count); 1167dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1168dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski ch->use_count--; 1169dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1170dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski /* Nothing to reconfigure, when called from fbcon */ 1171dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski if (user) { 1172ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_lock(); 1173dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski sh_mobile_fb_reconfig(info); 1174ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_unlock(); 1175dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski } 1176dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1177dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski mutex_unlock(&ch->open_lock); 1178dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1179dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski return 0; 1180dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski} 1181dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1182dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetskistatic int sh_mobile_open(struct fb_info *info, int user) 1183dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{ 1184dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski struct sh_mobile_lcdc_chan *ch = info->par; 1185dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1186dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski mutex_lock(&ch->open_lock); 1187dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski ch->use_count++; 1188dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1189dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count); 1190dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski mutex_unlock(&ch->open_lock); 1191dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1192dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski return 0; 1193dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski} 1194dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 1195dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetskistatic int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 1196dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski{ 1197dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski struct sh_mobile_lcdc_chan *ch = info->par; 1198417d48274e755e537bae60461558c1f63a4e14deMagnus Damm struct sh_mobile_lcdc_priv *p = ch->lcdc; 11990386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart unsigned int best_dist = (unsigned int)-1; 12000386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart unsigned int best_xres = 0; 12010386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart unsigned int best_yres = 0; 12020386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart unsigned int i; 1203dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski 12040386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart if (var->xres > MAX_XRES || var->yres > MAX_YRES) 1205dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski return -EINVAL; 12060386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart 12070386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart /* If board code provides us with a list of available modes, make sure 12080386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart * we use one of them. Find the mode closest to the requested one. The 12090386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart * distance between two modes is defined as the size of the 12100386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart * non-overlapping parts of the two rectangles. 12110386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart */ 1212b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart for (i = 0; i < ch->cfg->num_modes; ++i) { 1213b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart const struct fb_videomode *mode = &ch->cfg->lcd_modes[i]; 12140386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart unsigned int dist; 12150386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart 12160386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart /* We can only round up. */ 12170386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart if (var->xres > mode->xres || var->yres > mode->yres) 12180386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart continue; 12190386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart 12200386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart dist = var->xres * var->yres + mode->xres * mode->yres 12210386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart - 2 * min(var->xres, mode->xres) 12220386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart * min(var->yres, mode->yres); 12230386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart 12240386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart if (dist < best_dist) { 12250386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart best_xres = mode->xres; 12260386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart best_yres = mode->yres; 12270386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart best_dist = dist; 12280386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart } 1229dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski } 1230417d48274e755e537bae60461558c1f63a4e14deMagnus Damm 12310386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart /* If no available mode can be used, return an error. */ 1232b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart if (ch->cfg->num_modes != 0) { 12330386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart if (best_dist == (unsigned int)-1) 12340386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart return -EINVAL; 12350386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart 12360386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart var->xres = best_xres; 12370386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart var->yres = best_yres; 12380386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart } 12390386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart 12400386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart /* Make sure the virtual resolution is at least as big as the visible 12410386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart * resolution. 12420386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart */ 12430386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart if (var->xres_virtual < var->xres) 12440386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart var->xres_virtual = var->xres; 12450386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart if (var->yres_virtual < var->yres) 12460386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart var->yres_virtual = var->yres; 12470386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart 1248edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart if (sh_mobile_format_is_fourcc(var)) { 1249105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart const struct sh_mobile_lcdc_format_info *format; 1250105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart 1251105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart format = sh_mobile_format_info(var->grayscale); 1252105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart if (format == NULL) 1253edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart return -EINVAL; 1254105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart var->bits_per_pixel = format->bpp; 1255edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart 1256edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart /* Default to RGB and JPEG color-spaces for RGB and YUV formats 1257edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart * respectively. 1258edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart */ 1259105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart if (!format->yuv) 1260edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->colorspace = V4L2_COLORSPACE_SRGB; 1261edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart else if (var->colorspace != V4L2_COLORSPACE_REC709) 1262edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->colorspace = V4L2_COLORSPACE_JPEG; 1263edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart } else { 1264edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart if (var->bits_per_pixel <= 16) { /* RGB 565 */ 1265edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->bits_per_pixel = 16; 1266edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->red.offset = 11; 1267edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->red.length = 5; 1268edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->green.offset = 5; 1269edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->green.length = 6; 1270edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->blue.offset = 0; 1271edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->blue.length = 5; 1272edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->transp.offset = 0; 1273edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->transp.length = 0; 1274edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart } else if (var->bits_per_pixel <= 24) { /* RGB 888 */ 1275edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->bits_per_pixel = 24; 1276edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->red.offset = 16; 1277edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->red.length = 8; 1278edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->green.offset = 8; 1279edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->green.length = 8; 1280edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->blue.offset = 0; 1281edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->blue.length = 8; 1282edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->transp.offset = 0; 1283edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->transp.length = 0; 1284edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart } else if (var->bits_per_pixel <= 32) { /* RGBA 888 */ 1285edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->bits_per_pixel = 32; 1286edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->red.offset = 16; 1287edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->red.length = 8; 1288edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->green.offset = 8; 1289edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->green.length = 8; 1290edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->blue.offset = 0; 1291edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->blue.length = 8; 1292edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->transp.offset = 24; 1293edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->transp.length = 8; 1294edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart } else 1295edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart return -EINVAL; 1296417d48274e755e537bae60461558c1f63a4e14deMagnus Damm 1297edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->red.msb_right = 0; 1298edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->green.msb_right = 0; 1299edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->blue.msb_right = 0; 1300edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart var->transp.msb_right = 0; 1301edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart } 13020386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart 13030386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart /* Make sure we don't exceed our allocated memory. */ 13040386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 > 13050386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart info->fix.smem_len) 13060386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart return -EINVAL; 13070386219441d48e0f0902e9f145f0d75ad952d753Laurent Pinchart 1308edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart /* only accept the forced_fourcc for dual channel configurations */ 1309edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart if (p->forced_fourcc && 1310edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart p->forced_fourcc != sh_mobile_format_fourcc(var)) 1311417d48274e755e537bae60461558c1f63a4e14deMagnus Damm return -EINVAL; 1312417d48274e755e537bae60461558c1f63a4e14deMagnus Damm 1313dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski return 0; 1314dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski} 131540331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy 1316ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchartstatic int sh_mobile_set_par(struct fb_info *info) 1317ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart{ 1318ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart struct sh_mobile_lcdc_chan *ch = info->par; 1319ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart int ret; 1320ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart 1321ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart sh_mobile_lcdc_stop(ch->lcdc); 132291fba48d59666718e3d3e86964755b80d39cdbddLaurent Pinchart 1323fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart ch->format = sh_mobile_format_info(sh_mobile_format_fourcc(&info->var)); 132458f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart ch->colorspace = info->var.colorspace; 132558f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart 132658f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart ch->xres = info->var.xres; 132758f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart ch->xres_virtual = info->var.xres_virtual; 132858f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart ch->yres = info->var.yres; 132958f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart ch->yres_virtual = info->var.yres_virtual; 133058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart 133158f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart if (ch->format->yuv) 133258f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart ch->pitch = info->var.xres; 133358f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart else 133458f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart ch->pitch = info->var.xres * ch->format->bpp / 8; 1335fc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96Laurent Pinchart 1336ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart ret = sh_mobile_lcdc_start(ch->lcdc); 133758f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart if (ret < 0) 1338ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart dev_err(info->dev, "%s: unable to restart LCDC\n", __func__); 133958f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart 134058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart info->fix.line_length = ch->pitch; 1341ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart 1342edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart if (sh_mobile_format_is_fourcc(&info->var)) { 1343edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart info->fix.type = FB_TYPE_FOURCC; 1344edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart info->fix.visual = FB_VISUAL_FOURCC; 1345edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart } else { 1346edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart info->fix.type = FB_TYPE_PACKED_PIXELS; 1347edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart info->fix.visual = FB_VISUAL_TRUECOLOR; 1348edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart } 1349edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart 1350ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart return ret; 1351ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart} 1352ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart 13538857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot/* 13548857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * Screen blanking. Behavior is as follows: 13558857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_UNBLANK: screen unblanked, clocks enabled 13568857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_NORMAL: screen blanked, clocks enabled 13578857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_VSYNC, 13588857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_HSYNC, 13598857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * FB_BLANK_POWEROFF: screen blanked, clocks disabled 13608857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot */ 13618857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbotstatic int sh_mobile_lcdc_blank(int blank, struct fb_info *info) 13628857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot{ 13638857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot struct sh_mobile_lcdc_chan *ch = info->par; 13648857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot struct sh_mobile_lcdc_priv *p = ch->lcdc; 13658857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot 13668857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot /* blank the screen? */ 13678857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot if (blank > FB_BLANK_UNBLANK && ch->blank_status == FB_BLANK_UNBLANK) { 13688857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot struct fb_fillrect rect = { 136958f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart .width = ch->xres, 137058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart .height = ch->yres, 13718857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot }; 13728857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot sh_mobile_lcdc_fillrect(info, &rect); 13738857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot } 13748857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot /* turn clocks on? */ 13758857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot if (blank <= FB_BLANK_NORMAL && ch->blank_status > FB_BLANK_NORMAL) { 13768857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot sh_mobile_lcdc_clk_on(p); 13778857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot } 13788857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot /* turn clocks off? */ 13798857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot if (blank > FB_BLANK_NORMAL && ch->blank_status <= FB_BLANK_NORMAL) { 13808857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot /* make sure the screen is updated with the black fill before 13818857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * switching the clocks off. one vsync is not enough since 13828857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * blanking may occur in the middle of a refresh. deferred io 13838857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * mode will reenable the clocks and update the screen in time, 13848857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot * so it does not need this. */ 13858857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot if (!info->fbdefio) { 13864976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart sh_mobile_wait_for_vsync(ch); 13874976677f4d34df74d7207cae934b27f5d86feaceLaurent Pinchart sh_mobile_wait_for_vsync(ch); 13888857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot } 13898857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot sh_mobile_lcdc_clk_off(p); 13908857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot } 13918857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot 13928857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot ch->blank_status = blank; 13938857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot return 0; 13948857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot} 13958857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot 1396cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic struct fb_ops sh_mobile_lcdc_ops = { 13979dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy .owner = THIS_MODULE, 1398cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .fb_setcolreg = sh_mobile_lcdc_setcolreg, 13992540c111ead82cad605ec2b14a1905ad914cc124Magnus Damm .fb_read = fb_sys_read, 14002540c111ead82cad605ec2b14a1905ad914cc124Magnus Damm .fb_write = fb_sys_write, 14018564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm .fb_fillrect = sh_mobile_lcdc_fillrect, 14028564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm .fb_copyarea = sh_mobile_lcdc_copyarea, 14038564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm .fb_imageblit = sh_mobile_lcdc_imageblit, 14048857b9aa7e64a70852545ee01fa638481cb08a76Alexandre Courbot .fb_blank = sh_mobile_lcdc_blank, 14059dd38819c2257375ea05bcb92b1f607a1d523c84Phil Edworthy .fb_pan_display = sh_mobile_fb_pan_display, 140640331b21f5fdb746e80fc609ef60ef71b5cd47d9Phil Edworthy .fb_ioctl = sh_mobile_ioctl, 1407dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski .fb_open = sh_mobile_open, 1408dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski .fb_release = sh_mobile_release, 1409dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski .fb_check_var = sh_mobile_check_var, 1410ed5bebf29e82beab3456901e26a495ae0a49ebadLaurent Pinchart .fb_set_par = sh_mobile_set_par, 1411cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 1412cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1413a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartstatic void 1414a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartsh_mobile_lcdc_channel_fb_unregister(struct sh_mobile_lcdc_chan *ch) 1415a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart{ 1416a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart if (ch->info && ch->info->dev) 1417a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart unregister_framebuffer(ch->info); 1418a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart} 1419a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart 1420a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartstatic int __devinit 1421a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartsh_mobile_lcdc_channel_fb_register(struct sh_mobile_lcdc_chan *ch) 1422a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart{ 1423a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart struct fb_info *info = ch->info; 1424a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart int ret; 1425a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart 1426a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart if (info->fbdefio) { 1427a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart ch->sglist = vmalloc(sizeof(struct scatterlist) * 1428a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart ch->fb_size >> PAGE_SHIFT); 1429a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart if (!ch->sglist) { 1430a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart dev_err(ch->lcdc->dev, "cannot allocate sglist\n"); 1431a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart return -ENOMEM; 1432a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart } 1433a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart } 1434a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart 1435a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart info->bl_dev = ch->bl; 1436a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart 1437a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart ret = register_framebuffer(info); 1438a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart if (ret < 0) 1439a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart return ret; 1440a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart 1441a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart dev_info(ch->lcdc->dev, "registered %s/%s as %dx%d %dbpp.\n", 1442b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart dev_name(ch->lcdc->dev), (ch->cfg->chan == LCDC_CHAN_MAINLCD) ? 1443a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart "mainlcd" : "sublcd", info->var.xres, info->var.yres, 1444a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart info->var.bits_per_pixel); 1445a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart 1446a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart /* deferred io mode: disable clock to save power */ 1447a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED) 1448a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart sh_mobile_lcdc_clk_off(ch->lcdc); 1449a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart 1450a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart return ret; 1451a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart} 1452a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart 1453a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartstatic void 1454a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartsh_mobile_lcdc_channel_fb_cleanup(struct sh_mobile_lcdc_chan *ch) 1455a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart{ 1456a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart struct fb_info *info = ch->info; 1457a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart 1458a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart if (!info || !info->device) 1459a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart return; 1460a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart 1461a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart if (ch->sglist) 1462a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart vfree(ch->sglist); 1463a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart 1464a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart fb_dealloc_cmap(&info->cmap); 1465a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart framebuffer_release(info); 1466a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart} 1467a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart 1468a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartstatic int __devinit 1469a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchartsh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch, 1470a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart const struct fb_videomode *mode, 1471a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart unsigned int num_modes) 1472a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart{ 1473a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart struct sh_mobile_lcdc_priv *priv = ch->lcdc; 1474a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart struct fb_var_screeninfo *var; 1475a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart struct fb_info *info; 1476a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart int ret; 1477a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart 1478a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart /* Allocate and initialize the frame buffer device. Create the modes 1479a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart * list and allocate the color map. 1480a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart */ 1481a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart info = framebuffer_alloc(0, priv->dev); 1482a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart if (info == NULL) { 1483a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart dev_err(priv->dev, "unable to allocate fb_info\n"); 1484a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart return -ENOMEM; 1485a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart } 1486a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart 1487a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart ch->info = info; 1488a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart 1489a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart info->flags = FBINFO_FLAG_DEFAULT; 1490a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart info->fbops = &sh_mobile_lcdc_ops; 1491a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart info->device = priv->dev; 1492a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart info->screen_base = ch->fb_mem; 1493a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart info->pseudo_palette = &ch->pseudo_palette; 1494a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart info->par = ch; 1495a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart 1496a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart fb_videomode_to_modelist(mode, num_modes, &info->modelist); 1497a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart 1498a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0); 1499a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart if (ret < 0) { 1500a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart dev_err(priv->dev, "unable to allocate cmap\n"); 1501a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart return ret; 1502a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart } 1503a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart 1504a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart /* Initialize fixed screen information. Restrict pan to 2 lines steps 1505a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart * for NV12 and NV21. 1506a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart */ 1507a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart info->fix = sh_mobile_lcdc_fix; 1508a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart info->fix.smem_start = ch->dma_handle; 1509a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart info->fix.smem_len = ch->fb_size; 151058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart info->fix.line_length = ch->pitch; 151158f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart 151258f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart if (ch->format->yuv) 151358f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart info->fix.visual = FB_VISUAL_FOURCC; 151458f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart else 151558f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart info->fix.visual = FB_VISUAL_TRUECOLOR; 151658f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart 1517a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart if (ch->format->fourcc == V4L2_PIX_FMT_NV12 || 1518a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart ch->format->fourcc == V4L2_PIX_FMT_NV21) 1519a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart info->fix.ypanstep = 2; 1520a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart 1521a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart /* Initialize variable screen information using the first mode as 1522a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart * default. The default Y virtual resolution is twice the panel size to 1523a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart * allow for double-buffering. 1524a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart */ 1525a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart var = &info->var; 1526a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart fb_videomode_to_var(var, mode); 1527b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart var->width = ch->cfg->panel_cfg.width; 1528b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart var->height = ch->cfg->panel_cfg.height; 1529a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart var->yres_virtual = var->yres * 2; 1530a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart var->activate = FB_ACTIVATE_NOW; 1531a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart 1532a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart /* Use the legacy API by default for RGB formats, and the FOURCC API 1533a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart * for YUV formats. 1534a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart */ 1535a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart if (!ch->format->yuv) 1536a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart var->bits_per_pixel = ch->format->bpp; 1537a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart else 1538a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart var->grayscale = ch->format->fourcc; 1539a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart 1540a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart ret = sh_mobile_check_var(var, info); 1541a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart if (ret) 1542a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart return ret; 1543a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart 1544a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart return 0; 1545a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart} 1546a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart 1547f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* ----------------------------------------------------------------------------- 1548f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Backlight 1549f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */ 1550f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart 15513b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic int sh_mobile_lcdc_update_bl(struct backlight_device *bdev) 15523b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{ 15533b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev); 15543b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot int brightness = bdev->props.brightness; 15553b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 15563b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot if (bdev->props.power != FB_BLANK_UNBLANK || 15573b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot bdev->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK)) 15583b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot brightness = 0; 15593b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 1560b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart return ch->cfg->bl_info.set_brightness(brightness); 15613b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot} 15623b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 15633b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic int sh_mobile_lcdc_get_brightness(struct backlight_device *bdev) 15643b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{ 15653b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev); 15663b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 1567b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart return ch->cfg->bl_info.get_brightness(); 15683b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot} 15693b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 15703b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic int sh_mobile_lcdc_check_fb(struct backlight_device *bdev, 15713b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot struct fb_info *info) 15723b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{ 15733b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot return (info->bl_dev == bdev); 15743b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot} 15753b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 15763b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic struct backlight_ops sh_mobile_lcdc_bl_ops = { 15773b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot .options = BL_CORE_SUSPENDRESUME, 15783b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot .update_status = sh_mobile_lcdc_update_bl, 15793b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot .get_brightness = sh_mobile_lcdc_get_brightness, 15803b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot .check_fb = sh_mobile_lcdc_check_fb, 15813b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot}; 15823b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 15833b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic struct backlight_device *sh_mobile_lcdc_bl_probe(struct device *parent, 15843b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot struct sh_mobile_lcdc_chan *ch) 15853b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{ 15863b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot struct backlight_device *bl; 15873b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 1588b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart bl = backlight_device_register(ch->cfg->bl_info.name, parent, ch, 15893b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot &sh_mobile_lcdc_bl_ops, NULL); 1590beee1f20a185c7e79fd33bb83e04fe44ecd75af3Dan Carpenter if (IS_ERR(bl)) { 1591beee1f20a185c7e79fd33bb83e04fe44ecd75af3Dan Carpenter dev_err(parent, "unable to register backlight device: %ld\n", 1592beee1f20a185c7e79fd33bb83e04fe44ecd75af3Dan Carpenter PTR_ERR(bl)); 15933b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot return NULL; 15943b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot } 15953b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 1596b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart bl->props.max_brightness = ch->cfg->bl_info.max_brightness; 15973b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot bl->props.brightness = bl->props.max_brightness; 15983b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot backlight_update_status(bl); 15993b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 16003b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot return bl; 16013b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot} 16023b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 16033b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbotstatic void sh_mobile_lcdc_bl_remove(struct backlight_device *bdev) 16043b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot{ 16053b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot backlight_device_unregister(bdev); 16063b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot} 16073b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 1608f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* ----------------------------------------------------------------------------- 1609f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Power management 1610f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */ 1611f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart 16122feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Dammstatic int sh_mobile_lcdc_suspend(struct device *dev) 16132feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm{ 16142feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm struct platform_device *pdev = to_platform_device(dev); 16152feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 16162feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm sh_mobile_lcdc_stop(platform_get_drvdata(pdev)); 16172feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm return 0; 16182feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm} 16192feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 16202feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Dammstatic int sh_mobile_lcdc_resume(struct device *dev) 16212feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm{ 16222feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm struct platform_device *pdev = to_platform_device(dev); 16232feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 16242feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm return sh_mobile_lcdc_start(platform_get_drvdata(pdev)); 16252feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm} 16262feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 16270246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic int sh_mobile_lcdc_runtime_suspend(struct device *dev) 16280246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm{ 16290246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct platform_device *pdev = to_platform_device(dev); 16302427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev); 16310246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 16320246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm /* turn off LCDC hardware */ 16332427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart lcdc_write(priv, _LDCNT1R, 0); 16342427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart 16350246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm return 0; 16360246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm} 16370246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 16380246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Dammstatic int sh_mobile_lcdc_runtime_resume(struct device *dev) 16390246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm{ 16400246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm struct platform_device *pdev = to_platform_device(dev); 16412427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev); 16420246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 16432427bb241b1db35c6e699ad55adf4a30083b79cdLaurent Pinchart __sh_mobile_lcdc_start(priv); 16440246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 16450246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm return 0; 16460246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm} 16470246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm 1648471452104b8520337ae2fb48c4e61cd4896e025dAlexey Dobriyanstatic const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = { 16492feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm .suspend = sh_mobile_lcdc_suspend, 16502feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm .resume = sh_mobile_lcdc_resume, 16510246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm .runtime_suspend = sh_mobile_lcdc_runtime_suspend, 16520246c4712c40294bd5e8335f0c15a38c8e52709fMagnus Damm .runtime_resume = sh_mobile_lcdc_runtime_resume, 16532feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm}; 16542feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm 1655f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* ----------------------------------------------------------------------------- 1656f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Framebuffer notifier 1657f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */ 1658f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart 16596de9edd5bde0cdfea12e9948690e53ec669c3018Guennadi Liakhovetski/* locking: called with info->lock held */ 16606011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetskistatic int sh_mobile_lcdc_notify(struct notifier_block *nb, 16616011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski unsigned long action, void *data) 16626011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski{ 16636011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski struct fb_event *event = data; 16646011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski struct fb_info *info = event->info; 16656011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski struct sh_mobile_lcdc_chan *ch = info->par; 16666011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 16676011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski if (&ch->lcdc->notifier != nb) 1668baf163749952ca5e33dd2d6a74da023e385c3a00Guennadi Liakhovetski return NOTIFY_DONE; 16696011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 16706011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski dev_dbg(info->dev, "%s(): action = %lu, data = %p\n", 16716011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski __func__, action, event->data); 16726011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 16736011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski switch(action) { 16746011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski case FB_EVENT_SUSPEND: 167537c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart sh_mobile_lcdc_display_off(ch); 1676afe417c0355154c8b2547619771d6053b3c0aad7Guennadi Liakhovetski sh_mobile_lcdc_stop(ch->lcdc); 16776011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski break; 16786011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski case FB_EVENT_RESUME: 1679dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski mutex_lock(&ch->open_lock); 1680dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski sh_mobile_fb_reconfig(info); 1681dd210503b77ae04adfdb25ca45536c4f7e33edb1Guennadi Liakhovetski mutex_unlock(&ch->open_lock); 16826011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 168337c5dcc21ddaa9f946c4d691996bb3076598b813Laurent Pinchart sh_mobile_lcdc_display_on(ch); 1684ebe5e12d00f4785092a9650845ad3451bbf4b311Guennadi Liakhovetski sh_mobile_lcdc_start(ch->lcdc); 16856011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski } 16866011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 1687baf163749952ca5e33dd2d6a74da023e385c3a00Guennadi Liakhovetski return NOTIFY_OK; 16886011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski} 16896011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 1690f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart/* ----------------------------------------------------------------------------- 1691f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart * Probe/remove and driver init/exit 1692f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart */ 1693f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart 1694217e9c4353aa86f0c7eeb4c275bca73ea8b53be1Laurent Pinchartstatic const struct fb_videomode default_720p __devinitconst = { 1695f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart .name = "HDMI 720p", 1696f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart .xres = 1280, 1697f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart .yres = 720, 1698f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart 1699f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart .left_margin = 220, 1700f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart .right_margin = 110, 1701f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart .hsync_len = 40, 1702f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart 1703f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart .upper_margin = 20, 1704f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart .lower_margin = 5, 1705f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart .vsync_len = 5, 1706f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart 1707f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart .pixclock = 13468, 1708f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart .refresh = 60, 1709f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT, 1710f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart}; 1711f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart 1712b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchartstatic int sh_mobile_lcdc_remove(struct platform_device *pdev) 1713b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart{ 1714b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev); 1715b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart int i; 1716b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart 1717b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart fb_unregister_client(&priv->notifier); 1718b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart 1719b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart for (i = 0; i < ARRAY_SIZE(priv->ch); i++) 1720a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart sh_mobile_lcdc_channel_fb_unregister(&priv->ch[i]); 1721b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart 1722b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart sh_mobile_lcdc_stop(priv); 1723b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart 1724b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart for (i = 0; i < ARRAY_SIZE(priv->ch); i++) { 17259a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart struct sh_mobile_lcdc_chan *ch = &priv->ch[i]; 1726b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart 1727e34d0bbb062cc78802d0f0686c939ea1569889a6Laurent Pinchart if (ch->tx_dev) { 1728e34d0bbb062cc78802d0f0686c939ea1569889a6Laurent Pinchart ch->tx_dev->lcdc = NULL; 1729b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart module_put(ch->cfg->tx_dev->dev.driver->owner); 1730e34d0bbb062cc78802d0f0686c939ea1569889a6Laurent Pinchart } 17319a2985e7f943678154f5761dad753f1987c2fdd0Laurent Pinchart 1732a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart sh_mobile_lcdc_channel_fb_cleanup(ch); 1733b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart 1734a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart if (ch->fb_mem) 1735a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart dma_free_coherent(&pdev->dev, ch->fb_size, 1736a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart ch->fb_mem, ch->dma_handle); 1737b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart } 1738b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart 1739b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart for (i = 0; i < ARRAY_SIZE(priv->ch); i++) { 1740b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart if (priv->ch[i].bl) 1741b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart sh_mobile_lcdc_bl_remove(priv->ch[i].bl); 1742b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart } 1743b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart 17444774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart if (priv->dot_clk) { 17454774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart pm_runtime_disable(&pdev->dev); 1746b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart clk_put(priv->dot_clk); 17474774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart } 1748b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart 1749b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart if (priv->base) 1750b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart iounmap(priv->base); 1751b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart 1752b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart if (priv->irq) 1753b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart free_irq(priv->irq, priv); 1754b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart kfree(priv); 1755b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart return 0; 1756b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26Laurent Pinchart} 1757cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1758217e9c4353aa86f0c7eeb4c275bca73ea8b53be1Laurent Pinchartstatic int __devinit sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch) 1759f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart{ 1760b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart int interface_type = ch->cfg->interface_type; 1761f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart 1762f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart switch (interface_type) { 1763f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart case RGB8: 1764f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart case RGB9: 1765f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart case RGB12A: 1766f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart case RGB12B: 1767f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart case RGB16: 1768f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart case RGB18: 1769f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart case RGB24: 1770f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart case SYS8A: 1771f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart case SYS8B: 1772f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart case SYS8C: 1773f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart case SYS8D: 1774f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart case SYS9: 1775f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart case SYS12: 1776f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart case SYS16A: 1777f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart case SYS16B: 1778f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart case SYS16C: 1779f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart case SYS18: 1780f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart case SYS24: 1781f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart break; 1782f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart default: 1783f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart return -EINVAL; 1784f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart } 1785f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart 1786f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart /* SUBLCD only supports SYS interface */ 1787f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart if (lcdc_chan_is_sublcd(ch)) { 1788f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart if (!(interface_type & LDMT1R_IFM)) 1789f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart return -EINVAL; 1790f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart 1791f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart interface_type &= ~LDMT1R_IFM; 1792f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart } 1793f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart 1794f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart ch->ldmt1r_value = interface_type; 1795f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart return 0; 1796f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart} 1797f1f60b5f55099a658a5f79cc453b371a439864e6Laurent Pinchart 17980a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchartstatic int __devinit 17990a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchartsh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv, 18000a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart struct sh_mobile_lcdc_chan *ch) 1801cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 1802105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart const struct sh_mobile_lcdc_format_info *format; 1803b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart const struct sh_mobile_lcdc_chan_cfg *cfg = ch->cfg; 18043ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart const struct fb_videomode *max_mode; 18053ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart const struct fb_videomode *mode; 1806a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart unsigned int num_modes; 18073ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart unsigned int max_size; 1808a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart unsigned int i; 18093ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart 1810a67472ad1ae040f073e45048cbc5a01195f2e3f5Laurent Pinchart mutex_init(&ch->open_lock); 1811ecd29947862a9a145c07098499c76c22ed5b8eb3Laurent Pinchart ch->notify = sh_mobile_lcdc_display_notify; 1812a67472ad1ae040f073e45048cbc5a01195f2e3f5Laurent Pinchart 1813105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart /* Validate the format. */ 1814105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart format = sh_mobile_format_info(cfg->fourcc); 1815105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart if (format == NULL) { 1816105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart dev_err(priv->dev, "Invalid FOURCC %08x.\n", cfg->fourcc); 1817105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart return -EINVAL; 1818105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart } 1819105784bbb47cd76f0fc32954b047a13b704fa840Laurent Pinchart 18203ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart /* Iterate through the modes to validate them and find the highest 18213ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart * resolution. 18223ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart */ 18233ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart max_mode = NULL; 18243ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart max_size = 0; 18253ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart 182693ff259846a774ff37dca54792c5a3a6425882c0Laurent Pinchart for (i = 0, mode = cfg->lcd_modes; i < cfg->num_modes; i++, mode++) { 18273ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart unsigned int size = mode->yres * mode->xres; 18283ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart 1829edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart /* NV12/NV21 buffers must have even number of lines */ 1830edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart if ((cfg->fourcc == V4L2_PIX_FMT_NV12 || 1831edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart cfg->fourcc == V4L2_PIX_FMT_NV21) && (mode->yres & 0x1)) { 18320a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart dev_err(priv->dev, "yres must be multiple of 2 for " 18330a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart "YCbCr420 mode.\n"); 18343ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart return -EINVAL; 18353ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart } 18363ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart 18373ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart if (size > max_size) { 18383ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart max_mode = mode; 18393ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart max_size = size; 18403ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart } 18413ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart } 18423ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart 18433ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart if (!max_size) 18443ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart max_size = MAX_XRES * MAX_YRES; 18453ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart else 18460a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart dev_dbg(priv->dev, "Found largest videomode %ux%u\n", 18473ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart max_mode->xres, max_mode->yres); 18483ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart 184993ff259846a774ff37dca54792c5a3a6425882c0Laurent Pinchart if (cfg->lcd_modes == NULL) { 18503ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart mode = &default_720p; 185193ff259846a774ff37dca54792c5a3a6425882c0Laurent Pinchart num_modes = 1; 18523ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart } else { 185393ff259846a774ff37dca54792c5a3a6425882c0Laurent Pinchart mode = cfg->lcd_modes; 185493ff259846a774ff37dca54792c5a3a6425882c0Laurent Pinchart num_modes = cfg->num_modes; 18553ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart } 18563ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart 185758f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart /* Use the first mode as default. */ 185858f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart ch->format = format; 185958f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart ch->xres = mode->xres; 186058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart ch->xres_virtual = mode->xres; 186158f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart ch->yres = mode->yres; 186258f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart ch->yres_virtual = mode->yres * 2; 186358f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart 186458f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart if (!format->yuv) { 186558f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart ch->colorspace = V4L2_COLORSPACE_SRGB; 186658f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart ch->pitch = ch->xres * format->bpp / 8; 186758f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart } else { 186858f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart ch->colorspace = V4L2_COLORSPACE_REC709; 186958f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart ch->pitch = ch->xres; 187058f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart } 187158f03d998de08bb15ce50ad875e41bdc281d77ddLaurent Pinchart 1872a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart ch->display.width = cfg->panel_cfg.width; 1873a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart ch->display.height = cfg->panel_cfg.height; 1874a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart ch->display.mode = *mode; 1875a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart 1876a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart /* Allocate frame buffer memory. */ 1877a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart ch->fb_size = max_size * format->bpp / 8 * 2; 1878a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart ch->fb_mem = dma_alloc_coherent(priv->dev, ch->fb_size, &ch->dma_handle, 1879a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart GFP_KERNEL); 1880a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart if (ch->fb_mem == NULL) { 1881a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart dev_err(priv->dev, "unable to allocate buffer\n"); 1882a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart return -ENOMEM; 1883a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart } 18843ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart 188513f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart /* Initialize the transmitter device if present. */ 188613f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart if (cfg->tx_dev) { 188713f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart if (!cfg->tx_dev->dev.driver || 188813f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart !try_module_get(cfg->tx_dev->dev.driver->owner)) { 188913f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart dev_warn(priv->dev, 189013f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart "unable to get transmitter device\n"); 189113f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart return -EINVAL; 189213f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart } 189313f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart ch->tx_dev = platform_get_drvdata(cfg->tx_dev); 189413f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart ch->tx_dev->lcdc = ch; 189513f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart ch->tx_dev->def_mode = *mode; 189613f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart } 189713f80eea562be6cd58b5bdefc224c87cc0d9288dLaurent Pinchart 1898a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart return sh_mobile_lcdc_channel_fb_init(ch, mode, num_modes); 18993ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart} 19003ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart 19013ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchartstatic int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) 19023ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart{ 190301ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski struct sh_mobile_lcdc_info *pdata = pdev->dev.platform_data; 19043ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart struct sh_mobile_lcdc_priv *priv; 1905cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct resource *res; 19063ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart int num_channels; 1907cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int error; 19083ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart int i; 1909cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 191001ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski if (!pdata) { 1911cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "no platform data defined\n"); 19128bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski return -EINVAL; 1913cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1914cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1915cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 19168564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm i = platform_get_irq(pdev, 0); 19178564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (!res || i < 0) { 19188564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm dev_err(&pdev->dev, "cannot get platform resources\n"); 19198bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski return -ENOENT; 1920cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1921cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1922cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm priv = kzalloc(sizeof(*priv), GFP_KERNEL); 1923cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!priv) { 1924cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "cannot allocate device data\n"); 19258bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski return -ENOMEM; 1926cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1927cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 19284774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart priv->dev = &pdev->dev; 19294774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart priv->meram_dev = pdata->meram_dev; 19308bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski platform_set_drvdata(pdev, priv); 19318bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski 1932f8798ccbefc0e4ef7438c080b7ba0410738c8cfaYong Zhang error = request_irq(i, sh_mobile_lcdc_irq, 0, 19337ad33e74857f16f1202cbc5746faf52e88e8b376Kay Sievers dev_name(&pdev->dev), priv); 19348564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (error) { 19358564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm dev_err(&pdev->dev, "unable to request irq\n"); 19368564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm goto err1; 19378564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm } 19388564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 19398564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm priv->irq = i; 19405ef6b505d9df45558402bdb823a078840a6a26c4Guennadi Liakhovetski atomic_set(&priv->hw_usecnt, -1); 1941cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 19423ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart for (i = 0, num_channels = 0; i < ARRAY_SIZE(pdata->ch); i++) { 19433ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart struct sh_mobile_lcdc_chan *ch = priv->ch + num_channels; 1944cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 194501ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski ch->lcdc = priv; 1946b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart ch->cfg = &pdata->ch[i]; 1947cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 194801ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski error = sh_mobile_lcdc_check_interface(ch); 1949cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error) { 1950cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "unsupported interface type\n"); 1951cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 1952cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 195301ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski init_waitqueue_head(&ch->frame_end_wait); 195401ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski init_completion(&ch->vsync_completion); 195501ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski ch->pan_offset = 0; 1956cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 19573b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot /* probe the backlight is there is one defined */ 1958b5ef967df13d4d243a2954c32bdd9181a1ee7382Laurent Pinchart if (ch->cfg->bl_info.max_brightness) 19593b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot ch->bl = sh_mobile_lcdc_bl_probe(&pdev->dev, ch); 19603b0fd9d75598584478d1d3f6551f8a8a9696c34eAlexandre Courbot 1961cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm switch (pdata->ch[i].chan) { 1962cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case LCDC_CHAN_MAINLCD: 1963ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart ch->enabled = LDCNT2R_ME; 196401ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski ch->reg_offs = lcdc_offs_mainlcd; 19653ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart num_channels++; 1966cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 1967cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case LCDC_CHAN_SUBLCD: 1968ce1c0b0873bf4e970970a49612105cf6c36d81e3Laurent Pinchart ch->enabled = LDCNT2R_SE; 196901ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski ch->reg_offs = lcdc_offs_sublcd; 19703ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart num_channels++; 1971cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 1972cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1973cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1974cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 19753ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart if (!num_channels) { 1976cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "no channels defined\n"); 1977cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm error = -EINVAL; 1978cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 1979cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1980cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1981edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart /* for dual channel LCDC (MAIN + SUB) force shared format setting */ 19823ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart if (num_channels == 2) 1983edd153a3e4f7346551f98014b3ccf0494219a9d1Laurent Pinchart priv->forced_fourcc = pdata->ch[0].fourcc; 1984417d48274e755e537bae60461558c1f63a4e14deMagnus Damm 1985dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski priv->base = ioremap_nocache(res->start, resource_size(res)); 1986dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski if (!priv->base) 1987dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski goto err1; 1988dba6f385b83d7f19eb1d4df12f422bab945c7f10Guennadi Liakhovetski 19890a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart error = sh_mobile_lcdc_setup_clocks(priv, pdata->clock_source); 1990cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error) { 1991cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "unable to setup clocks\n"); 1992cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 1993cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 1994cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 19954774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart /* Enable runtime PM. */ 19964774c12aacafc0b8be81b1d159be5a761889e2d7Laurent Pinchart pm_runtime_enable(&pdev->dev); 19977caa4342ca5b37d2d178b464c16badd4228b3b7bDamian Hobson-Garcia 19983ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart for (i = 0; i < num_channels; i++) { 199901ac25b59f08c0bb56dd301f024eabd542205a42Guennadi Liakhovetski struct sh_mobile_lcdc_chan *ch = priv->ch + i; 2000c44f9f76d26c3b5158c65201d30e96393efe2fbdGuennadi Liakhovetski 20010a7f17aa3d6b693700af2e1cbf8cfdd28e18aebbLaurent Pinchart error = sh_mobile_lcdc_channel_init(priv, ch); 2002cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error) 20033ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart goto err1; 2004cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 2005cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 2006cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm error = sh_mobile_lcdc_start(priv); 2007cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error) { 2008cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "unable to start hardware\n"); 2009cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 2010cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 2011cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 20123ce05599907c604a8af9cefe8c5e0702a30d1112Laurent Pinchart for (i = 0; i < num_channels; i++) { 20131c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt struct sh_mobile_lcdc_chan *ch = priv->ch + i; 20141c6a307a54668eda556f499c94e75086aaf8f80fPaul Mundt 2015a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart error = sh_mobile_lcdc_channel_fb_register(ch); 2016a67f379d3648746be0dab7b616f2fb838ec0fdfbLaurent Pinchart if (error) 2017cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 2018cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 2019cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 20206011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski /* Failure ignored */ 20216011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski priv->notifier.notifier_call = sh_mobile_lcdc_notify; 20226011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski fb_register_client(&priv->notifier); 20236011bdeaa6089d49c02de69f05980da7bad314abGuennadi Liakhovetski 2024cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 20258bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetskierr1: 2026cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm sh_mobile_lcdc_remove(pdev); 20278bed90557d2600d25e58de30df48b244980164ecGuennadi Liakhovetski 2028cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return error; 2029cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 2030cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 2031cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic struct platform_driver sh_mobile_lcdc_driver = { 2032cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .driver = { 2033cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .name = "sh_mobile_lcdc_fb", 2034cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .owner = THIS_MODULE, 20352feb075a33905c2f6ef6be484c75ba6a35f6d12dMagnus Damm .pm = &sh_mobile_lcdc_dev_pm_ops, 2036cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm }, 2037cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .probe = sh_mobile_lcdc_probe, 2038cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .remove = sh_mobile_lcdc_remove, 2039cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 2040cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 20414277f2c4667187cbbdd3da3be31ee681bc6b8300Axel Linmodule_platform_driver(sh_mobile_lcdc_driver); 2042cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 2043cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_DESCRIPTION("SuperH Mobile LCDC Framebuffer driver"); 2044cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_AUTHOR("Magnus Damm <damm@opensource.se>"); 2045cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_LICENSE("GPL v2"); 2046