mx3fb.c

来自「Linux环境下视频显示卡设备的驱动程序源代码」· C语言 代码 · 共 1,556 行 · 第 1/4 页

C
1,556
字号
}/** * sdc_set_window_pos() - set window position of the respective plane. * @mx3fb:     mx3fb context. * @channel:   IPU DMAC channel ID. * @x_pos:     X coordinate relative to the top left corner to place window at. * @y_pos:     Y coordinate relative to the top left corner to place window at. * @return:    0 on success or negative error code on failure. */static int sdc_set_window_pos(struct mx3fb_data *mx3fb, enum ipu_channel channel,                             int16_t x_pos, int16_t y_pos){       x_pos += mx3fb->h_start_width;       y_pos += mx3fb->v_start_width;       if (channel != IDMAC_SDC_0)               return -EINVAL;       mx3fb_write_reg(mx3fb, (x_pos << 16) | y_pos, SDC_BG_POS);       return 0;}/** * sdc_init_panel() - initialize a synchronous LCD panel. * @mx3fb:             mx3fb context. * @panel:             panel type. * @pixel_clk:         desired pixel clock frequency in Hz. * @width:             width of panel in pixels. * @height:            height of panel in pixels. * @pixel_fmt:         pixel format of buffer as FOURCC ASCII code. * @h_start_width:     number of pixel clocks between the HSYNC signal pulse *                     and the start of valid data. * @h_sync_width:      width of the HSYNC signal in units of pixel clocks. * @h_end_width:       number of pixel clocks between the end of valid data *                     and the HSYNC signal for next line. * @v_start_width:     number of lines between the VSYNC signal pulse and the *                     start of valid data. * @v_sync_width:      width of the VSYNC signal in units of lines * @v_end_width:       number of lines between the end of valid data and the *                     VSYNC signal for next frame. * @sig:               bitfield of signal polarities for LCD interface. * @return:            0 on success or negative error code on failure. */static int sdc_init_panel(struct mx3fb_data *mx3fb, enum ipu_panel panel,                         uint32_t pixel_clk,                         uint16_t width, uint16_t height,                         enum pixel_fmt pixel_fmt,                         uint16_t h_start_width, uint16_t h_sync_width,                         uint16_t h_end_width, uint16_t v_start_width,                         uint16_t v_sync_width, uint16_t v_end_width,                         struct ipu_di_signal_cfg sig){       unsigned long lock_flags;       uint32_t reg;       uint32_t old_conf;       uint32_t div;       struct clk *ipu_clk;       dev_dbg(mx3fb->dev, "panel size = %d x %d", width, height);       if (v_sync_width == 0 || h_sync_width == 0)               return -EINVAL;       /* Init panel size and blanking periods */       reg = ((uint32_t) (h_sync_width - 1) << 26) |               ((uint32_t) (width + h_start_width + h_end_width - 1) << 16);       mx3fb_write_reg(mx3fb, reg, SDC_HOR_CONF);#ifdef DEBUG       printk(KERN_CONT " hor_conf %x,", reg);#endif       reg = ((uint32_t) (v_sync_width - 1) << 26) | SDC_V_SYNC_WIDTH_L |           ((uint32_t) (height + v_start_width + v_end_width - 1) << 16);       mx3fb_write_reg(mx3fb, reg, SDC_VER_CONF);#ifdef DEBUG       printk(KERN_CONT " ver_conf %x\n", reg);#endif       mx3fb->h_start_width = h_start_width;       mx3fb->v_start_width = v_start_width;       switch (panel) {       case IPU_PANEL_SHARP_TFT:               mx3fb_write_reg(mx3fb, 0x00FD0102L, SDC_SHARP_CONF_1);               mx3fb_write_reg(mx3fb, 0x00F500F4L, SDC_SHARP_CONF_2);               mx3fb_write_reg(mx3fb, SDC_COM_SHARP | SDC_COM_TFT_COLOR, SDC_COM_CONF);               break;       case IPU_PANEL_TFT:               mx3fb_write_reg(mx3fb, SDC_COM_TFT_COLOR, SDC_COM_CONF);               break;       default:               return -EINVAL;       }       /* Init clocking */       /*        * Calculate divider: fractional part is 4 bits so simply multiple by        * 24 to get fractional part, as long as we stay under ~250MHz and on        * i.MX31 it (HSP_CLK) is <= 178MHz. Currently 128.267MHz        */       dev_dbg(mx3fb->dev, "pixel clk = %d\n", pixel_clk);       ipu_clk = clk_get(mx3fb->dev, "ipu_clk");       div = clk_get_rate(ipu_clk) * 16 / pixel_clk;       clk_put(ipu_clk);       if (div < 0x40) {       /* Divider less than 4 */               dev_dbg(mx3fb->dev,                       "InitPanel() - Pixel clock divider less than 4\n");               div = 0x40;       }       spin_lock_irqsave(&mx3fb->lock, lock_flags);       /*        * DISP3_IF_CLK_DOWN_WR is half the divider value and 2 fraction bits        * fewer. Subtract 1 extra from DISP3_IF_CLK_DOWN_WR based on timing        * debug. DISP3_IF_CLK_UP_WR is 0        */       mx3fb_write_reg(mx3fb, (((div / 8) - 1) << 22) | div, DI_DISP3_TIME_CONF);       /* DI settings */       old_conf = mx3fb_read_reg(mx3fb, DI_DISP_IF_CONF) & 0x78FFFFFF;       old_conf |= sig.datamask_en << DI_D3_DATAMSK_SHIFT |           sig.clksel_en << DI_D3_CLK_SEL_SHIFT |           sig.clkidle_en << DI_D3_CLK_IDLE_SHIFT;       mx3fb_write_reg(mx3fb, old_conf, DI_DISP_IF_CONF);       old_conf = mx3fb_read_reg(mx3fb, DI_DISP_SIG_POL) & 0xE0FFFFFF;       old_conf |= sig.data_pol << DI_D3_DATA_POL_SHIFT |           sig.clk_pol << DI_D3_CLK_POL_SHIFT |           sig.enable_pol << DI_D3_DRDY_SHARP_POL_SHIFT |           sig.Hsync_pol << DI_D3_HSYNC_POL_SHIFT |           sig.Vsync_pol << DI_D3_VSYNC_POL_SHIFT;       mx3fb_write_reg(mx3fb, old_conf, DI_DISP_SIG_POL);       switch (pixel_fmt) {       case IPU_PIX_FMT_RGB24:               mx3fb_write_reg(mx3fb, di_mappings[0], DI_DISP3_B0_MAP);               mx3fb_write_reg(mx3fb, di_mappings[1], DI_DISP3_B1_MAP);               mx3fb_write_reg(mx3fb, di_mappings[2], DI_DISP3_B2_MAP);               mx3fb_write_reg(mx3fb, mx3fb_read_reg(mx3fb, DI_DISP_ACC_CC) |                            ((di_mappings[3] - 1) << 12), DI_DISP_ACC_CC);               break;       case IPU_PIX_FMT_RGB666:               mx3fb_write_reg(mx3fb, di_mappings[4], DI_DISP3_B0_MAP);               mx3fb_write_reg(mx3fb, di_mappings[5], DI_DISP3_B1_MAP);               mx3fb_write_reg(mx3fb, di_mappings[6], DI_DISP3_B2_MAP);               mx3fb_write_reg(mx3fb, mx3fb_read_reg(mx3fb, DI_DISP_ACC_CC) |                            ((di_mappings[7] - 1) << 12), DI_DISP_ACC_CC);               break;       case IPU_PIX_FMT_BGR666:               mx3fb_write_reg(mx3fb, di_mappings[8], DI_DISP3_B0_MAP);               mx3fb_write_reg(mx3fb, di_mappings[9], DI_DISP3_B1_MAP);               mx3fb_write_reg(mx3fb, di_mappings[10], DI_DISP3_B2_MAP);               mx3fb_write_reg(mx3fb, mx3fb_read_reg(mx3fb, DI_DISP_ACC_CC) |                            ((di_mappings[11] - 1) << 12), DI_DISP_ACC_CC);               break;       default:               mx3fb_write_reg(mx3fb, di_mappings[12], DI_DISP3_B0_MAP);               mx3fb_write_reg(mx3fb, di_mappings[13], DI_DISP3_B1_MAP);               mx3fb_write_reg(mx3fb, di_mappings[14], DI_DISP3_B2_MAP);               mx3fb_write_reg(mx3fb, mx3fb_read_reg(mx3fb, DI_DISP_ACC_CC) |                            ((di_mappings[15] - 1) << 12), DI_DISP_ACC_CC);               break;       }       spin_unlock_irqrestore(&mx3fb->lock, lock_flags);       dev_dbg(mx3fb->dev, "DI_DISP_IF_CONF = 0x%08X\n",               mx3fb_read_reg(mx3fb, DI_DISP_IF_CONF));       dev_dbg(mx3fb->dev, "DI_DISP_SIG_POL = 0x%08X\n",               mx3fb_read_reg(mx3fb, DI_DISP_SIG_POL));       dev_dbg(mx3fb->dev, "DI_DISP3_TIME_CONF = 0x%08X\n",               mx3fb_read_reg(mx3fb, DI_DISP3_TIME_CONF));       return 0;}/** * sdc_set_color_key() - set the transparent color key for SDC graphic plane. * @mx3fb:     mx3fb context. * @channel:   IPU DMAC channel ID. * @enable:    boolean to enable or disable color keyl. * @color_key: 24-bit RGB color to use as transparent color key. * @return:    0 on success or negative error code on failure. */static int sdc_set_color_key(struct mx3fb_data *mx3fb, enum ipu_channel channel,                            bool enable, uint32_t color_key){       uint32_t reg, sdc_conf;       unsigned long lock_flags;       spin_lock_irqsave(&mx3fb->lock, lock_flags);       sdc_conf = mx3fb_read_reg(mx3fb, SDC_COM_CONF);       if (channel == IDMAC_SDC_0)               sdc_conf &= ~SDC_COM_GWSEL;       else               sdc_conf |= SDC_COM_GWSEL;       if (enable) {               reg = mx3fb_read_reg(mx3fb, SDC_GW_CTRL) & 0xFF000000L;               mx3fb_write_reg(mx3fb, reg | (color_key & 0x00FFFFFFL),                            SDC_GW_CTRL);               sdc_conf |= SDC_COM_KEY_COLOR_G;       } else {               sdc_conf &= ~SDC_COM_KEY_COLOR_G;       }       mx3fb_write_reg(mx3fb, sdc_conf, SDC_COM_CONF);       spin_unlock_irqrestore(&mx3fb->lock, lock_flags);       return 0;}/** * sdc_set_global_alpha() - set global alpha blending modes. * @mx3fb:     mx3fb context. * @enable:    boolean to enable or disable global alpha blending. If disabled, *             per pixel blending is used. * @alpha:     global alpha value. * @return:    0 on success or negative error code on failure. */static int sdc_set_global_alpha(struct mx3fb_data *mx3fb, bool enable, uint8_t alpha){       uint32_t reg;       unsigned long lock_flags;       spin_lock_irqsave(&mx3fb->lock, lock_flags);       if (enable) {               reg = mx3fb_read_reg(mx3fb, SDC_GW_CTRL) & 0x00FFFFFFL;               mx3fb_write_reg(mx3fb, reg | ((uint32_t) alpha << 24), SDC_GW_CTRL);               reg = mx3fb_read_reg(mx3fb, SDC_COM_CONF);               mx3fb_write_reg(mx3fb, reg | SDC_COM_GLB_A, SDC_COM_CONF);       } else {               reg = mx3fb_read_reg(mx3fb, SDC_COM_CONF);               mx3fb_write_reg(mx3fb, reg & ~SDC_COM_GLB_A, SDC_COM_CONF);       }       spin_unlock_irqrestore(&mx3fb->lock, lock_flags);       return 0;}static void sdc_set_brightness(struct mx3fb_data *mx3fb, uint8_t value){       /* This might be board-specific */       mx3fb_write_reg(mx3fb, 0x03000000UL | value << 16, SDC_PWM_CTRL);       return;}static uint32_t bpp_to_pixfmt(int bpp){       uint32_t pixfmt = 0;       switch (bpp) {       case 24:               pixfmt = IPU_PIX_FMT_BGR24;               break;       case 32:               pixfmt = IPU_PIX_FMT_BGR32;               break;       case 16:               pixfmt = IPU_PIX_FMT_RGB565;               break;       }       return pixfmt;}static int mx3fb_blank(int blank, struct fb_info *fbi);static int mx3fb_map_video_memory(struct fb_info *fbi);static int mx3fb_unmap_video_memory(struct fb_info *fbi);/** * mx3fb_set_fix() - set fixed framebuffer parameters from variable settings. * @info:      framebuffer information pointer * @return:    0 on success or negative error code on failure. */static int mx3fb_set_fix(struct fb_info *fbi){       struct fb_fix_screeninfo *fix = &fbi->fix;       struct fb_var_screeninfo *var = &fbi->var;       strncpy(fix->id, "DISP3 BG", 8);       fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;       fix->type = FB_TYPE_PACKED_PIXELS;       fix->accel = FB_ACCEL_NONE;       fix->visual = FB_VISUAL_TRUECOLOR;       fix->xpanstep = 1;       fix->ypanstep = 1;       return 0;}static void mx3fb_dma_done(void *arg){       struct idmac_tx_desc *tx_desc = to_tx_desc(arg);       struct dma_chan *chan = tx_desc->txd.chan;       struct idmac_channel *ichannel = to_idmac_chan(chan);       struct mx3fb_data *mx3fb = ichannel->client;       struct mx3fb_info *mx3_fbi = mx3fb->fbi->par;       dev_dbg(mx3fb->dev, "irq %d callback\n", ichannel->eof_irq);       /* We only need one interrupt, it will be re-enabled as needed */       disable_irq(ichannel->eof_irq);       complete(&mx3_fbi->flip_cmpl);}/** * mx3fb_set_par() - set framebuffer parameters and change the operating mode. * @fbi:       framebuffer information pointer. * @return:    0 on success or negative error code on failure. */static int mx3fb_set_par(struct fb_info *fbi){       u32 mem_len;       struct ipu_di_signal_cfg sig_cfg;       enum ipu_panel mode = IPU_PANEL_TFT;       struct mx3fb_info *mx3_fbi = fbi->par;       struct mx3fb_data *mx3fb = mx3_fbi->mx3fb;       struct idmac_channel *ichan = mx3_fbi->idmac_channel;       struct idmac_video_param *video = &ichan->params.video;       struct scatterlist *sg = mx3_fbi->sg;       size_t screen_size;       dev_dbg(mx3fb->dev, "%s [%c]\n", __func__, list_empty(&ichan->queue) ? '-' : '+');       mutex_lock(&mx3_fbi->mutex);       /* Total cleanup */       if (mx3_fbi->txd)               sdc_disable_channel(mx3_fbi);       mx3fb_set_fix(fbi);       mem_len = fbi->var.yres_virtual * fbi->fix.line_length;       if (mem_len > fbi->fix.smem_len) {               if (fbi->fix.smem_start)                       mx3fb_unmap_video_memory(fbi);               fbi->fix.smem_len = mem_len;               if (mx3fb_map_video_memory(fbi) < 0) {                       mutex_unlock(&mx3_fbi->mutex);                       return -ENOMEM;               }       }       screen_size = fbi->fix.line_length * fbi->var.yres;       sg_init_table(&sg[0], 1);       sg_init_table(&sg[1], 1);       sg_dma_address(&sg[0])  = fbi->fix.smem_start;       sg_set_page(&sg[0], virt_to_page(fbi->screen_base),                   fbi->fix.smem_len,                   offset_in_page(fbi->screen_base));       if (mx3_fbi->ipu_ch == IDMAC_SDC_0) {               memset(&sig_cfg, 0, sizeof(sig_cfg));               if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT)                       sig_cfg.Hsync_pol = true;               if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)                       sig_cfg.Vsync_pol = true;               if (fbi->var.sync & FB_SYNC_CLK_INVERT)                       sig_cfg.clk_pol = true;               if (fbi->var.sync & FB_SYNC_DATA_INVERT)                       sig_cfg.data_pol = true;               if (fbi->var.sync & FB_SYNC_OE_ACT_HIGH)                       sig_cfg.enable_pol = true;               if (fbi->var.sync & FB_SYNC_CLK_IDLE_EN)                       sig_cfg.clkidle_en = true;               if (fbi->var.sync & FB_SYNC_CLK_SEL_EN)                       sig_cfg.clksel_en = true;               if (fbi->var.sync & FB_SYNC_SHARP_MODE)                       mode = IPU_PANEL_SHARP_TFT;               dev_dbg(fbi->device, "pixclock = %ul Hz\n",                       (u32) (PICOS2KHZ(fbi->var.pixclock) * 1000UL));

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?