Subversion Repositories Kolibri OS

Rev

Rev 1246 | Rev 1313 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1246 Rev 1268
1
/*
1
/*
2
 * Copyright (c) 2006-2009 Red Hat Inc.
2
 * Copyright (c) 2006-2009 Red Hat Inc.
3
 * Copyright (c) 2006-2008 Intel Corporation
3
 * Copyright (c) 2006-2008 Intel Corporation
4
 * Copyright (c) 2007 Dave Airlie 
4
 * Copyright (c) 2007 Dave Airlie 
5
 *
5
 *
6
 * DRM framebuffer helper functions
6
 * DRM framebuffer helper functions
7
 *
7
 *
8
 * Permission to use, copy, modify, distribute, and sell this software and its
8
 * Permission to use, copy, modify, distribute, and sell this software and its
9
 * documentation for any purpose is hereby granted without fee, provided that
9
 * documentation for any purpose is hereby granted without fee, provided that
10
 * the above copyright notice appear in all copies and that both that copyright
10
 * the above copyright notice appear in all copies and that both that copyright
11
 * notice and this permission notice appear in supporting documentation, and
11
 * notice and this permission notice appear in supporting documentation, and
12
 * that the name of the copyright holders not be used in advertising or
12
 * that the name of the copyright holders not be used in advertising or
13
 * publicity pertaining to distribution of the software without specific,
13
 * publicity pertaining to distribution of the software without specific,
14
 * written prior permission.  The copyright holders make no representations
14
 * written prior permission.  The copyright holders make no representations
15
 * about the suitability of this software for any purpose.  It is provided "as
15
 * about the suitability of this software for any purpose.  It is provided "as
16
 * is" without express or implied warranty.
16
 * is" without express or implied warranty.
17
 *
17
 *
18
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
19
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
20
 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
20
 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
21
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
22
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
22
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
23
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
23
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
24
 * OF THIS SOFTWARE.
24
 * OF THIS SOFTWARE.
25
 *
25
 *
26
 * Authors:
26
 * Authors:
27
 *      Dave Airlie 
27
 *      Dave Airlie 
28
 *      Jesse Barnes 
28
 *      Jesse Barnes 
29
 */
29
 */
30
//#include 
30
//#include 
31
#include 
31
#include 
32
#include "drmP.h"
32
#include "drmP.h"
33
#include "drm_crtc.h"
33
#include "drm_crtc.h"
34
#include "drm_fb_helper.h"
34
#include "drm_fb_helper.h"
35
#include "drm_crtc_helper.h"
35
#include "drm_crtc_helper.h"
36
 
36
 
37
//MODULE_AUTHOR("David Airlie, Jesse Barnes");
37
//MODULE_AUTHOR("David Airlie, Jesse Barnes");
38
//MODULE_DESCRIPTION("DRM KMS helper");
38
//MODULE_DESCRIPTION("DRM KMS helper");
39
//MODULE_LICENSE("GPL and additional rights");
39
//MODULE_LICENSE("GPL and additional rights");
40
 
40
 
41
static LIST_HEAD(kernel_fb_helper_list);
41
static LIST_HEAD(kernel_fb_helper_list);
42
 
42
 
43
int drm_fb_helper_add_connector(struct drm_connector *connector)
43
int drm_fb_helper_add_connector(struct drm_connector *connector)
44
{
44
{
45
	connector->fb_helper_private = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL);
45
	connector->fb_helper_private = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL);
46
	if (!connector->fb_helper_private)
46
	if (!connector->fb_helper_private)
47
		return -ENOMEM;
47
		return -ENOMEM;
48
 
48
 
49
	return 0;
49
	return 0;
50
}
50
}
51
EXPORT_SYMBOL(drm_fb_helper_add_connector);
51
EXPORT_SYMBOL(drm_fb_helper_add_connector);
52
 
52
 
53
bool drm_fb_helper_force_kernel_mode(void)
53
bool drm_fb_helper_force_kernel_mode(void)
54
{
54
{
55
	int i = 0;
55
	int i = 0;
56
	bool ret, error = false;
56
	bool ret, error = false;
57
	struct drm_fb_helper *helper;
57
	struct drm_fb_helper *helper;
58
 
58
 
59
	if (list_empty(&kernel_fb_helper_list))
59
	if (list_empty(&kernel_fb_helper_list))
60
		return false;
60
		return false;
61
 
61
 
62
	list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
62
	list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
63
		for (i = 0; i < helper->crtc_count; i++) {
63
		for (i = 0; i < helper->crtc_count; i++) {
64
			struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set;
64
			struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set;
65
			ret = drm_crtc_helper_set_config(mode_set);
65
			ret = drm_crtc_helper_set_config(mode_set);
66
			if (ret)
66
			if (ret)
67
				error = true;
67
				error = true;
68
		}
68
		}
69
	}
69
	}
70
	return error;
70
	return error;
71
}
71
}
72
 
72
 
73
/**
73
/**
74
 * drm_fb_helper_restore - restore the framebuffer console (kernel) config
74
 * drm_fb_helper_restore - restore the framebuffer console (kernel) config
75
 *
75
 *
76
 * Restore's the kernel's fbcon mode, used for lastclose & panic paths.
76
 * Restore's the kernel's fbcon mode, used for lastclose & panic paths.
77
 */
77
 */
78
void drm_fb_helper_restore(void)
78
void drm_fb_helper_restore(void)
79
{
79
{
80
	bool ret;
80
	bool ret;
81
	ret = drm_fb_helper_force_kernel_mode();
81
	ret = drm_fb_helper_force_kernel_mode();
82
	if (ret == true)
82
	if (ret == true)
83
		DRM_ERROR("Failed to restore crtc configuration\n");
83
		DRM_ERROR("Failed to restore crtc configuration\n");
84
}
84
}
85
EXPORT_SYMBOL(drm_fb_helper_restore);
85
EXPORT_SYMBOL(drm_fb_helper_restore);
86
 
86
 
87
 
87
 
