📄 dispc.c
字号:
int orig_width, int orig_height, int out_width, int out_height){ const u32 at_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES, DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES }; const u32 vs_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_SIZE, DISPC_VID2_BASE + DISPC_VID_SIZE }; const u32 fir_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_FIR, DISPC_VID2_BASE + DISPC_VID_FIR }; u32 l; int fir_hinc; int fir_vinc; if ((unsigned)plane > OMAPFB_PLANE_NUM) return -ENODEV; if (plane == OMAPFB_PLANE_GFX && (out_width != orig_width || out_height != orig_height)) return -EINVAL; enable_lcd_clocks(1); if (orig_width < out_width) { /* * Upsampling. * Currently you can only scale both dimensions in one way. */ if (orig_height > out_height || orig_width * 8 < out_width || orig_height * 8 < out_height) { enable_lcd_clocks(0); return -EINVAL; } set_upsampling_coef_table(plane); } else if (orig_width > out_width) { /* Downsampling not yet supported */ enable_lcd_clocks(0); return -EINVAL; } if (!orig_width || orig_width == out_width) fir_hinc = 0; else fir_hinc = 1024 * orig_width / out_width; if (!orig_height || orig_height == out_height) fir_vinc = 0; else fir_vinc = 1024 * orig_height / out_height; dispc.fir_hinc[plane] = fir_hinc; dispc.fir_vinc[plane] = fir_vinc; MOD_REG_FLD(fir_reg[plane], FLD_MASK(16, 12) | FLD_MASK(0, 12), ((fir_vinc & 4095) << 16) | (fir_hinc & 4095)); dev_dbg(dispc.fbdev->dev, "out_width %d out_height %d orig_width %d " "orig_height %d fir_hinc %d fir_vinc %d\n", out_width, out_height, orig_width, orig_height, fir_hinc, fir_vinc); MOD_REG_FLD(vs_reg[plane], FLD_MASK(16, 11) | FLD_MASK(0, 11), ((out_height - 1) << 16) | (out_width - 1)); l = dispc_read_reg(at_reg[plane]); l &= ~(0x03 << 5); l |= fir_hinc ? (1 << 5) : 0; l |= fir_vinc ? (1 << 6) : 0; dispc_write_reg(at_reg[plane], l); enable_lcd_clocks(0); return 0;}static int omap_dispc_enable_plane(int plane, int enable){ const u32 at_reg[] = { DISPC_GFX_ATTRIBUTES, DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES, DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES }; if ((unsigned int)plane > dispc.mem_desc.region_cnt) return -EINVAL; enable_lcd_clocks(1); MOD_REG_FLD(at_reg[plane], 1, enable ? 1 : 0); enable_lcd_clocks(0); return 0;}static int omap_dispc_set_color_key(struct omapfb_color_key *ck){ u32 df_reg, tr_reg; int shift, val; switch (ck->channel_out) { case OMAPFB_CHANNEL_OUT_LCD: df_reg = DISPC_DEFAULT_COLOR0; tr_reg = DISPC_TRANS_COLOR0; shift = 10; break; case OMAPFB_CHANNEL_OUT_DIGIT: df_reg = DISPC_DEFAULT_COLOR1; tr_reg = DISPC_TRANS_COLOR1; shift = 12; break; default: return -EINVAL; } switch (ck->key_type) { case OMAPFB_COLOR_KEY_DISABLED: val = 0; break; case OMAPFB_COLOR_KEY_GFX_DST: val = 1; break; case OMAPFB_COLOR_KEY_VID_SRC: val = 3; break; default: return -EINVAL; } enable_lcd_clocks(1); MOD_REG_FLD(DISPC_CONFIG, FLD_MASK(shift, 2), val << shift); if (val != 0) dispc_write_reg(tr_reg, ck->trans_key); dispc_write_reg(df_reg, ck->background); enable_lcd_clocks(0); dispc.color_key = *ck; return 0;}static int omap_dispc_get_color_key(struct omapfb_color_key *ck){ *ck = dispc.color_key; return 0;}static void load_palette(void){}static int omap_dispc_set_update_mode(enum omapfb_update_mode mode){ int r = 0; if (mode != dispc.update_mode) { switch (mode) { case OMAPFB_AUTO_UPDATE: case OMAPFB_MANUAL_UPDATE: enable_lcd_clocks(1); omap_dispc_enable_lcd_out(1); dispc.update_mode = mode; break; case OMAPFB_UPDATE_DISABLED: init_completion(&dispc.frame_done); omap_dispc_enable_lcd_out(0); if (!wait_for_completion_timeout(&dispc.frame_done, msecs_to_jiffies(500))) { dev_err(dispc.fbdev->dev, "timeout waiting for FRAME DONE\n"); } dispc.update_mode = mode; enable_lcd_clocks(0); break; default: r = -EINVAL; } } return r;}static void omap_dispc_get_caps(int plane, struct omapfb_caps *caps){ caps->ctrl |= OMAPFB_CAPS_PLANE_RELOCATE_MEM; if (plane > 0) caps->ctrl |= OMAPFB_CAPS_PLANE_SCALE; caps->plane_color |= (1 << OMAPFB_COLOR_RGB565) | (1 << OMAPFB_COLOR_YUV422) | (1 << OMAPFB_COLOR_YUY422); if (plane == 0) caps->plane_color |= (1 << OMAPFB_COLOR_CLUT_8BPP) | (1 << OMAPFB_COLOR_CLUT_4BPP) | (1 << OMAPFB_COLOR_CLUT_2BPP) | (1 << OMAPFB_COLOR_CLUT_1BPP) | (1 << OMAPFB_COLOR_RGB444);}static enum omapfb_update_mode omap_dispc_get_update_mode(void){ return dispc.update_mode;}static void setup_color_conv_coef(void){ u32 mask = FLD_MASK(16, 11) | FLD_MASK(0, 11); int cf1_reg = DISPC_VID1_BASE + DISPC_VID_CONV_COEF0; int cf2_reg = DISPC_VID2_BASE + DISPC_VID_CONV_COEF0; int at1_reg = DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES; int at2_reg = DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES; const struct color_conv_coef { int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb; int full_range; } ctbl_bt601_5 = { 298, 409, 0, 298, -208, -100, 298, 0, 517, 0, }; const struct color_conv_coef *ct;#define CVAL(x, y) (((x & 2047) << 16) | (y & 2047)) ct = &ctbl_bt601_5; MOD_REG_FLD(cf1_reg, mask, CVAL(ct->rcr, ct->ry)); MOD_REG_FLD(cf1_reg + 4, mask, CVAL(ct->gy, ct->rcb)); MOD_REG_FLD(cf1_reg + 8, mask, CVAL(ct->gcb, ct->gcr)); MOD_REG_FLD(cf1_reg + 12, mask, CVAL(ct->bcr, ct->by)); MOD_REG_FLD(cf1_reg + 16, mask, CVAL(0, ct->bcb)); MOD_REG_FLD(cf2_reg, mask, CVAL(ct->rcr, ct->ry)); MOD_REG_FLD(cf2_reg + 4, mask, CVAL(ct->gy, ct->rcb)); MOD_REG_FLD(cf2_reg + 8, mask, CVAL(ct->gcb, ct->gcr)); MOD_REG_FLD(cf2_reg + 12, mask, CVAL(ct->bcr, ct->by)); MOD_REG_FLD(cf2_reg + 16, mask, CVAL(0, ct->bcb));#undef CVAL MOD_REG_FLD(at1_reg, (1 << 11), ct->full_range); MOD_REG_FLD(at2_reg, (1 << 11), ct->full_range);}static void calc_ck_div(int is_tft, int pck, int *lck_div, int *pck_div){ unsigned long fck, lck; *lck_div = 1; pck = max(1, pck); fck = clk_get_rate(dispc.dss1_fck); lck = fck; *pck_div = (lck + pck - 1) / pck; if (is_tft) *pck_div = max(2, *pck_div); else *pck_div = max(3, *pck_div); if (*pck_div > 255) { *pck_div = 255; lck = pck * *pck_div; *lck_div = fck / lck; BUG_ON(*lck_div < 1); if (*lck_div > 255) { *lck_div = 255; dev_warn(dispc.fbdev->dev, "pixclock %d kHz too low.\n", pck / 1000); } }}static void set_lcd_tft_mode(int enable){ u32 mask; mask = 1 << 3; MOD_REG_FLD(DISPC_CONTROL, mask, enable ? mask : 0);}static void set_lcd_timings(void){ u32 l; int lck_div, pck_div; struct lcd_panel *panel = dispc.fbdev->panel; int is_tft = panel->config & OMAP_LCDC_PANEL_TFT; unsigned long fck; l = dispc_read_reg(DISPC_TIMING_H); l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8)); l |= ( max(1, (min(64, panel->hsw))) - 1 ) << 0; l |= ( max(1, (min(256, panel->hfp))) - 1 ) << 8; l |= ( max(1, (min(256, panel->hbp))) - 1 ) << 20; dispc_write_reg(DISPC_TIMING_H, l); l = dispc_read_reg(DISPC_TIMING_V); l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8)); l |= ( max(1, (min(64, panel->vsw))) - 1 ) << 0; l |= ( max(0, (min(255, panel->vfp))) - 0 ) << 8; l |= ( max(0, (min(255, panel->vbp))) - 0 ) << 20; dispc_write_reg(DISPC_TIMING_V, l); l = dispc_read_reg(DISPC_POL_FREQ); l &= ~FLD_MASK(12, 6); l |= (panel->config & OMAP_LCDC_SIGNAL_MASK) << 12; l |= panel->acb & 0xff; dispc_write_reg(DISPC_POL_FREQ, l); calc_ck_div(is_tft, panel->pixel_clock * 1000, &lck_div, &pck_div); l = dispc_read_reg(DISPC_DIVISOR); l &= ~(FLD_MASK(16, 8) | FLD_MASK(0, 8)); l |= (lck_div << 16) | (pck_div << 0); dispc_write_reg(DISPC_DIVISOR, l); /* update panel info with the exact clock */ fck = clk_get_rate(dispc.dss1_fck); panel->pixel_clock = fck / lck_div / pck_div / 1000;}int omap_dispc_request_irq(void (*callback)(void *data), void *data){ int r = 0; BUG_ON(callback == NULL); if (dispc.irq_callback) r = -EBUSY; else { dispc.irq_callback = callback; dispc.irq_callback_data = data; } return r;}EXPORT_SYMBOL(omap_dispc_request_irq);void omap_dispc_enable_irqs(int irq_mask){ enable_lcd_clocks(1); dispc.enabled_irqs = irq_mask; irq_mask |= DISPC_IRQ_MASK_ERROR; MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask); enable_lcd_clocks(0);}EXPORT_SYMBOL(omap_dispc_enable_irqs);void omap_dispc_disable_irqs(int irq_mask){ enable_lcd_clocks(1); dispc.enabled_irqs &= ~irq_mask; irq_mask &= ~DISPC_IRQ_MASK_ERROR; MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask); enable_lcd_clocks(0);}EXPORT_SYMBOL(omap_dispc_disable_irqs);void omap_dispc_free_irq(void){ enable_lcd_clocks(1); omap_dispc_disable_irqs(DISPC_IRQ_MASK_ALL); dispc.irq_callback = NULL; dispc.irq_callback_data = NULL; enable_lcd_clocks(0);}EXPORT_SYMBOL(omap_dispc_free_irq);static irqreturn_t omap_dispc_irq_handler(int irq, void *dev){ u32 stat = dispc_read_reg(DISPC_IRQSTATUS); if (stat & DISPC_IRQ_FRAMEMASK) complete(&dispc.frame_done); if (stat & DISPC_IRQ_MASK_ERROR) { if (printk_ratelimit()) { dev_err(dispc.fbdev->dev, "irq error status %04x\n", stat & 0x7fff); } } if ((stat & dispc.enabled_irqs) && dispc.irq_callback) dispc.irq_callback(dispc.irq_callback_data); dispc_write_reg(DISPC_IRQSTATUS, stat); return IRQ_HANDLED;}static int get_dss_clocks(void){ if (IS_ERR((dispc.dss_ick = clk_get(dispc.fbdev->dev, "dss_ick")))) { dev_err(dispc.fbdev->dev, "can't get dss_ick\n"); return PTR_ERR(dispc.dss_ick); } if (IS_ERR((dispc.dss1_fck = clk_get(dispc.fbdev->dev, "dss1_fck")))) { dev_err(dispc.fbdev->dev, "can't get dss1_fck\n"); clk_put(dispc.dss_ick); return PTR_ERR(dispc.dss1_fck); } if (IS_ERR((dispc.dss_54m_fck = clk_get(dispc.fbdev->dev, "dss_54m_fck")))) { dev_err(dispc.fbdev->dev, "can't get dss_54m_fck\n"); clk_put(dispc.dss_ick); clk_put(dispc.dss1_fck); return PTR_ERR(dispc.dss_54m_fck); } return 0;}static void put_dss_clocks(void){ clk_put(dispc.dss_54m_fck); clk_put(dispc.dss1_fck); clk_put(dispc.dss_ick);}static void enable_lcd_clocks(int enable){ if (enable) clk_enable(dispc.dss1_fck); else clk_disable(dispc.dss1_fck);}static void enable_interface_clocks(int enable){ if (enable) clk_enable(dispc.dss_ick); else clk_disable(dispc.dss_ick);}static void enable_digit_clocks(int enable){ if (enable) clk_enable(dispc.dss_54m_fck); else clk_disable(dispc.dss_54m_fck);}static void omap_dispc_suspend(void){ if (dispc.update_mode == OMAPFB_AUTO_UPDATE) { init_completion(&dispc.frame_done); omap_dispc_enable_lcd_out(0); if (!wait_for_completion_timeout(&dispc.frame_done, msecs_to_jiffies(500))) { dev_err(dispc.fbdev->dev, "timeout waiting for FRAME DONE\n"); } enable_lcd_clocks(0); }}static void omap_dispc_resume(void){ if (dispc.update_mode == OMAPFB_AUTO_UPDATE) { enable_lcd_clocks(1); if (!dispc.ext_mode) { set_lcd_timings(); load_palette(); } omap_dispc_enable_lcd_out(1); }}static int omap_dispc_update_window(struct fb_info *fbi, struct omapfb_update_window *win, void (*complete_callback)(void *arg), void *complete_callback_data){ return dispc.update_mode == OMAPFB_UPDATE_DISABLED ? -ENODEV : 0;}static int mmap_kern(struct omapfb_mem_region *region){ struct vm_struct *kvma; struct vm_area_struct vma; pgprot_t pgprot; unsigned long vaddr; kvma = get_vm_area(region->size, VM_IOREMAP); if (kvma == NULL) { dev_err(dispc.fbdev->dev, "can't get kernel vm area\n"); return -ENOMEM; } vma.vm_mm = &init_mm; vaddr = (unsigned long)kvma->addr; pgprot = pgprot_writecombine(pgprot_kernel); vma.vm_start = vaddr; vma.vm_end = vaddr + region->size; if (io_remap_pfn_range(&vma, vaddr, region->paddr >> PAGE_SHIFT, region->size, pgprot) < 0) { dev_err(dispc.fbdev->dev, "kernel mmap for FBMEM failed\n"); return -EAGAIN; } region->vaddr = (void *)vaddr; return 0;}static void mmap_user_open(struct vm_area_struct *vma){ int plane = (int)vma->vm_private_data; atomic_inc(&dispc.map_count[plane]);}static void mmap_user_close(struct vm_area_struct *vma){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -