static int ldb_suspend(struct platform_device *pdev, pm_message_t state) { 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_disable(0); break; case LDB_SIN_DI1: case LDB_DUL_DI1: case LDB_SPL_DI1: if (ldb.blank[1] != FB_BLANK_UNBLANK) ldb_disable(1); break; case LDB_SEP: if (ldb.blank[0] != FB_BLANK_UNBLANK) ldb_disable(0); if (ldb.blank[1] != FB_BLANK_UNBLANK) ldb_disable(1); break; default: break; } return 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; }
static int ldb_suspend(struct platform_device *pdev, pm_message_t state) { switch (ldb.chan_mode_opt) { case LDB_SIN_DI0: case LDB_DUL_DI0: case LDB_SPL_DI0: ldb_disable(0); break; case LDB_SIN_DI1: case LDB_DUL_DI1: case LDB_SPL_DI1: ldb_disable(1); break; case LDB_SEP: ldb_disable(0); ldb_disable(1); break; default: break; } return 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; }
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; }