88
static void drm_fb_helper_on(struct fb_info *info)
88
static void drm_fb_helper_on(struct fb_info *info)
89
{
89
{
90
	struct drm_fb_helper *fb_helper = info->par;
90
	struct drm_fb_helper *fb_helper = info->par;
91
	struct drm_device *dev = fb_helper->dev;
91
	struct drm_device *dev = fb_helper->dev;
92
	struct drm_crtc *crtc;
92
	struct drm_crtc *crtc;
93
	struct drm_encoder *encoder;
93
	struct drm_encoder *encoder;
94
	int i;
94
	int i;
95
 
95
 
96
	/*
96
	/*
97
	 * For each CRTC in this fb, turn the crtc on then,
97
	 * For each CRTC in this fb, turn the crtc on then,
98
	 * find all associated encoders and turn them on.
98
	 * find all associated encoders and turn them on.
99
	 */
99
	 */
100
	for (i = 0; i < fb_helper->crtc_count; i++) {
100
	for (i = 0; i < fb_helper->crtc_count; i++) {
101
		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
101
		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
102
			struct drm_crtc_helper_funcs *crtc_funcs =
102
			struct drm_crtc_helper_funcs *crtc_funcs =
103
				crtc->helper_private;
103
				crtc->helper_private;
104
 
104
 
105
			/* Only mess with CRTCs in this fb */
105
			/* Only mess with CRTCs in this fb */
106
			if (crtc->base.id != fb_helper->crtc_info[i].crtc_id ||
106
			if (crtc->base.id != fb_helper->crtc_info[i].crtc_id ||
107
			    !crtc->enabled)
107
			    !crtc->enabled)
108
				continue;
108
				continue;
109
 
109
 
110
			mutex_lock(&dev->mode_config.mutex);
110
			mutex_lock(&dev->mode_config.mutex);
111
			crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
111
			crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
112
			mutex_unlock(&dev->mode_config.mutex);
112
			mutex_unlock(&dev->mode_config.mutex);
113
 
113
 
114
			/* Found a CRTC on this fb, now find encoders */
114
			/* Found a CRTC on this fb, now find encoders */
115
			list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
115
			list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
116
				if (encoder->crtc == crtc) {
116
				if (encoder->crtc == crtc) {
117
					struct drm_encoder_helper_funcs *encoder_funcs;
117
					struct drm_encoder_helper_funcs *encoder_funcs;
118
 
118
 
119
					encoder_funcs = encoder->helper_private;
119
					encoder_funcs = encoder->helper_private;
120
					mutex_lock(&dev->mode_config.mutex);
120
					mutex_lock(&dev->mode_config.mutex);
121
					encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
121
					encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
122
					mutex_unlock(&dev->mode_config.mutex);
122
					mutex_unlock(&dev->mode_config.mutex);
123
				}
123
				}
124
			}
124
			}
125
		}
125
		}
126
	}
126
	}
127
}
127
}
128
 
128
 
129
static void drm_fb_helper_off(struct fb_info *info, int dpms_mode)
129
static void drm_fb_helper_off(struct fb_info *info, int dpms_mode)
130
{
130
{
131
	struct drm_fb_helper *fb_helper = info->par;
131
	struct drm_fb_helper *fb_helper = info->par;
132
	struct drm_device *dev = fb_helper->dev;
132
	struct drm_device *dev = fb_helper->dev;
133
	struct drm_crtc *crtc;
133
	struct drm_crtc *crtc;
134
	struct drm_encoder *encoder;
134
	struct drm_encoder *encoder;
135
	int i;
135
	int i;
136
 
136
 
137
	/*
137
	/*
138
	 * For each CRTC in this fb, find all associated encoders
138
	 * For each CRTC in this fb, find all associated encoders
139
	 * and turn them off, then turn off the CRTC.
139
	 * and turn them off, then turn off the CRTC.
140
	 */
140
	 */
141
	for (i = 0; i < fb_helper->crtc_count; i++) {
141
	for (i = 0; i < fb_helper->crtc_count; i++) {
142
		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
142
		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
143
			struct drm_crtc_helper_funcs *crtc_funcs =
143
			struct drm_crtc_helper_funcs *crtc_funcs =
144
				crtc->helper_private;
144
				crtc->helper_private;
145
 
145
 
146
			/* Only mess with CRTCs in this fb */
146
			/* Only mess with CRTCs in this fb */
147
			if (crtc->base.id != fb_helper->crtc_info[i].crtc_id ||
147
			if (crtc->base.id != fb_helper->crtc_info[i].crtc_id ||
148
			    !crtc->enabled)
148
			    !crtc->enabled)
149
				continue;
149
				continue;
150
 
150
 
151
			/* Found a CRTC on this fb, now find encoders */
151
			/* Found a CRTC on this fb, now find encoders */
152
			list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
152
			list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
153
				if (encoder->crtc == crtc) {
153
				if (encoder->crtc == crtc) {
154
					struct drm_encoder_helper_funcs *encoder_funcs;
154
					struct drm_encoder_helper_funcs *encoder_funcs;
155
 
155
 
156
					encoder_funcs = encoder->helper_private;
156
					encoder_funcs = encoder->helper_private;
157
					mutex_lock(&dev->mode_config.mutex);
157
					mutex_lock(&dev->mode_config.mutex);
158
					encoder_funcs->dpms(encoder, dpms_mode);
158
					encoder_funcs->dpms(encoder, dpms_mode);
159
					mutex_unlock(&dev->mode_config.mutex);
159
					mutex_unlock(&dev->mode_config.mutex);
160
				}
160
				}
161
			}
161
			}
162
			if (dpms_mode == DRM_MODE_DPMS_OFF) {
162
			if (dpms_mode == DRM_MODE_DPMS_OFF) {
163
				mutex_lock(&dev->mode_config.mutex);
163
				mutex_lock(&dev->mode_config.mutex);
164
				crtc_funcs->dpms(crtc, dpms_mode);
164
				crtc_funcs->dpms(crtc, dpms_mode);
165
				mutex_unlock(&dev->mode_config.mutex);
165
				mutex_unlock(&dev->mode_config.mutex);
166
			}
166
			}
167
		}
167
		}
168
	}
168
	}
169
}
169
}
170
 
170
 
171
int drm_fb_helper_blank(int blank, struct fb_info *info)
171
int drm_fb_helper_blank(int blank, struct fb_info *info)
172
{
172
{
173
	switch (blank) {
173
	switch (blank) {
174
	case FB_BLANK_UNBLANK:
174
	case FB_BLANK_UNBLANK:
175
		drm_fb_helper_on(info);
175
		drm_fb_helper_on(info);
176
		break;
176
		break;
177
	case FB_BLANK_NORMAL:
177
	case FB_BLANK_NORMAL:
178
		drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY);
178
		drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY);
179
		break;
179
		break;
180
	case FB_BLANK_HSYNC_SUSPEND:
180
	case FB_BLANK_HSYNC_SUSPEND:
181
		drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY);
181
		drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY);
182
		break;
182
		break;
183
	case FB_BLANK_VSYNC_SUSPEND:
183
	case FB_BLANK_VSYNC_SUSPEND:
184
		drm_fb_helper_off(info, DRM_MODE_DPMS_SUSPEND);
184
		drm_fb_helper_off(info, DRM_MODE_DPMS_SUSPEND);
185
		break;
185
		break;
186
	case FB_BLANK_POWERDOWN:
186
	case FB_BLANK_POWERDOWN:
187
		drm_fb_helper_off(info, DRM_MODE_DPMS_OFF);
187
		drm_fb_helper_off(info, DRM_MODE_DPMS_OFF);
188
		break;
188
		break;
189
	}
189
	}
190
	return 0;
190
	return 0;
191
}
191
}
192
EXPORT_SYMBOL(drm_fb_helper_blank);
192
EXPORT_SYMBOL(drm_fb_helper_blank);
193
 
