Subversion Repositories Kolibri OS

Rev

Rev 5060 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4560 Serge 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 
28
#include 
29
#include 
30
#include 
31
//#include 
32
//#include 
33
#include 
34
//#include 
35
#include 
36
//#include 
37
//#include 
38
 
39
#include 
40
#include 
41
#include 
42
#include "intel_drv.h"
43
#include 
44
#include "i915_drv.h"
45
 
46
 
47
struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
48
{
49
#define BYTES_PER_LONG (BITS_PER_LONG/8)
50
#define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG))
51
    int fb_info_size = sizeof(struct fb_info);
52
    struct fb_info *info;
53
    char *p;
54
 
55
    if (size)
56
        fb_info_size += PADDING;
57
 
58
    p = kzalloc(fb_info_size + size, GFP_KERNEL);
59
 
60
    if (!p)
61
        return NULL;
62
 
63
    info = (struct fb_info *) p;
64
 
65
    if (size)
66
        info->par = p + fb_info_size;
67
 
68
    return info;
69
#undef PADDING
70
#undef BYTES_PER_LONG
71
}
72
 
73
 
74
static struct fb_ops intelfb_ops = {
75
	.owner = THIS_MODULE,
76
	.fb_check_var = drm_fb_helper_check_var,
77
	.fb_set_par = drm_fb_helper_set_par,
78
//   .fb_fillrect = cfb_fillrect,
79
//   .fb_copyarea = cfb_copyarea,
80
//   .fb_imageblit = cfb_imageblit,
81
//   .fb_pan_display = drm_fb_helper_pan_display,
82
	.fb_blank = drm_fb_helper_blank,
83
//   .fb_setcmap = drm_fb_helper_setcmap,
84
//   .fb_debug_enter = drm_fb_helper_debug_enter,
85
//   .fb_debug_leave = drm_fb_helper_debug_leave,
86
};
87
 
88
static int intelfb_alloc(struct drm_fb_helper *helper,
89
			  struct drm_fb_helper_surface_size *sizes)
90
{
91
	struct intel_fbdev *ifbdev =
92
		container_of(helper, struct intel_fbdev, helper);
93
	struct drm_device *dev = helper->dev;
94
	struct drm_mode_fb_cmd2 mode_cmd = {};
95
	struct drm_i915_gem_object *obj;
96
	int size, ret;
97
 
98
	/* we don't do packed 24bpp */
99
	if (sizes->surface_bpp == 24)
100
		sizes->surface_bpp = 32;
101
 
102
	mode_cmd.width = sizes->surface_width;
103
	mode_cmd.height = sizes->surface_height;
104
 
105
	mode_cmd.pitches[0] = ALIGN(mode_cmd.width * ((sizes->surface_bpp + 7) /
106
                              8), 512);
107
	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
108
							  sizes->surface_depth);
109
 
110
	size = mode_cmd.pitches[0] * mode_cmd.height;
111
	size = ALIGN(size, PAGE_SIZE);
112
	obj = main_fb_obj;
113
	if (!obj) {
114
		DRM_ERROR("failed to allocate framebuffer\n");
115
		ret = -ENOMEM;
116
		goto out;
117
	}
118
    obj->has_global_gtt_mapping = 0;
119
    obj->stride = mode_cmd.pitches[0];
120
 
121
	/* Flush everything out, we'll be doing GTT only from now on */
122
	ret = intel_pin_and_fence_fb_obj(dev, obj, NULL);
123
	if (ret) {
124
		DRM_ERROR("failed to pin fb: %d\n", ret);
125
		goto out_unref;
126
	}
127
 
128
	ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj);
129
	if (ret)
130
		goto out_unpin;
131
 
132
	return 0;
133
 
134
out_unpin:
135
	i915_gem_object_unpin(obj);
136
out_unref:
137
	drm_gem_object_unreference(&obj->base);
138
out:
139
	return ret;
140
}
141
 
142
static int intelfb_create(struct drm_fb_helper *helper,
143
			  struct drm_fb_helper_surface_size *sizes)
