2659 lines · c
1/*2 * SuperH Mobile LCDC Framebuffer3 *4 * Copyright (c) 2008 Magnus Damm5 *6 * This file is subject to the terms and conditions of the GNU General Public7 * License. See the file "COPYING" in the main directory of this archive8 * for more details.9 */10 11#include <linux/atomic.h>12#include <linux/backlight.h>13#include <linux/clk.h>14#include <linux/console.h>15#include <linux/ctype.h>16#include <linux/dma-mapping.h>17#include <linux/delay.h>18#include <linux/fbcon.h>19#include <linux/init.h>20#include <linux/interrupt.h>21#include <linux/ioctl.h>22#include <linux/kernel.h>23#include <linux/mm.h>24#include <linux/module.h>25#include <linux/platform_device.h>26#include <linux/pm_runtime.h>27#include <linux/slab.h>28#include <linux/videodev2.h>29#include <linux/vmalloc.h>30 31#include <video/sh_mobile_lcdc.h>32 33#include "sh_mobile_lcdcfb.h"34 35/* ----------------------------------------------------------------------------36 * Overlay register definitions37 */38 39#define LDBCR 0xb0040#define LDBCR_UPC(n) (1 << ((n) + 16))41#define LDBCR_UPF(n) (1 << ((n) + 8))42#define LDBCR_UPD(n) (1 << ((n) + 0))43#define LDBnBSIFR(n) (0xb20 + (n) * 0x20 + 0x00)44#define LDBBSIFR_EN (1 << 31)45#define LDBBSIFR_VS (1 << 29)46#define LDBBSIFR_BRSEL (1 << 28)47#define LDBBSIFR_MX (1 << 27)48#define LDBBSIFR_MY (1 << 26)49#define LDBBSIFR_CV3 (3 << 24)50#define LDBBSIFR_CV2 (2 << 24)51#define LDBBSIFR_CV1 (1 << 24)52#define LDBBSIFR_CV0 (0 << 24)53#define LDBBSIFR_CV_MASK (3 << 24)54#define LDBBSIFR_LAY_MASK (0xff << 16)55#define LDBBSIFR_LAY_SHIFT 1656#define LDBBSIFR_ROP3_MASK (0xff << 16)57#define LDBBSIFR_ROP3_SHIFT 1658#define LDBBSIFR_AL_PL8 (3 << 14)59#define LDBBSIFR_AL_PL1 (2 << 14)60#define LDBBSIFR_AL_PK (1 << 14)61#define LDBBSIFR_AL_1 (0 << 14)62#define LDBBSIFR_AL_MASK (3 << 14)63#define LDBBSIFR_SWPL (1 << 10)64#define LDBBSIFR_SWPW (1 << 9)65#define LDBBSIFR_SWPB (1 << 8)66#define LDBBSIFR_RY (1 << 7)67#define LDBBSIFR_CHRR_420 (2 << 0)68#define LDBBSIFR_CHRR_422 (1 << 0)69#define LDBBSIFR_CHRR_444 (0 << 0)70#define LDBBSIFR_RPKF_ARGB32 (0x00 << 0)71#define LDBBSIFR_RPKF_RGB16 (0x03 << 0)72#define LDBBSIFR_RPKF_RGB24 (0x0b << 0)73#define LDBBSIFR_RPKF_MASK (0x1f << 0)74#define LDBnBSSZR(n) (0xb20 + (n) * 0x20 + 0x04)75#define LDBBSSZR_BVSS_MASK (0xfff << 16)76#define LDBBSSZR_BVSS_SHIFT 1677#define LDBBSSZR_BHSS_MASK (0xfff << 0)78#define LDBBSSZR_BHSS_SHIFT 079#define LDBnBLOCR(n) (0xb20 + (n) * 0x20 + 0x08)80#define LDBBLOCR_CVLC_MASK (0xfff << 16)81#define LDBBLOCR_CVLC_SHIFT 1682#define LDBBLOCR_CHLC_MASK (0xfff << 0)83#define LDBBLOCR_CHLC_SHIFT 084#define LDBnBSMWR(n) (0xb20 + (n) * 0x20 + 0x0c)85#define LDBBSMWR_BSMWA_MASK (0xffff << 16)86#define LDBBSMWR_BSMWA_SHIFT 1687#define LDBBSMWR_BSMW_MASK (0xffff << 0)88#define LDBBSMWR_BSMW_SHIFT 089#define LDBnBSAYR(n) (0xb20 + (n) * 0x20 + 0x10)90#define LDBBSAYR_FG1A_MASK (0xff << 24)91#define LDBBSAYR_FG1A_SHIFT 2492#define LDBBSAYR_FG1R_MASK (0xff << 16)93#define LDBBSAYR_FG1R_SHIFT 1694#define LDBBSAYR_FG1G_MASK (0xff << 8)95#define LDBBSAYR_FG1G_SHIFT 896#define LDBBSAYR_FG1B_MASK (0xff << 0)97#define LDBBSAYR_FG1B_SHIFT 098#define LDBnBSACR(n) (0xb20 + (n) * 0x20 + 0x14)99#define LDBBSACR_FG2A_MASK (0xff << 24)100#define LDBBSACR_FG2A_SHIFT 24101#define LDBBSACR_FG2R_MASK (0xff << 16)102#define LDBBSACR_FG2R_SHIFT 16103#define LDBBSACR_FG2G_MASK (0xff << 8)104#define LDBBSACR_FG2G_SHIFT 8105#define LDBBSACR_FG2B_MASK (0xff << 0)106#define LDBBSACR_FG2B_SHIFT 0107#define LDBnBSAAR(n) (0xb20 + (n) * 0x20 + 0x18)108#define LDBBSAAR_AP_MASK (0xff << 24)109#define LDBBSAAR_AP_SHIFT 24110#define LDBBSAAR_R_MASK (0xff << 16)111#define LDBBSAAR_R_SHIFT 16112#define LDBBSAAR_GY_MASK (0xff << 8)113#define LDBBSAAR_GY_SHIFT 8114#define LDBBSAAR_B_MASK (0xff << 0)115#define LDBBSAAR_B_SHIFT 0116#define LDBnBPPCR(n) (0xb20 + (n) * 0x20 + 0x1c)117#define LDBBPPCR_AP_MASK (0xff << 24)118#define LDBBPPCR_AP_SHIFT 24119#define LDBBPPCR_R_MASK (0xff << 16)120#define LDBBPPCR_R_SHIFT 16121#define LDBBPPCR_GY_MASK (0xff << 8)122#define LDBBPPCR_GY_SHIFT 8123#define LDBBPPCR_B_MASK (0xff << 0)124#define LDBBPPCR_B_SHIFT 0125#define LDBnBBGCL(n) (0xb10 + (n) * 0x04)126#define LDBBBGCL_BGA_MASK (0xff << 24)127#define LDBBBGCL_BGA_SHIFT 24128#define LDBBBGCL_BGR_MASK (0xff << 16)129#define LDBBBGCL_BGR_SHIFT 16130#define LDBBBGCL_BGG_MASK (0xff << 8)131#define LDBBBGCL_BGG_SHIFT 8132#define LDBBBGCL_BGB_MASK (0xff << 0)133#define LDBBBGCL_BGB_SHIFT 0134 135#define SIDE_B_OFFSET 0x1000136#define MIRROR_OFFSET 0x2000137 138#define MAX_XRES 1920139#define MAX_YRES 1080140 141enum sh_mobile_lcdc_overlay_mode {142 LCDC_OVERLAY_BLEND,143 LCDC_OVERLAY_ROP3,144};145 146/*147 * struct sh_mobile_lcdc_overlay - LCDC display overlay148 *149 * @channel: LCDC channel this overlay belongs to150 * @cfg: Overlay configuration151 * @info: Frame buffer device152 * @index: Overlay index (0-3)153 * @base: Overlay registers base address154 * @enabled: True if the overlay is enabled155 * @mode: Overlay blending mode (alpha blend or ROP3)156 * @alpha: Global alpha blending value (0-255, for alpha blending mode)157 * @rop3: Raster operation (for ROP3 mode)158 * @fb_mem: Frame buffer virtual memory address159 * @fb_size: Frame buffer size in bytes160 * @dma_handle: Frame buffer DMA address161 * @base_addr_y: Overlay base address (RGB or luma component)162 * @base_addr_c: Overlay base address (chroma component)163 * @pan_y_offset: Panning linear offset in bytes (luma component)164 * @format: Current pixelf format165 * @xres: Horizontal visible resolution166 * @xres_virtual: Horizontal total resolution167 * @yres: Vertical visible resolution168 * @yres_virtual: Vertical total resolution169 * @pitch: Overlay line pitch170 * @pos_x: Horizontal overlay position171 * @pos_y: Vertical overlay position172 */173struct sh_mobile_lcdc_overlay {174 struct sh_mobile_lcdc_chan *channel;175 176 const struct sh_mobile_lcdc_overlay_cfg *cfg;177 struct fb_info *info;178 179 unsigned int index;180 unsigned long base;181 182 bool enabled;183 enum sh_mobile_lcdc_overlay_mode mode;184 unsigned int alpha;185 unsigned int rop3;186 187 void *fb_mem;188 unsigned long fb_size;189 190 dma_addr_t dma_handle;191 unsigned long base_addr_y;192 unsigned long base_addr_c;193 unsigned long pan_y_offset;194 195 const struct sh_mobile_lcdc_format_info *format;196 unsigned int xres;197 unsigned int xres_virtual;198 unsigned int yres;199 unsigned int yres_virtual;200 unsigned int pitch;201 int pos_x;202 int pos_y;203};204 205struct sh_mobile_lcdc_priv {206 void __iomem *base;207 int irq;208 atomic_t hw_usecnt;209 struct device *dev;210 struct clk *dot_clk;211 unsigned long lddckr;212 213 struct sh_mobile_lcdc_chan ch[2];214 struct sh_mobile_lcdc_overlay overlays[4];215 216 int started;217 int forced_fourcc; /* 2 channel LCDC must share fourcc setting */218};219 220/* -----------------------------------------------------------------------------221 * Registers access222 */223 224static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = {225 [LDDCKPAT1R] = 0x400,226 [LDDCKPAT2R] = 0x404,227 [LDMT1R] = 0x418,228 [LDMT2R] = 0x41c,229 [LDMT3R] = 0x420,230 [LDDFR] = 0x424,231 [LDSM1R] = 0x428,232 [LDSM2R] = 0x42c,233 [LDSA1R] = 0x430,234 [LDSA2R] = 0x434,235 [LDMLSR] = 0x438,236 [LDHCNR] = 0x448,237 [LDHSYNR] = 0x44c,238 [LDVLNR] = 0x450,239 [LDVSYNR] = 0x454,240 [LDPMR] = 0x460,241 [LDHAJR] = 0x4a0,242};243 244static unsigned long lcdc_offs_sublcd[NR_CH_REGS] = {245 [LDDCKPAT1R] = 0x408,246 [LDDCKPAT2R] = 0x40c,247 [LDMT1R] = 0x600,248 [LDMT2R] = 0x604,249 [LDMT3R] = 0x608,250 [LDDFR] = 0x60c,251 [LDSM1R] = 0x610,252 [LDSM2R] = 0x614,253 [LDSA1R] = 0x618,254 [LDMLSR] = 0x620,255 [LDHCNR] = 0x624,256 [LDHSYNR] = 0x628,257 [LDVLNR] = 0x62c,258 [LDVSYNR] = 0x630,259 [LDPMR] = 0x63c,260};261 262static bool banked(int reg_nr)263{264 switch (reg_nr) {265 case LDMT1R:266 case LDMT2R:267 case LDMT3R:268 case LDDFR:269 case LDSM1R:270 case LDSA1R:271 case LDSA2R:272 case LDMLSR:273 case LDHCNR:274 case LDHSYNR:275 case LDVLNR:276 case LDVSYNR:277 return true;278 }279 return false;280}281 282static int lcdc_chan_is_sublcd(struct sh_mobile_lcdc_chan *chan)283{284 return chan->cfg->chan == LCDC_CHAN_SUBLCD;285}286 287static void lcdc_write_chan(struct sh_mobile_lcdc_chan *chan,288 int reg_nr, unsigned long data)289{290 iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr]);291 if (banked(reg_nr))292 iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr] +293 SIDE_B_OFFSET);294}295 296static void lcdc_write_chan_mirror(struct sh_mobile_lcdc_chan *chan,297 int reg_nr, unsigned long data)298{299 iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr] +300 MIRROR_OFFSET);301}302 303static unsigned long lcdc_read_chan(struct sh_mobile_lcdc_chan *chan,304 int reg_nr)305{306 return ioread32(chan->lcdc->base + chan->reg_offs[reg_nr]);307}308 309static void lcdc_write_overlay(struct sh_mobile_lcdc_overlay *ovl,310 int reg, unsigned long data)311{312 iowrite32(data, ovl->channel->lcdc->base + reg);313 iowrite32(data, ovl->channel->lcdc->base + reg + SIDE_B_OFFSET);314}315 316static void lcdc_write(struct sh_mobile_lcdc_priv *priv,317 unsigned long reg_offs, unsigned long data)318{319 iowrite32(data, priv->base + reg_offs);320}321 322static unsigned long lcdc_read(struct sh_mobile_lcdc_priv *priv,323 unsigned long reg_offs)324{325 return ioread32(priv->base + reg_offs);326}327 328static void lcdc_wait_bit(struct sh_mobile_lcdc_priv *priv,329 unsigned long reg_offs,330 unsigned long mask, unsigned long until)331{332 while ((lcdc_read(priv, reg_offs) & mask) != until)333 cpu_relax();334}335 336/* -----------------------------------------------------------------------------337 * Clock management338 */339 340static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv)341{342 if (atomic_inc_and_test(&priv->hw_usecnt)) {343 clk_prepare_enable(priv->dot_clk);344 pm_runtime_get_sync(priv->dev);345 }346}347 348static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv)349{350 if (atomic_sub_return(1, &priv->hw_usecnt) == -1) {351 pm_runtime_put(priv->dev);352 clk_disable_unprepare(priv->dot_clk);353 }354}355 356static int sh_mobile_lcdc_setup_clocks(struct sh_mobile_lcdc_priv *priv,357 int clock_source)358{359 struct clk *clk;360 char *str;361 362 switch (clock_source) {363 case LCDC_CLK_BUS:364 str = "bus_clk";365 priv->lddckr = LDDCKR_ICKSEL_BUS;366 break;367 case LCDC_CLK_PERIPHERAL:368 str = "peripheral_clk";369 priv->lddckr = LDDCKR_ICKSEL_MIPI;370 break;371 case LCDC_CLK_EXTERNAL:372 str = NULL;373 priv->lddckr = LDDCKR_ICKSEL_HDMI;374 break;375 default:376 return -EINVAL;377 }378 379 if (str == NULL)380 return 0;381 382 clk = clk_get(priv->dev, str);383 if (IS_ERR(clk)) {384 dev_err(priv->dev, "cannot get dot clock %s\n", str);385 return PTR_ERR(clk);386 }387 388 priv->dot_clk = clk;389 return 0;390}391 392/* -----------------------------------------------------------------------------393 * Display, panel and deferred I/O394 */395 396static void lcdc_sys_write_index(void *handle, unsigned long data)397{398 struct sh_mobile_lcdc_chan *ch = handle;399 400 lcdc_write(ch->lcdc, _LDDWD0R, data | LDDWDxR_WDACT);401 lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);402 lcdc_write(ch->lcdc, _LDDWAR, LDDWAR_WA |403 (lcdc_chan_is_sublcd(ch) ? 2 : 0));404 lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);405}406 407static void lcdc_sys_write_data(void *handle, unsigned long data)408{409 struct sh_mobile_lcdc_chan *ch = handle;410 411 lcdc_write(ch->lcdc, _LDDWD0R, data | LDDWDxR_WDACT | LDDWDxR_RSW);412 lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);413 lcdc_write(ch->lcdc, _LDDWAR, LDDWAR_WA |414 (lcdc_chan_is_sublcd(ch) ? 2 : 0));415 lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);416}417 418static unsigned long lcdc_sys_read_data(void *handle)419{420 struct sh_mobile_lcdc_chan *ch = handle;421 422 lcdc_write(ch->lcdc, _LDDRDR, LDDRDR_RSR);423 lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);424 lcdc_write(ch->lcdc, _LDDRAR, LDDRAR_RA |425 (lcdc_chan_is_sublcd(ch) ? 2 : 0));426 udelay(1);427 lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);428 429 return lcdc_read(ch->lcdc, _LDDRDR) & LDDRDR_DRD_MASK;430}431 432static struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = {433 .write_index = lcdc_sys_write_index,434 .write_data = lcdc_sys_write_data,435 .read_data = lcdc_sys_read_data,436};437 438static int sh_mobile_lcdc_sginit(struct fb_info *info, struct list_head *pagereflist)439{440 struct sh_mobile_lcdc_chan *ch = info->par;441 unsigned int nr_pages_max = ch->fb_size >> PAGE_SHIFT;442 struct fb_deferred_io_pageref *pageref;443 int nr_pages = 0;444 445 sg_init_table(ch->sglist, nr_pages_max);446 447 list_for_each_entry(pageref, pagereflist, list) {448 sg_set_page(&ch->sglist[nr_pages++], pageref->page, PAGE_SIZE, 0);449 }450 451 return nr_pages;452}453 454static void sh_mobile_lcdc_deferred_io(struct fb_info *info, struct list_head *pagereflist)455{456 struct sh_mobile_lcdc_chan *ch = info->par;457 const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg;458 459 /* enable clocks before accessing hardware */460 sh_mobile_lcdc_clk_on(ch->lcdc);461 462 /*463 * It's possible to get here without anything on the pagereflist via464 * sh_mobile_lcdc_deferred_io_touch() or via a userspace fsync()465 * invocation. In the former case, the acceleration routines are466 * stepped in to when using the framebuffer console causing the467 * workqueue to be scheduled without any dirty pages on the list.468 *469 * Despite this, a panel update is still needed given that the470 * acceleration routines have their own methods for writing in471 * that still need to be updated.472 *473 * The fsync() and empty pagereflist case could be optimized for,474 * but we don't bother, as any application exhibiting such475 * behaviour is fundamentally broken anyways.476 */477 if (!list_empty(pagereflist)) {478 unsigned int nr_pages = sh_mobile_lcdc_sginit(info, pagereflist);479 480 /* trigger panel update */481 dma_map_sg(ch->lcdc->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);482 if (panel->start_transfer)483 panel->start_transfer(ch, &sh_mobile_lcdc_sys_bus_ops);484 lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG);485 dma_unmap_sg(ch->lcdc->dev, ch->sglist, nr_pages,486 DMA_TO_DEVICE);487 } else {488 if (panel->start_transfer)489 panel->start_transfer(ch, &sh_mobile_lcdc_sys_bus_ops);490 lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG);491 }492}493 494static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info)495{496 struct fb_deferred_io *fbdefio = info->fbdefio;497 498 if (fbdefio)499 schedule_delayed_work(&info->deferred_work, fbdefio->delay);500}501 502static void sh_mobile_lcdc_display_on(struct sh_mobile_lcdc_chan *ch)503{504 const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg;505 506 if (ch->tx_dev) {507 int ret;508 509 ret = ch->tx_dev->ops->display_on(ch->tx_dev);510 if (ret < 0)511 return;512 513 if (ret == SH_MOBILE_LCDC_DISPLAY_DISCONNECTED)514 ch->info->state = FBINFO_STATE_SUSPENDED;515 }516 517 /* HDMI must be enabled before LCDC configuration */518 if (panel->display_on)519 panel->display_on();520}521 522static void sh_mobile_lcdc_display_off(struct sh_mobile_lcdc_chan *ch)523{524 const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg;525 526 if (panel->display_off)527 panel->display_off();528 529 if (ch->tx_dev)530 ch->tx_dev->ops->display_off(ch->tx_dev);531}532 533/* -----------------------------------------------------------------------------534 * Format helpers535 */536 537struct sh_mobile_lcdc_format_info {538 u32 fourcc;539 unsigned int bpp;540 bool yuv;541 u32 lddfr;542};543 544static const struct sh_mobile_lcdc_format_info sh_mobile_format_infos[] = {545 {546 .fourcc = V4L2_PIX_FMT_RGB565,547 .bpp = 16,548 .yuv = false,549 .lddfr = LDDFR_PKF_RGB16,550 }, {551 .fourcc = V4L2_PIX_FMT_BGR24,552 .bpp = 24,553 .yuv = false,554 .lddfr = LDDFR_PKF_RGB24,555 }, {556 .fourcc = V4L2_PIX_FMT_BGR32,557 .bpp = 32,558 .yuv = false,559 .lddfr = LDDFR_PKF_ARGB32,560 }, {561 .fourcc = V4L2_PIX_FMT_NV12,562 .bpp = 12,563 .yuv = true,564 .lddfr = LDDFR_CC | LDDFR_YF_420,565 }, {566 .fourcc = V4L2_PIX_FMT_NV21,567 .bpp = 12,568 .yuv = true,569 .lddfr = LDDFR_CC | LDDFR_YF_420,570 }, {571 .fourcc = V4L2_PIX_FMT_NV16,572 .bpp = 16,573 .yuv = true,574 .lddfr = LDDFR_CC | LDDFR_YF_422,575 }, {576 .fourcc = V4L2_PIX_FMT_NV61,577 .bpp = 16,578 .yuv = true,579 .lddfr = LDDFR_CC | LDDFR_YF_422,580 }, {581 .fourcc = V4L2_PIX_FMT_NV24,582 .bpp = 24,583 .yuv = true,584 .lddfr = LDDFR_CC | LDDFR_YF_444,585 }, {586 .fourcc = V4L2_PIX_FMT_NV42,587 .bpp = 24,588 .yuv = true,589 .lddfr = LDDFR_CC | LDDFR_YF_444,590 },591};592 593static const struct sh_mobile_lcdc_format_info *594sh_mobile_format_info(u32 fourcc)595{596 unsigned int i;597 598 for (i = 0; i < ARRAY_SIZE(sh_mobile_format_infos); ++i) {599 if (sh_mobile_format_infos[i].fourcc == fourcc)600 return &sh_mobile_format_infos[i];601 }602 603 return NULL;604}605 606static int sh_mobile_format_fourcc(const struct fb_var_screeninfo *var)607{608 if (var->grayscale > 1)609 return var->grayscale;610 611 switch (var->bits_per_pixel) {612 case 16:613 return V4L2_PIX_FMT_RGB565;614 case 24:615 return V4L2_PIX_FMT_BGR24;616 case 32:617 return V4L2_PIX_FMT_BGR32;618 default:619 return 0;620 }621}622 623static int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var)624{625 return var->grayscale > 1;626}627 628/* -----------------------------------------------------------------------------629 * Start, stop and IRQ630 */631 632static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)633{634 struct sh_mobile_lcdc_priv *priv = data;635 struct sh_mobile_lcdc_chan *ch;636 unsigned long ldintr;637 int is_sub;638 int k;639 640 /* Acknowledge interrupts and disable further VSYNC End IRQs. */641 ldintr = lcdc_read(priv, _LDINTR);642 lcdc_write(priv, _LDINTR, (ldintr ^ LDINTR_STATUS_MASK) & ~LDINTR_VEE);643 644 /* figure out if this interrupt is for main or sub lcd */645 is_sub = (lcdc_read(priv, _LDSR) & LDSR_MSS) ? 1 : 0;646 647 /* wake up channel and disable clocks */648 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {649 ch = &priv->ch[k];650 651 if (!ch->enabled)652 continue;653 654 /* Frame End */655 if (ldintr & LDINTR_FS) {656 if (is_sub == lcdc_chan_is_sublcd(ch)) {657 ch->frame_end = 1;658 wake_up(&ch->frame_end_wait);659 660 sh_mobile_lcdc_clk_off(priv);661 }662 }663 664 /* VSYNC End */665 if (ldintr & LDINTR_VES)666 complete(&ch->vsync_completion);667 }668 669 return IRQ_HANDLED;670}671 672static int sh_mobile_lcdc_wait_for_vsync(struct sh_mobile_lcdc_chan *ch)673{674 unsigned long ldintr;675 int ret;676 677 /* Enable VSync End interrupt and be careful not to acknowledge any678 * pending interrupt.679 */680 ldintr = lcdc_read(ch->lcdc, _LDINTR);681 ldintr |= LDINTR_VEE | LDINTR_STATUS_MASK;682 lcdc_write(ch->lcdc, _LDINTR, ldintr);683 684 ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion,685 msecs_to_jiffies(100));686 if (!ret)687 return -ETIMEDOUT;688 689 return 0;690}691 692static void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv,693 int start)694{695 unsigned long tmp = lcdc_read(priv, _LDCNT2R);696 int k;697 698 /* start or stop the lcdc */699 if (start)700 lcdc_write(priv, _LDCNT2R, tmp | LDCNT2R_DO);701 else702 lcdc_write(priv, _LDCNT2R, tmp & ~LDCNT2R_DO);703 704 /* wait until power is applied/stopped on all channels */705 for (k = 0; k < ARRAY_SIZE(priv->ch); k++)706 if (lcdc_read(priv, _LDCNT2R) & priv->ch[k].enabled)707 while (1) {708 tmp = lcdc_read_chan(&priv->ch[k], LDPMR)709 & LDPMR_LPS;710 if (start && tmp == LDPMR_LPS)711 break;712 if (!start && tmp == 0)713 break;714 cpu_relax();715 }716 717 if (!start)718 lcdc_write(priv, _LDDCKSTPR, 1); /* stop dotclock */719}720 721static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)722{723 const struct fb_var_screeninfo *var = &ch->info->var;724 const struct fb_videomode *mode = &ch->display.mode;725 unsigned long h_total, hsync_pos, display_h_total;726 u32 tmp;727 728 tmp = ch->ldmt1r_value;729 tmp |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : LDMT1R_VPOL;730 tmp |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : LDMT1R_HPOL;731 tmp |= (ch->cfg->flags & LCDC_FLAGS_DWPOL) ? LDMT1R_DWPOL : 0;732 tmp |= (ch->cfg->flags & LCDC_FLAGS_DIPOL) ? LDMT1R_DIPOL : 0;733 tmp |= (ch->cfg->flags & LCDC_FLAGS_DAPOL) ? LDMT1R_DAPOL : 0;734 tmp |= (ch->cfg->flags & LCDC_FLAGS_HSCNT) ? LDMT1R_HSCNT : 0;735 tmp |= (ch->cfg->flags & LCDC_FLAGS_DWCNT) ? LDMT1R_DWCNT : 0;736 lcdc_write_chan(ch, LDMT1R, tmp);737 738 /* setup SYS bus */739 lcdc_write_chan(ch, LDMT2R, ch->cfg->sys_bus_cfg.ldmt2r);740 lcdc_write_chan(ch, LDMT3R, ch->cfg->sys_bus_cfg.ldmt3r);741 742 /* horizontal configuration */743 h_total = mode->xres + mode->hsync_len + mode->left_margin744 + mode->right_margin;745 tmp = h_total / 8; /* HTCN */746 tmp |= (min(mode->xres, ch->xres) / 8) << 16; /* HDCN */747 lcdc_write_chan(ch, LDHCNR, tmp);748 749 hsync_pos = mode->xres + mode->right_margin;750 tmp = hsync_pos / 8; /* HSYNP */751 tmp |= (mode->hsync_len / 8) << 16; /* HSYNW */752 lcdc_write_chan(ch, LDHSYNR, tmp);753 754 /* vertical configuration */755 tmp = mode->yres + mode->vsync_len + mode->upper_margin756 + mode->lower_margin; /* VTLN */757 tmp |= min(mode->yres, ch->yres) << 16; /* VDLN */758 lcdc_write_chan(ch, LDVLNR, tmp);759 760 tmp = mode->yres + mode->lower_margin; /* VSYNP */761 tmp |= mode->vsync_len << 16; /* VSYNW */762 lcdc_write_chan(ch, LDVSYNR, tmp);763 764 /* Adjust horizontal synchronisation for HDMI */765 display_h_total = mode->xres + mode->hsync_len + mode->left_margin766 + mode->right_margin;767 tmp = ((mode->xres & 7) << 24) | ((display_h_total & 7) << 16)768 | ((mode->hsync_len & 7) << 8) | (hsync_pos & 7);769 lcdc_write_chan(ch, LDHAJR, tmp);770 lcdc_write_chan_mirror(ch, LDHAJR, tmp);771}772 773static void sh_mobile_lcdc_overlay_setup(struct sh_mobile_lcdc_overlay *ovl)774{775 u32 format = 0;776 777 if (!ovl->enabled) {778 lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index));779 lcdc_write_overlay(ovl, LDBnBSIFR(ovl->index), 0);780 lcdc_write(ovl->channel->lcdc, LDBCR,781 LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index));782 return;783 }784 785 ovl->base_addr_y = ovl->dma_handle;786 ovl->base_addr_c = ovl->dma_handle787 + ovl->xres_virtual * ovl->yres_virtual;788 789 switch (ovl->mode) {790 case LCDC_OVERLAY_BLEND:791 format = LDBBSIFR_EN | (ovl->alpha << LDBBSIFR_LAY_SHIFT);792 break;793 794 case LCDC_OVERLAY_ROP3:795 format = LDBBSIFR_EN | LDBBSIFR_BRSEL796 | (ovl->rop3 << LDBBSIFR_ROP3_SHIFT);797 break;798 }799 800 switch (ovl->format->fourcc) {801 case V4L2_PIX_FMT_RGB565:802 case V4L2_PIX_FMT_NV21:803 case V4L2_PIX_FMT_NV61:804 case V4L2_PIX_FMT_NV42:805 format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW;806 break;807 case V4L2_PIX_FMT_BGR24:808 case V4L2_PIX_FMT_NV12:809 case V4L2_PIX_FMT_NV16:810 case V4L2_PIX_FMT_NV24:811 format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW | LDBBSIFR_SWPB;812 break;813 case V4L2_PIX_FMT_BGR32:814 default:815 format |= LDBBSIFR_SWPL;816 break;817 }818 819 switch (ovl->format->fourcc) {820 case V4L2_PIX_FMT_RGB565:821 format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB16;822 break;823 case V4L2_PIX_FMT_BGR24:824 format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB24;825 break;826 case V4L2_PIX_FMT_BGR32:827 format |= LDBBSIFR_AL_PK | LDBBSIFR_RY | LDBBSIFR_RPKF_ARGB32;828 break;829 case V4L2_PIX_FMT_NV12:830 case V4L2_PIX_FMT_NV21:831 format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_420;832 break;833 case V4L2_PIX_FMT_NV16:834 case V4L2_PIX_FMT_NV61:835 format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_422;836 break;837 case V4L2_PIX_FMT_NV24:838 case V4L2_PIX_FMT_NV42:839 format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_444;840 break;841 }842 843 lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index));844 845 lcdc_write_overlay(ovl, LDBnBSIFR(ovl->index), format);846 847 lcdc_write_overlay(ovl, LDBnBSSZR(ovl->index),848 (ovl->yres << LDBBSSZR_BVSS_SHIFT) |849 (ovl->xres << LDBBSSZR_BHSS_SHIFT));850 lcdc_write_overlay(ovl, LDBnBLOCR(ovl->index),851 (ovl->pos_y << LDBBLOCR_CVLC_SHIFT) |852 (ovl->pos_x << LDBBLOCR_CHLC_SHIFT));853 lcdc_write_overlay(ovl, LDBnBSMWR(ovl->index),854 ovl->pitch << LDBBSMWR_BSMW_SHIFT);855 856 lcdc_write_overlay(ovl, LDBnBSAYR(ovl->index), ovl->base_addr_y);857 lcdc_write_overlay(ovl, LDBnBSACR(ovl->index), ovl->base_addr_c);858 859 lcdc_write(ovl->channel->lcdc, LDBCR,860 LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index));861}862 863/*864 * __sh_mobile_lcdc_start - Configure and start the LCDC865 * @priv: LCDC device866 *867 * Configure all enabled channels and start the LCDC device. All external868 * devices (clocks, MERAM, panels, ...) are not touched by this function.869 */870static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)871{872 struct sh_mobile_lcdc_chan *ch;873 unsigned long tmp;874 int k, m;875 876 /* Enable LCDC channels. Read data from external memory, avoid using the877 * BEU for now.878 */879 lcdc_write(priv, _LDCNT2R, priv->ch[0].enabled | priv->ch[1].enabled);880 881 /* Stop the LCDC first and disable all interrupts. */882 sh_mobile_lcdc_start_stop(priv, 0);883 lcdc_write(priv, _LDINTR, 0);884 885 /* Configure power supply, dot clocks and start them. */886 tmp = priv->lddckr;887 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {888 ch = &priv->ch[k];889 if (!ch->enabled)890 continue;891 892 /* Power supply */893 lcdc_write_chan(ch, LDPMR, 0);894 895 m = ch->cfg->clock_divider;896 if (!m)897 continue;898 899 /* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider900 * denominator.901 */902 lcdc_write_chan(ch, LDDCKPAT1R, 0);903 lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1);904 905 if (m == 1)906 m = LDDCKR_MOSEL;907 tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0);908 }909 910 lcdc_write(priv, _LDDCKR, tmp);911 lcdc_write(priv, _LDDCKSTPR, 0);912 lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0);913 914 /* Setup geometry, format, frame buffer memory and operation mode. */915 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {916 ch = &priv->ch[k];917 if (!ch->enabled)918 continue;919 920 sh_mobile_lcdc_geometry(ch);921 922 tmp = ch->format->lddfr;923 924 if (ch->format->yuv) {925 switch (ch->colorspace) {926 case V4L2_COLORSPACE_REC709:927 tmp |= LDDFR_CF1;928 break;929 case V4L2_COLORSPACE_JPEG:930 tmp |= LDDFR_CF0;931 break;932 }933 }934 935 lcdc_write_chan(ch, LDDFR, tmp);936 lcdc_write_chan(ch, LDMLSR, ch->line_size);937 lcdc_write_chan(ch, LDSA1R, ch->base_addr_y);938 if (ch->format->yuv)939 lcdc_write_chan(ch, LDSA2R, ch->base_addr_c);940 941 /* When using deferred I/O mode, configure the LCDC for one-shot942 * operation and enable the frame end interrupt. Otherwise use943 * continuous read mode.944 */945 if (ch->ldmt1r_value & LDMT1R_IFM &&946 ch->cfg->sys_bus_cfg.deferred_io_msec) {947 lcdc_write_chan(ch, LDSM1R, LDSM1R_OS);948 lcdc_write(priv, _LDINTR, LDINTR_FE);949 } else {950 lcdc_write_chan(ch, LDSM1R, 0);951 }952 }953 954 /* Word and long word swap. */955 switch (priv->ch[0].format->fourcc) {956 case V4L2_PIX_FMT_RGB565:957 case V4L2_PIX_FMT_NV21:958 case V4L2_PIX_FMT_NV61:959 case V4L2_PIX_FMT_NV42:960 tmp = LDDDSR_LS | LDDDSR_WS;961 break;962 case V4L2_PIX_FMT_BGR24:963 case V4L2_PIX_FMT_NV12:964 case V4L2_PIX_FMT_NV16:965 case V4L2_PIX_FMT_NV24:966 tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;967 break;968 case V4L2_PIX_FMT_BGR32:969 default:970 tmp = LDDDSR_LS;971 break;972 }973 lcdc_write(priv, _LDDDSR, tmp);974 975 /* Enable the display output. */976 lcdc_write(priv, _LDCNT1R, LDCNT1R_DE);977 sh_mobile_lcdc_start_stop(priv, 1);978 priv->started = 1;979}980 981static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)982{983 struct sh_mobile_lcdc_chan *ch;984 unsigned long tmp;985 int ret;986 int k;987 988 /* enable clocks before accessing the hardware */989 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {990 if (priv->ch[k].enabled)991 sh_mobile_lcdc_clk_on(priv);992 }993 994 /* reset */995 lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LDCNT2R_BR);996 lcdc_wait_bit(priv, _LDCNT2R, LDCNT2R_BR, 0);997 998 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {999 const struct sh_mobile_lcdc_panel_cfg *panel;1000 1001 ch = &priv->ch[k];1002 if (!ch->enabled)1003 continue;1004 1005 panel = &ch->cfg->panel_cfg;1006 if (panel->setup_sys) {1007 ret = panel->setup_sys(ch, &sh_mobile_lcdc_sys_bus_ops);1008 if (ret)1009 return ret;1010 }1011 }1012 1013 /* Compute frame buffer base address and pitch for each channel. */1014 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {1015 ch = &priv->ch[k];1016 if (!ch->enabled)1017 continue;1018 1019 ch->base_addr_y = ch->dma_handle;1020 ch->base_addr_c = ch->dma_handle1021 + ch->xres_virtual * ch->yres_virtual;1022 ch->line_size = ch->pitch;1023 }1024 1025 for (k = 0; k < ARRAY_SIZE(priv->overlays); ++k) {1026 struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[k];1027 sh_mobile_lcdc_overlay_setup(ovl);1028 }1029 1030 /* Start the LCDC. */1031 __sh_mobile_lcdc_start(priv);1032 1033 /* Setup deferred I/O, tell the board code to enable the panels, and1034 * turn backlight on.1035 */1036 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {1037 ch = &priv->ch[k];1038 if (!ch->enabled)1039 continue;1040 1041 tmp = ch->cfg->sys_bus_cfg.deferred_io_msec;1042 if (ch->ldmt1r_value & LDMT1R_IFM && tmp) {1043 ch->defio.deferred_io = sh_mobile_lcdc_deferred_io;1044 ch->defio.delay = msecs_to_jiffies(tmp);1045 ch->info->fbdefio = &ch->defio;1046 fb_deferred_io_init(ch->info);1047 }1048 1049 sh_mobile_lcdc_display_on(ch);1050 1051 if (ch->bl) {1052 ch->bl->props.power = FB_BLANK_UNBLANK;1053 backlight_update_status(ch->bl);1054 }1055 }1056 1057 return 0;1058}1059 1060static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)1061{1062 struct sh_mobile_lcdc_chan *ch;1063 int k;1064 1065 /* clean up deferred io and ask board code to disable panel */1066 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {1067 ch = &priv->ch[k];1068 if (!ch->enabled)1069 continue;1070 1071 /* deferred io mode:1072 * flush frame, and wait for frame end interrupt1073 * clean up deferred io and enable clock1074 */1075 if (ch->info && ch->info->fbdefio) {1076 ch->frame_end = 0;1077 schedule_delayed_work(&ch->info->deferred_work, 0);1078 wait_event(ch->frame_end_wait, ch->frame_end);1079 fb_deferred_io_cleanup(ch->info);1080 ch->info->fbdefio = NULL;1081 sh_mobile_lcdc_clk_on(priv);1082 }1083 1084 if (ch->bl) {1085 ch->bl->props.power = FB_BLANK_POWERDOWN;1086 backlight_update_status(ch->bl);1087 }1088 1089 sh_mobile_lcdc_display_off(ch);1090 }1091 1092 /* stop the lcdc */1093 if (priv->started) {1094 sh_mobile_lcdc_start_stop(priv, 0);1095 priv->started = 0;1096 }1097 1098 /* stop clocks */1099 for (k = 0; k < ARRAY_SIZE(priv->ch); k++)1100 if (priv->ch[k].enabled)1101 sh_mobile_lcdc_clk_off(priv);1102}1103 1104static int __sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var,1105 struct fb_info *info)1106{1107 if (var->xres > MAX_XRES || var->yres > MAX_YRES)1108 return -EINVAL;1109 1110 /* Make sure the virtual resolution is at least as big as the visible1111 * resolution.1112 */1113 if (var->xres_virtual < var->xres)1114 var->xres_virtual = var->xres;1115 if (var->yres_virtual < var->yres)1116 var->yres_virtual = var->yres;1117 1118 if (sh_mobile_format_is_fourcc(var)) {1119 const struct sh_mobile_lcdc_format_info *format;1120 1121 format = sh_mobile_format_info(var->grayscale);1122 if (format == NULL)1123 return -EINVAL;1124 var->bits_per_pixel = format->bpp;1125 1126 /* Default to RGB and JPEG color-spaces for RGB and YUV formats1127 * respectively.1128 */1129 if (!format->yuv)1130 var->colorspace = V4L2_COLORSPACE_SRGB;1131 else if (var->colorspace != V4L2_COLORSPACE_REC709)1132 var->colorspace = V4L2_COLORSPACE_JPEG;1133 } else {1134 if (var->bits_per_pixel <= 16) { /* RGB 565 */1135 var->bits_per_pixel = 16;1136 var->red.offset = 11;1137 var->red.length = 5;1138 var->green.offset = 5;1139 var->green.length = 6;1140 var->blue.offset = 0;1141 var->blue.length = 5;1142 var->transp.offset = 0;1143 var->transp.length = 0;1144 } else if (var->bits_per_pixel <= 24) { /* RGB 888 */1145 var->bits_per_pixel = 24;1146 var->red.offset = 16;1147 var->red.length = 8;1148 var->green.offset = 8;1149 var->green.length = 8;1150 var->blue.offset = 0;1151 var->blue.length = 8;1152 var->transp.offset = 0;1153 var->transp.length = 0;1154 } else if (var->bits_per_pixel <= 32) { /* RGBA 888 */1155 var->bits_per_pixel = 32;1156 var->red.offset = 16;1157 var->red.length = 8;1158 var->green.offset = 8;1159 var->green.length = 8;1160 var->blue.offset = 0;1161 var->blue.length = 8;1162 var->transp.offset = 24;1163 var->transp.length = 8;1164 } else1165 return -EINVAL;1166 1167 var->red.msb_right = 0;1168 var->green.msb_right = 0;1169 var->blue.msb_right = 0;1170 var->transp.msb_right = 0;1171 }1172 1173 /* Make sure we don't exceed our allocated memory. */1174 if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 >1175 info->fix.smem_len)1176 return -EINVAL;1177 1178 return 0;1179}1180 1181/* -----------------------------------------------------------------------------1182 * Frame buffer operations - Overlays1183 */1184 1185static ssize_t1186overlay_alpha_show(struct device *dev, struct device_attribute *attr, char *buf)1187{1188 struct fb_info *info = dev_get_drvdata(dev);1189 struct sh_mobile_lcdc_overlay *ovl = info->par;1190 1191 return sysfs_emit(buf, "%u\n", ovl->alpha);1192}1193 1194static ssize_t1195overlay_alpha_store(struct device *dev, struct device_attribute *attr,1196 const char *buf, size_t count)1197{1198 struct fb_info *info = dev_get_drvdata(dev);1199 struct sh_mobile_lcdc_overlay *ovl = info->par;1200 unsigned int alpha;1201 char *endp;1202 1203 alpha = simple_strtoul(buf, &endp, 10);1204 if (isspace(*endp))1205 endp++;1206 1207 if (endp - buf != count)1208 return -EINVAL;1209 1210 if (alpha > 255)1211 return -EINVAL;1212 1213 if (ovl->alpha != alpha) {1214 ovl->alpha = alpha;1215 1216 if (ovl->mode == LCDC_OVERLAY_BLEND && ovl->enabled)1217 sh_mobile_lcdc_overlay_setup(ovl);1218 }1219 1220 return count;1221}1222 1223static ssize_t1224overlay_mode_show(struct device *dev, struct device_attribute *attr, char *buf)1225{1226 struct fb_info *info = dev_get_drvdata(dev);1227 struct sh_mobile_lcdc_overlay *ovl = info->par;1228 1229 return sysfs_emit(buf, "%u\n", ovl->mode);1230}1231 1232static ssize_t1233overlay_mode_store(struct device *dev, struct device_attribute *attr,1234 const char *buf, size_t count)1235{1236 struct fb_info *info = dev_get_drvdata(dev);1237 struct sh_mobile_lcdc_overlay *ovl = info->par;1238 unsigned int mode;1239 char *endp;1240 1241 mode = simple_strtoul(buf, &endp, 10);1242 if (isspace(*endp))1243 endp++;1244 1245 if (endp - buf != count)1246 return -EINVAL;1247 1248 if (mode != LCDC_OVERLAY_BLEND && mode != LCDC_OVERLAY_ROP3)1249 return -EINVAL;1250 1251 if (ovl->mode != mode) {1252 ovl->mode = mode;1253 1254 if (ovl->enabled)1255 sh_mobile_lcdc_overlay_setup(ovl);1256 }1257 1258 return count;1259}1260 1261static ssize_t1262overlay_position_show(struct device *dev, struct device_attribute *attr,1263 char *buf)1264{1265 struct fb_info *info = dev_get_drvdata(dev);1266 struct sh_mobile_lcdc_overlay *ovl = info->par;1267 1268 return sysfs_emit(buf, "%d,%d\n", ovl->pos_x, ovl->pos_y);1269}1270 1271static ssize_t1272overlay_position_store(struct device *dev, struct device_attribute *attr,1273 const char *buf, size_t count)1274{1275 struct fb_info *info = dev_get_drvdata(dev);1276 struct sh_mobile_lcdc_overlay *ovl = info->par;1277 char *endp;1278 int pos_x;1279 int pos_y;1280 1281 pos_x = simple_strtol(buf, &endp, 10);1282 if (*endp != ',')1283 return -EINVAL;1284 1285 pos_y = simple_strtol(endp + 1, &endp, 10);1286 if (isspace(*endp))1287 endp++;1288 1289 if (endp - buf != count)1290 return -EINVAL;1291 1292 if (ovl->pos_x != pos_x || ovl->pos_y != pos_y) {1293 ovl->pos_x = pos_x;1294 ovl->pos_y = pos_y;1295 1296 if (ovl->enabled)1297 sh_mobile_lcdc_overlay_setup(ovl);1298 }1299 1300 return count;1301}1302 1303static ssize_t1304overlay_rop3_show(struct device *dev, struct device_attribute *attr, char *buf)1305{1306 struct fb_info *info = dev_get_drvdata(dev);1307 struct sh_mobile_lcdc_overlay *ovl = info->par;1308 1309 return sysfs_emit(buf, "%u\n", ovl->rop3);1310}1311 1312static ssize_t1313overlay_rop3_store(struct device *dev, struct device_attribute *attr,1314 const char *buf, size_t count)1315{1316 struct fb_info *info = dev_get_drvdata(dev);1317 struct sh_mobile_lcdc_overlay *ovl = info->par;1318 unsigned int rop3;1319 char *endp;1320 1321 rop3 = simple_strtoul(buf, &endp, 10);1322 if (isspace(*endp))1323 endp++;1324 1325 if (endp - buf != count)1326 return -EINVAL;1327 1328 if (rop3 > 255)1329 return -EINVAL;1330 1331 if (ovl->rop3 != rop3) {1332 ovl->rop3 = rop3;1333 1334 if (ovl->mode == LCDC_OVERLAY_ROP3 && ovl->enabled)1335 sh_mobile_lcdc_overlay_setup(ovl);1336 }1337 1338 return count;1339}1340 1341static const struct device_attribute overlay_sysfs_attrs[] = {1342 __ATTR(ovl_alpha, S_IRUGO|S_IWUSR,1343 overlay_alpha_show, overlay_alpha_store),1344 __ATTR(ovl_mode, S_IRUGO|S_IWUSR,1345 overlay_mode_show, overlay_mode_store),1346 __ATTR(ovl_position, S_IRUGO|S_IWUSR,1347 overlay_position_show, overlay_position_store),1348 __ATTR(ovl_rop3, S_IRUGO|S_IWUSR,1349 overlay_rop3_show, overlay_rop3_store),1350};1351 1352static const struct fb_fix_screeninfo sh_mobile_lcdc_overlay_fix = {1353 .id = "SH Mobile LCDC",1354 .type = FB_TYPE_PACKED_PIXELS,1355 .visual = FB_VISUAL_TRUECOLOR,1356 .accel = FB_ACCEL_NONE,1357 .xpanstep = 1,1358 .ypanstep = 1,1359 .ywrapstep = 0,1360 .capabilities = FB_CAP_FOURCC,1361};1362 1363static int sh_mobile_lcdc_overlay_pan(struct fb_var_screeninfo *var,1364 struct fb_info *info)1365{1366 struct sh_mobile_lcdc_overlay *ovl = info->par;1367 unsigned long base_addr_y;1368 unsigned long base_addr_c;1369 unsigned long y_offset;1370 unsigned long c_offset;1371 1372 if (!ovl->format->yuv) {1373 y_offset = (var->yoffset * ovl->xres_virtual + var->xoffset)1374 * ovl->format->bpp / 8;1375 c_offset = 0;1376 } else {1377 unsigned int xsub = ovl->format->bpp < 24 ? 2 : 1;1378 unsigned int ysub = ovl->format->bpp < 16 ? 2 : 1;1379 1380 y_offset = var->yoffset * ovl->xres_virtual + var->xoffset;1381 c_offset = var->yoffset / ysub * ovl->xres_virtual * 2 / xsub1382 + var->xoffset * 2 / xsub;1383 }1384 1385 /* If the Y offset hasn't changed, the C offset hasn't either. There's1386 * nothing to do in that case.1387 */1388 if (y_offset == ovl->pan_y_offset)1389 return 0;1390 1391 /* Set the source address for the next refresh */1392 base_addr_y = ovl->dma_handle + y_offset;1393 base_addr_c = ovl->dma_handle + ovl->xres_virtual * ovl->yres_virtual1394 + c_offset;1395 1396 ovl->base_addr_y = base_addr_y;1397 ovl->base_addr_c = base_addr_c;1398 ovl->pan_y_offset = y_offset;1399 1400 lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index));1401 1402 lcdc_write_overlay(ovl, LDBnBSAYR(ovl->index), ovl->base_addr_y);1403 lcdc_write_overlay(ovl, LDBnBSACR(ovl->index), ovl->base_addr_c);1404 1405 lcdc_write(ovl->channel->lcdc, LDBCR,1406 LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index));1407 1408 return 0;1409}1410 1411static int sh_mobile_lcdc_overlay_ioctl(struct fb_info *info, unsigned int cmd,1412 unsigned long arg)1413{1414 struct sh_mobile_lcdc_overlay *ovl = info->par;1415 1416 switch (cmd) {1417 case FBIO_WAITFORVSYNC:1418 return sh_mobile_lcdc_wait_for_vsync(ovl->channel);1419 1420 default:1421 return -ENOIOCTLCMD;1422 }1423}1424 1425static int sh_mobile_lcdc_overlay_check_var(struct fb_var_screeninfo *var,1426 struct fb_info *info)1427{1428 return __sh_mobile_lcdc_check_var(var, info);1429}1430 1431static int sh_mobile_lcdc_overlay_set_par(struct fb_info *info)1432{1433 struct sh_mobile_lcdc_overlay *ovl = info->par;1434 1435 ovl->format =1436 sh_mobile_format_info(sh_mobile_format_fourcc(&info->var));1437 1438 ovl->xres = info->var.xres;1439 ovl->xres_virtual = info->var.xres_virtual;1440 ovl->yres = info->var.yres;1441 ovl->yres_virtual = info->var.yres_virtual;1442 1443 if (ovl->format->yuv)1444 ovl->pitch = info->var.xres_virtual;1445 else1446 ovl->pitch = info->var.xres_virtual * ovl->format->bpp / 8;1447 1448 sh_mobile_lcdc_overlay_setup(ovl);1449 1450 info->fix.line_length = ovl->pitch;1451 1452 if (sh_mobile_format_is_fourcc(&info->var)) {1453 info->fix.type = FB_TYPE_FOURCC;1454 info->fix.visual = FB_VISUAL_FOURCC;1455 } else {1456 info->fix.type = FB_TYPE_PACKED_PIXELS;1457 info->fix.visual = FB_VISUAL_TRUECOLOR;1458 }1459 1460 return 0;1461}1462 1463/* Overlay blanking. Disable the overlay when blanked. */1464static int sh_mobile_lcdc_overlay_blank(int blank, struct fb_info *info)1465{1466 struct sh_mobile_lcdc_overlay *ovl = info->par;1467 1468 ovl->enabled = !blank;1469 sh_mobile_lcdc_overlay_setup(ovl);1470 1471 /* Prevent the backlight from receiving a blanking event by returning1472 * a non-zero value.1473 */1474 return 1;1475}1476 1477static int1478sh_mobile_lcdc_overlay_mmap(struct fb_info *info, struct vm_area_struct *vma)1479{1480 struct sh_mobile_lcdc_overlay *ovl = info->par;1481 1482 if (info->fbdefio)1483 return fb_deferred_io_mmap(info, vma);1484 1485 vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);1486 1487 return dma_mmap_coherent(ovl->channel->lcdc->dev, vma, ovl->fb_mem,1488 ovl->dma_handle, ovl->fb_size);1489}1490 1491static const struct fb_ops sh_mobile_lcdc_overlay_ops = {1492 .owner = THIS_MODULE,1493 __FB_DEFAULT_DMAMEM_OPS_RDWR,1494 .fb_blank = sh_mobile_lcdc_overlay_blank,1495 .fb_pan_display = sh_mobile_lcdc_overlay_pan,1496 __FB_DEFAULT_DMAMEM_OPS_DRAW,1497 .fb_ioctl = sh_mobile_lcdc_overlay_ioctl,1498 .fb_check_var = sh_mobile_lcdc_overlay_check_var,1499 .fb_set_par = sh_mobile_lcdc_overlay_set_par,1500 .fb_mmap = sh_mobile_lcdc_overlay_mmap,1501};1502 1503static void1504sh_mobile_lcdc_overlay_fb_unregister(struct sh_mobile_lcdc_overlay *ovl)1505{1506 struct fb_info *info = ovl->info;1507 1508 if (info == NULL || info->dev == NULL)1509 return;1510 1511 unregister_framebuffer(ovl->info);1512}1513 1514static int1515sh_mobile_lcdc_overlay_fb_register(struct sh_mobile_lcdc_overlay *ovl)1516{1517 struct sh_mobile_lcdc_priv *lcdc = ovl->channel->lcdc;1518 struct fb_info *info = ovl->info;1519 unsigned int i;1520 int ret;1521 1522 if (info == NULL)1523 return 0;1524 1525 ret = register_framebuffer(info);1526 if (ret < 0)1527 return ret;1528 1529 dev_info(lcdc->dev, "registered %s/overlay %u as %dx%d %dbpp.\n",1530 dev_name(lcdc->dev), ovl->index, info->var.xres,1531 info->var.yres, info->var.bits_per_pixel);1532 1533 for (i = 0; i < ARRAY_SIZE(overlay_sysfs_attrs); ++i) {1534 ret = device_create_file(info->dev, &overlay_sysfs_attrs[i]);1535 if (ret < 0)1536 return ret;1537 }1538 1539 return 0;1540}1541 1542static void1543sh_mobile_lcdc_overlay_fb_cleanup(struct sh_mobile_lcdc_overlay *ovl)1544{1545 struct fb_info *info = ovl->info;1546 1547 if (info == NULL || info->device == NULL)1548 return;1549 1550 framebuffer_release(info);1551}1552 1553static int1554sh_mobile_lcdc_overlay_fb_init(struct sh_mobile_lcdc_overlay *ovl)1555{1556 struct sh_mobile_lcdc_priv *priv = ovl->channel->lcdc;1557 struct fb_var_screeninfo *var;1558 struct fb_info *info;1559 1560 /* Allocate and initialize the frame buffer device. */1561 info = framebuffer_alloc(0, priv->dev);1562 if (!info)1563 return -ENOMEM;1564 1565 ovl->info = info;1566 1567 info->fbops = &sh_mobile_lcdc_overlay_ops;1568 info->device = priv->dev;1569 info->flags |= FBINFO_VIRTFB;1570 info->screen_buffer = ovl->fb_mem;1571 info->par = ovl;1572 1573 /* Initialize fixed screen information. Restrict pan to 2 lines steps1574 * for NV12 and NV21.1575 */1576 info->fix = sh_mobile_lcdc_overlay_fix;1577 snprintf(info->fix.id, sizeof(info->fix.id),1578 "SHMobile ovl %u", ovl->index);1579 info->fix.smem_start = ovl->dma_handle;1580 info->fix.smem_len = ovl->fb_size;1581 info->fix.line_length = ovl->pitch;1582 1583 if (ovl->format->yuv)1584 info->fix.visual = FB_VISUAL_FOURCC;1585 else1586 info->fix.visual = FB_VISUAL_TRUECOLOR;1587 1588 switch (ovl->format->fourcc) {1589 case V4L2_PIX_FMT_NV12:1590 case V4L2_PIX_FMT_NV21:1591 info->fix.ypanstep = 2;1592 fallthrough;1593 case V4L2_PIX_FMT_NV16:1594 case V4L2_PIX_FMT_NV61:1595 info->fix.xpanstep = 2;1596 }1597 1598 /* Initialize variable screen information. */1599 var = &info->var;1600 memset(var, 0, sizeof(*var));1601 var->xres = ovl->xres;1602 var->yres = ovl->yres;1603 var->xres_virtual = ovl->xres_virtual;1604 var->yres_virtual = ovl->yres_virtual;1605 var->activate = FB_ACTIVATE_NOW;1606 1607 /* Use the legacy API by default for RGB formats, and the FOURCC API1608 * for YUV formats.1609 */1610 if (!ovl->format->yuv)1611 var->bits_per_pixel = ovl->format->bpp;1612 else1613 var->grayscale = ovl->format->fourcc;1614 1615 return sh_mobile_lcdc_overlay_check_var(var, info);1616}1617 1618/* -----------------------------------------------------------------------------1619 * Frame buffer operations - main frame buffer1620 */1621 1622static int sh_mobile_lcdc_setcolreg(u_int regno,1623 u_int red, u_int green, u_int blue,1624 u_int transp, struct fb_info *info)1625{1626 u32 *palette = info->pseudo_palette;1627 1628 if (regno >= PALETTE_NR)1629 return -EINVAL;1630 1631 /* only FB_VISUAL_TRUECOLOR supported */1632 1633 red >>= 16 - info->var.red.length;1634 green >>= 16 - info->var.green.length;1635 blue >>= 16 - info->var.blue.length;1636 transp >>= 16 - info->var.transp.length;1637 1638 palette[regno] = (red << info->var.red.offset) |1639 (green << info->var.green.offset) |1640 (blue << info->var.blue.offset) |1641 (transp << info->var.transp.offset);1642 1643 return 0;1644}1645 1646static const struct fb_fix_screeninfo sh_mobile_lcdc_fix = {1647 .id = "SH Mobile LCDC",1648 .type = FB_TYPE_PACKED_PIXELS,1649 .visual = FB_VISUAL_TRUECOLOR,1650 .accel = FB_ACCEL_NONE,1651 .xpanstep = 1,1652 .ypanstep = 1,1653 .ywrapstep = 0,1654 .capabilities = FB_CAP_FOURCC,1655};1656 1657static void sh_mobile_lcdc_fillrect(struct fb_info *info,1658 const struct fb_fillrect *rect)1659{1660 sys_fillrect(info, rect);1661 sh_mobile_lcdc_deferred_io_touch(info);1662}1663 1664static void sh_mobile_lcdc_copyarea(struct fb_info *info,1665 const struct fb_copyarea *area)1666{1667 sys_copyarea(info, area);1668 sh_mobile_lcdc_deferred_io_touch(info);1669}1670 1671static void sh_mobile_lcdc_imageblit(struct fb_info *info,1672 const struct fb_image *image)1673{1674 sys_imageblit(info, image);1675 sh_mobile_lcdc_deferred_io_touch(info);1676}1677 1678static int sh_mobile_lcdc_pan(struct fb_var_screeninfo *var,1679 struct fb_info *info)1680{1681 struct sh_mobile_lcdc_chan *ch = info->par;1682 struct sh_mobile_lcdc_priv *priv = ch->lcdc;1683 unsigned long ldrcntr;1684 unsigned long base_addr_y, base_addr_c;1685 unsigned long y_offset;1686 unsigned long c_offset;1687 1688 if (!ch->format->yuv) {1689 y_offset = (var->yoffset * ch->xres_virtual + var->xoffset)1690 * ch->format->bpp / 8;1691 c_offset = 0;1692 } else {1693 unsigned int xsub = ch->format->bpp < 24 ? 2 : 1;1694 unsigned int ysub = ch->format->bpp < 16 ? 2 : 1;1695 1696 y_offset = var->yoffset * ch->xres_virtual + var->xoffset;1697 c_offset = var->yoffset / ysub * ch->xres_virtual * 2 / xsub1698 + var->xoffset * 2 / xsub;1699 }1700 1701 /* If the Y offset hasn't changed, the C offset hasn't either. There's1702 * nothing to do in that case.1703 */1704 if (y_offset == ch->pan_y_offset)1705 return 0;1706 1707 /* Set the source address for the next refresh */1708 base_addr_y = ch->dma_handle + y_offset;1709 base_addr_c = ch->dma_handle + ch->xres_virtual * ch->yres_virtual1710 + c_offset;1711 1712 ch->base_addr_y = base_addr_y;1713 ch->base_addr_c = base_addr_c;1714 ch->pan_y_offset = y_offset;1715 1716 lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);1717 if (ch->format->yuv)1718 lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c);1719 1720 ldrcntr = lcdc_read(priv, _LDRCNTR);1721 if (lcdc_chan_is_sublcd(ch))1722 lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS);1723 else1724 lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_MRS);1725 1726 1727 sh_mobile_lcdc_deferred_io_touch(info);1728 1729 return 0;1730}1731 1732static int sh_mobile_lcdc_ioctl(struct fb_info *info, unsigned int cmd,1733 unsigned long arg)1734{1735 struct sh_mobile_lcdc_chan *ch = info->par;1736 int retval;1737 1738 switch (cmd) {1739 case FBIO_WAITFORVSYNC:1740 retval = sh_mobile_lcdc_wait_for_vsync(ch);1741 break;1742 1743 default:1744 retval = -ENOIOCTLCMD;1745 break;1746 }1747 return retval;1748}1749 1750static void sh_mobile_fb_reconfig(struct fb_info *info)1751{1752 struct sh_mobile_lcdc_chan *ch = info->par;1753 struct fb_var_screeninfo var;1754 struct fb_videomode mode;1755 1756 if (ch->use_count > 1 || (ch->use_count == 1 && !info->fbcon_par))1757 /* More framebuffer users are active */1758 return;1759 1760 fb_var_to_videomode(&mode, &info->var);1761 1762 if (fb_mode_is_equal(&ch->display.mode, &mode))1763 return;1764 1765 /* Display has been re-plugged, framebuffer is free now, reconfigure */1766 var = info->var;1767 fb_videomode_to_var(&var, &ch->display.mode);1768 var.width = ch->display.width;1769 var.height = ch->display.height;1770 var.activate = FB_ACTIVATE_NOW;1771 1772 if (fb_set_var(info, &var) < 0)1773 /* Couldn't reconfigure, hopefully, can continue as before */1774 return;1775 1776 fbcon_update_vcs(info, true);1777}1778 1779/*1780 * Locking: both .fb_release() and .fb_open() are called with info->lock held if1781 * user == 1, or with console sem held, if user == 0.1782 */1783static int sh_mobile_lcdc_release(struct fb_info *info, int user)1784{1785 struct sh_mobile_lcdc_chan *ch = info->par;1786 1787 mutex_lock(&ch->open_lock);1788 dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count);1789 1790 ch->use_count--;1791 1792 /* Nothing to reconfigure, when called from fbcon */1793 if (user) {1794 console_lock();1795 sh_mobile_fb_reconfig(info);1796 console_unlock();1797 }1798 1799 mutex_unlock(&ch->open_lock);1800 1801 return 0;1802}1803 1804static int sh_mobile_lcdc_open(struct fb_info *info, int user)1805{1806 struct sh_mobile_lcdc_chan *ch = info->par;1807 1808 mutex_lock(&ch->open_lock);1809 ch->use_count++;1810 1811 dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count);1812 mutex_unlock(&ch->open_lock);1813 1814 return 0;1815}1816 1817static int sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var,1818 struct fb_info *info)1819{1820 struct sh_mobile_lcdc_chan *ch = info->par;1821 struct sh_mobile_lcdc_priv *p = ch->lcdc;1822 unsigned int best_dist = (unsigned int)-1;1823 unsigned int best_xres = 0;1824 unsigned int best_yres = 0;1825 unsigned int i;1826 int ret;1827 1828 /* If board code provides us with a list of available modes, make sure1829 * we use one of them. Find the mode closest to the requested one. The1830 * distance between two modes is defined as the size of the1831 * non-overlapping parts of the two rectangles.1832 */1833 for (i = 0; i < ch->cfg->num_modes; ++i) {1834 const struct fb_videomode *mode = &ch->cfg->lcd_modes[i];1835 unsigned int dist;1836 1837 /* We can only round up. */1838 if (var->xres > mode->xres || var->yres > mode->yres)1839 continue;1840 1841 dist = var->xres * var->yres + mode->xres * mode->yres1842 - 2 * min(var->xres, mode->xres)1843 * min(var->yres, mode->yres);1844 1845 if (dist < best_dist) {1846 best_xres = mode->xres;1847 best_yres = mode->yres;1848 best_dist = dist;1849 }1850 }1851 1852 /* If no available mode can be used, return an error. */1853 if (ch->cfg->num_modes != 0) {1854 if (best_dist == (unsigned int)-1)1855 return -EINVAL;1856 1857 var->xres = best_xres;1858 var->yres = best_yres;1859 }1860 1861 ret = __sh_mobile_lcdc_check_var(var, info);1862 if (ret < 0)1863 return ret;1864 1865 /* only accept the forced_fourcc for dual channel configurations */1866 if (p->forced_fourcc &&1867 p->forced_fourcc != sh_mobile_format_fourcc(var))1868 return -EINVAL;1869 1870 return 0;1871}1872 1873static int sh_mobile_lcdc_set_par(struct fb_info *info)1874{1875 struct sh_mobile_lcdc_chan *ch = info->par;1876 int ret;1877 1878 sh_mobile_lcdc_stop(ch->lcdc);1879 1880 ch->format = sh_mobile_format_info(sh_mobile_format_fourcc(&info->var));1881 ch->colorspace = info->var.colorspace;1882 1883 ch->xres = info->var.xres;1884 ch->xres_virtual = info->var.xres_virtual;1885 ch->yres = info->var.yres;1886 ch->yres_virtual = info->var.yres_virtual;1887 1888 if (ch->format->yuv)1889 ch->pitch = info->var.xres_virtual;1890 else1891 ch->pitch = info->var.xres_virtual * ch->format->bpp / 8;1892 1893 ret = sh_mobile_lcdc_start(ch->lcdc);1894 if (ret < 0)1895 dev_err(info->dev, "%s: unable to restart LCDC\n", __func__);1896 1897 info->fix.line_length = ch->pitch;1898 1899 if (sh_mobile_format_is_fourcc(&info->var)) {1900 info->fix.type = FB_TYPE_FOURCC;1901 info->fix.visual = FB_VISUAL_FOURCC;1902 } else {1903 info->fix.type = FB_TYPE_PACKED_PIXELS;1904 info->fix.visual = FB_VISUAL_TRUECOLOR;1905 }1906 1907 return ret;1908}1909 1910/*1911 * Screen blanking. Behavior is as follows:1912 * FB_BLANK_UNBLANK: screen unblanked, clocks enabled1913 * FB_BLANK_NORMAL: screen blanked, clocks enabled1914 * FB_BLANK_VSYNC,1915 * FB_BLANK_HSYNC,1916 * FB_BLANK_POWEROFF: screen blanked, clocks disabled1917 */1918static int sh_mobile_lcdc_blank(int blank, struct fb_info *info)1919{1920 struct sh_mobile_lcdc_chan *ch = info->par;1921 struct sh_mobile_lcdc_priv *p = ch->lcdc;1922 1923 /* blank the screen? */1924 if (blank > FB_BLANK_UNBLANK && ch->blank_status == FB_BLANK_UNBLANK) {1925 struct fb_fillrect rect = {1926 .width = ch->xres,1927 .height = ch->yres,1928 };1929 sh_mobile_lcdc_fillrect(info, &rect);1930 }1931 /* turn clocks on? */1932 if (blank <= FB_BLANK_NORMAL && ch->blank_status > FB_BLANK_NORMAL) {1933 sh_mobile_lcdc_clk_on(p);1934 }1935 /* turn clocks off? */1936 if (blank > FB_BLANK_NORMAL && ch->blank_status <= FB_BLANK_NORMAL) {1937 /* make sure the screen is updated with the black fill before1938 * switching the clocks off. one vsync is not enough since1939 * blanking may occur in the middle of a refresh. deferred io1940 * mode will reenable the clocks and update the screen in time,1941 * so it does not need this. */1942 if (!info->fbdefio) {1943 sh_mobile_lcdc_wait_for_vsync(ch);1944 sh_mobile_lcdc_wait_for_vsync(ch);1945 }1946 sh_mobile_lcdc_clk_off(p);1947 }1948 1949 ch->blank_status = blank;1950 return 0;1951}1952 1953static int1954sh_mobile_lcdc_mmap(struct fb_info *info, struct vm_area_struct *vma)1955{1956 struct sh_mobile_lcdc_chan *ch = info->par;1957 1958 if (info->fbdefio)1959 return fb_deferred_io_mmap(info, vma);1960 1961 vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);1962 1963 return dma_mmap_coherent(ch->lcdc->dev, vma, ch->fb_mem,1964 ch->dma_handle, ch->fb_size);1965}1966 1967static const struct fb_ops sh_mobile_lcdc_ops = {1968 .owner = THIS_MODULE,1969 .fb_setcolreg = sh_mobile_lcdc_setcolreg,1970 __FB_DEFAULT_DMAMEM_OPS_RDWR,1971 .fb_fillrect = sh_mobile_lcdc_fillrect,1972 .fb_copyarea = sh_mobile_lcdc_copyarea,1973 .fb_imageblit = sh_mobile_lcdc_imageblit,1974 .fb_blank = sh_mobile_lcdc_blank,1975 .fb_pan_display = sh_mobile_lcdc_pan,1976 .fb_ioctl = sh_mobile_lcdc_ioctl,1977 .fb_open = sh_mobile_lcdc_open,1978 .fb_release = sh_mobile_lcdc_release,1979 .fb_check_var = sh_mobile_lcdc_check_var,1980 .fb_set_par = sh_mobile_lcdc_set_par,1981 .fb_mmap = sh_mobile_lcdc_mmap,1982};1983 1984static void1985sh_mobile_lcdc_channel_fb_unregister(struct sh_mobile_lcdc_chan *ch)1986{1987 if (ch->info && ch->info->dev)1988 unregister_framebuffer(ch->info);1989}1990 1991static int1992sh_mobile_lcdc_channel_fb_register(struct sh_mobile_lcdc_chan *ch)1993{1994 struct fb_info *info = ch->info;1995 int ret;1996 1997 if (info->fbdefio) {1998 ch->sglist = vmalloc(sizeof(struct scatterlist) *1999 ch->fb_size >> PAGE_SHIFT);2000 if (!ch->sglist)2001 return -ENOMEM;2002 }2003 2004 info->bl_dev = ch->bl;2005 2006 ret = register_framebuffer(info);2007 if (ret < 0)2008 return ret;2009 2010 dev_info(ch->lcdc->dev, "registered %s/%s as %dx%d %dbpp.\n",2011 dev_name(ch->lcdc->dev), (ch->cfg->chan == LCDC_CHAN_MAINLCD) ?2012 "mainlcd" : "sublcd", info->var.xres, info->var.yres,2013 info->var.bits_per_pixel);2014 2015 /* deferred io mode: disable clock to save power */2016 if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED)2017 sh_mobile_lcdc_clk_off(ch->lcdc);2018 2019 return ret;2020}2021 2022static void2023sh_mobile_lcdc_channel_fb_cleanup(struct sh_mobile_lcdc_chan *ch)2024{2025 struct fb_info *info = ch->info;2026 2027 if (!info || !info->device)2028 return;2029 2030 vfree(ch->sglist);2031 2032 fb_dealloc_cmap(&info->cmap);2033 framebuffer_release(info);2034}2035 2036static int2037sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch,2038 const struct fb_videomode *modes,2039 unsigned int num_modes)2040{2041 struct sh_mobile_lcdc_priv *priv = ch->lcdc;2042 struct fb_var_screeninfo *var;2043 struct fb_info *info;2044 int ret;2045 2046 /* Allocate and initialize the frame buffer device. Create the modes2047 * list and allocate the color map.2048 */2049 info = framebuffer_alloc(0, priv->dev);2050 if (!info)2051 return -ENOMEM;2052 2053 ch->info = info;2054 2055 info->fbops = &sh_mobile_lcdc_ops;2056 info->device = priv->dev;2057 info->flags |= FBINFO_VIRTFB;2058 info->screen_buffer = ch->fb_mem;2059 info->pseudo_palette = &ch->pseudo_palette;2060 info->par = ch;2061 2062 fb_videomode_to_modelist(modes, num_modes, &info->modelist);2063 2064 ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);2065 if (ret < 0) {2066 dev_err(priv->dev, "unable to allocate cmap\n");2067 return ret;2068 }2069 2070 /* Initialize fixed screen information. Restrict pan to 2 lines steps2071 * for NV12 and NV21.2072 */2073 info->fix = sh_mobile_lcdc_fix;2074 info->fix.smem_start = ch->dma_handle;2075 info->fix.smem_len = ch->fb_size;2076 info->fix.line_length = ch->pitch;2077 2078 if (ch->format->yuv)2079 info->fix.visual = FB_VISUAL_FOURCC;2080 else2081 info->fix.visual = FB_VISUAL_TRUECOLOR;2082 2083 switch (ch->format->fourcc) {2084 case V4L2_PIX_FMT_NV12:2085 case V4L2_PIX_FMT_NV21:2086 info->fix.ypanstep = 2;2087 fallthrough;2088 case V4L2_PIX_FMT_NV16:2089 case V4L2_PIX_FMT_NV61:2090 info->fix.xpanstep = 2;2091 }2092 2093 /* Initialize variable screen information using the first mode as2094 * default.2095 */2096 var = &info->var;2097 fb_videomode_to_var(var, modes);2098 var->width = ch->display.width;2099 var->height = ch->display.height;2100 var->xres_virtual = ch->xres_virtual;2101 var->yres_virtual = ch->yres_virtual;2102 var->activate = FB_ACTIVATE_NOW;2103 2104 /* Use the legacy API by default for RGB formats, and the FOURCC API2105 * for YUV formats.2106 */2107 if (!ch->format->yuv)2108 var->bits_per_pixel = ch->format->bpp;2109 else2110 var->grayscale = ch->format->fourcc;2111 2112 ret = sh_mobile_lcdc_check_var(var, info);2113 if (ret)2114 return ret;2115 2116 return 0;2117}2118 2119/* -----------------------------------------------------------------------------2120 * Backlight2121 */2122 2123static int sh_mobile_lcdc_update_bl(struct backlight_device *bdev)2124{2125 struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev);2126 int brightness = bdev->props.brightness;2127 2128 if (bdev->props.power != FB_BLANK_UNBLANK ||2129 bdev->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))2130 brightness = 0;2131 2132 ch->bl_brightness = brightness;2133 return ch->cfg->bl_info.set_brightness(brightness);2134}2135 2136static int sh_mobile_lcdc_get_brightness(struct backlight_device *bdev)2137{2138 struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev);2139 2140 return ch->bl_brightness;2141}2142 2143static const struct backlight_ops sh_mobile_lcdc_bl_ops = {2144 .options = BL_CORE_SUSPENDRESUME,2145 .update_status = sh_mobile_lcdc_update_bl,2146 .get_brightness = sh_mobile_lcdc_get_brightness,2147};2148 2149static struct backlight_device *sh_mobile_lcdc_bl_probe(struct device *parent,2150 struct sh_mobile_lcdc_chan *ch)2151{2152 struct backlight_device *bl;2153 2154 bl = backlight_device_register(ch->cfg->bl_info.name, parent, ch,2155 &sh_mobile_lcdc_bl_ops, NULL);2156 if (IS_ERR(bl)) {2157 dev_err(parent, "unable to register backlight device: %ld\n",2158 PTR_ERR(bl));2159 return NULL;2160 }2161 2162 bl->props.max_brightness = ch->cfg->bl_info.max_brightness;2163 bl->props.brightness = bl->props.max_brightness;2164 backlight_update_status(bl);2165 2166 return bl;2167}2168 2169static void sh_mobile_lcdc_bl_remove(struct backlight_device *bdev)2170{2171 backlight_device_unregister(bdev);2172}2173 2174/* -----------------------------------------------------------------------------2175 * Power management2176 */2177 2178static int sh_mobile_lcdc_suspend(struct device *dev)2179{2180 struct platform_device *pdev = to_platform_device(dev);2181 2182 sh_mobile_lcdc_stop(platform_get_drvdata(pdev));2183 return 0;2184}2185 2186static int sh_mobile_lcdc_resume(struct device *dev)2187{2188 struct platform_device *pdev = to_platform_device(dev);2189 2190 return sh_mobile_lcdc_start(platform_get_drvdata(pdev));2191}2192 2193static int sh_mobile_lcdc_runtime_suspend(struct device *dev)2194{2195 struct sh_mobile_lcdc_priv *priv = dev_get_drvdata(dev);2196 2197 /* turn off LCDC hardware */2198 lcdc_write(priv, _LDCNT1R, 0);2199 2200 return 0;2201}2202 2203static int sh_mobile_lcdc_runtime_resume(struct device *dev)2204{2205 struct sh_mobile_lcdc_priv *priv = dev_get_drvdata(dev);2206 2207 __sh_mobile_lcdc_start(priv);2208 2209 return 0;2210}2211 2212static const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = {2213 .suspend = sh_mobile_lcdc_suspend,2214 .resume = sh_mobile_lcdc_resume,2215 .runtime_suspend = sh_mobile_lcdc_runtime_suspend,2216 .runtime_resume = sh_mobile_lcdc_runtime_resume,2217};2218 2219/* -----------------------------------------------------------------------------2220 * Framebuffer notifier2221 */2222 2223/* -----------------------------------------------------------------------------2224 * Probe/remove and driver init/exit2225 */2226 2227static const struct fb_videomode default_720p = {2228 .name = "HDMI 720p",2229 .xres = 1280,2230 .yres = 720,2231 2232 .left_margin = 220,2233 .right_margin = 110,2234 .hsync_len = 40,2235 2236 .upper_margin = 20,2237 .lower_margin = 5,2238 .vsync_len = 5,2239 2240 .pixclock = 13468,2241 .refresh = 60,2242 .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,2243};2244 2245static void sh_mobile_lcdc_remove(struct platform_device *pdev)2246{2247 struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);2248 unsigned int i;2249 2250 for (i = 0; i < ARRAY_SIZE(priv->overlays); i++)2251 sh_mobile_lcdc_overlay_fb_unregister(&priv->overlays[i]);2252 for (i = 0; i < ARRAY_SIZE(priv->ch); i++)2253 sh_mobile_lcdc_channel_fb_unregister(&priv->ch[i]);2254 2255 sh_mobile_lcdc_stop(priv);2256 2257 for (i = 0; i < ARRAY_SIZE(priv->overlays); i++) {2258 struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i];2259 2260 sh_mobile_lcdc_overlay_fb_cleanup(ovl);2261 2262 if (ovl->fb_mem)2263 dma_free_coherent(&pdev->dev, ovl->fb_size,2264 ovl->fb_mem, ovl->dma_handle);2265 }2266 2267 for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {2268 struct sh_mobile_lcdc_chan *ch = &priv->ch[i];2269 2270 if (ch->tx_dev) {2271 ch->tx_dev->lcdc = NULL;2272 module_put(ch->cfg->tx_dev->dev.driver->owner);2273 }2274 2275 sh_mobile_lcdc_channel_fb_cleanup(ch);2276 2277 if (ch->fb_mem)2278 dma_free_coherent(&pdev->dev, ch->fb_size,2279 ch->fb_mem, ch->dma_handle);2280 }2281 2282 for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {2283 struct sh_mobile_lcdc_chan *ch = &priv->ch[i];2284 2285 if (ch->bl)2286 sh_mobile_lcdc_bl_remove(ch->bl);2287 mutex_destroy(&ch->open_lock);2288 }2289 2290 if (priv->dot_clk) {2291 pm_runtime_disable(&pdev->dev);2292 clk_put(priv->dot_clk);2293 }2294 2295 if (priv->base)2296 iounmap(priv->base);2297 2298 if (priv->irq)2299 free_irq(priv->irq, priv);2300 kfree(priv);2301}2302 2303static int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)2304{2305 int interface_type = ch->cfg->interface_type;2306 2307 switch (interface_type) {2308 case RGB8:2309 case RGB9:2310 case RGB12A:2311 case RGB12B:2312 case RGB16:2313 case RGB18:2314 case RGB24:2315 case SYS8A:2316 case SYS8B:2317 case SYS8C:2318 case SYS8D:2319 case SYS9:2320 case SYS12:2321 case SYS16A:2322 case SYS16B:2323 case SYS16C:2324 case SYS18:2325 case SYS24:2326 break;2327 default:2328 return -EINVAL;2329 }2330 2331 /* SUBLCD only supports SYS interface */2332 if (lcdc_chan_is_sublcd(ch)) {2333 if (!(interface_type & LDMT1R_IFM))2334 return -EINVAL;2335 2336 interface_type &= ~LDMT1R_IFM;2337 }2338 2339 ch->ldmt1r_value = interface_type;2340 return 0;2341}2342 2343static int2344sh_mobile_lcdc_overlay_init(struct sh_mobile_lcdc_overlay *ovl)2345{2346 const struct sh_mobile_lcdc_format_info *format;2347 struct device *dev = ovl->channel->lcdc->dev;2348 int ret;2349 2350 if (ovl->cfg->fourcc == 0)2351 return 0;2352 2353 /* Validate the format. */2354 format = sh_mobile_format_info(ovl->cfg->fourcc);2355 if (format == NULL) {2356 dev_err(dev, "Invalid FOURCC %08x\n", ovl->cfg->fourcc);2357 return -EINVAL;2358 }2359 2360 ovl->enabled = false;2361 ovl->mode = LCDC_OVERLAY_BLEND;2362 ovl->alpha = 255;2363 ovl->rop3 = 0;2364 ovl->pos_x = 0;2365 ovl->pos_y = 0;2366 2367 /* The default Y virtual resolution is twice the panel size to allow for2368 * double-buffering.2369 */2370 ovl->format = format;2371 ovl->xres = ovl->cfg->max_xres;2372 ovl->xres_virtual = ovl->xres;2373 ovl->yres = ovl->cfg->max_yres;2374 ovl->yres_virtual = ovl->yres * 2;2375 2376 if (!format->yuv)2377 ovl->pitch = ovl->xres_virtual * format->bpp / 8;2378 else2379 ovl->pitch = ovl->xres_virtual;2380 2381 /* Allocate frame buffer memory. */2382 ovl->fb_size = ovl->cfg->max_xres * ovl->cfg->max_yres2383 * format->bpp / 8 * 2;2384 ovl->fb_mem = dma_alloc_coherent(dev, ovl->fb_size, &ovl->dma_handle,2385 GFP_KERNEL);2386 if (!ovl->fb_mem) {2387 dev_err(dev, "unable to allocate buffer\n");2388 return -ENOMEM;2389 }2390 2391 ret = sh_mobile_lcdc_overlay_fb_init(ovl);2392 if (ret < 0)2393 return ret;2394 2395 return 0;2396}2397 2398static int2399sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch)2400{2401 const struct sh_mobile_lcdc_format_info *format;2402 const struct sh_mobile_lcdc_chan_cfg *cfg = ch->cfg;2403 struct device *dev = ch->lcdc->dev;2404 const struct fb_videomode *max_mode;2405 const struct fb_videomode *mode;2406 unsigned int num_modes;2407 unsigned int max_size;2408 unsigned int i;2409 2410 /* Validate the format. */2411 format = sh_mobile_format_info(cfg->fourcc);2412 if (format == NULL) {2413 dev_err(dev, "Invalid FOURCC %08x.\n", cfg->fourcc);2414 return -EINVAL;2415 }2416 2417 /* Iterate through the modes to validate them and find the highest2418 * resolution.2419 */2420 max_mode = NULL;2421 max_size = 0;2422 2423 for (i = 0, mode = cfg->lcd_modes; i < cfg->num_modes; i++, mode++) {2424 unsigned int size = mode->yres * mode->xres;2425 2426 /* NV12/NV21 buffers must have even number of lines */2427 if ((cfg->fourcc == V4L2_PIX_FMT_NV12 ||2428 cfg->fourcc == V4L2_PIX_FMT_NV21) && (mode->yres & 0x1)) {2429 dev_err(dev, "yres must be multiple of 2 for "2430 "YCbCr420 mode.\n");2431 return -EINVAL;2432 }2433 2434 if (size > max_size) {2435 max_mode = mode;2436 max_size = size;2437 }2438 }2439 2440 if (!max_size)2441 max_size = MAX_XRES * MAX_YRES;2442 else2443 dev_dbg(dev, "Found largest videomode %ux%u\n",2444 max_mode->xres, max_mode->yres);2445 2446 if (cfg->lcd_modes == NULL) {2447 mode = &default_720p;2448 num_modes = 1;2449 } else {2450 mode = cfg->lcd_modes;2451 num_modes = cfg->num_modes;2452 }2453 2454 /* Use the first mode as default. The default Y virtual resolution is2455 * twice the panel size to allow for double-buffering.2456 */2457 ch->format = format;2458 ch->xres = mode->xres;2459 ch->xres_virtual = mode->xres;2460 ch->yres = mode->yres;2461 ch->yres_virtual = mode->yres * 2;2462 2463 if (!format->yuv) {2464 ch->colorspace = V4L2_COLORSPACE_SRGB;2465 ch->pitch = ch->xres_virtual * format->bpp / 8;2466 } else {2467 ch->colorspace = V4L2_COLORSPACE_REC709;2468 ch->pitch = ch->xres_virtual;2469 }2470 2471 ch->display.width = cfg->panel_cfg.width;2472 ch->display.height = cfg->panel_cfg.height;2473 ch->display.mode = *mode;2474 2475 /* Allocate frame buffer memory. */2476 ch->fb_size = max_size * format->bpp / 8 * 2;2477 ch->fb_mem = dma_alloc_coherent(dev, ch->fb_size, &ch->dma_handle,2478 GFP_KERNEL);2479 if (ch->fb_mem == NULL) {2480 dev_err(dev, "unable to allocate buffer\n");2481 return -ENOMEM;2482 }2483 2484 /* Initialize the transmitter device if present. */2485 if (cfg->tx_dev) {2486 if (!cfg->tx_dev->dev.driver ||2487 !try_module_get(cfg->tx_dev->dev.driver->owner)) {2488 dev_warn(dev, "unable to get transmitter device\n");2489 return -EINVAL;2490 }2491 ch->tx_dev = platform_get_drvdata(cfg->tx_dev);2492 ch->tx_dev->lcdc = ch;2493 ch->tx_dev->def_mode = *mode;2494 }2495 2496 return sh_mobile_lcdc_channel_fb_init(ch, mode, num_modes);2497}2498 2499static int sh_mobile_lcdc_probe(struct platform_device *pdev)2500{2501 struct sh_mobile_lcdc_info *pdata = pdev->dev.platform_data;2502 struct sh_mobile_lcdc_priv *priv;2503 struct resource *res;2504 int num_channels;2505 int error;2506 int irq, i;2507 2508 if (!pdata) {2509 dev_err(&pdev->dev, "no platform data defined\n");2510 return -EINVAL;2511 }2512 2513 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);2514 irq = platform_get_irq(pdev, 0);2515 if (!res || irq < 0) {2516 dev_err(&pdev->dev, "cannot get platform resources\n");2517 return -ENOENT;2518 }2519 2520 priv = kzalloc(sizeof(*priv), GFP_KERNEL);2521 if (!priv)2522 return -ENOMEM;2523 2524 priv->dev = &pdev->dev;2525 2526 for (i = 0; i < ARRAY_SIZE(priv->ch); i++)2527 mutex_init(&priv->ch[i].open_lock);2528 platform_set_drvdata(pdev, priv);2529 2530 error = request_irq(irq, sh_mobile_lcdc_irq, 0,2531 dev_name(&pdev->dev), priv);2532 if (error) {2533 dev_err(&pdev->dev, "unable to request irq\n");2534 goto err1;2535 }2536 2537 priv->irq = irq;2538 atomic_set(&priv->hw_usecnt, -1);2539 2540 for (i = 0, num_channels = 0; i < ARRAY_SIZE(pdata->ch); i++) {2541 struct sh_mobile_lcdc_chan *ch = priv->ch + num_channels;2542 2543 ch->lcdc = priv;2544 ch->cfg = &pdata->ch[i];2545 2546 error = sh_mobile_lcdc_check_interface(ch);2547 if (error) {2548 dev_err(&pdev->dev, "unsupported interface type\n");2549 goto err1;2550 }2551 init_waitqueue_head(&ch->frame_end_wait);2552 init_completion(&ch->vsync_completion);2553 2554 /* probe the backlight is there is one defined */2555 if (ch->cfg->bl_info.max_brightness)2556 ch->bl = sh_mobile_lcdc_bl_probe(&pdev->dev, ch);2557 2558 switch (pdata->ch[i].chan) {2559 case LCDC_CHAN_MAINLCD:2560 ch->enabled = LDCNT2R_ME;2561 ch->reg_offs = lcdc_offs_mainlcd;2562 num_channels++;2563 break;2564 case LCDC_CHAN_SUBLCD:2565 ch->enabled = LDCNT2R_SE;2566 ch->reg_offs = lcdc_offs_sublcd;2567 num_channels++;2568 break;2569 }2570 }2571 2572 if (!num_channels) {2573 dev_err(&pdev->dev, "no channels defined\n");2574 error = -EINVAL;2575 goto err1;2576 }2577 2578 /* for dual channel LCDC (MAIN + SUB) force shared format setting */2579 if (num_channels == 2)2580 priv->forced_fourcc = pdata->ch[0].fourcc;2581 2582 priv->base = ioremap(res->start, resource_size(res));2583 if (!priv->base) {2584 error = -ENOMEM;2585 goto err1;2586 }2587 2588 error = sh_mobile_lcdc_setup_clocks(priv, pdata->clock_source);2589 if (error) {2590 dev_err(&pdev->dev, "unable to setup clocks\n");2591 goto err1;2592 }2593 2594 /* Enable runtime PM. */2595 pm_runtime_enable(&pdev->dev);2596 2597 for (i = 0; i < num_channels; i++) {2598 struct sh_mobile_lcdc_chan *ch = &priv->ch[i];2599 2600 error = sh_mobile_lcdc_channel_init(ch);2601 if (error)2602 goto err1;2603 }2604 2605 for (i = 0; i < ARRAY_SIZE(pdata->overlays); i++) {2606 struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i];2607 2608 ovl->cfg = &pdata->overlays[i];2609 ovl->channel = &priv->ch[0];2610 2611 error = sh_mobile_lcdc_overlay_init(ovl);2612 if (error)2613 goto err1;2614 }2615 2616 error = sh_mobile_lcdc_start(priv);2617 if (error) {2618 dev_err(&pdev->dev, "unable to start hardware\n");2619 goto err1;2620 }2621 2622 for (i = 0; i < num_channels; i++) {2623 struct sh_mobile_lcdc_chan *ch = priv->ch + i;2624 2625 error = sh_mobile_lcdc_channel_fb_register(ch);2626 if (error)2627 goto err1;2628 }2629 2630 for (i = 0; i < ARRAY_SIZE(pdata->overlays); i++) {2631 struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i];2632 2633 error = sh_mobile_lcdc_overlay_fb_register(ovl);2634 if (error)2635 goto err1;2636 }2637 2638 return 0;2639err1:2640 sh_mobile_lcdc_remove(pdev);2641 2642 return error;2643}2644 2645static struct platform_driver sh_mobile_lcdc_driver = {2646 .driver = {2647 .name = "sh_mobile_lcdc_fb",2648 .pm = &sh_mobile_lcdc_dev_pm_ops,2649 },2650 .probe = sh_mobile_lcdc_probe,2651 .remove = sh_mobile_lcdc_remove,2652};2653 2654module_platform_driver(sh_mobile_lcdc_driver);2655 2656MODULE_DESCRIPTION("SuperH Mobile LCDC Framebuffer driver");2657MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");2658MODULE_LICENSE("GPL v2");2659