193
 
194
static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
194
static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
195
{
195
{
196
	int i;
196
	int i;
197
 
197
 
198
	for (i = 0; i < helper->crtc_count; i++)
198
	for (i = 0; i < helper->crtc_count; i++)
199
		kfree(helper->crtc_info[i].mode_set.connectors);
199
		kfree(helper->crtc_info[i].mode_set.connectors);
200
	kfree(helper->crtc_info);
200
	kfree(helper->crtc_info);
201
}
201
}
202
 
202
 
203
int drm_fb_helper_init_crtc_count(struct drm_fb_helper *helper, int crtc_count, int max_conn_count)
203
int drm_fb_helper_init_crtc_count(struct drm_fb_helper *helper, int crtc_count, int max_conn_count)
204
{
204
{
205
	struct drm_device *dev = helper->dev;
205
	struct drm_device *dev = helper->dev;
206
	struct drm_crtc *crtc;
206
	struct drm_crtc *crtc;
207
	int ret = 0;
207
	int ret = 0;
208
	int i;
208
	int i;
209
 
209
 
210
	helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL);
210
	helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL);
211
	if (!helper->crtc_info)
211
	if (!helper->crtc_info)
212
		return -ENOMEM;
212
		return -ENOMEM;
213
 
213
 
214
	helper->crtc_count = crtc_count;
214
	helper->crtc_count = crtc_count;
215
 
215
 
216
	for (i = 0; i < crtc_count; i++) {
216
	for (i = 0; i < crtc_count; i++) {
217
		helper->crtc_info[i].mode_set.connectors =
217
		helper->crtc_info[i].mode_set.connectors =
218
			kcalloc(max_conn_count,
218
			kcalloc(max_conn_count,
219
				sizeof(struct drm_connector *),
219
				sizeof(struct drm_connector *),
220
				GFP_KERNEL);
220
				GFP_KERNEL);
221
 
221
 
222
		if (!helper->crtc_info[i].mode_set.connectors) {
222
		if (!helper->crtc_info[i].mode_set.connectors) {
223
			ret = -ENOMEM;
223
			ret = -ENOMEM;
224
			goto out_free;
224
			goto out_free;
225
		}
225
		}
226
		helper->crtc_info[i].mode_set.num_connectors = 0;
226
		helper->crtc_info[i].mode_set.num_connectors = 0;
227
	}
227
	}
228
 
228
 
229
	i = 0;
229
	i = 0;
230
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
230
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
231
		helper->crtc_info[i].crtc_id = crtc->base.id;
231
		helper->crtc_info[i].crtc_id = crtc->base.id;
232
		helper->crtc_info[i].mode_set.crtc = crtc;
232
		helper->crtc_info[i].mode_set.crtc = crtc;
233
		i++;
233
		i++;
234
	}
234
	}
235
	helper->conn_limit = max_conn_count;
235
	helper->conn_limit = max_conn_count;
236
	return 0;
236
	return 0;
237
out_free:
237
out_free:
238
	drm_fb_helper_crtc_free(helper);
238
	drm_fb_helper_crtc_free(helper);
239
	return -ENOMEM;
239
	return -ENOMEM;
240
}
240
}
241
EXPORT_SYMBOL(drm_fb_helper_init_crtc_count);
241
EXPORT_SYMBOL(drm_fb_helper_init_crtc_count);
242
 
242
 
243
static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
243
static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
244
		     u16 blue, u16 regno, struct fb_info *info)
244
		     u16 blue, u16 regno, struct fb_info *info)
245
{
245
{
246
	struct drm_fb_helper *fb_helper = info->par;
246
	struct drm_fb_helper *fb_helper = info->par;
247
	struct drm_framebuffer *fb = fb_helper->fb;
247
	struct drm_framebuffer *fb = fb_helper->fb;
248
	int pindex;
248
	int pindex;
249
 
249
 
250
	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
250
	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
251
		u32 *palette;
251
		u32 *palette;
252
		u32 value;
252
		u32 value;
253
		/* place color in psuedopalette */
253
		/* place color in psuedopalette */
254
		if (regno > 16)
254
		if (regno > 16)
255
			return -EINVAL;
255
			return -EINVAL;
256
		palette = (u32 *)info->pseudo_palette;
256
		palette = (u32 *)info->pseudo_palette;
257
		red >>= (16 - info->var.red.length);
257
		red >>= (16 - info->var.red.length);
258
		green >>= (16 - info->var.green.length);
258
		green >>= (16 - info->var.green.length);
259
		blue >>= (16 - info->var.blue.length);
259
		blue >>= (16 - info->var.blue.length);
260
		value = (red << info->var.red.offset) |
260
		value = (red << info->var.red.offset) |
261
			(green << info->var.green.offset) |
261
			(green << info->var.green.offset) |
262
			(blue << info->var.blue.offset);
262
			(blue << info->var.blue.offset);
263
		palette[regno] = value;
263
		palette[regno] = value;
264
		return 0;
264
		return 0;
265
	}
265
	}
266
 
266
 
267
	pindex = regno;
267
	pindex = regno;
268
 
268
 
269
	if (fb->bits_per_pixel == 16) {
269
	if (fb->bits_per_pixel == 16) {
270
		pindex = regno << 3;
270
		pindex = regno << 3;
271
 
271
 
272
		if (fb->depth == 16 && regno > 63)
272
		if (fb->depth == 16 && regno > 63)
273
			return -EINVAL;
273
			return -EINVAL;
274
		if (fb->depth == 15 && regno > 31)
274
		if (fb->depth == 15 && regno > 31)
275
			return -EINVAL;
275
			return -EINVAL;
276
 
276
 
277
		if (fb->depth == 16) {
277
		if (fb->depth == 16) {
278
			u16 r, g, b;
278
			u16 r, g, b;
279
			int i;
279
			int i;
280
			if (regno < 32) {
280
			if (regno < 32) {
281
				for (i = 0; i < 8; i++)
281
				for (i = 0; i < 8; i++)
282
					fb_helper->funcs->gamma_set(crtc, red,
282
					fb_helper->funcs->gamma_set(crtc, red,
283
						green, blue, pindex + i);
283
						green, blue, pindex + i);
284
			}
284
			}
285
 
285
 
286
			fb_helper->funcs->gamma_get(crtc, &r,
286
			fb_helper->funcs->gamma_get(crtc, &r,
287
						    &g, &b,
287
						    &g, &b,
288
						    pindex >> 1);
288
						    pindex >> 1);
289
 
289
 
290
			for (i = 0; i < 4; i++)
290
			for (i = 0; i < 4; i++)
291
				fb_helper->funcs->gamma_set(crtc, r,
291
				fb_helper->funcs->gamma_set(crtc, r,
292
							    green, b,
292
							    green, b,
293
							    (pindex >> 1) + i);
293
							    (pindex >> 1) + i);
294
		}
294
		}
295
	}
295
	}
