]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/gpu/drm/bochs/bochs_kms.c
drm/bochs: drop use of drmP.h
[linux.git] / drivers / gpu / drm / bochs / bochs_kms.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  */
4
5 #include <linux/moduleparam.h>
6
7 #include <drm/drm_atomic_helper.h>
8 #include <drm/drm_gem_framebuffer_helper.h>
9 #include <drm/drm_probe_helper.h>
10 #include <drm/drm_vblank.h>
11
12 #include "bochs.h"
13
14 static int defx = 1024;
15 static int defy = 768;
16
17 module_param(defx, int, 0444);
18 module_param(defy, int, 0444);
19 MODULE_PARM_DESC(defx, "default x resolution");
20 MODULE_PARM_DESC(defy, "default y resolution");
21
22 /* ---------------------------------------------------------------------- */
23
24 static const uint32_t bochs_formats[] = {
25         DRM_FORMAT_XRGB8888,
26         DRM_FORMAT_BGRX8888,
27 };
28
29 static void bochs_plane_update(struct bochs_device *bochs,
30                                struct drm_plane_state *state)
31 {
32         struct drm_gem_vram_object *gbo;
33
34         if (!state->fb || !bochs->stride)
35                 return;
36
37         gbo = drm_gem_vram_of_gem(state->fb->obj[0]);
38         bochs_hw_setbase(bochs,
39                          state->crtc_x,
40                          state->crtc_y,
41                          gbo->bo.offset);
42         bochs_hw_setformat(bochs, state->fb->format);
43 }
44
45 static void bochs_pipe_enable(struct drm_simple_display_pipe *pipe,
46                               struct drm_crtc_state *crtc_state,
47                               struct drm_plane_state *plane_state)
48 {
49         struct bochs_device *bochs = pipe->crtc.dev->dev_private;
50
51         bochs_hw_setmode(bochs, &crtc_state->mode);
52         bochs_plane_update(bochs, plane_state);
53 }
54
55 static void bochs_pipe_update(struct drm_simple_display_pipe *pipe,
56                               struct drm_plane_state *old_state)
57 {
58         struct bochs_device *bochs = pipe->crtc.dev->dev_private;
59         struct drm_crtc *crtc = &pipe->crtc;
60
61         bochs_plane_update(bochs, pipe->plane.state);
62
63         if (crtc->state->event) {
64                 spin_lock_irq(&crtc->dev->event_lock);
65                 drm_crtc_send_vblank_event(crtc, crtc->state->event);
66                 crtc->state->event = NULL;
67                 spin_unlock_irq(&crtc->dev->event_lock);
68         }
69 }
70
71 static int bochs_pipe_prepare_fb(struct drm_simple_display_pipe *pipe,
72                                  struct drm_plane_state *new_state)
73 {
74         struct drm_gem_vram_object *gbo;
75
76         if (!new_state->fb)
77                 return 0;
78         gbo = drm_gem_vram_of_gem(new_state->fb->obj[0]);
79         return drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM);
80 }
81
82 static void bochs_pipe_cleanup_fb(struct drm_simple_display_pipe *pipe,
83                                   struct drm_plane_state *old_state)
84 {
85         struct drm_gem_vram_object *gbo;
86
87         if (!old_state->fb)
88                 return;
89         gbo = drm_gem_vram_of_gem(old_state->fb->obj[0]);
90         drm_gem_vram_unpin(gbo);
91 }
92
93 static const struct drm_simple_display_pipe_funcs bochs_pipe_funcs = {
94         .enable     = bochs_pipe_enable,
95         .update     = bochs_pipe_update,
96         .prepare_fb = bochs_pipe_prepare_fb,
97         .cleanup_fb = bochs_pipe_cleanup_fb,
98 };
99
100 static int bochs_connector_get_modes(struct drm_connector *connector)
101 {
102         struct bochs_device *bochs =
103                 container_of(connector, struct bochs_device, connector);
104         int count = 0;
105
106         if (bochs->edid)
107                 count = drm_add_edid_modes(connector, bochs->edid);
108
109         if (!count) {
110                 count = drm_add_modes_noedid(connector, 8192, 8192);
111                 drm_set_preferred_mode(connector, defx, defy);
112         }
113         return count;
114 }
115
116 static enum drm_mode_status bochs_connector_mode_valid(struct drm_connector *connector,
117                                       struct drm_display_mode *mode)
118 {
119         struct bochs_device *bochs =
120                 container_of(connector, struct bochs_device, connector);
121         unsigned long size = mode->hdisplay * mode->vdisplay * 4;
122
123         /*
124          * Make sure we can fit two framebuffers into video memory.
125          * This allows up to 1600x1200 with 16 MB (default size).
126          * If you want more try this:
127          *     'qemu -vga std -global VGA.vgamem_mb=32 $otherargs'
128          */
129         if (size * 2 > bochs->fb_size)
130                 return MODE_BAD;
131
132         return MODE_OK;
133 }
134
135 static const struct drm_connector_helper_funcs bochs_connector_connector_helper_funcs = {
136         .get_modes = bochs_connector_get_modes,
137         .mode_valid = bochs_connector_mode_valid,
138 };
139
140 static const struct drm_connector_funcs bochs_connector_connector_funcs = {
141         .dpms = drm_helper_connector_dpms,
142         .fill_modes = drm_helper_probe_single_connector_modes,
143         .destroy = drm_connector_cleanup,
144         .reset = drm_atomic_helper_connector_reset,
145         .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
146         .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
147 };
148
149 static void bochs_connector_init(struct drm_device *dev)
150 {
151         struct bochs_device *bochs = dev->dev_private;
152         struct drm_connector *connector = &bochs->connector;
153
154         drm_connector_init(dev, connector, &bochs_connector_connector_funcs,
155                            DRM_MODE_CONNECTOR_VIRTUAL);
156         drm_connector_helper_add(connector,
157                                  &bochs_connector_connector_helper_funcs);
158         drm_connector_register(connector);
159
160         bochs_hw_load_edid(bochs);
161         if (bochs->edid) {
162                 DRM_INFO("Found EDID data blob.\n");
163                 drm_connector_attach_edid_property(connector);
164                 drm_connector_update_edid_property(connector, bochs->edid);
165         }
166 }
167
168 static struct drm_framebuffer *
169 bochs_gem_fb_create(struct drm_device *dev, struct drm_file *file,
170                     const struct drm_mode_fb_cmd2 *mode_cmd)
171 {
172         if (mode_cmd->pixel_format != DRM_FORMAT_XRGB8888 &&
173             mode_cmd->pixel_format != DRM_FORMAT_BGRX8888)
174                 return ERR_PTR(-EINVAL);
175
176         return drm_gem_fb_create(dev, file, mode_cmd);
177 }
178
179 const struct drm_mode_config_funcs bochs_mode_funcs = {
180         .fb_create = bochs_gem_fb_create,
181         .atomic_check = drm_atomic_helper_check,
182         .atomic_commit = drm_atomic_helper_commit,
183 };
184
185 int bochs_kms_init(struct bochs_device *bochs)
186 {
187         drm_mode_config_init(bochs->dev);
188
189         bochs->dev->mode_config.max_width = 8192;
190         bochs->dev->mode_config.max_height = 8192;
191
192         bochs->dev->mode_config.fb_base = bochs->fb_base;
193         bochs->dev->mode_config.preferred_depth = 24;
194         bochs->dev->mode_config.prefer_shadow = 0;
195         bochs->dev->mode_config.prefer_shadow_fbdev = 1;
196         bochs->dev->mode_config.quirk_addfb_prefer_host_byte_order = true;
197
198         bochs->dev->mode_config.funcs = &bochs_mode_funcs;
199
200         bochs_connector_init(bochs->dev);
201         drm_simple_display_pipe_init(bochs->dev,
202                                      &bochs->pipe,
203                                      &bochs_pipe_funcs,
204                                      bochs_formats,
205                                      ARRAY_SIZE(bochs_formats),
206                                      NULL,
207                                      &bochs->connector);
208
209         drm_mode_config_reset(bochs->dev);
210
211         return 0;
212 }
213
214 void bochs_kms_fini(struct bochs_device *bochs)
215 {
216         drm_atomic_helper_shutdown(bochs->dev);
217         drm_mode_config_cleanup(bochs->dev);
218 }