intel_fb.c revision 262861
1167514Skmacy/*
2167514Skmacy * Copyright �� 2007 David Airlie
3167514Skmacy *
4167514Skmacy * Permission is hereby granted, free of charge, to any person obtaining a
5167514Skmacy * copy of this software and associated documentation files (the "Software"),
6167514Skmacy * to deal in the Software without restriction, including without limitation
7167514Skmacy * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8167514Skmacy * and/or sell copies of the Software, and to permit persons to whom the
9167514Skmacy * Software is furnished to do so, subject to the following conditions:
10167514Skmacy *
11167514Skmacy * The above copyright notice and this permission notice (including the next
12170076Skmacy * paragraph) shall be included in all copies or substantial portions of the
13167514Skmacy * Software.
14167514Skmacy *
15167514Skmacy * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16167514Skmacy * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17167514Skmacy * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18167514Skmacy * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19167514Skmacy * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20167514Skmacy * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21167514Skmacy * DEALINGS IN THE SOFTWARE.
22167514Skmacy *
23167514Skmacy * Authors:
24167514Skmacy *     David Airlie
25167514Skmacy */
26167514Skmacy
27167514Skmacy#include <sys/cdefs.h>
28167514Skmacy__FBSDID("$FreeBSD: stable/10/sys/dev/drm2/i915/intel_fb.c 262861 2014-03-06 18:30:56Z jhb $");
29167514Skmacy
30167514Skmacy#include <dev/drm2/drmP.h>
31167514Skmacy#include <dev/drm2/drm.h>
32167514Skmacy#include <dev/drm2/drm_crtc.h>
33170076Skmacy#include <dev/drm2/drm_fb_helper.h>
34167514Skmacy#include <dev/drm2/i915/i915_drm.h>
35167514Skmacy#include <dev/drm2/i915/i915_drv.h>
36167514Skmacy#include <dev/drm2/i915/intel_drv.h>
37167514Skmacy
38167514Skmacystatic int intelfb_create(struct intel_fbdev *ifbdev,
39167514Skmacy			  struct drm_fb_helper_surface_size *sizes)
40167514Skmacy{
41167514Skmacy	struct drm_device *dev = ifbdev->helper.dev;
42167514Skmacy#if 0
43167514Skmacy	struct drm_i915_private *dev_priv = dev->dev_private;
44167514Skmacy#endif
45167514Skmacy	struct fb_info *info;
46167514Skmacy	struct drm_framebuffer *fb;
47167514Skmacy	struct drm_mode_fb_cmd2 mode_cmd;
48167514Skmacy	struct drm_i915_gem_object *obj;
49167514Skmacy	int size, ret;
50167514Skmacy
51167514Skmacy	/* we don't do packed 24bpp */
52167514Skmacy	if (sizes->surface_bpp == 24)
53167514Skmacy		sizes->surface_bpp = 32;
54167514Skmacy
55167514Skmacy	mode_cmd.width = sizes->surface_width;
56167514Skmacy	mode_cmd.height = sizes->surface_height;
57167514Skmacy
58167514Skmacy	mode_cmd.pitches[0] = roundup2(mode_cmd.width * ((sizes->surface_bpp + 7) /
59167514Skmacy							 8), 64);
60167514Skmacy	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
61167514Skmacy							  sizes->surface_depth);
62167514Skmacy
63167514Skmacy	size = mode_cmd.pitches[0] * mode_cmd.height;
64167514Skmacy	size = roundup2(size, PAGE_SIZE);
65167514Skmacy	obj = i915_gem_alloc_object(dev, size);
66167514Skmacy	if (!obj) {
67167514Skmacy		DRM_ERROR("failed to allocate framebuffer\n");
68167514Skmacy		ret = -ENOMEM;
69167514Skmacy		goto out;
70167514Skmacy	}
71167514Skmacy
72167514Skmacy	DRM_LOCK(dev);
73167514Skmacy
74167514Skmacy	/* Flush everything out, we'll be doing GTT only from now on */
75167514Skmacy	ret = intel_pin_and_fence_fb_obj(dev, obj, false);
76167514Skmacy	if (ret) {
77167514Skmacy		DRM_ERROR("failed to pin fb: %d\n", ret);
78167514Skmacy		goto out_unref;
79167514Skmacy	}
80167514Skmacy
81167514Skmacy#if 0
82167514Skmacy	info = framebuffer_alloc(0, device);
83167514Skmacy	if (!info) {
84167514Skmacy		ret = -ENOMEM;
85167514Skmacy		goto out_unpin;
86167514Skmacy	}
87167514Skmacy
88167514Skmacy	info->par = ifbdev;
89167514Skmacy#else
90167514Skmacy	info = malloc(sizeof(struct fb_info), DRM_MEM_KMS, M_WAITOK | M_ZERO);
91167514Skmacy	info->fb_size = size;
92167514Skmacy	info->fb_bpp = sizes->surface_bpp;
93167514Skmacy	info->fb_width = sizes->fb_width;
94167514Skmacy	info->fb_height = sizes->fb_height;
95167514Skmacy	info->fb_pbase = dev->agp->base + obj->gtt_offset;
96167514Skmacy	info->fb_vbase = (vm_offset_t)pmap_mapdev_attr(info->fb_pbase, size,
97167514Skmacy	    PAT_WRITE_COMBINING);
98167514Skmacy
99167514Skmacy#endif
100167514Skmacy
101167514Skmacy	ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj);
102167514Skmacy	if (ret)
103167514Skmacy		goto out_unpin;
104167514Skmacy
105167514Skmacy	fb = &ifbdev->ifb.base;
106167514Skmacy
107167514Skmacy	ifbdev->helper.fb = fb;
108167514Skmacy	ifbdev->helper.fbdev = info;
109167514Skmacy#if 0
110167514Skmacy
111167514Skmacy	strcpy(info->fix.id, "inteldrmfb");
112167514Skmacy
113167514Skmacy	info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
114167514Skmacy	info->fbops = &intelfb_ops;
115167514Skmacy
116167514Skmacy	ret = fb_alloc_cmap(&info->cmap, 256, 0);
117167514Skmacy	if (ret) {
118167514Skmacy		ret = -ENOMEM;
119167514Skmacy		goto out_unpin;
120167514Skmacy	}
121167514Skmacy	/* setup aperture base/size for vesafb takeover */
122167514Skmacy	info->apertures = alloc_apertures(1);
123167514Skmacy	if (!info->apertures) {
124167514Skmacy		ret = -ENOMEM;
125167514Skmacy		goto out_unpin;
126167514Skmacy	}
127167514Skmacy	info->apertures->ranges[0].base = dev->mode_config.fb_base;
128167514Skmacy	info->apertures->ranges[0].size =
129167514Skmacy		dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
130167514Skmacy
131167514Skmacy	info->fix.smem_start = dev->mode_config.fb_base + obj->gtt_offset;
132167514Skmacy	info->fix.smem_len = size;
133167514Skmacy
134167514Skmacy	info->screen_base = ioremap_wc(dev->agp->base + obj->gtt_offset, size);
135167514Skmacy	if (!info->screen_base) {
136167514Skmacy		ret = -ENOSPC;
137167514Skmacy		goto out_unpin;
138167514Skmacy	}
139167514Skmacy	info->screen_size = size;
140167514Skmacy
141167514Skmacy//	memset(info->screen_base, 0, size);
142167514Skmacy
143167514Skmacy	drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
144167514Skmacy	drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height);
145167514Skmacy
146167514Skmacy	/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
147167514Skmacy#endif
148167514Skmacy	DRM_DEBUG_KMS("allocated %dx%d (s %dbits) fb: 0x%08x, bo %p\n",
149167514Skmacy		      fb->width, fb->height, fb->depth,
150167514Skmacy		      obj->gtt_offset, obj);
151167514Skmacy
152167514Skmacy	DRM_UNLOCK(dev);
153167514Skmacy#if 1
154167514Skmacy	KIB_NOTYET();
155167514Skmacy#else
156167514Skmacy	vga_switcheroo_client_fb_set(dev->pdev, info);
157167514Skmacy#endif
158167514Skmacy	return 0;
159167514Skmacy
160167514Skmacyout_unpin:
161167514Skmacy	i915_gem_object_unpin(obj);
162167514Skmacyout_unref:
163167514Skmacy	drm_gem_object_unreference(&obj->base);
164167514Skmacy	DRM_UNLOCK(dev);
165167514Skmacyout:
166167514Skmacy	return ret;
167167514Skmacy}
168167514Skmacy
169167514Skmacystatic int intel_fb_find_or_create_single(struct drm_fb_helper *helper,
170167514Skmacy					  struct drm_fb_helper_surface_size *sizes)
171167514Skmacy{
172167514Skmacy	struct intel_fbdev *ifbdev = (struct intel_fbdev *)helper;
173167514Skmacy	int new_fb = 0;
174167514Skmacy	int ret;
175167514Skmacy
176167514Skmacy	if (!helper->fb) {
177167514Skmacy		ret = intelfb_create(ifbdev, sizes);
178167514Skmacy		if (ret)
179167514Skmacy			return ret;
180167514Skmacy		new_fb = 1;
181167514Skmacy	}
182167514Skmacy	return new_fb;
183167514Skmacy}
184167514Skmacy
185167514Skmacystatic struct drm_fb_helper_funcs intel_fb_helper_funcs = {
186167514Skmacy	.gamma_set = intel_crtc_fb_gamma_set,
187167514Skmacy	.gamma_get = intel_crtc_fb_gamma_get,
188276959Snp	.fb_probe = intel_fb_find_or_create_single,
189167514Skmacy};
190167514Skmacy
191167514Skmacystatic void intel_fbdev_destroy(struct drm_device *dev,
192167514Skmacy				struct intel_fbdev *ifbdev)
193167514Skmacy{
194167514Skmacy#if 0
195167514Skmacy	struct fb_info *info;
196167514Skmacy#endif
197167514Skmacy	struct intel_framebuffer *ifb = &ifbdev->ifb;
198167514Skmacy
199167514Skmacy#if 0
200167514Skmacy	if (ifbdev->helper.fbdev) {
201167514Skmacy		info = ifbdev->helper.fbdev;
202167514Skmacy		unregister_framebuffer(info);
203167514Skmacy		iounmap(info->screen_base);
204167514Skmacy		if (info->cmap.len)
205167514Skmacy			fb_dealloc_cmap(&info->cmap);
206167514Skmacy		framebuffer_release(info);
207167514Skmacy	}
208167514Skmacy#endif
209276959Snp
210276959Snp	drm_fb_helper_fini(&ifbdev->helper);
211276959Snp
212167514Skmacy	drm_framebuffer_cleanup(&ifb->base);
213167514Skmacy	if (ifb->obj) {
214167514Skmacy		drm_gem_object_unreference_unlocked(&ifb->obj->base);
215167514Skmacy		ifb->obj = NULL;
216167514Skmacy	}
217167514Skmacy}
218167514Skmacy
219167514Skmacyextern int sc_txtmouse_no_retrace_wait;
220167514Skmacy
221176472Skmacyint intel_fbdev_init(struct drm_device *dev)
222176472Skmacy{
223176472Skmacy	struct intel_fbdev *ifbdev;
224176472Skmacy	drm_i915_private_t *dev_priv = dev->dev_private;
225176472Skmacy	int ret;
226176472Skmacy
227176472Skmacy	ifbdev = malloc(sizeof(struct intel_fbdev), DRM_MEM_KMS,
228176472Skmacy	    M_WAITOK | M_ZERO);
229176472Skmacy
230176472Skmacy	dev_priv->fbdev = ifbdev;
231167514Skmacy	ifbdev->helper.funcs = &intel_fb_helper_funcs;
232167514Skmacy
233167514Skmacy	ret = drm_fb_helper_init(dev, &ifbdev->helper,
234167514Skmacy				 dev_priv->num_pipe,
235167514Skmacy				 INTELFB_CONN_LIMIT);
236167514Skmacy	if (ret) {
237167514Skmacy		free(ifbdev, DRM_MEM_KMS);
238167514Skmacy		return ret;
239167514Skmacy	}
240167514Skmacy
241167514Skmacy	drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
242167514Skmacy	drm_fb_helper_initial_config(&ifbdev->helper, 32);
243167514Skmacy	sc_txtmouse_no_retrace_wait = 1;
244167514Skmacy	return 0;
245167514Skmacy}
246167514Skmacy
247167514Skmacyvoid intel_fbdev_fini(struct drm_device *dev)
248167514Skmacy{
249167514Skmacy	drm_i915_private_t *dev_priv = dev->dev_private;
250167514Skmacy	if (!dev_priv->fbdev)
251167514Skmacy		return;
252167514Skmacy
253167514Skmacy	intel_fbdev_destroy(dev, dev_priv->fbdev);
254167514Skmacy	free(dev_priv->fbdev, DRM_MEM_KMS);
255167514Skmacy	dev_priv->fbdev = NULL;
256167514Skmacy}
257167514Skmacy
258167514Skmacyvoid intel_fb_output_poll_changed(struct drm_device *dev)
259167514Skmacy{
260167514Skmacy	drm_i915_private_t *dev_priv = dev->dev_private;
261167514Skmacy	drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
262167514Skmacy}
263167514Skmacy
264167514Skmacyvoid intel_fb_restore_mode(struct drm_device *dev)
265167514Skmacy{
266167514Skmacy	int ret;
267167514Skmacy	drm_i915_private_t *dev_priv = dev->dev_private;
268167514Skmacy	struct drm_mode_config *config = &dev->mode_config;
269167514Skmacy	struct drm_plane *plane;
270167514Skmacy
271167514Skmacy	sx_xlock(&dev->mode_config.mutex);
272167514Skmacy
273167514Skmacy	ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper);
274167514Skmacy	if (ret)
275167514Skmacy		DRM_DEBUG("failed to restore crtc mode\n");
276167514Skmacy
277176472Skmacy	/* Be sure to shut off any planes that may be active */
278167514Skmacy	list_for_each_entry(plane, &config->plane_list, head)
279167514Skmacy		plane->funcs->disable_plane(plane);
280167514Skmacy
281167514Skmacy	sx_xunlock(&dev->mode_config.mutex);
282167514Skmacy}
283167514Skmacy