296
 
296
 
297
	if (fb->depth != 16)
297
	if (fb->depth != 16)
298
		fb_helper->funcs->gamma_set(crtc, red, green, blue, pindex);
298
		fb_helper->funcs->gamma_set(crtc, red, green, blue, pindex);
299
	return 0;
299
	return 0;
300
}
300
}
301
 
301
 
302
int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
302
int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
303
{
303
{
304
	struct drm_fb_helper *fb_helper = info->par;
304
	struct drm_fb_helper *fb_helper = info->par;
305
	struct drm_device *dev = fb_helper->dev;
305
	struct drm_device *dev = fb_helper->dev;
306
	u16 *red, *green, *blue, *transp;
306
	u16 *red, *green, *blue, *transp;
307
	struct drm_crtc *crtc;
307
	struct drm_crtc *crtc;
308
	int i, rc = 0;
308
	int i, rc = 0;
309
	int start;
309
	int start;
310
 
310
 
311
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
311
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
312
		struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
312
		struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
313
		for (i = 0; i < fb_helper->crtc_count; i++) {
313
		for (i = 0; i < fb_helper->crtc_count; i++) {
314
			if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
314
			if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
315
				break;
315
				break;
316
		}
316
		}
317
		if (i == fb_helper->crtc_count)
317
		if (i == fb_helper->crtc_count)
318
			continue;
318
			continue;
319
 
319
 
320
		red = cmap->red;
320
		red = cmap->red;
321
		green = cmap->green;
321
		green = cmap->green;
322
		blue = cmap->blue;
322
		blue = cmap->blue;
323
		transp = cmap->transp;
323
		transp = cmap->transp;
324
		start = cmap->start;
324
		start = cmap->start;
325
 
325
 
326
		for (i = 0; i < cmap->len; i++) {
326
		for (i = 0; i < cmap->len; i++) {
327
			u16 hred, hgreen, hblue, htransp = 0xffff;
327
			u16 hred, hgreen, hblue, htransp = 0xffff;
328
 
328
 
329
			hred = *red++;
329
			hred = *red++;
330
			hgreen = *green++;
330
			hgreen = *green++;
331
			hblue = *blue++;
331
			hblue = *blue++;
332
 
332
 
333
			if (transp)
333
			if (transp)
334
				htransp = *transp++;
334
				htransp = *transp++;
335
 
335
 
336
			rc = setcolreg(crtc, hred, hgreen, hblue, start++, info);
336
			rc = setcolreg(crtc, hred, hgreen, hblue, start++, info);
337
			if (rc)
337
			if (rc)
338
				return rc;
338
				return rc;
339
		}
339
		}
340
		crtc_funcs->load_lut(crtc);
340
		crtc_funcs->load_lut(crtc);
341
	}
341
	}
342
	return rc;
342
	return rc;
343
}
343
}
344
EXPORT_SYMBOL(drm_fb_helper_setcmap);
344
EXPORT_SYMBOL(drm_fb_helper_setcmap);
345
 
345
 
346
int drm_fb_helper_setcolreg(unsigned regno,
346
int drm_fb_helper_setcolreg(unsigned regno,
347
			    unsigned red,
347
			    unsigned red,
348
			    unsigned green,
348
			    unsigned green,
349
			    unsigned blue,
349
			    unsigned blue,
350
			    unsigned transp,
350
			    unsigned transp,
351
			    struct fb_info *info)
351
			    struct fb_info *info)
352
{
352
{
353
	struct drm_fb_helper *fb_helper = info->par;
353
	struct drm_fb_helper *fb_helper = info->par;
354
	struct drm_device *dev = fb_helper->dev;
354
	struct drm_device *dev = fb_helper->dev;
355
	struct drm_crtc *crtc;
355
	struct drm_crtc *crtc;
356
	int i;
356
	int i;
357
	int ret;
357
	int ret;
358
 
358
 
359
	if (regno > 255)
359
	if (regno > 255)
360
		return 1;
360
		return 1;
361
 
361
 
362
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
362
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
363
		struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
363
		struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
364
		for (i = 0; i < fb_helper->crtc_count; i++) {
364
		for (i = 0; i < fb_helper->crtc_count; i++) {
365
			if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
365
			if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
366
				break;
366
				break;
367
		}
367
		}
368
		if (i == fb_helper->crtc_count)
368
		if (i == fb_helper->crtc_count)
369
			continue;
369
			continue;
370
 
370
 
371
		ret = setcolreg(crtc, red, green, blue, regno, info);
371
		ret = setcolreg(crtc, red, green, blue, regno, info);
372
		if (ret)
372
		if (ret)
373
			return ret;
373
			return ret;
374
 
374
 
375
		crtc_funcs->load_lut(crtc);
375
		crtc_funcs->load_lut(crtc);
376
	}
376
	}
377
	return 0;
377
	return 0;
378
}
378
}
379
EXPORT_SYMBOL(drm_fb_helper_setcolreg);
379
EXPORT_SYMBOL(drm_fb_helper_setcolreg);
380
 
380
 
381
int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
381
int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
382
			    struct fb_info *info)
382
			    struct fb_info *info)
