brintos

brintos / linux-shallow public Read only

0
0
Text · 5.4 KiB · 42426d0 Raw
256 lines · c
1/* sunxvr2500.c: Sun 3DLABS XVR-2500 et al. fb driver for sparc64 systems2 *3 * License: GPL4 *5 * Copyright (C) 2007 David S. Miller (davem@davemloft.net)6 */7 8#include <linux/aperture.h>9#include <linux/kernel.h>10#include <linux/fb.h>11#include <linux/pci.h>12#include <linux/init.h>13#include <linux/of.h>14 15#include <asm/io.h>16 17struct s3d_info {18	struct fb_info		*info;19	struct pci_dev		*pdev;20 21	char __iomem		*fb_base;22	unsigned long		fb_base_phys;23 24	struct device_node	*of_node;25 26	unsigned int		width;27	unsigned int		height;28	unsigned int		depth;29	unsigned int		fb_size;30 31	u32			pseudo_palette[16];32};33 34static int s3d_get_props(struct s3d_info *sp)35{36	sp->width = of_getintprop_default(sp->of_node, "width", 0);37	sp->height = of_getintprop_default(sp->of_node, "height", 0);38	sp->depth = of_getintprop_default(sp->of_node, "depth", 8);39 40	if (!sp->width || !sp->height) {41		printk(KERN_ERR "s3d: Critical properties missing for %s\n",42		       pci_name(sp->pdev));43		return -EINVAL;44	}45 46	return 0;47}48 49static int s3d_setcolreg(unsigned regno,50			 unsigned red, unsigned green, unsigned blue,51			 unsigned transp, struct fb_info *info)52{53	u32 value;54 55	if (regno < 16) {56		red >>= 8;57		green >>= 8;58		blue >>= 8;59 60		value = (blue << 24) | (green << 16) | (red << 8);61		((u32 *)info->pseudo_palette)[regno] = value;62	}63 64	return 0;65}66 67static const struct fb_ops s3d_ops = {68	.owner			= THIS_MODULE,69	FB_DEFAULT_IOMEM_OPS,70	.fb_setcolreg		= s3d_setcolreg,71};72 73static int s3d_set_fbinfo(struct s3d_info *sp)74{75	struct fb_info *info = sp->info;76	struct fb_var_screeninfo *var = &info->var;77 78	info->fbops = &s3d_ops;79	info->screen_base = sp->fb_base;80	info->screen_size = sp->fb_size;81 82	info->pseudo_palette = sp->pseudo_palette;83 84	/* Fill fix common fields */85	strscpy(info->fix.id, "s3d", sizeof(info->fix.id));86        info->fix.smem_start = sp->fb_base_phys;87        info->fix.smem_len = sp->fb_size;88        info->fix.type = FB_TYPE_PACKED_PIXELS;89	if (sp->depth == 32 || sp->depth == 24)90		info->fix.visual = FB_VISUAL_TRUECOLOR;91	else92		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;93 94	var->xres = sp->width;95	var->yres = sp->height;96	var->xres_virtual = var->xres;97	var->yres_virtual = var->yres;98	var->bits_per_pixel = sp->depth;99 100	var->red.offset = 8;101	var->red.length = 8;102	var->green.offset = 16;103	var->green.length = 8;104	var->blue.offset = 24;105	var->blue.length = 8;106	var->transp.offset = 0;107	var->transp.length = 0;108 109	if (fb_alloc_cmap(&info->cmap, 256, 0)) {110		printk(KERN_ERR "s3d: Cannot allocate color map.\n");111		return -ENOMEM;112	}113 114        return 0;115}116 117static int s3d_pci_register(struct pci_dev *pdev,118			    const struct pci_device_id *ent)119{120	struct fb_info *info;121	struct s3d_info *sp;122	int err;123 124	err = aperture_remove_conflicting_pci_devices(pdev, "s3dfb");125	if (err)126		return err;127 128	err = pci_enable_device(pdev);129	if (err < 0) {130		printk(KERN_ERR "s3d: Cannot enable PCI device %s\n",131		       pci_name(pdev));132		goto err_out;133	}134 135	info = framebuffer_alloc(sizeof(struct s3d_info), &pdev->dev);136	if (!info) {137		err = -ENOMEM;138		goto err_disable;139	}140 141	sp = info->par;142	sp->info = info;143	sp->pdev = pdev;144	sp->of_node = pci_device_to_OF_node(pdev);145	if (!sp->of_node) {146		printk(KERN_ERR "s3d: Cannot find OF node of %s\n",147		       pci_name(pdev));148		err = -ENODEV;149		goto err_release_fb;150	}151 152	sp->fb_base_phys = pci_resource_start (pdev, 1);153 154	err = pci_request_region(pdev, 1, "s3d framebuffer");155	if (err < 0) {156		printk("s3d: Cannot request region 1 for %s\n",157		       pci_name(pdev));158		goto err_release_fb;159	}160 161	err = s3d_get_props(sp);162	if (err)163		goto err_release_pci;164 165	/* XXX 'linebytes' is often wrong, it is equal to the width166	 * XXX with depth of 32 on my XVR-2500 which is clearly not167	 * XXX right.  So we don't try to use it.168	 */169	switch (sp->depth) {170	case 8:171		info->fix.line_length = sp->width;172		break;173	case 16:174		info->fix.line_length = sp->width * 2;175		break;176	case 24:177		info->fix.line_length = sp->width * 3;178		break;179	case 32:180		info->fix.line_length = sp->width * 4;181		break;182	}183	sp->fb_size = info->fix.line_length * sp->height;184 185	sp->fb_base = ioremap(sp->fb_base_phys, sp->fb_size);186	if (!sp->fb_base) {187		err = -ENOMEM;188		goto err_release_pci;189	}190 191	err = s3d_set_fbinfo(sp);192	if (err)193		goto err_unmap_fb;194 195	pci_set_drvdata(pdev, info);196 197	printk("s3d: Found device at %s\n", pci_name(pdev));198 199	err = register_framebuffer(info);200	if (err < 0) {201		printk(KERN_ERR "s3d: Could not register framebuffer %s\n",202		       pci_name(pdev));203		goto err_unmap_fb;204	}205 206	return 0;207 208err_unmap_fb:209	iounmap(sp->fb_base);210 211err_release_pci:212	pci_release_region(pdev, 1);213 214err_release_fb:215        framebuffer_release(info);216 217err_disable:218	pci_disable_device(pdev);219 220err_out:221	return err;222}223 224static const struct pci_device_id s3d_pci_table[] = {225	{	PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x002c),	},226	{	PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x002d),	},227	{	PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x002e),	},228	{	PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x002f),	},229	{	PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x0030),	},230	{	PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x0031),	},231	{	PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x0032),	},232	{	PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x0033),	},233	{ 0, }234};235 236static struct pci_driver s3d_driver = {237	.driver = {238		.suppress_bind_attrs = true,239	},240	.name		= "s3d",241	.id_table	= s3d_pci_table,242	.probe		= s3d_pci_register,243};244 245static int __init s3d_init(void)246{247	if (fb_modesetting_disabled("s3d"))248		return -ENODEV;249 250	if (fb_get_options("s3d", NULL))251		return -ENODEV;252 253	return pci_register_driver(&s3d_driver);254}255device_initcall(s3d_init);256