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

📄 voyager.c

📁 嵌入式linux下sm501芯片的驱动源码
💻 C
📖 第 1 页 / 共 5 页
字号:
 *
 *  So here's what we should do in our fbdev blank routine:
 *
 *  	VESA_NO_BLANKING (mode 0)	Video on,  front/back light on
 *  	VESA_VSYNC_SUSPEND (mode 1)  	Video on,  front/back light off
 *  	VESA_HSYNC_SUSPEND (mode 2)  	Video on,  front/back light off
 *  	VESA_POWERDOWN (mode 3)		Video off, front/back light off
 *
 *  This will match the matrox implementation.
 */
/*
 * smifb_blank():
 *	Blank the display by setting all palette values to zero.  Note, the
 * 	12 and 16 bpp modes don't really use the palette, so this will not
 *      blank the display in all modes.
 */
static void smifb_blank(int blank, struct fb_info *info)
{
//	struct smifb_info *sfb = (struct smifb_info *)info;

}

static int smifb_updatevar(int con, struct fb_info *info)
{
	return 0;
}

#endif //CONFIG_FB_SM501_KERNEL_2_4_X


static struct fb_var_screeninfo smifb_var = {
	.xres 		= 640,
	.yres 		= 480,
	.xres_virtual 	= 640,
	.yres_virtual 	= 480,
	.bits_per_pixel = 16,
	.red 		= { 11, 5, 0 },
	.green 		= {  5, 6, 0 }, 
	.blue 		= {  0, 5, 0 },
	.activate	= FB_ACTIVATE_NOW,
	.height		= -1,
	.width		= -1,
	.vmode		= FB_VMODE_NONINTERLACED,
};

static struct fb_fix_screeninfo smifb_fix = {
	.id 		= "vgxFB",
	.type 		= FB_TYPE_PACKED_PIXELS,
	.visual 	= FB_VISUAL_TRUECOLOR,
	.line_length 	= 640*2,
	.accel 		= FB_ACCEL_NONE,
};

#ifdef CONFIG_FB_SM501_KERNEL_2_6_X
static u32 colreg[17];

static int smi_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,  unsigned trans, struct fb_info *info)
{
	struct smifb_info *sfb = (struct smifb_info *)info;
	u32 *pal;
    
    switch (sfb->fb.var.bits_per_pixel)
    {
    case 8:
        if (regno >= 256)
            return 1;
        if (hw.chipID==0x501) 
            sm501_setpalette(regno,red,green,blue);
        break;
    case 32:
        pal = sfb->fb.pseudo_palette;	// System has 16 default color
        if (regno >= 16)
            return 1;
        
        red   >>= 8;
        green >>= 8;
        blue  >>= 8;
        pal[regno] = 
            (red   << sfb->fb.var.red.offset)   |
            (green << sfb->fb.var.green.offset) |
            (blue  << sfb->fb.var.blue.offset);
        
        break;
    case 16:
    default:
        pal = sfb->fb.pseudo_palette;	// System has 16 default color
        if (regno >= 16)
            return 1;
        
        pal[regno] = (red & 0xf800) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
        break;
    }
    
    return 0;
}

void smifb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
{
	if (!area->width || !area->height)
		return;

	deCopy(0, 0, info->var.bits_per_pixel,  
        area->dx, area->dy, area->width, area->height, 
        0, 0, area->sx, area->sy, 0, 0xC);
}

void smifb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
	if (!rect->width || !rect->height)
		return;

	deFillRect(0, 0, rect->dx, rect->dy, rect->width, rect->height, rect->color);
}

void smifb_imageblit(struct fb_info *info, const struct fb_image *image)
{
	if (SMI_de_busy)
		deWaitForNotBusy();

	cfb_imageblit(info, image);
}


static struct fb_ops smifb_ops = {
	.owner        =	THIS_MODULE,
		.fb_setcolreg = smi_setcolreg,
		.fb_fillrect  = smifb_fillrect,
		.fb_copyarea  = smifb_copyarea,
		.fb_imageblit = smifb_imageblit,
		.fb_cursor	= soft_cursor,
};
#endif //CONFIG_FB_SM501_KERNEL_2_6_X


