Пример #1
0
static int ldb_resume(struct platform_device *pdev)
{
	switch (ldb.chan_mode_opt) {
	case LDB_SIN_DI0:
	case LDB_DUL_DI0:
	case LDB_SPL_DI0:
		if (ldb.blank[0] == FB_BLANK_UNBLANK)
			ldb_enable(0);
		break;
	case LDB_SIN_DI1:
	case LDB_DUL_DI1:
	case LDB_SPL_DI1:
		if (ldb.blank[1] == FB_BLANK_UNBLANK)
			ldb_enable(1);
		break;
	case LDB_SEP:
		if (ldb.blank[0] == FB_BLANK_UNBLANK)
			ldb_enable(0);
		if (ldb.blank[1] == FB_BLANK_UNBLANK)
			ldb_enable(1);
		break;
	default:
		break;
	}
	return 0;
}
Пример #2
0
int ldb_fb_event(struct notifier_block *nb, unsigned long val, void *v)
{
	struct fb_event *event = v;
	struct fb_info *fbi = event->info;
	mm_segment_t old_fs;
	int ipu_di = 0;

	switch (val) {
	case FB_EVENT_BLANK:
		if (ldb.fbi[0] != fbi && ldb.fbi[1] != fbi)
			return 0;

		if (fbi->fbops->fb_ioctl) {
			old_fs = get_fs();
			set_fs(KERNEL_DS);
			fbi->fbops->fb_ioctl(fbi,
					MXCFB_GET_FB_IPU_DI,
					(unsigned long)&ipu_di);
			set_fs(old_fs);
		} else
			return 0;

		if (*((int *)event->data) == FB_BLANK_UNBLANK)
			ldb_enable(ipu_di);
		else
			ldb_disable(ipu_di);
		break;
	default:
		break;
	}
	return 0;
}
Пример #3
0
static int ldb_resume(struct platform_device *pdev)
{
	switch (ldb.chan_mode_opt) {
	case LDB_SIN_DI0:
	case LDB_DUL_DI0:
	case LDB_SPL_DI0:
		ldb_enable(0);
		break;
	case LDB_SIN_DI1:
	case LDB_DUL_DI1:
	case LDB_SPL_DI1:
		ldb_enable(1);
		break;
	case LDB_SEP:
		ldb_enable(0);
		ldb_enable(1);
		break;
	default:
		break;
	}
	return 0;
}
Пример #4
0
static int mxc_ldb_ioctl(struct inode *inode, struct file *file,
		unsigned int cmd, unsigned long arg)
{
	int ret = 0;
	uint32_t reg;

	switch (cmd) {
	case LDB_BGREF_RMODE:
		{
		ldb_bgref_parm parm;

		if (copy_from_user(&parm, (ldb_bgref_parm *) arg,
				   sizeof(ldb_bgref_parm)))
			return -EFAULT;

		spin_lock(&ldb_lock);
		reg = __raw_readl(ldb.control_reg);
		if (parm.bgref_mode == LDB_EXT_REF)
			__raw_writel((reg & ~LDB_BGREF_RMODE_MASK) |
				      LDB_BGREF_RMODE_EXT, ldb.control_reg);
		else if (parm.bgref_mode == LDB_INT_REF)
			__raw_writel((reg & ~LDB_BGREF_RMODE_MASK) |
				      LDB_BGREF_RMODE_INT, ldb.control_reg);
		spin_unlock(&ldb_lock);
		break;
		}
	case LDB_VSYNC_POL:
		{
		ldb_vsync_parm parm;

		if (copy_from_user(&parm, (ldb_vsync_parm *) arg,
				   sizeof(ldb_vsync_parm)))
			return -EFAULT;

		spin_lock(&ldb_lock);
		reg = __raw_readl(ldb.control_reg);
		if (parm.vsync_mode == LDB_VS_ACT_H) {
			if (parm.di == 0)
				__raw_writel((reg &
					~LDB_DI0_VS_POL_MASK) |
					LDB_DI0_VS_POL_ACT_HIGH,
					ldb.control_reg);
			else
				__raw_writel((reg &
					~LDB_DI1_VS_POL_MASK) |
					LDB_DI1_VS_POL_ACT_HIGH,
					ldb.control_reg);
		} else if (parm.vsync_mode == LDB_VS_ACT_L) {
			if (parm.di == 0)
				__raw_writel((reg &
					~LDB_DI0_VS_POL_MASK) |
					LDB_DI0_VS_POL_ACT_LOW,
					ldb.control_reg);
			else
				__raw_writel((reg &
					~LDB_DI1_VS_POL_MASK) |
					LDB_DI1_VS_POL_ACT_LOW,
					ldb.control_reg);

		}
		spin_unlock(&ldb_lock);
		break;
		}
	case LDB_BIT_MAP:
		{
		ldb_bitmap_parm parm;

		if (copy_from_user(&parm, (ldb_bitmap_parm *) arg,
				   sizeof(ldb_bitmap_parm)))
			return -EFAULT;

		spin_lock(&ldb_lock);
		reg = __raw_readl(ldb.control_reg);
		if (parm.bitmap_mode == LDB_BIT_MAP_SPWG) {
			if (parm.channel == 0)
				__raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
					      LDB_BIT_MAP_CH0_SPWG,
					      ldb.control_reg);
			else
				__raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
					      LDB_BIT_MAP_CH1_SPWG,
					      ldb.control_reg);
		} else if (parm.bitmap_mode == LDB_BIT_MAP_JEIDA) {
			if (parm.channel == 0)
				__raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
					      LDB_BIT_MAP_CH0_JEIDA,
					      ldb.control_reg);
			else
				__raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
					      LDB_BIT_MAP_CH1_JEIDA,
					      ldb.control_reg);
		}
		spin_unlock(&ldb_lock);
		break;
		}
	case LDB_DATA_WIDTH:
		{
		ldb_data_width_parm parm;

		if (copy_from_user(&parm, (ldb_data_width_parm *) arg,
				   sizeof(ldb_data_width_parm)))
			return -EFAULT;

		spin_lock(&ldb_lock);
		reg = __raw_readl(ldb.control_reg);
		if (parm.data_width == 24) {
			if (parm.channel == 0)
				__raw_writel((reg & ~LDB_DATA_WIDTH_CH0_MASK) |
					      LDB_DATA_WIDTH_CH0_24,
					      ldb.control_reg);
			else
				__raw_writel((reg & ~LDB_DATA_WIDTH_CH0_MASK) |
					      LDB_DATA_WIDTH_CH1_24,
					      ldb.control_reg);
		} else if (parm.data_width == 18) {
			if (parm.channel == 0)
				__raw_writel((reg & ~LDB_DATA_WIDTH_CH0_MASK) |
					      LDB_DATA_WIDTH_CH0_18,
					      ldb.control_reg);
			else
				__raw_writel((reg & ~LDB_DATA_WIDTH_CH0_MASK) |
					      LDB_DATA_WIDTH_CH1_18,
					      ldb.control_reg);
		}
		spin_unlock(&ldb_lock);
		break;
		}
	case LDB_CHAN_MODE:
		{
		ldb_chan_mode_parm parm;
		struct clk *pll4_clk;
		unsigned long pll4_rate = 0;

		if (copy_from_user(&parm, (ldb_chan_mode_parm *) arg,
				   sizeof(ldb_chan_mode_parm)))
			return -EFAULT;

		spin_lock(&ldb_lock);

		/* TODO:Set the correct pll4 rate for all situations */
		pll4_clk = clk_get(NULL, "pll4");
		pll4_rate = clk_get_rate(pll4_clk);
		pll4_rate = 455000000;
		clk_set_rate(pll4_clk, pll4_rate);
		clk_put(pll4_clk);

		reg = __raw_readl(ldb.control_reg);
		switch (parm.channel_mode) {
		case LDB_CHAN_MODE_SIN:
			if (parm.di == 0) {
				ldb.chan_mode_opt = LDB_SIN_DI0;

				ldb.ldb_di_clk[0] = clk_get(NULL,
							    "ldb_di0_clk");
				clk_set_rate(ldb.ldb_di_clk[0], pll4_rate/7);
				clk_put(ldb.ldb_di_clk[0]);

				__raw_writel((reg & ~LDB_CH0_MODE_MASK) |
					      LDB_CH0_MODE_EN_TO_DI0,
					      ldb.control_reg);
			} else {
				ldb.chan_mode_opt = LDB_SIN_DI1;

				ldb.ldb_di_clk[1] = clk_get(NULL,
							    "ldb_di1_clk");
				clk_set_rate(ldb.ldb_di_clk[1], pll4_rate/7);
				clk_put(ldb.ldb_di_clk[1]);

				__raw_writel((reg & ~LDB_CH1_MODE_MASK) |
					      LDB_CH1_MODE_EN_TO_DI1,
					      ldb.control_reg);
			}
			break;
		case LDB_CHAN_MODE_SEP:
			ldb.chan_mode_opt = LDB_SEP;

			ldb.ldb_di_clk[0] = clk_get(NULL, "ldb_di0_clk");
			clk_set_rate(ldb.ldb_di_clk[0], pll4_rate/7);
			clk_put(ldb.ldb_di_clk[0]);
			ldb.ldb_di_clk[1] = clk_get(NULL, "ldb_di1_clk");
			clk_set_rate(ldb.ldb_di_clk[1], pll4_rate/7);
			clk_put(ldb.ldb_di_clk[1]);

			__raw_writel((reg & ~(LDB_CH0_MODE_MASK |
					      LDB_CH1_MODE_MASK)) |
				      LDB_CH0_MODE_EN_TO_DI0 |
				      LDB_CH1_MODE_EN_TO_DI1,
				      ldb.control_reg);
			break;
		case LDB_CHAN_MODE_DUL:
		case LDB_CHAN_MODE_SPL:
			ldb.ldb_di_clk[0] = clk_get(NULL, "ldb_di0_clk");
			ldb.ldb_di_clk[1] = clk_get(NULL, "ldb_di1_clk");
			if (parm.di == 0) {
				if (parm.channel_mode == LDB_CHAN_MODE_DUL) {
					ldb.chan_mode_opt = LDB_DUL_DI0;
					clk_set_rate(ldb.ldb_di_clk[0],
						     pll4_rate/7);
				} else {
					ldb.chan_mode_opt = LDB_SPL_DI0;
					clk_set_rate(ldb.ldb_di_clk[0],
						     2*pll4_rate/7);
					clk_set_rate(ldb.ldb_di_clk[1],
						     2*pll4_rate/7);
					reg = __raw_readl(ldb.control_reg);
					__raw_writel(reg | LDB_SPLIT_MODE_EN,
						      ldb.control_reg);
				}

				reg = __raw_readl(ldb.control_reg);
				__raw_writel((reg & ~(LDB_CH0_MODE_MASK |
						      LDB_CH1_MODE_MASK)) |
					      LDB_CH0_MODE_EN_TO_DI0 |
					      LDB_CH1_MODE_EN_TO_DI0,
					      ldb.control_reg);
			} else {
				if (parm.channel_mode == LDB_CHAN_MODE_DUL) {
					ldb.chan_mode_opt = LDB_DUL_DI1;
					clk_set_rate(ldb.ldb_di_clk[1],
						     pll4_rate/7);
				} else {
					ldb.chan_mode_opt = LDB_SPL_DI1;
					clk_set_rate(ldb.ldb_di_clk[0],
						     2*pll4_rate/7);
					clk_set_rate(ldb.ldb_di_clk[1],
						     2*pll4_rate/7);
					reg = __raw_readl(ldb.control_reg);
					__raw_writel(reg | LDB_SPLIT_MODE_EN,
						      ldb.control_reg);
				}

				reg = __raw_readl(ldb.control_reg);
				__raw_writel((reg & ~(LDB_CH0_MODE_MASK |
						      LDB_CH1_MODE_MASK)) |
					      LDB_CH0_MODE_EN_TO_DI1 |
					      LDB_CH1_MODE_EN_TO_DI1,
					      ldb.control_reg);
			}
			clk_put(ldb.ldb_di_clk[0]);
			clk_put(ldb.ldb_di_clk[1]);
			break;
		default:
			ret = -EINVAL;
			break;
		}
		spin_unlock(&ldb_lock);
		break;
		}
	case LDB_ENABLE:
		{
		int ipu_di;

		if (copy_from_user(&ipu_di, (int *) arg, sizeof(int)))
			return -EFAULT;

		ldb_enable(ipu_di);
		break;
		}
	case LDB_DISABLE:
		{
		int ipu_di;

		if (copy_from_user(&ipu_di, (int *) arg, sizeof(int)))
			return -EFAULT;

		ldb_disable(ipu_di);
		break;
		}
	default:
		ret = -EINVAL;
		break;
	}

	return ret;
}
Пример #5
0
int ldb_fb_event(struct notifier_block *nb, unsigned long val, void *v)
{
	struct fb_event *event = v;
	struct fb_info *fbi = event->info;
	mm_segment_t old_fs;
	int ipu_di = 0;

	/* Get rid of impact from FG fb */
	if (strcmp(fbi->fix.id, "DISP3 FG") == 0)
		return 0;

	if (fbi->fbops->fb_ioctl) {
		old_fs = get_fs();
		set_fs(KERNEL_DS);
		fbi->fbops->fb_ioctl(fbi,
				MXCFB_GET_FB_IPU_DI,
				(unsigned long)&ipu_di);
		set_fs(old_fs);
	} else
		return 0;

	if ((ipu_di == 0 && !g_di0_used) ||
	    (ipu_di == 1 && !g_di1_used) ||
	    ipu_di > 1)
		return 0;

	fbi->mode = (struct fb_videomode *)fb_match_mode(&fbi->var,
			&fbi->modelist);

	if (!fbi->mode) {
		dev_warn(g_ldb_dev, "can not find mode for xres=%d, yres=%d\n",
				fbi->var.xres, fbi->var.yres);
		return 0;
	}

	switch (val) {
	case FB_EVENT_MODE_CHANGE: {
		int ipu_di_pix_fmt;
		uint32_t reg;

		if ((ldb.fbi[0] != NULL && ldb.chan_mode_opt != LDB_SEP) ||
		    ldb.fbi[1] != NULL)
			return 0;

		/*
		 * We cannot support two LVDS panels with different
		 * pixel clock rates except that one's pixel clock rate
		 * is two times of the others'.
		 */
		if (ldb.fbi[0]) {
			if (ldb.fbi[0]->var.pixclock == fbi->var.pixclock ||
			    ldb.fbi[0]->var.pixclock ==
						2 * fbi->var.pixclock ||
			    fbi->var.pixclock == 2 * ldb.fbi[0]->var.pixclock)
				ldb.fbi[1] = fbi;
			else
				return 0;
		} else
			ldb.fbi[0] = fbi;

		old_fs = get_fs();
		set_fs(KERNEL_DS);
		fbi->fbops->fb_ioctl(fbi, MXCFB_GET_DIFMT,
				(unsigned long)&ipu_di_pix_fmt);
		set_fs(old_fs);

		if (!valid_mode(ipu_di_pix_fmt)) {
			dev_err(g_ldb_dev, "Unsupport pixel format "
					   "for ldb input\n");
			return 0;
		}

		reg = __raw_readl(ldb.control_reg);
		if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT) {
			if (ipu_di == 0)
				__raw_writel((reg &
					~LDB_DI0_VS_POL_MASK) |
					LDB_DI0_VS_POL_ACT_HIGH,
					ldb.control_reg);
			else
				__raw_writel((reg &
					~LDB_DI1_VS_POL_MASK) |
					LDB_DI1_VS_POL_ACT_HIGH,
					ldb.control_reg);
		} else {
			if (ipu_di == 0)
				__raw_writel((reg &
					~LDB_DI0_VS_POL_MASK) |
					LDB_DI0_VS_POL_ACT_LOW,
					ldb.control_reg);
			else
				__raw_writel((reg &
					~LDB_DI1_VS_POL_MASK) |
					LDB_DI1_VS_POL_ACT_LOW,
					ldb.control_reg);
		}

		switch (ldb.chan_mode_opt) {
		case LDB_SIN_DI0:
			reg = __raw_readl(ldb.control_reg);
			if (bits_per_pixel(ipu_di_pix_fmt) == 24)
				__raw_writel((reg & ~LDB_DATA_WIDTH_CH0_MASK) |
					      LDB_DATA_WIDTH_CH0_24,
					      ldb.control_reg);
			else if (bits_per_pixel(ipu_di_pix_fmt) == 18)
				__raw_writel((reg & ~LDB_DATA_WIDTH_CH0_MASK) |
					      LDB_DATA_WIDTH_CH0_18,
					      ldb.control_reg);

			reg = __raw_readl(ldb.control_reg);
			if (ldb.chan_bit_map[0] == LDB_BIT_MAP_SPWG)
				__raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
					      LDB_BIT_MAP_CH0_SPWG,
					      ldb.control_reg);
			else
				__raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
					      LDB_BIT_MAP_CH0_JEIDA,
					      ldb.control_reg);

			reg = __raw_readl(ldb.control_reg);
			__raw_writel((reg & ~LDB_CH0_MODE_MASK) |
				      LDB_CH0_MODE_EN_TO_DI0, ldb.control_reg);
			if (ldb.blank[0] == FB_BLANK_UNBLANK)
				ldb.ch_working[0] = true;
			break;
		case LDB_SIN_DI1:
			reg = __raw_readl(ldb.control_reg);
			if (bits_per_pixel(ipu_di_pix_fmt) == 24)
				__raw_writel((reg & ~LDB_DATA_WIDTH_CH1_MASK) |
					      LDB_DATA_WIDTH_CH1_24,
					      ldb.control_reg);
			else if (bits_per_pixel(ipu_di_pix_fmt) == 18)
				__raw_writel((reg & ~LDB_DATA_WIDTH_CH1_MASK) |
					      LDB_DATA_WIDTH_CH1_18,
					      ldb.control_reg);

			reg = __raw_readl(ldb.control_reg);
			if (ldb.chan_bit_map[1] == LDB_BIT_MAP_SPWG)
				__raw_writel((reg & ~LDB_BIT_MAP_CH1_MASK) |
					      LDB_BIT_MAP_CH1_SPWG,
					      ldb.control_reg);
			else
				__raw_writel((reg & ~LDB_BIT_MAP_CH1_MASK) |
					      LDB_BIT_MAP_CH1_JEIDA,
					      ldb.control_reg);

			reg = __raw_readl(ldb.control_reg);
			__raw_writel((reg & ~LDB_CH1_MODE_MASK) |
				      LDB_CH1_MODE_EN_TO_DI1, ldb.control_reg);
			if (ldb.blank[1] == FB_BLANK_UNBLANK)
				ldb.ch_working[1] = true;
			break;
		case LDB_SEP:
			reg = __raw_readl(ldb.control_reg);
			if (ipu_di == 0) {
				if (bits_per_pixel(ipu_di_pix_fmt) == 24)
					__raw_writel((reg & ~LDB_DATA_WIDTH_CH0_MASK) |
						      LDB_DATA_WIDTH_CH0_24,
						      ldb.control_reg);
				else if (bits_per_pixel(ipu_di_pix_fmt) == 18)
					__raw_writel((reg & ~LDB_DATA_WIDTH_CH0_MASK) |
						      LDB_DATA_WIDTH_CH0_18,
						      ldb.control_reg);
			} else {
				if (bits_per_pixel(ipu_di_pix_fmt) == 24)
					__raw_writel((reg & ~LDB_DATA_WIDTH_CH1_MASK) |
						      LDB_DATA_WIDTH_CH1_24,
						      ldb.control_reg);
				else if (bits_per_pixel(ipu_di_pix_fmt) == 18)
					__raw_writel((reg & ~LDB_DATA_WIDTH_CH1_MASK) |
						      LDB_DATA_WIDTH_CH1_18,
						      ldb.control_reg);
			}

			reg = __raw_readl(ldb.control_reg);
			if (ldb.chan_bit_map[0] == LDB_BIT_MAP_SPWG)
				__raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
					      LDB_BIT_MAP_CH0_SPWG,
					      ldb.control_reg);
			else
				__raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
					      LDB_BIT_MAP_CH0_JEIDA,
					      ldb.control_reg);
			reg = __raw_readl(ldb.control_reg);
			if (ldb.chan_bit_map[1] == LDB_BIT_MAP_SPWG)
				__raw_writel((reg & ~LDB_BIT_MAP_CH1_MASK) |
					      LDB_BIT_MAP_CH1_SPWG,
					      ldb.control_reg);
			else
				__raw_writel((reg & ~LDB_BIT_MAP_CH1_MASK) |
					      LDB_BIT_MAP_CH1_JEIDA,
					      ldb.control_reg);

			reg = __raw_readl(ldb.control_reg);
			__raw_writel((reg & ~(LDB_CH0_MODE_MASK |
					      LDB_CH1_MODE_MASK)) |
				      LDB_CH0_MODE_EN_TO_DI0 |
				      LDB_CH1_MODE_EN_TO_DI1, ldb.control_reg);
			if (ldb.blank[0] == FB_BLANK_UNBLANK)
				ldb.ch_working[0] = true;
			if (ldb.blank[1] == FB_BLANK_UNBLANK)
				ldb.ch_working[1] = true;
			break;
		case LDB_DUL_DI0:
		case LDB_SPL_DI0:
			reg = __raw_readl(ldb.control_reg);
			if (bits_per_pixel(ipu_di_pix_fmt) == 24)
				__raw_writel((reg & ~(LDB_DATA_WIDTH_CH0_MASK |
						      LDB_DATA_WIDTH_CH1_MASK)) |
					      LDB_DATA_WIDTH_CH0_24 |
					      LDB_DATA_WIDTH_CH1_24,
					      ldb.control_reg);
			else if (bits_per_pixel(ipu_di_pix_fmt) == 18)
				__raw_writel((reg & ~(LDB_DATA_WIDTH_CH0_MASK |
						      LDB_DATA_WIDTH_CH1_MASK)) |
					      LDB_DATA_WIDTH_CH0_18 |
					      LDB_DATA_WIDTH_CH1_18,
					      ldb.control_reg);

			reg = __raw_readl(ldb.control_reg);
			if (ldb.chan_bit_map[0] == LDB_BIT_MAP_SPWG)
				__raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
					      LDB_BIT_MAP_CH0_SPWG,
					      ldb.control_reg);
			else
				__raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
					      LDB_BIT_MAP_CH0_JEIDA,
					      ldb.control_reg);
			reg = __raw_readl(ldb.control_reg);
			if (ldb.chan_bit_map[1] == LDB_BIT_MAP_SPWG)
				__raw_writel((reg & ~LDB_BIT_MAP_CH1_MASK) |
					      LDB_BIT_MAP_CH1_SPWG,
					      ldb.control_reg);
			else
				__raw_writel((reg & ~LDB_BIT_MAP_CH1_MASK) |
					      LDB_BIT_MAP_CH1_JEIDA,
					      ldb.control_reg);

			reg = __raw_readl(ldb.control_reg);
			if (ldb.chan_mode_opt == LDB_SPL_DI0)
				__raw_writel(reg | LDB_SPLIT_MODE_EN,
					      ldb.control_reg);

			reg = __raw_readl(ldb.control_reg);
			__raw_writel((reg & ~(LDB_CH0_MODE_MASK |
					      LDB_CH1_MODE_MASK)) |
				      LDB_CH0_MODE_EN_TO_DI0 |
				      LDB_CH1_MODE_EN_TO_DI0, ldb.control_reg);
			if (ldb.blank[0] == FB_BLANK_UNBLANK) {
				ldb.ch_working[0] = true;
				ldb.ch_working[1] = true;
			}
			break;
		case LDB_DUL_DI1:
		case LDB_SPL_DI1:
			reg = __raw_readl(ldb.control_reg);
			if (bits_per_pixel(ipu_di_pix_fmt) == 24)
				__raw_writel((reg & ~(LDB_DATA_WIDTH_CH0_MASK |
						      LDB_DATA_WIDTH_CH1_MASK)) |
					      LDB_DATA_WIDTH_CH0_24 |
					      LDB_DATA_WIDTH_CH1_24,
					      ldb.control_reg);
			else if (bits_per_pixel(ipu_di_pix_fmt) == 18)
				__raw_writel((reg & ~(LDB_DATA_WIDTH_CH0_MASK |
						      LDB_DATA_WIDTH_CH1_MASK)) |
					      LDB_DATA_WIDTH_CH0_18 |
					      LDB_DATA_WIDTH_CH1_18,
					      ldb.control_reg);

			reg = __raw_readl(ldb.control_reg);
			if (ldb.chan_bit_map[0] == LDB_BIT_MAP_SPWG)
				__raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
					      LDB_BIT_MAP_CH0_SPWG,
					      ldb.control_reg);
			else
				__raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
					      LDB_BIT_MAP_CH0_JEIDA,
					      ldb.control_reg);
			reg = __raw_readl(ldb.control_reg);
			if (ldb.chan_bit_map[1] == LDB_BIT_MAP_SPWG)
				__raw_writel((reg & ~LDB_BIT_MAP_CH1_MASK) |
					      LDB_BIT_MAP_CH1_SPWG,
					      ldb.control_reg);
			else
				__raw_writel((reg & ~LDB_BIT_MAP_CH1_MASK) |
					      LDB_BIT_MAP_CH1_JEIDA,
					      ldb.control_reg);

			reg = __raw_readl(ldb.control_reg);
			if (ldb.chan_mode_opt == LDB_SPL_DI1)
				__raw_writel(reg | LDB_SPLIT_MODE_EN,
					      ldb.control_reg);

			reg = __raw_readl(ldb.control_reg);
			__raw_writel((reg & ~(LDB_CH0_MODE_MASK |
					      LDB_CH1_MODE_MASK)) |
				      LDB_CH0_MODE_EN_TO_DI1 |
				      LDB_CH1_MODE_EN_TO_DI1, ldb.control_reg);
			if (ldb.blank[1] == FB_BLANK_UNBLANK) {
				ldb.ch_working[0] = true;
				ldb.ch_working[1] = true;
			}
			break;
		default:
			break;
		}
		break;
	}
	case FB_EVENT_BLANK: {
		if (ldb.fbi[0] != fbi && ldb.fbi[1] != fbi)
			return 0;

		if (*((int *)event->data) == ldb.blank[ipu_di])
			return 0;

		if (*((int *)event->data) == FB_BLANK_UNBLANK)
			ldb_enable(ipu_di);
		else
			ldb_disable(ipu_di);

		ldb.blank[ipu_di] = *((int *)event->data);
		break;
	}
	default:
		break;
	}
	return 0;
}
Пример #6
0
static int ldb_fb_pre_setup(struct fb_info *fbi)
{
	int ipu_di = 0;
	struct clk *di_clk, *ldb_clk_parent;
	unsigned long ldb_clk_prate = 455000000;

	fbi->mode = (struct fb_videomode *)fb_match_mode(&fbi->var,
			&fbi->modelist);
	if (!fbi->mode) {
		dev_warn(g_ldb_dev, "can not find mode for xres=%d, yres=%d\n",
				fbi->var.xres, fbi->var.yres);
		return 0;
	}

	if (fbi->fbops->fb_ioctl) {
		mm_segment_t old_fs;

		old_fs = get_fs();
		set_fs(KERNEL_DS);
		fbi->fbops->fb_ioctl(fbi,
				MXCFB_GET_FB_IPU_DI,
				(unsigned long)&ipu_di);
		fbi->fbops->fb_ioctl(fbi,
				MXCFB_GET_FB_BLANK,
				(unsigned int)(&ldb.blank[ipu_di]));
		set_fs(old_fs);

		/*
		 * Default ldb mode:
		 * 1080p: DI0 split, SPWG or DI1 split, SPWG
		 * others: single, SPWG
		 */
		if (ldb.chan_mode_opt == LDB_NO_MODE) {
			if (fb_mode_is_equal(fbi->mode, &mxcfb_ldb_modedb[0])) {
				if (ipu_di == 0) {
					ldb.chan_mode_opt = LDB_SPL_DI0;
					dev_warn(g_ldb_dev,
						"default di0 split mode\n");
				} else {
					ldb.chan_mode_opt = LDB_SPL_DI1;
					dev_warn(g_ldb_dev,
						"default di1 split mode\n");
				}
				ldb.chan_bit_map[0] = LDB_BIT_MAP_SPWG;
				ldb.chan_bit_map[1] = LDB_BIT_MAP_SPWG;
			} else if (fb_mode_is_equal(fbi->mode, &mxcfb_ldb_modedb[1])) {
				if (ipu_di == 0) {
					ldb.chan_mode_opt = LDB_SIN_DI0;
					ldb.chan_bit_map[0] = LDB_BIT_MAP_SPWG;
					dev_warn(g_ldb_dev,
						 "default di0 single mode\n");
				} else {
					ldb.chan_mode_opt = LDB_SIN_DI1;
					ldb.chan_bit_map[1] = LDB_BIT_MAP_SPWG;
					dev_warn(g_ldb_dev,
						 "default di1 single mode\n");
				}
			}
		}

		/* TODO:Set the correct pll4 rate for all situations */
		if (ipu_di == 1) {
			ldb.ldb_di_clk[1] =
				clk_get(g_ldb_dev, "ldb_di1_clk");
			di_clk = clk_get(g_ldb_dev, "ipu_di1_clk");
			ldb_clk_parent =
				clk_get_parent(ldb.ldb_di_clk[1]);
			clk_set_rate(ldb_clk_parent, ldb_clk_prate);
			clk_set_parent(di_clk, ldb.ldb_di_clk[1]);
			clk_put(di_clk);
			clk_put(ldb.ldb_di_clk[1]);
		} else {
			ldb.ldb_di_clk[0] =
				clk_get(g_ldb_dev, "ldb_di0_clk");
			di_clk = clk_get(g_ldb_dev, "ipu_di0_clk");
			ldb_clk_parent =
				clk_get_parent(ldb.ldb_di_clk[0]);
			clk_set_rate(ldb_clk_parent, ldb_clk_prate);
			clk_set_parent(di_clk, ldb.ldb_di_clk[0]);
			clk_put(di_clk);
			clk_put(ldb.ldb_di_clk[0]);
		}

		switch (ldb.chan_mode_opt) {
		case LDB_SIN_DI0:
			ldb.ldb_di_clk[0] = clk_get(g_ldb_dev, "ldb_di0_clk");
			clk_set_rate(ldb.ldb_di_clk[0], ldb_clk_prate/7);
			if (ldb.blank[0] == FB_BLANK_UNBLANK &&
			    clk_get_usecount(ldb.ldb_di_clk[0]) == 0)
				clk_enable(ldb.ldb_di_clk[0]);
			clk_put(ldb.ldb_di_clk[0]);
			break;
		case LDB_SIN_DI1:
			ldb.ldb_di_clk[1] = clk_get(g_ldb_dev, "ldb_di1_clk");
			clk_set_rate(ldb.ldb_di_clk[1], ldb_clk_prate/7);
			if (ldb.blank[1] == FB_BLANK_UNBLANK &&
			    clk_get_usecount(ldb.ldb_di_clk[1]) == 0)
				clk_enable(ldb.ldb_di_clk[1]);
			clk_put(ldb.ldb_di_clk[1]);
			break;
		case LDB_SEP:
			if (ipu_di == 0) {
				ldb.ldb_di_clk[0] = clk_get(g_ldb_dev, "ldb_di0_clk");
				clk_set_rate(ldb.ldb_di_clk[0], ldb_clk_prate/7);
				if (ldb.blank[0] == FB_BLANK_UNBLANK &&
				    clk_get_usecount(ldb.ldb_di_clk[0]) == 0)
					clk_enable(ldb.ldb_di_clk[0]);
				clk_put(ldb.ldb_di_clk[0]);
			} else {
				ldb.ldb_di_clk[1] = clk_get(g_ldb_dev, "ldb_di1_clk");
				clk_set_rate(ldb.ldb_di_clk[1], ldb_clk_prate/7);
				if (ldb.blank[1] == FB_BLANK_UNBLANK &&
				    clk_get_usecount(ldb.ldb_di_clk[1]) == 0)
					clk_enable(ldb.ldb_di_clk[1]);
				clk_put(ldb.ldb_di_clk[1]);
			}
			break;
		case LDB_DUL_DI0:
		case LDB_SPL_DI0:
			ldb.ldb_di_clk[0] = clk_get(g_ldb_dev, "ldb_di0_clk");
			ldb.ldb_di_clk[1] = clk_get(g_ldb_dev, "ldb_di1_clk");
			if (ldb.chan_mode_opt == LDB_DUL_DI0) {
				clk_set_rate(ldb.ldb_di_clk[0], ldb_clk_prate/7);
			} else {
				clk_set_rate(ldb.ldb_di_clk[0], 2*ldb_clk_prate/7);
				clk_set_rate(ldb.ldb_di_clk[1], 2*ldb_clk_prate/7);
			}
			if (ldb.blank[0] == FB_BLANK_UNBLANK) {
				if (clk_get_usecount(ldb.ldb_di_clk[0]) == 0)
					clk_enable(ldb.ldb_di_clk[0]);
				if (clk_get_usecount(ldb.ldb_di_clk[1]) == 0)
					clk_enable(ldb.ldb_di_clk[1]);
			}
			clk_put(ldb.ldb_di_clk[0]);
			clk_put(ldb.ldb_di_clk[1]);
			break;
		case LDB_DUL_DI1:
		case LDB_SPL_DI1:
			ldb.ldb_di_clk[0] = clk_get(g_ldb_dev, "ldb_di0_clk");
			ldb.ldb_di_clk[1] = clk_get(g_ldb_dev, "ldb_di1_clk");
			if (ldb.chan_mode_opt == LDB_DUL_DI1) {
				clk_set_rate(ldb.ldb_di_clk[1], ldb_clk_prate/7);
			} else {
				clk_set_rate(ldb.ldb_di_clk[0], 2*ldb_clk_prate/7);
				clk_set_rate(ldb.ldb_di_clk[1], 2*ldb_clk_prate/7);
			}
			if (ldb.blank[1] == FB_BLANK_UNBLANK) {
				if (clk_get_usecount(ldb.ldb_di_clk[0]) == 0)
					clk_enable(ldb.ldb_di_clk[0]);
				if (clk_get_usecount(ldb.ldb_di_clk[1]) == 0)
					clk_enable(ldb.ldb_di_clk[1]);
			}
			clk_put(ldb.ldb_di_clk[0]);
			clk_put(ldb.ldb_di_clk[1]);
			break;
		default:
			break;
		}

		if (ldb.blank[ipu_di] == FB_BLANK_UNBLANK)
			ldb_enable(ipu_di);
	}

	return 0;
}