intel_fb.c revision 235783
1/*
2 * Copyright �� 2007 David Airlie
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 *
23 * Authors:
24 *     David Airlie
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/dev/drm2/i915/intel_fb.c 235783 2012-05-22 11:07:44Z kib $");
29
30#include <dev/drm2/drmP.h>
31#include <dev/drm2/drm.h>
32#include <dev/drm2/drm_crtc.h>
33#include <dev/drm2/drm_fb_helper.h>
34#include <dev/drm2/i915/i915_drm.h>
35#include <dev/drm2/i915/i915_drv.h>
36#include <dev/drm2/i915/intel_drv.h>
37
38static int intelfb_create(struct intel_fbdev *ifbdev,
39			  struct drm_fb_helper_surface_size *sizes)
40{
41	struct drm_device *dev = ifbdev->helper.dev;
42#if 0
43	struct drm_i915_private *dev_priv = dev->dev_private;
44	struct fb_info *info;
45#endif
46	struct drm_framebuffer *fb;
47	struct drm_mode_fb_cmd2 mode_cmd;
48	struct drm_i915_gem_object *obj;
49	int size, ret;
50
51	/* we don't do packed 24bpp */
52	if (sizes->surface_bpp == 24)
53		sizes->surface_bpp = 32;
54
55	mode_cmd.width = sizes->surface_width;
56	mode_cmd.height = sizes->surface_height;
57
58	mode_cmd.pitches[0] = roundup2(mode_cmd.width * ((sizes->surface_bpp + 7) /
59							 8), 64);
60	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
61							  sizes->surface_depth);
62
63	size = mode_cmd.pitches[0] * mode_cmd.height;
64	size = roundup2(size, PAGE_SIZE);
65	obj = i915_gem_alloc_object(dev, size);
66	if (!obj) {
67		DRM_ERROR("failed to allocate framebuffer\n");
68		ret = -ENOMEM;
69		goto out;
70	}
71
72	DRM_LOCK(dev);
73
74	/* Flush everything out, we'll be doing GTT only from now on */
75	ret = intel_pin_and_fence_fb_obj(dev, obj, false);
76	if (ret) {
77		DRM_ERROR("failed to pin fb: %d\n", ret);
78		goto out_unref;
79	}
80
81#if 0
82	info = framebuffer_alloc(0, device);
83	if (!info) {
84		ret = -ENOMEM;
85		goto out_unpin;
86	}
87
88	info->par = ifbdev;
89#endif
90
91	ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj);
92	if (ret)
93		goto out_unpin;
94
95	fb = &ifbdev->ifb.base;
96
97	ifbdev->helper.fb = fb;
98#if 0
99	ifbdev->helper.fbdev = info;
100
101	strcpy(info->fix.id, "inteldrmfb");
102
103	info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
104	info->fbops = &intelfb_ops;
105
106	ret = fb_alloc_cmap(&info->cmap, 256, 0);
107	if (ret) {
108		ret = -ENOMEM;
109		goto out_unpin;
110	}
111	/* setup aperture base/size for vesafb takeover */
112	info->apertures = alloc_apertures(1);
113	if (!info->apertures) {
114		ret = -ENOMEM;
115		goto out_unpin;
116	}
117	info->apertures->ranges[0].base = dev->mode_config.fb_base;
118	info->apertures->ranges[0].size =
119		dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
120
121	info->fix.smem_start = dev->mode_config.fb_base + obj->gtt_offset;
122	info->fix.smem_len = size;
123
124	info->screen_base = ioremap_wc(dev->agp->base + obj->gtt_offset, size);
125	if (!info->screen_base) {
126		ret = -ENOSPC;
127		goto out_unpin;
128	}
129	info->screen_size = size;
130
131//	memset(info->screen_base, 0, size);
132
133	drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
134	drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height);
135
136	/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
137#endif
138
139	DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x, bo %p\n",
140		      fb->width, fb->height,
141		      obj->gtt_offset, obj);
142
143	DRM_UNLOCK(dev);
144#if 1
145	KIB_NOTYET();
146#else
147	vga_switcheroo_client_fb_set(dev->pdev, info);
148#endif
149	return 0;
150
151out_unpin:
152	i915_gem_object_unpin(obj);
153out_unref:
154	drm_gem_object_unreference(&obj->base);
155	DRM_UNLOCK(dev);
156out:
157	return ret;
158}
159
160static int intel_fb_find_or_create_single(struct drm_fb_helper *helper,
161					  struct drm_fb_helper_surface_size *sizes)
162{
163	struct intel_fbdev *ifbdev = (struct intel_fbdev *)helper;
164	int new_fb = 0;
165	int ret;
166
167	if (!helper->fb) {
168		ret = intelfb_create(ifbdev, sizes);
169		if (ret)
170			return ret;
171		new_fb = 1;
172	}
173	return new_fb;
174}
175
176static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
177	.gamma_set = intel_crtc_fb_gamma_set,
178	.gamma_get = intel_crtc_fb_gamma_get,
179	.fb_probe = intel_fb_find_or_create_single,
180};
181
182static void intel_fbdev_destroy(struct drm_device *dev,
183				struct intel_fbdev *ifbdev)
184{
185#if 0
186	struct fb_info *info;
187#endif
188	struct intel_framebuffer *ifb = &ifbdev->ifb;
189
190#if 0
191	if (ifbdev->helper.fbdev) {
192		info = ifbdev->helper.fbdev;
193		unregister_framebuffer(info);
194		iounmap(info->screen_base);
195		if (info->cmap.len)
196			fb_dealloc_cmap(&info->cmap);
197		framebuffer_release(info);
198	}
199#endif
200
201	drm_fb_helper_fini(&ifbdev->helper);
202
203	drm_framebuffer_cleanup(&ifb->base);
204	if (ifb->obj) {
205		drm_gem_object_unreference_unlocked(&ifb->obj->base);
206		ifb->obj = NULL;
207	}
208}
209
210int intel_fbdev_init(struct drm_device *dev)
211{
212	struct intel_fbdev *ifbdev;
213	drm_i915_private_t *dev_priv = dev->dev_private;
214	int ret;
215
216	ifbdev = malloc(sizeof(struct intel_fbdev), DRM_MEM_KMS,
217	    M_WAITOK | M_ZERO);
218
219	dev_priv->fbdev = ifbdev;
220	ifbdev->helper.funcs = &intel_fb_helper_funcs;
221
222	ret = drm_fb_helper_init(dev, &ifbdev->helper,
223				 dev_priv->num_pipe,
224				 INTELFB_CONN_LIMIT);
225	if (ret) {
226		free(ifbdev, DRM_MEM_KMS);
227		return ret;
228	}
229
230	drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
231	drm_fb_helper_initial_config(&ifbdev->helper, 32);
232	return 0;
233}
234
235void intel_fbdev_fini(struct drm_device *dev)
236{
237	drm_i915_private_t *dev_priv = dev->dev_private;
238	if (!dev_priv->fbdev)
239		return;
240
241	intel_fbdev_destroy(dev, dev_priv->fbdev);
242	free(dev_priv->fbdev, DRM_MEM_KMS);
243	dev_priv->fbdev = NULL;
244}
245
246void intel_fb_output_poll_changed(struct drm_device *dev)
247{
248	drm_i915_private_t *dev_priv = dev->dev_private;
249	drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
250}
251
252void intel_fb_restore_mode(struct drm_device *dev)
253{
254	int ret;
255	drm_i915_private_t *dev_priv = dev->dev_private;
256	struct drm_mode_config *config = &dev->mode_config;
257	struct drm_plane *plane;
258
259	sx_xlock(&dev->mode_config.mutex);
260
261	ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper);
262	if (ret)
263		DRM_DEBUG("failed to restore crtc mode\n");
264
265	/* Be sure to shut off any planes that may be active */
266	list_for_each_entry(plane, &config->plane_list, head)
267		plane->funcs->disable_plane(plane);
268
269	sx_xunlock(&dev->mode_config.mutex);
270}
271