383
{
383
{
384
	struct drm_fb_helper *fb_helper = info->par;
384
	struct drm_fb_helper *fb_helper = info->par;
385
	struct drm_framebuffer *fb = fb_helper->fb;
385
	struct drm_framebuffer *fb = fb_helper->fb;
386
	int depth;
386
	int depth;
387
 
387
 
388
	if (var->pixclock == -1 || !var->pixclock)
388
	if (var->pixclock == -1 || !var->pixclock)
389
		return -EINVAL;
389
		return -EINVAL;
390
 
390
 
391
	/* Need to resize the fb object !!! */
391
	/* Need to resize the fb object !!! */
392
	if (var->xres > fb->width || var->yres > fb->height) {
392
	if (var->xres > fb->width || var->yres > fb->height) {
393
		DRM_ERROR("Requested width/height is greater than current fb "
393
		DRM_ERROR("Requested width/height is greater than current fb "
394
			   "object %dx%d > %dx%d\n", var->xres, var->yres,
394
			   "object %dx%d > %dx%d\n", var->xres, var->yres,
395
			   fb->width, fb->height);
395
			   fb->width, fb->height);
396
		DRM_ERROR("Need resizing code.\n");
396
		DRM_ERROR("Need resizing code.\n");
397
		return -EINVAL;
397
		return -EINVAL;
398
	}
398
	}
399
 
399
 
400
	switch (var->bits_per_pixel) {
400
	switch (var->bits_per_pixel) {
401
	case 16:
401
	case 16:
402
		depth = (var->green.length == 6) ? 16 : 15;
402
		depth = (var->green.length == 6) ? 16 : 15;
403
		break;
403
		break;
404
	case 32:
404
	case 32:
405
		depth = (var->transp.length > 0) ? 32 : 24;
405
		depth = (var->transp.length > 0) ? 32 : 24;
406
		break;
406
		break;
407
	default:
407
	default:
408
		depth = var->bits_per_pixel;
408
		depth = var->bits_per_pixel;
409
		break;
409
		break;
410
	}
410
	}
411
 
411
 
412
	switch (depth) {
412
	switch (depth) {
413
	case 8:
413
	case 8:
414
		var->red.offset = 0;
414
		var->red.offset = 0;
415
		var->green.offset = 0;
415
		var->green.offset = 0;
416
		var->blue.offset = 0;
416
		var->blue.offset = 0;
417
		var->red.length = 8;
417
		var->red.length = 8;
418
		var->green.length = 8;
418
		var->green.length = 8;
419
		var->blue.length = 8;
419
		var->blue.length = 8;
420
		var->transp.length = 0;
420
		var->transp.length = 0;
421
		var->transp.offset = 0;
421
		var->transp.offset = 0;
422
		break;
422
		break;
423
	case 15:
423
	case 15:
424
		var->red.offset = 10;
424
		var->red.offset = 10;
425
		var->green.offset = 5;
425
		var->green.offset = 5;
426
		var->blue.offset = 0;
426
		var->blue.offset = 0;
427
		var->red.length = 5;
427
		var->red.length = 5;
428
		var->green.length = 5;
428
		var->green.length = 5;
429
		var->blue.length = 5;
429
		var->blue.length = 5;
430
		var->transp.length = 1;
430
		var->transp.length = 1;
431
		var->transp.offset = 15;
431
		var->transp.offset = 15;
432
		break;
432
		break;
433
	case 16:
433
	case 16:
434
		var->red.offset = 11;
434
		var->red.offset = 11;
435
		var->green.offset = 5;
435
		var->green.offset = 5;
436
		var->blue.offset = 0;
436
		var->blue.offset = 0;
437
		var->red.length = 5;
437
		var->red.length = 5;
438
		var->green.length = 6;
438
		var->green.length = 6;
439
		var->blue.length = 5;
439
		var->blue.length = 5;
440
		var->transp.length = 0;
440
		var->transp.length = 0;
441
		var->transp.offset = 0;
441
		var->transp.offset = 0;
442
		break;
442
		break;
443
	case 24:
443
	case 24:
444
		var->red.offset = 16;
444
		var->red.offset = 16;
445
		var->green.offset = 8;
445
		var->green.offset = 8;
446
		var->blue.offset = 0;
446
		var->blue.offset = 0;
447
		var->red.length = 8;
447
		var->red.length = 8;
448
		var->green.length = 8;
448
		var->green.length = 8;
449
		var->blue.length = 8;
449
		var->blue.length = 8;
450
		var->transp.length = 0;
450
		var->transp.length = 0;
451
		var->transp.offset = 0;
451
		var->transp.offset = 0;
452
		break;
452
		break;
453
	case 32:
453
	case 32:
454
		var->red.offset = 16;
454
		var->red.offset = 16;
455
		var->green.offset = 8;
455
		var->green.offset = 8;
456
		var->blue.offset = 0;
456
		var->blue.offset = 0;
457
		var->red.length = 8;
457
		var->red.length = 8;
458
		var->green.length = 8;
458
		var->green.length = 8;
459
		var->blue.length = 8;
459
		var->blue.length = 8;
460
		var->transp.length = 8;
460
		var->transp.length = 8;
461
		var->transp.offset = 24;
461
		var->transp.offset = 24;
462
		break;
462
		break;
463
	default:
463
	default:
464
		return -EINVAL;
464
		return -EINVAL;
465
	}
465
	}
466
	return 0;
466
	return 0;
467
}
467
}
468
EXPORT_SYMBOL(drm_fb_helper_check_var);
468
EXPORT_SYMBOL(drm_fb_helper_check_var);
469
 
469
 
470
/* this will let fbcon do the mode init */
470
/* this will let fbcon do the mode init */
471
int drm_fb_helper_set_par(struct fb_info *info)
471
int drm_fb_helper_set_par(struct fb_info *info)
472
{
472
{
473
	struct drm_fb_helper *fb_helper = info->par;
473
	struct drm_fb_helper *fb_helper = info->par;
474
	struct drm_device *dev = fb_helper->dev;
474
	struct drm_device *dev = fb_helper->dev;
475
	struct fb_var_screeninfo *var = &info->var;
475
	struct fb_var_screeninfo *var = &info->var;
476
	struct drm_crtc *crtc;
476
	struct drm_crtc *crtc;
477
	int ret;
477
	int ret;
478
	int i;
478
	int i;
479
 
479
 
480
	if (var->pixclock != -1) {
480
	if (var->pixclock != -1) {
481
		DRM_ERROR("PIXEL CLCOK SET\n");
481
		DRM_ERROR("PIXEL CLCOK SET\n");
482
		return -EINVAL;
482
		return -EINVAL;
483
	}
483
	}
484
 
484
 
485
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
485
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
486
 
486
 
487
		for (i = 0; i < fb_helper->crtc_count; i++) {
487
		for (i = 0; i < fb_helper->crtc_count; i++) {
488
			if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
488
			if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
489
				break;
489
				break;
490
		}
490
		}
491
		if (i == fb_helper->crtc_count)
491
		if (i == fb_helper->crtc_count)
492
			continue;
492
			continue;
493
 
493
 
494
		if (crtc->fb == fb_helper->crtc_info[i].mode_set.fb) {
494
		if (crtc->fb == fb_helper->crtc_info[i].mode_set.fb) {
495
			mutex_lock(&dev->mode_config.mutex);
495
			mutex_lock(&dev->mode_config.mutex);
496
			ret = crtc->funcs->set_config(&fb_helper->crtc_info->mode_set);
496
			ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set);
497
			mutex_unlock(&dev->mode_config.mutex);
497
			mutex_unlock(&dev->mode_config.mutex);
498
			if (ret)
498
			if (ret)
499
				return ret;
499
				return ret;
500
		}
500
		}
501
	}
501
	}
502
	return 0;
502
	return 0;
503
}
503
}
504
EXPORT_SYMBOL(drm_fb_helper_set_par);
504
EXPORT_SYMBOL(drm_fb_helper_set_par);
505
 
505
 
506
int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
506
int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
507
			      struct fb_info *info)
507
			      struct fb_info *info)