144
{
145
	struct intel_fbdev *ifbdev =
146
		container_of(helper, struct intel_fbdev, helper);
147
	struct intel_framebuffer *intel_fb = &ifbdev->ifb;
148
	struct drm_device *dev = helper->dev;
149
	struct drm_i915_private *dev_priv = dev->dev_private;
150
	struct fb_info *info;
151
	struct drm_framebuffer *fb;
152
	struct drm_i915_gem_object *obj;
153
	int size, ret;
154
 
155
	mutex_lock(&dev->struct_mutex);
156
 
157
	if (!intel_fb->obj) {
158
		DRM_DEBUG_KMS("no BIOS fb, allocating a new one\n");
159
		ret = intelfb_alloc(helper, sizes);
160
		if (ret)
161
			goto out_unlock;
162
	} else {
163
		DRM_DEBUG_KMS("re-using BIOS fb\n");
164
		sizes->fb_width = intel_fb->base.width;
165
		sizes->fb_height = intel_fb->base.height;
166
	}
167
 
168
	obj = intel_fb->obj;
169
	size = obj->base.size;
170
 
171
	info = framebuffer_alloc(0, &dev->pdev->dev);
172
	if (!info) {
173
		ret = -ENOMEM;
174
		goto out_unpin;
175
	}
176
 
177
	info->par = helper;
178
 
179
	fb = &ifbdev->ifb.base;
180
 
181
	ifbdev->helper.fb = fb;
182
	ifbdev->helper.fbdev = info;
183
 
184
    strcpy(info->fix.id, "inteldrmfb");
185
 
186
    info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
187
    info->fbops = &intelfb_ops;
188
 
189
    /* setup aperture base/size for vesafb takeover */
190
	info->apertures = alloc_apertures(1);
191
	if (!info->apertures) {
192
		ret = -ENOMEM;
193
		goto out_unpin;
194
	}
195
	info->apertures->ranges[0].base = dev->mode_config.fb_base;
196
	info->apertures->ranges[0].size = dev_priv->gtt.mappable_end;
197
 
198
 
199
	info->screen_base = (void*) 0xFE000000;
200
	info->screen_size = size;
201
 
202
	/* This driver doesn't need a VT switch to restore the mode on resume */
203
	info->skip_vt_switch = true;
204
 
205
	drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
206
	drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height);
207
 
208
	/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
209
 
210
	DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08lx, bo %p\n",
211
		      fb->width, fb->height,
212
		      i915_gem_obj_ggtt_offset(obj), obj);
213
 
214
	mutex_unlock(&dev->struct_mutex);
215
	return 0;
216
 
217
out_unpin:
218
	i915_gem_object_unpin(obj);
219
	drm_gem_object_unreference(&obj->base);
220
out_unlock:
221
	mutex_unlock(&dev->struct_mutex);
222
	return ret;
223
}
224
 
225
/** Sets the color ramps on behalf of RandR */
226
static void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
227
				    u16 blue, int regno)
228
{
229
	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
230
 
231
	intel_crtc->lut_r[regno] = red >> 8;
232
	intel_crtc->lut_g[regno] = green >> 8;
233
	intel_crtc->lut_b[regno] = blue >> 8;
234
}
235
 
236
static void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
237
				    u16 *blue, int regno)
238
{
239
	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
240
 
241
	*red = intel_crtc->lut_r[regno] << 8;
242
	*green = intel_crtc->lut_g[regno] << 8;
243
	*blue = intel_crtc->lut_b[regno] << 8;
244
}
245
 
246
static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
247
	.gamma_set = intel_crtc_fb_gamma_set,
248
	.gamma_get = intel_crtc_fb_gamma_get,
249
	.fb_probe = intelfb_create,
250
};
251
 
252
 
253
int intel_fbdev_init(struct drm_device *dev)
254
{
255
	struct intel_fbdev *ifbdev;
256
	struct drm_i915_private *dev_priv = dev->dev_private;
257
	int ret;
258
 
259
	ifbdev = kzalloc(sizeof(*ifbdev), GFP_KERNEL);
260
	if (!ifbdev)
261
		return -ENOMEM;
262
 
263
	dev_priv->fbdev = ifbdev;
264
	ifbdev->helper.funcs = &intel_fb_helper_funcs;
265
 
266
	ret = drm_fb_helper_init(dev, &ifbdev->helper,
267
				 INTEL_INFO(dev)->num_pipes,
268
				 4);
269
	if (ret) {
270
		kfree(ifbdev);
271
		return ret;
272
	}
273
 
274
	drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
275
 
276
    return 0;
277
}
278
 
279
void intel_fbdev_initial_config(struct drm_device *dev)
280
{
281
	struct drm_i915_private *dev_priv = dev->dev_private;
282
 
283
	/* Due to peculiar init order wrt to hpd handling this is separate. */
284
	drm_fb_helper_initial_config(&dev_priv->fbdev->helper, 32);
285
}
286
 
287
 
288
void intel_fbdev_output_poll_changed(struct drm_device *dev)
289
{
290
	struct drm_i915_private *dev_priv = dev->dev_private;
291
	drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
292
}