0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/atomic.h>
0012 #include <linux/backlight.h>
0013 #include <linux/clk.h>
0014 #include <linux/console.h>
0015 #include <linux/ctype.h>
0016 #include <linux/dma-mapping.h>
0017 #include <linux/delay.h>
0018 #include <linux/fbcon.h>
0019 #include <linux/init.h>
0020 #include <linux/interrupt.h>
0021 #include <linux/ioctl.h>
0022 #include <linux/kernel.h>
0023 #include <linux/mm.h>
0024 #include <linux/module.h>
0025 #include <linux/platform_device.h>
0026 #include <linux/pm_runtime.h>
0027 #include <linux/slab.h>
0028 #include <linux/videodev2.h>
0029 #include <linux/vmalloc.h>
0030
0031 #include <video/sh_mobile_lcdc.h>
0032
0033 #include "sh_mobile_lcdcfb.h"
0034
0035
0036
0037
0038
0039 #define LDBCR 0xb00
0040 #define LDBCR_UPC(n) (1 << ((n) + 16))
0041 #define LDBCR_UPF(n) (1 << ((n) + 8))
0042 #define LDBCR_UPD(n) (1 << ((n) + 0))
0043 #define LDBnBSIFR(n) (0xb20 + (n) * 0x20 + 0x00)
0044 #define LDBBSIFR_EN (1 << 31)
0045 #define LDBBSIFR_VS (1 << 29)
0046 #define LDBBSIFR_BRSEL (1 << 28)
0047 #define LDBBSIFR_MX (1 << 27)
0048 #define LDBBSIFR_MY (1 << 26)
0049 #define LDBBSIFR_CV3 (3 << 24)
0050 #define LDBBSIFR_CV2 (2 << 24)
0051 #define LDBBSIFR_CV1 (1 << 24)
0052 #define LDBBSIFR_CV0 (0 << 24)
0053 #define LDBBSIFR_CV_MASK (3 << 24)
0054 #define LDBBSIFR_LAY_MASK (0xff << 16)
0055 #define LDBBSIFR_LAY_SHIFT 16
0056 #define LDBBSIFR_ROP3_MASK (0xff << 16)
0057 #define LDBBSIFR_ROP3_SHIFT 16
0058 #define LDBBSIFR_AL_PL8 (3 << 14)
0059 #define LDBBSIFR_AL_PL1 (2 << 14)
0060 #define LDBBSIFR_AL_PK (1 << 14)
0061 #define LDBBSIFR_AL_1 (0 << 14)
0062 #define LDBBSIFR_AL_MASK (3 << 14)
0063 #define LDBBSIFR_SWPL (1 << 10)
0064 #define LDBBSIFR_SWPW (1 << 9)
0065 #define LDBBSIFR_SWPB (1 << 8)
0066 #define LDBBSIFR_RY (1 << 7)
0067 #define LDBBSIFR_CHRR_420 (2 << 0)
0068 #define LDBBSIFR_CHRR_422 (1 << 0)
0069 #define LDBBSIFR_CHRR_444 (0 << 0)
0070 #define LDBBSIFR_RPKF_ARGB32 (0x00 << 0)
0071 #define LDBBSIFR_RPKF_RGB16 (0x03 << 0)
0072 #define LDBBSIFR_RPKF_RGB24 (0x0b << 0)
0073 #define LDBBSIFR_RPKF_MASK (0x1f << 0)
0074 #define LDBnBSSZR(n) (0xb20 + (n) * 0x20 + 0x04)
0075 #define LDBBSSZR_BVSS_MASK (0xfff << 16)
0076 #define LDBBSSZR_BVSS_SHIFT 16
0077 #define LDBBSSZR_BHSS_MASK (0xfff << 0)
0078 #define LDBBSSZR_BHSS_SHIFT 0
0079 #define LDBnBLOCR(n) (0xb20 + (n) * 0x20 + 0x08)
0080 #define LDBBLOCR_CVLC_MASK (0xfff << 16)
0081 #define LDBBLOCR_CVLC_SHIFT 16
0082 #define LDBBLOCR_CHLC_MASK (0xfff << 0)
0083 #define LDBBLOCR_CHLC_SHIFT 0
0084 #define LDBnBSMWR(n) (0xb20 + (n) * 0x20 + 0x0c)
0085 #define LDBBSMWR_BSMWA_MASK (0xffff << 16)
0086 #define LDBBSMWR_BSMWA_SHIFT 16
0087 #define LDBBSMWR_BSMW_MASK (0xffff << 0)
0088 #define LDBBSMWR_BSMW_SHIFT 0
0089 #define LDBnBSAYR(n) (0xb20 + (n) * 0x20 + 0x10)
0090 #define LDBBSAYR_FG1A_MASK (0xff << 24)
0091 #define LDBBSAYR_FG1A_SHIFT 24
0092 #define LDBBSAYR_FG1R_MASK (0xff << 16)
0093 #define LDBBSAYR_FG1R_SHIFT 16
0094 #define LDBBSAYR_FG1G_MASK (0xff << 8)
0095 #define LDBBSAYR_FG1G_SHIFT 8
0096 #define LDBBSAYR_FG1B_MASK (0xff << 0)
0097 #define LDBBSAYR_FG1B_SHIFT 0
0098 #define LDBnBSACR(n) (0xb20 + (n) * 0x20 + 0x14)
0099 #define LDBBSACR_FG2A_MASK (0xff << 24)
0100 #define LDBBSACR_FG2A_SHIFT 24
0101 #define LDBBSACR_FG2R_MASK (0xff << 16)
0102 #define LDBBSACR_FG2R_SHIFT 16
0103 #define LDBBSACR_FG2G_MASK (0xff << 8)
0104 #define LDBBSACR_FG2G_SHIFT 8
0105 #define LDBBSACR_FG2B_MASK (0xff << 0)
0106 #define LDBBSACR_FG2B_SHIFT 0
0107 #define LDBnBSAAR(n) (0xb20 + (n) * 0x20 + 0x18)
0108 #define LDBBSAAR_AP_MASK (0xff << 24)
0109 #define LDBBSAAR_AP_SHIFT 24
0110 #define LDBBSAAR_R_MASK (0xff << 16)
0111 #define LDBBSAAR_R_SHIFT 16
0112 #define LDBBSAAR_GY_MASK (0xff << 8)
0113 #define LDBBSAAR_GY_SHIFT 8
0114 #define LDBBSAAR_B_MASK (0xff << 0)
0115 #define LDBBSAAR_B_SHIFT 0
0116 #define LDBnBPPCR(n) (0xb20 + (n) * 0x20 + 0x1c)
0117 #define LDBBPPCR_AP_MASK (0xff << 24)
0118 #define LDBBPPCR_AP_SHIFT 24
0119 #define LDBBPPCR_R_MASK (0xff << 16)
0120 #define LDBBPPCR_R_SHIFT 16
0121 #define LDBBPPCR_GY_MASK (0xff << 8)
0122 #define LDBBPPCR_GY_SHIFT 8
0123 #define LDBBPPCR_B_MASK (0xff << 0)
0124 #define LDBBPPCR_B_SHIFT 0
0125 #define LDBnBBGCL(n) (0xb10 + (n) * 0x04)
0126 #define LDBBBGCL_BGA_MASK (0xff << 24)
0127 #define LDBBBGCL_BGA_SHIFT 24
0128 #define LDBBBGCL_BGR_MASK (0xff << 16)
0129 #define LDBBBGCL_BGR_SHIFT 16
0130 #define LDBBBGCL_BGG_MASK (0xff << 8)
0131 #define LDBBBGCL_BGG_SHIFT 8
0132 #define LDBBBGCL_BGB_MASK (0xff << 0)
0133 #define LDBBBGCL_BGB_SHIFT 0
0134
0135 #define SIDE_B_OFFSET 0x1000
0136 #define MIRROR_OFFSET 0x2000
0137
0138 #define MAX_XRES 1920
0139 #define MAX_YRES 1080
0140
0141 enum sh_mobile_lcdc_overlay_mode {
0142 LCDC_OVERLAY_BLEND,
0143 LCDC_OVERLAY_ROP3,
0144 };
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173 struct sh_mobile_lcdc_overlay {
0174 struct sh_mobile_lcdc_chan *channel;
0175
0176 const struct sh_mobile_lcdc_overlay_cfg *cfg;
0177 struct fb_info *info;
0178
0179 unsigned int index;
0180 unsigned long base;
0181
0182 bool enabled;
0183 enum sh_mobile_lcdc_overlay_mode mode;
0184 unsigned int alpha;
0185 unsigned int rop3;
0186
0187 void *fb_mem;
0188 unsigned long fb_size;
0189
0190 dma_addr_t dma_handle;
0191 unsigned long base_addr_y;
0192 unsigned long base_addr_c;
0193 unsigned long pan_y_offset;
0194
0195 const struct sh_mobile_lcdc_format_info *format;
0196 unsigned int xres;
0197 unsigned int xres_virtual;
0198 unsigned int yres;
0199 unsigned int yres_virtual;
0200 unsigned int pitch;
0201 int pos_x;
0202 int pos_y;
0203 };
0204
0205 struct sh_mobile_lcdc_priv {
0206 void __iomem *base;
0207 int irq;
0208 atomic_t hw_usecnt;
0209 struct device *dev;
0210 struct clk *dot_clk;
0211 unsigned long lddckr;
0212
0213 struct sh_mobile_lcdc_chan ch[2];
0214 struct sh_mobile_lcdc_overlay overlays[4];
0215
0216 int started;
0217 int forced_fourcc;
0218 };
0219
0220
0221
0222
0223
0224 static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = {
0225 [LDDCKPAT1R] = 0x400,
0226 [LDDCKPAT2R] = 0x404,
0227 [LDMT1R] = 0x418,
0228 [LDMT2R] = 0x41c,
0229 [LDMT3R] = 0x420,
0230 [LDDFR] = 0x424,
0231 [LDSM1R] = 0x428,
0232 [LDSM2R] = 0x42c,
0233 [LDSA1R] = 0x430,
0234 [LDSA2R] = 0x434,
0235 [LDMLSR] = 0x438,
0236 [LDHCNR] = 0x448,
0237 [LDHSYNR] = 0x44c,
0238 [LDVLNR] = 0x450,
0239 [LDVSYNR] = 0x454,
0240 [LDPMR] = 0x460,
0241 [LDHAJR] = 0x4a0,
0242 };
0243
0244 static unsigned long lcdc_offs_sublcd[NR_CH_REGS] = {
0245 [LDDCKPAT1R] = 0x408,
0246 [LDDCKPAT2R] = 0x40c,
0247 [LDMT1R] = 0x600,
0248 [LDMT2R] = 0x604,
0249 [LDMT3R] = 0x608,
0250 [LDDFR] = 0x60c,
0251 [LDSM1R] = 0x610,
0252 [LDSM2R] = 0x614,
0253 [LDSA1R] = 0x618,
0254 [LDMLSR] = 0x620,
0255 [LDHCNR] = 0x624,
0256 [LDHSYNR] = 0x628,
0257 [LDVLNR] = 0x62c,
0258 [LDVSYNR] = 0x630,
0259 [LDPMR] = 0x63c,
0260 };
0261
0262 static bool banked(int reg_nr)
0263 {
0264 switch (reg_nr) {
0265 case LDMT1R:
0266 case LDMT2R:
0267 case LDMT3R:
0268 case LDDFR:
0269 case LDSM1R:
0270 case LDSA1R:
0271 case LDSA2R:
0272 case LDMLSR:
0273 case LDHCNR:
0274 case LDHSYNR:
0275 case LDVLNR:
0276 case LDVSYNR:
0277 return true;
0278 }
0279 return false;
0280 }
0281
0282 static int lcdc_chan_is_sublcd(struct sh_mobile_lcdc_chan *chan)
0283 {
0284 return chan->cfg->chan == LCDC_CHAN_SUBLCD;
0285 }
0286
0287 static void lcdc_write_chan(struct sh_mobile_lcdc_chan *chan,
0288 int reg_nr, unsigned long data)
0289 {
0290 iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr]);
0291 if (banked(reg_nr))
0292 iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr] +
0293 SIDE_B_OFFSET);
0294 }
0295
0296 static void lcdc_write_chan_mirror(struct sh_mobile_lcdc_chan *chan,
0297 int reg_nr, unsigned long data)
0298 {
0299 iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr] +
0300 MIRROR_OFFSET);
0301 }
0302
0303 static unsigned long lcdc_read_chan(struct sh_mobile_lcdc_chan *chan,
0304 int reg_nr)
0305 {
0306 return ioread32(chan->lcdc->base + chan->reg_offs[reg_nr]);
0307 }
0308
0309 static void lcdc_write_overlay(struct sh_mobile_lcdc_overlay *ovl,
0310 int reg, unsigned long data)
0311 {
0312 iowrite32(data, ovl->channel->lcdc->base + reg);
0313 iowrite32(data, ovl->channel->lcdc->base + reg + SIDE_B_OFFSET);
0314 }
0315
0316 static void lcdc_write(struct sh_mobile_lcdc_priv *priv,
0317 unsigned long reg_offs, unsigned long data)
0318 {
0319 iowrite32(data, priv->base + reg_offs);
0320 }
0321
0322 static unsigned long lcdc_read(struct sh_mobile_lcdc_priv *priv,
0323 unsigned long reg_offs)
0324 {
0325 return ioread32(priv->base + reg_offs);
0326 }
0327
0328 static void lcdc_wait_bit(struct sh_mobile_lcdc_priv *priv,
0329 unsigned long reg_offs,
0330 unsigned long mask, unsigned long until)
0331 {
0332 while ((lcdc_read(priv, reg_offs) & mask) != until)
0333 cpu_relax();
0334 }
0335
0336
0337
0338
0339
0340 static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv)
0341 {
0342 if (atomic_inc_and_test(&priv->hw_usecnt)) {
0343 clk_prepare_enable(priv->dot_clk);
0344 pm_runtime_get_sync(priv->dev);
0345 }
0346 }
0347
0348 static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv)
0349 {
0350 if (atomic_sub_return(1, &priv->hw_usecnt) == -1) {
0351 pm_runtime_put(priv->dev);
0352 clk_disable_unprepare(priv->dot_clk);
0353 }
0354 }
0355
0356 static int sh_mobile_lcdc_setup_clocks(struct sh_mobile_lcdc_priv *priv,
0357 int clock_source)
0358 {
0359 struct clk *clk;
0360 char *str;
0361
0362 switch (clock_source) {
0363 case LCDC_CLK_BUS:
0364 str = "bus_clk";
0365 priv->lddckr = LDDCKR_ICKSEL_BUS;
0366 break;
0367 case LCDC_CLK_PERIPHERAL:
0368 str = "peripheral_clk";
0369 priv->lddckr = LDDCKR_ICKSEL_MIPI;
0370 break;
0371 case LCDC_CLK_EXTERNAL:
0372 str = NULL;
0373 priv->lddckr = LDDCKR_ICKSEL_HDMI;
0374 break;
0375 default:
0376 return -EINVAL;
0377 }
0378
0379 if (str == NULL)
0380 return 0;
0381
0382 clk = clk_get(priv->dev, str);
0383 if (IS_ERR(clk)) {
0384 dev_err(priv->dev, "cannot get dot clock %s\n", str);
0385 return PTR_ERR(clk);
0386 }
0387
0388 priv->dot_clk = clk;
0389 return 0;
0390 }
0391
0392
0393
0394
0395
0396 static void lcdc_sys_write_index(void *handle, unsigned long data)
0397 {
0398 struct sh_mobile_lcdc_chan *ch = handle;
0399
0400 lcdc_write(ch->lcdc, _LDDWD0R, data | LDDWDxR_WDACT);
0401 lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
0402 lcdc_write(ch->lcdc, _LDDWAR, LDDWAR_WA |
0403 (lcdc_chan_is_sublcd(ch) ? 2 : 0));
0404 lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
0405 }
0406
0407 static void lcdc_sys_write_data(void *handle, unsigned long data)
0408 {
0409 struct sh_mobile_lcdc_chan *ch = handle;
0410
0411 lcdc_write(ch->lcdc, _LDDWD0R, data | LDDWDxR_WDACT | LDDWDxR_RSW);
0412 lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
0413 lcdc_write(ch->lcdc, _LDDWAR, LDDWAR_WA |
0414 (lcdc_chan_is_sublcd(ch) ? 2 : 0));
0415 lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
0416 }
0417
0418 static unsigned long lcdc_sys_read_data(void *handle)
0419 {
0420 struct sh_mobile_lcdc_chan *ch = handle;
0421
0422 lcdc_write(ch->lcdc, _LDDRDR, LDDRDR_RSR);
0423 lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
0424 lcdc_write(ch->lcdc, _LDDRAR, LDDRAR_RA |
0425 (lcdc_chan_is_sublcd(ch) ? 2 : 0));
0426 udelay(1);
0427 lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
0428
0429 return lcdc_read(ch->lcdc, _LDDRDR) & LDDRDR_DRD_MASK;
0430 }
0431
0432 static struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = {
0433 .write_index = lcdc_sys_write_index,
0434 .write_data = lcdc_sys_write_data,
0435 .read_data = lcdc_sys_read_data,
0436 };
0437
0438 static int sh_mobile_lcdc_sginit(struct fb_info *info, struct list_head *pagereflist)
0439 {
0440 struct sh_mobile_lcdc_chan *ch = info->par;
0441 unsigned int nr_pages_max = ch->fb_size >> PAGE_SHIFT;
0442 struct fb_deferred_io_pageref *pageref;
0443 int nr_pages = 0;
0444
0445 sg_init_table(ch->sglist, nr_pages_max);
0446
0447 list_for_each_entry(pageref, pagereflist, list) {
0448 sg_set_page(&ch->sglist[nr_pages++], pageref->page, PAGE_SIZE, 0);
0449 }
0450
0451 return nr_pages;
0452 }
0453
0454 static void sh_mobile_lcdc_deferred_io(struct fb_info *info, struct list_head *pagereflist)
0455 {
0456 struct sh_mobile_lcdc_chan *ch = info->par;
0457 const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg;
0458
0459
0460 sh_mobile_lcdc_clk_on(ch->lcdc);
0461
0462
0463
0464
0465
0466
0467
0468
0469
0470
0471
0472
0473
0474
0475
0476
0477 if (!list_empty(pagereflist)) {
0478 unsigned int nr_pages = sh_mobile_lcdc_sginit(info, pagereflist);
0479
0480
0481 dma_map_sg(ch->lcdc->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
0482 if (panel->start_transfer)
0483 panel->start_transfer(ch, &sh_mobile_lcdc_sys_bus_ops);
0484 lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG);
0485 dma_unmap_sg(ch->lcdc->dev, ch->sglist, nr_pages,
0486 DMA_TO_DEVICE);
0487 } else {
0488 if (panel->start_transfer)
0489 panel->start_transfer(ch, &sh_mobile_lcdc_sys_bus_ops);
0490 lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG);
0491 }
0492 }
0493
0494 static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info)
0495 {
0496 struct fb_deferred_io *fbdefio = info->fbdefio;
0497
0498 if (fbdefio)
0499 schedule_delayed_work(&info->deferred_work, fbdefio->delay);
0500 }
0501
0502 static void sh_mobile_lcdc_display_on(struct sh_mobile_lcdc_chan *ch)
0503 {
0504 const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg;
0505
0506 if (ch->tx_dev) {
0507 int ret;
0508
0509 ret = ch->tx_dev->ops->display_on(ch->tx_dev);
0510 if (ret < 0)
0511 return;
0512
0513 if (ret == SH_MOBILE_LCDC_DISPLAY_DISCONNECTED)
0514 ch->info->state = FBINFO_STATE_SUSPENDED;
0515 }
0516
0517
0518 if (panel->display_on)
0519 panel->display_on();
0520 }
0521
0522 static void sh_mobile_lcdc_display_off(struct sh_mobile_lcdc_chan *ch)
0523 {
0524 const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg;
0525
0526 if (panel->display_off)
0527 panel->display_off();
0528
0529 if (ch->tx_dev)
0530 ch->tx_dev->ops->display_off(ch->tx_dev);
0531 }
0532
0533
0534
0535
0536
0537 struct sh_mobile_lcdc_format_info {
0538 u32 fourcc;
0539 unsigned int bpp;
0540 bool yuv;
0541 u32 lddfr;
0542 };
0543
0544 static const struct sh_mobile_lcdc_format_info sh_mobile_format_infos[] = {
0545 {
0546 .fourcc = V4L2_PIX_FMT_RGB565,
0547 .bpp = 16,
0548 .yuv = false,
0549 .lddfr = LDDFR_PKF_RGB16,
0550 }, {
0551 .fourcc = V4L2_PIX_FMT_BGR24,
0552 .bpp = 24,
0553 .yuv = false,
0554 .lddfr = LDDFR_PKF_RGB24,
0555 }, {
0556 .fourcc = V4L2_PIX_FMT_BGR32,
0557 .bpp = 32,
0558 .yuv = false,
0559 .lddfr = LDDFR_PKF_ARGB32,
0560 }, {
0561 .fourcc = V4L2_PIX_FMT_NV12,
0562 .bpp = 12,
0563 .yuv = true,
0564 .lddfr = LDDFR_CC | LDDFR_YF_420,
0565 }, {
0566 .fourcc = V4L2_PIX_FMT_NV21,
0567 .bpp = 12,
0568 .yuv = true,
0569 .lddfr = LDDFR_CC | LDDFR_YF_420,
0570 }, {
0571 .fourcc = V4L2_PIX_FMT_NV16,
0572 .bpp = 16,
0573 .yuv = true,
0574 .lddfr = LDDFR_CC | LDDFR_YF_422,
0575 }, {
0576 .fourcc = V4L2_PIX_FMT_NV61,
0577 .bpp = 16,
0578 .yuv = true,
0579 .lddfr = LDDFR_CC | LDDFR_YF_422,
0580 }, {
0581 .fourcc = V4L2_PIX_FMT_NV24,
0582 .bpp = 24,
0583 .yuv = true,
0584 .lddfr = LDDFR_CC | LDDFR_YF_444,
0585 }, {
0586 .fourcc = V4L2_PIX_FMT_NV42,
0587 .bpp = 24,
0588 .yuv = true,
0589 .lddfr = LDDFR_CC | LDDFR_YF_444,
0590 },
0591 };
0592
0593 static const struct sh_mobile_lcdc_format_info *
0594 sh_mobile_format_info(u32 fourcc)
0595 {
0596 unsigned int i;
0597
0598 for (i = 0; i < ARRAY_SIZE(sh_mobile_format_infos); ++i) {
0599 if (sh_mobile_format_infos[i].fourcc == fourcc)
0600 return &sh_mobile_format_infos[i];
0601 }
0602
0603 return NULL;
0604 }
0605
0606 static int sh_mobile_format_fourcc(const struct fb_var_screeninfo *var)
0607 {
0608 if (var->grayscale > 1)
0609 return var->grayscale;
0610
0611 switch (var->bits_per_pixel) {
0612 case 16:
0613 return V4L2_PIX_FMT_RGB565;
0614 case 24:
0615 return V4L2_PIX_FMT_BGR24;
0616 case 32:
0617 return V4L2_PIX_FMT_BGR32;
0618 default:
0619 return 0;
0620 }
0621 }
0622
0623 static int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var)
0624 {
0625 return var->grayscale > 1;
0626 }
0627
0628
0629
0630
0631
0632 static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
0633 {
0634 struct sh_mobile_lcdc_priv *priv = data;
0635 struct sh_mobile_lcdc_chan *ch;
0636 unsigned long ldintr;
0637 int is_sub;
0638 int k;
0639
0640
0641 ldintr = lcdc_read(priv, _LDINTR);
0642 lcdc_write(priv, _LDINTR, (ldintr ^ LDINTR_STATUS_MASK) & ~LDINTR_VEE);
0643
0644
0645 is_sub = (lcdc_read(priv, _LDSR) & LDSR_MSS) ? 1 : 0;
0646
0647
0648 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
0649 ch = &priv->ch[k];
0650
0651 if (!ch->enabled)
0652 continue;
0653
0654
0655 if (ldintr & LDINTR_FS) {
0656 if (is_sub == lcdc_chan_is_sublcd(ch)) {
0657 ch->frame_end = 1;
0658 wake_up(&ch->frame_end_wait);
0659
0660 sh_mobile_lcdc_clk_off(priv);
0661 }
0662 }
0663
0664
0665 if (ldintr & LDINTR_VES)
0666 complete(&ch->vsync_completion);
0667 }
0668
0669 return IRQ_HANDLED;
0670 }
0671
0672 static int sh_mobile_lcdc_wait_for_vsync(struct sh_mobile_lcdc_chan *ch)
0673 {
0674 unsigned long ldintr;
0675 int ret;
0676
0677
0678
0679
0680 ldintr = lcdc_read(ch->lcdc, _LDINTR);
0681 ldintr |= LDINTR_VEE | LDINTR_STATUS_MASK;
0682 lcdc_write(ch->lcdc, _LDINTR, ldintr);
0683
0684 ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion,
0685 msecs_to_jiffies(100));
0686 if (!ret)
0687 return -ETIMEDOUT;
0688
0689 return 0;
0690 }
0691
0692 static void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv,
0693 int start)
0694 {
0695 unsigned long tmp = lcdc_read(priv, _LDCNT2R);
0696 int k;
0697
0698
0699 if (start)
0700 lcdc_write(priv, _LDCNT2R, tmp | LDCNT2R_DO);
0701 else
0702 lcdc_write(priv, _LDCNT2R, tmp & ~LDCNT2R_DO);
0703
0704
0705 for (k = 0; k < ARRAY_SIZE(priv->ch); k++)
0706 if (lcdc_read(priv, _LDCNT2R) & priv->ch[k].enabled)
0707 while (1) {
0708 tmp = lcdc_read_chan(&priv->ch[k], LDPMR)
0709 & LDPMR_LPS;
0710 if (start && tmp == LDPMR_LPS)
0711 break;
0712 if (!start && tmp == 0)
0713 break;
0714 cpu_relax();
0715 }
0716
0717 if (!start)
0718 lcdc_write(priv, _LDDCKSTPR, 1);
0719 }
0720
0721 static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
0722 {
0723 const struct fb_var_screeninfo *var = &ch->info->var;
0724 const struct fb_videomode *mode = &ch->display.mode;
0725 unsigned long h_total, hsync_pos, display_h_total;
0726 u32 tmp;
0727
0728 tmp = ch->ldmt1r_value;
0729 tmp |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : LDMT1R_VPOL;
0730 tmp |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : LDMT1R_HPOL;
0731 tmp |= (ch->cfg->flags & LCDC_FLAGS_DWPOL) ? LDMT1R_DWPOL : 0;
0732 tmp |= (ch->cfg->flags & LCDC_FLAGS_DIPOL) ? LDMT1R_DIPOL : 0;
0733 tmp |= (ch->cfg->flags & LCDC_FLAGS_DAPOL) ? LDMT1R_DAPOL : 0;
0734 tmp |= (ch->cfg->flags & LCDC_FLAGS_HSCNT) ? LDMT1R_HSCNT : 0;
0735 tmp |= (ch->cfg->flags & LCDC_FLAGS_DWCNT) ? LDMT1R_DWCNT : 0;
0736 lcdc_write_chan(ch, LDMT1R, tmp);
0737
0738
0739 lcdc_write_chan(ch, LDMT2R, ch->cfg->sys_bus_cfg.ldmt2r);
0740 lcdc_write_chan(ch, LDMT3R, ch->cfg->sys_bus_cfg.ldmt3r);
0741
0742
0743 h_total = mode->xres + mode->hsync_len + mode->left_margin
0744 + mode->right_margin;
0745 tmp = h_total / 8;
0746 tmp |= (min(mode->xres, ch->xres) / 8) << 16;
0747 lcdc_write_chan(ch, LDHCNR, tmp);
0748
0749 hsync_pos = mode->xres + mode->right_margin;
0750 tmp = hsync_pos / 8;
0751 tmp |= (mode->hsync_len / 8) << 16;
0752 lcdc_write_chan(ch, LDHSYNR, tmp);
0753
0754
0755 tmp = mode->yres + mode->vsync_len + mode->upper_margin
0756 + mode->lower_margin;
0757 tmp |= min(mode->yres, ch->yres) << 16;
0758 lcdc_write_chan(ch, LDVLNR, tmp);
0759
0760 tmp = mode->yres + mode->lower_margin;
0761 tmp |= mode->vsync_len << 16;
0762 lcdc_write_chan(ch, LDVSYNR, tmp);
0763
0764
0765 display_h_total = mode->xres + mode->hsync_len + mode->left_margin
0766 + mode->right_margin;
0767 tmp = ((mode->xres & 7) << 24) | ((display_h_total & 7) << 16)
0768 | ((mode->hsync_len & 7) << 8) | (hsync_pos & 7);
0769 lcdc_write_chan(ch, LDHAJR, tmp);
0770 lcdc_write_chan_mirror(ch, LDHAJR, tmp);
0771 }
0772
0773 static void sh_mobile_lcdc_overlay_setup(struct sh_mobile_lcdc_overlay *ovl)
0774 {
0775 u32 format = 0;
0776
0777 if (!ovl->enabled) {
0778 lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index));
0779 lcdc_write_overlay(ovl, LDBnBSIFR(ovl->index), 0);
0780 lcdc_write(ovl->channel->lcdc, LDBCR,
0781 LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index));
0782 return;
0783 }
0784
0785 ovl->base_addr_y = ovl->dma_handle;
0786 ovl->base_addr_c = ovl->dma_handle
0787 + ovl->xres_virtual * ovl->yres_virtual;
0788
0789 switch (ovl->mode) {
0790 case LCDC_OVERLAY_BLEND:
0791 format = LDBBSIFR_EN | (ovl->alpha << LDBBSIFR_LAY_SHIFT);
0792 break;
0793
0794 case LCDC_OVERLAY_ROP3:
0795 format = LDBBSIFR_EN | LDBBSIFR_BRSEL
0796 | (ovl->rop3 << LDBBSIFR_ROP3_SHIFT);
0797 break;
0798 }
0799
0800 switch (ovl->format->fourcc) {
0801 case V4L2_PIX_FMT_RGB565:
0802 case V4L2_PIX_FMT_NV21:
0803 case V4L2_PIX_FMT_NV61:
0804 case V4L2_PIX_FMT_NV42:
0805 format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW;
0806 break;
0807 case V4L2_PIX_FMT_BGR24:
0808 case V4L2_PIX_FMT_NV12:
0809 case V4L2_PIX_FMT_NV16:
0810 case V4L2_PIX_FMT_NV24:
0811 format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW | LDBBSIFR_SWPB;
0812 break;
0813 case V4L2_PIX_FMT_BGR32:
0814 default:
0815 format |= LDBBSIFR_SWPL;
0816 break;
0817 }
0818
0819 switch (ovl->format->fourcc) {
0820 case V4L2_PIX_FMT_RGB565:
0821 format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB16;
0822 break;
0823 case V4L2_PIX_FMT_BGR24:
0824 format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB24;
0825 break;
0826 case V4L2_PIX_FMT_BGR32:
0827 format |= LDBBSIFR_AL_PK | LDBBSIFR_RY | LDDFR_PKF_ARGB32;
0828 break;
0829 case V4L2_PIX_FMT_NV12:
0830 case V4L2_PIX_FMT_NV21:
0831 format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_420;
0832 break;
0833 case V4L2_PIX_FMT_NV16:
0834 case V4L2_PIX_FMT_NV61:
0835 format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_422;
0836 break;
0837 case V4L2_PIX_FMT_NV24:
0838 case V4L2_PIX_FMT_NV42:
0839 format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_444;
0840 break;
0841 }
0842
0843 lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index));
0844
0845 lcdc_write_overlay(ovl, LDBnBSIFR(ovl->index), format);
0846
0847 lcdc_write_overlay(ovl, LDBnBSSZR(ovl->index),
0848 (ovl->yres << LDBBSSZR_BVSS_SHIFT) |
0849 (ovl->xres << LDBBSSZR_BHSS_SHIFT));
0850 lcdc_write_overlay(ovl, LDBnBLOCR(ovl->index),
0851 (ovl->pos_y << LDBBLOCR_CVLC_SHIFT) |
0852 (ovl->pos_x << LDBBLOCR_CHLC_SHIFT));
0853 lcdc_write_overlay(ovl, LDBnBSMWR(ovl->index),
0854 ovl->pitch << LDBBSMWR_BSMW_SHIFT);
0855
0856 lcdc_write_overlay(ovl, LDBnBSAYR(ovl->index), ovl->base_addr_y);
0857 lcdc_write_overlay(ovl, LDBnBSACR(ovl->index), ovl->base_addr_c);
0858
0859 lcdc_write(ovl->channel->lcdc, LDBCR,
0860 LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index));
0861 }
0862
0863
0864
0865
0866
0867
0868
0869
0870 static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
0871 {
0872 struct sh_mobile_lcdc_chan *ch;
0873 unsigned long tmp;
0874 int k, m;
0875
0876
0877
0878
0879 lcdc_write(priv, _LDCNT2R, priv->ch[0].enabled | priv->ch[1].enabled);
0880
0881
0882 sh_mobile_lcdc_start_stop(priv, 0);
0883 lcdc_write(priv, _LDINTR, 0);
0884
0885
0886 tmp = priv->lddckr;
0887 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
0888 ch = &priv->ch[k];
0889 if (!ch->enabled)
0890 continue;
0891
0892
0893 lcdc_write_chan(ch, LDPMR, 0);
0894
0895 m = ch->cfg->clock_divider;
0896 if (!m)
0897 continue;
0898
0899
0900
0901
0902 lcdc_write_chan(ch, LDDCKPAT1R, 0);
0903 lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1);
0904
0905 if (m == 1)
0906 m = LDDCKR_MOSEL;
0907 tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0);
0908 }
0909
0910 lcdc_write(priv, _LDDCKR, tmp);
0911 lcdc_write(priv, _LDDCKSTPR, 0);
0912 lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0);
0913
0914
0915 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
0916 ch = &priv->ch[k];
0917 if (!ch->enabled)
0918 continue;
0919
0920 sh_mobile_lcdc_geometry(ch);
0921
0922 tmp = ch->format->lddfr;
0923
0924 if (ch->format->yuv) {
0925 switch (ch->colorspace) {
0926 case V4L2_COLORSPACE_REC709:
0927 tmp |= LDDFR_CF1;
0928 break;
0929 case V4L2_COLORSPACE_JPEG:
0930 tmp |= LDDFR_CF0;
0931 break;
0932 }
0933 }
0934
0935 lcdc_write_chan(ch, LDDFR, tmp);
0936 lcdc_write_chan(ch, LDMLSR, ch->line_size);
0937 lcdc_write_chan(ch, LDSA1R, ch->base_addr_y);
0938 if (ch->format->yuv)
0939 lcdc_write_chan(ch, LDSA2R, ch->base_addr_c);
0940
0941
0942
0943
0944
0945 if (ch->ldmt1r_value & LDMT1R_IFM &&
0946 ch->cfg->sys_bus_cfg.deferred_io_msec) {
0947 lcdc_write_chan(ch, LDSM1R, LDSM1R_OS);
0948 lcdc_write(priv, _LDINTR, LDINTR_FE);
0949 } else {
0950 lcdc_write_chan(ch, LDSM1R, 0);
0951 }
0952 }
0953
0954
0955 switch (priv->ch[0].format->fourcc) {
0956 case V4L2_PIX_FMT_RGB565:
0957 case V4L2_PIX_FMT_NV21:
0958 case V4L2_PIX_FMT_NV61:
0959 case V4L2_PIX_FMT_NV42:
0960 tmp = LDDDSR_LS | LDDDSR_WS;
0961 break;
0962 case V4L2_PIX_FMT_BGR24:
0963 case V4L2_PIX_FMT_NV12:
0964 case V4L2_PIX_FMT_NV16:
0965 case V4L2_PIX_FMT_NV24:
0966 tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;
0967 break;
0968 case V4L2_PIX_FMT_BGR32:
0969 default:
0970 tmp = LDDDSR_LS;
0971 break;
0972 }
0973 lcdc_write(priv, _LDDDSR, tmp);
0974
0975
0976 lcdc_write(priv, _LDCNT1R, LDCNT1R_DE);
0977 sh_mobile_lcdc_start_stop(priv, 1);
0978 priv->started = 1;
0979 }
0980
0981 static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
0982 {
0983 struct sh_mobile_lcdc_chan *ch;
0984 unsigned long tmp;
0985 int ret;
0986 int k;
0987
0988
0989 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
0990 if (priv->ch[k].enabled)
0991 sh_mobile_lcdc_clk_on(priv);
0992 }
0993
0994
0995 lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LDCNT2R_BR);
0996 lcdc_wait_bit(priv, _LDCNT2R, LDCNT2R_BR, 0);
0997
0998 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
0999 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
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_handle
1021 + 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
1031 __sh_mobile_lcdc_start(priv);
1032
1033
1034
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
1060 static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
1061 {
1062 struct sh_mobile_lcdc_chan *ch;
1063 int k;
1064
1065
1066 for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
1067 ch = &priv->ch[k];
1068 if (!ch->enabled)
1069 continue;
1070
1071
1072
1073
1074
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
1093 if (priv->started) {
1094 sh_mobile_lcdc_start_stop(priv, 0);
1095 priv->started = 0;
1096 }
1097
1098
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
1104 static 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
1111
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
1127
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) {
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) {
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) {
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 } else
1165 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
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
1183
1184
1185 static ssize_t
1186 overlay_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 scnprintf(buf, PAGE_SIZE, "%u\n", ovl->alpha);
1192 }
1193
1194 static ssize_t
1195 overlay_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
1223 static ssize_t
1224 overlay_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 scnprintf(buf, PAGE_SIZE, "%u\n", ovl->mode);
1230 }
1231
1232 static ssize_t
1233 overlay_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
1261 static ssize_t
1262 overlay_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 scnprintf(buf, PAGE_SIZE, "%d,%d\n", ovl->pos_x, ovl->pos_y);
1269 }
1270
1271 static ssize_t
1272 overlay_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
1303 static ssize_t
1304 overlay_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 scnprintf(buf, PAGE_SIZE, "%u\n", ovl->rop3);
1310 }
1311
1312 static ssize_t
1313 overlay_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
1341 static 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
1352 static 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
1363 static 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 / xsub
1382 + var->xoffset * 2 / xsub;
1383 }
1384
1385
1386
1387
1388 if (y_offset == ovl->pan_y_offset)
1389 return 0;
1390
1391
1392 base_addr_y = ovl->dma_handle + y_offset;
1393 base_addr_c = ovl->dma_handle + ovl->xres_virtual * ovl->yres_virtual
1394 + 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
1411 static 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
1425 static 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
1431 static 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 else
1446 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
1464 static 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
1472
1473
1474 return 1;
1475 }
1476
1477 static int
1478 sh_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 return dma_mmap_coherent(ovl->channel->lcdc->dev, vma, ovl->fb_mem,
1486 ovl->dma_handle, ovl->fb_size);
1487 }
1488
1489 static const struct fb_ops sh_mobile_lcdc_overlay_ops = {
1490 .owner = THIS_MODULE,
1491 .fb_read = fb_sys_read,
1492 .fb_write = fb_sys_write,
1493 .fb_fillrect = sys_fillrect,
1494 .fb_copyarea = sys_copyarea,
1495 .fb_imageblit = sys_imageblit,
1496 .fb_blank = sh_mobile_lcdc_overlay_blank,
1497 .fb_pan_display = sh_mobile_lcdc_overlay_pan,
1498 .fb_ioctl = sh_mobile_lcdc_overlay_ioctl,
1499 .fb_check_var = sh_mobile_lcdc_overlay_check_var,
1500 .fb_set_par = sh_mobile_lcdc_overlay_set_par,
1501 .fb_mmap = sh_mobile_lcdc_overlay_mmap,
1502 };
1503
1504 static void
1505 sh_mobile_lcdc_overlay_fb_unregister(struct sh_mobile_lcdc_overlay *ovl)
1506 {
1507 struct fb_info *info = ovl->info;
1508
1509 if (info == NULL || info->dev == NULL)
1510 return;
1511
1512 unregister_framebuffer(ovl->info);
1513 }
1514
1515 static int
1516 sh_mobile_lcdc_overlay_fb_register(struct sh_mobile_lcdc_overlay *ovl)
1517 {
1518 struct sh_mobile_lcdc_priv *lcdc = ovl->channel->lcdc;
1519 struct fb_info *info = ovl->info;
1520 unsigned int i;
1521 int ret;
1522
1523 if (info == NULL)
1524 return 0;
1525
1526 ret = register_framebuffer(info);
1527 if (ret < 0)
1528 return ret;
1529
1530 dev_info(lcdc->dev, "registered %s/overlay %u as %dx%d %dbpp.\n",
1531 dev_name(lcdc->dev), ovl->index, info->var.xres,
1532 info->var.yres, info->var.bits_per_pixel);
1533
1534 for (i = 0; i < ARRAY_SIZE(overlay_sysfs_attrs); ++i) {
1535 ret = device_create_file(info->dev, &overlay_sysfs_attrs[i]);
1536 if (ret < 0)
1537 return ret;
1538 }
1539
1540 return 0;
1541 }
1542
1543 static void
1544 sh_mobile_lcdc_overlay_fb_cleanup(struct sh_mobile_lcdc_overlay *ovl)
1545 {
1546 struct fb_info *info = ovl->info;
1547
1548 if (info == NULL || info->device == NULL)
1549 return;
1550
1551 framebuffer_release(info);
1552 }
1553
1554 static int
1555 sh_mobile_lcdc_overlay_fb_init(struct sh_mobile_lcdc_overlay *ovl)
1556 {
1557 struct sh_mobile_lcdc_priv *priv = ovl->channel->lcdc;
1558 struct fb_var_screeninfo *var;
1559 struct fb_info *info;
1560
1561
1562 info = framebuffer_alloc(0, priv->dev);
1563 if (!info)
1564 return -ENOMEM;
1565
1566 ovl->info = info;
1567
1568 info->flags = FBINFO_FLAG_DEFAULT;
1569 info->fbops = &sh_mobile_lcdc_overlay_ops;
1570 info->device = priv->dev;
1571 info->screen_buffer = ovl->fb_mem;
1572 info->par = ovl;
1573
1574
1575
1576
1577 info->fix = sh_mobile_lcdc_overlay_fix;
1578 snprintf(info->fix.id, sizeof(info->fix.id),
1579 "SH Mobile LCDC Overlay %u", ovl->index);
1580 info->fix.smem_start = ovl->dma_handle;
1581 info->fix.smem_len = ovl->fb_size;
1582 info->fix.line_length = ovl->pitch;
1583
1584 if (ovl->format->yuv)
1585 info->fix.visual = FB_VISUAL_FOURCC;
1586 else
1587 info->fix.visual = FB_VISUAL_TRUECOLOR;
1588
1589 switch (ovl->format->fourcc) {
1590 case V4L2_PIX_FMT_NV12:
1591 case V4L2_PIX_FMT_NV21:
1592 info->fix.ypanstep = 2;
1593 fallthrough;
1594 case V4L2_PIX_FMT_NV16:
1595 case V4L2_PIX_FMT_NV61:
1596 info->fix.xpanstep = 2;
1597 }
1598
1599
1600 var = &info->var;
1601 memset(var, 0, sizeof(*var));
1602 var->xres = ovl->xres;
1603 var->yres = ovl->yres;
1604 var->xres_virtual = ovl->xres_virtual;
1605 var->yres_virtual = ovl->yres_virtual;
1606 var->activate = FB_ACTIVATE_NOW;
1607
1608
1609
1610
1611 if (!ovl->format->yuv)
1612 var->bits_per_pixel = ovl->format->bpp;
1613 else
1614 var->grayscale = ovl->format->fourcc;
1615
1616 return sh_mobile_lcdc_overlay_check_var(var, info);
1617 }
1618
1619
1620
1621
1622
1623 static int sh_mobile_lcdc_setcolreg(u_int regno,
1624 u_int red, u_int green, u_int blue,
1625 u_int transp, struct fb_info *info)
1626 {
1627 u32 *palette = info->pseudo_palette;
1628
1629 if (regno >= PALETTE_NR)
1630 return -EINVAL;
1631
1632
1633
1634 red >>= 16 - info->var.red.length;
1635 green >>= 16 - info->var.green.length;
1636 blue >>= 16 - info->var.blue.length;
1637 transp >>= 16 - info->var.transp.length;
1638
1639 palette[regno] = (red << info->var.red.offset) |
1640 (green << info->var.green.offset) |
1641 (blue << info->var.blue.offset) |
1642 (transp << info->var.transp.offset);
1643
1644 return 0;
1645 }
1646
1647 static const struct fb_fix_screeninfo sh_mobile_lcdc_fix = {
1648 .id = "SH Mobile LCDC",
1649 .type = FB_TYPE_PACKED_PIXELS,
1650 .visual = FB_VISUAL_TRUECOLOR,
1651 .accel = FB_ACCEL_NONE,
1652 .xpanstep = 1,
1653 .ypanstep = 1,
1654 .ywrapstep = 0,
1655 .capabilities = FB_CAP_FOURCC,
1656 };
1657
1658 static void sh_mobile_lcdc_fillrect(struct fb_info *info,
1659 const struct fb_fillrect *rect)
1660 {
1661 sys_fillrect(info, rect);
1662 sh_mobile_lcdc_deferred_io_touch(info);
1663 }
1664
1665 static void sh_mobile_lcdc_copyarea(struct fb_info *info,
1666 const struct fb_copyarea *area)
1667 {
1668 sys_copyarea(info, area);
1669 sh_mobile_lcdc_deferred_io_touch(info);
1670 }
1671
1672 static void sh_mobile_lcdc_imageblit(struct fb_info *info,
1673 const struct fb_image *image)
1674 {
1675 sys_imageblit(info, image);
1676 sh_mobile_lcdc_deferred_io_touch(info);
1677 }
1678
1679 static int sh_mobile_lcdc_pan(struct fb_var_screeninfo *var,
1680 struct fb_info *info)
1681 {
1682 struct sh_mobile_lcdc_chan *ch = info->par;
1683 struct sh_mobile_lcdc_priv *priv = ch->lcdc;
1684 unsigned long ldrcntr;
1685 unsigned long base_addr_y, base_addr_c;
1686 unsigned long y_offset;
1687 unsigned long c_offset;
1688
1689 if (!ch->format->yuv) {
1690 y_offset = (var->yoffset * ch->xres_virtual + var->xoffset)
1691 * ch->format->bpp / 8;
1692 c_offset = 0;
1693 } else {
1694 unsigned int xsub = ch->format->bpp < 24 ? 2 : 1;
1695 unsigned int ysub = ch->format->bpp < 16 ? 2 : 1;
1696
1697 y_offset = var->yoffset * ch->xres_virtual + var->xoffset;
1698 c_offset = var->yoffset / ysub * ch->xres_virtual * 2 / xsub
1699 + var->xoffset * 2 / xsub;
1700 }
1701
1702
1703
1704
1705 if (y_offset == ch->pan_y_offset)
1706 return 0;
1707
1708
1709 base_addr_y = ch->dma_handle + y_offset;
1710 base_addr_c = ch->dma_handle + ch->xres_virtual * ch->yres_virtual
1711 + c_offset;
1712
1713 ch->base_addr_y = base_addr_y;
1714 ch->base_addr_c = base_addr_c;
1715 ch->pan_y_offset = y_offset;
1716
1717 lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);
1718 if (ch->format->yuv)
1719 lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c);
1720
1721 ldrcntr = lcdc_read(priv, _LDRCNTR);
1722 if (lcdc_chan_is_sublcd(ch))
1723 lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS);
1724 else
1725 lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_MRS);
1726
1727
1728 sh_mobile_lcdc_deferred_io_touch(info);
1729
1730 return 0;
1731 }
1732
1733 static int sh_mobile_lcdc_ioctl(struct fb_info *info, unsigned int cmd,
1734 unsigned long arg)
1735 {
1736 struct sh_mobile_lcdc_chan *ch = info->par;
1737 int retval;
1738
1739 switch (cmd) {
1740 case FBIO_WAITFORVSYNC:
1741 retval = sh_mobile_lcdc_wait_for_vsync(ch);
1742 break;
1743
1744 default:
1745 retval = -ENOIOCTLCMD;
1746 break;
1747 }
1748 return retval;
1749 }
1750
1751 static void sh_mobile_fb_reconfig(struct fb_info *info)
1752 {
1753 struct sh_mobile_lcdc_chan *ch = info->par;
1754 struct fb_var_screeninfo var;
1755 struct fb_videomode mode;
1756
1757 if (ch->use_count > 1 || (ch->use_count == 1 && !info->fbcon_par))
1758
1759 return;
1760
1761 fb_var_to_videomode(&mode, &info->var);
1762
1763 if (fb_mode_is_equal(&ch->display.mode, &mode))
1764 return;
1765
1766
1767 var = info->var;
1768 fb_videomode_to_var(&var, &ch->display.mode);
1769 var.width = ch->display.width;
1770 var.height = ch->display.height;
1771 var.activate = FB_ACTIVATE_NOW;
1772
1773 if (fb_set_var(info, &var) < 0)
1774
1775 return;
1776
1777 fbcon_update_vcs(info, true);
1778 }
1779
1780
1781
1782
1783
1784 static int sh_mobile_lcdc_release(struct fb_info *info, int user)
1785 {
1786 struct sh_mobile_lcdc_chan *ch = info->par;
1787
1788 mutex_lock(&ch->open_lock);
1789 dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count);
1790
1791 ch->use_count--;
1792
1793
1794 if (user) {
1795 console_lock();
1796 sh_mobile_fb_reconfig(info);
1797 console_unlock();
1798 }
1799
1800 mutex_unlock(&ch->open_lock);
1801
1802 return 0;
1803 }
1804
1805 static int sh_mobile_lcdc_open(struct fb_info *info, int user)
1806 {
1807 struct sh_mobile_lcdc_chan *ch = info->par;
1808
1809 mutex_lock(&ch->open_lock);
1810 ch->use_count++;
1811
1812 dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count);
1813 mutex_unlock(&ch->open_lock);
1814
1815 return 0;
1816 }
1817
1818 static int sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var,
1819 struct fb_info *info)
1820 {
1821 struct sh_mobile_lcdc_chan *ch = info->par;
1822 struct sh_mobile_lcdc_priv *p = ch->lcdc;
1823 unsigned int best_dist = (unsigned int)-1;
1824 unsigned int best_xres = 0;
1825 unsigned int best_yres = 0;
1826 unsigned int i;
1827 int ret;
1828
1829
1830
1831
1832
1833
1834 for (i = 0; i < ch->cfg->num_modes; ++i) {
1835 const struct fb_videomode *mode = &ch->cfg->lcd_modes[i];
1836 unsigned int dist;
1837
1838
1839 if (var->xres > mode->xres || var->yres > mode->yres)
1840 continue;
1841
1842 dist = var->xres * var->yres + mode->xres * mode->yres
1843 - 2 * min(var->xres, mode->xres)
1844 * min(var->yres, mode->yres);
1845
1846 if (dist < best_dist) {
1847 best_xres = mode->xres;
1848 best_yres = mode->yres;
1849 best_dist = dist;
1850 }
1851 }
1852
1853
1854 if (ch->cfg->num_modes != 0) {
1855 if (best_dist == (unsigned int)-1)
1856 return -EINVAL;
1857
1858 var->xres = best_xres;
1859 var->yres = best_yres;
1860 }
1861
1862 ret = __sh_mobile_lcdc_check_var(var, info);
1863 if (ret < 0)
1864 return ret;
1865
1866
1867 if (p->forced_fourcc &&
1868 p->forced_fourcc != sh_mobile_format_fourcc(var))
1869 return -EINVAL;
1870
1871 return 0;
1872 }
1873
1874 static int sh_mobile_lcdc_set_par(struct fb_info *info)
1875 {
1876 struct sh_mobile_lcdc_chan *ch = info->par;
1877 int ret;
1878
1879 sh_mobile_lcdc_stop(ch->lcdc);
1880
1881 ch->format = sh_mobile_format_info(sh_mobile_format_fourcc(&info->var));
1882 ch->colorspace = info->var.colorspace;
1883
1884 ch->xres = info->var.xres;
1885 ch->xres_virtual = info->var.xres_virtual;
1886 ch->yres = info->var.yres;
1887 ch->yres_virtual = info->var.yres_virtual;
1888
1889 if (ch->format->yuv)
1890 ch->pitch = info->var.xres_virtual;
1891 else
1892 ch->pitch = info->var.xres_virtual * ch->format->bpp / 8;
1893
1894 ret = sh_mobile_lcdc_start(ch->lcdc);
1895 if (ret < 0)
1896 dev_err(info->dev, "%s: unable to restart LCDC\n", __func__);
1897
1898 info->fix.line_length = ch->pitch;
1899
1900 if (sh_mobile_format_is_fourcc(&info->var)) {
1901 info->fix.type = FB_TYPE_FOURCC;
1902 info->fix.visual = FB_VISUAL_FOURCC;
1903 } else {
1904 info->fix.type = FB_TYPE_PACKED_PIXELS;
1905 info->fix.visual = FB_VISUAL_TRUECOLOR;
1906 }
1907
1908 return ret;
1909 }
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919 static int sh_mobile_lcdc_blank(int blank, struct fb_info *info)
1920 {
1921 struct sh_mobile_lcdc_chan *ch = info->par;
1922 struct sh_mobile_lcdc_priv *p = ch->lcdc;
1923
1924
1925 if (blank > FB_BLANK_UNBLANK && ch->blank_status == FB_BLANK_UNBLANK) {
1926 struct fb_fillrect rect = {
1927 .width = ch->xres,
1928 .height = ch->yres,
1929 };
1930 sh_mobile_lcdc_fillrect(info, &rect);
1931 }
1932
1933 if (blank <= FB_BLANK_NORMAL && ch->blank_status > FB_BLANK_NORMAL) {
1934 sh_mobile_lcdc_clk_on(p);
1935 }
1936
1937 if (blank > FB_BLANK_NORMAL && ch->blank_status <= FB_BLANK_NORMAL) {
1938
1939
1940
1941
1942
1943 if (!info->fbdefio) {
1944 sh_mobile_lcdc_wait_for_vsync(ch);
1945 sh_mobile_lcdc_wait_for_vsync(ch);
1946 }
1947 sh_mobile_lcdc_clk_off(p);
1948 }
1949
1950 ch->blank_status = blank;
1951 return 0;
1952 }
1953
1954 static int
1955 sh_mobile_lcdc_mmap(struct fb_info *info, struct vm_area_struct *vma)
1956 {
1957 struct sh_mobile_lcdc_chan *ch = info->par;
1958
1959 if (info->fbdefio)
1960 return fb_deferred_io_mmap(info, vma);
1961
1962 return dma_mmap_coherent(ch->lcdc->dev, vma, ch->fb_mem,
1963 ch->dma_handle, ch->fb_size);
1964 }
1965
1966 static const struct fb_ops sh_mobile_lcdc_ops = {
1967 .owner = THIS_MODULE,
1968 .fb_setcolreg = sh_mobile_lcdc_setcolreg,
1969 .fb_read = fb_sys_read,
1970 .fb_write = fb_sys_write,
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
1984 static void
1985 sh_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
1991 static int
1992 sh_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
2016 if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED)
2017 sh_mobile_lcdc_clk_off(ch->lcdc);
2018
2019 return ret;
2020 }
2021
2022 static void
2023 sh_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
2036 static int
2037 sh_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
2047
2048
2049 info = framebuffer_alloc(0, priv->dev);
2050 if (!info)
2051 return -ENOMEM;
2052
2053 ch->info = info;
2054
2055 info->flags = FBINFO_FLAG_DEFAULT;
2056 info->fbops = &sh_mobile_lcdc_ops;
2057 info->device = priv->dev;
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
2071
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 else
2081 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
2094
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
2105
2106
2107 if (!ch->format->yuv)
2108 var->bits_per_pixel = ch->format->bpp;
2109 else
2110 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
2121
2122
2123 static 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
2136 static 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
2143 static int sh_mobile_lcdc_check_fb(struct backlight_device *bdev,
2144 struct fb_info *info)
2145 {
2146 return (info->bl_dev == bdev);
2147 }
2148
2149 static const struct backlight_ops sh_mobile_lcdc_bl_ops = {
2150 .options = BL_CORE_SUSPENDRESUME,
2151 .update_status = sh_mobile_lcdc_update_bl,
2152 .get_brightness = sh_mobile_lcdc_get_brightness,
2153 .check_fb = sh_mobile_lcdc_check_fb,
2154 };
2155
2156 static struct backlight_device *sh_mobile_lcdc_bl_probe(struct device *parent,
2157 struct sh_mobile_lcdc_chan *ch)
2158 {
2159 struct backlight_device *bl;
2160
2161 bl = backlight_device_register(ch->cfg->bl_info.name, parent, ch,
2162 &sh_mobile_lcdc_bl_ops, NULL);
2163 if (IS_ERR(bl)) {
2164 dev_err(parent, "unable to register backlight device: %ld\n",
2165 PTR_ERR(bl));
2166 return NULL;
2167 }
2168
2169 bl->props.max_brightness = ch->cfg->bl_info.max_brightness;
2170 bl->props.brightness = bl->props.max_brightness;
2171 backlight_update_status(bl);
2172
2173 return bl;
2174 }
2175
2176 static void sh_mobile_lcdc_bl_remove(struct backlight_device *bdev)
2177 {
2178 backlight_device_unregister(bdev);
2179 }
2180
2181
2182
2183
2184
2185 static int sh_mobile_lcdc_suspend(struct device *dev)
2186 {
2187 struct platform_device *pdev = to_platform_device(dev);
2188
2189 sh_mobile_lcdc_stop(platform_get_drvdata(pdev));
2190 return 0;
2191 }
2192
2193 static int sh_mobile_lcdc_resume(struct device *dev)
2194 {
2195 struct platform_device *pdev = to_platform_device(dev);
2196
2197 return sh_mobile_lcdc_start(platform_get_drvdata(pdev));
2198 }
2199
2200 static int sh_mobile_lcdc_runtime_suspend(struct device *dev)
2201 {
2202 struct sh_mobile_lcdc_priv *priv = dev_get_drvdata(dev);
2203
2204
2205 lcdc_write(priv, _LDCNT1R, 0);
2206
2207 return 0;
2208 }
2209
2210 static int sh_mobile_lcdc_runtime_resume(struct device *dev)
2211 {
2212 struct sh_mobile_lcdc_priv *priv = dev_get_drvdata(dev);
2213
2214 __sh_mobile_lcdc_start(priv);
2215
2216 return 0;
2217 }
2218
2219 static const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = {
2220 .suspend = sh_mobile_lcdc_suspend,
2221 .resume = sh_mobile_lcdc_resume,
2222 .runtime_suspend = sh_mobile_lcdc_runtime_suspend,
2223 .runtime_resume = sh_mobile_lcdc_runtime_resume,
2224 };
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234 static const struct fb_videomode default_720p = {
2235 .name = "HDMI 720p",
2236 .xres = 1280,
2237 .yres = 720,
2238
2239 .left_margin = 220,
2240 .right_margin = 110,
2241 .hsync_len = 40,
2242
2243 .upper_margin = 20,
2244 .lower_margin = 5,
2245 .vsync_len = 5,
2246
2247 .pixclock = 13468,
2248 .refresh = 60,
2249 .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
2250 };
2251
2252 static int sh_mobile_lcdc_remove(struct platform_device *pdev)
2253 {
2254 struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
2255 unsigned int i;
2256
2257 for (i = 0; i < ARRAY_SIZE(priv->overlays); i++)
2258 sh_mobile_lcdc_overlay_fb_unregister(&priv->overlays[i]);
2259 for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
2260 sh_mobile_lcdc_channel_fb_unregister(&priv->ch[i]);
2261
2262 sh_mobile_lcdc_stop(priv);
2263
2264 for (i = 0; i < ARRAY_SIZE(priv->overlays); i++) {
2265 struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i];
2266
2267 sh_mobile_lcdc_overlay_fb_cleanup(ovl);
2268
2269 if (ovl->fb_mem)
2270 dma_free_coherent(&pdev->dev, ovl->fb_size,
2271 ovl->fb_mem, ovl->dma_handle);
2272 }
2273
2274 for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
2275 struct sh_mobile_lcdc_chan *ch = &priv->ch[i];
2276
2277 if (ch->tx_dev) {
2278 ch->tx_dev->lcdc = NULL;
2279 module_put(ch->cfg->tx_dev->dev.driver->owner);
2280 }
2281
2282 sh_mobile_lcdc_channel_fb_cleanup(ch);
2283
2284 if (ch->fb_mem)
2285 dma_free_coherent(&pdev->dev, ch->fb_size,
2286 ch->fb_mem, ch->dma_handle);
2287 }
2288
2289 for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
2290 struct sh_mobile_lcdc_chan *ch = &priv->ch[i];
2291
2292 if (ch->bl)
2293 sh_mobile_lcdc_bl_remove(ch->bl);
2294 mutex_destroy(&ch->open_lock);
2295 }
2296
2297 if (priv->dot_clk) {
2298 pm_runtime_disable(&pdev->dev);
2299 clk_put(priv->dot_clk);
2300 }
2301
2302 if (priv->base)
2303 iounmap(priv->base);
2304
2305 if (priv->irq)
2306 free_irq(priv->irq, priv);
2307 kfree(priv);
2308 return 0;
2309 }
2310
2311 static int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
2312 {
2313 int interface_type = ch->cfg->interface_type;
2314
2315 switch (interface_type) {
2316 case RGB8:
2317 case RGB9:
2318 case RGB12A:
2319 case RGB12B:
2320 case RGB16:
2321 case RGB18:
2322 case RGB24:
2323 case SYS8A:
2324 case SYS8B:
2325 case SYS8C:
2326 case SYS8D:
2327 case SYS9:
2328 case SYS12:
2329 case SYS16A:
2330 case SYS16B:
2331 case SYS16C:
2332 case SYS18:
2333 case SYS24:
2334 break;
2335 default:
2336 return -EINVAL;
2337 }
2338
2339
2340 if (lcdc_chan_is_sublcd(ch)) {
2341 if (!(interface_type & LDMT1R_IFM))
2342 return -EINVAL;
2343
2344 interface_type &= ~LDMT1R_IFM;
2345 }
2346
2347 ch->ldmt1r_value = interface_type;
2348 return 0;
2349 }
2350
2351 static int
2352 sh_mobile_lcdc_overlay_init(struct sh_mobile_lcdc_overlay *ovl)
2353 {
2354 const struct sh_mobile_lcdc_format_info *format;
2355 struct device *dev = ovl->channel->lcdc->dev;
2356 int ret;
2357
2358 if (ovl->cfg->fourcc == 0)
2359 return 0;
2360
2361
2362 format = sh_mobile_format_info(ovl->cfg->fourcc);
2363 if (format == NULL) {
2364 dev_err(dev, "Invalid FOURCC %08x\n", ovl->cfg->fourcc);
2365 return -EINVAL;
2366 }
2367
2368 ovl->enabled = false;
2369 ovl->mode = LCDC_OVERLAY_BLEND;
2370 ovl->alpha = 255;
2371 ovl->rop3 = 0;
2372 ovl->pos_x = 0;
2373 ovl->pos_y = 0;
2374
2375
2376
2377
2378 ovl->format = format;
2379 ovl->xres = ovl->cfg->max_xres;
2380 ovl->xres_virtual = ovl->xres;
2381 ovl->yres = ovl->cfg->max_yres;
2382 ovl->yres_virtual = ovl->yres * 2;
2383
2384 if (!format->yuv)
2385 ovl->pitch = ovl->xres_virtual * format->bpp / 8;
2386 else
2387 ovl->pitch = ovl->xres_virtual;
2388
2389
2390 ovl->fb_size = ovl->cfg->max_xres * ovl->cfg->max_yres
2391 * format->bpp / 8 * 2;
2392 ovl->fb_mem = dma_alloc_coherent(dev, ovl->fb_size, &ovl->dma_handle,
2393 GFP_KERNEL);
2394 if (!ovl->fb_mem) {
2395 dev_err(dev, "unable to allocate buffer\n");
2396 return -ENOMEM;
2397 }
2398
2399 ret = sh_mobile_lcdc_overlay_fb_init(ovl);
2400 if (ret < 0)
2401 return ret;
2402
2403 return 0;
2404 }
2405
2406 static int
2407 sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch)
2408 {
2409 const struct sh_mobile_lcdc_format_info *format;
2410 const struct sh_mobile_lcdc_chan_cfg *cfg = ch->cfg;
2411 struct device *dev = ch->lcdc->dev;
2412 const struct fb_videomode *max_mode;
2413 const struct fb_videomode *mode;
2414 unsigned int num_modes;
2415 unsigned int max_size;
2416 unsigned int i;
2417
2418
2419 format = sh_mobile_format_info(cfg->fourcc);
2420 if (format == NULL) {
2421 dev_err(dev, "Invalid FOURCC %08x.\n", cfg->fourcc);
2422 return -EINVAL;
2423 }
2424
2425
2426
2427
2428 max_mode = NULL;
2429 max_size = 0;
2430
2431 for (i = 0, mode = cfg->lcd_modes; i < cfg->num_modes; i++, mode++) {
2432 unsigned int size = mode->yres * mode->xres;
2433
2434
2435 if ((cfg->fourcc == V4L2_PIX_FMT_NV12 ||
2436 cfg->fourcc == V4L2_PIX_FMT_NV21) && (mode->yres & 0x1)) {
2437 dev_err(dev, "yres must be multiple of 2 for "
2438 "YCbCr420 mode.\n");
2439 return -EINVAL;
2440 }
2441
2442 if (size > max_size) {
2443 max_mode = mode;
2444 max_size = size;
2445 }
2446 }
2447
2448 if (!max_size)
2449 max_size = MAX_XRES * MAX_YRES;
2450 else
2451 dev_dbg(dev, "Found largest videomode %ux%u\n",
2452 max_mode->xres, max_mode->yres);
2453
2454 if (cfg->lcd_modes == NULL) {
2455 mode = &default_720p;
2456 num_modes = 1;
2457 } else {
2458 mode = cfg->lcd_modes;
2459 num_modes = cfg->num_modes;
2460 }
2461
2462
2463
2464
2465 ch->format = format;
2466 ch->xres = mode->xres;
2467 ch->xres_virtual = mode->xres;
2468 ch->yres = mode->yres;
2469 ch->yres_virtual = mode->yres * 2;
2470
2471 if (!format->yuv) {
2472 ch->colorspace = V4L2_COLORSPACE_SRGB;
2473 ch->pitch = ch->xres_virtual * format->bpp / 8;
2474 } else {
2475 ch->colorspace = V4L2_COLORSPACE_REC709;
2476 ch->pitch = ch->xres_virtual;
2477 }
2478
2479 ch->display.width = cfg->panel_cfg.width;
2480 ch->display.height = cfg->panel_cfg.height;
2481 ch->display.mode = *mode;
2482
2483
2484 ch->fb_size = max_size * format->bpp / 8 * 2;
2485 ch->fb_mem = dma_alloc_coherent(dev, ch->fb_size, &ch->dma_handle,
2486 GFP_KERNEL);
2487 if (ch->fb_mem == NULL) {
2488 dev_err(dev, "unable to allocate buffer\n");
2489 return -ENOMEM;
2490 }
2491
2492
2493 if (cfg->tx_dev) {
2494 if (!cfg->tx_dev->dev.driver ||
2495 !try_module_get(cfg->tx_dev->dev.driver->owner)) {
2496 dev_warn(dev, "unable to get transmitter device\n");
2497 return -EINVAL;
2498 }
2499 ch->tx_dev = platform_get_drvdata(cfg->tx_dev);
2500 ch->tx_dev->lcdc = ch;
2501 ch->tx_dev->def_mode = *mode;
2502 }
2503
2504 return sh_mobile_lcdc_channel_fb_init(ch, mode, num_modes);
2505 }
2506
2507 static int sh_mobile_lcdc_probe(struct platform_device *pdev)
2508 {
2509 struct sh_mobile_lcdc_info *pdata = pdev->dev.platform_data;
2510 struct sh_mobile_lcdc_priv *priv;
2511 struct resource *res;
2512 int num_channels;
2513 int error;
2514 int irq, i;
2515
2516 if (!pdata) {
2517 dev_err(&pdev->dev, "no platform data defined\n");
2518 return -EINVAL;
2519 }
2520
2521 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2522 irq = platform_get_irq(pdev, 0);
2523 if (!res || irq < 0) {
2524 dev_err(&pdev->dev, "cannot get platform resources\n");
2525 return -ENOENT;
2526 }
2527
2528 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
2529 if (!priv)
2530 return -ENOMEM;
2531
2532 priv->dev = &pdev->dev;
2533
2534 for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
2535 mutex_init(&priv->ch[i].open_lock);
2536 platform_set_drvdata(pdev, priv);
2537
2538 error = request_irq(irq, sh_mobile_lcdc_irq, 0,
2539 dev_name(&pdev->dev), priv);
2540 if (error) {
2541 dev_err(&pdev->dev, "unable to request irq\n");
2542 goto err1;
2543 }
2544
2545 priv->irq = irq;
2546 atomic_set(&priv->hw_usecnt, -1);
2547
2548 for (i = 0, num_channels = 0; i < ARRAY_SIZE(pdata->ch); i++) {
2549 struct sh_mobile_lcdc_chan *ch = priv->ch + num_channels;
2550
2551 ch->lcdc = priv;
2552 ch->cfg = &pdata->ch[i];
2553
2554 error = sh_mobile_lcdc_check_interface(ch);
2555 if (error) {
2556 dev_err(&pdev->dev, "unsupported interface type\n");
2557 goto err1;
2558 }
2559 init_waitqueue_head(&ch->frame_end_wait);
2560 init_completion(&ch->vsync_completion);
2561
2562
2563 if (ch->cfg->bl_info.max_brightness)
2564 ch->bl = sh_mobile_lcdc_bl_probe(&pdev->dev, ch);
2565
2566 switch (pdata->ch[i].chan) {
2567 case LCDC_CHAN_MAINLCD:
2568 ch->enabled = LDCNT2R_ME;
2569 ch->reg_offs = lcdc_offs_mainlcd;
2570 num_channels++;
2571 break;
2572 case LCDC_CHAN_SUBLCD:
2573 ch->enabled = LDCNT2R_SE;
2574 ch->reg_offs = lcdc_offs_sublcd;
2575 num_channels++;
2576 break;
2577 }
2578 }
2579
2580 if (!num_channels) {
2581 dev_err(&pdev->dev, "no channels defined\n");
2582 error = -EINVAL;
2583 goto err1;
2584 }
2585
2586
2587 if (num_channels == 2)
2588 priv->forced_fourcc = pdata->ch[0].fourcc;
2589
2590 priv->base = ioremap(res->start, resource_size(res));
2591 if (!priv->base) {
2592 error = -ENOMEM;
2593 goto err1;
2594 }
2595
2596 error = sh_mobile_lcdc_setup_clocks(priv, pdata->clock_source);
2597 if (error) {
2598 dev_err(&pdev->dev, "unable to setup clocks\n");
2599 goto err1;
2600 }
2601
2602
2603 pm_runtime_enable(&pdev->dev);
2604
2605 for (i = 0; i < num_channels; i++) {
2606 struct sh_mobile_lcdc_chan *ch = &priv->ch[i];
2607
2608 error = sh_mobile_lcdc_channel_init(ch);
2609 if (error)
2610 goto err1;
2611 }
2612
2613 for (i = 0; i < ARRAY_SIZE(pdata->overlays); i++) {
2614 struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i];
2615
2616 ovl->cfg = &pdata->overlays[i];
2617 ovl->channel = &priv->ch[0];
2618
2619 error = sh_mobile_lcdc_overlay_init(ovl);
2620 if (error)
2621 goto err1;
2622 }
2623
2624 error = sh_mobile_lcdc_start(priv);
2625 if (error) {
2626 dev_err(&pdev->dev, "unable to start hardware\n");
2627 goto err1;
2628 }
2629
2630 for (i = 0; i < num_channels; i++) {
2631 struct sh_mobile_lcdc_chan *ch = priv->ch + i;
2632
2633 error = sh_mobile_lcdc_channel_fb_register(ch);
2634 if (error)
2635 goto err1;
2636 }
2637
2638 for (i = 0; i < ARRAY_SIZE(pdata->overlays); i++) {
2639 struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i];
2640
2641 error = sh_mobile_lcdc_overlay_fb_register(ovl);
2642 if (error)
2643 goto err1;
2644 }
2645
2646 return 0;
2647 err1:
2648 sh_mobile_lcdc_remove(pdev);
2649
2650 return error;
2651 }
2652
2653 static struct platform_driver sh_mobile_lcdc_driver = {
2654 .driver = {
2655 .name = "sh_mobile_lcdc_fb",
2656 .pm = &sh_mobile_lcdc_dev_pm_ops,
2657 },
2658 .probe = sh_mobile_lcdc_probe,
2659 .remove = sh_mobile_lcdc_remove,
2660 };
2661
2662 module_platform_driver(sh_mobile_lcdc_driver);
2663
2664 MODULE_DESCRIPTION("SuperH Mobile LCDC Framebuffer driver");
2665 MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
2666 MODULE_LICENSE("GPL v2");