508
{
508
{
509
	struct drm_fb_helper *fb_helper = info->par;
509
	struct drm_fb_helper *fb_helper = info->par;
510
	struct drm_device *dev = fb_helper->dev;
510
	struct drm_device *dev = fb_helper->dev;
511
	struct drm_mode_set *modeset;
511
	struct drm_mode_set *modeset;
512
	struct drm_crtc *crtc;
512
	struct drm_crtc *crtc;
513
	int ret = 0;
513
	int ret = 0;
514
	int i;
514
	int i;
515
 
515
 
516
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
516
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
517
		for (i = 0; i < fb_helper->crtc_count; i++) {
517
		for (i = 0; i < fb_helper->crtc_count; i++) {
518
			if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
518
			if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
519
				break;
519
				break;
520
		}
520
		}
521
 
521
 
522
		if (i == fb_helper->crtc_count)
522
		if (i == fb_helper->crtc_count)
523
			continue;
523
			continue;
524
 
524
 
525
		modeset = &fb_helper->crtc_info[i].mode_set;
525
		modeset = &fb_helper->crtc_info[i].mode_set;
526
 
526
 
527
		modeset->x = var->xoffset;
527
		modeset->x = var->xoffset;
528
		modeset->y = var->yoffset;
528
		modeset->y = var->yoffset;
529
 
529
 
530
		if (modeset->num_connectors) {
530
		if (modeset->num_connectors) {
531
			mutex_lock(&dev->mode_config.mutex);
531
			mutex_lock(&dev->mode_config.mutex);
532
			ret = crtc->funcs->set_config(modeset);
532
			ret = crtc->funcs->set_config(modeset);
533
			mutex_unlock(&dev->mode_config.mutex);
533
			mutex_unlock(&dev->mode_config.mutex);
534
			if (!ret) {
534
			if (!ret) {
535
				info->var.xoffset = var->xoffset;
535
				info->var.xoffset = var->xoffset;
536
				info->var.yoffset = var->yoffset;
536
				info->var.yoffset = var->yoffset;
537
			}
537
			}
538
		}
538
		}
539
	}
539
	}
540
	return ret;
540
	return ret;
541
}
541
}
542
EXPORT_SYMBOL(drm_fb_helper_pan_display);
542
EXPORT_SYMBOL(drm_fb_helper_pan_display);
543
 
543
 
544
int drm_fb_helper_single_fb_probe(struct drm_device *dev,
544
int drm_fb_helper_single_fb_probe(struct drm_device *dev,
545
				  int preferred_bpp,
545
				  int preferred_bpp,
546
				  int (*fb_create)(struct drm_device *dev,
546
				  int (*fb_create)(struct drm_device *dev,
547
						   uint32_t fb_width,
547
						   uint32_t fb_width,
548
						   uint32_t fb_height,
548
						   uint32_t fb_height,
549
						   uint32_t surface_width,
549
						   uint32_t surface_width,
550
						   uint32_t surface_height,
550
						   uint32_t surface_height,
551
						   uint32_t surface_depth,
551
						   uint32_t surface_depth,
552
						   uint32_t surface_bpp,
552
						   uint32_t surface_bpp,
553
						   struct drm_framebuffer **fb_ptr))
553
						   struct drm_framebuffer **fb_ptr))
554
{
554
{
555
	struct drm_crtc *crtc;
555
	struct drm_crtc *crtc;
556
	struct drm_connector *connector;
556
	struct drm_connector *connector;
557
	unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1;
557
	unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1;
558
	unsigned int surface_width = 0, surface_height = 0;
558
	unsigned int surface_width = 0, surface_height = 0;
559
	int new_fb = 0;
559
	int new_fb = 0;
560
	int crtc_count = 0;
560
	int crtc_count = 0;
561
	int ret, i, conn_count = 0;
561
	int ret, i, conn_count = 0;
562
	struct fb_info *info;
562
	struct fb_info *info;
563
	struct drm_framebuffer *fb;
563
	struct drm_framebuffer *fb;
564
	struct drm_mode_set *modeset = NULL;
564
	struct drm_mode_set *modeset = NULL;
565
	struct drm_fb_helper *fb_helper;
565
	struct drm_fb_helper *fb_helper;
566
	uint32_t surface_depth = 24, surface_bpp = 32;
566
	uint32_t surface_depth = 24, surface_bpp = 32;
567
 
567
 
568
	/* if driver picks 8 or 16 by default use that
568
	/* if driver picks 8 or 16 by default use that
569
	   for both depth/bpp */
569
	   for both depth/bpp */
570
	if (preferred_bpp != surface_bpp) {
570
	if (preferred_bpp != surface_bpp) {
571
		surface_depth = surface_bpp = preferred_bpp;
571
		surface_depth = surface_bpp = preferred_bpp;
572
	}
572
	}
573
	/* first up get a count of crtcs now in use and new min/maxes width/heights */
573
	/* first up get a count of crtcs now in use and new min/maxes width/heights */
574
	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
574
	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
575
		struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
575
		struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
576
 
576
 
577
		struct drm_fb_helper_cmdline_mode *cmdline_mode;
577
		struct drm_fb_helper_cmdline_mode *cmdline_mode;
578
 
578
 
579
		if (!fb_help_conn)
579
		if (!fb_help_conn)
580
			continue;
580
			continue;
581
		
581
		
582
		cmdline_mode = &fb_help_conn->cmdline_mode;
582
		cmdline_mode = &fb_help_conn->cmdline_mode;
583
 
583
 
584
		if (cmdline_mode->bpp_specified) {
584
		if (cmdline_mode->bpp_specified) {
585
			switch (cmdline_mode->bpp) {
585
			switch (cmdline_mode->bpp) {
586
			case 8:
586
			case 8:
587
				surface_depth = surface_bpp = 8;
587
				surface_depth = surface_bpp = 8;
588
				break;
588
				break;
589
			case 15:
589
			case 15:
590
				surface_depth = 15;
590
				surface_depth = 15;
591
				surface_bpp = 16;
591
				surface_bpp = 16;
592
				break;
592
				break;
593
			case 16:
593
			case 16:
594
				surface_depth = surface_bpp = 16;
594
				surface_depth = surface_bpp = 16;
595
				break;
595
				break;
596
			case 24:
596
			case 24:
597
				surface_depth = surface_bpp = 24;
597
				surface_depth = surface_bpp = 24;
598
				break;
598
				break;
599
			case 32:
599
			case 32:
600
				surface_depth = 24;
600
				surface_depth = 24;
601
				surface_bpp = 32;
601
				surface_bpp = 32;
602
				break;
602
				break;
603
			}
603
			}
604
			break;
604
			break;
605
		}
605
		}
606
	}
606
	}
607
 
607
 
608
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
608
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
609
		if (drm_helper_crtc_in_use(crtc)) {
609
		if (drm_helper_crtc_in_use(crtc)) {
610
			if (crtc->desired_mode) {
610
			if (crtc->desired_mode) {
611
				if (crtc->desired_mode->hdisplay < fb_width)
611
				if (crtc->desired_mode->hdisplay < fb_width)
612
					fb_width = crtc->desired_mode->hdisplay;
612
					fb_width = crtc->desired_mode->hdisplay;
613
 
613
 
614
				if (crtc->desired_mode->vdisplay < fb_height)
614
				if (crtc->desired_mode->vdisplay < fb_height)
615
					fb_height = crtc->desired_mode->vdisplay;
615
					fb_height = crtc->desired_mode->vdisplay;
616
 
616
 
617
				if (crtc->desired_mode->hdisplay > surface_width)
617
				if (crtc->desired_mode->hdisplay > surface_width)
618
					surface_width = crtc->desired_mode->hdisplay;
618
					surface_width = crtc->desired_mode->hdisplay;
619
 
619
 
620
				if (crtc->desired_mode->vdisplay > surface_height)
620
				if (crtc->desired_mode->vdisplay > surface_height)
621
					surface_height = crtc->desired_mode->vdisplay;
621
					surface_height = crtc->desired_mode->vdisplay;
622
			}
622
			}
623
			crtc_count++;
623
			crtc_count++;
624
		}
624
		}
