intel_fb.c revision 259016
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 259016 2013-12-05 22:38:53Z ray $");
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#endif
45	struct fb_info *info;
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#else
90	info = malloc(sizeof(struct fb_info), DRM_MEM_KMS, M_WAITOK | M_ZERO);
91	info->fb_size = size;
92	info->fb_bpp = sizes->surface_bpp;
93	info->fb_width = sizes->fb_width;
94	info->fb_height = sizes->fb_height;
95	info->fb_pbase = dev->agp->base + obj->gtt_offset;
96	info->fb_vbase = (vm_offset_t)pmap_mapdev_attr(info->fb_pbase, size,
97	    PAT_WRITE_COMBINING);
98
99#endif
100
101	ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj);
102	if (ret)
103		goto out_unpin;
104
105	fb = &ifbdev->ifb.base;
106
107	ifbdev->helper.fb = fb;
108	ifbdev->helper.fbdev = info;
109#if 0
110
111	strcpy(info->fix.id, "inteldrmfb");
112
113	info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
114	info->fbops = &intelfb_ops;
115
116	ret = fb_alloc_cmap(&info->cmap, 256, 0);
117	if (ret) {
118		ret = -ENOMEM;
119		goto out_unpin;
120	}
121	/* setup aperture base/size for vesafb takeover */
122	info->apertures = alloc_apertures(1);
123	if (!info->apertures) {
124		ret = -ENOMEM;
125		goto out_unpin;
126	}
127	info->apertures->ranges[0].base = dev->mode_config.fb_base;
128	info->apertures->ranges[0].size =
129		dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
130
131	info->fix.smem_start = dev->mode_config.fb_base + obj->gtt_offset;
132	info->fix.smem_len = size;
133
134	info->screen_base = ioremap_wc(dev->agp->base + obj->gtt_offset, size);
135	if (!info->screen_base) {
136		ret = -ENOSPC;
137		goto out_unpin;
138	}
139	info->screen_size = size;
140
141//	memset(info->screen_base, 0, size);
142
143	drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
144	drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height);
145
146	/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
147#endif
148	DRM_DEBUG_KMS("allocated %dx%d (s %dbits) fb: 0x%08x, bo %p\n",
149		      fb->width, fb->height, fb->depth,
150		      obj->gtt_offset, obj);
151
152	DRM_UNLOCK(dev);
153#if 1
154	KIB_NOTYET();
155#else
156	vga_switcheroo_client_fb_set(dev->pdev, info);
157#endif
158	return 0;
159
160out_unpin:
161	i915_gem_object_unpin(obj);
162out_unref:
163	drm_gem_object_unreference(&obj->base);
164	DRM_UNLOCK(dev);
165out:
166	return ret;
167}
168
169static int intel_fb_find_or_create_single(struct drm_fb_helper *helper,
170					  struct drm_fb_helper_surface_size *sizes)
171{
172	struct intel_fbdev *ifbdev = (struct intel_fbdev *)helper;
173	int new_fb = 0;
174	int ret;
175
176	if (!helper->fb) {
177		ret = intelfb_create(ifbdev, sizes);
178		if (ret)
179			return ret;
180		new_fb = 1;
181	}
182	return new_fb;
183}
184
185static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
186	.gamma_set = intel_crtc_fb_gamma_set,
187	.gamma_get = intel_crtc_fb_gamma_get,
188	.fb_probe = intel_fb_find_or_create_single,
189};
190
191static void intel_fbdev_destroy(struct drm_device *dev,
192				struct intel_fbdev *ifbdev)
193{
194#if 0
195	struct fb_info *info;
196#endif
197	struct intel_framebuffer *ifb = &ifbdev->ifb;
198
199#if 0
200	if (ifbdev->helper.fbdev) {
201		info = ifbdev->helper.fbdev;
202		unregister_framebuffer(info);
203		iounmap(info->screen_base);
204		if (info->cmap.len)
205			fb_dealloc_cmap(&info->cmap);
206		framebuffer_release(info);
207	}
208#endif
209
210	drm_fb_helper_fini(&ifbdev->helper);
211
212	drm_framebuffer_cleanup(&ifb->base);
213	if (ifb->obj) {
214		drm_gem_object_unreference_unlocked(&ifb->obj->base);
215		ifb->obj = NULL;
216	}
217}
218
219extern int sc_txtmouse_no_retrace_wait;
220
221int intel_fbdev_init(struct drm_device *dev)
222{
223	struct intel_fbdev *ifbdev;
224	drm_i915_private_t *dev_priv = dev->dev_private;
225	int ret;
226
227	ifbdev = malloc(sizeof(struct intel_fbdev), DRM_MEM_KMS,
228	    M_WAITOK | M_ZERO);
229
230	dev_priv->fbdev = ifbdev;
231	ifbdev->helper.funcs = &intel_fb_helper_funcs;
232
233	ret = drm_fb_helper_init(dev, &ifbdev->helper,
234				 dev_priv->num_pipe,
235				 INTELFB_CONN_LIMIT);
236	if (ret) {
237		free(ifbdev, DRM_MEM_KMS);
238		return ret;
239	}
240
241	drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
242	drm_fb_helper_initial_config(&ifbdev->helper, 32);
243	sc_txtmouse_no_retrace_wait = 1;
244	return 0;
245}
246
247void intel_fbdev_fini(struct drm_device *dev)
248{
249	drm_i915_private_t *dev_priv = dev->dev_private;
250	if (!dev_priv->fbdev)
251		return;
252
253	intel_fbdev_destroy(dev, dev_priv->fbdev);
254	free(dev_priv->fbdev, DRM_MEM_KMS);
255	dev_priv->fbdev = NULL;
256}
257
258void intel_fb_output_poll_changed(struct drm_device *dev)
259{
260	drm_i915_private_t *dev_priv = dev->dev_private;
261	drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
262}
263
264void intel_fb_restore_mode(struct drm_device *dev)
265{
266	int ret;
267	drm_i915_private_t *dev_priv = dev->dev_private;
268	struct drm_mode_config *config = &dev->mode_config;
269	struct drm_plane *plane;
270
271	sx_xlock(&dev->mode_config.mutex);
272
273	ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper);
274	if (ret)
275		DRM_DEBUG("failed to restore crtc mode\n");
276
277	/* Be sure to shut off any planes that may be active */
278	list_for_each_entry(plane, &config->plane_list, head)
279		plane->funcs->disable_plane(plane);
280
281	sx_xunlock(&dev->mode_config.mutex);
282}
283