Exemple #1
0
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
Exemple #3
0
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;
}
Exemple #4
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;
}
Exemple #5
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;
}
Exemple #6
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);
}
Exemple #10
0
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;
}