625
	}
625
	}
626
 
626
 
627
	if (crtc_count == 0 || fb_width == -1 || fb_height == -1) {
627
	if (crtc_count == 0 || fb_width == -1 || fb_height == -1) {
628
		/* hmm everyone went away - assume VGA cable just fell out
628
		/* hmm everyone went away - assume VGA cable just fell out
629
		   and will come back later. */
629
		   and will come back later. */
630
		return 0;
630
		return 0;
631
	}
631
	}
632
 
632
 
633
	/* do we have an fb already? */
633
	/* do we have an fb already? */
634
	if (list_empty(&dev->mode_config.fb_kernel_list)) {
634
	if (list_empty(&dev->mode_config.fb_kernel_list)) {
635
		ret = (*fb_create)(dev, fb_width, fb_height, surface_width,
635
		ret = (*fb_create)(dev, fb_width, fb_height, surface_width,
636
				   surface_height, surface_depth, surface_bpp,
636
				   surface_height, surface_depth, surface_bpp,
637
				   &fb);
637
				   &fb);
638
		if (ret)
638
		if (ret)
639
			return -EINVAL;
639
			return -EINVAL;
640
		new_fb = 1;
640
		new_fb = 1;
641
	} else {
641
	} else {
642
		fb = list_first_entry(&dev->mode_config.fb_kernel_list,
642
		fb = list_first_entry(&dev->mode_config.fb_kernel_list,
643
				      struct drm_framebuffer, filp_head);
643
				      struct drm_framebuffer, filp_head);
644
 
644
 
645
		/* if someone hotplugs something bigger than we have already allocated, we are pwned.
645
		/* if someone hotplugs something bigger than we have already allocated, we are pwned.
646
		   As really we can't resize an fbdev that is in the wild currently due to fbdev
646
		   As really we can't resize an fbdev that is in the wild currently due to fbdev
647
		   not really being designed for the lower layers moving stuff around under it.
647
		   not really being designed for the lower layers moving stuff around under it.
648
		   - so in the grand style of things - punt. */
648
		   - so in the grand style of things - punt. */
649
		if ((fb->width < surface_width) ||
649
		if ((fb->width < surface_width) ||
650
		    (fb->height < surface_height)) {
650
		    (fb->height < surface_height)) {
651
			DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
651
			DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
652
			return -EINVAL;
652
			return -EINVAL;
653
		}
653
		}
654
	}
654
	}
655
 
655
 
656
	info = fb->fbdev;
656
	info = fb->fbdev;
657
	fb_helper = info->par;
657
	fb_helper = info->par;
658
 
658
 
659
	crtc_count = 0;
659
	crtc_count = 0;
660
	/* okay we need to setup new connector sets in the crtcs */
660
	/* okay we need to setup new connector sets in the crtcs */
661
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
661
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
662
		modeset = &fb_helper->crtc_info[crtc_count].mode_set;
662
		modeset = &fb_helper->crtc_info[crtc_count].mode_set;
663
		modeset->fb = fb;
663
		modeset->fb = fb;
664
		conn_count = 0;
664
		conn_count = 0;
665
		list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
665
		list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
666
			if (connector->encoder)
666
			if (connector->encoder)
667
				if (connector->encoder->crtc == modeset->crtc) {
667
				if (connector->encoder->crtc == modeset->crtc) {
668
					modeset->connectors[conn_count] = connector;
668
					modeset->connectors[conn_count] = connector;
669
					conn_count++;
669
					conn_count++;
670
					if (conn_count > fb_helper->conn_limit)
670
					if (conn_count > fb_helper->conn_limit)
671
						BUG();
671
						BUG();
672
				}
672
				}
673
		}
673
		}
674
 
674
 
675
		for (i = conn_count; i < fb_helper->conn_limit; i++)
675
		for (i = conn_count; i < fb_helper->conn_limit; i++)
676
			modeset->connectors[i] = NULL;
676
			modeset->connectors[i] = NULL;
677
 
677
 
678
		modeset->crtc = crtc;
678
		modeset->crtc = crtc;
679
		crtc_count++;
679
		crtc_count++;
680
 
680
 
681
		modeset->num_connectors = conn_count;
681
		modeset->num_connectors = conn_count;
682
		if (modeset->crtc->desired_mode) {
682
		if (modeset->crtc->desired_mode) {
683
			if (modeset->mode)
683
			if (modeset->mode)
684
				drm_mode_destroy(dev, modeset->mode);
684
				drm_mode_destroy(dev, modeset->mode);
685
			modeset->mode = drm_mode_duplicate(dev,
685
			modeset->mode = drm_mode_duplicate(dev,
686
							   modeset->crtc->desired_mode);
686
							   modeset->crtc->desired_mode);
687
		}
687
		}
688
	}
688
	}
689
	fb_helper->crtc_count = crtc_count;
689
	fb_helper->crtc_count = crtc_count;
690
	fb_helper->fb = fb;
690
	fb_helper->fb = fb;
691
 
691
 
692
	if (new_fb) {
692
	if (new_fb) {
693
		info->var.pixclock = -1;
693
		info->var.pixclock = -1;
694
//       if (register_framebuffer(info) < 0)
694
//       if (register_framebuffer(info) < 0)
695
//           return -EINVAL;
695
//           return -EINVAL;
696
	} else {
696
	} else {
697
		drm_fb_helper_set_par(info);
697
		drm_fb_helper_set_par(info);
698
	}
698
	}
699
	printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
699
	printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
700
	       info->fix.id);
700
	       info->fix.id);
701
 
701
 
702
	/* Switch back to kernel console on panic */
702
	/* Switch back to kernel console on panic */
703
	/* multi card linked list maybe */
703
	/* multi card linked list maybe */
704
	list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
704
	list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
705
	return 0;
705
	return 0;
706
}
706
}
707
EXPORT_SYMBOL(drm_fb_helper_single_fb_probe);
707
EXPORT_SYMBOL(drm_fb_helper_single_fb_probe);
708
 
708
 
709
void drm_fb_helper_free(struct drm_fb_helper *helper)
709
void drm_fb_helper_free(struct drm_fb_helper *helper)
710
{
710
{
711
	list_del(&helper->kernel_fb_list);
711
	list_del(&helper->kernel_fb_list);
712
	drm_fb_helper_crtc_free(helper);
712
	drm_fb_helper_crtc_free(helper);
713
}
713
}
714
EXPORT_SYMBOL(drm_fb_helper_free);
714
EXPORT_SYMBOL(drm_fb_helper_free);
715
 
