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 const 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");
112 goto err_disable_dev
;
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
);
121 goto err_release_regions
;
123 if (width
< 100 || width
> 10000) {
124 pci_err(pdev
, "width (%d) out of range\n", width
);
126 goto err_release_regions
;
128 if (height
< 100 || height
> 10000) {
129 pci_err(pdev
, "height (%d) out of range\n", height
);
131 goto err_release_regions
;
133 pci_info(pdev
, "mdpy found: %dx%d framebuffer\n",
136 info
= framebuffer_alloc(sizeof(struct mdpy_fb_par
), &pdev
->dev
);
139 goto err_release_regions
;
141 pci_set_drvdata(pdev
, info
);
144 info
->fix
= mdpy_fb_fix
;
145 info
->fix
.smem_start
= pci_resource_start(pdev
, 0);
146 info
->fix
.smem_len
= pci_resource_len(pdev
, 0);
147 info
->fix
.line_length
= width
* 4;
149 info
->var
= mdpy_fb_var
;
150 info
->var
.xres
= width
;
151 info
->var
.yres
= height
;
152 info
->var
.xres_virtual
= width
;
153 info
->var
.yres_virtual
= height
;
155 info
->screen_size
= info
->fix
.smem_len
;
156 info
->screen_base
= ioremap(info
->fix
.smem_start
,
158 if (!info
->screen_base
) {
159 pci_err(pdev
, "ioremap(pcibar) failed\n");
164 info
->fbops
= &mdpy_fb_ops
;
165 info
->flags
= FBINFO_DEFAULT
;
166 info
->pseudo_palette
= par
->palette
;
168 ret
= register_framebuffer(info
);
170 pci_err(pdev
, "mdpy-fb device register failed: %d\n", ret
);
174 pci_info(pdev
, "fb%d registered\n", info
->node
);
178 iounmap(info
->screen_base
);
181 framebuffer_release(info
);
184 pci_release_regions(pdev
);
187 pci_disable_device(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 iounmap(info
->screen_base
);
198 framebuffer_release(info
);
199 pci_release_regions(pdev
);
200 pci_disable_device(pdev
);
203 static struct pci_device_id mdpy_fb_pci_table
[] = {
205 .vendor
= MDPY_PCI_VENDOR_ID
,
206 .device
= MDPY_PCI_DEVICE_ID
,
207 .subvendor
= MDPY_PCI_SUBVENDOR_ID
,
208 .subdevice
= MDPY_PCI_SUBDEVICE_ID
,
214 static struct pci_driver mdpy_fb_pci_driver
= {
216 .id_table
= mdpy_fb_pci_table
,
217 .probe
= mdpy_fb_probe
,
218 .remove
= mdpy_fb_remove
,
221 static int __init
mdpy_fb_init(void)
225 ret
= pci_register_driver(&mdpy_fb_pci_driver
);
232 module_init(mdpy_fb_init
);
234 MODULE_DEVICE_TABLE(pci
, mdpy_fb_pci_table
);
235 MODULE_LICENSE("GPL v2");