⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mx3fb.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * Copyright (C) 2008 * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de> * * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#include <linux/module.h>#include <linux/kernel.h>#include <linux/platform_device.h>#include <linux/sched.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/interrupt.h>#include <linux/slab.h>#include <linux/fb.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/ioport.h>#include <linux/dma-mapping.h>#include <linux/dmaengine.h>#include <linux/console.h>#include <linux/clk.h>#include <linux/mutex.h>#include <mach/hardware.h>#include <mach/ipu.h>#include <mach/mx3fb.h>#include <asm/io.h>#include <asm/uaccess.h>#define MX3FB_NAME             "mx3_sdc_fb"#define MX3FB_REG_OFFSET       0xB4/* SDC Registers */#define SDC_COM_CONF           (0xB4 - MX3FB_REG_OFFSET)#define SDC_GW_CTRL            (0xB8 - MX3FB_REG_OFFSET)#define SDC_FG_POS             (0xBC - MX3FB_REG_OFFSET)#define SDC_BG_POS             (0xC0 - MX3FB_REG_OFFSET)#define SDC_CUR_POS            (0xC4 - MX3FB_REG_OFFSET)#define SDC_PWM_CTRL           (0xC8 - MX3FB_REG_OFFSET)#define SDC_CUR_MAP            (0xCC - MX3FB_REG_OFFSET)#define SDC_HOR_CONF           (0xD0 - MX3FB_REG_OFFSET)#define SDC_VER_CONF           (0xD4 - MX3FB_REG_OFFSET)#define SDC_SHARP_CONF_1       (0xD8 - MX3FB_REG_OFFSET)#define SDC_SHARP_CONF_2       (0xDC - MX3FB_REG_OFFSET)/* Register bits */#define SDC_COM_TFT_COLOR      0x00000001UL#define SDC_COM_FG_EN          0x00000010UL#define SDC_COM_GWSEL          0x00000020UL#define SDC_COM_GLB_A          0x00000040UL#define SDC_COM_KEY_COLOR_G    0x00000080UL#define SDC_COM_BG_EN          0x00000200UL#define SDC_COM_SHARP          0x00001000UL#define SDC_V_SYNC_WIDTH_L     0x00000001UL/* Display Interface registers */#define DI_DISP_IF_CONF                (0x0124 - MX3FB_REG_OFFSET)#define DI_DISP_SIG_POL                (0x0128 - MX3FB_REG_OFFSET)#define DI_SER_DISP1_CONF      (0x012C - MX3FB_REG_OFFSET)#define DI_SER_DISP2_CONF      (0x0130 - MX3FB_REG_OFFSET)#define DI_HSP_CLK_PER         (0x0134 - MX3FB_REG_OFFSET)#define DI_DISP0_TIME_CONF_1   (0x0138 - MX3FB_REG_OFFSET)#define DI_DISP0_TIME_CONF_2   (0x013C - MX3FB_REG_OFFSET)#define DI_DISP0_TIME_CONF_3   (0x0140 - MX3FB_REG_OFFSET)#define DI_DISP1_TIME_CONF_1   (0x0144 - MX3FB_REG_OFFSET)#define DI_DISP1_TIME_CONF_2   (0x0148 - MX3FB_REG_OFFSET)#define DI_DISP1_TIME_CONF_3   (0x014C - MX3FB_REG_OFFSET)#define DI_DISP2_TIME_CONF_1   (0x0150 - MX3FB_REG_OFFSET)#define DI_DISP2_TIME_CONF_2   (0x0154 - MX3FB_REG_OFFSET)#define DI_DISP2_TIME_CONF_3   (0x0158 - MX3FB_REG_OFFSET)#define DI_DISP3_TIME_CONF     (0x015C - MX3FB_REG_OFFSET)#define DI_DISP0_DB0_MAP       (0x0160 - MX3FB_REG_OFFSET)#define DI_DISP0_DB1_MAP       (0x0164 - MX3FB_REG_OFFSET)#define DI_DISP0_DB2_MAP       (0x0168 - MX3FB_REG_OFFSET)#define DI_DISP0_CB0_MAP       (0x016C - MX3FB_REG_OFFSET)#define DI_DISP0_CB1_MAP       (0x0170 - MX3FB_REG_OFFSET)#define DI_DISP0_CB2_MAP       (0x0174 - MX3FB_REG_OFFSET)#define DI_DISP1_DB0_MAP       (0x0178 - MX3FB_REG_OFFSET)#define DI_DISP1_DB1_MAP       (0x017C - MX3FB_REG_OFFSET)#define DI_DISP1_DB2_MAP       (0x0180 - MX3FB_REG_OFFSET)#define DI_DISP1_CB0_MAP       (0x0184 - MX3FB_REG_OFFSET)#define DI_DISP1_CB1_MAP       (0x0188 - MX3FB_REG_OFFSET)#define DI_DISP1_CB2_MAP       (0x018C - MX3FB_REG_OFFSET)#define DI_DISP2_DB0_MAP       (0x0190 - MX3FB_REG_OFFSET)#define DI_DISP2_DB1_MAP       (0x0194 - MX3FB_REG_OFFSET)#define DI_DISP2_DB2_MAP       (0x0198 - MX3FB_REG_OFFSET)#define DI_DISP2_CB0_MAP       (0x019C - MX3FB_REG_OFFSET)#define DI_DISP2_CB1_MAP       (0x01A0 - MX3FB_REG_OFFSET)#define DI_DISP2_CB2_MAP       (0x01A4 - MX3FB_REG_OFFSET)#define DI_DISP3_B0_MAP                (0x01A8 - MX3FB_REG_OFFSET)#define DI_DISP3_B1_MAP                (0x01AC - MX3FB_REG_OFFSET)#define DI_DISP3_B2_MAP                (0x01B0 - MX3FB_REG_OFFSET)#define DI_DISP_ACC_CC         (0x01B4 - MX3FB_REG_OFFSET)#define DI_DISP_LLA_CONF       (0x01B8 - MX3FB_REG_OFFSET)#define DI_DISP_LLA_DATA       (0x01BC - MX3FB_REG_OFFSET)/* DI_DISP_SIG_POL bits */#define DI_D3_VSYNC_POL_SHIFT          28#define DI_D3_HSYNC_POL_SHIFT          27#define DI_D3_DRDY_SHARP_POL_SHIFT     26#define DI_D3_CLK_POL_SHIFT            25#define DI_D3_DATA_POL_SHIFT           24/* DI_DISP_IF_CONF bits */#define DI_D3_CLK_IDLE_SHIFT           26#define DI_D3_CLK_SEL_SHIFT            25#define DI_D3_DATAMSK_SHIFT            24enum ipu_panel {       IPU_PANEL_SHARP_TFT,       IPU_PANEL_TFT,};struct ipu_di_signal_cfg {       unsigned datamask_en:1;       unsigned clksel_en:1;       unsigned clkidle_en:1;       unsigned data_pol:1;    /* true = inverted */       unsigned clk_pol:1;     /* true = rising edge */       unsigned enable_pol:1;       unsigned Hsync_pol:1;   /* true = active high */       unsigned Vsync_pol:1;};static const struct fb_videomode mx3fb_modedb[] = {       {               /* 240x320 @ 60 Hz */               .name           = "Sharp-QVGA",               .refresh        = 60,               .xres           = 240,               .yres           = 320,               .pixclock       = 185925,               .left_margin    = 9,               .right_margin   = 16,               .upper_margin   = 7,               .lower_margin   = 9,               .hsync_len      = 1,               .vsync_len      = 1,               .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_SHARP_MODE |                                 FB_SYNC_CLK_INVERT | FB_SYNC_DATA_INVERT |                                 FB_SYNC_CLK_IDLE_EN,               .vmode          = FB_VMODE_NONINTERLACED,               .flag           = 0,       }, {               /* 240x33 @ 60 Hz */               .name           = "Sharp-CLI",               .refresh        = 60,               .xres           = 240,               .yres           = 33,               .pixclock       = 185925,               .left_margin    = 9,               .right_margin   = 16,               .upper_margin   = 7,               .lower_margin   = 9 + 287,               .hsync_len      = 1,               .vsync_len      = 1,               .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_SHARP_MODE |                                 FB_SYNC_CLK_INVERT | FB_SYNC_DATA_INVERT |                                 FB_SYNC_CLK_IDLE_EN,               .vmode          = FB_VMODE_NONINTERLACED,               .flag           = 0,       }, {               /* 640x480 @ 60 Hz */               .name           = "NEC-VGA",               .refresh        = 60,               .xres           = 640,               .yres           = 480,               .pixclock       = 38255,               .left_margin    = 144,               .right_margin   = 0,               .upper_margin   = 34,               .lower_margin   = 40,               .hsync_len      = 1,               .vsync_len      = 1,               .sync           = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_OE_ACT_HIGH,               .vmode          = FB_VMODE_NONINTERLACED,               .flag           = 0,       }, {               /* NTSC TV output */               .name           = "TV-NTSC",               .refresh        = 60,               .xres           = 640,               .yres           = 480,               .pixclock       = 37538,               .left_margin    = 38,               .right_margin   = 858 - 640 - 38 - 3,               .upper_margin   = 36,               .lower_margin   = 518 - 480 - 36 - 1,               .hsync_len      = 3,               .vsync_len      = 1,               .sync           = 0,               .vmode          = FB_VMODE_NONINTERLACED,               .flag           = 0,       }, {               /* PAL TV output */               .name           = "TV-PAL",               .refresh        = 50,               .xres           = 640,               .yres           = 480,               .pixclock       = 37538,               .left_margin    = 38,               .right_margin   = 960 - 640 - 38 - 32,               .upper_margin   = 32,               .lower_margin   = 555 - 480 - 32 - 3,               .hsync_len      = 32,               .vsync_len      = 3,               .sync           = 0,               .vmode          = FB_VMODE_NONINTERLACED,               .flag           = 0,       }, {               /* TV output VGA mode, 640x480 @ 65 Hz */               .name           = "TV-VGA",               .refresh        = 60,               .xres           = 640,               .yres           = 480,               .pixclock       = 40574,               .left_margin    = 35,               .right_margin   = 45,               .upper_margin   = 9,               .lower_margin   = 1,               .hsync_len      = 46,               .vsync_len      = 5,               .sync           = 0,               .vmode          = FB_VMODE_NONINTERLACED,               .flag           = 0,       },};struct mx3fb_data {       struct fb_info          *fbi;       int                     backlight_level;       void __iomem            *reg_base;       spinlock_t              lock;       struct device           *dev;       uint32_t                h_start_width;       uint32_t                v_start_width;};struct dma_chan_request {       struct mx3fb_data       *mx3fb;       enum ipu_channel        id;};/* MX3 specific framebuffer information. */struct mx3fb_info {       int                             blank;       enum ipu_channel                ipu_ch;       uint32_t                        cur_ipu_buf;       u32                             pseudo_palette[16];       struct completion               flip_cmpl;       struct mutex                    mutex;  /* Protects fb-ops */       struct mx3fb_data               *mx3fb;       struct idmac_channel            *idmac_channel;       struct dma_async_tx_descriptor  *txd;       dma_cookie_t                    cookie;       struct scatterlist              sg[2];       u32                             sync;   /* preserve var->sync flags */};static void mx3fb_dma_done(void *);/* Used fb-mode and bpp. Can be set on kernel command line, therefore file-static. */static const char *fb_mode;static unsigned long default_bpp = 16;static u32 mx3fb_read_reg(struct mx3fb_data *mx3fb, unsigned long reg){       return __raw_readl(mx3fb->reg_base + reg);}static void mx3fb_write_reg(struct mx3fb_data *mx3fb, u32 value, unsigned long reg){       __raw_writel(value, mx3fb->reg_base + reg);}static const uint32_t di_mappings[] = {       0x1600AAAA, 0x00E05555, 0x00070000, 3,  /* RGB888 */       0x0005000F, 0x000B000F, 0x0011000F, 1,  /* RGB666 */       0x0011000F, 0x000B000F, 0x0005000F, 1,  /* BGR666 */       0x0004003F, 0x000A000F, 0x000F003F, 1   /* RGB565 */};static void sdc_fb_init(struct mx3fb_info *fbi){       struct mx3fb_data *mx3fb = fbi->mx3fb;       uint32_t reg;       reg = mx3fb_read_reg(mx3fb, SDC_COM_CONF);       mx3fb_write_reg(mx3fb, reg | SDC_COM_BG_EN, SDC_COM_CONF);}/* Returns enabled flag before uninit */static uint32_t sdc_fb_uninit(struct mx3fb_info *fbi){       struct mx3fb_data *mx3fb = fbi->mx3fb;       uint32_t reg;       reg = mx3fb_read_reg(mx3fb, SDC_COM_CONF);       mx3fb_write_reg(mx3fb, reg & ~SDC_COM_BG_EN, SDC_COM_CONF);       return reg & SDC_COM_BG_EN;}static void sdc_enable_channel(struct mx3fb_info *mx3_fbi){       struct mx3fb_data *mx3fb = mx3_fbi->mx3fb;       struct idmac_channel *ichan = mx3_fbi->idmac_channel;       struct dma_chan *dma_chan = &ichan->dma_chan;       unsigned long flags;       dma_cookie_t cookie;       dev_dbg(mx3fb->dev, "mx3fbi %p, desc %p, sg %p\n", mx3_fbi,               to_tx_desc(mx3_fbi->txd), to_tx_desc(mx3_fbi->txd)->sg);       /* This enables the channel */       if (mx3_fbi->cookie < 0) {               mx3_fbi->txd = dma_chan->device->device_prep_slave_sg(dma_chan,                     &mx3_fbi->sg[0], 1, DMA_TO_DEVICE, DMA_PREP_INTERRUPT);               if (!mx3_fbi->txd) {                       dev_err(mx3fb->dev, "Cannot allocate descriptor on %d\n",                               dma_chan->chan_id);                       return;               }               mx3_fbi->txd->callback_param    = mx3_fbi->txd;               mx3_fbi->txd->callback          = mx3fb_dma_done;               cookie = mx3_fbi->txd->tx_submit(mx3_fbi->txd);               dev_dbg(mx3fb->dev, "%d: Submit %p #%d [%c]\n", __LINE__,                      mx3_fbi->txd, cookie, list_empty(&ichan->queue) ? '-' : '+');       } else {               if (!mx3_fbi->txd || !mx3_fbi->txd->tx_submit) {                       dev_err(mx3fb->dev, "Cannot enable channel %d\n",                               dma_chan->chan_id);                       return;               }               /* Just re-activate the same buffer */               dma_async_issue_pending(dma_chan);               cookie = mx3_fbi->cookie;               dev_dbg(mx3fb->dev, "%d: Re-submit %p #%d [%c]\n", __LINE__,                      mx3_fbi->txd, cookie, list_empty(&ichan->queue) ? '-' : '+');       }       if (cookie >= 0) {               spin_lock_irqsave(&mx3fb->lock, flags);               sdc_fb_init(mx3_fbi);               mx3_fbi->cookie = cookie;               spin_unlock_irqrestore(&mx3fb->lock, flags);       }       /*        * Attention! Without this msleep the channel keeps generating        * interrupts. Next sdc_set_brightness() is going to be called        * from mx3fb_blank().        */       msleep(2);}static void sdc_disable_channel(struct mx3fb_info *mx3_fbi){       struct mx3fb_data *mx3fb = mx3_fbi->mx3fb;       uint32_t enabled;       unsigned long flags;       spin_lock_irqsave(&mx3fb->lock, flags);       enabled = sdc_fb_uninit(mx3_fbi);       spin_unlock_irqrestore(&mx3fb->lock, flags);       mx3_fbi->txd->chan->device->device_terminate_all(mx3_fbi->txd->chan);       mx3_fbi->txd = NULL;       mx3_fbi->cookie = -EINVAL;

⌨️ 快捷键说明

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