715
 
716
void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
716
void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
717
			    uint32_t depth)
717
			    uint32_t depth)
718
{
718
{
719
	info->fix.type = FB_TYPE_PACKED_PIXELS;
719
	info->fix.type = FB_TYPE_PACKED_PIXELS;
720
	info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
720
	info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
721
		FB_VISUAL_TRUECOLOR;
721
		FB_VISUAL_TRUECOLOR;
722
	info->fix.type_aux = 0;
722
	info->fix.type_aux = 0;
723
	info->fix.xpanstep = 1; /* doing it in hw */
723
	info->fix.xpanstep = 1; /* doing it in hw */
724
	info->fix.ypanstep = 1; /* doing it in hw */
724
	info->fix.ypanstep = 1; /* doing it in hw */
725
	info->fix.ywrapstep = 0;
725
	info->fix.ywrapstep = 0;
726
	info->fix.accel = FB_ACCEL_NONE;
726
	info->fix.accel = FB_ACCEL_NONE;
727
	info->fix.type_aux = 0;
727
	info->fix.type_aux = 0;
728
 
728
 
729
	info->fix.line_length = pitch;
729
	info->fix.line_length = pitch;
730
	return;
730
	return;
731
}
731
}
732
EXPORT_SYMBOL(drm_fb_helper_fill_fix);
732
EXPORT_SYMBOL(drm_fb_helper_fill_fix);
733
 
733
 
734
void drm_fb_helper_fill_var(struct fb_info *info, struct drm_framebuffer *fb,
734
void drm_fb_helper_fill_var(struct fb_info *info, struct drm_framebuffer *fb,
735
			    uint32_t fb_width, uint32_t fb_height)
735
			    uint32_t fb_width, uint32_t fb_height)
736
{
736
{
737
	info->pseudo_palette = fb->pseudo_palette;
737
	info->pseudo_palette = fb->pseudo_palette;
738
	info->var.xres_virtual = fb->width;
738
	info->var.xres_virtual = fb->width;
739
	info->var.yres_virtual = fb->height;
739
	info->var.yres_virtual = fb->height;
740
	info->var.bits_per_pixel = fb->bits_per_pixel;
740
	info->var.bits_per_pixel = fb->bits_per_pixel;
741
	info->var.xoffset = 0;
741
	info->var.xoffset = 0;
742
	info->var.yoffset = 0;
742
	info->var.yoffset = 0;
743
	info->var.activate = FB_ACTIVATE_NOW;
743
	info->var.activate = FB_ACTIVATE_NOW;
744
	info->var.height = -1;
744
	info->var.height = -1;
745
	info->var.width = -1;
745
	info->var.width = -1;
746
 
746
 
747
	switch (fb->depth) {
747
	switch (fb->depth) {
748
	case 8:
748
	case 8:
749
		info->var.red.offset = 0;
749
		info->var.red.offset = 0;
750
		info->var.green.offset = 0;
750
		info->var.green.offset = 0;
751
		info->var.blue.offset = 0;
751
		info->var.blue.offset = 0;
752
		info->var.red.length = 8; /* 8bit DAC */
752
		info->var.red.length = 8; /* 8bit DAC */
753
		info->var.green.length = 8;
753
		info->var.green.length = 8;
754
		info->var.blue.length = 8;
754
		info->var.blue.length = 8;
755
		info->var.transp.offset = 0;
755
		info->var.transp.offset = 0;
756
		info->var.transp.length = 0;
756
		info->var.transp.length = 0;
757
		break;
757
		break;
758
	case 15:
758
	case 15:
759
		info->var.red.offset = 10;
759
		info->var.red.offset = 10;
760
		info->var.green.offset = 5;
760
		info->var.green.offset = 5;
761
		info->var.blue.offset = 0;
761
		info->var.blue.offset = 0;
762
		info->var.red.length = 5;
762
		info->var.red.length = 5;
763
		info->var.green.length = 5;
763
		info->var.green.length = 5;
764
		info->var.blue.length = 5;
764
		info->var.blue.length = 5;
765
		info->var.transp.offset = 15;
765
		info->var.transp.offset = 15;
766
		info->var.transp.length = 1;
766
		info->var.transp.length = 1;
767
		break;
767
		break;
768
	case 16:
768
	case 16:
769
		info->var.red.offset = 11;
769
		info->var.red.offset = 11;
770
		info->var.green.offset = 5;
770
		info->var.green.offset = 5;
771
		info->var.blue.offset = 0;
771
		info->var.blue.offset = 0;
772
		info->var.red.length = 5;
772
		info->var.red.length = 5;
773
		info->var.green.length = 6;
773
		info->var.green.length = 6;
774
		info->var.blue.length = 5;
774
		info->var.blue.length = 5;
775
		info->var.transp.offset = 0;
775
		info->var.transp.offset = 0;
776
		break;
776
		break;
777
	case 24:
777
	case 24:
778
		info->var.red.offset = 16;
778
		info->var.red.offset = 16;
779
		info->var.green.offset = 8;
779
		info->var.green.offset = 8;
780
		info->var.blue.offset = 0;
780
		info->var.blue.offset = 0;
781
		info->var.red.length = 8;
781
		info->var.red.length = 8;
782
		info->var.green.length = 8;
782
		info->var.green.length = 8;
783
		info->var.blue.length = 8;
783
		info->var.blue.length = 8;
784
		info->var.transp.offset = 0;
784
		info->var.transp.offset = 0;
785
		info->var.transp.length = 0;
785
		info->var.transp.length = 0;
786
		break;
786
		break;
787
	case 32:
787
	case 32:
788
		info->var.red.offset = 16;
788
		info->var.red.offset = 16;
789
		info->var.green.offset = 8;
789
		info->var.green.offset = 8;
790
		info->var.blue.offset = 0;
790
		info->var.blue.offset = 0;
791
		info->var.red.length = 8;
791
		info->var.red.length = 8;
792
		info->var.green.length = 8;
792
		info->var.green.length = 8;
793
		info->var.blue.length = 8;
793
		info->var.blue.length = 8;
794
		info->var.transp.offset = 24;
794
		info->var.transp.offset = 24;
795
		info->var.transp.length = 8;
795
		info->var.transp.length = 8;
796
		break;
796
		break;
797
	default:
797
	default:
798
		break;
798
		break;
799
	}
799
	}
800
 
800
 
801
	info->var.xres = fb_width;
801
	info->var.xres = fb_width;
802
	info->var.yres = fb_height;
802
	info->var.yres = fb_height;
803
}
803
}
804
EXPORT_SYMBOL(drm_fb_helper_fill_var);
804
EXPORT_SYMBOL(drm_fb_helper_fill_var);