1 // SPDX-License-Identifier: GPL-2.0
3 * Framebuffer driver for mdpy (mediated virtual pci display device).
5 * See mdpy-defs.h for device specs
7 * (c) Gerd Hoffmann <kraxel@redhat.com>
9 * Using some code snippets from simplefb and cirrusfb.
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms and conditions of the GNU General Public License,
13 * version 2, as published by the Free Software Foundation.
15 * This program is distributed in the hope it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
20 #include <linux/errno.h>
23 #include <linux/pci.h>
24 #include <linux/module.h>
25 #include <drm/drm_fourcc.h>
26 #include "mdpy-defs.h"
28 static const struct fb_fix_screeninfo mdpy_fb_fix
= {
30 .type
= FB_TYPE_PACKED_PIXELS
,
31 .visual
= FB_VISUAL_TRUECOLOR
,
32 .accel
= FB_ACCEL_NONE
,
35 static const struct fb_var_screeninfo mdpy_fb_var
= {
38 .activate
= FB_ACTIVATE_NOW
,
39 .vmode
= FB_VMODE_NONINTERLACED
,
52 #define PSEUDO_PALETTE_SIZE 16
55 u32 palette
[PSEUDO_PALETTE_SIZE
];
58 static int mdpy_fb_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
59 u_int transp
, struct fb_info
*info
)
61 u32
*pal
= info
->pseudo_palette
;
62 u32 cr
= red
>> (16 - info
->var
.red
.length
);
63 u32 cg
= green
>> (16 - info
->var
.green
.length
);
64 u32 cb
= blue
>> (16 - info
->var
.blue
.length
);
67 if (regno
>= PSEUDO_PALETTE_SIZE
)
70 value
= (cr
<< info
->var
.red
.offset
) |
71 (cg
<< info
->var
.green
.offset
) |
72 (cb
<< info
->var
.blue
.offset
);
73 if (info
->var
.transp
.length
> 0) {
74 mask
= (1 << info
->var
.transp
.length
) - 1;
75 mask
<<= info
->var
.transp
.offset
;
83 static void mdpy_fb_destroy(struct fb_info
*info
)
85 if (info
->screen_base
)
86 iounmap(info
->screen_base
);
89 static struct fb_ops mdpy_fb_ops
= {
91 .fb_destroy
= mdpy_fb_destroy
,
92 .fb_setcolreg
= mdpy_fb_setcolreg
,
93 .fb_fillrect
= cfb_fillrect
,
94 .fb_copyarea
= cfb_copyarea
,
95 .fb_imageblit
= cfb_imageblit
,
98 static int mdpy_fb_probe(struct pci_dev
*pdev
,
99 const struct pci_device_id
*ent
)
101 struct fb_info
*info
;
102 struct mdpy_fb_par
*par
;
103 u32 format
, width
, height
;
106 ret
= pci_enable_device(pdev
);
110 ret
= pci_request_regions(pdev
, "mdpy-fb");
114 pci_read_config_dword(pdev
, MDPY_FORMAT_OFFSET
, &format
);
115 pci_read_config_dword(pdev
, MDPY_WIDTH_OFFSET
, &width
);
116 pci_read_config_dword(pdev
, MDPY_HEIGHT_OFFSET
, &height
);
117 if (format
!= DRM_FORMAT_XRGB8888
) {
118 pci_err(pdev
, "format mismatch (0x%x != 0x%x)\n",
119 format
, DRM_FORMAT_XRGB8888
);
122 if (width
< 100 || width
> 10000) {
123 pci_err(pdev
, "width (%d) out of range\n", width
);
126 if (height
< 100 || height
> 10000) {
127 pci_err(pdev
, "height (%d) out of range\n", height
);
130 pci_info(pdev
, "mdpy found: %dx%d framebuffer\n",
133 info
= framebuffer_alloc(sizeof(struct mdpy_fb_par
), &pdev
->dev
);
135 goto err_release_regions
;
136 pci_set_drvdata(pdev
, info
);
139 info
->fix
= mdpy_fb_fix
;
140 info
->fix
.smem_start
= pci_resource_start(pdev
, 0);
141 info
->fix
.smem_len
= pci_resource_len(pdev
, 0);
142 info
->fix
.line_length
= width
* 4;
144 info
->var
= mdpy_fb_var
;
145 info
->var
.xres
= width
;
146 info
->var
.yres
= height
;
147 info
->var
.xres_virtual
= width
;
148 info
->var
.yres_virtual
= height
;
150 info
->screen_size
= info
->fix
.smem_len
;
151 info
->screen_base
= ioremap(info
->fix
.smem_start
,
153 if (!info
->screen_base
) {
154 pci_err(pdev
, "ioremap(pcibar) failed\n");
159 info
->apertures
= alloc_apertures(1);
160 if (!info
->apertures
) {
164 info
->apertures
->ranges
[0].base
= info
->fix
.smem_start
;
165 info
->apertures
->ranges
[0].size
= info
->fix
.smem_len
;
167 info
->fbops
= &mdpy_fb_ops
;
168 info
->flags
= FBINFO_DEFAULT
;
169 info
->pseudo_palette
= par
->palette
;
171 ret
= register_framebuffer(info
);
173 pci_err(pdev
, "mdpy-fb device register failed: %d\n", ret
);
177 pci_info(pdev
, "fb%d registered\n", info
->node
);
181 iounmap(info
->screen_base
);
184 framebuffer_release(info
);
187 pci_release_regions(pdev
);
192 static void mdpy_fb_remove(struct pci_dev
*pdev
)
194 struct fb_info
*info
= pci_get_drvdata(pdev
);
196 unregister_framebuffer(info
);
197 framebuffer_release(info
);
200 static struct pci_device_id mdpy_fb_pci_table
[] = {
202 .vendor
= MDPY_PCI_VENDOR_ID
,
203 .device
= MDPY_PCI_DEVICE_ID
,
204 .subvendor
= MDPY_PCI_SUBVENDOR_ID
,
205 .subdevice
= MDPY_PCI_SUBDEVICE_ID
,
211 static struct pci_driver mdpy_fb_pci_driver
= {
213 .id_table
= mdpy_fb_pci_table
,
214 .probe
= mdpy_fb_probe
,
215 .remove
= mdpy_fb_remove
,
218 static int __init
mdpy_fb_init(void)
222 ret
= pci_register_driver(&mdpy_fb_pci_driver
);
229 module_init(mdpy_fb_init
);
231 MODULE_DEVICE_TABLE(pci
, mdpy_fb_pci_table
);
232 MODULE_LICENSE("GPL v2");