static int sh_mobile_lcdc_runtime_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct sh_mobile_lcdc_priv *p = platform_get_drvdata(pdev); struct sh_mobile_lcdc_chan *ch; int k, n; /* save per-channel registers */ for (k = 0; k < ARRAY_SIZE(p->ch); k++) { ch = &p->ch[k]; if (!ch->enabled) continue; for (n = 0; n < NR_CH_REGS; n++) ch->saved_ch_regs[n] = lcdc_read_chan(ch, n); } /* save shared registers */ for (n = 0; n < NR_SHARED_REGS; n++) p->saved_shared_regs[n] = lcdc_read(p, lcdc_shared_regs[n]); /* turn off LCDC hardware */ lcdc_write(p, _LDCNT1R, 0); return 0; }
static int32_t sprdfb_lcdc_refresh (struct sprdfb_device *dev) { struct fb_info *fb = dev->fb; uint32_t base = fb->fix.smem_start + fb->fix.line_length * fb->var.yoffset; pr_debug(KERN_INFO "sprdfb:[%s]\n",__FUNCTION__); lcdc_ctx.vsync_waiter ++; lcdc_sync(dev); pr_debug(KERN_INFO "srpdfb: [%s] got sync\n", __FUNCTION__); lcdc_ctx.dev = dev; lcdc_ctx.vsync_done = 0; #ifdef LCD_UPDATE_PARTLY if (fb->var.reserved[0] == 0x6f766572) { uint32_t x,y, width, height; x = fb->var.reserved[1] & 0xffff; y = fb->var.reserved[1] >> 16; width = fb->var.reserved[2] & 0xffff; height = fb->var.reserved[2] >> 16; base += ((x + y * fb->var.xres) * fb->var.bits_per_pixel / 8); lcdc_write(base, LCDC_OSD1_BASE_ADDR); lcdc_write(0, LCDC_OSD1_DISP_XY); lcdc_write(fb->var.reserved[2], LCDC_OSD1_SIZE_XY); lcdc_write(fb->var.xres, LCDC_OSD1_PITCH); lcdc_write(fb->var.reserved[2], LCDC_DISP_SIZE); lcdc_write(0, LCDC_LCM_START); lcdc_write(fb->var.reserved[2], LCDC_LCM_SIZE); sprdfb_panel_invalidate_rect(dev->panel, x, y, x+width-1, y+height-1); } else
static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { struct sh_mobile_lcdc_chan *ch = info->par; struct sh_mobile_lcdc_priv *priv = ch->lcdc; unsigned long ldrcntr; unsigned long new_pan_offset; unsigned long base_addr_y, base_addr_c; unsigned long c_offset; if (!var->nonstd) new_pan_offset = (var->yoffset * info->fix.line_length) + (var->xoffset * (info->var.bits_per_pixel / 8)); else new_pan_offset = (var->yoffset * info->fix.line_length) + (var->xoffset); if (new_pan_offset == ch->pan_offset) return 0; /* No change, do nothing */ ldrcntr = lcdc_read(priv, _LDRCNTR); /* Set the source address for the next refresh */ base_addr_y = ch->dma_handle + new_pan_offset; if (var->nonstd) { /* Set y offset */ c_offset = (var->yoffset * info->fix.line_length * (info->var.bits_per_pixel - 8)) / 8; base_addr_c = ch->dma_handle + var->xres * var->yres_virtual + c_offset; /* Set x offset */ if (info->var.bits_per_pixel == 24) base_addr_c += 2 * var->xoffset; else base_addr_c += var->xoffset; } else base_addr_c = 0; if (!ch->meram_enabled) { lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y); if (base_addr_c) lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c); } else { struct sh_mobile_meram_cfg *cfg; struct sh_mobile_meram_info *mdev; unsigned long icb_addr_y, icb_addr_c; int ret; cfg = ch->cfg.meram_cfg; mdev = priv->meram_dev; ret = mdev->ops->meram_update(mdev, cfg, base_addr_y, base_addr_c, &icb_addr_y, &icb_addr_c); if (ret) return ret; lcdc_write_chan_mirror(ch, LDSA1R, icb_addr_y); if (icb_addr_c) lcdc_write_chan_mirror(ch, LDSA2R, icb_addr_c); } if (lcdc_chan_is_sublcd(ch)) lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS); else lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_MRS); ch->pan_offset = new_pan_offset; sh_mobile_lcdc_deferred_io_touch(info); return 0; }
static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) { struct sh_mobile_lcdc_chan *ch; struct sh_mobile_lcdc_board_cfg *board_cfg; unsigned long tmp; int bpp = 0; unsigned long ldddsr; int k, m, ret; /* enable clocks before accessing the hardware */ for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { if (priv->ch[k].enabled) { sh_mobile_lcdc_clk_on(priv); if (!bpp) bpp = priv->ch[k].info->var.bits_per_pixel; } } /* reset */ lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LCDC_RESET); lcdc_wait_bit(priv, _LDCNT2R, LCDC_RESET, 0); /* enable LCDC channels */ tmp = lcdc_read(priv, _LDCNT2R); tmp |= priv->ch[0].enabled; tmp |= priv->ch[1].enabled; lcdc_write(priv, _LDCNT2R, tmp); /* read data from external memory, avoid using the BEU for now */ lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) & ~DISPLAY_BEU); /* stop the lcdc first */ sh_mobile_lcdc_start_stop(priv, 0); /* configure clocks */ tmp = priv->lddckr; for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!priv->ch[k].enabled) continue; m = ch->cfg.clock_divider; if (!m) continue; if (m == 1) m = 1 << 6; tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0); /* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider denominator */ lcdc_write_chan(ch, LDDCKPAT1R, 0); lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1); } lcdc_write(priv, _LDDCKR, tmp); /* start dotclock again */ lcdc_write(priv, _LDDCKSTPR, 0); lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0); /* interrupts are disabled to begin with */ lcdc_write(priv, _LDINTR, 0); for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!ch->enabled) continue; sh_mobile_lcdc_geometry(ch); /* power supply */ lcdc_write_chan(ch, LDPMR, 0); board_cfg = &ch->cfg.board_cfg; if (board_cfg->setup_sys) { ret = board_cfg->setup_sys(board_cfg->board_data, ch, &sh_mobile_lcdc_sys_bus_ops); if (ret) return ret; } } /* word and long word swap */ ldddsr = lcdc_read(priv, _LDDDSR); if (priv->ch[0].info->var.nonstd) lcdc_write(priv, _LDDDSR, ldddsr | 7); else { switch (bpp) { case 16: lcdc_write(priv, _LDDDSR, ldddsr | 6); break; case 24: lcdc_write(priv, _LDDDSR, ldddsr | 7); break; case 32: lcdc_write(priv, _LDDDSR, ldddsr | 4); break; } } for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { unsigned long base_addr_y; unsigned long base_addr_c = 0; int pitch; ch = &priv->ch[k]; if (!priv->ch[k].enabled) continue; /* set bpp format in PKF[4:0] */ tmp = lcdc_read_chan(ch, LDDFR); tmp &= ~0x0003031f; if (ch->info->var.nonstd) { tmp |= (ch->info->var.nonstd << 16); switch (ch->info->var.bits_per_pixel) { case 12: break; case 16: tmp |= (0x1 << 8); break; case 24: tmp |= (0x2 << 8); break; } } else { switch (ch->info->var.bits_per_pixel) { case 16: tmp |= 0x03; break; case 24: tmp |= 0x0b; break; case 32: break; } } lcdc_write_chan(ch, LDDFR, tmp); base_addr_y = ch->info->fix.smem_start; base_addr_c = base_addr_y + ch->info->var.xres * ch->info->var.yres_virtual; pitch = ch->info->fix.line_length; /* test if we can enable meram */ if (ch->cfg.meram_cfg && priv->meram_dev && priv->meram_dev->ops) { struct sh_mobile_meram_cfg *cfg; struct sh_mobile_meram_info *mdev; unsigned long icb_addr_y, icb_addr_c; int icb_pitch; int pf; cfg = ch->cfg.meram_cfg; mdev = priv->meram_dev; /* we need to de-init configured ICBs before we * we can re-initialize them. */ if (ch->meram_enabled) mdev->ops->meram_unregister(mdev, cfg); ch->meram_enabled = 0; if (ch->info->var.nonstd) { if (ch->info->var.bits_per_pixel == 24) pf = SH_MOBILE_MERAM_PF_NV24; else pf = SH_MOBILE_MERAM_PF_NV; } else { pf = SH_MOBILE_MERAM_PF_RGB; } ret = mdev->ops->meram_register(mdev, cfg, pitch, ch->info->var.yres, pf, base_addr_y, base_addr_c, &icb_addr_y, &icb_addr_c, &icb_pitch); if (!ret) { /* set LDSA1R value */ base_addr_y = icb_addr_y; pitch = icb_pitch; /* set LDSA2R value if required */ if (base_addr_c) base_addr_c = icb_addr_c; ch->meram_enabled = 1; } } /* point out our frame buffer */ lcdc_write_chan(ch, LDSA1R, base_addr_y); if (ch->info->var.nonstd) lcdc_write_chan(ch, LDSA2R, base_addr_c); /* set line size */ lcdc_write_chan(ch, LDMLSR, pitch); /* setup deferred io if SYS bus */ tmp = ch->cfg.sys_bus_cfg.deferred_io_msec; if (ch->ldmt1r_value & (1 << 12) && tmp) { ch->defio.deferred_io = sh_mobile_lcdc_deferred_io; ch->defio.delay = msecs_to_jiffies(tmp); ch->info->fbdefio = &ch->defio; fb_deferred_io_init(ch->info); /* one-shot mode */ lcdc_write_chan(ch, LDSM1R, 1); /* enable "Frame End Interrupt Enable" bit */ lcdc_write(priv, _LDINTR, LDINTR_FE); } else { /* continuous read mode */ lcdc_write_chan(ch, LDSM1R, 0); } } /* display output */ lcdc_write(priv, _LDCNT1R, LCDC_ENABLE); /* start the lcdc */ sh_mobile_lcdc_start_stop(priv, 1); priv->started = 1; /* tell the board code to enable the panel */ for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!ch->enabled) continue; board_cfg = &ch->cfg.board_cfg; if (board_cfg->display_on && try_module_get(board_cfg->owner)) { board_cfg->display_on(board_cfg->board_data, ch->info); module_put(board_cfg->owner); } if (ch->bl) { ch->bl->props.power = FB_BLANK_UNBLANK; backlight_update_status(ch->bl); } } return 0; }
static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) { struct sh_mobile_lcdc_chan *ch; struct sh_mobile_lcdc_board_cfg *board_cfg; unsigned long tmp; int bpp = 0; int k, m; int ret = 0; /* enable clocks before accessing the hardware */ for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { if (priv->ch[k].enabled) { sh_mobile_lcdc_clk_on(priv); if (!bpp) bpp = priv->ch[k].info->var.bits_per_pixel; } } /* reset */ lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LCDC_RESET); lcdc_wait_bit(priv, _LDCNT2R, LCDC_RESET, 0); /* enable LCDC channels */ tmp = lcdc_read(priv, _LDCNT2R); tmp |= priv->ch[0].enabled; tmp |= priv->ch[1].enabled; lcdc_write(priv, _LDCNT2R, tmp); /* read data from external memory, avoid using the BEU for now */ lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) & ~DISPLAY_BEU); /* stop the lcdc first */ sh_mobile_lcdc_start_stop(priv, 0); /* configure clocks */ tmp = priv->lddckr; for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!priv->ch[k].enabled) continue; m = ch->cfg.clock_divider; if (!m) continue; if (m == 1) m = 1 << 6; tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0); /* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider denominator */ lcdc_write_chan(ch, LDDCKPAT1R, 0); lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1); } lcdc_write(priv, _LDDCKR, tmp); /* start dotclock again */ lcdc_write(priv, _LDDCKSTPR, 0); lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0); /* interrupts are disabled to begin with */ lcdc_write(priv, _LDINTR, 0); for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!ch->enabled) continue; sh_mobile_lcdc_geometry(ch); /* power supply */ lcdc_write_chan(ch, LDPMR, 0); board_cfg = &ch->cfg.board_cfg; if (board_cfg->setup_sys) ret = board_cfg->setup_sys(board_cfg->board_data, ch, &sh_mobile_lcdc_sys_bus_ops); if (ret) return ret; } /* word and long word swap */ switch (bpp) { case 16: lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 6); break; case 24: lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 7); break; case 32: lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 4); break; } for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!priv->ch[k].enabled) continue; /* set bpp format in PKF[4:0] */ tmp = lcdc_read_chan(ch, LDDFR); tmp &= ~0x0001001f; switch (ch->info->var.bits_per_pixel) { case 16: tmp |= 0x03; break; case 24: tmp |= 0x0b; break; case 32: break; } lcdc_write_chan(ch, LDDFR, tmp); /* point out our frame buffer */ lcdc_write_chan(ch, LDSA1R, ch->info->fix.smem_start); /* set line size */ lcdc_write_chan(ch, LDMLSR, ch->info->fix.line_length); /* setup deferred io if SYS bus */ tmp = ch->cfg.sys_bus_cfg.deferred_io_msec; if (ch->ldmt1r_value & (1 << 12) && tmp) { ch->defio.deferred_io = sh_mobile_lcdc_deferred_io; ch->defio.delay = msecs_to_jiffies(tmp); ch->info->fbdefio = &ch->defio; fb_deferred_io_init(ch->info); /* one-shot mode */ lcdc_write_chan(ch, LDSM1R, 1); /* enable "Frame End Interrupt Enable" bit */ lcdc_write(priv, _LDINTR, LDINTR_FE); } else { /* continuous read mode */ lcdc_write_chan(ch, LDSM1R, 0); } } /* display output */ lcdc_write(priv, _LDCNT1R, LCDC_ENABLE); /* start the lcdc */ sh_mobile_lcdc_start_stop(priv, 1); priv->started = 1; /* tell the board code to enable the panel */ for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!ch->enabled) continue; board_cfg = &ch->cfg.board_cfg; if (try_module_get(board_cfg->owner) && board_cfg->display_on) { board_cfg->display_on(board_cfg->board_data, ch->info); module_put(board_cfg->owner); } } return 0; }
/* * shmob_drm_crtc_start - Configure and start the LCDC * @scrtc: the SH Mobile CRTC * * Configure and start the LCDC device. External devices (clocks, MERAM, panels, * ...) are not touched by this function. */ static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc) { struct drm_crtc *crtc = &scrtc->crtc; struct shmob_drm_device *sdev = crtc->dev->dev_private; const struct shmob_drm_interface_data *idata = &sdev->pdata->iface; const struct shmob_drm_format_info *format; struct drm_device *dev = sdev->ddev; struct drm_plane *plane; u32 value; int ret; if (scrtc->started) return; format = shmob_drm_format_info(crtc->primary->fb->pixel_format); if (WARN_ON(format == NULL)) return; /* Enable clocks before accessing the hardware. */ ret = shmob_drm_clk_on(sdev); if (ret < 0) return; /* Reset and enable the LCDC. */ lcdc_write(sdev, LDCNT2R, lcdc_read(sdev, LDCNT2R) | LDCNT2R_BR); lcdc_wait_bit(sdev, LDCNT2R, LDCNT2R_BR, 0); lcdc_write(sdev, LDCNT2R, LDCNT2R_ME); /* Stop the LCDC first and disable all interrupts. */ shmob_drm_crtc_start_stop(scrtc, false); lcdc_write(sdev, LDINTR, 0); /* Configure power supply, dot clocks and start them. */ lcdc_write(sdev, LDPMR, 0); value = sdev->lddckr; if (idata->clk_div) { /* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider * denominator. */ lcdc_write(sdev, LDDCKPAT1R, 0); lcdc_write(sdev, LDDCKPAT2R, (1 << (idata->clk_div / 2)) - 1); if (idata->clk_div == 1) value |= LDDCKR_MOSEL; else value |= idata->clk_div; } lcdc_write(sdev, LDDCKR, value); lcdc_write(sdev, LDDCKSTPR, 0); lcdc_wait_bit(sdev, LDDCKSTPR, ~0, 0); /* TODO: Setup SYS panel */ /* Setup geometry, format, frame buffer memory and operation mode. */ shmob_drm_crtc_setup_geometry(scrtc); /* TODO: Handle YUV colorspaces. Hardcode REC709 for now. */ lcdc_write(sdev, LDDFR, format->lddfr | LDDFR_CF1); lcdc_write(sdev, LDMLSR, scrtc->line_size); lcdc_write(sdev, LDSA1R, scrtc->dma[0]); if (format->yuv) lcdc_write(sdev, LDSA2R, scrtc->dma[1]); lcdc_write(sdev, LDSM1R, 0); /* Word and long word swap. */ switch (format->fourcc) { case DRM_FORMAT_RGB565: case DRM_FORMAT_NV21: case DRM_FORMAT_NV61: case DRM_FORMAT_NV42: value = LDDDSR_LS | LDDDSR_WS; break; case DRM_FORMAT_RGB888: case DRM_FORMAT_NV12: case DRM_FORMAT_NV16: case DRM_FORMAT_NV24: value = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS; break; case DRM_FORMAT_ARGB8888: default: value = LDDDSR_LS; break; } lcdc_write(sdev, LDDDSR, value); /* Setup planes. */ drm_for_each_legacy_plane(plane, dev) { if (plane->crtc == crtc) shmob_drm_plane_setup(plane); } /* Enable the display output. */ lcdc_write(sdev, LDCNT1R, LDCNT1R_DE); shmob_drm_crtc_start_stop(scrtc, true); scrtc->started = true; }
static int32_t r61581b_init(struct panel_spec *self) { #ifdef CONFIG_LCD_DATA_WIDTH_8BIT lcdc_write(4, LCM_CTRL); #endif self->info.mcu->ops->send_cmd(0xff); LCD_DelayMS(130); self->info.mcu->ops->send_cmd(0xff); LCD_DelayMS(5); self->info.mcu->ops->send_cmd(0xff); self->info.mcu->ops->send_cmd(0xff); self->info.mcu->ops->send_cmd(0xff); self->info.mcu->ops->send_cmd(0xff); LCD_DelayMS(10); self->info.mcu->ops->send_cmd(0xb0); self->info.mcu->ops->send_data(0x00); self->info.mcu->ops->send_cmd(0x11); LCD_DelayMS(150); self->info.mcu->ops->send_cmd(0xb3); self->info.mcu->ops->send_data(0x02); self->info.mcu->ops->send_data(0x00); //17 self->info.mcu->ops->send_data(0x00); //0x18 self->info.mcu->ops->send_data(0x00); self->info.mcu->ops->send_cmd(0xC0); #ifdef MENGBO_SHENGDA_R61581b self->info.mcu->ops->send_data(0x16);//0x00 #else self->info.mcu->ops->send_data(0x13);//0x00 #endif self->info.mcu->ops->send_data(0x3B); self->info.mcu->ops->send_data(0x00); self->info.mcu->ops->send_data(0x02); self->info.mcu->ops->send_data(0x00); self->info.mcu->ops->send_data(0x01); self->info.mcu->ops->send_data(0x00); self->info.mcu->ops->send_data(0x43); self->info.mcu->ops->send_cmd(0xC1);// Frame frequency self->info.mcu->ops->send_data(0x08);//0x00 self->info.mcu->ops->send_data(0x10);//0x16 22 clocks, 0x1a 26clocks self->info.mcu->ops->send_data(0x08); self->info.mcu->ops->send_data(0x08); self->info.mcu->ops->send_cmd(0xC4); self->info.mcu->ops->send_data(0x11);//0x00 self->info.mcu->ops->send_data(0x07); self->info.mcu->ops->send_data(0x03); self->info.mcu->ops->send_data(0x03); self->info.mcu->ops->send_cmd(0xC6); self->info.mcu->ops->send_data(0x00);//0x00 self->info.mcu->ops->send_cmd(0xC8); self->info.mcu->ops->send_data(0x03); self->info.mcu->ops->send_data(0x03); self->info.mcu->ops->send_data(0x13); self->info.mcu->ops->send_data(0x5c); self->info.mcu->ops->send_data(0x03); self->info.mcu->ops->send_data(0x07); self->info.mcu->ops->send_data(0x14); self->info.mcu->ops->send_data(0x08); self->info.mcu->ops->send_data(0x00); self->info.mcu->ops->send_data(0x21); self->info.mcu->ops->send_data(0x08); self->info.mcu->ops->send_data(0x14); self->info.mcu->ops->send_data(0x07); self->info.mcu->ops->send_data(0x53); self->info.mcu->ops->send_data(0x0c); self->info.mcu->ops->send_data(0x13); self->info.mcu->ops->send_data(0x03); self->info.mcu->ops->send_data(0x03); self->info.mcu->ops->send_data(0x21); self->info.mcu->ops->send_data(0x00); self->info.mcu->ops->send_cmd(0x35); self->info.mcu->ops->send_data(0x00);//0A self->info.mcu->ops->send_cmd(0x36); self->info.mcu->ops->send_data(0x00); self->info.mcu->ops->send_cmd(0x3A);// self->info.mcu->ops->send_data(0x55); self->info.mcu->ops->send_cmd(0x44); self->info.mcu->ops->send_data(0x00); self->info.mcu->ops->send_data(0x01); self->info.mcu->ops->send_cmd(0xd0); self->info.mcu->ops->send_data(0x07); self->info.mcu->ops->send_data(0x07); self->info.mcu->ops->send_data(0x1d); self->info.mcu->ops->send_data(0x03); self->info.mcu->ops->send_cmd(0xd1);//set vcom self->info.mcu->ops->send_data(0x03); self->info.mcu->ops->send_data(0x30); self->info.mcu->ops->send_data(0x10); self->info.mcu->ops->send_cmd(0xd2); self->info.mcu->ops->send_data(0x03); self->info.mcu->ops->send_data(0x14); self->info.mcu->ops->send_data(0x04); self->info.mcu->ops->send_cmd(0x29); LCD_DelayMS(30); self->info.mcu->ops->send_cmd(0x2A); self->info.mcu->ops->send_data(0x00); self->info.mcu->ops->send_data(0x00); self->info.mcu->ops->send_data(0x01); self->info.mcu->ops->send_data(0x3F); self->info.mcu->ops->send_cmd(0x2B); self->info.mcu->ops->send_data(0x00); self->info.mcu->ops->send_data(0x00); self->info.mcu->ops->send_data(0x01); self->info.mcu->ops->send_data(0xDF); self->info.mcu->ops->send_cmd(0x35); // TE on self->info.mcu->ops->send_data(0x00); self->info.mcu->ops->send_cmd(0xb4); self->info.mcu->ops->send_data(0x00); LCD_DelayMS(120); self->info.mcu->ops->send_cmd(0x2c);// Set_display_on #ifdef CONFIG_LCD_DATA_WIDTH_8BIT lcdc_write(0, LCM_CTRL); #endif return 0; }
static int32_t r61581b_set_window(struct panel_spec *self, uint16_t left, uint16_t top, uint16_t right, uint16_t bottom) { send_data_t send_cmd = self->info.mcu->ops->send_cmd; send_data_t send_data = self->info.mcu->ops->send_data; // send_data_t send_cmd_data = self->info.mcu->ops->send_cmd_data; #ifdef CONFIG_LCD_DATA_WIDTH_8BIT lcdc_write(4, LCM_CTRL); #endif /* set window size */ //send_cmd_data(0x002A, (left >> 8)); send_cmd(0x002A); send_data((left >> 8)); send_data( (left & 0xff)); send_data((right >> 8)); send_data((right & 0xff)); // send_cmd_data(0x002A, (left & 0xff)); // send_cmd_data(0x002A, (right >> 8)); // send_cmd_data(0x002A, (right & 0xff)); //send_cmd_data(0x002B, (top >> 8)); send_cmd(0x002B); send_data((left >> 8)); send_data( (top & 0xff)); send_data((bottom >> 8)); send_data((bottom & 0xff)); // send_cmd_data(0x002B, (top & 0xff)); // send_cmd_data(0x002B,(bottom >> 8)); // send_cmd_data(0x002B,(bottom & 0xff)); #if 0 switch (self->direction) { case LCD_DIRECT_NORMAL: default: send_cmd_data(0x0080, (left >> 8)); send_cmd_data(0x0081, (left & 0xff)); send_cmd_data(0x0082, (top >> 8)); send_cmd_data(0x0083, (top & 0xff)); break; case LCD_DIRECT_ROT_90: send_cmd_data(0x0080, (top >> 8)); send_cmd_data(0x0081, (top & 0xff)); send_cmd_data(0x0082, (left >> 8)); send_cmd_data(0x0083, (left & 0xff)); break; case LCD_DIRECT_ROT_180: case LCD_DIRECT_MIR_HV: send_cmd_data(0x0080, (right >> 8)); send_cmd_data(0x0081, (right & 0xff)); send_cmd_data(0x0082, (bottom >> 8)); send_cmd_data(0x0083, (bottom & 0xff)); break; case LCD_DIRECT_ROT_270: send_cmd_data(0x0080, (bottom >> 8)); send_cmd_data(0x0081, (bottom & 0xff)); send_cmd_data(0x0082, (left >> 8)); send_cmd_data(0x0083, (left & 0xff)); break; case LCD_DIRECT_MIR_H: send_cmd_data(0x0080, (left >> 8)); send_cmd_data(0x0081, (left & 0xff)); send_cmd_data(0x0082, (bottom >> 8)); send_cmd_data(0x0083, (bottom & 0xff)); break; case LCD_DIRECT_MIR_V: send_cmd_data(0x0080, (right >> 8)); send_cmd_data(0x0081, (right & 0xff)); send_cmd_data(0x0082, (top >> 8)); send_cmd_data(0x0083, (top & 0xff)); break; } #endif send_cmd(0x002c); #ifdef CONFIG_LCD_DATA_WIDTH_8BIT lcdc_write(0, LCM_CTRL); #endif return 0; }
static void lcdc_layer_init(struct fb_var_screeninfo *var) { uint32_t reg_val = 0; /******************* OSD1 layer setting **********************/ lcdc_clear_bits((1<<0),LCDC_IMG_CTRL); lcdc_clear_bits((1<<0),LCDC_OSD2_CTRL); lcdc_clear_bits((1<<0),LCDC_OSD3_CTRL); lcdc_clear_bits((1<<0),LCDC_OSD4_CTRL); lcdc_clear_bits((1<<0),LCDC_OSD5_CTRL); /*enable OSD1 layer*/ reg_val |= (1 << 0); /* color key */ /* alpha mode select */ reg_val |= (1 << 2); /* data format */ if (var->bits_per_pixel == 32) { /* ABGR */ reg_val |= (3 << 3); /* rb switch */ reg_val |= (1 << 9); } else { /* RGB565 */ reg_val |= (5 << 3); /* B2B3B0B1 */ reg_val |= (2 << 7); } lcdc_write(reg_val, LCDC_OSD1_CTRL); /* OSD1 layer alpha value */ lcdc_write(0xff, LCDC_OSD1_ALPHA); /* alpha base addr */ /* OSD1 layer size */ reg_val = ( var->xres & 0xfff) | (( var->yres & 0xfff ) << 16); lcdc_write(reg_val, LCDC_OSD1_SIZE_XY); /* OSD1 layer start position */ lcdc_write(0, LCDC_OSD1_DISP_XY); /* OSD1 layer pitch */ reg_val = ( var->xres & 0xfff) ; lcdc_write(reg_val, LCDC_OSD1_PITCH); /* OSD1 color_key value */ /* OSD1 grey RGB */ /* LCDC workplane size */ set_lcdsize(var); /*LCDC LCM rect size */ set_lcmrect(var); }
static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) { struct sh_mobile_lcdc_chan *ch; struct fb_videomode *lcd_cfg; struct sh_mobile_lcdc_board_cfg *board_cfg; unsigned long tmp; int k, m; int ret = 0; for (k = 0; k < ARRAY_SIZE(priv->ch); k++) if (priv->ch[k].enabled) sh_mobile_lcdc_clk_on(priv); lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LCDC_RESET); lcdc_wait_bit(priv, _LDCNT2R, LCDC_RESET, 0); tmp = lcdc_read(priv, _LDCNT2R); tmp |= priv->ch[0].enabled; tmp |= priv->ch[1].enabled; lcdc_write(priv, _LDCNT2R, tmp); lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) & ~DISPLAY_BEU); sh_mobile_lcdc_start_stop(priv, 0); tmp = priv->lddckr; for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!priv->ch[k].enabled) continue; m = ch->cfg.clock_divider; if (!m) continue; if (m == 1) m = 1 << 6; tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0); lcdc_write_chan(ch, LDDCKPAT1R, 0x00000000); lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1); } lcdc_write(priv, _LDDCKR, tmp); lcdc_write(priv, _LDDCKSTPR, 0); lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0); lcdc_write(priv, _LDINTR, 0); for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; lcd_cfg = &ch->cfg.lcd_cfg; if (!ch->enabled) continue; tmp = ch->ldmt1r_value; tmp |= (lcd_cfg->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1 << 28; tmp |= (lcd_cfg->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1 << 27; tmp |= (ch->cfg.flags & LCDC_FLAGS_DWPOL) ? 1 << 26 : 0; tmp |= (ch->cfg.flags & LCDC_FLAGS_DIPOL) ? 1 << 25 : 0; tmp |= (ch->cfg.flags & LCDC_FLAGS_DAPOL) ? 1 << 24 : 0; tmp |= (ch->cfg.flags & LCDC_FLAGS_HSCNT) ? 1 << 17 : 0; tmp |= (ch->cfg.flags & LCDC_FLAGS_DWCNT) ? 1 << 16 : 0; lcdc_write_chan(ch, LDMT1R, tmp); lcdc_write_chan(ch, LDMT2R, ch->cfg.sys_bus_cfg.ldmt2r); lcdc_write_chan(ch, LDMT3R, ch->cfg.sys_bus_cfg.ldmt3r); tmp = lcd_cfg->xres + lcd_cfg->hsync_len; tmp += lcd_cfg->left_margin; tmp += lcd_cfg->right_margin; tmp /= 8; tmp |= (lcd_cfg->xres / 8) << 16; lcdc_write_chan(ch, LDHCNR, tmp); tmp = lcd_cfg->xres; tmp += lcd_cfg->right_margin; tmp /= 8; tmp |= (lcd_cfg->hsync_len / 8) << 16; lcdc_write_chan(ch, LDHSYNR, tmp); lcdc_write_chan(ch, LDPMR, 0); tmp = lcd_cfg->yres + lcd_cfg->vsync_len; tmp += lcd_cfg->upper_margin; tmp += lcd_cfg->lower_margin; tmp |= lcd_cfg->yres << 16; lcdc_write_chan(ch, LDVLNR, tmp); tmp = lcd_cfg->yres; tmp += lcd_cfg->lower_margin; tmp |= lcd_cfg->vsync_len << 16; lcdc_write_chan(ch, LDVSYNR, tmp); board_cfg = &ch->cfg.board_cfg; if (board_cfg->setup_sys) ret = board_cfg->setup_sys(board_cfg->board_data, ch, &sh_mobile_lcdc_sys_bus_ops); if (ret) return ret; } lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 6); for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!priv->ch[k].enabled) continue; tmp = lcdc_read_chan(ch, LDDFR); tmp &= ~(0x0001001f); tmp |= (ch->info->var.bits_per_pixel == 16) ? 3 : 0; lcdc_write_chan(ch, LDDFR, tmp); lcdc_write_chan(ch, LDSA1R, ch->info->fix.smem_start); lcdc_write_chan(ch, LDMLSR, ch->info->fix.line_length); tmp = ch->cfg.sys_bus_cfg.deferred_io_msec; if (ch->ldmt1r_value & (1 << 12) && tmp) { ch->defio.deferred_io = sh_mobile_lcdc_deferred_io; ch->defio.delay = msecs_to_jiffies(tmp); ch->info->fbdefio = &ch->defio; fb_deferred_io_init(ch->info); lcdc_write_chan(ch, LDSM1R, 1); lcdc_write(priv, _LDINTR, LDINTR_FE); } else { lcdc_write_chan(ch, LDSM1R, 0); } } lcdc_write(priv, _LDCNT1R, LCDC_ENABLE); sh_mobile_lcdc_start_stop(priv, 1); priv->started = 1; for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!ch->enabled) continue; board_cfg = &ch->cfg.board_cfg; if (board_cfg->display_on) board_cfg->display_on(board_cfg->board_data); } return 0; }
static inline void lcdc_set_osd_ck(uint32_t ck_color) { lcdc_write(ck_color, LCDC_OSD1_CK); }
static inline void lcdc_set_bg_color(uint32_t bg_color) { lcdc_write(bg_color, LCDC_BG_COLOR); }
static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) { struct sh_mobile_lcdc_chan *ch; struct fb_videomode *lcd_cfg; struct sh_mobile_lcdc_board_cfg *board_cfg; unsigned long tmp; int k, m; int ret = 0; /* enable clocks before accessing the hardware */ for (k = 0; k < ARRAY_SIZE(priv->ch); k++) if (priv->ch[k].enabled) sh_mobile_lcdc_clk_on(priv); /* reset */ lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LCDC_RESET); lcdc_wait_bit(priv, _LDCNT2R, LCDC_RESET, 0); /* enable LCDC channels */ tmp = lcdc_read(priv, _LDCNT2R); tmp |= priv->ch[0].enabled; tmp |= priv->ch[1].enabled; lcdc_write(priv, _LDCNT2R, tmp); /* read data from external memory, avoid using the BEU for now */ lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) & ~DISPLAY_BEU); /* stop the lcdc first */ sh_mobile_lcdc_start_stop(priv, 0); /* configure clocks */ tmp = priv->lddckr; for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!priv->ch[k].enabled) continue; m = ch->cfg.clock_divider; if (!m) continue; if (m == 1) m = 1 << 6; tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0); lcdc_write_chan(ch, LDDCKPAT1R, 0x00000000); lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1); } lcdc_write(priv, _LDDCKR, tmp); /* start dotclock again */ lcdc_write(priv, _LDDCKSTPR, 0); lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0); /* interrupts are disabled to begin with */ lcdc_write(priv, _LDINTR, 0); for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; lcd_cfg = &ch->cfg.lcd_cfg; if (!ch->enabled) continue; tmp = ch->ldmt1r_value; tmp |= (lcd_cfg->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1 << 28; tmp |= (lcd_cfg->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1 << 27; tmp |= (ch->cfg.flags & LCDC_FLAGS_DWPOL) ? 1 << 26 : 0; tmp |= (ch->cfg.flags & LCDC_FLAGS_DIPOL) ? 1 << 25 : 0; tmp |= (ch->cfg.flags & LCDC_FLAGS_DAPOL) ? 1 << 24 : 0; tmp |= (ch->cfg.flags & LCDC_FLAGS_HSCNT) ? 1 << 17 : 0; tmp |= (ch->cfg.flags & LCDC_FLAGS_DWCNT) ? 1 << 16 : 0; lcdc_write_chan(ch, LDMT1R, tmp); /* setup SYS bus */ lcdc_write_chan(ch, LDMT2R, ch->cfg.sys_bus_cfg.ldmt2r); lcdc_write_chan(ch, LDMT3R, ch->cfg.sys_bus_cfg.ldmt3r); /* horizontal configuration */ tmp = lcd_cfg->xres + lcd_cfg->hsync_len; tmp += lcd_cfg->left_margin; tmp += lcd_cfg->right_margin; tmp /= 8; /* HTCN */ tmp |= (lcd_cfg->xres / 8) << 16; /* HDCN */ lcdc_write_chan(ch, LDHCNR, tmp); tmp = lcd_cfg->xres; tmp += lcd_cfg->right_margin; tmp /= 8; /* HSYNP */ tmp |= (lcd_cfg->hsync_len / 8) << 16; /* HSYNW */ lcdc_write_chan(ch, LDHSYNR, tmp); /* power supply */ lcdc_write_chan(ch, LDPMR, 0); /* vertical configuration */ tmp = lcd_cfg->yres + lcd_cfg->vsync_len; tmp += lcd_cfg->upper_margin; tmp += lcd_cfg->lower_margin; /* VTLN */ tmp |= lcd_cfg->yres << 16; /* VDLN */ lcdc_write_chan(ch, LDVLNR, tmp); tmp = lcd_cfg->yres; tmp += lcd_cfg->lower_margin; /* VSYNP */ tmp |= lcd_cfg->vsync_len << 16; /* VSYNW */ lcdc_write_chan(ch, LDVSYNR, tmp); board_cfg = &ch->cfg.board_cfg; if (board_cfg->setup_sys) ret = board_cfg->setup_sys(board_cfg->board_data, ch, &sh_mobile_lcdc_sys_bus_ops); if (ret) return ret; } /* word and long word swap */ lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 6); for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!priv->ch[k].enabled) continue; /* set bpp format in PKF[4:0] */ tmp = lcdc_read_chan(ch, LDDFR); tmp &= ~(0x0001001f); tmp |= (ch->info->var.bits_per_pixel == 16) ? 3 : 0; lcdc_write_chan(ch, LDDFR, tmp); /* point out our frame buffer */ lcdc_write_chan(ch, LDSA1R, ch->info->fix.smem_start); /* set line size */ lcdc_write_chan(ch, LDMLSR, ch->info->fix.line_length); /* setup deferred io if SYS bus */ tmp = ch->cfg.sys_bus_cfg.deferred_io_msec; if (ch->ldmt1r_value & (1 << 12) && tmp) { ch->defio.deferred_io = sh_mobile_lcdc_deferred_io; ch->defio.delay = msecs_to_jiffies(tmp); ch->info->fbdefio = &ch->defio; fb_deferred_io_init(ch->info); /* one-shot mode */ lcdc_write_chan(ch, LDSM1R, 1); /* enable "Frame End Interrupt Enable" bit */ lcdc_write(priv, _LDINTR, LDINTR_FE); } else { /* continuous read mode */ lcdc_write_chan(ch, LDSM1R, 0); } } /* display output */ lcdc_write(priv, _LDCNT1R, LCDC_ENABLE); /* start the lcdc */ sh_mobile_lcdc_start_stop(priv, 1); priv->started = 1; /* tell the board code to enable the panel */ for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!ch->enabled) continue; board_cfg = &ch->cfg.board_cfg; if (board_cfg->display_on) board_cfg->display_on(board_cfg->board_data); } return 0; }