/*
 * Alloc struct smifb_info and assign the default value
 */
static struct smifb_info * __devinit
smi_alloc_fb_info(struct pci_dev *dev, char *name)
{
    struct smifb_info *sfb;

#if CONFIG_FB_SM501_KERNEL_2_4_X
    sfb = kmalloc(sizeof(struct smifb_info) + sizeof(struct display) +
                  sizeof(u32) * 16, GFP_KERNEL);

    if (!sfb)
        return NULL;

    memset(sfb, 0, sizeof(struct smifb_info) + sizeof(struct display));
#endif //CONFIG_FB_SM501_KERNEL_2_4_X

#if CONFIG_FB_SM501_KERNEL_2_6_X
    sfb = kmalloc(sizeof(struct smifb_info), GFP_KERNEL);

    if (!sfb)
        return NULL;

    memset(sfb, 0, sizeof(struct smifb_info));
#endif //CONFIG_FB_SM501_KERNEL_2_6_X

    sfb->currcon        = -1;
    sfb->dev            = dev;

	/*** Init sfb->fb with default value ***/
	sfb->fb.flags = FBINFO_FLAG_DEFAULT;
	sfb->fb.fbops = &smifb_ops;
	sfb->fb.var = smifb_var;
	sfb->fb.fix = smifb_fix;
    
	strcpy(sfb->fb.fix.id, name);

    sfb->fb.fix.type		= FB_TYPE_PACKED_PIXELS;
    sfb->fb.fix.type_aux	= 0;
    sfb->fb.fix.xpanstep	= 0;
    sfb->fb.fix.ypanstep	= 0;
    sfb->fb.fix.ywrapstep	= 0;
    sfb->fb.fix.accel		= FB_ACCEL_NONE;

    sfb->fb.var.nonstd		= 0;
    sfb->fb.var.activate	= FB_ACTIVATE_NOW;
    sfb->fb.var.height		= -1;
    sfb->fb.var.width		= -1;
    sfb->fb.var.accel_flags	= FB_ACCELF_TEXT; /* text mode acceleration */
    sfb->fb.var.vmode		= FB_VMODE_NONINTERLACED;

#ifdef CONFIG_FB_SM501_KERNEL_2_4_X
    strcpy(sfb->fb.modename, sfb->fb.fix.id);
    strcpy(sfb->fb.fontname, "VGA8x8");

    sfb->fb.changevar	= NULL;
    sfb->fb.switch_con	= smifb_switch;
    sfb->fb.updatevar	= smifb_updatevar;
    sfb->fb.blank		= smifb_blank;
    sfb->fb.node		= -1;
    sfb->fb.disp		= (struct display *)(sfb + 1);
    sfb->fb.pseudo_palette	= (void *)(sfb->fb.disp + 1);
#endif //CONFIG_FB_SM501_KERNEL_2_4_X

#ifdef CONFIG_FB_SM501_KERNEL_2_6_X
	sfb->fb.pseudo_palette = colreg;
#endif //CONFIG_FB_SM501_KERNEL_2_6_X
    return sfb;
}

/*
 * Unmap in the memory mapped IO registers
 *
 */

static void __devinit
smi_unmap_mmio(struct smifb_info *sfb)
{
    if (sfb && SMI_VRAMBaseAddress)
    {
        iounmap(SMI_VRAMBaseAddress);
        SMI_RegBaseAddress = NULL;
    }
}

/*
 * Map in the screen memory
 *
 */
static int __devinit
smi_map_smem(struct smifb_info *sfb, struct pci_dev *dev, u_long smem_len)
{
#if isPCI
    sfb->fb.fix.smem_start = pci_resource_start(dev, 0);
#else
    sfb->fb.fix.smem_start =FB_PHYSICAL_ADDR;
#endif
    sfb->fb.fix.smem_len  = smem_len;

    sfb->fb.screen_base = SMI_VRAMBaseAddress;

    if (!sfb->fb.screen_base)
    {
        printk("%s: unable to map screen memory\n",sfb->fb.fix.id);
        return -ENOMEM;
    }

    return 0;
}


/*
 * Unmap in the screen memory
 *
 */
static void __devinit
smi_unmap_smem(struct smifb_info *sfb)
{
    if (sfb && sfb->fb.screen_base)
    {
        iounmap(sfb->fb.screen_base);
        sfb->fb.screen_base = NULL;
    }
}

/*
 * We need to wake up the LynxEM+, and make sure its in linear memory mode.
 */
static inline void __devinit
smi_init_hw(void)
{
    outb(0x18, 0x3c4);
    outb(0x11, 0x3c5);
}

static void __devinit
smi_free_fb_info(struct smifb_info *sfb)
{
	if (sfb) {
		fb_alloc_cmap(&sfb->fb.cmap, 0, 0);
		kfree(sfb);
	}
}


u16 SMI_ChipIDs[numChipIDs] = {0x501};

int __init sm501fb_init(void)
{
    struct smifb_info *sfb;
    u_long smem_size= 0x00800000; //default 8MB
    char name[16];
    int err;
    char *m_pLAW;
    unsigned long pFramebufferPhysical;
    unsigned long pRegPhysical;
    struct pci_dev *pdev = NULL;
    int i = 0;

#if isPCI
    do {
		pdev = pci_find_device(0x126f,SMI_ChipIDs[i], pdev);
		if (pdev == NULL)
			i++;
		else {
			hw.chipID = SMI_ChipIDs[i];
			break;
		}
    } while (i< numChipIDs);

    sprintf(name, "voyager");

    err = pci_enable_device(pdev); // enable voyager chip
    if (err) {
        return err;
    }
#else
	hw.chipID = CHIP_ID;
#endif
    err = -ENOMEM;

    sfb = smi_alloc_fb_info(pdev, name);

    if (!sfb) {
        goto failed;
    }

	// Map address and memory detection
#if isPCI
	pFramebufferPhysical = pci_resource_start(pdev,0);
  	pRegPhysical = pci_resource_start(pdev,1);
#else
	pFramebufferPhysical = FB_PHYSICAL_ADDR;
  	pRegPhysical = REG_PHYSICAL_ADDR;
#endif
    
    switch (hw.chipID) 
    {
    case 0x501:
        sfb->fb.fix.mmio_start = pRegPhysical;
        sfb->fb.fix.mmio_len   = 0x00200000;
        smem_size = 0x00800000; //8MB
        if (!request_mem_region(pFramebufferPhysical, smem_size, "voyager")) {
            printk("request_region pFramebufferPhysical failed!\n");
            return -1;
        };
        if (!request_mem_region(pRegPhysical, sfb->fb.fix.mmio_len, "voyager")) {
            printk("request_region pRegPhysical failed!\n");
            return -1;
        };
#if isACCELENT
        {
            volatile unsigned char *pCPLDS;
            
            MSC1 &= 0xffff0000;
            MSC1 |= 0x00009204; // 0x00009234
            
            MDREFR |= 0x01010000;	// Set free running clock and SDCLK[1] to 100MHz
            
            LCCR0 |= LCCR0_DIS;	// BIT:10 DISABLE lcd CONTROLLER
            
            GAFR2_L = (GAFR2_L & ~0x30000000) | 0x20000000; 
            GAFR0_U = (GAFR0_U & ~0x30) | 0x10;
            GAFR1_U = (GAFR1_U & ~0xf) | 0xa;
            
            pCPLDS = ioremap_nocache(0x17C00000, 0x1000);
            
            *(volatile unsigned long*) (pCPLDS+0x38) = (*(volatile unsigned long*)(pCPLDS+0x38)) & ~0x10; 
            
            iounmap(pCPLDS);	
        }
#endif //isACCELENT
        hw.m_pLFB = SMI_VRAMBaseAddress=m_pLAW = ioremap_nocache(pFramebufferPhysical, smem_size);
        hw.m_pMMIO = SMI_RegBaseAddress = ioremap_nocache(pRegPhysical, sfb->fb.fix.mmio_len);
        break;
	default:
		printk("No valid Silicon Motion video chip was detected!\n");
		smi_free_fb_info(sfb);
		return err;
    }

#if isPC	
	sfb->fb.var.xres = screen_info.lfb_width;
	sfb->fb.var.yres = screen_info.lfb_height;
	sfb->fb.var.bits_per_pixel = screen_info.lfb_depth;
#else
	sfb->fb.var.xres = SCREEN_X_RES;	// default resolution 640x480 16bit mode
	sfb->fb.var.yres = SCREEN_Y_RES;
	sfb->fb.var.bits_per_pixel = SCREEN_BPP;
#endif

	if (15 == sfb->fb.var.bits_per_pixel)
		sfb->fb.var.bits_per_pixel = 16;

	if (24 == sfb->fb.var.bits_per_pixel)
		sfb->fb.var.bits_per_pixel = 32; //SM501 does not support 24bpp. It supports 32bpp true color.

   	sfb->fb.var.xres_virtual = sfb->fb.var.xres;

	sfb->fb.var.yres_virtual = sfb->fb.var.yres;

    err = smi_map_smem(sfb, pdev, smem_size);
    if (err) {
		goto failed;
    }
	
#ifdef CONFIG_FB_SM501_KERNEL_2_4_X
    smifb_set_var(&sfb->fb.var, -1, &sfb->fb);
#endif //CONFIG_FB_SM501_KERNEL_2_4_X

#ifdef CONFIG_FB_SM501_KERNEL_2_6_X
	switch (sfb->fb.var.bits_per_pixel) {
	case 8:
		sfb->fb.fix.visual		= FB_VISUAL_PSEUDOCOLOR;
		sfb->fb.fix.line_length= sfb->fb.var.xres ;
		sfb->fb.var.red.offset	= 5;
		sfb->fb.var.red.length	= 3;
		sfb->fb.var.green.offset= 2;
		sfb->fb.var.green.length= 3;
		sfb->fb.var.blue.offset	= 0;
		sfb->fb.var.blue.length	= 2;
		break;
	case 32:
		sfb->fb.fix.visual		= FB_VISUAL_TRUECOLOR;
		sfb->fb.fix.line_length= sfb->fb.var.xres * 4;
		sfb->fb.var.red.offset	= 16;
		sfb->fb.var.red.length	= 8;
		sfb->fb.var.green.offset= 8;
		sfb->fb.var.green.length= 8;
		sfb->fb.var.blue.offset	= 0;
		sfb->fb.var.blue.length	= 8;
		break;
	case 16:
	default:
		sfb->fb.fix.visual		= FB_VISUAL_TRUECOLOR;
		sfb->fb.fix.line_length= sfb->fb.var.xres * 2;
		sfb->fb.var.red.offset	= 11;
		sfb->fb.var.red.length	= 5;
		sfb->fb.var.green.offset= 5;
		sfb->fb.var.green.length= 6;
		sfb->fb.var.blue.offset	= 0;
		sfb->fb.var.blue.length	= 5;
		break;
	}

    hw.width = sfb->fb.var.xres;
    hw.height = sfb->fb.var.yres;
    hw.hz = 60;
    smi_set_timing(sfb, &hw);
	deInit(sfb->fb.var.xres, sfb->fb.var.yres, sfb->fb.var.bits_per_pixel); /* Init SMI drawing engine */
#endif //CONFIG_FB_SM501_KERNEL_2_6_X
	
	err = register_framebuffer(&sfb->fb);
    if (err < 0) {
		goto failed;
    }

	MOD_INC_USE_COUNT;

    //printk("FBbase=%08X, CURRENT_POWER_GATE=%08X, CURRENT_POWER_CLOCK=%08X\n", (unsigned int)sfb->fb.screen_base, regRead32(CURRENT_POWER_GATE), regRead32(CURRENT_POWER_CLOCK));
	printk("Silicon Motion, Inc. SM501 mode %dx%d-%d Init Complete.\n",sfb->fb.var.xres, sfb->fb.var.yres, sfb->fb.var.bits_per_pixel);

	return 0;

failed:
	smi_unmap_smem(sfb);
	smi_unmap_mmio(sfb);
	smi_free_fb_info(sfb);

	return err;
}

⌨️ 快捷键说明

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