Commit 6d1a05033bf0bfe236b1c5f425315967d7d684cd

Authored by Linus Torvalds

Merge tag 'fbdev-fixes-for-3.6-1' of git://github.com/schandinat/linux-2.6

Pull fbdev fixes from Florian Tobias Schandinat:
 - a fix by Paul Cercueil to prevent a possible buffer overflow
 - a fix by Bruno Prémont to prevent a rare sleep in invalid context
 - a fix by Julia Lawall for a double free in auo_k190x
 - a fix by Dan Carpenter to prevent a division by zero in mb862xxfb
 - a regression fix by Tomi Valkeinen for the SDI output in OMAP
 - a fix by Grazvydas Ignotas to fix the console colors in OMAP

* tag 'fbdev-fixes-for-3.6-1' of git://github.com/schandinat/linux-2.6:
  OMAPFB: fix framebuffer console colors
  OMAPDSS: Fix SDI PLL locking
  video: mb862xxfb: prevent divide by zero bug
  drivers/video/auo_k190x.c: drop kfree of devm_kzalloc's data
  fbcon: Fix bit_putcs() call to kmalloc(s, GFP_KERNEL)
  fbcon: prevent possible buffer overflow.

Showing 6 changed files Inline Diff

drivers/video/auo_k190x.c
1 /* 1 /*
2 * Common code for AUO-K190X framebuffer drivers 2 * Common code for AUO-K190X framebuffer drivers
3 * 3 *
4 * Copyright (C) 2012 Heiko Stuebner <heiko@sntech.de> 4 * Copyright (C) 2012 Heiko Stuebner <heiko@sntech.de>
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as 7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation. 8 * published by the Free Software Foundation.
9 */ 9 */
10 10
11 #include <linux/module.h> 11 #include <linux/module.h>
12 #include <linux/kernel.h> 12 #include <linux/kernel.h>
13 #include <linux/gpio.h> 13 #include <linux/gpio.h>
14 #include <linux/pm_runtime.h> 14 #include <linux/pm_runtime.h>
15 #include <linux/fb.h> 15 #include <linux/fb.h>
16 #include <linux/delay.h> 16 #include <linux/delay.h>
17 #include <linux/uaccess.h> 17 #include <linux/uaccess.h>
18 #include <linux/vmalloc.h> 18 #include <linux/vmalloc.h>
19 #include <linux/regulator/consumer.h> 19 #include <linux/regulator/consumer.h>
20 20
21 #include <video/auo_k190xfb.h> 21 #include <video/auo_k190xfb.h>
22 22
23 #include "auo_k190x.h" 23 #include "auo_k190x.h"
24 24
25 struct panel_info { 25 struct panel_info {
26 int w; 26 int w;
27 int h; 27 int h;
28 }; 28 };
29 29
30 /* table of panel specific parameters to be indexed into by the board drivers */ 30 /* table of panel specific parameters to be indexed into by the board drivers */
31 static struct panel_info panel_table[] = { 31 static struct panel_info panel_table[] = {
32 /* standard 6" */ 32 /* standard 6" */
33 [AUOK190X_RESOLUTION_800_600] = { 33 [AUOK190X_RESOLUTION_800_600] = {
34 .w = 800, 34 .w = 800,
35 .h = 600, 35 .h = 600,
36 }, 36 },
37 /* standard 9" */ 37 /* standard 9" */
38 [AUOK190X_RESOLUTION_1024_768] = { 38 [AUOK190X_RESOLUTION_1024_768] = {
39 .w = 1024, 39 .w = 1024,
40 .h = 768, 40 .h = 768,
41 }, 41 },
42 }; 42 };
43 43
44 /* 44 /*
45 * private I80 interface to the board driver 45 * private I80 interface to the board driver
46 */ 46 */
47 47
48 static void auok190x_issue_data(struct auok190xfb_par *par, u16 data) 48 static void auok190x_issue_data(struct auok190xfb_par *par, u16 data)
49 { 49 {
50 par->board->set_ctl(par, AUOK190X_I80_WR, 0); 50 par->board->set_ctl(par, AUOK190X_I80_WR, 0);
51 par->board->set_hdb(par, data); 51 par->board->set_hdb(par, data);
52 par->board->set_ctl(par, AUOK190X_I80_WR, 1); 52 par->board->set_ctl(par, AUOK190X_I80_WR, 1);
53 } 53 }
54 54
55 static void auok190x_issue_cmd(struct auok190xfb_par *par, u16 data) 55 static void auok190x_issue_cmd(struct auok190xfb_par *par, u16 data)
56 { 56 {
57 par->board->set_ctl(par, AUOK190X_I80_DC, 0); 57 par->board->set_ctl(par, AUOK190X_I80_DC, 0);
58 auok190x_issue_data(par, data); 58 auok190x_issue_data(par, data);
59 par->board->set_ctl(par, AUOK190X_I80_DC, 1); 59 par->board->set_ctl(par, AUOK190X_I80_DC, 1);
60 } 60 }
61 61
62 static int auok190x_issue_pixels(struct auok190xfb_par *par, int size, 62 static int auok190x_issue_pixels(struct auok190xfb_par *par, int size,
63 u16 *data) 63 u16 *data)
64 { 64 {
65 struct device *dev = par->info->device; 65 struct device *dev = par->info->device;
66 int i; 66 int i;
67 u16 tmp; 67 u16 tmp;
68 68
69 if (size & 3) { 69 if (size & 3) {
70 dev_err(dev, "issue_pixels: size %d must be a multiple of 4\n", 70 dev_err(dev, "issue_pixels: size %d must be a multiple of 4\n",
71 size); 71 size);
72 return -EINVAL; 72 return -EINVAL;
73 } 73 }
74 74
75 for (i = 0; i < (size >> 1); i++) { 75 for (i = 0; i < (size >> 1); i++) {
76 par->board->set_ctl(par, AUOK190X_I80_WR, 0); 76 par->board->set_ctl(par, AUOK190X_I80_WR, 0);
77 77
78 /* simple reduction of 8bit staticgray to 4bit gray 78 /* simple reduction of 8bit staticgray to 4bit gray
79 * combines 4 * 4bit pixel values into a 16bit value 79 * combines 4 * 4bit pixel values into a 16bit value
80 */ 80 */
81 tmp = (data[2*i] & 0xF0) >> 4; 81 tmp = (data[2*i] & 0xF0) >> 4;
82 tmp |= (data[2*i] & 0xF000) >> 8; 82 tmp |= (data[2*i] & 0xF000) >> 8;
83 tmp |= (data[2*i+1] & 0xF0) << 4; 83 tmp |= (data[2*i+1] & 0xF0) << 4;
84 tmp |= (data[2*i+1] & 0xF000); 84 tmp |= (data[2*i+1] & 0xF000);
85 85
86 par->board->set_hdb(par, tmp); 86 par->board->set_hdb(par, tmp);
87 par->board->set_ctl(par, AUOK190X_I80_WR, 1); 87 par->board->set_ctl(par, AUOK190X_I80_WR, 1);
88 } 88 }
89 89
90 return 0; 90 return 0;
91 } 91 }
92 92
93 static u16 auok190x_read_data(struct auok190xfb_par *par) 93 static u16 auok190x_read_data(struct auok190xfb_par *par)
94 { 94 {
95 u16 data; 95 u16 data;
96 96
97 par->board->set_ctl(par, AUOK190X_I80_OE, 0); 97 par->board->set_ctl(par, AUOK190X_I80_OE, 0);
98 data = par->board->get_hdb(par); 98 data = par->board->get_hdb(par);
99 par->board->set_ctl(par, AUOK190X_I80_OE, 1); 99 par->board->set_ctl(par, AUOK190X_I80_OE, 1);
100 100
101 return data; 101 return data;
102 } 102 }
103 103
104 /* 104 /*
105 * Command interface for the controller drivers 105 * Command interface for the controller drivers
106 */ 106 */
107 107
108 void auok190x_send_command_nowait(struct auok190xfb_par *par, u16 data) 108 void auok190x_send_command_nowait(struct auok190xfb_par *par, u16 data)
109 { 109 {
110 par->board->set_ctl(par, AUOK190X_I80_CS, 0); 110 par->board->set_ctl(par, AUOK190X_I80_CS, 0);
111 auok190x_issue_cmd(par, data); 111 auok190x_issue_cmd(par, data);
112 par->board->set_ctl(par, AUOK190X_I80_CS, 1); 112 par->board->set_ctl(par, AUOK190X_I80_CS, 1);
113 } 113 }
114 EXPORT_SYMBOL_GPL(auok190x_send_command_nowait); 114 EXPORT_SYMBOL_GPL(auok190x_send_command_nowait);
115 115
116 void auok190x_send_cmdargs_nowait(struct auok190xfb_par *par, u16 cmd, 116 void auok190x_send_cmdargs_nowait(struct auok190xfb_par *par, u16 cmd,
117 int argc, u16 *argv) 117 int argc, u16 *argv)
118 { 118 {
119 int i; 119 int i;
120 120
121 par->board->set_ctl(par, AUOK190X_I80_CS, 0); 121 par->board->set_ctl(par, AUOK190X_I80_CS, 0);
122 auok190x_issue_cmd(par, cmd); 122 auok190x_issue_cmd(par, cmd);
123 123
124 for (i = 0; i < argc; i++) 124 for (i = 0; i < argc; i++)
125 auok190x_issue_data(par, argv[i]); 125 auok190x_issue_data(par, argv[i]);
126 par->board->set_ctl(par, AUOK190X_I80_CS, 1); 126 par->board->set_ctl(par, AUOK190X_I80_CS, 1);
127 } 127 }
128 EXPORT_SYMBOL_GPL(auok190x_send_cmdargs_nowait); 128 EXPORT_SYMBOL_GPL(auok190x_send_cmdargs_nowait);
129 129
130 int auok190x_send_command(struct auok190xfb_par *par, u16 data) 130 int auok190x_send_command(struct auok190xfb_par *par, u16 data)
131 { 131 {
132 int ret; 132 int ret;
133 133
134 ret = par->board->wait_for_rdy(par); 134 ret = par->board->wait_for_rdy(par);
135 if (ret) 135 if (ret)
136 return ret; 136 return ret;
137 137
138 auok190x_send_command_nowait(par, data); 138 auok190x_send_command_nowait(par, data);
139 return 0; 139 return 0;
140 } 140 }
141 EXPORT_SYMBOL_GPL(auok190x_send_command); 141 EXPORT_SYMBOL_GPL(auok190x_send_command);
142 142
143 int auok190x_send_cmdargs(struct auok190xfb_par *par, u16 cmd, 143 int auok190x_send_cmdargs(struct auok190xfb_par *par, u16 cmd,
144 int argc, u16 *argv) 144 int argc, u16 *argv)
145 { 145 {
146 int ret; 146 int ret;
147 147
148 ret = par->board->wait_for_rdy(par); 148 ret = par->board->wait_for_rdy(par);
149 if (ret) 149 if (ret)
150 return ret; 150 return ret;
151 151
152 auok190x_send_cmdargs_nowait(par, cmd, argc, argv); 152 auok190x_send_cmdargs_nowait(par, cmd, argc, argv);
153 return 0; 153 return 0;
154 } 154 }
155 EXPORT_SYMBOL_GPL(auok190x_send_cmdargs); 155 EXPORT_SYMBOL_GPL(auok190x_send_cmdargs);
156 156
157 int auok190x_read_cmdargs(struct auok190xfb_par *par, u16 cmd, 157 int auok190x_read_cmdargs(struct auok190xfb_par *par, u16 cmd,
158 int argc, u16 *argv) 158 int argc, u16 *argv)
159 { 159 {
160 int i, ret; 160 int i, ret;
161 161
162 ret = par->board->wait_for_rdy(par); 162 ret = par->board->wait_for_rdy(par);
163 if (ret) 163 if (ret)
164 return ret; 164 return ret;
165 165
166 par->board->set_ctl(par, AUOK190X_I80_CS, 0); 166 par->board->set_ctl(par, AUOK190X_I80_CS, 0);
167 auok190x_issue_cmd(par, cmd); 167 auok190x_issue_cmd(par, cmd);
168 168
169 for (i = 0; i < argc; i++) 169 for (i = 0; i < argc; i++)
170 argv[i] = auok190x_read_data(par); 170 argv[i] = auok190x_read_data(par);
171 par->board->set_ctl(par, AUOK190X_I80_CS, 1); 171 par->board->set_ctl(par, AUOK190X_I80_CS, 1);
172 172
173 return 0; 173 return 0;
174 } 174 }
175 EXPORT_SYMBOL_GPL(auok190x_read_cmdargs); 175 EXPORT_SYMBOL_GPL(auok190x_read_cmdargs);
176 176
177 void auok190x_send_cmdargs_pixels_nowait(struct auok190xfb_par *par, u16 cmd, 177 void auok190x_send_cmdargs_pixels_nowait(struct auok190xfb_par *par, u16 cmd,
178 int argc, u16 *argv, int size, u16 *data) 178 int argc, u16 *argv, int size, u16 *data)
179 { 179 {
180 int i; 180 int i;
181 181
182 par->board->set_ctl(par, AUOK190X_I80_CS, 0); 182 par->board->set_ctl(par, AUOK190X_I80_CS, 0);
183 183
184 auok190x_issue_cmd(par, cmd); 184 auok190x_issue_cmd(par, cmd);
185 185
186 for (i = 0; i < argc; i++) 186 for (i = 0; i < argc; i++)
187 auok190x_issue_data(par, argv[i]); 187 auok190x_issue_data(par, argv[i]);
188 188
189 auok190x_issue_pixels(par, size, data); 189 auok190x_issue_pixels(par, size, data);
190 190
191 par->board->set_ctl(par, AUOK190X_I80_CS, 1); 191 par->board->set_ctl(par, AUOK190X_I80_CS, 1);
192 } 192 }
193 EXPORT_SYMBOL_GPL(auok190x_send_cmdargs_pixels_nowait); 193 EXPORT_SYMBOL_GPL(auok190x_send_cmdargs_pixels_nowait);
194 194
195 int auok190x_send_cmdargs_pixels(struct auok190xfb_par *par, u16 cmd, 195 int auok190x_send_cmdargs_pixels(struct auok190xfb_par *par, u16 cmd,
196 int argc, u16 *argv, int size, u16 *data) 196 int argc, u16 *argv, int size, u16 *data)
197 { 197 {
198 int ret; 198 int ret;
199 199
200 ret = par->board->wait_for_rdy(par); 200 ret = par->board->wait_for_rdy(par);
201 if (ret) 201 if (ret)
202 return ret; 202 return ret;
203 203
204 auok190x_send_cmdargs_pixels_nowait(par, cmd, argc, argv, size, data); 204 auok190x_send_cmdargs_pixels_nowait(par, cmd, argc, argv, size, data);
205 205
206 return 0; 206 return 0;
207 } 207 }
208 EXPORT_SYMBOL_GPL(auok190x_send_cmdargs_pixels); 208 EXPORT_SYMBOL_GPL(auok190x_send_cmdargs_pixels);
209 209
210 /* 210 /*
211 * fbdefio callbacks - common on both controllers. 211 * fbdefio callbacks - common on both controllers.
212 */ 212 */
213 213
214 static void auok190xfb_dpy_first_io(struct fb_info *info) 214 static void auok190xfb_dpy_first_io(struct fb_info *info)
215 { 215 {
216 /* tell runtime-pm that we wish to use the device in a short time */ 216 /* tell runtime-pm that we wish to use the device in a short time */
217 pm_runtime_get(info->device); 217 pm_runtime_get(info->device);
218 } 218 }
219 219
220 /* this is called back from the deferred io workqueue */ 220 /* this is called back from the deferred io workqueue */
221 static void auok190xfb_dpy_deferred_io(struct fb_info *info, 221 static void auok190xfb_dpy_deferred_io(struct fb_info *info,
222 struct list_head *pagelist) 222 struct list_head *pagelist)
223 { 223 {
224 struct fb_deferred_io *fbdefio = info->fbdefio; 224 struct fb_deferred_io *fbdefio = info->fbdefio;
225 struct auok190xfb_par *par = info->par; 225 struct auok190xfb_par *par = info->par;
226 u16 yres = info->var.yres; 226 u16 yres = info->var.yres;
227 u16 xres = info->var.xres; 227 u16 xres = info->var.xres;
228 u16 y1 = 0, h = 0; 228 u16 y1 = 0, h = 0;
229 int prev_index = -1; 229 int prev_index = -1;
230 struct page *cur; 230 struct page *cur;
231 int h_inc; 231 int h_inc;
232 int threshold; 232 int threshold;
233 233
234 if (!list_empty(pagelist)) 234 if (!list_empty(pagelist))
235 /* the device resume should've been requested through first_io, 235 /* the device resume should've been requested through first_io,
236 * if the resume did not finish until now, wait for it. 236 * if the resume did not finish until now, wait for it.
237 */ 237 */
238 pm_runtime_barrier(info->device); 238 pm_runtime_barrier(info->device);
239 else 239 else
240 /* We reached this via the fsync or some other way. 240 /* We reached this via the fsync or some other way.
241 * In either case the first_io function did not run, 241 * In either case the first_io function did not run,
242 * so we runtime_resume the device here synchronously. 242 * so we runtime_resume the device here synchronously.
243 */ 243 */
244 pm_runtime_get_sync(info->device); 244 pm_runtime_get_sync(info->device);
245 245
246 /* Do a full screen update every n updates to prevent 246 /* Do a full screen update every n updates to prevent
247 * excessive darkening of the Sipix display. 247 * excessive darkening of the Sipix display.
248 * If we do this, there is no need to walk the pages. 248 * If we do this, there is no need to walk the pages.
249 */ 249 */
250 if (par->need_refresh(par)) { 250 if (par->need_refresh(par)) {
251 par->update_all(par); 251 par->update_all(par);
252 goto out; 252 goto out;
253 } 253 }
254 254
255 /* height increment is fixed per page */ 255 /* height increment is fixed per page */
256 h_inc = DIV_ROUND_UP(PAGE_SIZE , xres); 256 h_inc = DIV_ROUND_UP(PAGE_SIZE , xres);
257 257
258 /* calculate number of pages from pixel height */ 258 /* calculate number of pages from pixel height */
259 threshold = par->consecutive_threshold / h_inc; 259 threshold = par->consecutive_threshold / h_inc;
260 if (threshold < 1) 260 if (threshold < 1)
261 threshold = 1; 261 threshold = 1;
262 262
263 /* walk the written page list and swizzle the data */ 263 /* walk the written page list and swizzle the data */
264 list_for_each_entry(cur, &fbdefio->pagelist, lru) { 264 list_for_each_entry(cur, &fbdefio->pagelist, lru) {
265 if (prev_index < 0) { 265 if (prev_index < 0) {
266 /* just starting so assign first page */ 266 /* just starting so assign first page */
267 y1 = (cur->index << PAGE_SHIFT) / xres; 267 y1 = (cur->index << PAGE_SHIFT) / xres;
268 h = h_inc; 268 h = h_inc;
269 } else if ((cur->index - prev_index) <= threshold) { 269 } else if ((cur->index - prev_index) <= threshold) {
270 /* page is within our threshold for single updates */ 270 /* page is within our threshold for single updates */
271 h += h_inc * (cur->index - prev_index); 271 h += h_inc * (cur->index - prev_index);
272 } else { 272 } else {
273 /* page not consecutive, issue previous update first */ 273 /* page not consecutive, issue previous update first */
274 par->update_partial(par, y1, y1 + h); 274 par->update_partial(par, y1, y1 + h);
275 275
276 /* start over with our non consecutive page */ 276 /* start over with our non consecutive page */
277 y1 = (cur->index << PAGE_SHIFT) / xres; 277 y1 = (cur->index << PAGE_SHIFT) / xres;
278 h = h_inc; 278 h = h_inc;
279 } 279 }
280 prev_index = cur->index; 280 prev_index = cur->index;
281 } 281 }
282 282
283 /* if we still have any pages to update we do so now */ 283 /* if we still have any pages to update we do so now */
284 if (h >= yres) 284 if (h >= yres)
285 /* its a full screen update, just do it */ 285 /* its a full screen update, just do it */
286 par->update_all(par); 286 par->update_all(par);
287 else 287 else
288 par->update_partial(par, y1, min((u16) (y1 + h), yres)); 288 par->update_partial(par, y1, min((u16) (y1 + h), yres));
289 289
290 out: 290 out:
291 pm_runtime_mark_last_busy(info->device); 291 pm_runtime_mark_last_busy(info->device);
292 pm_runtime_put_autosuspend(info->device); 292 pm_runtime_put_autosuspend(info->device);
293 } 293 }
294 294
295 /* 295 /*
296 * framebuffer operations 296 * framebuffer operations
297 */ 297 */
298 298
299 /* 299 /*
300 * this is the slow path from userspace. they can seek and write to 300 * this is the slow path from userspace. they can seek and write to
301 * the fb. it's inefficient to do anything less than a full screen draw 301 * the fb. it's inefficient to do anything less than a full screen draw
302 */ 302 */
303 static ssize_t auok190xfb_write(struct fb_info *info, const char __user *buf, 303 static ssize_t auok190xfb_write(struct fb_info *info, const char __user *buf,
304 size_t count, loff_t *ppos) 304 size_t count, loff_t *ppos)
305 { 305 {
306 struct auok190xfb_par *par = info->par; 306 struct auok190xfb_par *par = info->par;
307 unsigned long p = *ppos; 307 unsigned long p = *ppos;
308 void *dst; 308 void *dst;
309 int err = 0; 309 int err = 0;
310 unsigned long total_size; 310 unsigned long total_size;
311 311
312 if (info->state != FBINFO_STATE_RUNNING) 312 if (info->state != FBINFO_STATE_RUNNING)
313 return -EPERM; 313 return -EPERM;
314 314
315 total_size = info->fix.smem_len; 315 total_size = info->fix.smem_len;
316 316
317 if (p > total_size) 317 if (p > total_size)
318 return -EFBIG; 318 return -EFBIG;
319 319
320 if (count > total_size) { 320 if (count > total_size) {
321 err = -EFBIG; 321 err = -EFBIG;
322 count = total_size; 322 count = total_size;
323 } 323 }
324 324
325 if (count + p > total_size) { 325 if (count + p > total_size) {
326 if (!err) 326 if (!err)
327 err = -ENOSPC; 327 err = -ENOSPC;
328 328
329 count = total_size - p; 329 count = total_size - p;
330 } 330 }
331 331
332 dst = (void *)(info->screen_base + p); 332 dst = (void *)(info->screen_base + p);
333 333
334 if (copy_from_user(dst, buf, count)) 334 if (copy_from_user(dst, buf, count))
335 err = -EFAULT; 335 err = -EFAULT;
336 336
337 if (!err) 337 if (!err)
338 *ppos += count; 338 *ppos += count;
339 339
340 par->update_all(par); 340 par->update_all(par);
341 341
342 return (err) ? err : count; 342 return (err) ? err : count;
343 } 343 }
344 344
345 static void auok190xfb_fillrect(struct fb_info *info, 345 static void auok190xfb_fillrect(struct fb_info *info,
346 const struct fb_fillrect *rect) 346 const struct fb_fillrect *rect)
347 { 347 {
348 struct auok190xfb_par *par = info->par; 348 struct auok190xfb_par *par = info->par;
349 349
350 sys_fillrect(info, rect); 350 sys_fillrect(info, rect);
351 351
352 par->update_all(par); 352 par->update_all(par);
353 } 353 }
354 354
355 static void auok190xfb_copyarea(struct fb_info *info, 355 static void auok190xfb_copyarea(struct fb_info *info,
356 const struct fb_copyarea *area) 356 const struct fb_copyarea *area)
357 { 357 {
358 struct auok190xfb_par *par = info->par; 358 struct auok190xfb_par *par = info->par;
359 359
360 sys_copyarea(info, area); 360 sys_copyarea(info, area);
361 361
362 par->update_all(par); 362 par->update_all(par);
363 } 363 }
364 364
365 static void auok190xfb_imageblit(struct fb_info *info, 365 static void auok190xfb_imageblit(struct fb_info *info,
366 const struct fb_image *image) 366 const struct fb_image *image)
367 { 367 {
368 struct auok190xfb_par *par = info->par; 368 struct auok190xfb_par *par = info->par;
369 369
370 sys_imageblit(info, image); 370 sys_imageblit(info, image);
371 371
372 par->update_all(par); 372 par->update_all(par);
373 } 373 }
374 374
375 static int auok190xfb_check_var(struct fb_var_screeninfo *var, 375 static int auok190xfb_check_var(struct fb_var_screeninfo *var,
376 struct fb_info *info) 376 struct fb_info *info)
377 { 377 {
378 if (info->var.xres != var->xres || info->var.yres != var->yres || 378 if (info->var.xres != var->xres || info->var.yres != var->yres ||
379 info->var.xres_virtual != var->xres_virtual || 379 info->var.xres_virtual != var->xres_virtual ||
380 info->var.yres_virtual != var->yres_virtual) { 380 info->var.yres_virtual != var->yres_virtual) {
381 pr_info("%s: Resolution not supported: X%u x Y%u\n", 381 pr_info("%s: Resolution not supported: X%u x Y%u\n",
382 __func__, var->xres, var->yres); 382 __func__, var->xres, var->yres);
383 return -EINVAL; 383 return -EINVAL;
384 } 384 }
385 385
386 /* 386 /*
387 * Memory limit 387 * Memory limit
388 */ 388 */
389 389
390 if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) { 390 if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) {
391 pr_info("%s: Memory Limit requested yres_virtual = %u\n", 391 pr_info("%s: Memory Limit requested yres_virtual = %u\n",
392 __func__, var->yres_virtual); 392 __func__, var->yres_virtual);
393 return -ENOMEM; 393 return -ENOMEM;
394 } 394 }
395 395
396 return 0; 396 return 0;
397 } 397 }
398 398
399 static struct fb_ops auok190xfb_ops = { 399 static struct fb_ops auok190xfb_ops = {
400 .owner = THIS_MODULE, 400 .owner = THIS_MODULE,
401 .fb_read = fb_sys_read, 401 .fb_read = fb_sys_read,
402 .fb_write = auok190xfb_write, 402 .fb_write = auok190xfb_write,
403 .fb_fillrect = auok190xfb_fillrect, 403 .fb_fillrect = auok190xfb_fillrect,
404 .fb_copyarea = auok190xfb_copyarea, 404 .fb_copyarea = auok190xfb_copyarea,
405 .fb_imageblit = auok190xfb_imageblit, 405 .fb_imageblit = auok190xfb_imageblit,
406 .fb_check_var = auok190xfb_check_var, 406 .fb_check_var = auok190xfb_check_var,
407 }; 407 };
408 408
409 /* 409 /*
410 * Controller-functions common to both K1900 and K1901 410 * Controller-functions common to both K1900 and K1901
411 */ 411 */
412 412
413 static int auok190x_read_temperature(struct auok190xfb_par *par) 413 static int auok190x_read_temperature(struct auok190xfb_par *par)
414 { 414 {
415 struct device *dev = par->info->device; 415 struct device *dev = par->info->device;
416 u16 data[4]; 416 u16 data[4];
417 int temp; 417 int temp;
418 418
419 pm_runtime_get_sync(dev); 419 pm_runtime_get_sync(dev);
420 420
421 mutex_lock(&(par->io_lock)); 421 mutex_lock(&(par->io_lock));
422 422
423 auok190x_read_cmdargs(par, AUOK190X_CMD_READ_VERSION, 4, data); 423 auok190x_read_cmdargs(par, AUOK190X_CMD_READ_VERSION, 4, data);
424 424
425 mutex_unlock(&(par->io_lock)); 425 mutex_unlock(&(par->io_lock));
426 426
427 pm_runtime_mark_last_busy(dev); 427 pm_runtime_mark_last_busy(dev);
428 pm_runtime_put_autosuspend(dev); 428 pm_runtime_put_autosuspend(dev);
429 429
430 /* sanitize and split of half-degrees for now */ 430 /* sanitize and split of half-degrees for now */
431 temp = ((data[0] & AUOK190X_VERSION_TEMP_MASK) >> 1); 431 temp = ((data[0] & AUOK190X_VERSION_TEMP_MASK) >> 1);
432 432
433 /* handle positive and negative temperatures */ 433 /* handle positive and negative temperatures */
434 if (temp >= 201) 434 if (temp >= 201)
435 return (255 - temp + 1) * (-1); 435 return (255 - temp + 1) * (-1);
436 else 436 else
437 return temp; 437 return temp;
438 } 438 }
439 439
440 static void auok190x_identify(struct auok190xfb_par *par) 440 static void auok190x_identify(struct auok190xfb_par *par)
441 { 441 {
442 struct device *dev = par->info->device; 442 struct device *dev = par->info->device;
443 u16 data[4]; 443 u16 data[4];
444 444
445 pm_runtime_get_sync(dev); 445 pm_runtime_get_sync(dev);
446 446
447 mutex_lock(&(par->io_lock)); 447 mutex_lock(&(par->io_lock));
448 448
449 auok190x_read_cmdargs(par, AUOK190X_CMD_READ_VERSION, 4, data); 449 auok190x_read_cmdargs(par, AUOK190X_CMD_READ_VERSION, 4, data);
450 450
451 mutex_unlock(&(par->io_lock)); 451 mutex_unlock(&(par->io_lock));
452 452
453 par->epd_type = data[1] & AUOK190X_VERSION_TEMP_MASK; 453 par->epd_type = data[1] & AUOK190X_VERSION_TEMP_MASK;
454 454
455 par->panel_size_int = AUOK190X_VERSION_SIZE_INT(data[2]); 455 par->panel_size_int = AUOK190X_VERSION_SIZE_INT(data[2]);
456 par->panel_size_float = AUOK190X_VERSION_SIZE_FLOAT(data[2]); 456 par->panel_size_float = AUOK190X_VERSION_SIZE_FLOAT(data[2]);
457 par->panel_model = AUOK190X_VERSION_MODEL(data[2]); 457 par->panel_model = AUOK190X_VERSION_MODEL(data[2]);
458 458
459 par->tcon_version = AUOK190X_VERSION_TCON(data[3]); 459 par->tcon_version = AUOK190X_VERSION_TCON(data[3]);
460 par->lut_version = AUOK190X_VERSION_LUT(data[3]); 460 par->lut_version = AUOK190X_VERSION_LUT(data[3]);
461 461
462 dev_dbg(dev, "panel %d.%din, model 0x%x, EPD 0x%x TCON-rev 0x%x, LUT-rev 0x%x", 462 dev_dbg(dev, "panel %d.%din, model 0x%x, EPD 0x%x TCON-rev 0x%x, LUT-rev 0x%x",
463 par->panel_size_int, par->panel_size_float, par->panel_model, 463 par->panel_size_int, par->panel_size_float, par->panel_model,
464 par->epd_type, par->tcon_version, par->lut_version); 464 par->epd_type, par->tcon_version, par->lut_version);
465 465
466 pm_runtime_mark_last_busy(dev); 466 pm_runtime_mark_last_busy(dev);
467 pm_runtime_put_autosuspend(dev); 467 pm_runtime_put_autosuspend(dev);
468 } 468 }
469 469
470 /* 470 /*
471 * Sysfs functions 471 * Sysfs functions
472 */ 472 */
473 473
474 static ssize_t update_mode_show(struct device *dev, 474 static ssize_t update_mode_show(struct device *dev,
475 struct device_attribute *attr, char *buf) 475 struct device_attribute *attr, char *buf)
476 { 476 {
477 struct fb_info *info = dev_get_drvdata(dev); 477 struct fb_info *info = dev_get_drvdata(dev);
478 struct auok190xfb_par *par = info->par; 478 struct auok190xfb_par *par = info->par;
479 479
480 return sprintf(buf, "%d\n", par->update_mode); 480 return sprintf(buf, "%d\n", par->update_mode);
481 } 481 }
482 482
483 static ssize_t update_mode_store(struct device *dev, 483 static ssize_t update_mode_store(struct device *dev,
484 struct device_attribute *attr, 484 struct device_attribute *attr,
485 const char *buf, size_t count) 485 const char *buf, size_t count)
486 { 486 {
487 struct fb_info *info = dev_get_drvdata(dev); 487 struct fb_info *info = dev_get_drvdata(dev);
488 struct auok190xfb_par *par = info->par; 488 struct auok190xfb_par *par = info->par;
489 int mode, ret; 489 int mode, ret;
490 490
491 ret = kstrtoint(buf, 10, &mode); 491 ret = kstrtoint(buf, 10, &mode);
492 if (ret) 492 if (ret)
493 return ret; 493 return ret;
494 494
495 par->update_mode = mode; 495 par->update_mode = mode;
496 496
497 /* if we enter a better mode, do a full update */ 497 /* if we enter a better mode, do a full update */
498 if (par->last_mode > 1 && mode < par->last_mode) 498 if (par->last_mode > 1 && mode < par->last_mode)
499 par->update_all(par); 499 par->update_all(par);
500 500
501 return count; 501 return count;
502 } 502 }
503 503
504 static ssize_t flash_show(struct device *dev, struct device_attribute *attr, 504 static ssize_t flash_show(struct device *dev, struct device_attribute *attr,
505 char *buf) 505 char *buf)
506 { 506 {
507 struct fb_info *info = dev_get_drvdata(dev); 507 struct fb_info *info = dev_get_drvdata(dev);
508 struct auok190xfb_par *par = info->par; 508 struct auok190xfb_par *par = info->par;
509 509
510 return sprintf(buf, "%d\n", par->flash); 510 return sprintf(buf, "%d\n", par->flash);
511 } 511 }
512 512
513 static ssize_t flash_store(struct device *dev, struct device_attribute *attr, 513 static ssize_t flash_store(struct device *dev, struct device_attribute *attr,
514 const char *buf, size_t count) 514 const char *buf, size_t count)
515 { 515 {
516 struct fb_info *info = dev_get_drvdata(dev); 516 struct fb_info *info = dev_get_drvdata(dev);
517 struct auok190xfb_par *par = info->par; 517 struct auok190xfb_par *par = info->par;
518 int flash, ret; 518 int flash, ret;
519 519
520 ret = kstrtoint(buf, 10, &flash); 520 ret = kstrtoint(buf, 10, &flash);
521 if (ret) 521 if (ret)
522 return ret; 522 return ret;
523 523
524 if (flash > 0) 524 if (flash > 0)
525 par->flash = 1; 525 par->flash = 1;
526 else 526 else
527 par->flash = 0; 527 par->flash = 0;
528 528
529 return count; 529 return count;
530 } 530 }
531 531
532 static ssize_t temp_show(struct device *dev, struct device_attribute *attr, 532 static ssize_t temp_show(struct device *dev, struct device_attribute *attr,
533 char *buf) 533 char *buf)
534 { 534 {
535 struct fb_info *info = dev_get_drvdata(dev); 535 struct fb_info *info = dev_get_drvdata(dev);
536 struct auok190xfb_par *par = info->par; 536 struct auok190xfb_par *par = info->par;
537 int temp; 537 int temp;
538 538
539 temp = auok190x_read_temperature(par); 539 temp = auok190x_read_temperature(par);
540 return sprintf(buf, "%d\n", temp); 540 return sprintf(buf, "%d\n", temp);
541 } 541 }
542 542
543 static DEVICE_ATTR(update_mode, 0644, update_mode_show, update_mode_store); 543 static DEVICE_ATTR(update_mode, 0644, update_mode_show, update_mode_store);
544 static DEVICE_ATTR(flash, 0644, flash_show, flash_store); 544 static DEVICE_ATTR(flash, 0644, flash_show, flash_store);
545 static DEVICE_ATTR(temp, 0644, temp_show, NULL); 545 static DEVICE_ATTR(temp, 0644, temp_show, NULL);
546 546
547 static struct attribute *auok190x_attributes[] = { 547 static struct attribute *auok190x_attributes[] = {
548 &dev_attr_update_mode.attr, 548 &dev_attr_update_mode.attr,
549 &dev_attr_flash.attr, 549 &dev_attr_flash.attr,
550 &dev_attr_temp.attr, 550 &dev_attr_temp.attr,
551 NULL 551 NULL
552 }; 552 };
553 553
554 static const struct attribute_group auok190x_attr_group = { 554 static const struct attribute_group auok190x_attr_group = {
555 .attrs = auok190x_attributes, 555 .attrs = auok190x_attributes,
556 }; 556 };
557 557
558 static int auok190x_power(struct auok190xfb_par *par, bool on) 558 static int auok190x_power(struct auok190xfb_par *par, bool on)
559 { 559 {
560 struct auok190x_board *board = par->board; 560 struct auok190x_board *board = par->board;
561 int ret; 561 int ret;
562 562
563 if (on) { 563 if (on) {
564 /* We should maintain POWER up for at least 80ms before set 564 /* We should maintain POWER up for at least 80ms before set
565 * RST_N and SLP_N to high (TCON spec 20100803_v35 p59) 565 * RST_N and SLP_N to high (TCON spec 20100803_v35 p59)
566 */ 566 */
567 ret = regulator_enable(par->regulator); 567 ret = regulator_enable(par->regulator);
568 if (ret) 568 if (ret)
569 return ret; 569 return ret;
570 570
571 msleep(200); 571 msleep(200);
572 gpio_set_value(board->gpio_nrst, 1); 572 gpio_set_value(board->gpio_nrst, 1);
573 gpio_set_value(board->gpio_nsleep, 1); 573 gpio_set_value(board->gpio_nsleep, 1);
574 msleep(200); 574 msleep(200);
575 } else { 575 } else {
576 regulator_disable(par->regulator); 576 regulator_disable(par->regulator);
577 gpio_set_value(board->gpio_nrst, 0); 577 gpio_set_value(board->gpio_nrst, 0);
578 gpio_set_value(board->gpio_nsleep, 0); 578 gpio_set_value(board->gpio_nsleep, 0);
579 } 579 }
580 580
581 return 0; 581 return 0;
582 } 582 }
583 583
584 /* 584 /*
585 * Recovery - powercycle the controller 585 * Recovery - powercycle the controller
586 */ 586 */
587 587
588 static void auok190x_recover(struct auok190xfb_par *par) 588 static void auok190x_recover(struct auok190xfb_par *par)
589 { 589 {
590 auok190x_power(par, 0); 590 auok190x_power(par, 0);
591 msleep(100); 591 msleep(100);
592 auok190x_power(par, 1); 592 auok190x_power(par, 1);
593 593
594 par->init(par); 594 par->init(par);
595 595
596 /* wait for init to complete */ 596 /* wait for init to complete */
597 par->board->wait_for_rdy(par); 597 par->board->wait_for_rdy(par);
598 } 598 }
599 599
600 /* 600 /*
601 * Power-management 601 * Power-management
602 */ 602 */
603 603
604 #ifdef CONFIG_PM 604 #ifdef CONFIG_PM
605 static int auok190x_runtime_suspend(struct device *dev) 605 static int auok190x_runtime_suspend(struct device *dev)
606 { 606 {
607 struct platform_device *pdev = to_platform_device(dev); 607 struct platform_device *pdev = to_platform_device(dev);
608 struct fb_info *info = platform_get_drvdata(pdev); 608 struct fb_info *info = platform_get_drvdata(pdev);
609 struct auok190xfb_par *par = info->par; 609 struct auok190xfb_par *par = info->par;
610 struct auok190x_board *board = par->board; 610 struct auok190x_board *board = par->board;
611 u16 standby_param; 611 u16 standby_param;
612 612
613 /* take and keep the lock until we are resumed, as the controller 613 /* take and keep the lock until we are resumed, as the controller
614 * will never reach the non-busy state when in standby mode 614 * will never reach the non-busy state when in standby mode
615 */ 615 */
616 mutex_lock(&(par->io_lock)); 616 mutex_lock(&(par->io_lock));
617 617
618 if (par->standby) { 618 if (par->standby) {
619 dev_warn(dev, "already in standby, runtime-pm pairing mismatch\n"); 619 dev_warn(dev, "already in standby, runtime-pm pairing mismatch\n");
620 mutex_unlock(&(par->io_lock)); 620 mutex_unlock(&(par->io_lock));
621 return 0; 621 return 0;
622 } 622 }
623 623
624 /* according to runtime_pm.txt runtime_suspend only means, that the 624 /* according to runtime_pm.txt runtime_suspend only means, that the
625 * device will not process data and will not communicate with the CPU 625 * device will not process data and will not communicate with the CPU
626 * As we hold the lock, this stays true even without standby 626 * As we hold the lock, this stays true even without standby
627 */ 627 */
628 if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) { 628 if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) {
629 dev_dbg(dev, "runtime suspend without standby\n"); 629 dev_dbg(dev, "runtime suspend without standby\n");
630 goto finish; 630 goto finish;
631 } else if (board->quirks & AUOK190X_QUIRK_STANDBYPARAM) { 631 } else if (board->quirks & AUOK190X_QUIRK_STANDBYPARAM) {
632 /* for some TCON versions STANDBY expects a parameter (0) but 632 /* for some TCON versions STANDBY expects a parameter (0) but
633 * it seems the real tcon version has to be determined yet. 633 * it seems the real tcon version has to be determined yet.
634 */ 634 */
635 dev_dbg(dev, "runtime suspend with additional empty param\n"); 635 dev_dbg(dev, "runtime suspend with additional empty param\n");
636 standby_param = 0; 636 standby_param = 0;
637 auok190x_send_cmdargs(par, AUOK190X_CMD_STANDBY, 1, 637 auok190x_send_cmdargs(par, AUOK190X_CMD_STANDBY, 1,
638 &standby_param); 638 &standby_param);
639 } else { 639 } else {
640 dev_dbg(dev, "runtime suspend without param\n"); 640 dev_dbg(dev, "runtime suspend without param\n");
641 auok190x_send_command(par, AUOK190X_CMD_STANDBY); 641 auok190x_send_command(par, AUOK190X_CMD_STANDBY);
642 } 642 }
643 643
644 msleep(64); 644 msleep(64);
645 645
646 finish: 646 finish:
647 par->standby = 1; 647 par->standby = 1;
648 648
649 return 0; 649 return 0;
650 } 650 }
651 651
652 static int auok190x_runtime_resume(struct device *dev) 652 static int auok190x_runtime_resume(struct device *dev)
653 { 653 {
654 struct platform_device *pdev = to_platform_device(dev); 654 struct platform_device *pdev = to_platform_device(dev);
655 struct fb_info *info = platform_get_drvdata(pdev); 655 struct fb_info *info = platform_get_drvdata(pdev);
656 struct auok190xfb_par *par = info->par; 656 struct auok190xfb_par *par = info->par;
657 struct auok190x_board *board = par->board; 657 struct auok190x_board *board = par->board;
658 658
659 if (!par->standby) { 659 if (!par->standby) {
660 dev_warn(dev, "not in standby, runtime-pm pairing mismatch\n"); 660 dev_warn(dev, "not in standby, runtime-pm pairing mismatch\n");
661 return 0; 661 return 0;
662 } 662 }
663 663
664 if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) { 664 if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) {
665 dev_dbg(dev, "runtime resume without standby\n"); 665 dev_dbg(dev, "runtime resume without standby\n");
666 } else { 666 } else {
667 /* when in standby, controller is always busy 667 /* when in standby, controller is always busy
668 * and only accepts the wakeup command 668 * and only accepts the wakeup command
669 */ 669 */
670 dev_dbg(dev, "runtime resume from standby\n"); 670 dev_dbg(dev, "runtime resume from standby\n");
671 auok190x_send_command_nowait(par, AUOK190X_CMD_WAKEUP); 671 auok190x_send_command_nowait(par, AUOK190X_CMD_WAKEUP);
672 672
673 msleep(160); 673 msleep(160);
674 674
675 /* wait for the controller to be ready and release the lock */ 675 /* wait for the controller to be ready and release the lock */
676 board->wait_for_rdy(par); 676 board->wait_for_rdy(par);
677 } 677 }
678 678
679 par->standby = 0; 679 par->standby = 0;
680 680
681 mutex_unlock(&(par->io_lock)); 681 mutex_unlock(&(par->io_lock));
682 682
683 return 0; 683 return 0;
684 } 684 }
685 685
686 static int auok190x_suspend(struct device *dev) 686 static int auok190x_suspend(struct device *dev)
687 { 687 {
688 struct platform_device *pdev = to_platform_device(dev); 688 struct platform_device *pdev = to_platform_device(dev);
689 struct fb_info *info = platform_get_drvdata(pdev); 689 struct fb_info *info = platform_get_drvdata(pdev);
690 struct auok190xfb_par *par = info->par; 690 struct auok190xfb_par *par = info->par;
691 struct auok190x_board *board = par->board; 691 struct auok190x_board *board = par->board;
692 int ret; 692 int ret;
693 693
694 dev_dbg(dev, "suspend\n"); 694 dev_dbg(dev, "suspend\n");
695 if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) { 695 if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) {
696 /* suspend via powering off the ic */ 696 /* suspend via powering off the ic */
697 dev_dbg(dev, "suspend with broken standby\n"); 697 dev_dbg(dev, "suspend with broken standby\n");
698 698
699 auok190x_power(par, 0); 699 auok190x_power(par, 0);
700 } else { 700 } else {
701 dev_dbg(dev, "suspend using sleep\n"); 701 dev_dbg(dev, "suspend using sleep\n");
702 702
703 /* the sleep state can only be entered from the standby state. 703 /* the sleep state can only be entered from the standby state.
704 * pm_runtime_get_noresume gets called before the suspend call. 704 * pm_runtime_get_noresume gets called before the suspend call.
705 * So the devices usage count is >0 but it is not necessarily 705 * So the devices usage count is >0 but it is not necessarily
706 * active. 706 * active.
707 */ 707 */
708 if (!pm_runtime_status_suspended(dev)) { 708 if (!pm_runtime_status_suspended(dev)) {
709 ret = auok190x_runtime_suspend(dev); 709 ret = auok190x_runtime_suspend(dev);
710 if (ret < 0) { 710 if (ret < 0) {
711 dev_err(dev, "auok190x_runtime_suspend failed with %d\n", 711 dev_err(dev, "auok190x_runtime_suspend failed with %d\n",
712 ret); 712 ret);
713 return ret; 713 return ret;
714 } 714 }
715 par->manual_standby = 1; 715 par->manual_standby = 1;
716 } 716 }
717 717
718 gpio_direction_output(board->gpio_nsleep, 0); 718 gpio_direction_output(board->gpio_nsleep, 0);
719 } 719 }
720 720
721 msleep(100); 721 msleep(100);
722 722
723 return 0; 723 return 0;
724 } 724 }
725 725
726 static int auok190x_resume(struct device *dev) 726 static int auok190x_resume(struct device *dev)
727 { 727 {
728 struct platform_device *pdev = to_platform_device(dev); 728 struct platform_device *pdev = to_platform_device(dev);
729 struct fb_info *info = platform_get_drvdata(pdev); 729 struct fb_info *info = platform_get_drvdata(pdev);
730 struct auok190xfb_par *par = info->par; 730 struct auok190xfb_par *par = info->par;
731 struct auok190x_board *board = par->board; 731 struct auok190x_board *board = par->board;
732 732
733 dev_dbg(dev, "resume\n"); 733 dev_dbg(dev, "resume\n");
734 if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) { 734 if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) {
735 dev_dbg(dev, "resume with broken standby\n"); 735 dev_dbg(dev, "resume with broken standby\n");
736 736
737 auok190x_power(par, 1); 737 auok190x_power(par, 1);
738 738
739 par->init(par); 739 par->init(par);
740 } else { 740 } else {
741 dev_dbg(dev, "resume from sleep\n"); 741 dev_dbg(dev, "resume from sleep\n");
742 742
743 /* device should be in runtime suspend when we were suspended 743 /* device should be in runtime suspend when we were suspended
744 * and pm_runtime_put_sync gets called after this function. 744 * and pm_runtime_put_sync gets called after this function.
745 * So there is no need to touch the standby mode here at all. 745 * So there is no need to touch the standby mode here at all.
746 */ 746 */
747 gpio_direction_output(board->gpio_nsleep, 1); 747 gpio_direction_output(board->gpio_nsleep, 1);
748 msleep(100); 748 msleep(100);
749 749
750 /* an additional init call seems to be necessary after sleep */ 750 /* an additional init call seems to be necessary after sleep */
751 auok190x_runtime_resume(dev); 751 auok190x_runtime_resume(dev);
752 par->init(par); 752 par->init(par);
753 753
754 /* if we were runtime-suspended before, suspend again*/ 754 /* if we were runtime-suspended before, suspend again*/
755 if (!par->manual_standby) 755 if (!par->manual_standby)
756 auok190x_runtime_suspend(dev); 756 auok190x_runtime_suspend(dev);
757 else 757 else
758 par->manual_standby = 0; 758 par->manual_standby = 0;
759 } 759 }
760 760
761 return 0; 761 return 0;
762 } 762 }
763 #endif 763 #endif
764 764
765 const struct dev_pm_ops auok190x_pm = { 765 const struct dev_pm_ops auok190x_pm = {
766 SET_RUNTIME_PM_OPS(auok190x_runtime_suspend, auok190x_runtime_resume, 766 SET_RUNTIME_PM_OPS(auok190x_runtime_suspend, auok190x_runtime_resume,
767 NULL) 767 NULL)
768 SET_SYSTEM_SLEEP_PM_OPS(auok190x_suspend, auok190x_resume) 768 SET_SYSTEM_SLEEP_PM_OPS(auok190x_suspend, auok190x_resume)
769 }; 769 };
770 EXPORT_SYMBOL_GPL(auok190x_pm); 770 EXPORT_SYMBOL_GPL(auok190x_pm);
771 771
772 /* 772 /*
773 * Common probe and remove code 773 * Common probe and remove code
774 */ 774 */
775 775
776 int __devinit auok190x_common_probe(struct platform_device *pdev, 776 int __devinit auok190x_common_probe(struct platform_device *pdev,
777 struct auok190x_init_data *init) 777 struct auok190x_init_data *init)
778 { 778 {
779 struct auok190x_board *board = init->board; 779 struct auok190x_board *board = init->board;
780 struct auok190xfb_par *par; 780 struct auok190xfb_par *par;
781 struct fb_info *info; 781 struct fb_info *info;
782 struct panel_info *panel; 782 struct panel_info *panel;
783 int videomemorysize, ret; 783 int videomemorysize, ret;
784 unsigned char *videomemory; 784 unsigned char *videomemory;
785 785
786 /* check board contents */ 786 /* check board contents */
787 if (!board->init || !board->cleanup || !board->wait_for_rdy 787 if (!board->init || !board->cleanup || !board->wait_for_rdy
788 || !board->set_ctl || !board->set_hdb || !board->get_hdb 788 || !board->set_ctl || !board->set_hdb || !board->get_hdb
789 || !board->setup_irq) 789 || !board->setup_irq)
790 return -EINVAL; 790 return -EINVAL;
791 791
792 info = framebuffer_alloc(sizeof(struct auok190xfb_par), &pdev->dev); 792 info = framebuffer_alloc(sizeof(struct auok190xfb_par), &pdev->dev);
793 if (!info) 793 if (!info)
794 return -ENOMEM; 794 return -ENOMEM;
795 795
796 par = info->par; 796 par = info->par;
797 par->info = info; 797 par->info = info;
798 par->board = board; 798 par->board = board;
799 par->recover = auok190x_recover; 799 par->recover = auok190x_recover;
800 par->update_partial = init->update_partial; 800 par->update_partial = init->update_partial;
801 par->update_all = init->update_all; 801 par->update_all = init->update_all;
802 par->need_refresh = init->need_refresh; 802 par->need_refresh = init->need_refresh;
803 par->init = init->init; 803 par->init = init->init;
804 804
805 /* init update modes */ 805 /* init update modes */
806 par->update_cnt = 0; 806 par->update_cnt = 0;
807 par->update_mode = -1; 807 par->update_mode = -1;
808 par->last_mode = -1; 808 par->last_mode = -1;
809 par->flash = 0; 809 par->flash = 0;
810 810
811 par->regulator = regulator_get(info->device, "vdd"); 811 par->regulator = regulator_get(info->device, "vdd");
812 if (IS_ERR(par->regulator)) { 812 if (IS_ERR(par->regulator)) {
813 ret = PTR_ERR(par->regulator); 813 ret = PTR_ERR(par->regulator);
814 dev_err(info->device, "Failed to get regulator: %d\n", ret); 814 dev_err(info->device, "Failed to get regulator: %d\n", ret);
815 goto err_reg; 815 goto err_reg;
816 } 816 }
817 817
818 ret = board->init(par); 818 ret = board->init(par);
819 if (ret) { 819 if (ret) {
820 dev_err(info->device, "board init failed, %d\n", ret); 820 dev_err(info->device, "board init failed, %d\n", ret);
821 goto err_board; 821 goto err_board;
822 } 822 }
823 823
824 ret = gpio_request(board->gpio_nsleep, "AUOK190x sleep"); 824 ret = gpio_request(board->gpio_nsleep, "AUOK190x sleep");
825 if (ret) { 825 if (ret) {
826 dev_err(info->device, "could not request sleep gpio, %d\n", 826 dev_err(info->device, "could not request sleep gpio, %d\n",
827 ret); 827 ret);
828 goto err_gpio1; 828 goto err_gpio1;
829 } 829 }
830 830
831 ret = gpio_direction_output(board->gpio_nsleep, 0); 831 ret = gpio_direction_output(board->gpio_nsleep, 0);
832 if (ret) { 832 if (ret) {
833 dev_err(info->device, "could not set sleep gpio, %d\n", ret); 833 dev_err(info->device, "could not set sleep gpio, %d\n", ret);
834 goto err_gpio2; 834 goto err_gpio2;
835 } 835 }
836 836
837 ret = gpio_request(board->gpio_nrst, "AUOK190x reset"); 837 ret = gpio_request(board->gpio_nrst, "AUOK190x reset");
838 if (ret) { 838 if (ret) {
839 dev_err(info->device, "could not request reset gpio, %d\n", 839 dev_err(info->device, "could not request reset gpio, %d\n",
840 ret); 840 ret);
841 goto err_gpio2; 841 goto err_gpio2;
842 } 842 }
843 843
844 ret = gpio_direction_output(board->gpio_nrst, 0); 844 ret = gpio_direction_output(board->gpio_nrst, 0);
845 if (ret) { 845 if (ret) {
846 dev_err(info->device, "could not set reset gpio, %d\n", ret); 846 dev_err(info->device, "could not set reset gpio, %d\n", ret);
847 goto err_gpio3; 847 goto err_gpio3;
848 } 848 }
849 849
850 ret = auok190x_power(par, 1); 850 ret = auok190x_power(par, 1);
851 if (ret) { 851 if (ret) {
852 dev_err(info->device, "could not power on the device, %d\n", 852 dev_err(info->device, "could not power on the device, %d\n",
853 ret); 853 ret);
854 goto err_gpio3; 854 goto err_gpio3;
855 } 855 }
856 856
857 mutex_init(&par->io_lock); 857 mutex_init(&par->io_lock);
858 858
859 init_waitqueue_head(&par->waitq); 859 init_waitqueue_head(&par->waitq);
860 860
861 ret = par->board->setup_irq(par->info); 861 ret = par->board->setup_irq(par->info);
862 if (ret) { 862 if (ret) {
863 dev_err(info->device, "could not setup ready-irq, %d\n", ret); 863 dev_err(info->device, "could not setup ready-irq, %d\n", ret);
864 goto err_irq; 864 goto err_irq;
865 } 865 }
866 866
867 /* wait for init to complete */ 867 /* wait for init to complete */
868 par->board->wait_for_rdy(par); 868 par->board->wait_for_rdy(par);
869 869
870 /* 870 /*
871 * From here on the controller can talk to us 871 * From here on the controller can talk to us
872 */ 872 */
873 873
874 /* initialise fix, var, resolution and rotation */ 874 /* initialise fix, var, resolution and rotation */
875 875
876 strlcpy(info->fix.id, init->id, 16); 876 strlcpy(info->fix.id, init->id, 16);
877 info->fix.type = FB_TYPE_PACKED_PIXELS; 877 info->fix.type = FB_TYPE_PACKED_PIXELS;
878 info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR; 878 info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
879 info->fix.xpanstep = 0; 879 info->fix.xpanstep = 0;
880 info->fix.ypanstep = 0; 880 info->fix.ypanstep = 0;
881 info->fix.ywrapstep = 0; 881 info->fix.ywrapstep = 0;
882 info->fix.accel = FB_ACCEL_NONE; 882 info->fix.accel = FB_ACCEL_NONE;
883 883
884 info->var.bits_per_pixel = 8; 884 info->var.bits_per_pixel = 8;
885 info->var.grayscale = 1; 885 info->var.grayscale = 1;
886 info->var.red.length = 8; 886 info->var.red.length = 8;
887 info->var.green.length = 8; 887 info->var.green.length = 8;
888 info->var.blue.length = 8; 888 info->var.blue.length = 8;
889 889
890 panel = &panel_table[board->resolution]; 890 panel = &panel_table[board->resolution];
891 891
892 /* if 90 degree rotation, switch width and height */ 892 /* if 90 degree rotation, switch width and height */
893 if (board->rotation & 1) { 893 if (board->rotation & 1) {
894 info->var.xres = panel->h; 894 info->var.xres = panel->h;
895 info->var.yres = panel->w; 895 info->var.yres = panel->w;
896 info->var.xres_virtual = panel->h; 896 info->var.xres_virtual = panel->h;
897 info->var.yres_virtual = panel->w; 897 info->var.yres_virtual = panel->w;
898 info->fix.line_length = panel->h; 898 info->fix.line_length = panel->h;
899 } else { 899 } else {
900 info->var.xres = panel->w; 900 info->var.xres = panel->w;
901 info->var.yres = panel->h; 901 info->var.yres = panel->h;
902 info->var.xres_virtual = panel->w; 902 info->var.xres_virtual = panel->w;
903 info->var.yres_virtual = panel->h; 903 info->var.yres_virtual = panel->h;
904 info->fix.line_length = panel->w; 904 info->fix.line_length = panel->w;
905 } 905 }
906 906
907 par->resolution = board->resolution; 907 par->resolution = board->resolution;
908 par->rotation = board->rotation; 908 par->rotation = board->rotation;
909 909
910 /* videomemory handling */ 910 /* videomemory handling */
911 911
912 videomemorysize = roundup((panel->w * panel->h), PAGE_SIZE); 912 videomemorysize = roundup((panel->w * panel->h), PAGE_SIZE);
913 videomemory = vmalloc(videomemorysize); 913 videomemory = vmalloc(videomemorysize);
914 if (!videomemory) { 914 if (!videomemory) {
915 ret = -ENOMEM; 915 ret = -ENOMEM;
916 goto err_irq; 916 goto err_irq;
917 } 917 }
918 918
919 memset(videomemory, 0, videomemorysize); 919 memset(videomemory, 0, videomemorysize);
920 info->screen_base = (char *)videomemory; 920 info->screen_base = (char *)videomemory;
921 info->fix.smem_len = videomemorysize; 921 info->fix.smem_len = videomemorysize;
922 922
923 info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB; 923 info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
924 info->fbops = &auok190xfb_ops; 924 info->fbops = &auok190xfb_ops;
925 925
926 /* deferred io init */ 926 /* deferred io init */
927 927
928 info->fbdefio = devm_kzalloc(info->device, 928 info->fbdefio = devm_kzalloc(info->device,
929 sizeof(struct fb_deferred_io), 929 sizeof(struct fb_deferred_io),
930 GFP_KERNEL); 930 GFP_KERNEL);
931 if (!info->fbdefio) { 931 if (!info->fbdefio) {
932 dev_err(info->device, "Failed to allocate memory\n"); 932 dev_err(info->device, "Failed to allocate memory\n");
933 ret = -ENOMEM; 933 ret = -ENOMEM;
934 goto err_defio; 934 goto err_defio;
935 } 935 }
936 936
937 dev_dbg(info->device, "targetting %d frames per second\n", board->fps); 937 dev_dbg(info->device, "targetting %d frames per second\n", board->fps);
938 info->fbdefio->delay = HZ / board->fps; 938 info->fbdefio->delay = HZ / board->fps;
939 info->fbdefio->first_io = auok190xfb_dpy_first_io, 939 info->fbdefio->first_io = auok190xfb_dpy_first_io,
940 info->fbdefio->deferred_io = auok190xfb_dpy_deferred_io, 940 info->fbdefio->deferred_io = auok190xfb_dpy_deferred_io,
941 fb_deferred_io_init(info); 941 fb_deferred_io_init(info);
942 942
943 /* color map */ 943 /* color map */
944 944
945 ret = fb_alloc_cmap(&info->cmap, 256, 0); 945 ret = fb_alloc_cmap(&info->cmap, 256, 0);
946 if (ret < 0) { 946 if (ret < 0) {
947 dev_err(info->device, "Failed to allocate colormap\n"); 947 dev_err(info->device, "Failed to allocate colormap\n");
948 goto err_cmap; 948 goto err_cmap;
949 } 949 }
950 950
951 /* controller init */ 951 /* controller init */
952 952
953 par->consecutive_threshold = 100; 953 par->consecutive_threshold = 100;
954 par->init(par); 954 par->init(par);
955 auok190x_identify(par); 955 auok190x_identify(par);
956 956
957 platform_set_drvdata(pdev, info); 957 platform_set_drvdata(pdev, info);
958 958
959 ret = register_framebuffer(info); 959 ret = register_framebuffer(info);
960 if (ret < 0) 960 if (ret < 0)
961 goto err_regfb; 961 goto err_regfb;
962 962
963 ret = sysfs_create_group(&info->device->kobj, &auok190x_attr_group); 963 ret = sysfs_create_group(&info->device->kobj, &auok190x_attr_group);
964 if (ret) 964 if (ret)
965 goto err_sysfs; 965 goto err_sysfs;
966 966
967 dev_info(info->device, "fb%d: %dx%d using %dK of video memory\n", 967 dev_info(info->device, "fb%d: %dx%d using %dK of video memory\n",
968 info->node, info->var.xres, info->var.yres, 968 info->node, info->var.xres, info->var.yres,
969 videomemorysize >> 10); 969 videomemorysize >> 10);
970 970
971 /* increase autosuspend_delay when we use alternative methods 971 /* increase autosuspend_delay when we use alternative methods
972 * for runtime_pm 972 * for runtime_pm
973 */ 973 */
974 par->autosuspend_delay = (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) 974 par->autosuspend_delay = (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN)
975 ? 1000 : 200; 975 ? 1000 : 200;
976 976
977 pm_runtime_set_active(info->device); 977 pm_runtime_set_active(info->device);
978 pm_runtime_enable(info->device); 978 pm_runtime_enable(info->device);
979 pm_runtime_set_autosuspend_delay(info->device, par->autosuspend_delay); 979 pm_runtime_set_autosuspend_delay(info->device, par->autosuspend_delay);
980 pm_runtime_use_autosuspend(info->device); 980 pm_runtime_use_autosuspend(info->device);
981 981
982 return 0; 982 return 0;
983 983
984 err_sysfs: 984 err_sysfs:
985 unregister_framebuffer(info); 985 unregister_framebuffer(info);
986 err_regfb: 986 err_regfb:
987 fb_dealloc_cmap(&info->cmap); 987 fb_dealloc_cmap(&info->cmap);
988 err_cmap: 988 err_cmap:
989 fb_deferred_io_cleanup(info); 989 fb_deferred_io_cleanup(info);
990 kfree(info->fbdefio);
991 err_defio: 990 err_defio:
992 vfree((void *)info->screen_base); 991 vfree((void *)info->screen_base);
993 err_irq: 992 err_irq:
994 auok190x_power(par, 0); 993 auok190x_power(par, 0);
995 err_gpio3: 994 err_gpio3:
996 gpio_free(board->gpio_nrst); 995 gpio_free(board->gpio_nrst);
997 err_gpio2: 996 err_gpio2:
998 gpio_free(board->gpio_nsleep); 997 gpio_free(board->gpio_nsleep);
999 err_gpio1: 998 err_gpio1:
1000 board->cleanup(par); 999 board->cleanup(par);
1001 err_board: 1000 err_board:
1002 regulator_put(par->regulator); 1001 regulator_put(par->regulator);
1003 err_reg: 1002 err_reg:
1004 framebuffer_release(info); 1003 framebuffer_release(info);
1005 1004
1006 return ret; 1005 return ret;
1007 } 1006 }
1008 EXPORT_SYMBOL_GPL(auok190x_common_probe); 1007 EXPORT_SYMBOL_GPL(auok190x_common_probe);
1009 1008
1010 int __devexit auok190x_common_remove(struct platform_device *pdev) 1009 int __devexit auok190x_common_remove(struct platform_device *pdev)
1011 { 1010 {
1012 struct fb_info *info = platform_get_drvdata(pdev); 1011 struct fb_info *info = platform_get_drvdata(pdev);
1013 struct auok190xfb_par *par = info->par; 1012 struct auok190xfb_par *par = info->par;
1014 struct auok190x_board *board = par->board; 1013 struct auok190x_board *board = par->board;
1015 1014
1016 pm_runtime_disable(info->device); 1015 pm_runtime_disable(info->device);
1017 1016
1018 sysfs_remove_group(&info->device->kobj, &auok190x_attr_group); 1017 sysfs_remove_group(&info->device->kobj, &auok190x_attr_group);
1019 1018
1020 unregister_framebuffer(info); 1019 unregister_framebuffer(info);
1021 1020
1022 fb_dealloc_cmap(&info->cmap); 1021 fb_dealloc_cmap(&info->cmap);
1023 1022
1024 fb_deferred_io_cleanup(info); 1023 fb_deferred_io_cleanup(info);
1025 kfree(info->fbdefio);
1026 1024
1027 vfree((void *)info->screen_base); 1025 vfree((void *)info->screen_base);
1028 1026
1029 auok190x_power(par, 0); 1027 auok190x_power(par, 0);
1030 1028
1031 gpio_free(board->gpio_nrst); 1029 gpio_free(board->gpio_nrst);
1032 gpio_free(board->gpio_nsleep); 1030 gpio_free(board->gpio_nsleep);
1033 1031
1034 board->cleanup(par); 1032 board->cleanup(par);
1035 1033
1036 regulator_put(par->regulator); 1034 regulator_put(par->regulator);
1037 1035
1038 framebuffer_release(info); 1036 framebuffer_release(info);
1039 1037
1040 return 0; 1038 return 0;
1041 } 1039 }
1042 EXPORT_SYMBOL_GPL(auok190x_common_remove); 1040 EXPORT_SYMBOL_GPL(auok190x_common_remove);
1043 1041
1044 MODULE_DESCRIPTION("Common code for AUO-K190X controllers"); 1042 MODULE_DESCRIPTION("Common code for AUO-K190X controllers");
1045 MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); 1043 MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
1046 MODULE_LICENSE("GPL"); 1044 MODULE_LICENSE("GPL");
1047 1045
drivers/video/console/bitblit.c
1 /* 1 /*
2 * linux/drivers/video/console/bitblit.c -- BitBlitting Operation 2 * linux/drivers/video/console/bitblit.c -- BitBlitting Operation
3 * 3 *
4 * Originally from the 'accel_*' routines in drivers/video/console/fbcon.c 4 * Originally from the 'accel_*' routines in drivers/video/console/fbcon.c
5 * 5 *
6 * Copyright (C) 2004 Antonino Daplas <adaplas @pol.net> 6 * Copyright (C) 2004 Antonino Daplas <adaplas @pol.net>
7 * 7 *
8 * This file is subject to the terms and conditions of the GNU General Public 8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file COPYING in the main directory of this archive for 9 * License. See the file COPYING in the main directory of this archive for
10 * more details. 10 * more details.
11 */ 11 */
12 12
13 #include <linux/module.h> 13 #include <linux/module.h>
14 #include <linux/slab.h> 14 #include <linux/slab.h>
15 #include <linux/string.h> 15 #include <linux/string.h>
16 #include <linux/fb.h> 16 #include <linux/fb.h>
17 #include <linux/vt_kern.h> 17 #include <linux/vt_kern.h>
18 #include <linux/console.h> 18 #include <linux/console.h>
19 #include <asm/types.h> 19 #include <asm/types.h>
20 #include "fbcon.h" 20 #include "fbcon.h"
21 21
22 /* 22 /*
23 * Accelerated handlers. 23 * Accelerated handlers.
24 */ 24 */
25 static void update_attr(u8 *dst, u8 *src, int attribute, 25 static void update_attr(u8 *dst, u8 *src, int attribute,
26 struct vc_data *vc) 26 struct vc_data *vc)
27 { 27 {
28 int i, offset = (vc->vc_font.height < 10) ? 1 : 2; 28 int i, offset = (vc->vc_font.height < 10) ? 1 : 2;
29 int width = DIV_ROUND_UP(vc->vc_font.width, 8); 29 int width = DIV_ROUND_UP(vc->vc_font.width, 8);
30 unsigned int cellsize = vc->vc_font.height * width; 30 unsigned int cellsize = vc->vc_font.height * width;
31 u8 c; 31 u8 c;
32 32
33 offset = cellsize - (offset * width); 33 offset = cellsize - (offset * width);
34 for (i = 0; i < cellsize; i++) { 34 for (i = 0; i < cellsize; i++) {
35 c = src[i]; 35 c = src[i];
36 if (attribute & FBCON_ATTRIBUTE_UNDERLINE && i >= offset) 36 if (attribute & FBCON_ATTRIBUTE_UNDERLINE && i >= offset)
37 c = 0xff; 37 c = 0xff;
38 if (attribute & FBCON_ATTRIBUTE_BOLD) 38 if (attribute & FBCON_ATTRIBUTE_BOLD)
39 c |= c >> 1; 39 c |= c >> 1;
40 if (attribute & FBCON_ATTRIBUTE_REVERSE) 40 if (attribute & FBCON_ATTRIBUTE_REVERSE)
41 c = ~c; 41 c = ~c;
42 dst[i] = c; 42 dst[i] = c;
43 } 43 }
44 } 44 }
45 45
46 static void bit_bmove(struct vc_data *vc, struct fb_info *info, int sy, 46 static void bit_bmove(struct vc_data *vc, struct fb_info *info, int sy,
47 int sx, int dy, int dx, int height, int width) 47 int sx, int dy, int dx, int height, int width)
48 { 48 {
49 struct fb_copyarea area; 49 struct fb_copyarea area;
50 50
51 area.sx = sx * vc->vc_font.width; 51 area.sx = sx * vc->vc_font.width;
52 area.sy = sy * vc->vc_font.height; 52 area.sy = sy * vc->vc_font.height;
53 area.dx = dx * vc->vc_font.width; 53 area.dx = dx * vc->vc_font.width;
54 area.dy = dy * vc->vc_font.height; 54 area.dy = dy * vc->vc_font.height;
55 area.height = height * vc->vc_font.height; 55 area.height = height * vc->vc_font.height;
56 area.width = width * vc->vc_font.width; 56 area.width = width * vc->vc_font.width;
57 57
58 info->fbops->fb_copyarea(info, &area); 58 info->fbops->fb_copyarea(info, &area);
59 } 59 }
60 60
61 static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy, 61 static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy,
62 int sx, int height, int width) 62 int sx, int height, int width)
63 { 63 {
64 int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; 64 int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
65 struct fb_fillrect region; 65 struct fb_fillrect region;
66 66
67 region.color = attr_bgcol_ec(bgshift, vc, info); 67 region.color = attr_bgcol_ec(bgshift, vc, info);
68 region.dx = sx * vc->vc_font.width; 68 region.dx = sx * vc->vc_font.width;
69 region.dy = sy * vc->vc_font.height; 69 region.dy = sy * vc->vc_font.height;
70 region.width = width * vc->vc_font.width; 70 region.width = width * vc->vc_font.width;
71 region.height = height * vc->vc_font.height; 71 region.height = height * vc->vc_font.height;
72 region.rop = ROP_COPY; 72 region.rop = ROP_COPY;
73 73
74 info->fbops->fb_fillrect(info, &region); 74 info->fbops->fb_fillrect(info, &region);
75 } 75 }
76 76
77 static inline void bit_putcs_aligned(struct vc_data *vc, struct fb_info *info, 77 static inline void bit_putcs_aligned(struct vc_data *vc, struct fb_info *info,
78 const u16 *s, u32 attr, u32 cnt, 78 const u16 *s, u32 attr, u32 cnt,
79 u32 d_pitch, u32 s_pitch, u32 cellsize, 79 u32 d_pitch, u32 s_pitch, u32 cellsize,
80 struct fb_image *image, u8 *buf, u8 *dst) 80 struct fb_image *image, u8 *buf, u8 *dst)
81 { 81 {
82 u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; 82 u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
83 u32 idx = vc->vc_font.width >> 3; 83 u32 idx = vc->vc_font.width >> 3;
84 u8 *src; 84 u8 *src;
85 85
86 while (cnt--) { 86 while (cnt--) {
87 src = vc->vc_font.data + (scr_readw(s++)& 87 src = vc->vc_font.data + (scr_readw(s++)&
88 charmask)*cellsize; 88 charmask)*cellsize;
89 89
90 if (attr) { 90 if (attr) {
91 update_attr(buf, src, attr, vc); 91 update_attr(buf, src, attr, vc);
92 src = buf; 92 src = buf;
93 } 93 }
94 94
95 if (likely(idx == 1)) 95 if (likely(idx == 1))
96 __fb_pad_aligned_buffer(dst, d_pitch, src, idx, 96 __fb_pad_aligned_buffer(dst, d_pitch, src, idx,
97 image->height); 97 image->height);
98 else 98 else
99 fb_pad_aligned_buffer(dst, d_pitch, src, idx, 99 fb_pad_aligned_buffer(dst, d_pitch, src, idx,
100 image->height); 100 image->height);
101 101
102 dst += s_pitch; 102 dst += s_pitch;
103 } 103 }
104 104
105 info->fbops->fb_imageblit(info, image); 105 info->fbops->fb_imageblit(info, image);
106 } 106 }
107 107
108 static inline void bit_putcs_unaligned(struct vc_data *vc, 108 static inline void bit_putcs_unaligned(struct vc_data *vc,
109 struct fb_info *info, const u16 *s, 109 struct fb_info *info, const u16 *s,
110 u32 attr, u32 cnt, u32 d_pitch, 110 u32 attr, u32 cnt, u32 d_pitch,
111 u32 s_pitch, u32 cellsize, 111 u32 s_pitch, u32 cellsize,
112 struct fb_image *image, u8 *buf, 112 struct fb_image *image, u8 *buf,
113 u8 *dst) 113 u8 *dst)
114 { 114 {
115 u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; 115 u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
116 u32 shift_low = 0, mod = vc->vc_font.width % 8; 116 u32 shift_low = 0, mod = vc->vc_font.width % 8;
117 u32 shift_high = 8; 117 u32 shift_high = 8;
118 u32 idx = vc->vc_font.width >> 3; 118 u32 idx = vc->vc_font.width >> 3;
119 u8 *src; 119 u8 *src;
120 120
121 while (cnt--) { 121 while (cnt--) {
122 src = vc->vc_font.data + (scr_readw(s++)& 122 src = vc->vc_font.data + (scr_readw(s++)&
123 charmask)*cellsize; 123 charmask)*cellsize;
124 124
125 if (attr) { 125 if (attr) {
126 update_attr(buf, src, attr, vc); 126 update_attr(buf, src, attr, vc);
127 src = buf; 127 src = buf;
128 } 128 }
129 129
130 fb_pad_unaligned_buffer(dst, d_pitch, src, idx, 130 fb_pad_unaligned_buffer(dst, d_pitch, src, idx,
131 image->height, shift_high, 131 image->height, shift_high,
132 shift_low, mod); 132 shift_low, mod);
133 shift_low += mod; 133 shift_low += mod;
134 dst += (shift_low >= 8) ? s_pitch : s_pitch - 1; 134 dst += (shift_low >= 8) ? s_pitch : s_pitch - 1;
135 shift_low &= 7; 135 shift_low &= 7;
136 shift_high = 8 - shift_low; 136 shift_high = 8 - shift_low;
137 } 137 }
138 138
139 info->fbops->fb_imageblit(info, image); 139 info->fbops->fb_imageblit(info, image);
140 140
141 } 141 }
142 142
143 static void bit_putcs(struct vc_data *vc, struct fb_info *info, 143 static void bit_putcs(struct vc_data *vc, struct fb_info *info,
144 const unsigned short *s, int count, int yy, int xx, 144 const unsigned short *s, int count, int yy, int xx,
145 int fg, int bg) 145 int fg, int bg)
146 { 146 {
147 struct fb_image image; 147 struct fb_image image;
148 u32 width = DIV_ROUND_UP(vc->vc_font.width, 8); 148 u32 width = DIV_ROUND_UP(vc->vc_font.width, 8);
149 u32 cellsize = width * vc->vc_font.height; 149 u32 cellsize = width * vc->vc_font.height;
150 u32 maxcnt = info->pixmap.size/cellsize; 150 u32 maxcnt = info->pixmap.size/cellsize;
151 u32 scan_align = info->pixmap.scan_align - 1; 151 u32 scan_align = info->pixmap.scan_align - 1;
152 u32 buf_align = info->pixmap.buf_align - 1; 152 u32 buf_align = info->pixmap.buf_align - 1;
153 u32 mod = vc->vc_font.width % 8, cnt, pitch, size; 153 u32 mod = vc->vc_font.width % 8, cnt, pitch, size;
154 u32 attribute = get_attribute(info, scr_readw(s)); 154 u32 attribute = get_attribute(info, scr_readw(s));
155 u8 *dst, *buf = NULL; 155 u8 *dst, *buf = NULL;
156 156
157 image.fg_color = fg; 157 image.fg_color = fg;
158 image.bg_color = bg; 158 image.bg_color = bg;
159 image.dx = xx * vc->vc_font.width; 159 image.dx = xx * vc->vc_font.width;
160 image.dy = yy * vc->vc_font.height; 160 image.dy = yy * vc->vc_font.height;
161 image.height = vc->vc_font.height; 161 image.height = vc->vc_font.height;
162 image.depth = 1; 162 image.depth = 1;
163 163
164 if (attribute) { 164 if (attribute) {
165 buf = kmalloc(cellsize, GFP_KERNEL); 165 buf = kmalloc(cellsize, GFP_ATOMIC);
166 if (!buf) 166 if (!buf)
167 return; 167 return;
168 } 168 }
169 169
170 while (count) { 170 while (count) {
171 if (count > maxcnt) 171 if (count > maxcnt)
172 cnt = maxcnt; 172 cnt = maxcnt;
173 else 173 else
174 cnt = count; 174 cnt = count;
175 175
176 image.width = vc->vc_font.width * cnt; 176 image.width = vc->vc_font.width * cnt;
177 pitch = DIV_ROUND_UP(image.width, 8) + scan_align; 177 pitch = DIV_ROUND_UP(image.width, 8) + scan_align;
178 pitch &= ~scan_align; 178 pitch &= ~scan_align;
179 size = pitch * image.height + buf_align; 179 size = pitch * image.height + buf_align;
180 size &= ~buf_align; 180 size &= ~buf_align;
181 dst = fb_get_buffer_offset(info, &info->pixmap, size); 181 dst = fb_get_buffer_offset(info, &info->pixmap, size);
182 image.data = dst; 182 image.data = dst;
183 183
184 if (!mod) 184 if (!mod)
185 bit_putcs_aligned(vc, info, s, attribute, cnt, pitch, 185 bit_putcs_aligned(vc, info, s, attribute, cnt, pitch,
186 width, cellsize, &image, buf, dst); 186 width, cellsize, &image, buf, dst);
187 else 187 else
188 bit_putcs_unaligned(vc, info, s, attribute, cnt, 188 bit_putcs_unaligned(vc, info, s, attribute, cnt,
189 pitch, width, cellsize, &image, 189 pitch, width, cellsize, &image,
190 buf, dst); 190 buf, dst);
191 191
192 image.dx += cnt * vc->vc_font.width; 192 image.dx += cnt * vc->vc_font.width;
193 count -= cnt; 193 count -= cnt;
194 s += cnt; 194 s += cnt;
195 } 195 }
196 196
197 /* buf is always NULL except when in monochrome mode, so in this case 197 /* buf is always NULL except when in monochrome mode, so in this case
198 it's a gain to check buf against NULL even though kfree() handles 198 it's a gain to check buf against NULL even though kfree() handles
199 NULL pointers just fine */ 199 NULL pointers just fine */
200 if (unlikely(buf)) 200 if (unlikely(buf))
201 kfree(buf); 201 kfree(buf);
202 202
203 } 203 }
204 204
205 static void bit_clear_margins(struct vc_data *vc, struct fb_info *info, 205 static void bit_clear_margins(struct vc_data *vc, struct fb_info *info,
206 int bottom_only) 206 int bottom_only)
207 { 207 {
208 int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; 208 int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
209 unsigned int cw = vc->vc_font.width; 209 unsigned int cw = vc->vc_font.width;
210 unsigned int ch = vc->vc_font.height; 210 unsigned int ch = vc->vc_font.height;
211 unsigned int rw = info->var.xres - (vc->vc_cols*cw); 211 unsigned int rw = info->var.xres - (vc->vc_cols*cw);
212 unsigned int bh = info->var.yres - (vc->vc_rows*ch); 212 unsigned int bh = info->var.yres - (vc->vc_rows*ch);
213 unsigned int rs = info->var.xres - rw; 213 unsigned int rs = info->var.xres - rw;
214 unsigned int bs = info->var.yres - bh; 214 unsigned int bs = info->var.yres - bh;
215 struct fb_fillrect region; 215 struct fb_fillrect region;
216 216
217 region.color = attr_bgcol_ec(bgshift, vc, info); 217 region.color = attr_bgcol_ec(bgshift, vc, info);
218 region.rop = ROP_COPY; 218 region.rop = ROP_COPY;
219 219
220 if (rw && !bottom_only) { 220 if (rw && !bottom_only) {
221 region.dx = info->var.xoffset + rs; 221 region.dx = info->var.xoffset + rs;
222 region.dy = 0; 222 region.dy = 0;
223 region.width = rw; 223 region.width = rw;
224 region.height = info->var.yres_virtual; 224 region.height = info->var.yres_virtual;
225 info->fbops->fb_fillrect(info, &region); 225 info->fbops->fb_fillrect(info, &region);
226 } 226 }
227 227
228 if (bh) { 228 if (bh) {
229 region.dx = info->var.xoffset; 229 region.dx = info->var.xoffset;
230 region.dy = info->var.yoffset + bs; 230 region.dy = info->var.yoffset + bs;
231 region.width = rs; 231 region.width = rs;
232 region.height = bh; 232 region.height = bh;
233 info->fbops->fb_fillrect(info, &region); 233 info->fbops->fb_fillrect(info, &region);
234 } 234 }
235 } 235 }
236 236
237 static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode, 237 static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode,
238 int softback_lines, int fg, int bg) 238 int softback_lines, int fg, int bg)
239 { 239 {
240 struct fb_cursor cursor; 240 struct fb_cursor cursor;
241 struct fbcon_ops *ops = info->fbcon_par; 241 struct fbcon_ops *ops = info->fbcon_par;
242 unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; 242 unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
243 int w = DIV_ROUND_UP(vc->vc_font.width, 8), c; 243 int w = DIV_ROUND_UP(vc->vc_font.width, 8), c;
244 int y = real_y(ops->p, vc->vc_y); 244 int y = real_y(ops->p, vc->vc_y);
245 int attribute, use_sw = (vc->vc_cursor_type & 0x10); 245 int attribute, use_sw = (vc->vc_cursor_type & 0x10);
246 int err = 1; 246 int err = 1;
247 char *src; 247 char *src;
248 248
249 cursor.set = 0; 249 cursor.set = 0;
250 250
251 if (softback_lines) { 251 if (softback_lines) {
252 if (y + softback_lines >= vc->vc_rows) { 252 if (y + softback_lines >= vc->vc_rows) {
253 mode = CM_ERASE; 253 mode = CM_ERASE;
254 ops->cursor_flash = 0; 254 ops->cursor_flash = 0;
255 return; 255 return;
256 } else 256 } else
257 y += softback_lines; 257 y += softback_lines;
258 } 258 }
259 259
260 c = scr_readw((u16 *) vc->vc_pos); 260 c = scr_readw((u16 *) vc->vc_pos);
261 attribute = get_attribute(info, c); 261 attribute = get_attribute(info, c);
262 src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height)); 262 src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height));
263 263
264 if (ops->cursor_state.image.data != src || 264 if (ops->cursor_state.image.data != src ||
265 ops->cursor_reset) { 265 ops->cursor_reset) {
266 ops->cursor_state.image.data = src; 266 ops->cursor_state.image.data = src;
267 cursor.set |= FB_CUR_SETIMAGE; 267 cursor.set |= FB_CUR_SETIMAGE;
268 } 268 }
269 269
270 if (attribute) { 270 if (attribute) {
271 u8 *dst; 271 u8 *dst;
272 272
273 dst = kmalloc(w * vc->vc_font.height, GFP_ATOMIC); 273 dst = kmalloc(w * vc->vc_font.height, GFP_ATOMIC);
274 if (!dst) 274 if (!dst)
275 return; 275 return;
276 kfree(ops->cursor_data); 276 kfree(ops->cursor_data);
277 ops->cursor_data = dst; 277 ops->cursor_data = dst;
278 update_attr(dst, src, attribute, vc); 278 update_attr(dst, src, attribute, vc);
279 src = dst; 279 src = dst;
280 } 280 }
281 281
282 if (ops->cursor_state.image.fg_color != fg || 282 if (ops->cursor_state.image.fg_color != fg ||
283 ops->cursor_state.image.bg_color != bg || 283 ops->cursor_state.image.bg_color != bg ||
284 ops->cursor_reset) { 284 ops->cursor_reset) {
285 ops->cursor_state.image.fg_color = fg; 285 ops->cursor_state.image.fg_color = fg;
286 ops->cursor_state.image.bg_color = bg; 286 ops->cursor_state.image.bg_color = bg;
287 cursor.set |= FB_CUR_SETCMAP; 287 cursor.set |= FB_CUR_SETCMAP;
288 } 288 }
289 289
290 if ((ops->cursor_state.image.dx != (vc->vc_font.width * vc->vc_x)) || 290 if ((ops->cursor_state.image.dx != (vc->vc_font.width * vc->vc_x)) ||
291 (ops->cursor_state.image.dy != (vc->vc_font.height * y)) || 291 (ops->cursor_state.image.dy != (vc->vc_font.height * y)) ||
292 ops->cursor_reset) { 292 ops->cursor_reset) {
293 ops->cursor_state.image.dx = vc->vc_font.width * vc->vc_x; 293 ops->cursor_state.image.dx = vc->vc_font.width * vc->vc_x;
294 ops->cursor_state.image.dy = vc->vc_font.height * y; 294 ops->cursor_state.image.dy = vc->vc_font.height * y;
295 cursor.set |= FB_CUR_SETPOS; 295 cursor.set |= FB_CUR_SETPOS;
296 } 296 }
297 297
298 if (ops->cursor_state.image.height != vc->vc_font.height || 298 if (ops->cursor_state.image.height != vc->vc_font.height ||
299 ops->cursor_state.image.width != vc->vc_font.width || 299 ops->cursor_state.image.width != vc->vc_font.width ||
300 ops->cursor_reset) { 300 ops->cursor_reset) {
301 ops->cursor_state.image.height = vc->vc_font.height; 301 ops->cursor_state.image.height = vc->vc_font.height;
302 ops->cursor_state.image.width = vc->vc_font.width; 302 ops->cursor_state.image.width = vc->vc_font.width;
303 cursor.set |= FB_CUR_SETSIZE; 303 cursor.set |= FB_CUR_SETSIZE;
304 } 304 }
305 305
306 if (ops->cursor_state.hot.x || ops->cursor_state.hot.y || 306 if (ops->cursor_state.hot.x || ops->cursor_state.hot.y ||
307 ops->cursor_reset) { 307 ops->cursor_reset) {
308 ops->cursor_state.hot.x = cursor.hot.y = 0; 308 ops->cursor_state.hot.x = cursor.hot.y = 0;
309 cursor.set |= FB_CUR_SETHOT; 309 cursor.set |= FB_CUR_SETHOT;
310 } 310 }
311 311
312 if (cursor.set & FB_CUR_SETSIZE || 312 if (cursor.set & FB_CUR_SETSIZE ||
313 vc->vc_cursor_type != ops->p->cursor_shape || 313 vc->vc_cursor_type != ops->p->cursor_shape ||
314 ops->cursor_state.mask == NULL || 314 ops->cursor_state.mask == NULL ||
315 ops->cursor_reset) { 315 ops->cursor_reset) {
316 char *mask = kmalloc(w*vc->vc_font.height, GFP_ATOMIC); 316 char *mask = kmalloc(w*vc->vc_font.height, GFP_ATOMIC);
317 int cur_height, size, i = 0; 317 int cur_height, size, i = 0;
318 u8 msk = 0xff; 318 u8 msk = 0xff;
319 319
320 if (!mask) 320 if (!mask)
321 return; 321 return;
322 322
323 kfree(ops->cursor_state.mask); 323 kfree(ops->cursor_state.mask);
324 ops->cursor_state.mask = mask; 324 ops->cursor_state.mask = mask;
325 325
326 ops->p->cursor_shape = vc->vc_cursor_type; 326 ops->p->cursor_shape = vc->vc_cursor_type;
327 cursor.set |= FB_CUR_SETSHAPE; 327 cursor.set |= FB_CUR_SETSHAPE;
328 328
329 switch (ops->p->cursor_shape & CUR_HWMASK) { 329 switch (ops->p->cursor_shape & CUR_HWMASK) {
330 case CUR_NONE: 330 case CUR_NONE:
331 cur_height = 0; 331 cur_height = 0;
332 break; 332 break;
333 case CUR_UNDERLINE: 333 case CUR_UNDERLINE:
334 cur_height = (vc->vc_font.height < 10) ? 1 : 2; 334 cur_height = (vc->vc_font.height < 10) ? 1 : 2;
335 break; 335 break;
336 case CUR_LOWER_THIRD: 336 case CUR_LOWER_THIRD:
337 cur_height = vc->vc_font.height/3; 337 cur_height = vc->vc_font.height/3;
338 break; 338 break;
339 case CUR_LOWER_HALF: 339 case CUR_LOWER_HALF:
340 cur_height = vc->vc_font.height >> 1; 340 cur_height = vc->vc_font.height >> 1;
341 break; 341 break;
342 case CUR_TWO_THIRDS: 342 case CUR_TWO_THIRDS:
343 cur_height = (vc->vc_font.height << 1)/3; 343 cur_height = (vc->vc_font.height << 1)/3;
344 break; 344 break;
345 case CUR_BLOCK: 345 case CUR_BLOCK:
346 default: 346 default:
347 cur_height = vc->vc_font.height; 347 cur_height = vc->vc_font.height;
348 break; 348 break;
349 } 349 }
350 size = (vc->vc_font.height - cur_height) * w; 350 size = (vc->vc_font.height - cur_height) * w;
351 while (size--) 351 while (size--)
352 mask[i++] = ~msk; 352 mask[i++] = ~msk;
353 size = cur_height * w; 353 size = cur_height * w;
354 while (size--) 354 while (size--)
355 mask[i++] = msk; 355 mask[i++] = msk;
356 } 356 }
357 357
358 switch (mode) { 358 switch (mode) {
359 case CM_ERASE: 359 case CM_ERASE:
360 ops->cursor_state.enable = 0; 360 ops->cursor_state.enable = 0;
361 break; 361 break;
362 case CM_DRAW: 362 case CM_DRAW:
363 case CM_MOVE: 363 case CM_MOVE:
364 default: 364 default:
365 ops->cursor_state.enable = (use_sw) ? 0 : 1; 365 ops->cursor_state.enable = (use_sw) ? 0 : 1;
366 break; 366 break;
367 } 367 }
368 368
369 cursor.image.data = src; 369 cursor.image.data = src;
370 cursor.image.fg_color = ops->cursor_state.image.fg_color; 370 cursor.image.fg_color = ops->cursor_state.image.fg_color;
371 cursor.image.bg_color = ops->cursor_state.image.bg_color; 371 cursor.image.bg_color = ops->cursor_state.image.bg_color;
372 cursor.image.dx = ops->cursor_state.image.dx; 372 cursor.image.dx = ops->cursor_state.image.dx;
373 cursor.image.dy = ops->cursor_state.image.dy; 373 cursor.image.dy = ops->cursor_state.image.dy;
374 cursor.image.height = ops->cursor_state.image.height; 374 cursor.image.height = ops->cursor_state.image.height;
375 cursor.image.width = ops->cursor_state.image.width; 375 cursor.image.width = ops->cursor_state.image.width;
376 cursor.hot.x = ops->cursor_state.hot.x; 376 cursor.hot.x = ops->cursor_state.hot.x;
377 cursor.hot.y = ops->cursor_state.hot.y; 377 cursor.hot.y = ops->cursor_state.hot.y;
378 cursor.mask = ops->cursor_state.mask; 378 cursor.mask = ops->cursor_state.mask;
379 cursor.enable = ops->cursor_state.enable; 379 cursor.enable = ops->cursor_state.enable;
380 cursor.image.depth = 1; 380 cursor.image.depth = 1;
381 cursor.rop = ROP_XOR; 381 cursor.rop = ROP_XOR;
382 382
383 if (info->fbops->fb_cursor) 383 if (info->fbops->fb_cursor)
384 err = info->fbops->fb_cursor(info, &cursor); 384 err = info->fbops->fb_cursor(info, &cursor);
385 385
386 if (err) 386 if (err)
387 soft_cursor(info, &cursor); 387 soft_cursor(info, &cursor);
388 388
389 ops->cursor_reset = 0; 389 ops->cursor_reset = 0;
390 } 390 }
391 391
392 static int bit_update_start(struct fb_info *info) 392 static int bit_update_start(struct fb_info *info)
393 { 393 {
394 struct fbcon_ops *ops = info->fbcon_par; 394 struct fbcon_ops *ops = info->fbcon_par;
395 int err; 395 int err;
396 396
397 err = fb_pan_display(info, &ops->var); 397 err = fb_pan_display(info, &ops->var);
398 ops->var.xoffset = info->var.xoffset; 398 ops->var.xoffset = info->var.xoffset;
399 ops->var.yoffset = info->var.yoffset; 399 ops->var.yoffset = info->var.yoffset;
400 ops->var.vmode = info->var.vmode; 400 ops->var.vmode = info->var.vmode;
401 return err; 401 return err;
402 } 402 }
403 403
404 void fbcon_set_bitops(struct fbcon_ops *ops) 404 void fbcon_set_bitops(struct fbcon_ops *ops)
405 { 405 {
406 ops->bmove = bit_bmove; 406 ops->bmove = bit_bmove;
407 ops->clear = bit_clear; 407 ops->clear = bit_clear;
408 ops->putcs = bit_putcs; 408 ops->putcs = bit_putcs;
409 ops->clear_margins = bit_clear_margins; 409 ops->clear_margins = bit_clear_margins;
410 ops->cursor = bit_cursor; 410 ops->cursor = bit_cursor;
411 ops->update_start = bit_update_start; 411 ops->update_start = bit_update_start;
412 ops->rotate_font = NULL; 412 ops->rotate_font = NULL;
413 413
414 if (ops->rotate) 414 if (ops->rotate)
415 fbcon_set_rotate(ops); 415 fbcon_set_rotate(ops);
416 } 416 }
417 417
418 EXPORT_SYMBOL(fbcon_set_bitops); 418 EXPORT_SYMBOL(fbcon_set_bitops);
419 419
420 MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>"); 420 MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
421 MODULE_DESCRIPTION("Bit Blitting Operation"); 421 MODULE_DESCRIPTION("Bit Blitting Operation");
422 MODULE_LICENSE("GPL"); 422 MODULE_LICENSE("GPL");
423 423
424 424
drivers/video/console/fbcon.c
1 /* 1 /*
2 * linux/drivers/video/fbcon.c -- Low level frame buffer based console driver 2 * linux/drivers/video/fbcon.c -- Low level frame buffer based console driver
3 * 3 *
4 * Copyright (C) 1995 Geert Uytterhoeven 4 * Copyright (C) 1995 Geert Uytterhoeven
5 * 5 *
6 * 6 *
7 * This file is based on the original Amiga console driver (amicon.c): 7 * This file is based on the original Amiga console driver (amicon.c):
8 * 8 *
9 * Copyright (C) 1993 Hamish Macdonald 9 * Copyright (C) 1993 Hamish Macdonald
10 * Greg Harp 10 * Greg Harp
11 * Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk] 11 * Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk]
12 * 12 *
13 * with work by William Rucklidge (wjr@cs.cornell.edu) 13 * with work by William Rucklidge (wjr@cs.cornell.edu)
14 * Geert Uytterhoeven 14 * Geert Uytterhoeven
15 * Jes Sorensen (jds@kom.auc.dk) 15 * Jes Sorensen (jds@kom.auc.dk)
16 * Martin Apel 16 * Martin Apel
17 * 17 *
18 * and on the original Atari console driver (atacon.c): 18 * and on the original Atari console driver (atacon.c):
19 * 19 *
20 * Copyright (C) 1993 Bjoern Brauel 20 * Copyright (C) 1993 Bjoern Brauel
21 * Roman Hodek 21 * Roman Hodek
22 * 22 *
23 * with work by Guenther Kelleter 23 * with work by Guenther Kelleter
24 * Martin Schaller 24 * Martin Schaller
25 * Andreas Schwab 25 * Andreas Schwab
26 * 26 *
27 * Hardware cursor support added by Emmanuel Marty (core@ggi-project.org) 27 * Hardware cursor support added by Emmanuel Marty (core@ggi-project.org)
28 * Smart redraw scrolling, arbitrary font width support, 512char font support 28 * Smart redraw scrolling, arbitrary font width support, 512char font support
29 * and software scrollback added by 29 * and software scrollback added by
30 * Jakub Jelinek (jj@ultra.linux.cz) 30 * Jakub Jelinek (jj@ultra.linux.cz)
31 * 31 *
32 * Random hacking by Martin Mares <mj@ucw.cz> 32 * Random hacking by Martin Mares <mj@ucw.cz>
33 * 33 *
34 * 2001 - Documented with DocBook 34 * 2001 - Documented with DocBook
35 * - Brad Douglas <brad@neruo.com> 35 * - Brad Douglas <brad@neruo.com>
36 * 36 *
37 * The low level operations for the various display memory organizations are 37 * The low level operations for the various display memory organizations are
38 * now in separate source files. 38 * now in separate source files.
39 * 39 *
40 * Currently the following organizations are supported: 40 * Currently the following organizations are supported:
41 * 41 *
42 * o afb Amiga bitplanes 42 * o afb Amiga bitplanes
43 * o cfb{2,4,8,16,24,32} Packed pixels 43 * o cfb{2,4,8,16,24,32} Packed pixels
44 * o ilbm Amiga interleaved bitplanes 44 * o ilbm Amiga interleaved bitplanes
45 * o iplan2p[248] Atari interleaved bitplanes 45 * o iplan2p[248] Atari interleaved bitplanes
46 * o mfb Monochrome 46 * o mfb Monochrome
47 * o vga VGA characters/attributes 47 * o vga VGA characters/attributes
48 * 48 *
49 * To do: 49 * To do:
50 * 50 *
51 * - Implement 16 plane mode (iplan2p16) 51 * - Implement 16 plane mode (iplan2p16)
52 * 52 *
53 * 53 *
54 * This file is subject to the terms and conditions of the GNU General Public 54 * This file is subject to the terms and conditions of the GNU General Public
55 * License. See the file COPYING in the main directory of this archive for 55 * License. See the file COPYING in the main directory of this archive for
56 * more details. 56 * more details.
57 */ 57 */
58 58
59 #undef FBCONDEBUG 59 #undef FBCONDEBUG
60 60
61 #include <linux/module.h> 61 #include <linux/module.h>
62 #include <linux/types.h> 62 #include <linux/types.h>
63 #include <linux/fs.h> 63 #include <linux/fs.h>
64 #include <linux/kernel.h> 64 #include <linux/kernel.h>
65 #include <linux/delay.h> /* MSch: for IRQ probe */ 65 #include <linux/delay.h> /* MSch: for IRQ probe */
66 #include <linux/console.h> 66 #include <linux/console.h>
67 #include <linux/string.h> 67 #include <linux/string.h>
68 #include <linux/kd.h> 68 #include <linux/kd.h>
69 #include <linux/slab.h> 69 #include <linux/slab.h>
70 #include <linux/fb.h> 70 #include <linux/fb.h>
71 #include <linux/vt_kern.h> 71 #include <linux/vt_kern.h>
72 #include <linux/selection.h> 72 #include <linux/selection.h>
73 #include <linux/font.h> 73 #include <linux/font.h>
74 #include <linux/smp.h> 74 #include <linux/smp.h>
75 #include <linux/init.h> 75 #include <linux/init.h>
76 #include <linux/interrupt.h> 76 #include <linux/interrupt.h>
77 #include <linux/crc32.h> /* For counting font checksums */ 77 #include <linux/crc32.h> /* For counting font checksums */
78 #include <asm/fb.h> 78 #include <asm/fb.h>
79 #include <asm/irq.h> 79 #include <asm/irq.h>
80 80
81 #include "fbcon.h" 81 #include "fbcon.h"
82 82
83 #ifdef FBCONDEBUG 83 #ifdef FBCONDEBUG
84 # define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) 84 # define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)
85 #else 85 #else
86 # define DPRINTK(fmt, args...) 86 # define DPRINTK(fmt, args...)
87 #endif 87 #endif
88 88
89 enum { 89 enum {
90 FBCON_LOGO_CANSHOW = -1, /* the logo can be shown */ 90 FBCON_LOGO_CANSHOW = -1, /* the logo can be shown */
91 FBCON_LOGO_DRAW = -2, /* draw the logo to a console */ 91 FBCON_LOGO_DRAW = -2, /* draw the logo to a console */
92 FBCON_LOGO_DONTSHOW = -3 /* do not show the logo */ 92 FBCON_LOGO_DONTSHOW = -3 /* do not show the logo */
93 }; 93 };
94 94
95 static struct display fb_display[MAX_NR_CONSOLES]; 95 static struct display fb_display[MAX_NR_CONSOLES];
96 96
97 static signed char con2fb_map[MAX_NR_CONSOLES]; 97 static signed char con2fb_map[MAX_NR_CONSOLES];
98 static signed char con2fb_map_boot[MAX_NR_CONSOLES]; 98 static signed char con2fb_map_boot[MAX_NR_CONSOLES];
99 99
100 static int logo_lines; 100 static int logo_lines;
101 /* logo_shown is an index to vc_cons when >= 0; otherwise follows FBCON_LOGO 101 /* logo_shown is an index to vc_cons when >= 0; otherwise follows FBCON_LOGO
102 enums. */ 102 enums. */
103 static int logo_shown = FBCON_LOGO_CANSHOW; 103 static int logo_shown = FBCON_LOGO_CANSHOW;
104 /* Software scrollback */ 104 /* Software scrollback */
105 static int fbcon_softback_size = 32768; 105 static int fbcon_softback_size = 32768;
106 static unsigned long softback_buf, softback_curr; 106 static unsigned long softback_buf, softback_curr;
107 static unsigned long softback_in; 107 static unsigned long softback_in;
108 static unsigned long softback_top, softback_end; 108 static unsigned long softback_top, softback_end;
109 static int softback_lines; 109 static int softback_lines;
110 /* console mappings */ 110 /* console mappings */
111 static int first_fb_vc; 111 static int first_fb_vc;
112 static int last_fb_vc = MAX_NR_CONSOLES - 1; 112 static int last_fb_vc = MAX_NR_CONSOLES - 1;
113 static int fbcon_is_default = 1; 113 static int fbcon_is_default = 1;
114 static int fbcon_has_exited; 114 static int fbcon_has_exited;
115 static int primary_device = -1; 115 static int primary_device = -1;
116 static int fbcon_has_console_bind; 116 static int fbcon_has_console_bind;
117 117
118 #ifdef CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY 118 #ifdef CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
119 static int map_override; 119 static int map_override;
120 120
121 static inline void fbcon_map_override(void) 121 static inline void fbcon_map_override(void)
122 { 122 {
123 map_override = 1; 123 map_override = 1;
124 } 124 }
125 #else 125 #else
126 static inline void fbcon_map_override(void) 126 static inline void fbcon_map_override(void)
127 { 127 {
128 } 128 }
129 #endif /* CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY */ 129 #endif /* CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY */
130 130
131 /* font data */ 131 /* font data */
132 static char fontname[40]; 132 static char fontname[40];
133 133
134 /* current fb_info */ 134 /* current fb_info */
135 static int info_idx = -1; 135 static int info_idx = -1;
136 136
137 /* console rotation */ 137 /* console rotation */
138 static int initial_rotation; 138 static int initial_rotation;
139 static int fbcon_has_sysfs; 139 static int fbcon_has_sysfs;
140 140
141 static const struct consw fb_con; 141 static const struct consw fb_con;
142 142
143 #define CM_SOFTBACK (8) 143 #define CM_SOFTBACK (8)
144 144
145 #define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row) 145 #define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row)
146 146
147 static int fbcon_set_origin(struct vc_data *); 147 static int fbcon_set_origin(struct vc_data *);
148 148
149 #define CURSOR_DRAW_DELAY (1) 149 #define CURSOR_DRAW_DELAY (1)
150 150
151 static int vbl_cursor_cnt; 151 static int vbl_cursor_cnt;
152 static int fbcon_cursor_noblink; 152 static int fbcon_cursor_noblink;
153 153
154 #define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1) 154 #define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1)
155 155
156 /* 156 /*
157 * Interface used by the world 157 * Interface used by the world
158 */ 158 */
159 159
160 static const char *fbcon_startup(void); 160 static const char *fbcon_startup(void);
161 static void fbcon_init(struct vc_data *vc, int init); 161 static void fbcon_init(struct vc_data *vc, int init);
162 static void fbcon_deinit(struct vc_data *vc); 162 static void fbcon_deinit(struct vc_data *vc);
163 static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height, 163 static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height,
164 int width); 164 int width);
165 static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos); 165 static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos);
166 static void fbcon_putcs(struct vc_data *vc, const unsigned short *s, 166 static void fbcon_putcs(struct vc_data *vc, const unsigned short *s,
167 int count, int ypos, int xpos); 167 int count, int ypos, int xpos);
168 static void fbcon_clear_margins(struct vc_data *vc, int bottom_only); 168 static void fbcon_clear_margins(struct vc_data *vc, int bottom_only);
169 static void fbcon_cursor(struct vc_data *vc, int mode); 169 static void fbcon_cursor(struct vc_data *vc, int mode);
170 static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, 170 static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
171 int count); 171 int count);
172 static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, 172 static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx,
173 int height, int width); 173 int height, int width);
174 static int fbcon_switch(struct vc_data *vc); 174 static int fbcon_switch(struct vc_data *vc);
175 static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch); 175 static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch);
176 static int fbcon_set_palette(struct vc_data *vc, unsigned char *table); 176 static int fbcon_set_palette(struct vc_data *vc, unsigned char *table);
177 static int fbcon_scrolldelta(struct vc_data *vc, int lines); 177 static int fbcon_scrolldelta(struct vc_data *vc, int lines);
178 178
179 /* 179 /*
180 * Internal routines 180 * Internal routines
181 */ 181 */
182 static __inline__ void ywrap_up(struct vc_data *vc, int count); 182 static __inline__ void ywrap_up(struct vc_data *vc, int count);
183 static __inline__ void ywrap_down(struct vc_data *vc, int count); 183 static __inline__ void ywrap_down(struct vc_data *vc, int count);
184 static __inline__ void ypan_up(struct vc_data *vc, int count); 184 static __inline__ void ypan_up(struct vc_data *vc, int count);
185 static __inline__ void ypan_down(struct vc_data *vc, int count); 185 static __inline__ void ypan_down(struct vc_data *vc, int count);
186 static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx, 186 static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx,
187 int dy, int dx, int height, int width, u_int y_break); 187 int dy, int dx, int height, int width, u_int y_break);
188 static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, 188 static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
189 int unit); 189 int unit);
190 static void fbcon_redraw_move(struct vc_data *vc, struct display *p, 190 static void fbcon_redraw_move(struct vc_data *vc, struct display *p,
191 int line, int count, int dy); 191 int line, int count, int dy);
192 static void fbcon_modechanged(struct fb_info *info); 192 static void fbcon_modechanged(struct fb_info *info);
193 static void fbcon_set_all_vcs(struct fb_info *info); 193 static void fbcon_set_all_vcs(struct fb_info *info);
194 static void fbcon_start(void); 194 static void fbcon_start(void);
195 static void fbcon_exit(void); 195 static void fbcon_exit(void);
196 static struct device *fbcon_device; 196 static struct device *fbcon_device;
197 197
198 #ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION 198 #ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
199 static inline void fbcon_set_rotation(struct fb_info *info) 199 static inline void fbcon_set_rotation(struct fb_info *info)
200 { 200 {
201 struct fbcon_ops *ops = info->fbcon_par; 201 struct fbcon_ops *ops = info->fbcon_par;
202 202
203 if (!(info->flags & FBINFO_MISC_TILEBLITTING) && 203 if (!(info->flags & FBINFO_MISC_TILEBLITTING) &&
204 ops->p->con_rotate < 4) 204 ops->p->con_rotate < 4)
205 ops->rotate = ops->p->con_rotate; 205 ops->rotate = ops->p->con_rotate;
206 else 206 else
207 ops->rotate = 0; 207 ops->rotate = 0;
208 } 208 }
209 209
210 static void fbcon_rotate(struct fb_info *info, u32 rotate) 210 static void fbcon_rotate(struct fb_info *info, u32 rotate)
211 { 211 {
212 struct fbcon_ops *ops= info->fbcon_par; 212 struct fbcon_ops *ops= info->fbcon_par;
213 struct fb_info *fb_info; 213 struct fb_info *fb_info;
214 214
215 if (!ops || ops->currcon == -1) 215 if (!ops || ops->currcon == -1)
216 return; 216 return;
217 217
218 fb_info = registered_fb[con2fb_map[ops->currcon]]; 218 fb_info = registered_fb[con2fb_map[ops->currcon]];
219 219
220 if (info == fb_info) { 220 if (info == fb_info) {
221 struct display *p = &fb_display[ops->currcon]; 221 struct display *p = &fb_display[ops->currcon];
222 222
223 if (rotate < 4) 223 if (rotate < 4)
224 p->con_rotate = rotate; 224 p->con_rotate = rotate;
225 else 225 else
226 p->con_rotate = 0; 226 p->con_rotate = 0;
227 227
228 fbcon_modechanged(info); 228 fbcon_modechanged(info);
229 } 229 }
230 } 230 }
231 231
232 static void fbcon_rotate_all(struct fb_info *info, u32 rotate) 232 static void fbcon_rotate_all(struct fb_info *info, u32 rotate)
233 { 233 {
234 struct fbcon_ops *ops = info->fbcon_par; 234 struct fbcon_ops *ops = info->fbcon_par;
235 struct vc_data *vc; 235 struct vc_data *vc;
236 struct display *p; 236 struct display *p;
237 int i; 237 int i;
238 238
239 if (!ops || ops->currcon < 0 || rotate > 3) 239 if (!ops || ops->currcon < 0 || rotate > 3)
240 return; 240 return;
241 241
242 for (i = first_fb_vc; i <= last_fb_vc; i++) { 242 for (i = first_fb_vc; i <= last_fb_vc; i++) {
243 vc = vc_cons[i].d; 243 vc = vc_cons[i].d;
244 if (!vc || vc->vc_mode != KD_TEXT || 244 if (!vc || vc->vc_mode != KD_TEXT ||
245 registered_fb[con2fb_map[i]] != info) 245 registered_fb[con2fb_map[i]] != info)
246 continue; 246 continue;
247 247
248 p = &fb_display[vc->vc_num]; 248 p = &fb_display[vc->vc_num];
249 p->con_rotate = rotate; 249 p->con_rotate = rotate;
250 } 250 }
251 251
252 fbcon_set_all_vcs(info); 252 fbcon_set_all_vcs(info);
253 } 253 }
254 #else 254 #else
255 static inline void fbcon_set_rotation(struct fb_info *info) 255 static inline void fbcon_set_rotation(struct fb_info *info)
256 { 256 {
257 struct fbcon_ops *ops = info->fbcon_par; 257 struct fbcon_ops *ops = info->fbcon_par;
258 258
259 ops->rotate = FB_ROTATE_UR; 259 ops->rotate = FB_ROTATE_UR;
260 } 260 }
261 261
262 static void fbcon_rotate(struct fb_info *info, u32 rotate) 262 static void fbcon_rotate(struct fb_info *info, u32 rotate)
263 { 263 {
264 return; 264 return;
265 } 265 }
266 266
267 static void fbcon_rotate_all(struct fb_info *info, u32 rotate) 267 static void fbcon_rotate_all(struct fb_info *info, u32 rotate)
268 { 268 {
269 return; 269 return;
270 } 270 }
271 #endif /* CONFIG_FRAMEBUFFER_CONSOLE_ROTATION */ 271 #endif /* CONFIG_FRAMEBUFFER_CONSOLE_ROTATION */
272 272
273 static int fbcon_get_rotate(struct fb_info *info) 273 static int fbcon_get_rotate(struct fb_info *info)
274 { 274 {
275 struct fbcon_ops *ops = info->fbcon_par; 275 struct fbcon_ops *ops = info->fbcon_par;
276 276
277 return (ops) ? ops->rotate : 0; 277 return (ops) ? ops->rotate : 0;
278 } 278 }
279 279
280 static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info) 280 static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info)
281 { 281 {
282 struct fbcon_ops *ops = info->fbcon_par; 282 struct fbcon_ops *ops = info->fbcon_par;
283 283
284 return (info->state != FBINFO_STATE_RUNNING || 284 return (info->state != FBINFO_STATE_RUNNING ||
285 vc->vc_mode != KD_TEXT || ops->graphics) && 285 vc->vc_mode != KD_TEXT || ops->graphics) &&
286 !vt_force_oops_output(vc); 286 !vt_force_oops_output(vc);
287 } 287 }
288 288
289 static int get_color(struct vc_data *vc, struct fb_info *info, 289 static int get_color(struct vc_data *vc, struct fb_info *info,
290 u16 c, int is_fg) 290 u16 c, int is_fg)
291 { 291 {
292 int depth = fb_get_color_depth(&info->var, &info->fix); 292 int depth = fb_get_color_depth(&info->var, &info->fix);
293 int color = 0; 293 int color = 0;
294 294
295 if (console_blanked) { 295 if (console_blanked) {
296 unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; 296 unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
297 297
298 c = vc->vc_video_erase_char & charmask; 298 c = vc->vc_video_erase_char & charmask;
299 } 299 }
300 300
301 if (depth != 1) 301 if (depth != 1)
302 color = (is_fg) ? attr_fgcol((vc->vc_hi_font_mask) ? 9 : 8, c) 302 color = (is_fg) ? attr_fgcol((vc->vc_hi_font_mask) ? 9 : 8, c)
303 : attr_bgcol((vc->vc_hi_font_mask) ? 13 : 12, c); 303 : attr_bgcol((vc->vc_hi_font_mask) ? 13 : 12, c);
304 304
305 switch (depth) { 305 switch (depth) {
306 case 1: 306 case 1:
307 { 307 {
308 int col = mono_col(info); 308 int col = mono_col(info);
309 /* 0 or 1 */ 309 /* 0 or 1 */
310 int fg = (info->fix.visual != FB_VISUAL_MONO01) ? col : 0; 310 int fg = (info->fix.visual != FB_VISUAL_MONO01) ? col : 0;
311 int bg = (info->fix.visual != FB_VISUAL_MONO01) ? 0 : col; 311 int bg = (info->fix.visual != FB_VISUAL_MONO01) ? 0 : col;
312 312
313 if (console_blanked) 313 if (console_blanked)
314 fg = bg; 314 fg = bg;
315 315
316 color = (is_fg) ? fg : bg; 316 color = (is_fg) ? fg : bg;
317 break; 317 break;
318 } 318 }
319 case 2: 319 case 2:
320 /* 320 /*
321 * Scale down 16-colors to 4 colors. Default 4-color palette 321 * Scale down 16-colors to 4 colors. Default 4-color palette
322 * is grayscale. However, simply dividing the values by 4 322 * is grayscale. However, simply dividing the values by 4
323 * will not work, as colors 1, 2 and 3 will be scaled-down 323 * will not work, as colors 1, 2 and 3 will be scaled-down
324 * to zero rendering them invisible. So empirically convert 324 * to zero rendering them invisible. So empirically convert
325 * colors to a sane 4-level grayscale. 325 * colors to a sane 4-level grayscale.
326 */ 326 */
327 switch (color) { 327 switch (color) {
328 case 0: 328 case 0:
329 color = 0; /* black */ 329 color = 0; /* black */
330 break; 330 break;
331 case 1 ... 6: 331 case 1 ... 6:
332 color = 2; /* white */ 332 color = 2; /* white */
333 break; 333 break;
334 case 7 ... 8: 334 case 7 ... 8:
335 color = 1; /* gray */ 335 color = 1; /* gray */
336 break; 336 break;
337 default: 337 default:
338 color = 3; /* intense white */ 338 color = 3; /* intense white */
339 break; 339 break;
340 } 340 }
341 break; 341 break;
342 case 3: 342 case 3:
343 /* 343 /*
344 * Last 8 entries of default 16-color palette is a more intense 344 * Last 8 entries of default 16-color palette is a more intense
345 * version of the first 8 (i.e., same chrominance, different 345 * version of the first 8 (i.e., same chrominance, different
346 * luminance). 346 * luminance).
347 */ 347 */
348 color &= 7; 348 color &= 7;
349 break; 349 break;
350 } 350 }
351 351
352 352
353 return color; 353 return color;
354 } 354 }
355 355
356 static void fbcon_update_softback(struct vc_data *vc) 356 static void fbcon_update_softback(struct vc_data *vc)
357 { 357 {
358 int l = fbcon_softback_size / vc->vc_size_row; 358 int l = fbcon_softback_size / vc->vc_size_row;
359 359
360 if (l > 5) 360 if (l > 5)
361 softback_end = softback_buf + l * vc->vc_size_row; 361 softback_end = softback_buf + l * vc->vc_size_row;
362 else 362 else
363 /* Smaller scrollback makes no sense, and 0 would screw 363 /* Smaller scrollback makes no sense, and 0 would screw
364 the operation totally */ 364 the operation totally */
365 softback_top = 0; 365 softback_top = 0;
366 } 366 }
367 367
368 static void fb_flashcursor(struct work_struct *work) 368 static void fb_flashcursor(struct work_struct *work)
369 { 369 {
370 struct fb_info *info = container_of(work, struct fb_info, queue); 370 struct fb_info *info = container_of(work, struct fb_info, queue);
371 struct fbcon_ops *ops = info->fbcon_par; 371 struct fbcon_ops *ops = info->fbcon_par;
372 struct vc_data *vc = NULL; 372 struct vc_data *vc = NULL;
373 int c; 373 int c;
374 int mode; 374 int mode;
375 int ret; 375 int ret;
376 376
377 /* FIXME: we should sort out the unbind locking instead */ 377 /* FIXME: we should sort out the unbind locking instead */
378 /* instead we just fail to flash the cursor if we can't get 378 /* instead we just fail to flash the cursor if we can't get
379 * the lock instead of blocking fbcon deinit */ 379 * the lock instead of blocking fbcon deinit */
380 ret = console_trylock(); 380 ret = console_trylock();
381 if (ret == 0) 381 if (ret == 0)
382 return; 382 return;
383 383
384 if (ops && ops->currcon != -1) 384 if (ops && ops->currcon != -1)
385 vc = vc_cons[ops->currcon].d; 385 vc = vc_cons[ops->currcon].d;
386 386
387 if (!vc || !CON_IS_VISIBLE(vc) || 387 if (!vc || !CON_IS_VISIBLE(vc) ||
388 registered_fb[con2fb_map[vc->vc_num]] != info || 388 registered_fb[con2fb_map[vc->vc_num]] != info ||
389 vc->vc_deccm != 1) { 389 vc->vc_deccm != 1) {
390 console_unlock(); 390 console_unlock();
391 return; 391 return;
392 } 392 }
393 393
394 c = scr_readw((u16 *) vc->vc_pos); 394 c = scr_readw((u16 *) vc->vc_pos);
395 mode = (!ops->cursor_flash || ops->cursor_state.enable) ? 395 mode = (!ops->cursor_flash || ops->cursor_state.enable) ?
396 CM_ERASE : CM_DRAW; 396 CM_ERASE : CM_DRAW;
397 ops->cursor(vc, info, mode, softback_lines, get_color(vc, info, c, 1), 397 ops->cursor(vc, info, mode, softback_lines, get_color(vc, info, c, 1),
398 get_color(vc, info, c, 0)); 398 get_color(vc, info, c, 0));
399 console_unlock(); 399 console_unlock();
400 } 400 }
401 401
402 static void cursor_timer_handler(unsigned long dev_addr) 402 static void cursor_timer_handler(unsigned long dev_addr)
403 { 403 {
404 struct fb_info *info = (struct fb_info *) dev_addr; 404 struct fb_info *info = (struct fb_info *) dev_addr;
405 struct fbcon_ops *ops = info->fbcon_par; 405 struct fbcon_ops *ops = info->fbcon_par;
406 406
407 schedule_work(&info->queue); 407 schedule_work(&info->queue);
408 mod_timer(&ops->cursor_timer, jiffies + HZ/5); 408 mod_timer(&ops->cursor_timer, jiffies + HZ/5);
409 } 409 }
410 410
411 static void fbcon_add_cursor_timer(struct fb_info *info) 411 static void fbcon_add_cursor_timer(struct fb_info *info)
412 { 412 {
413 struct fbcon_ops *ops = info->fbcon_par; 413 struct fbcon_ops *ops = info->fbcon_par;
414 414
415 if ((!info->queue.func || info->queue.func == fb_flashcursor) && 415 if ((!info->queue.func || info->queue.func == fb_flashcursor) &&
416 !(ops->flags & FBCON_FLAGS_CURSOR_TIMER) && 416 !(ops->flags & FBCON_FLAGS_CURSOR_TIMER) &&
417 !fbcon_cursor_noblink) { 417 !fbcon_cursor_noblink) {
418 if (!info->queue.func) 418 if (!info->queue.func)
419 INIT_WORK(&info->queue, fb_flashcursor); 419 INIT_WORK(&info->queue, fb_flashcursor);
420 420
421 init_timer(&ops->cursor_timer); 421 init_timer(&ops->cursor_timer);
422 ops->cursor_timer.function = cursor_timer_handler; 422 ops->cursor_timer.function = cursor_timer_handler;
423 ops->cursor_timer.expires = jiffies + HZ / 5; 423 ops->cursor_timer.expires = jiffies + HZ / 5;
424 ops->cursor_timer.data = (unsigned long ) info; 424 ops->cursor_timer.data = (unsigned long ) info;
425 add_timer(&ops->cursor_timer); 425 add_timer(&ops->cursor_timer);
426 ops->flags |= FBCON_FLAGS_CURSOR_TIMER; 426 ops->flags |= FBCON_FLAGS_CURSOR_TIMER;
427 } 427 }
428 } 428 }
429 429
430 static void fbcon_del_cursor_timer(struct fb_info *info) 430 static void fbcon_del_cursor_timer(struct fb_info *info)
431 { 431 {
432 struct fbcon_ops *ops = info->fbcon_par; 432 struct fbcon_ops *ops = info->fbcon_par;
433 433
434 if (info->queue.func == fb_flashcursor && 434 if (info->queue.func == fb_flashcursor &&
435 ops->flags & FBCON_FLAGS_CURSOR_TIMER) { 435 ops->flags & FBCON_FLAGS_CURSOR_TIMER) {
436 del_timer_sync(&ops->cursor_timer); 436 del_timer_sync(&ops->cursor_timer);
437 ops->flags &= ~FBCON_FLAGS_CURSOR_TIMER; 437 ops->flags &= ~FBCON_FLAGS_CURSOR_TIMER;
438 } 438 }
439 } 439 }
440 440
441 #ifndef MODULE 441 #ifndef MODULE
442 static int __init fb_console_setup(char *this_opt) 442 static int __init fb_console_setup(char *this_opt)
443 { 443 {
444 char *options; 444 char *options;
445 int i, j; 445 int i, j;
446 446
447 if (!this_opt || !*this_opt) 447 if (!this_opt || !*this_opt)
448 return 1; 448 return 1;
449 449
450 while ((options = strsep(&this_opt, ",")) != NULL) { 450 while ((options = strsep(&this_opt, ",")) != NULL) {
451 if (!strncmp(options, "font:", 5)) 451 if (!strncmp(options, "font:", 5))
452 strcpy(fontname, options + 5); 452 strlcpy(fontname, options + 5, sizeof(fontname));
453 453
454 if (!strncmp(options, "scrollback:", 11)) { 454 if (!strncmp(options, "scrollback:", 11)) {
455 options += 11; 455 options += 11;
456 if (*options) { 456 if (*options) {
457 fbcon_softback_size = simple_strtoul(options, &options, 0); 457 fbcon_softback_size = simple_strtoul(options, &options, 0);
458 if (*options == 'k' || *options == 'K') { 458 if (*options == 'k' || *options == 'K') {
459 fbcon_softback_size *= 1024; 459 fbcon_softback_size *= 1024;
460 options++; 460 options++;
461 } 461 }
462 if (*options != ',') 462 if (*options != ',')
463 return 1; 463 return 1;
464 options++; 464 options++;
465 } else 465 } else
466 return 1; 466 return 1;
467 } 467 }
468 468
469 if (!strncmp(options, "map:", 4)) { 469 if (!strncmp(options, "map:", 4)) {
470 options += 4; 470 options += 4;
471 if (*options) { 471 if (*options) {
472 for (i = 0, j = 0; i < MAX_NR_CONSOLES; i++) { 472 for (i = 0, j = 0; i < MAX_NR_CONSOLES; i++) {
473 if (!options[j]) 473 if (!options[j])
474 j = 0; 474 j = 0;
475 con2fb_map_boot[i] = 475 con2fb_map_boot[i] =
476 (options[j++]-'0') % FB_MAX; 476 (options[j++]-'0') % FB_MAX;
477 } 477 }
478 478
479 fbcon_map_override(); 479 fbcon_map_override();
480 } 480 }
481 481
482 return 1; 482 return 1;
483 } 483 }
484 484
485 if (!strncmp(options, "vc:", 3)) { 485 if (!strncmp(options, "vc:", 3)) {
486 options += 3; 486 options += 3;
487 if (*options) 487 if (*options)
488 first_fb_vc = simple_strtoul(options, &options, 10) - 1; 488 first_fb_vc = simple_strtoul(options, &options, 10) - 1;
489 if (first_fb_vc < 0) 489 if (first_fb_vc < 0)
490 first_fb_vc = 0; 490 first_fb_vc = 0;
491 if (*options++ == '-') 491 if (*options++ == '-')
492 last_fb_vc = simple_strtoul(options, &options, 10) - 1; 492 last_fb_vc = simple_strtoul(options, &options, 10) - 1;
493 fbcon_is_default = 0; 493 fbcon_is_default = 0;
494 } 494 }
495 495
496 if (!strncmp(options, "rotate:", 7)) { 496 if (!strncmp(options, "rotate:", 7)) {
497 options += 7; 497 options += 7;
498 if (*options) 498 if (*options)
499 initial_rotation = simple_strtoul(options, &options, 0); 499 initial_rotation = simple_strtoul(options, &options, 0);
500 if (initial_rotation > 3) 500 if (initial_rotation > 3)
501 initial_rotation = 0; 501 initial_rotation = 0;
502 } 502 }
503 } 503 }
504 return 1; 504 return 1;
505 } 505 }
506 506
507 __setup("fbcon=", fb_console_setup); 507 __setup("fbcon=", fb_console_setup);
508 #endif 508 #endif
509 509
510 static int search_fb_in_map(int idx) 510 static int search_fb_in_map(int idx)
511 { 511 {
512 int i, retval = 0; 512 int i, retval = 0;
513 513
514 for (i = first_fb_vc; i <= last_fb_vc; i++) { 514 for (i = first_fb_vc; i <= last_fb_vc; i++) {
515 if (con2fb_map[i] == idx) 515 if (con2fb_map[i] == idx)
516 retval = 1; 516 retval = 1;
517 } 517 }
518 return retval; 518 return retval;
519 } 519 }
520 520
521 static int search_for_mapped_con(void) 521 static int search_for_mapped_con(void)
522 { 522 {
523 int i, retval = 0; 523 int i, retval = 0;
524 524
525 for (i = first_fb_vc; i <= last_fb_vc; i++) { 525 for (i = first_fb_vc; i <= last_fb_vc; i++) {
526 if (con2fb_map[i] != -1) 526 if (con2fb_map[i] != -1)
527 retval = 1; 527 retval = 1;
528 } 528 }
529 return retval; 529 return retval;
530 } 530 }
531 531
532 static int fbcon_takeover(int show_logo) 532 static int fbcon_takeover(int show_logo)
533 { 533 {
534 int err, i; 534 int err, i;
535 535
536 if (!num_registered_fb) 536 if (!num_registered_fb)
537 return -ENODEV; 537 return -ENODEV;
538 538
539 if (!show_logo) 539 if (!show_logo)
540 logo_shown = FBCON_LOGO_DONTSHOW; 540 logo_shown = FBCON_LOGO_DONTSHOW;
541 541
542 for (i = first_fb_vc; i <= last_fb_vc; i++) 542 for (i = first_fb_vc; i <= last_fb_vc; i++)
543 con2fb_map[i] = info_idx; 543 con2fb_map[i] = info_idx;
544 544
545 err = take_over_console(&fb_con, first_fb_vc, last_fb_vc, 545 err = take_over_console(&fb_con, first_fb_vc, last_fb_vc,
546 fbcon_is_default); 546 fbcon_is_default);
547 547
548 if (err) { 548 if (err) {
549 for (i = first_fb_vc; i <= last_fb_vc; i++) { 549 for (i = first_fb_vc; i <= last_fb_vc; i++) {
550 con2fb_map[i] = -1; 550 con2fb_map[i] = -1;
551 } 551 }
552 info_idx = -1; 552 info_idx = -1;
553 } else { 553 } else {
554 fbcon_has_console_bind = 1; 554 fbcon_has_console_bind = 1;
555 } 555 }
556 556
557 return err; 557 return err;
558 } 558 }
559 559
560 #ifdef MODULE 560 #ifdef MODULE
561 static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, 561 static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
562 int cols, int rows, int new_cols, int new_rows) 562 int cols, int rows, int new_cols, int new_rows)
563 { 563 {
564 logo_shown = FBCON_LOGO_DONTSHOW; 564 logo_shown = FBCON_LOGO_DONTSHOW;
565 } 565 }
566 #else 566 #else
567 static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, 567 static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
568 int cols, int rows, int new_cols, int new_rows) 568 int cols, int rows, int new_cols, int new_rows)
569 { 569 {
570 /* Need to make room for the logo */ 570 /* Need to make room for the logo */
571 struct fbcon_ops *ops = info->fbcon_par; 571 struct fbcon_ops *ops = info->fbcon_par;
572 int cnt, erase = vc->vc_video_erase_char, step; 572 int cnt, erase = vc->vc_video_erase_char, step;
573 unsigned short *save = NULL, *r, *q; 573 unsigned short *save = NULL, *r, *q;
574 int logo_height; 574 int logo_height;
575 575
576 if (info->flags & FBINFO_MODULE) { 576 if (info->flags & FBINFO_MODULE) {
577 logo_shown = FBCON_LOGO_DONTSHOW; 577 logo_shown = FBCON_LOGO_DONTSHOW;
578 return; 578 return;
579 } 579 }
580 580
581 /* 581 /*
582 * remove underline attribute from erase character 582 * remove underline attribute from erase character
583 * if black and white framebuffer. 583 * if black and white framebuffer.
584 */ 584 */
585 if (fb_get_color_depth(&info->var, &info->fix) == 1) 585 if (fb_get_color_depth(&info->var, &info->fix) == 1)
586 erase &= ~0x400; 586 erase &= ~0x400;
587 logo_height = fb_prepare_logo(info, ops->rotate); 587 logo_height = fb_prepare_logo(info, ops->rotate);
588 logo_lines = DIV_ROUND_UP(logo_height, vc->vc_font.height); 588 logo_lines = DIV_ROUND_UP(logo_height, vc->vc_font.height);
589 q = (unsigned short *) (vc->vc_origin + 589 q = (unsigned short *) (vc->vc_origin +
590 vc->vc_size_row * rows); 590 vc->vc_size_row * rows);
591 step = logo_lines * cols; 591 step = logo_lines * cols;
592 for (r = q - logo_lines * cols; r < q; r++) 592 for (r = q - logo_lines * cols; r < q; r++)
593 if (scr_readw(r) != vc->vc_video_erase_char) 593 if (scr_readw(r) != vc->vc_video_erase_char)
594 break; 594 break;
595 if (r != q && new_rows >= rows + logo_lines) { 595 if (r != q && new_rows >= rows + logo_lines) {
596 save = kmalloc(logo_lines * new_cols * 2, GFP_KERNEL); 596 save = kmalloc(logo_lines * new_cols * 2, GFP_KERNEL);
597 if (save) { 597 if (save) {
598 int i = cols < new_cols ? cols : new_cols; 598 int i = cols < new_cols ? cols : new_cols;
599 scr_memsetw(save, erase, logo_lines * new_cols * 2); 599 scr_memsetw(save, erase, logo_lines * new_cols * 2);
600 r = q - step; 600 r = q - step;
601 for (cnt = 0; cnt < logo_lines; cnt++, r += i) 601 for (cnt = 0; cnt < logo_lines; cnt++, r += i)
602 scr_memcpyw(save + cnt * new_cols, r, 2 * i); 602 scr_memcpyw(save + cnt * new_cols, r, 2 * i);
603 r = q; 603 r = q;
604 } 604 }
605 } 605 }
606 if (r == q) { 606 if (r == q) {
607 /* We can scroll screen down */ 607 /* We can scroll screen down */
608 r = q - step - cols; 608 r = q - step - cols;
609 for (cnt = rows - logo_lines; cnt > 0; cnt--) { 609 for (cnt = rows - logo_lines; cnt > 0; cnt--) {
610 scr_memcpyw(r + step, r, vc->vc_size_row); 610 scr_memcpyw(r + step, r, vc->vc_size_row);
611 r -= cols; 611 r -= cols;
612 } 612 }
613 if (!save) { 613 if (!save) {
614 int lines; 614 int lines;
615 if (vc->vc_y + logo_lines >= rows) 615 if (vc->vc_y + logo_lines >= rows)
616 lines = rows - vc->vc_y - 1; 616 lines = rows - vc->vc_y - 1;
617 else 617 else
618 lines = logo_lines; 618 lines = logo_lines;
619 vc->vc_y += lines; 619 vc->vc_y += lines;
620 vc->vc_pos += lines * vc->vc_size_row; 620 vc->vc_pos += lines * vc->vc_size_row;
621 } 621 }
622 } 622 }
623 scr_memsetw((unsigned short *) vc->vc_origin, 623 scr_memsetw((unsigned short *) vc->vc_origin,
624 erase, 624 erase,
625 vc->vc_size_row * logo_lines); 625 vc->vc_size_row * logo_lines);
626 626
627 if (CON_IS_VISIBLE(vc) && vc->vc_mode == KD_TEXT) { 627 if (CON_IS_VISIBLE(vc) && vc->vc_mode == KD_TEXT) {
628 fbcon_clear_margins(vc, 0); 628 fbcon_clear_margins(vc, 0);
629 update_screen(vc); 629 update_screen(vc);
630 } 630 }
631 631
632 if (save) { 632 if (save) {
633 q = (unsigned short *) (vc->vc_origin + 633 q = (unsigned short *) (vc->vc_origin +
634 vc->vc_size_row * 634 vc->vc_size_row *
635 rows); 635 rows);
636 scr_memcpyw(q, save, logo_lines * new_cols * 2); 636 scr_memcpyw(q, save, logo_lines * new_cols * 2);
637 vc->vc_y += logo_lines; 637 vc->vc_y += logo_lines;
638 vc->vc_pos += logo_lines * vc->vc_size_row; 638 vc->vc_pos += logo_lines * vc->vc_size_row;
639 kfree(save); 639 kfree(save);
640 } 640 }
641 641
642 if (logo_lines > vc->vc_bottom) { 642 if (logo_lines > vc->vc_bottom) {
643 logo_shown = FBCON_LOGO_CANSHOW; 643 logo_shown = FBCON_LOGO_CANSHOW;
644 printk(KERN_INFO 644 printk(KERN_INFO
645 "fbcon_init: disable boot-logo (boot-logo bigger than screen).\n"); 645 "fbcon_init: disable boot-logo (boot-logo bigger than screen).\n");
646 } else if (logo_shown != FBCON_LOGO_DONTSHOW) { 646 } else if (logo_shown != FBCON_LOGO_DONTSHOW) {
647 logo_shown = FBCON_LOGO_DRAW; 647 logo_shown = FBCON_LOGO_DRAW;
648 vc->vc_top = logo_lines; 648 vc->vc_top = logo_lines;
649 } 649 }
650 } 650 }
651 #endif /* MODULE */ 651 #endif /* MODULE */
652 652
653 #ifdef CONFIG_FB_TILEBLITTING 653 #ifdef CONFIG_FB_TILEBLITTING
654 static void set_blitting_type(struct vc_data *vc, struct fb_info *info) 654 static void set_blitting_type(struct vc_data *vc, struct fb_info *info)
655 { 655 {
656 struct fbcon_ops *ops = info->fbcon_par; 656 struct fbcon_ops *ops = info->fbcon_par;
657 657
658 ops->p = &fb_display[vc->vc_num]; 658 ops->p = &fb_display[vc->vc_num];
659 659
660 if ((info->flags & FBINFO_MISC_TILEBLITTING)) 660 if ((info->flags & FBINFO_MISC_TILEBLITTING))
661 fbcon_set_tileops(vc, info); 661 fbcon_set_tileops(vc, info);
662 else { 662 else {
663 fbcon_set_rotation(info); 663 fbcon_set_rotation(info);
664 fbcon_set_bitops(ops); 664 fbcon_set_bitops(ops);
665 } 665 }
666 } 666 }
667 667
668 static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount) 668 static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount)
669 { 669 {
670 int err = 0; 670 int err = 0;
671 671
672 if (info->flags & FBINFO_MISC_TILEBLITTING && 672 if (info->flags & FBINFO_MISC_TILEBLITTING &&
673 info->tileops->fb_get_tilemax(info) < charcount) 673 info->tileops->fb_get_tilemax(info) < charcount)
674 err = 1; 674 err = 1;
675 675
676 return err; 676 return err;
677 } 677 }
678 #else 678 #else
679 static void set_blitting_type(struct vc_data *vc, struct fb_info *info) 679 static void set_blitting_type(struct vc_data *vc, struct fb_info *info)
680 { 680 {
681 struct fbcon_ops *ops = info->fbcon_par; 681 struct fbcon_ops *ops = info->fbcon_par;
682 682
683 info->flags &= ~FBINFO_MISC_TILEBLITTING; 683 info->flags &= ~FBINFO_MISC_TILEBLITTING;
684 ops->p = &fb_display[vc->vc_num]; 684 ops->p = &fb_display[vc->vc_num];
685 fbcon_set_rotation(info); 685 fbcon_set_rotation(info);
686 fbcon_set_bitops(ops); 686 fbcon_set_bitops(ops);
687 } 687 }
688 688
689 static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount) 689 static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount)
690 { 690 {
691 return 0; 691 return 0;
692 } 692 }
693 693
694 #endif /* CONFIG_MISC_TILEBLITTING */ 694 #endif /* CONFIG_MISC_TILEBLITTING */
695 695
696 696
697 static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info, 697 static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info,
698 int unit, int oldidx) 698 int unit, int oldidx)
699 { 699 {
700 struct fbcon_ops *ops = NULL; 700 struct fbcon_ops *ops = NULL;
701 int err = 0; 701 int err = 0;
702 702
703 if (!try_module_get(info->fbops->owner)) 703 if (!try_module_get(info->fbops->owner))
704 err = -ENODEV; 704 err = -ENODEV;
705 705
706 if (!err && info->fbops->fb_open && 706 if (!err && info->fbops->fb_open &&
707 info->fbops->fb_open(info, 0)) 707 info->fbops->fb_open(info, 0))
708 err = -ENODEV; 708 err = -ENODEV;
709 709
710 if (!err) { 710 if (!err) {
711 ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL); 711 ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
712 if (!ops) 712 if (!ops)
713 err = -ENOMEM; 713 err = -ENOMEM;
714 } 714 }
715 715
716 if (!err) { 716 if (!err) {
717 info->fbcon_par = ops; 717 info->fbcon_par = ops;
718 718
719 if (vc) 719 if (vc)
720 set_blitting_type(vc, info); 720 set_blitting_type(vc, info);
721 } 721 }
722 722
723 if (err) { 723 if (err) {
724 con2fb_map[unit] = oldidx; 724 con2fb_map[unit] = oldidx;
725 module_put(info->fbops->owner); 725 module_put(info->fbops->owner);
726 } 726 }
727 727
728 return err; 728 return err;
729 } 729 }
730 730
731 static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo, 731 static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo,
732 struct fb_info *newinfo, int unit, 732 struct fb_info *newinfo, int unit,
733 int oldidx, int found) 733 int oldidx, int found)
734 { 734 {
735 struct fbcon_ops *ops = oldinfo->fbcon_par; 735 struct fbcon_ops *ops = oldinfo->fbcon_par;
736 int err = 0, ret; 736 int err = 0, ret;
737 737
738 if (oldinfo->fbops->fb_release && 738 if (oldinfo->fbops->fb_release &&
739 oldinfo->fbops->fb_release(oldinfo, 0)) { 739 oldinfo->fbops->fb_release(oldinfo, 0)) {
740 con2fb_map[unit] = oldidx; 740 con2fb_map[unit] = oldidx;
741 if (!found && newinfo->fbops->fb_release) 741 if (!found && newinfo->fbops->fb_release)
742 newinfo->fbops->fb_release(newinfo, 0); 742 newinfo->fbops->fb_release(newinfo, 0);
743 if (!found) 743 if (!found)
744 module_put(newinfo->fbops->owner); 744 module_put(newinfo->fbops->owner);
745 err = -ENODEV; 745 err = -ENODEV;
746 } 746 }
747 747
748 if (!err) { 748 if (!err) {
749 fbcon_del_cursor_timer(oldinfo); 749 fbcon_del_cursor_timer(oldinfo);
750 kfree(ops->cursor_state.mask); 750 kfree(ops->cursor_state.mask);
751 kfree(ops->cursor_data); 751 kfree(ops->cursor_data);
752 kfree(ops->fontbuffer); 752 kfree(ops->fontbuffer);
753 kfree(oldinfo->fbcon_par); 753 kfree(oldinfo->fbcon_par);
754 oldinfo->fbcon_par = NULL; 754 oldinfo->fbcon_par = NULL;
755 module_put(oldinfo->fbops->owner); 755 module_put(oldinfo->fbops->owner);
756 /* 756 /*
757 If oldinfo and newinfo are driving the same hardware, 757 If oldinfo and newinfo are driving the same hardware,
758 the fb_release() method of oldinfo may attempt to 758 the fb_release() method of oldinfo may attempt to
759 restore the hardware state. This will leave the 759 restore the hardware state. This will leave the
760 newinfo in an undefined state. Thus, a call to 760 newinfo in an undefined state. Thus, a call to
761 fb_set_par() may be needed for the newinfo. 761 fb_set_par() may be needed for the newinfo.
762 */ 762 */
763 if (newinfo->fbops->fb_set_par) { 763 if (newinfo->fbops->fb_set_par) {
764 ret = newinfo->fbops->fb_set_par(newinfo); 764 ret = newinfo->fbops->fb_set_par(newinfo);
765 765
766 if (ret) 766 if (ret)
767 printk(KERN_ERR "con2fb_release_oldinfo: " 767 printk(KERN_ERR "con2fb_release_oldinfo: "
768 "detected unhandled fb_set_par error, " 768 "detected unhandled fb_set_par error, "
769 "error code %d\n", ret); 769 "error code %d\n", ret);
770 } 770 }
771 } 771 }
772 772
773 return err; 773 return err;
774 } 774 }
775 775
776 static void con2fb_init_display(struct vc_data *vc, struct fb_info *info, 776 static void con2fb_init_display(struct vc_data *vc, struct fb_info *info,
777 int unit, int show_logo) 777 int unit, int show_logo)
778 { 778 {
779 struct fbcon_ops *ops = info->fbcon_par; 779 struct fbcon_ops *ops = info->fbcon_par;
780 int ret; 780 int ret;
781 781
782 ops->currcon = fg_console; 782 ops->currcon = fg_console;
783 783
784 if (info->fbops->fb_set_par && !(ops->flags & FBCON_FLAGS_INIT)) { 784 if (info->fbops->fb_set_par && !(ops->flags & FBCON_FLAGS_INIT)) {
785 ret = info->fbops->fb_set_par(info); 785 ret = info->fbops->fb_set_par(info);
786 786
787 if (ret) 787 if (ret)
788 printk(KERN_ERR "con2fb_init_display: detected " 788 printk(KERN_ERR "con2fb_init_display: detected "
789 "unhandled fb_set_par error, " 789 "unhandled fb_set_par error, "
790 "error code %d\n", ret); 790 "error code %d\n", ret);
791 } 791 }
792 792
793 ops->flags |= FBCON_FLAGS_INIT; 793 ops->flags |= FBCON_FLAGS_INIT;
794 ops->graphics = 0; 794 ops->graphics = 0;
795 fbcon_set_disp(info, &info->var, unit); 795 fbcon_set_disp(info, &info->var, unit);
796 796
797 if (show_logo) { 797 if (show_logo) {
798 struct vc_data *fg_vc = vc_cons[fg_console].d; 798 struct vc_data *fg_vc = vc_cons[fg_console].d;
799 struct fb_info *fg_info = 799 struct fb_info *fg_info =
800 registered_fb[con2fb_map[fg_console]]; 800 registered_fb[con2fb_map[fg_console]];
801 801
802 fbcon_prepare_logo(fg_vc, fg_info, fg_vc->vc_cols, 802 fbcon_prepare_logo(fg_vc, fg_info, fg_vc->vc_cols,
803 fg_vc->vc_rows, fg_vc->vc_cols, 803 fg_vc->vc_rows, fg_vc->vc_cols,
804 fg_vc->vc_rows); 804 fg_vc->vc_rows);
805 } 805 }
806 806
807 update_screen(vc_cons[fg_console].d); 807 update_screen(vc_cons[fg_console].d);
808 } 808 }
809 809
810 /** 810 /**
811 * set_con2fb_map - map console to frame buffer device 811 * set_con2fb_map - map console to frame buffer device
812 * @unit: virtual console number to map 812 * @unit: virtual console number to map
813 * @newidx: frame buffer index to map virtual console to 813 * @newidx: frame buffer index to map virtual console to
814 * @user: user request 814 * @user: user request
815 * 815 *
816 * Maps a virtual console @unit to a frame buffer device 816 * Maps a virtual console @unit to a frame buffer device
817 * @newidx. 817 * @newidx.
818 */ 818 */
819 static int set_con2fb_map(int unit, int newidx, int user) 819 static int set_con2fb_map(int unit, int newidx, int user)
820 { 820 {
821 struct vc_data *vc = vc_cons[unit].d; 821 struct vc_data *vc = vc_cons[unit].d;
822 int oldidx = con2fb_map[unit]; 822 int oldidx = con2fb_map[unit];
823 struct fb_info *info = registered_fb[newidx]; 823 struct fb_info *info = registered_fb[newidx];
824 struct fb_info *oldinfo = NULL; 824 struct fb_info *oldinfo = NULL;
825 int found, err = 0; 825 int found, err = 0;
826 826
827 if (oldidx == newidx) 827 if (oldidx == newidx)
828 return 0; 828 return 0;
829 829
830 if (!info) 830 if (!info)
831 return -EINVAL; 831 return -EINVAL;
832 832
833 if (!search_for_mapped_con() || !con_is_bound(&fb_con)) { 833 if (!search_for_mapped_con() || !con_is_bound(&fb_con)) {
834 info_idx = newidx; 834 info_idx = newidx;
835 return fbcon_takeover(0); 835 return fbcon_takeover(0);
836 } 836 }
837 837
838 if (oldidx != -1) 838 if (oldidx != -1)
839 oldinfo = registered_fb[oldidx]; 839 oldinfo = registered_fb[oldidx];
840 840
841 found = search_fb_in_map(newidx); 841 found = search_fb_in_map(newidx);
842 842
843 console_lock(); 843 console_lock();
844 con2fb_map[unit] = newidx; 844 con2fb_map[unit] = newidx;
845 if (!err && !found) 845 if (!err && !found)
846 err = con2fb_acquire_newinfo(vc, info, unit, oldidx); 846 err = con2fb_acquire_newinfo(vc, info, unit, oldidx);
847 847
848 848
849 /* 849 /*
850 * If old fb is not mapped to any of the consoles, 850 * If old fb is not mapped to any of the consoles,
851 * fbcon should release it. 851 * fbcon should release it.
852 */ 852 */
853 if (!err && oldinfo && !search_fb_in_map(oldidx)) 853 if (!err && oldinfo && !search_fb_in_map(oldidx))
854 err = con2fb_release_oldinfo(vc, oldinfo, info, unit, oldidx, 854 err = con2fb_release_oldinfo(vc, oldinfo, info, unit, oldidx,
855 found); 855 found);
856 856
857 if (!err) { 857 if (!err) {
858 int show_logo = (fg_console == 0 && !user && 858 int show_logo = (fg_console == 0 && !user &&
859 logo_shown != FBCON_LOGO_DONTSHOW); 859 logo_shown != FBCON_LOGO_DONTSHOW);
860 860
861 if (!found) 861 if (!found)
862 fbcon_add_cursor_timer(info); 862 fbcon_add_cursor_timer(info);
863 con2fb_map_boot[unit] = newidx; 863 con2fb_map_boot[unit] = newidx;
864 con2fb_init_display(vc, info, unit, show_logo); 864 con2fb_init_display(vc, info, unit, show_logo);
865 } 865 }
866 866
867 if (!search_fb_in_map(info_idx)) 867 if (!search_fb_in_map(info_idx))
868 info_idx = newidx; 868 info_idx = newidx;
869 869
870 console_unlock(); 870 console_unlock();
871 return err; 871 return err;
872 } 872 }
873 873
874 /* 874 /*
875 * Low Level Operations 875 * Low Level Operations
876 */ 876 */
877 /* NOTE: fbcon cannot be __init: it may be called from take_over_console later */ 877 /* NOTE: fbcon cannot be __init: it may be called from take_over_console later */
878 static int var_to_display(struct display *disp, 878 static int var_to_display(struct display *disp,
879 struct fb_var_screeninfo *var, 879 struct fb_var_screeninfo *var,
880 struct fb_info *info) 880 struct fb_info *info)
881 { 881 {
882 disp->xres_virtual = var->xres_virtual; 882 disp->xres_virtual = var->xres_virtual;
883 disp->yres_virtual = var->yres_virtual; 883 disp->yres_virtual = var->yres_virtual;
884 disp->bits_per_pixel = var->bits_per_pixel; 884 disp->bits_per_pixel = var->bits_per_pixel;
885 disp->grayscale = var->grayscale; 885 disp->grayscale = var->grayscale;
886 disp->nonstd = var->nonstd; 886 disp->nonstd = var->nonstd;
887 disp->accel_flags = var->accel_flags; 887 disp->accel_flags = var->accel_flags;
888 disp->height = var->height; 888 disp->height = var->height;
889 disp->width = var->width; 889 disp->width = var->width;
890 disp->red = var->red; 890 disp->red = var->red;
891 disp->green = var->green; 891 disp->green = var->green;
892 disp->blue = var->blue; 892 disp->blue = var->blue;
893 disp->transp = var->transp; 893 disp->transp = var->transp;
894 disp->rotate = var->rotate; 894 disp->rotate = var->rotate;
895 disp->mode = fb_match_mode(var, &info->modelist); 895 disp->mode = fb_match_mode(var, &info->modelist);
896 if (disp->mode == NULL) 896 if (disp->mode == NULL)
897 /* This should not happen */ 897 /* This should not happen */
898 return -EINVAL; 898 return -EINVAL;
899 return 0; 899 return 0;
900 } 900 }
901 901
902 static void display_to_var(struct fb_var_screeninfo *var, 902 static void display_to_var(struct fb_var_screeninfo *var,
903 struct display *disp) 903 struct display *disp)
904 { 904 {
905 fb_videomode_to_var(var, disp->mode); 905 fb_videomode_to_var(var, disp->mode);
906 var->xres_virtual = disp->xres_virtual; 906 var->xres_virtual = disp->xres_virtual;
907 var->yres_virtual = disp->yres_virtual; 907 var->yres_virtual = disp->yres_virtual;
908 var->bits_per_pixel = disp->bits_per_pixel; 908 var->bits_per_pixel = disp->bits_per_pixel;
909 var->grayscale = disp->grayscale; 909 var->grayscale = disp->grayscale;
910 var->nonstd = disp->nonstd; 910 var->nonstd = disp->nonstd;
911 var->accel_flags = disp->accel_flags; 911 var->accel_flags = disp->accel_flags;
912 var->height = disp->height; 912 var->height = disp->height;
913 var->width = disp->width; 913 var->width = disp->width;
914 var->red = disp->red; 914 var->red = disp->red;
915 var->green = disp->green; 915 var->green = disp->green;
916 var->blue = disp->blue; 916 var->blue = disp->blue;
917 var->transp = disp->transp; 917 var->transp = disp->transp;
918 var->rotate = disp->rotate; 918 var->rotate = disp->rotate;
919 } 919 }
920 920
921 static const char *fbcon_startup(void) 921 static const char *fbcon_startup(void)
922 { 922 {
923 const char *display_desc = "frame buffer device"; 923 const char *display_desc = "frame buffer device";
924 struct display *p = &fb_display[fg_console]; 924 struct display *p = &fb_display[fg_console];
925 struct vc_data *vc = vc_cons[fg_console].d; 925 struct vc_data *vc = vc_cons[fg_console].d;
926 const struct font_desc *font = NULL; 926 const struct font_desc *font = NULL;
927 struct module *owner; 927 struct module *owner;
928 struct fb_info *info = NULL; 928 struct fb_info *info = NULL;
929 struct fbcon_ops *ops; 929 struct fbcon_ops *ops;
930 int rows, cols; 930 int rows, cols;
931 931
932 /* 932 /*
933 * If num_registered_fb is zero, this is a call for the dummy part. 933 * If num_registered_fb is zero, this is a call for the dummy part.
934 * The frame buffer devices weren't initialized yet. 934 * The frame buffer devices weren't initialized yet.
935 */ 935 */
936 if (!num_registered_fb || info_idx == -1) 936 if (!num_registered_fb || info_idx == -1)
937 return display_desc; 937 return display_desc;
938 /* 938 /*
939 * Instead of blindly using registered_fb[0], we use info_idx, set by 939 * Instead of blindly using registered_fb[0], we use info_idx, set by
940 * fb_console_init(); 940 * fb_console_init();
941 */ 941 */
942 info = registered_fb[info_idx]; 942 info = registered_fb[info_idx];
943 if (!info) 943 if (!info)
944 return NULL; 944 return NULL;
945 945
946 owner = info->fbops->owner; 946 owner = info->fbops->owner;
947 if (!try_module_get(owner)) 947 if (!try_module_get(owner))
948 return NULL; 948 return NULL;
949 if (info->fbops->fb_open && info->fbops->fb_open(info, 0)) { 949 if (info->fbops->fb_open && info->fbops->fb_open(info, 0)) {
950 module_put(owner); 950 module_put(owner);
951 return NULL; 951 return NULL;
952 } 952 }
953 953
954 ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL); 954 ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
955 if (!ops) { 955 if (!ops) {
956 module_put(owner); 956 module_put(owner);
957 return NULL; 957 return NULL;
958 } 958 }
959 959
960 ops->currcon = -1; 960 ops->currcon = -1;
961 ops->graphics = 1; 961 ops->graphics = 1;
962 ops->cur_rotate = -1; 962 ops->cur_rotate = -1;
963 info->fbcon_par = ops; 963 info->fbcon_par = ops;
964 p->con_rotate = initial_rotation; 964 p->con_rotate = initial_rotation;
965 set_blitting_type(vc, info); 965 set_blitting_type(vc, info);
966 966
967 if (info->fix.type != FB_TYPE_TEXT) { 967 if (info->fix.type != FB_TYPE_TEXT) {
968 if (fbcon_softback_size) { 968 if (fbcon_softback_size) {
969 if (!softback_buf) { 969 if (!softback_buf) {
970 softback_buf = 970 softback_buf =
971 (unsigned long) 971 (unsigned long)
972 kmalloc(fbcon_softback_size, 972 kmalloc(fbcon_softback_size,
973 GFP_KERNEL); 973 GFP_KERNEL);
974 if (!softback_buf) { 974 if (!softback_buf) {
975 fbcon_softback_size = 0; 975 fbcon_softback_size = 0;
976 softback_top = 0; 976 softback_top = 0;
977 } 977 }
978 } 978 }
979 } else { 979 } else {
980 if (softback_buf) { 980 if (softback_buf) {
981 kfree((void *) softback_buf); 981 kfree((void *) softback_buf);
982 softback_buf = 0; 982 softback_buf = 0;
983 softback_top = 0; 983 softback_top = 0;
984 } 984 }
985 } 985 }
986 if (softback_buf) 986 if (softback_buf)
987 softback_in = softback_top = softback_curr = 987 softback_in = softback_top = softback_curr =
988 softback_buf; 988 softback_buf;
989 softback_lines = 0; 989 softback_lines = 0;
990 } 990 }
991 991
992 /* Setup default font */ 992 /* Setup default font */
993 if (!p->fontdata) { 993 if (!p->fontdata) {
994 if (!fontname[0] || !(font = find_font(fontname))) 994 if (!fontname[0] || !(font = find_font(fontname)))
995 font = get_default_font(info->var.xres, 995 font = get_default_font(info->var.xres,
996 info->var.yres, 996 info->var.yres,
997 info->pixmap.blit_x, 997 info->pixmap.blit_x,
998 info->pixmap.blit_y); 998 info->pixmap.blit_y);
999 vc->vc_font.width = font->width; 999 vc->vc_font.width = font->width;
1000 vc->vc_font.height = font->height; 1000 vc->vc_font.height = font->height;
1001 vc->vc_font.data = (void *)(p->fontdata = font->data); 1001 vc->vc_font.data = (void *)(p->fontdata = font->data);
1002 vc->vc_font.charcount = 256; /* FIXME Need to support more fonts */ 1002 vc->vc_font.charcount = 256; /* FIXME Need to support more fonts */
1003 } 1003 }
1004 1004
1005 cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); 1005 cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
1006 rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); 1006 rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
1007 cols /= vc->vc_font.width; 1007 cols /= vc->vc_font.width;
1008 rows /= vc->vc_font.height; 1008 rows /= vc->vc_font.height;
1009 vc_resize(vc, cols, rows); 1009 vc_resize(vc, cols, rows);
1010 1010
1011 DPRINTK("mode: %s\n", info->fix.id); 1011 DPRINTK("mode: %s\n", info->fix.id);
1012 DPRINTK("visual: %d\n", info->fix.visual); 1012 DPRINTK("visual: %d\n", info->fix.visual);
1013 DPRINTK("res: %dx%d-%d\n", info->var.xres, 1013 DPRINTK("res: %dx%d-%d\n", info->var.xres,
1014 info->var.yres, 1014 info->var.yres,
1015 info->var.bits_per_pixel); 1015 info->var.bits_per_pixel);
1016 1016
1017 fbcon_add_cursor_timer(info); 1017 fbcon_add_cursor_timer(info);
1018 fbcon_has_exited = 0; 1018 fbcon_has_exited = 0;
1019 return display_desc; 1019 return display_desc;
1020 } 1020 }
1021 1021
1022 static void fbcon_init(struct vc_data *vc, int init) 1022 static void fbcon_init(struct vc_data *vc, int init)
1023 { 1023 {
1024 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 1024 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
1025 struct fbcon_ops *ops; 1025 struct fbcon_ops *ops;
1026 struct vc_data **default_mode = vc->vc_display_fg; 1026 struct vc_data **default_mode = vc->vc_display_fg;
1027 struct vc_data *svc = *default_mode; 1027 struct vc_data *svc = *default_mode;
1028 struct display *t, *p = &fb_display[vc->vc_num]; 1028 struct display *t, *p = &fb_display[vc->vc_num];
1029 int logo = 1, new_rows, new_cols, rows, cols, charcnt = 256; 1029 int logo = 1, new_rows, new_cols, rows, cols, charcnt = 256;
1030 int cap, ret; 1030 int cap, ret;
1031 1031
1032 if (info_idx == -1 || info == NULL) 1032 if (info_idx == -1 || info == NULL)
1033 return; 1033 return;
1034 1034
1035 cap = info->flags; 1035 cap = info->flags;
1036 1036
1037 if (vc != svc || logo_shown == FBCON_LOGO_DONTSHOW || 1037 if (vc != svc || logo_shown == FBCON_LOGO_DONTSHOW ||
1038 (info->fix.type == FB_TYPE_TEXT)) 1038 (info->fix.type == FB_TYPE_TEXT))
1039 logo = 0; 1039 logo = 0;
1040 1040
1041 if (var_to_display(p, &info->var, info)) 1041 if (var_to_display(p, &info->var, info))
1042 return; 1042 return;
1043 1043
1044 if (!info->fbcon_par) 1044 if (!info->fbcon_par)
1045 con2fb_acquire_newinfo(vc, info, vc->vc_num, -1); 1045 con2fb_acquire_newinfo(vc, info, vc->vc_num, -1);
1046 1046
1047 /* If we are not the first console on this 1047 /* If we are not the first console on this
1048 fb, copy the font from that console */ 1048 fb, copy the font from that console */
1049 t = &fb_display[fg_console]; 1049 t = &fb_display[fg_console];
1050 if (!p->fontdata) { 1050 if (!p->fontdata) {
1051 if (t->fontdata) { 1051 if (t->fontdata) {
1052 struct vc_data *fvc = vc_cons[fg_console].d; 1052 struct vc_data *fvc = vc_cons[fg_console].d;
1053 1053
1054 vc->vc_font.data = (void *)(p->fontdata = 1054 vc->vc_font.data = (void *)(p->fontdata =
1055 fvc->vc_font.data); 1055 fvc->vc_font.data);
1056 vc->vc_font.width = fvc->vc_font.width; 1056 vc->vc_font.width = fvc->vc_font.width;
1057 vc->vc_font.height = fvc->vc_font.height; 1057 vc->vc_font.height = fvc->vc_font.height;
1058 p->userfont = t->userfont; 1058 p->userfont = t->userfont;
1059 1059
1060 if (p->userfont) 1060 if (p->userfont)
1061 REFCOUNT(p->fontdata)++; 1061 REFCOUNT(p->fontdata)++;
1062 } else { 1062 } else {
1063 const struct font_desc *font = NULL; 1063 const struct font_desc *font = NULL;
1064 1064
1065 if (!fontname[0] || !(font = find_font(fontname))) 1065 if (!fontname[0] || !(font = find_font(fontname)))
1066 font = get_default_font(info->var.xres, 1066 font = get_default_font(info->var.xres,
1067 info->var.yres, 1067 info->var.yres,
1068 info->pixmap.blit_x, 1068 info->pixmap.blit_x,
1069 info->pixmap.blit_y); 1069 info->pixmap.blit_y);
1070 vc->vc_font.width = font->width; 1070 vc->vc_font.width = font->width;
1071 vc->vc_font.height = font->height; 1071 vc->vc_font.height = font->height;
1072 vc->vc_font.data = (void *)(p->fontdata = font->data); 1072 vc->vc_font.data = (void *)(p->fontdata = font->data);
1073 vc->vc_font.charcount = 256; /* FIXME Need to 1073 vc->vc_font.charcount = 256; /* FIXME Need to
1074 support more fonts */ 1074 support more fonts */
1075 } 1075 }
1076 } 1076 }
1077 1077
1078 if (p->userfont) 1078 if (p->userfont)
1079 charcnt = FNTCHARCNT(p->fontdata); 1079 charcnt = FNTCHARCNT(p->fontdata);
1080 1080
1081 vc->vc_panic_force_write = !!(info->flags & FBINFO_CAN_FORCE_OUTPUT); 1081 vc->vc_panic_force_write = !!(info->flags & FBINFO_CAN_FORCE_OUTPUT);
1082 vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1); 1082 vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1);
1083 vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; 1083 vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
1084 if (charcnt == 256) { 1084 if (charcnt == 256) {
1085 vc->vc_hi_font_mask = 0; 1085 vc->vc_hi_font_mask = 0;
1086 } else { 1086 } else {
1087 vc->vc_hi_font_mask = 0x100; 1087 vc->vc_hi_font_mask = 0x100;
1088 if (vc->vc_can_do_color) 1088 if (vc->vc_can_do_color)
1089 vc->vc_complement_mask <<= 1; 1089 vc->vc_complement_mask <<= 1;
1090 } 1090 }
1091 1091
1092 if (!*svc->vc_uni_pagedir_loc) 1092 if (!*svc->vc_uni_pagedir_loc)
1093 con_set_default_unimap(svc); 1093 con_set_default_unimap(svc);
1094 if (!*vc->vc_uni_pagedir_loc) 1094 if (!*vc->vc_uni_pagedir_loc)
1095 con_copy_unimap(vc, svc); 1095 con_copy_unimap(vc, svc);
1096 1096
1097 ops = info->fbcon_par; 1097 ops = info->fbcon_par;
1098 p->con_rotate = initial_rotation; 1098 p->con_rotate = initial_rotation;
1099 set_blitting_type(vc, info); 1099 set_blitting_type(vc, info);
1100 1100
1101 cols = vc->vc_cols; 1101 cols = vc->vc_cols;
1102 rows = vc->vc_rows; 1102 rows = vc->vc_rows;
1103 new_cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); 1103 new_cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
1104 new_rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); 1104 new_rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
1105 new_cols /= vc->vc_font.width; 1105 new_cols /= vc->vc_font.width;
1106 new_rows /= vc->vc_font.height; 1106 new_rows /= vc->vc_font.height;
1107 1107
1108 /* 1108 /*
1109 * We must always set the mode. The mode of the previous console 1109 * We must always set the mode. The mode of the previous console
1110 * driver could be in the same resolution but we are using different 1110 * driver could be in the same resolution but we are using different
1111 * hardware so we have to initialize the hardware. 1111 * hardware so we have to initialize the hardware.
1112 * 1112 *
1113 * We need to do it in fbcon_init() to prevent screen corruption. 1113 * We need to do it in fbcon_init() to prevent screen corruption.
1114 */ 1114 */
1115 if (CON_IS_VISIBLE(vc) && vc->vc_mode == KD_TEXT) { 1115 if (CON_IS_VISIBLE(vc) && vc->vc_mode == KD_TEXT) {
1116 if (info->fbops->fb_set_par && 1116 if (info->fbops->fb_set_par &&
1117 !(ops->flags & FBCON_FLAGS_INIT)) { 1117 !(ops->flags & FBCON_FLAGS_INIT)) {
1118 ret = info->fbops->fb_set_par(info); 1118 ret = info->fbops->fb_set_par(info);
1119 1119
1120 if (ret) 1120 if (ret)
1121 printk(KERN_ERR "fbcon_init: detected " 1121 printk(KERN_ERR "fbcon_init: detected "
1122 "unhandled fb_set_par error, " 1122 "unhandled fb_set_par error, "
1123 "error code %d\n", ret); 1123 "error code %d\n", ret);
1124 } 1124 }
1125 1125
1126 ops->flags |= FBCON_FLAGS_INIT; 1126 ops->flags |= FBCON_FLAGS_INIT;
1127 } 1127 }
1128 1128
1129 ops->graphics = 0; 1129 ops->graphics = 0;
1130 1130
1131 if ((cap & FBINFO_HWACCEL_COPYAREA) && 1131 if ((cap & FBINFO_HWACCEL_COPYAREA) &&
1132 !(cap & FBINFO_HWACCEL_DISABLED)) 1132 !(cap & FBINFO_HWACCEL_DISABLED))
1133 p->scrollmode = SCROLL_MOVE; 1133 p->scrollmode = SCROLL_MOVE;
1134 else /* default to something safe */ 1134 else /* default to something safe */
1135 p->scrollmode = SCROLL_REDRAW; 1135 p->scrollmode = SCROLL_REDRAW;
1136 1136
1137 /* 1137 /*
1138 * ++guenther: console.c:vc_allocate() relies on initializing 1138 * ++guenther: console.c:vc_allocate() relies on initializing
1139 * vc_{cols,rows}, but we must not set those if we are only 1139 * vc_{cols,rows}, but we must not set those if we are only
1140 * resizing the console. 1140 * resizing the console.
1141 */ 1141 */
1142 if (init) { 1142 if (init) {
1143 vc->vc_cols = new_cols; 1143 vc->vc_cols = new_cols;
1144 vc->vc_rows = new_rows; 1144 vc->vc_rows = new_rows;
1145 } else 1145 } else
1146 vc_resize(vc, new_cols, new_rows); 1146 vc_resize(vc, new_cols, new_rows);
1147 1147
1148 if (logo) 1148 if (logo)
1149 fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows); 1149 fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows);
1150 1150
1151 if (vc == svc && softback_buf) 1151 if (vc == svc && softback_buf)
1152 fbcon_update_softback(vc); 1152 fbcon_update_softback(vc);
1153 1153
1154 if (ops->rotate_font && ops->rotate_font(info, vc)) { 1154 if (ops->rotate_font && ops->rotate_font(info, vc)) {
1155 ops->rotate = FB_ROTATE_UR; 1155 ops->rotate = FB_ROTATE_UR;
1156 set_blitting_type(vc, info); 1156 set_blitting_type(vc, info);
1157 } 1157 }
1158 1158
1159 ops->p = &fb_display[fg_console]; 1159 ops->p = &fb_display[fg_console];
1160 } 1160 }
1161 1161
1162 static void fbcon_free_font(struct display *p) 1162 static void fbcon_free_font(struct display *p)
1163 { 1163 {
1164 if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0)) 1164 if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0))
1165 kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int)); 1165 kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int));
1166 p->fontdata = NULL; 1166 p->fontdata = NULL;
1167 p->userfont = 0; 1167 p->userfont = 0;
1168 } 1168 }
1169 1169
1170 static void fbcon_deinit(struct vc_data *vc) 1170 static void fbcon_deinit(struct vc_data *vc)
1171 { 1171 {
1172 struct display *p = &fb_display[vc->vc_num]; 1172 struct display *p = &fb_display[vc->vc_num];
1173 struct fb_info *info; 1173 struct fb_info *info;
1174 struct fbcon_ops *ops; 1174 struct fbcon_ops *ops;
1175 int idx; 1175 int idx;
1176 1176
1177 fbcon_free_font(p); 1177 fbcon_free_font(p);
1178 idx = con2fb_map[vc->vc_num]; 1178 idx = con2fb_map[vc->vc_num];
1179 1179
1180 if (idx == -1) 1180 if (idx == -1)
1181 goto finished; 1181 goto finished;
1182 1182
1183 info = registered_fb[idx]; 1183 info = registered_fb[idx];
1184 1184
1185 if (!info) 1185 if (!info)
1186 goto finished; 1186 goto finished;
1187 1187
1188 ops = info->fbcon_par; 1188 ops = info->fbcon_par;
1189 1189
1190 if (!ops) 1190 if (!ops)
1191 goto finished; 1191 goto finished;
1192 1192
1193 if (CON_IS_VISIBLE(vc)) 1193 if (CON_IS_VISIBLE(vc))
1194 fbcon_del_cursor_timer(info); 1194 fbcon_del_cursor_timer(info);
1195 1195
1196 ops->flags &= ~FBCON_FLAGS_INIT; 1196 ops->flags &= ~FBCON_FLAGS_INIT;
1197 finished: 1197 finished:
1198 1198
1199 if (!con_is_bound(&fb_con)) 1199 if (!con_is_bound(&fb_con))
1200 fbcon_exit(); 1200 fbcon_exit();
1201 1201
1202 return; 1202 return;
1203 } 1203 }
1204 1204
1205 /* ====================================================================== */ 1205 /* ====================================================================== */
1206 1206
1207 /* fbcon_XXX routines - interface used by the world 1207 /* fbcon_XXX routines - interface used by the world
1208 * 1208 *
1209 * This system is now divided into two levels because of complications 1209 * This system is now divided into two levels because of complications
1210 * caused by hardware scrolling. Top level functions: 1210 * caused by hardware scrolling. Top level functions:
1211 * 1211 *
1212 * fbcon_bmove(), fbcon_clear(), fbcon_putc(), fbcon_clear_margins() 1212 * fbcon_bmove(), fbcon_clear(), fbcon_putc(), fbcon_clear_margins()
1213 * 1213 *
1214 * handles y values in range [0, scr_height-1] that correspond to real 1214 * handles y values in range [0, scr_height-1] that correspond to real
1215 * screen positions. y_wrap shift means that first line of bitmap may be 1215 * screen positions. y_wrap shift means that first line of bitmap may be
1216 * anywhere on this display. These functions convert lineoffsets to 1216 * anywhere on this display. These functions convert lineoffsets to
1217 * bitmap offsets and deal with the wrap-around case by splitting blits. 1217 * bitmap offsets and deal with the wrap-around case by splitting blits.
1218 * 1218 *
1219 * fbcon_bmove_physical_8() -- These functions fast implementations 1219 * fbcon_bmove_physical_8() -- These functions fast implementations
1220 * fbcon_clear_physical_8() -- of original fbcon_XXX fns. 1220 * fbcon_clear_physical_8() -- of original fbcon_XXX fns.
1221 * fbcon_putc_physical_8() -- (font width != 8) may be added later 1221 * fbcon_putc_physical_8() -- (font width != 8) may be added later
1222 * 1222 *
1223 * WARNING: 1223 * WARNING:
1224 * 1224 *
1225 * At the moment fbcon_putc() cannot blit across vertical wrap boundary 1225 * At the moment fbcon_putc() cannot blit across vertical wrap boundary
1226 * Implies should only really hardware scroll in rows. Only reason for 1226 * Implies should only really hardware scroll in rows. Only reason for
1227 * restriction is simplicity & efficiency at the moment. 1227 * restriction is simplicity & efficiency at the moment.
1228 */ 1228 */
1229 1229
1230 static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height, 1230 static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height,
1231 int width) 1231 int width)
1232 { 1232 {
1233 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 1233 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
1234 struct fbcon_ops *ops = info->fbcon_par; 1234 struct fbcon_ops *ops = info->fbcon_par;
1235 1235
1236 struct display *p = &fb_display[vc->vc_num]; 1236 struct display *p = &fb_display[vc->vc_num];
1237 u_int y_break; 1237 u_int y_break;
1238 1238
1239 if (fbcon_is_inactive(vc, info)) 1239 if (fbcon_is_inactive(vc, info))
1240 return; 1240 return;
1241 1241
1242 if (!height || !width) 1242 if (!height || !width)
1243 return; 1243 return;
1244 1244
1245 if (sy < vc->vc_top && vc->vc_top == logo_lines) 1245 if (sy < vc->vc_top && vc->vc_top == logo_lines)
1246 vc->vc_top = 0; 1246 vc->vc_top = 0;
1247 1247
1248 /* Split blits that cross physical y_wrap boundary */ 1248 /* Split blits that cross physical y_wrap boundary */
1249 1249
1250 y_break = p->vrows - p->yscroll; 1250 y_break = p->vrows - p->yscroll;
1251 if (sy < y_break && sy + height - 1 >= y_break) { 1251 if (sy < y_break && sy + height - 1 >= y_break) {
1252 u_int b = y_break - sy; 1252 u_int b = y_break - sy;
1253 ops->clear(vc, info, real_y(p, sy), sx, b, width); 1253 ops->clear(vc, info, real_y(p, sy), sx, b, width);
1254 ops->clear(vc, info, real_y(p, sy + b), sx, height - b, 1254 ops->clear(vc, info, real_y(p, sy + b), sx, height - b,
1255 width); 1255 width);
1256 } else 1256 } else
1257 ops->clear(vc, info, real_y(p, sy), sx, height, width); 1257 ops->clear(vc, info, real_y(p, sy), sx, height, width);
1258 } 1258 }
1259 1259
1260 static void fbcon_putcs(struct vc_data *vc, const unsigned short *s, 1260 static void fbcon_putcs(struct vc_data *vc, const unsigned short *s,
1261 int count, int ypos, int xpos) 1261 int count, int ypos, int xpos)
1262 { 1262 {
1263 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 1263 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
1264 struct display *p = &fb_display[vc->vc_num]; 1264 struct display *p = &fb_display[vc->vc_num];
1265 struct fbcon_ops *ops = info->fbcon_par; 1265 struct fbcon_ops *ops = info->fbcon_par;
1266 1266
1267 if (!fbcon_is_inactive(vc, info)) 1267 if (!fbcon_is_inactive(vc, info))
1268 ops->putcs(vc, info, s, count, real_y(p, ypos), xpos, 1268 ops->putcs(vc, info, s, count, real_y(p, ypos), xpos,
1269 get_color(vc, info, scr_readw(s), 1), 1269 get_color(vc, info, scr_readw(s), 1),
1270 get_color(vc, info, scr_readw(s), 0)); 1270 get_color(vc, info, scr_readw(s), 0));
1271 } 1271 }
1272 1272
1273 static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos) 1273 static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos)
1274 { 1274 {
1275 unsigned short chr; 1275 unsigned short chr;
1276 1276
1277 scr_writew(c, &chr); 1277 scr_writew(c, &chr);
1278 fbcon_putcs(vc, &chr, 1, ypos, xpos); 1278 fbcon_putcs(vc, &chr, 1, ypos, xpos);
1279 } 1279 }
1280 1280
1281 static void fbcon_clear_margins(struct vc_data *vc, int bottom_only) 1281 static void fbcon_clear_margins(struct vc_data *vc, int bottom_only)
1282 { 1282 {
1283 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 1283 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
1284 struct fbcon_ops *ops = info->fbcon_par; 1284 struct fbcon_ops *ops = info->fbcon_par;
1285 1285
1286 if (!fbcon_is_inactive(vc, info)) 1286 if (!fbcon_is_inactive(vc, info))
1287 ops->clear_margins(vc, info, bottom_only); 1287 ops->clear_margins(vc, info, bottom_only);
1288 } 1288 }
1289 1289
1290 static void fbcon_cursor(struct vc_data *vc, int mode) 1290 static void fbcon_cursor(struct vc_data *vc, int mode)
1291 { 1291 {
1292 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 1292 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
1293 struct fbcon_ops *ops = info->fbcon_par; 1293 struct fbcon_ops *ops = info->fbcon_par;
1294 int y; 1294 int y;
1295 int c = scr_readw((u16 *) vc->vc_pos); 1295 int c = scr_readw((u16 *) vc->vc_pos);
1296 1296
1297 if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1) 1297 if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1)
1298 return; 1298 return;
1299 1299
1300 if (vc->vc_cursor_type & 0x10) 1300 if (vc->vc_cursor_type & 0x10)
1301 fbcon_del_cursor_timer(info); 1301 fbcon_del_cursor_timer(info);
1302 else 1302 else
1303 fbcon_add_cursor_timer(info); 1303 fbcon_add_cursor_timer(info);
1304 1304
1305 ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1; 1305 ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
1306 if (mode & CM_SOFTBACK) { 1306 if (mode & CM_SOFTBACK) {
1307 mode &= ~CM_SOFTBACK; 1307 mode &= ~CM_SOFTBACK;
1308 y = softback_lines; 1308 y = softback_lines;
1309 } else { 1309 } else {
1310 if (softback_lines) 1310 if (softback_lines)
1311 fbcon_set_origin(vc); 1311 fbcon_set_origin(vc);
1312 y = 0; 1312 y = 0;
1313 } 1313 }
1314 1314
1315 ops->cursor(vc, info, mode, y, get_color(vc, info, c, 1), 1315 ops->cursor(vc, info, mode, y, get_color(vc, info, c, 1),
1316 get_color(vc, info, c, 0)); 1316 get_color(vc, info, c, 0));
1317 vbl_cursor_cnt = CURSOR_DRAW_DELAY; 1317 vbl_cursor_cnt = CURSOR_DRAW_DELAY;
1318 } 1318 }
1319 1319
1320 static int scrollback_phys_max = 0; 1320 static int scrollback_phys_max = 0;
1321 static int scrollback_max = 0; 1321 static int scrollback_max = 0;
1322 static int scrollback_current = 0; 1322 static int scrollback_current = 0;
1323 1323
1324 static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, 1324 static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
1325 int unit) 1325 int unit)
1326 { 1326 {
1327 struct display *p, *t; 1327 struct display *p, *t;
1328 struct vc_data **default_mode, *vc; 1328 struct vc_data **default_mode, *vc;
1329 struct vc_data *svc; 1329 struct vc_data *svc;
1330 struct fbcon_ops *ops = info->fbcon_par; 1330 struct fbcon_ops *ops = info->fbcon_par;
1331 int rows, cols, charcnt = 256; 1331 int rows, cols, charcnt = 256;
1332 1332
1333 p = &fb_display[unit]; 1333 p = &fb_display[unit];
1334 1334
1335 if (var_to_display(p, var, info)) 1335 if (var_to_display(p, var, info))
1336 return; 1336 return;
1337 1337
1338 vc = vc_cons[unit].d; 1338 vc = vc_cons[unit].d;
1339 1339
1340 if (!vc) 1340 if (!vc)
1341 return; 1341 return;
1342 1342
1343 default_mode = vc->vc_display_fg; 1343 default_mode = vc->vc_display_fg;
1344 svc = *default_mode; 1344 svc = *default_mode;
1345 t = &fb_display[svc->vc_num]; 1345 t = &fb_display[svc->vc_num];
1346 1346
1347 if (!vc->vc_font.data) { 1347 if (!vc->vc_font.data) {
1348 vc->vc_font.data = (void *)(p->fontdata = t->fontdata); 1348 vc->vc_font.data = (void *)(p->fontdata = t->fontdata);
1349 vc->vc_font.width = (*default_mode)->vc_font.width; 1349 vc->vc_font.width = (*default_mode)->vc_font.width;
1350 vc->vc_font.height = (*default_mode)->vc_font.height; 1350 vc->vc_font.height = (*default_mode)->vc_font.height;
1351 p->userfont = t->userfont; 1351 p->userfont = t->userfont;
1352 if (p->userfont) 1352 if (p->userfont)
1353 REFCOUNT(p->fontdata)++; 1353 REFCOUNT(p->fontdata)++;
1354 } 1354 }
1355 if (p->userfont) 1355 if (p->userfont)
1356 charcnt = FNTCHARCNT(p->fontdata); 1356 charcnt = FNTCHARCNT(p->fontdata);
1357 1357
1358 var->activate = FB_ACTIVATE_NOW; 1358 var->activate = FB_ACTIVATE_NOW;
1359 info->var.activate = var->activate; 1359 info->var.activate = var->activate;
1360 var->yoffset = info->var.yoffset; 1360 var->yoffset = info->var.yoffset;
1361 var->xoffset = info->var.xoffset; 1361 var->xoffset = info->var.xoffset;
1362 fb_set_var(info, var); 1362 fb_set_var(info, var);
1363 ops->var = info->var; 1363 ops->var = info->var;
1364 vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1); 1364 vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1);
1365 vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; 1365 vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
1366 if (charcnt == 256) { 1366 if (charcnt == 256) {
1367 vc->vc_hi_font_mask = 0; 1367 vc->vc_hi_font_mask = 0;
1368 } else { 1368 } else {
1369 vc->vc_hi_font_mask = 0x100; 1369 vc->vc_hi_font_mask = 0x100;
1370 if (vc->vc_can_do_color) 1370 if (vc->vc_can_do_color)
1371 vc->vc_complement_mask <<= 1; 1371 vc->vc_complement_mask <<= 1;
1372 } 1372 }
1373 1373
1374 if (!*svc->vc_uni_pagedir_loc) 1374 if (!*svc->vc_uni_pagedir_loc)
1375 con_set_default_unimap(svc); 1375 con_set_default_unimap(svc);
1376 if (!*vc->vc_uni_pagedir_loc) 1376 if (!*vc->vc_uni_pagedir_loc)
1377 con_copy_unimap(vc, svc); 1377 con_copy_unimap(vc, svc);
1378 1378
1379 cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); 1379 cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
1380 rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); 1380 rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
1381 cols /= vc->vc_font.width; 1381 cols /= vc->vc_font.width;
1382 rows /= vc->vc_font.height; 1382 rows /= vc->vc_font.height;
1383 vc_resize(vc, cols, rows); 1383 vc_resize(vc, cols, rows);
1384 1384
1385 if (CON_IS_VISIBLE(vc)) { 1385 if (CON_IS_VISIBLE(vc)) {
1386 update_screen(vc); 1386 update_screen(vc);
1387 if (softback_buf) 1387 if (softback_buf)
1388 fbcon_update_softback(vc); 1388 fbcon_update_softback(vc);
1389 } 1389 }
1390 } 1390 }
1391 1391
1392 static __inline__ void ywrap_up(struct vc_data *vc, int count) 1392 static __inline__ void ywrap_up(struct vc_data *vc, int count)
1393 { 1393 {
1394 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 1394 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
1395 struct fbcon_ops *ops = info->fbcon_par; 1395 struct fbcon_ops *ops = info->fbcon_par;
1396 struct display *p = &fb_display[vc->vc_num]; 1396 struct display *p = &fb_display[vc->vc_num];
1397 1397
1398 p->yscroll += count; 1398 p->yscroll += count;
1399 if (p->yscroll >= p->vrows) /* Deal with wrap */ 1399 if (p->yscroll >= p->vrows) /* Deal with wrap */
1400 p->yscroll -= p->vrows; 1400 p->yscroll -= p->vrows;
1401 ops->var.xoffset = 0; 1401 ops->var.xoffset = 0;
1402 ops->var.yoffset = p->yscroll * vc->vc_font.height; 1402 ops->var.yoffset = p->yscroll * vc->vc_font.height;
1403 ops->var.vmode |= FB_VMODE_YWRAP; 1403 ops->var.vmode |= FB_VMODE_YWRAP;
1404 ops->update_start(info); 1404 ops->update_start(info);
1405 scrollback_max += count; 1405 scrollback_max += count;
1406 if (scrollback_max > scrollback_phys_max) 1406 if (scrollback_max > scrollback_phys_max)
1407 scrollback_max = scrollback_phys_max; 1407 scrollback_max = scrollback_phys_max;
1408 scrollback_current = 0; 1408 scrollback_current = 0;
1409 } 1409 }
1410 1410
1411 static __inline__ void ywrap_down(struct vc_data *vc, int count) 1411 static __inline__ void ywrap_down(struct vc_data *vc, int count)
1412 { 1412 {
1413 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 1413 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
1414 struct fbcon_ops *ops = info->fbcon_par; 1414 struct fbcon_ops *ops = info->fbcon_par;
1415 struct display *p = &fb_display[vc->vc_num]; 1415 struct display *p = &fb_display[vc->vc_num];
1416 1416
1417 p->yscroll -= count; 1417 p->yscroll -= count;
1418 if (p->yscroll < 0) /* Deal with wrap */ 1418 if (p->yscroll < 0) /* Deal with wrap */
1419 p->yscroll += p->vrows; 1419 p->yscroll += p->vrows;
1420 ops->var.xoffset = 0; 1420 ops->var.xoffset = 0;
1421 ops->var.yoffset = p->yscroll * vc->vc_font.height; 1421 ops->var.yoffset = p->yscroll * vc->vc_font.height;
1422 ops->var.vmode |= FB_VMODE_YWRAP; 1422 ops->var.vmode |= FB_VMODE_YWRAP;
1423 ops->update_start(info); 1423 ops->update_start(info);
1424 scrollback_max -= count; 1424 scrollback_max -= count;
1425 if (scrollback_max < 0) 1425 if (scrollback_max < 0)
1426 scrollback_max = 0; 1426 scrollback_max = 0;
1427 scrollback_current = 0; 1427 scrollback_current = 0;
1428 } 1428 }
1429 1429
1430 static __inline__ void ypan_up(struct vc_data *vc, int count) 1430 static __inline__ void ypan_up(struct vc_data *vc, int count)
1431 { 1431 {
1432 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 1432 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
1433 struct display *p = &fb_display[vc->vc_num]; 1433 struct display *p = &fb_display[vc->vc_num];
1434 struct fbcon_ops *ops = info->fbcon_par; 1434 struct fbcon_ops *ops = info->fbcon_par;
1435 1435
1436 p->yscroll += count; 1436 p->yscroll += count;
1437 if (p->yscroll > p->vrows - vc->vc_rows) { 1437 if (p->yscroll > p->vrows - vc->vc_rows) {
1438 ops->bmove(vc, info, p->vrows - vc->vc_rows, 1438 ops->bmove(vc, info, p->vrows - vc->vc_rows,
1439 0, 0, 0, vc->vc_rows, vc->vc_cols); 1439 0, 0, 0, vc->vc_rows, vc->vc_cols);
1440 p->yscroll -= p->vrows - vc->vc_rows; 1440 p->yscroll -= p->vrows - vc->vc_rows;
1441 } 1441 }
1442 1442
1443 ops->var.xoffset = 0; 1443 ops->var.xoffset = 0;
1444 ops->var.yoffset = p->yscroll * vc->vc_font.height; 1444 ops->var.yoffset = p->yscroll * vc->vc_font.height;
1445 ops->var.vmode &= ~FB_VMODE_YWRAP; 1445 ops->var.vmode &= ~FB_VMODE_YWRAP;
1446 ops->update_start(info); 1446 ops->update_start(info);
1447 fbcon_clear_margins(vc, 1); 1447 fbcon_clear_margins(vc, 1);
1448 scrollback_max += count; 1448 scrollback_max += count;
1449 if (scrollback_max > scrollback_phys_max) 1449 if (scrollback_max > scrollback_phys_max)
1450 scrollback_max = scrollback_phys_max; 1450 scrollback_max = scrollback_phys_max;
1451 scrollback_current = 0; 1451 scrollback_current = 0;
1452 } 1452 }
1453 1453
1454 static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count) 1454 static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count)
1455 { 1455 {
1456 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 1456 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
1457 struct fbcon_ops *ops = info->fbcon_par; 1457 struct fbcon_ops *ops = info->fbcon_par;
1458 struct display *p = &fb_display[vc->vc_num]; 1458 struct display *p = &fb_display[vc->vc_num];
1459 1459
1460 p->yscroll += count; 1460 p->yscroll += count;
1461 1461
1462 if (p->yscroll > p->vrows - vc->vc_rows) { 1462 if (p->yscroll > p->vrows - vc->vc_rows) {
1463 p->yscroll -= p->vrows - vc->vc_rows; 1463 p->yscroll -= p->vrows - vc->vc_rows;
1464 fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t); 1464 fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t);
1465 } 1465 }
1466 1466
1467 ops->var.xoffset = 0; 1467 ops->var.xoffset = 0;
1468 ops->var.yoffset = p->yscroll * vc->vc_font.height; 1468 ops->var.yoffset = p->yscroll * vc->vc_font.height;
1469 ops->var.vmode &= ~FB_VMODE_YWRAP; 1469 ops->var.vmode &= ~FB_VMODE_YWRAP;
1470 ops->update_start(info); 1470 ops->update_start(info);
1471 fbcon_clear_margins(vc, 1); 1471 fbcon_clear_margins(vc, 1);
1472 scrollback_max += count; 1472 scrollback_max += count;
1473 if (scrollback_max > scrollback_phys_max) 1473 if (scrollback_max > scrollback_phys_max)
1474 scrollback_max = scrollback_phys_max; 1474 scrollback_max = scrollback_phys_max;
1475 scrollback_current = 0; 1475 scrollback_current = 0;
1476 } 1476 }
1477 1477
1478 static __inline__ void ypan_down(struct vc_data *vc, int count) 1478 static __inline__ void ypan_down(struct vc_data *vc, int count)
1479 { 1479 {
1480 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 1480 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
1481 struct display *p = &fb_display[vc->vc_num]; 1481 struct display *p = &fb_display[vc->vc_num];
1482 struct fbcon_ops *ops = info->fbcon_par; 1482 struct fbcon_ops *ops = info->fbcon_par;
1483 1483
1484 p->yscroll -= count; 1484 p->yscroll -= count;
1485 if (p->yscroll < 0) { 1485 if (p->yscroll < 0) {
1486 ops->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows, 1486 ops->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows,
1487 0, vc->vc_rows, vc->vc_cols); 1487 0, vc->vc_rows, vc->vc_cols);
1488 p->yscroll += p->vrows - vc->vc_rows; 1488 p->yscroll += p->vrows - vc->vc_rows;
1489 } 1489 }
1490 1490
1491 ops->var.xoffset = 0; 1491 ops->var.xoffset = 0;
1492 ops->var.yoffset = p->yscroll * vc->vc_font.height; 1492 ops->var.yoffset = p->yscroll * vc->vc_font.height;
1493 ops->var.vmode &= ~FB_VMODE_YWRAP; 1493 ops->var.vmode &= ~FB_VMODE_YWRAP;
1494 ops->update_start(info); 1494 ops->update_start(info);
1495 fbcon_clear_margins(vc, 1); 1495 fbcon_clear_margins(vc, 1);
1496 scrollback_max -= count; 1496 scrollback_max -= count;
1497 if (scrollback_max < 0) 1497 if (scrollback_max < 0)
1498 scrollback_max = 0; 1498 scrollback_max = 0;
1499 scrollback_current = 0; 1499 scrollback_current = 0;
1500 } 1500 }
1501 1501
1502 static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count) 1502 static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
1503 { 1503 {
1504 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 1504 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
1505 struct fbcon_ops *ops = info->fbcon_par; 1505 struct fbcon_ops *ops = info->fbcon_par;
1506 struct display *p = &fb_display[vc->vc_num]; 1506 struct display *p = &fb_display[vc->vc_num];
1507 1507
1508 p->yscroll -= count; 1508 p->yscroll -= count;
1509 1509
1510 if (p->yscroll < 0) { 1510 if (p->yscroll < 0) {
1511 p->yscroll += p->vrows - vc->vc_rows; 1511 p->yscroll += p->vrows - vc->vc_rows;
1512 fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count); 1512 fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count);
1513 } 1513 }
1514 1514
1515 ops->var.xoffset = 0; 1515 ops->var.xoffset = 0;
1516 ops->var.yoffset = p->yscroll * vc->vc_font.height; 1516 ops->var.yoffset = p->yscroll * vc->vc_font.height;
1517 ops->var.vmode &= ~FB_VMODE_YWRAP; 1517 ops->var.vmode &= ~FB_VMODE_YWRAP;
1518 ops->update_start(info); 1518 ops->update_start(info);
1519 fbcon_clear_margins(vc, 1); 1519 fbcon_clear_margins(vc, 1);
1520 scrollback_max -= count; 1520 scrollback_max -= count;
1521 if (scrollback_max < 0) 1521 if (scrollback_max < 0)
1522 scrollback_max = 0; 1522 scrollback_max = 0;
1523 scrollback_current = 0; 1523 scrollback_current = 0;
1524 } 1524 }
1525 1525
1526 static void fbcon_redraw_softback(struct vc_data *vc, struct display *p, 1526 static void fbcon_redraw_softback(struct vc_data *vc, struct display *p,
1527 long delta) 1527 long delta)
1528 { 1528 {
1529 int count = vc->vc_rows; 1529 int count = vc->vc_rows;
1530 unsigned short *d, *s; 1530 unsigned short *d, *s;
1531 unsigned long n; 1531 unsigned long n;
1532 int line = 0; 1532 int line = 0;
1533 1533
1534 d = (u16 *) softback_curr; 1534 d = (u16 *) softback_curr;
1535 if (d == (u16 *) softback_in) 1535 if (d == (u16 *) softback_in)
1536 d = (u16 *) vc->vc_origin; 1536 d = (u16 *) vc->vc_origin;
1537 n = softback_curr + delta * vc->vc_size_row; 1537 n = softback_curr + delta * vc->vc_size_row;
1538 softback_lines -= delta; 1538 softback_lines -= delta;
1539 if (delta < 0) { 1539 if (delta < 0) {
1540 if (softback_curr < softback_top && n < softback_buf) { 1540 if (softback_curr < softback_top && n < softback_buf) {
1541 n += softback_end - softback_buf; 1541 n += softback_end - softback_buf;
1542 if (n < softback_top) { 1542 if (n < softback_top) {
1543 softback_lines -= 1543 softback_lines -=
1544 (softback_top - n) / vc->vc_size_row; 1544 (softback_top - n) / vc->vc_size_row;
1545 n = softback_top; 1545 n = softback_top;
1546 } 1546 }
1547 } else if (softback_curr >= softback_top 1547 } else if (softback_curr >= softback_top
1548 && n < softback_top) { 1548 && n < softback_top) {
1549 softback_lines -= 1549 softback_lines -=
1550 (softback_top - n) / vc->vc_size_row; 1550 (softback_top - n) / vc->vc_size_row;
1551 n = softback_top; 1551 n = softback_top;
1552 } 1552 }
1553 } else { 1553 } else {
1554 if (softback_curr > softback_in && n >= softback_end) { 1554 if (softback_curr > softback_in && n >= softback_end) {
1555 n += softback_buf - softback_end; 1555 n += softback_buf - softback_end;
1556 if (n > softback_in) { 1556 if (n > softback_in) {
1557 n = softback_in; 1557 n = softback_in;
1558 softback_lines = 0; 1558 softback_lines = 0;
1559 } 1559 }
1560 } else if (softback_curr <= softback_in && n > softback_in) { 1560 } else if (softback_curr <= softback_in && n > softback_in) {
1561 n = softback_in; 1561 n = softback_in;
1562 softback_lines = 0; 1562 softback_lines = 0;
1563 } 1563 }
1564 } 1564 }
1565 if (n == softback_curr) 1565 if (n == softback_curr)
1566 return; 1566 return;
1567 softback_curr = n; 1567 softback_curr = n;
1568 s = (u16 *) softback_curr; 1568 s = (u16 *) softback_curr;
1569 if (s == (u16 *) softback_in) 1569 if (s == (u16 *) softback_in)
1570 s = (u16 *) vc->vc_origin; 1570 s = (u16 *) vc->vc_origin;
1571 while (count--) { 1571 while (count--) {
1572 unsigned short *start; 1572 unsigned short *start;
1573 unsigned short *le; 1573 unsigned short *le;
1574 unsigned short c; 1574 unsigned short c;
1575 int x = 0; 1575 int x = 0;
1576 unsigned short attr = 1; 1576 unsigned short attr = 1;
1577 1577
1578 start = s; 1578 start = s;
1579 le = advance_row(s, 1); 1579 le = advance_row(s, 1);
1580 do { 1580 do {
1581 c = scr_readw(s); 1581 c = scr_readw(s);
1582 if (attr != (c & 0xff00)) { 1582 if (attr != (c & 0xff00)) {
1583 attr = c & 0xff00; 1583 attr = c & 0xff00;
1584 if (s > start) { 1584 if (s > start) {
1585 fbcon_putcs(vc, start, s - start, 1585 fbcon_putcs(vc, start, s - start,
1586 line, x); 1586 line, x);
1587 x += s - start; 1587 x += s - start;
1588 start = s; 1588 start = s;
1589 } 1589 }
1590 } 1590 }
1591 if (c == scr_readw(d)) { 1591 if (c == scr_readw(d)) {
1592 if (s > start) { 1592 if (s > start) {
1593 fbcon_putcs(vc, start, s - start, 1593 fbcon_putcs(vc, start, s - start,
1594 line, x); 1594 line, x);
1595 x += s - start + 1; 1595 x += s - start + 1;
1596 start = s + 1; 1596 start = s + 1;
1597 } else { 1597 } else {
1598 x++; 1598 x++;
1599 start++; 1599 start++;
1600 } 1600 }
1601 } 1601 }
1602 s++; 1602 s++;
1603 d++; 1603 d++;
1604 } while (s < le); 1604 } while (s < le);
1605 if (s > start) 1605 if (s > start)
1606 fbcon_putcs(vc, start, s - start, line, x); 1606 fbcon_putcs(vc, start, s - start, line, x);
1607 line++; 1607 line++;
1608 if (d == (u16 *) softback_end) 1608 if (d == (u16 *) softback_end)
1609 d = (u16 *) softback_buf; 1609 d = (u16 *) softback_buf;
1610 if (d == (u16 *) softback_in) 1610 if (d == (u16 *) softback_in)
1611 d = (u16 *) vc->vc_origin; 1611 d = (u16 *) vc->vc_origin;
1612 if (s == (u16 *) softback_end) 1612 if (s == (u16 *) softback_end)
1613 s = (u16 *) softback_buf; 1613 s = (u16 *) softback_buf;
1614 if (s == (u16 *) softback_in) 1614 if (s == (u16 *) softback_in)
1615 s = (u16 *) vc->vc_origin; 1615 s = (u16 *) vc->vc_origin;
1616 } 1616 }
1617 } 1617 }
1618 1618
1619 static void fbcon_redraw_move(struct vc_data *vc, struct display *p, 1619 static void fbcon_redraw_move(struct vc_data *vc, struct display *p,
1620 int line, int count, int dy) 1620 int line, int count, int dy)
1621 { 1621 {
1622 unsigned short *s = (unsigned short *) 1622 unsigned short *s = (unsigned short *)
1623 (vc->vc_origin + vc->vc_size_row * line); 1623 (vc->vc_origin + vc->vc_size_row * line);
1624 1624
1625 while (count--) { 1625 while (count--) {
1626 unsigned short *start = s; 1626 unsigned short *start = s;
1627 unsigned short *le = advance_row(s, 1); 1627 unsigned short *le = advance_row(s, 1);
1628 unsigned short c; 1628 unsigned short c;
1629 int x = 0; 1629 int x = 0;
1630 unsigned short attr = 1; 1630 unsigned short attr = 1;
1631 1631
1632 do { 1632 do {
1633 c = scr_readw(s); 1633 c = scr_readw(s);
1634 if (attr != (c & 0xff00)) { 1634 if (attr != (c & 0xff00)) {
1635 attr = c & 0xff00; 1635 attr = c & 0xff00;
1636 if (s > start) { 1636 if (s > start) {
1637 fbcon_putcs(vc, start, s - start, 1637 fbcon_putcs(vc, start, s - start,
1638 dy, x); 1638 dy, x);
1639 x += s - start; 1639 x += s - start;
1640 start = s; 1640 start = s;
1641 } 1641 }
1642 } 1642 }
1643 console_conditional_schedule(); 1643 console_conditional_schedule();
1644 s++; 1644 s++;
1645 } while (s < le); 1645 } while (s < le);
1646 if (s > start) 1646 if (s > start)
1647 fbcon_putcs(vc, start, s - start, dy, x); 1647 fbcon_putcs(vc, start, s - start, dy, x);
1648 console_conditional_schedule(); 1648 console_conditional_schedule();
1649 dy++; 1649 dy++;
1650 } 1650 }
1651 } 1651 }
1652 1652
1653 static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info, 1653 static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info,
1654 struct display *p, int line, int count, int ycount) 1654 struct display *p, int line, int count, int ycount)
1655 { 1655 {
1656 int offset = ycount * vc->vc_cols; 1656 int offset = ycount * vc->vc_cols;
1657 unsigned short *d = (unsigned short *) 1657 unsigned short *d = (unsigned short *)
1658 (vc->vc_origin + vc->vc_size_row * line); 1658 (vc->vc_origin + vc->vc_size_row * line);
1659 unsigned short *s = d + offset; 1659 unsigned short *s = d + offset;
1660 struct fbcon_ops *ops = info->fbcon_par; 1660 struct fbcon_ops *ops = info->fbcon_par;
1661 1661
1662 while (count--) { 1662 while (count--) {
1663 unsigned short *start = s; 1663 unsigned short *start = s;
1664 unsigned short *le = advance_row(s, 1); 1664 unsigned short *le = advance_row(s, 1);
1665 unsigned short c; 1665 unsigned short c;
1666 int x = 0; 1666 int x = 0;
1667 1667
1668 do { 1668 do {
1669 c = scr_readw(s); 1669 c = scr_readw(s);
1670 1670
1671 if (c == scr_readw(d)) { 1671 if (c == scr_readw(d)) {
1672 if (s > start) { 1672 if (s > start) {
1673 ops->bmove(vc, info, line + ycount, x, 1673 ops->bmove(vc, info, line + ycount, x,
1674 line, x, 1, s-start); 1674 line, x, 1, s-start);
1675 x += s - start + 1; 1675 x += s - start + 1;
1676 start = s + 1; 1676 start = s + 1;
1677 } else { 1677 } else {
1678 x++; 1678 x++;
1679 start++; 1679 start++;
1680 } 1680 }
1681 } 1681 }
1682 1682
1683 scr_writew(c, d); 1683 scr_writew(c, d);
1684 console_conditional_schedule(); 1684 console_conditional_schedule();
1685 s++; 1685 s++;
1686 d++; 1686 d++;
1687 } while (s < le); 1687 } while (s < le);
1688 if (s > start) 1688 if (s > start)
1689 ops->bmove(vc, info, line + ycount, x, line, x, 1, 1689 ops->bmove(vc, info, line + ycount, x, line, x, 1,
1690 s-start); 1690 s-start);
1691 console_conditional_schedule(); 1691 console_conditional_schedule();
1692 if (ycount > 0) 1692 if (ycount > 0)
1693 line++; 1693 line++;
1694 else { 1694 else {
1695 line--; 1695 line--;
1696 /* NOTE: We subtract two lines from these pointers */ 1696 /* NOTE: We subtract two lines from these pointers */
1697 s -= vc->vc_size_row; 1697 s -= vc->vc_size_row;
1698 d -= vc->vc_size_row; 1698 d -= vc->vc_size_row;
1699 } 1699 }
1700 } 1700 }
1701 } 1701 }
1702 1702
1703 static void fbcon_redraw(struct vc_data *vc, struct display *p, 1703 static void fbcon_redraw(struct vc_data *vc, struct display *p,
1704 int line, int count, int offset) 1704 int line, int count, int offset)
1705 { 1705 {
1706 unsigned short *d = (unsigned short *) 1706 unsigned short *d = (unsigned short *)
1707 (vc->vc_origin + vc->vc_size_row * line); 1707 (vc->vc_origin + vc->vc_size_row * line);
1708 unsigned short *s = d + offset; 1708 unsigned short *s = d + offset;
1709 1709
1710 while (count--) { 1710 while (count--) {
1711 unsigned short *start = s; 1711 unsigned short *start = s;
1712 unsigned short *le = advance_row(s, 1); 1712 unsigned short *le = advance_row(s, 1);
1713 unsigned short c; 1713 unsigned short c;
1714 int x = 0; 1714 int x = 0;
1715 unsigned short attr = 1; 1715 unsigned short attr = 1;
1716 1716
1717 do { 1717 do {
1718 c = scr_readw(s); 1718 c = scr_readw(s);
1719 if (attr != (c & 0xff00)) { 1719 if (attr != (c & 0xff00)) {
1720 attr = c & 0xff00; 1720 attr = c & 0xff00;
1721 if (s > start) { 1721 if (s > start) {
1722 fbcon_putcs(vc, start, s - start, 1722 fbcon_putcs(vc, start, s - start,
1723 line, x); 1723 line, x);
1724 x += s - start; 1724 x += s - start;
1725 start = s; 1725 start = s;
1726 } 1726 }
1727 } 1727 }
1728 if (c == scr_readw(d)) { 1728 if (c == scr_readw(d)) {
1729 if (s > start) { 1729 if (s > start) {
1730 fbcon_putcs(vc, start, s - start, 1730 fbcon_putcs(vc, start, s - start,
1731 line, x); 1731 line, x);
1732 x += s - start + 1; 1732 x += s - start + 1;
1733 start = s + 1; 1733 start = s + 1;
1734 } else { 1734 } else {
1735 x++; 1735 x++;
1736 start++; 1736 start++;
1737 } 1737 }
1738 } 1738 }
1739 scr_writew(c, d); 1739 scr_writew(c, d);
1740 console_conditional_schedule(); 1740 console_conditional_schedule();
1741 s++; 1741 s++;
1742 d++; 1742 d++;
1743 } while (s < le); 1743 } while (s < le);
1744 if (s > start) 1744 if (s > start)
1745 fbcon_putcs(vc, start, s - start, line, x); 1745 fbcon_putcs(vc, start, s - start, line, x);
1746 console_conditional_schedule(); 1746 console_conditional_schedule();
1747 if (offset > 0) 1747 if (offset > 0)
1748 line++; 1748 line++;
1749 else { 1749 else {
1750 line--; 1750 line--;
1751 /* NOTE: We subtract two lines from these pointers */ 1751 /* NOTE: We subtract two lines from these pointers */
1752 s -= vc->vc_size_row; 1752 s -= vc->vc_size_row;
1753 d -= vc->vc_size_row; 1753 d -= vc->vc_size_row;
1754 } 1754 }
1755 } 1755 }
1756 } 1756 }
1757 1757
1758 static inline void fbcon_softback_note(struct vc_data *vc, int t, 1758 static inline void fbcon_softback_note(struct vc_data *vc, int t,
1759 int count) 1759 int count)
1760 { 1760 {
1761 unsigned short *p; 1761 unsigned short *p;
1762 1762
1763 if (vc->vc_num != fg_console) 1763 if (vc->vc_num != fg_console)
1764 return; 1764 return;
1765 p = (unsigned short *) (vc->vc_origin + t * vc->vc_size_row); 1765 p = (unsigned short *) (vc->vc_origin + t * vc->vc_size_row);
1766 1766
1767 while (count) { 1767 while (count) {
1768 scr_memcpyw((u16 *) softback_in, p, vc->vc_size_row); 1768 scr_memcpyw((u16 *) softback_in, p, vc->vc_size_row);
1769 count--; 1769 count--;
1770 p = advance_row(p, 1); 1770 p = advance_row(p, 1);
1771 softback_in += vc->vc_size_row; 1771 softback_in += vc->vc_size_row;
1772 if (softback_in == softback_end) 1772 if (softback_in == softback_end)
1773 softback_in = softback_buf; 1773 softback_in = softback_buf;
1774 if (softback_in == softback_top) { 1774 if (softback_in == softback_top) {
1775 softback_top += vc->vc_size_row; 1775 softback_top += vc->vc_size_row;
1776 if (softback_top == softback_end) 1776 if (softback_top == softback_end)
1777 softback_top = softback_buf; 1777 softback_top = softback_buf;
1778 } 1778 }
1779 } 1779 }
1780 softback_curr = softback_in; 1780 softback_curr = softback_in;
1781 } 1781 }
1782 1782
1783 static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, 1783 static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
1784 int count) 1784 int count)
1785 { 1785 {
1786 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 1786 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
1787 struct display *p = &fb_display[vc->vc_num]; 1787 struct display *p = &fb_display[vc->vc_num];
1788 int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK; 1788 int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK;
1789 1789
1790 if (fbcon_is_inactive(vc, info)) 1790 if (fbcon_is_inactive(vc, info))
1791 return -EINVAL; 1791 return -EINVAL;
1792 1792
1793 fbcon_cursor(vc, CM_ERASE); 1793 fbcon_cursor(vc, CM_ERASE);
1794 1794
1795 /* 1795 /*
1796 * ++Geert: Only use ywrap/ypan if the console is in text mode 1796 * ++Geert: Only use ywrap/ypan if the console is in text mode
1797 * ++Andrew: Only use ypan on hardware text mode when scrolling the 1797 * ++Andrew: Only use ypan on hardware text mode when scrolling the
1798 * whole screen (prevents flicker). 1798 * whole screen (prevents flicker).
1799 */ 1799 */
1800 1800
1801 switch (dir) { 1801 switch (dir) {
1802 case SM_UP: 1802 case SM_UP:
1803 if (count > vc->vc_rows) /* Maximum realistic size */ 1803 if (count > vc->vc_rows) /* Maximum realistic size */
1804 count = vc->vc_rows; 1804 count = vc->vc_rows;
1805 if (softback_top) 1805 if (softback_top)
1806 fbcon_softback_note(vc, t, count); 1806 fbcon_softback_note(vc, t, count);
1807 if (logo_shown >= 0) 1807 if (logo_shown >= 0)
1808 goto redraw_up; 1808 goto redraw_up;
1809 switch (p->scrollmode) { 1809 switch (p->scrollmode) {
1810 case SCROLL_MOVE: 1810 case SCROLL_MOVE:
1811 fbcon_redraw_blit(vc, info, p, t, b - t - count, 1811 fbcon_redraw_blit(vc, info, p, t, b - t - count,
1812 count); 1812 count);
1813 fbcon_clear(vc, b - count, 0, count, vc->vc_cols); 1813 fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
1814 scr_memsetw((unsigned short *) (vc->vc_origin + 1814 scr_memsetw((unsigned short *) (vc->vc_origin +
1815 vc->vc_size_row * 1815 vc->vc_size_row *
1816 (b - count)), 1816 (b - count)),
1817 vc->vc_video_erase_char, 1817 vc->vc_video_erase_char,
1818 vc->vc_size_row * count); 1818 vc->vc_size_row * count);
1819 return 1; 1819 return 1;
1820 break; 1820 break;
1821 1821
1822 case SCROLL_WRAP_MOVE: 1822 case SCROLL_WRAP_MOVE:
1823 if (b - t - count > 3 * vc->vc_rows >> 2) { 1823 if (b - t - count > 3 * vc->vc_rows >> 2) {
1824 if (t > 0) 1824 if (t > 0)
1825 fbcon_bmove(vc, 0, 0, count, 0, t, 1825 fbcon_bmove(vc, 0, 0, count, 0, t,
1826 vc->vc_cols); 1826 vc->vc_cols);
1827 ywrap_up(vc, count); 1827 ywrap_up(vc, count);
1828 if (vc->vc_rows - b > 0) 1828 if (vc->vc_rows - b > 0)
1829 fbcon_bmove(vc, b - count, 0, b, 0, 1829 fbcon_bmove(vc, b - count, 0, b, 0,
1830 vc->vc_rows - b, 1830 vc->vc_rows - b,
1831 vc->vc_cols); 1831 vc->vc_cols);
1832 } else if (info->flags & FBINFO_READS_FAST) 1832 } else if (info->flags & FBINFO_READS_FAST)
1833 fbcon_bmove(vc, t + count, 0, t, 0, 1833 fbcon_bmove(vc, t + count, 0, t, 0,
1834 b - t - count, vc->vc_cols); 1834 b - t - count, vc->vc_cols);
1835 else 1835 else
1836 goto redraw_up; 1836 goto redraw_up;
1837 fbcon_clear(vc, b - count, 0, count, vc->vc_cols); 1837 fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
1838 break; 1838 break;
1839 1839
1840 case SCROLL_PAN_REDRAW: 1840 case SCROLL_PAN_REDRAW:
1841 if ((p->yscroll + count <= 1841 if ((p->yscroll + count <=
1842 2 * (p->vrows - vc->vc_rows)) 1842 2 * (p->vrows - vc->vc_rows))
1843 && ((!scroll_partial && (b - t == vc->vc_rows)) 1843 && ((!scroll_partial && (b - t == vc->vc_rows))
1844 || (scroll_partial 1844 || (scroll_partial
1845 && (b - t - count > 1845 && (b - t - count >
1846 3 * vc->vc_rows >> 2)))) { 1846 3 * vc->vc_rows >> 2)))) {
1847 if (t > 0) 1847 if (t > 0)
1848 fbcon_redraw_move(vc, p, 0, t, count); 1848 fbcon_redraw_move(vc, p, 0, t, count);
1849 ypan_up_redraw(vc, t, count); 1849 ypan_up_redraw(vc, t, count);
1850 if (vc->vc_rows - b > 0) 1850 if (vc->vc_rows - b > 0)
1851 fbcon_redraw_move(vc, p, b, 1851 fbcon_redraw_move(vc, p, b,
1852 vc->vc_rows - b, b); 1852 vc->vc_rows - b, b);
1853 } else 1853 } else
1854 fbcon_redraw_move(vc, p, t + count, b - t - count, t); 1854 fbcon_redraw_move(vc, p, t + count, b - t - count, t);
1855 fbcon_clear(vc, b - count, 0, count, vc->vc_cols); 1855 fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
1856 break; 1856 break;
1857 1857
1858 case SCROLL_PAN_MOVE: 1858 case SCROLL_PAN_MOVE:
1859 if ((p->yscroll + count <= 1859 if ((p->yscroll + count <=
1860 2 * (p->vrows - vc->vc_rows)) 1860 2 * (p->vrows - vc->vc_rows))
1861 && ((!scroll_partial && (b - t == vc->vc_rows)) 1861 && ((!scroll_partial && (b - t == vc->vc_rows))
1862 || (scroll_partial 1862 || (scroll_partial
1863 && (b - t - count > 1863 && (b - t - count >
1864 3 * vc->vc_rows >> 2)))) { 1864 3 * vc->vc_rows >> 2)))) {
1865 if (t > 0) 1865 if (t > 0)
1866 fbcon_bmove(vc, 0, 0, count, 0, t, 1866 fbcon_bmove(vc, 0, 0, count, 0, t,
1867 vc->vc_cols); 1867 vc->vc_cols);
1868 ypan_up(vc, count); 1868 ypan_up(vc, count);
1869 if (vc->vc_rows - b > 0) 1869 if (vc->vc_rows - b > 0)
1870 fbcon_bmove(vc, b - count, 0, b, 0, 1870 fbcon_bmove(vc, b - count, 0, b, 0,
1871 vc->vc_rows - b, 1871 vc->vc_rows - b,
1872 vc->vc_cols); 1872 vc->vc_cols);
1873 } else if (info->flags & FBINFO_READS_FAST) 1873 } else if (info->flags & FBINFO_READS_FAST)
1874 fbcon_bmove(vc, t + count, 0, t, 0, 1874 fbcon_bmove(vc, t + count, 0, t, 0,
1875 b - t - count, vc->vc_cols); 1875 b - t - count, vc->vc_cols);
1876 else 1876 else
1877 goto redraw_up; 1877 goto redraw_up;
1878 fbcon_clear(vc, b - count, 0, count, vc->vc_cols); 1878 fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
1879 break; 1879 break;
1880 1880
1881 case SCROLL_REDRAW: 1881 case SCROLL_REDRAW:
1882 redraw_up: 1882 redraw_up:
1883 fbcon_redraw(vc, p, t, b - t - count, 1883 fbcon_redraw(vc, p, t, b - t - count,
1884 count * vc->vc_cols); 1884 count * vc->vc_cols);
1885 fbcon_clear(vc, b - count, 0, count, vc->vc_cols); 1885 fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
1886 scr_memsetw((unsigned short *) (vc->vc_origin + 1886 scr_memsetw((unsigned short *) (vc->vc_origin +
1887 vc->vc_size_row * 1887 vc->vc_size_row *
1888 (b - count)), 1888 (b - count)),
1889 vc->vc_video_erase_char, 1889 vc->vc_video_erase_char,
1890 vc->vc_size_row * count); 1890 vc->vc_size_row * count);
1891 return 1; 1891 return 1;
1892 } 1892 }
1893 break; 1893 break;
1894 1894
1895 case SM_DOWN: 1895 case SM_DOWN:
1896 if (count > vc->vc_rows) /* Maximum realistic size */ 1896 if (count > vc->vc_rows) /* Maximum realistic size */
1897 count = vc->vc_rows; 1897 count = vc->vc_rows;
1898 if (logo_shown >= 0) 1898 if (logo_shown >= 0)
1899 goto redraw_down; 1899 goto redraw_down;
1900 switch (p->scrollmode) { 1900 switch (p->scrollmode) {
1901 case SCROLL_MOVE: 1901 case SCROLL_MOVE:
1902 fbcon_redraw_blit(vc, info, p, b - 1, b - t - count, 1902 fbcon_redraw_blit(vc, info, p, b - 1, b - t - count,
1903 -count); 1903 -count);
1904 fbcon_clear(vc, t, 0, count, vc->vc_cols); 1904 fbcon_clear(vc, t, 0, count, vc->vc_cols);
1905 scr_memsetw((unsigned short *) (vc->vc_origin + 1905 scr_memsetw((unsigned short *) (vc->vc_origin +
1906 vc->vc_size_row * 1906 vc->vc_size_row *
1907 t), 1907 t),
1908 vc->vc_video_erase_char, 1908 vc->vc_video_erase_char,
1909 vc->vc_size_row * count); 1909 vc->vc_size_row * count);
1910 return 1; 1910 return 1;
1911 break; 1911 break;
1912 1912
1913 case SCROLL_WRAP_MOVE: 1913 case SCROLL_WRAP_MOVE:
1914 if (b - t - count > 3 * vc->vc_rows >> 2) { 1914 if (b - t - count > 3 * vc->vc_rows >> 2) {
1915 if (vc->vc_rows - b > 0) 1915 if (vc->vc_rows - b > 0)
1916 fbcon_bmove(vc, b, 0, b - count, 0, 1916 fbcon_bmove(vc, b, 0, b - count, 0,
1917 vc->vc_rows - b, 1917 vc->vc_rows - b,
1918 vc->vc_cols); 1918 vc->vc_cols);
1919 ywrap_down(vc, count); 1919 ywrap_down(vc, count);
1920 if (t > 0) 1920 if (t > 0)
1921 fbcon_bmove(vc, count, 0, 0, 0, t, 1921 fbcon_bmove(vc, count, 0, 0, 0, t,
1922 vc->vc_cols); 1922 vc->vc_cols);
1923 } else if (info->flags & FBINFO_READS_FAST) 1923 } else if (info->flags & FBINFO_READS_FAST)
1924 fbcon_bmove(vc, t, 0, t + count, 0, 1924 fbcon_bmove(vc, t, 0, t + count, 0,
1925 b - t - count, vc->vc_cols); 1925 b - t - count, vc->vc_cols);
1926 else 1926 else
1927 goto redraw_down; 1927 goto redraw_down;
1928 fbcon_clear(vc, t, 0, count, vc->vc_cols); 1928 fbcon_clear(vc, t, 0, count, vc->vc_cols);
1929 break; 1929 break;
1930 1930
1931 case SCROLL_PAN_MOVE: 1931 case SCROLL_PAN_MOVE:
1932 if ((count - p->yscroll <= p->vrows - vc->vc_rows) 1932 if ((count - p->yscroll <= p->vrows - vc->vc_rows)
1933 && ((!scroll_partial && (b - t == vc->vc_rows)) 1933 && ((!scroll_partial && (b - t == vc->vc_rows))
1934 || (scroll_partial 1934 || (scroll_partial
1935 && (b - t - count > 1935 && (b - t - count >
1936 3 * vc->vc_rows >> 2)))) { 1936 3 * vc->vc_rows >> 2)))) {
1937 if (vc->vc_rows - b > 0) 1937 if (vc->vc_rows - b > 0)
1938 fbcon_bmove(vc, b, 0, b - count, 0, 1938 fbcon_bmove(vc, b, 0, b - count, 0,
1939 vc->vc_rows - b, 1939 vc->vc_rows - b,
1940 vc->vc_cols); 1940 vc->vc_cols);
1941 ypan_down(vc, count); 1941 ypan_down(vc, count);
1942 if (t > 0) 1942 if (t > 0)
1943 fbcon_bmove(vc, count, 0, 0, 0, t, 1943 fbcon_bmove(vc, count, 0, 0, 0, t,
1944 vc->vc_cols); 1944 vc->vc_cols);
1945 } else if (info->flags & FBINFO_READS_FAST) 1945 } else if (info->flags & FBINFO_READS_FAST)
1946 fbcon_bmove(vc, t, 0, t + count, 0, 1946 fbcon_bmove(vc, t, 0, t + count, 0,
1947 b - t - count, vc->vc_cols); 1947 b - t - count, vc->vc_cols);
1948 else 1948 else
1949 goto redraw_down; 1949 goto redraw_down;
1950 fbcon_clear(vc, t, 0, count, vc->vc_cols); 1950 fbcon_clear(vc, t, 0, count, vc->vc_cols);
1951 break; 1951 break;
1952 1952
1953 case SCROLL_PAN_REDRAW: 1953 case SCROLL_PAN_REDRAW:
1954 if ((count - p->yscroll <= p->vrows - vc->vc_rows) 1954 if ((count - p->yscroll <= p->vrows - vc->vc_rows)
1955 && ((!scroll_partial && (b - t == vc->vc_rows)) 1955 && ((!scroll_partial && (b - t == vc->vc_rows))
1956 || (scroll_partial 1956 || (scroll_partial
1957 && (b - t - count > 1957 && (b - t - count >
1958 3 * vc->vc_rows >> 2)))) { 1958 3 * vc->vc_rows >> 2)))) {
1959 if (vc->vc_rows - b > 0) 1959 if (vc->vc_rows - b > 0)
1960 fbcon_redraw_move(vc, p, b, vc->vc_rows - b, 1960 fbcon_redraw_move(vc, p, b, vc->vc_rows - b,
1961 b - count); 1961 b - count);
1962 ypan_down_redraw(vc, t, count); 1962 ypan_down_redraw(vc, t, count);
1963 if (t > 0) 1963 if (t > 0)
1964 fbcon_redraw_move(vc, p, count, t, 0); 1964 fbcon_redraw_move(vc, p, count, t, 0);
1965 } else 1965 } else
1966 fbcon_redraw_move(vc, p, t, b - t - count, t + count); 1966 fbcon_redraw_move(vc, p, t, b - t - count, t + count);
1967 fbcon_clear(vc, t, 0, count, vc->vc_cols); 1967 fbcon_clear(vc, t, 0, count, vc->vc_cols);
1968 break; 1968 break;
1969 1969
1970 case SCROLL_REDRAW: 1970 case SCROLL_REDRAW:
1971 redraw_down: 1971 redraw_down:
1972 fbcon_redraw(vc, p, b - 1, b - t - count, 1972 fbcon_redraw(vc, p, b - 1, b - t - count,
1973 -count * vc->vc_cols); 1973 -count * vc->vc_cols);
1974 fbcon_clear(vc, t, 0, count, vc->vc_cols); 1974 fbcon_clear(vc, t, 0, count, vc->vc_cols);
1975 scr_memsetw((unsigned short *) (vc->vc_origin + 1975 scr_memsetw((unsigned short *) (vc->vc_origin +
1976 vc->vc_size_row * 1976 vc->vc_size_row *
1977 t), 1977 t),
1978 vc->vc_video_erase_char, 1978 vc->vc_video_erase_char,
1979 vc->vc_size_row * count); 1979 vc->vc_size_row * count);
1980 return 1; 1980 return 1;
1981 } 1981 }
1982 } 1982 }
1983 return 0; 1983 return 0;
1984 } 1984 }
1985 1985
1986 1986
1987 static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, 1987 static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx,
1988 int height, int width) 1988 int height, int width)
1989 { 1989 {
1990 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 1990 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
1991 struct display *p = &fb_display[vc->vc_num]; 1991 struct display *p = &fb_display[vc->vc_num];
1992 1992
1993 if (fbcon_is_inactive(vc, info)) 1993 if (fbcon_is_inactive(vc, info))
1994 return; 1994 return;
1995 1995
1996 if (!width || !height) 1996 if (!width || !height)
1997 return; 1997 return;
1998 1998
1999 /* Split blits that cross physical y_wrap case. 1999 /* Split blits that cross physical y_wrap case.
2000 * Pathological case involves 4 blits, better to use recursive 2000 * Pathological case involves 4 blits, better to use recursive
2001 * code rather than unrolled case 2001 * code rather than unrolled case
2002 * 2002 *
2003 * Recursive invocations don't need to erase the cursor over and 2003 * Recursive invocations don't need to erase the cursor over and
2004 * over again, so we use fbcon_bmove_rec() 2004 * over again, so we use fbcon_bmove_rec()
2005 */ 2005 */
2006 fbcon_bmove_rec(vc, p, sy, sx, dy, dx, height, width, 2006 fbcon_bmove_rec(vc, p, sy, sx, dy, dx, height, width,
2007 p->vrows - p->yscroll); 2007 p->vrows - p->yscroll);
2008 } 2008 }
2009 2009
2010 static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx, 2010 static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx,
2011 int dy, int dx, int height, int width, u_int y_break) 2011 int dy, int dx, int height, int width, u_int y_break)
2012 { 2012 {
2013 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 2013 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
2014 struct fbcon_ops *ops = info->fbcon_par; 2014 struct fbcon_ops *ops = info->fbcon_par;
2015 u_int b; 2015 u_int b;
2016 2016
2017 if (sy < y_break && sy + height > y_break) { 2017 if (sy < y_break && sy + height > y_break) {
2018 b = y_break - sy; 2018 b = y_break - sy;
2019 if (dy < sy) { /* Avoid trashing self */ 2019 if (dy < sy) { /* Avoid trashing self */
2020 fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width, 2020 fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
2021 y_break); 2021 y_break);
2022 fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx, 2022 fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
2023 height - b, width, y_break); 2023 height - b, width, y_break);
2024 } else { 2024 } else {
2025 fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx, 2025 fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
2026 height - b, width, y_break); 2026 height - b, width, y_break);
2027 fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width, 2027 fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
2028 y_break); 2028 y_break);
2029 } 2029 }
2030 return; 2030 return;
2031 } 2031 }
2032 2032
2033 if (dy < y_break && dy + height > y_break) { 2033 if (dy < y_break && dy + height > y_break) {
2034 b = y_break - dy; 2034 b = y_break - dy;
2035 if (dy < sy) { /* Avoid trashing self */ 2035 if (dy < sy) { /* Avoid trashing self */
2036 fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width, 2036 fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
2037 y_break); 2037 y_break);
2038 fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx, 2038 fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
2039 height - b, width, y_break); 2039 height - b, width, y_break);
2040 } else { 2040 } else {
2041 fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx, 2041 fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
2042 height - b, width, y_break); 2042 height - b, width, y_break);
2043 fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width, 2043 fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
2044 y_break); 2044 y_break);
2045 } 2045 }
2046 return; 2046 return;
2047 } 2047 }
2048 ops->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx, 2048 ops->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx,
2049 height, width); 2049 height, width);
2050 } 2050 }
2051 2051
2052 static void updatescrollmode(struct display *p, 2052 static void updatescrollmode(struct display *p,
2053 struct fb_info *info, 2053 struct fb_info *info,
2054 struct vc_data *vc) 2054 struct vc_data *vc)
2055 { 2055 {
2056 struct fbcon_ops *ops = info->fbcon_par; 2056 struct fbcon_ops *ops = info->fbcon_par;
2057 int fh = vc->vc_font.height; 2057 int fh = vc->vc_font.height;
2058 int cap = info->flags; 2058 int cap = info->flags;
2059 u16 t = 0; 2059 u16 t = 0;
2060 int ypan = FBCON_SWAP(ops->rotate, info->fix.ypanstep, 2060 int ypan = FBCON_SWAP(ops->rotate, info->fix.ypanstep,
2061 info->fix.xpanstep); 2061 info->fix.xpanstep);
2062 int ywrap = FBCON_SWAP(ops->rotate, info->fix.ywrapstep, t); 2062 int ywrap = FBCON_SWAP(ops->rotate, info->fix.ywrapstep, t);
2063 int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); 2063 int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
2064 int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual, 2064 int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual,
2065 info->var.xres_virtual); 2065 info->var.xres_virtual);
2066 int good_pan = (cap & FBINFO_HWACCEL_YPAN) && 2066 int good_pan = (cap & FBINFO_HWACCEL_YPAN) &&
2067 divides(ypan, vc->vc_font.height) && vyres > yres; 2067 divides(ypan, vc->vc_font.height) && vyres > yres;
2068 int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) && 2068 int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) &&
2069 divides(ywrap, vc->vc_font.height) && 2069 divides(ywrap, vc->vc_font.height) &&
2070 divides(vc->vc_font.height, vyres) && 2070 divides(vc->vc_font.height, vyres) &&
2071 divides(vc->vc_font.height, yres); 2071 divides(vc->vc_font.height, yres);
2072 int reading_fast = cap & FBINFO_READS_FAST; 2072 int reading_fast = cap & FBINFO_READS_FAST;
2073 int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) && 2073 int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) &&
2074 !(cap & FBINFO_HWACCEL_DISABLED); 2074 !(cap & FBINFO_HWACCEL_DISABLED);
2075 int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) && 2075 int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) &&
2076 !(cap & FBINFO_HWACCEL_DISABLED); 2076 !(cap & FBINFO_HWACCEL_DISABLED);
2077 2077
2078 p->vrows = vyres/fh; 2078 p->vrows = vyres/fh;
2079 if (yres > (fh * (vc->vc_rows + 1))) 2079 if (yres > (fh * (vc->vc_rows + 1)))
2080 p->vrows -= (yres - (fh * vc->vc_rows)) / fh; 2080 p->vrows -= (yres - (fh * vc->vc_rows)) / fh;
2081 if ((yres % fh) && (vyres % fh < yres % fh)) 2081 if ((yres % fh) && (vyres % fh < yres % fh))
2082 p->vrows--; 2082 p->vrows--;
2083 2083
2084 if (good_wrap || good_pan) { 2084 if (good_wrap || good_pan) {
2085 if (reading_fast || fast_copyarea) 2085 if (reading_fast || fast_copyarea)
2086 p->scrollmode = good_wrap ? 2086 p->scrollmode = good_wrap ?
2087 SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE; 2087 SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE;
2088 else 2088 else
2089 p->scrollmode = good_wrap ? SCROLL_REDRAW : 2089 p->scrollmode = good_wrap ? SCROLL_REDRAW :
2090 SCROLL_PAN_REDRAW; 2090 SCROLL_PAN_REDRAW;
2091 } else { 2091 } else {
2092 if (reading_fast || (fast_copyarea && !fast_imageblit)) 2092 if (reading_fast || (fast_copyarea && !fast_imageblit))
2093 p->scrollmode = SCROLL_MOVE; 2093 p->scrollmode = SCROLL_MOVE;
2094 else 2094 else
2095 p->scrollmode = SCROLL_REDRAW; 2095 p->scrollmode = SCROLL_REDRAW;
2096 } 2096 }
2097 } 2097 }
2098 2098
2099 static int fbcon_resize(struct vc_data *vc, unsigned int width, 2099 static int fbcon_resize(struct vc_data *vc, unsigned int width,
2100 unsigned int height, unsigned int user) 2100 unsigned int height, unsigned int user)
2101 { 2101 {
2102 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 2102 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
2103 struct fbcon_ops *ops = info->fbcon_par; 2103 struct fbcon_ops *ops = info->fbcon_par;
2104 struct display *p = &fb_display[vc->vc_num]; 2104 struct display *p = &fb_display[vc->vc_num];
2105 struct fb_var_screeninfo var = info->var; 2105 struct fb_var_screeninfo var = info->var;
2106 int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh; 2106 int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh;
2107 2107
2108 virt_w = FBCON_SWAP(ops->rotate, width, height); 2108 virt_w = FBCON_SWAP(ops->rotate, width, height);
2109 virt_h = FBCON_SWAP(ops->rotate, height, width); 2109 virt_h = FBCON_SWAP(ops->rotate, height, width);
2110 virt_fw = FBCON_SWAP(ops->rotate, vc->vc_font.width, 2110 virt_fw = FBCON_SWAP(ops->rotate, vc->vc_font.width,
2111 vc->vc_font.height); 2111 vc->vc_font.height);
2112 virt_fh = FBCON_SWAP(ops->rotate, vc->vc_font.height, 2112 virt_fh = FBCON_SWAP(ops->rotate, vc->vc_font.height,
2113 vc->vc_font.width); 2113 vc->vc_font.width);
2114 var.xres = virt_w * virt_fw; 2114 var.xres = virt_w * virt_fw;
2115 var.yres = virt_h * virt_fh; 2115 var.yres = virt_h * virt_fh;
2116 x_diff = info->var.xres - var.xres; 2116 x_diff = info->var.xres - var.xres;
2117 y_diff = info->var.yres - var.yres; 2117 y_diff = info->var.yres - var.yres;
2118 if (x_diff < 0 || x_diff > virt_fw || 2118 if (x_diff < 0 || x_diff > virt_fw ||
2119 y_diff < 0 || y_diff > virt_fh) { 2119 y_diff < 0 || y_diff > virt_fh) {
2120 const struct fb_videomode *mode; 2120 const struct fb_videomode *mode;
2121 2121
2122 DPRINTK("attempting resize %ix%i\n", var.xres, var.yres); 2122 DPRINTK("attempting resize %ix%i\n", var.xres, var.yres);
2123 mode = fb_find_best_mode(&var, &info->modelist); 2123 mode = fb_find_best_mode(&var, &info->modelist);
2124 if (mode == NULL) 2124 if (mode == NULL)
2125 return -EINVAL; 2125 return -EINVAL;
2126 display_to_var(&var, p); 2126 display_to_var(&var, p);
2127 fb_videomode_to_var(&var, mode); 2127 fb_videomode_to_var(&var, mode);
2128 2128
2129 if (virt_w > var.xres/virt_fw || virt_h > var.yres/virt_fh) 2129 if (virt_w > var.xres/virt_fw || virt_h > var.yres/virt_fh)
2130 return -EINVAL; 2130 return -EINVAL;
2131 2131
2132 DPRINTK("resize now %ix%i\n", var.xres, var.yres); 2132 DPRINTK("resize now %ix%i\n", var.xres, var.yres);
2133 if (CON_IS_VISIBLE(vc)) { 2133 if (CON_IS_VISIBLE(vc)) {
2134 var.activate = FB_ACTIVATE_NOW | 2134 var.activate = FB_ACTIVATE_NOW |
2135 FB_ACTIVATE_FORCE; 2135 FB_ACTIVATE_FORCE;
2136 fb_set_var(info, &var); 2136 fb_set_var(info, &var);
2137 } 2137 }
2138 var_to_display(p, &info->var, info); 2138 var_to_display(p, &info->var, info);
2139 ops->var = info->var; 2139 ops->var = info->var;
2140 } 2140 }
2141 updatescrollmode(p, info, vc); 2141 updatescrollmode(p, info, vc);
2142 return 0; 2142 return 0;
2143 } 2143 }
2144 2144
2145 static int fbcon_switch(struct vc_data *vc) 2145 static int fbcon_switch(struct vc_data *vc)
2146 { 2146 {
2147 struct fb_info *info, *old_info = NULL; 2147 struct fb_info *info, *old_info = NULL;
2148 struct fbcon_ops *ops; 2148 struct fbcon_ops *ops;
2149 struct display *p = &fb_display[vc->vc_num]; 2149 struct display *p = &fb_display[vc->vc_num];
2150 struct fb_var_screeninfo var; 2150 struct fb_var_screeninfo var;
2151 int i, ret, prev_console, charcnt = 256; 2151 int i, ret, prev_console, charcnt = 256;
2152 2152
2153 info = registered_fb[con2fb_map[vc->vc_num]]; 2153 info = registered_fb[con2fb_map[vc->vc_num]];
2154 ops = info->fbcon_par; 2154 ops = info->fbcon_par;
2155 2155
2156 if (softback_top) { 2156 if (softback_top) {
2157 if (softback_lines) 2157 if (softback_lines)
2158 fbcon_set_origin(vc); 2158 fbcon_set_origin(vc);
2159 softback_top = softback_curr = softback_in = softback_buf; 2159 softback_top = softback_curr = softback_in = softback_buf;
2160 softback_lines = 0; 2160 softback_lines = 0;
2161 fbcon_update_softback(vc); 2161 fbcon_update_softback(vc);
2162 } 2162 }
2163 2163
2164 if (logo_shown >= 0) { 2164 if (logo_shown >= 0) {
2165 struct vc_data *conp2 = vc_cons[logo_shown].d; 2165 struct vc_data *conp2 = vc_cons[logo_shown].d;
2166 2166
2167 if (conp2->vc_top == logo_lines 2167 if (conp2->vc_top == logo_lines
2168 && conp2->vc_bottom == conp2->vc_rows) 2168 && conp2->vc_bottom == conp2->vc_rows)
2169 conp2->vc_top = 0; 2169 conp2->vc_top = 0;
2170 logo_shown = FBCON_LOGO_CANSHOW; 2170 logo_shown = FBCON_LOGO_CANSHOW;
2171 } 2171 }
2172 2172
2173 prev_console = ops->currcon; 2173 prev_console = ops->currcon;
2174 if (prev_console != -1) 2174 if (prev_console != -1)
2175 old_info = registered_fb[con2fb_map[prev_console]]; 2175 old_info = registered_fb[con2fb_map[prev_console]];
2176 /* 2176 /*
2177 * FIXME: If we have multiple fbdev's loaded, we need to 2177 * FIXME: If we have multiple fbdev's loaded, we need to
2178 * update all info->currcon. Perhaps, we can place this 2178 * update all info->currcon. Perhaps, we can place this
2179 * in a centralized structure, but this might break some 2179 * in a centralized structure, but this might break some
2180 * drivers. 2180 * drivers.
2181 * 2181 *
2182 * info->currcon = vc->vc_num; 2182 * info->currcon = vc->vc_num;
2183 */ 2183 */
2184 for (i = 0; i < FB_MAX; i++) { 2184 for (i = 0; i < FB_MAX; i++) {
2185 if (registered_fb[i] != NULL && registered_fb[i]->fbcon_par) { 2185 if (registered_fb[i] != NULL && registered_fb[i]->fbcon_par) {
2186 struct fbcon_ops *o = registered_fb[i]->fbcon_par; 2186 struct fbcon_ops *o = registered_fb[i]->fbcon_par;
2187 2187
2188 o->currcon = vc->vc_num; 2188 o->currcon = vc->vc_num;
2189 } 2189 }
2190 } 2190 }
2191 memset(&var, 0, sizeof(struct fb_var_screeninfo)); 2191 memset(&var, 0, sizeof(struct fb_var_screeninfo));
2192 display_to_var(&var, p); 2192 display_to_var(&var, p);
2193 var.activate = FB_ACTIVATE_NOW; 2193 var.activate = FB_ACTIVATE_NOW;
2194 2194
2195 /* 2195 /*
2196 * make sure we don't unnecessarily trip the memcmp() 2196 * make sure we don't unnecessarily trip the memcmp()
2197 * in fb_set_var() 2197 * in fb_set_var()
2198 */ 2198 */
2199 info->var.activate = var.activate; 2199 info->var.activate = var.activate;
2200 var.vmode |= info->var.vmode & ~FB_VMODE_MASK; 2200 var.vmode |= info->var.vmode & ~FB_VMODE_MASK;
2201 fb_set_var(info, &var); 2201 fb_set_var(info, &var);
2202 ops->var = info->var; 2202 ops->var = info->var;
2203 2203
2204 if (old_info != NULL && (old_info != info || 2204 if (old_info != NULL && (old_info != info ||
2205 info->flags & FBINFO_MISC_ALWAYS_SETPAR)) { 2205 info->flags & FBINFO_MISC_ALWAYS_SETPAR)) {
2206 if (info->fbops->fb_set_par) { 2206 if (info->fbops->fb_set_par) {
2207 ret = info->fbops->fb_set_par(info); 2207 ret = info->fbops->fb_set_par(info);
2208 2208
2209 if (ret) 2209 if (ret)
2210 printk(KERN_ERR "fbcon_switch: detected " 2210 printk(KERN_ERR "fbcon_switch: detected "
2211 "unhandled fb_set_par error, " 2211 "unhandled fb_set_par error, "
2212 "error code %d\n", ret); 2212 "error code %d\n", ret);
2213 } 2213 }
2214 2214
2215 if (old_info != info) 2215 if (old_info != info)
2216 fbcon_del_cursor_timer(old_info); 2216 fbcon_del_cursor_timer(old_info);
2217 } 2217 }
2218 2218
2219 if (fbcon_is_inactive(vc, info) || 2219 if (fbcon_is_inactive(vc, info) ||
2220 ops->blank_state != FB_BLANK_UNBLANK) 2220 ops->blank_state != FB_BLANK_UNBLANK)
2221 fbcon_del_cursor_timer(info); 2221 fbcon_del_cursor_timer(info);
2222 else 2222 else
2223 fbcon_add_cursor_timer(info); 2223 fbcon_add_cursor_timer(info);
2224 2224
2225 set_blitting_type(vc, info); 2225 set_blitting_type(vc, info);
2226 ops->cursor_reset = 1; 2226 ops->cursor_reset = 1;
2227 2227
2228 if (ops->rotate_font && ops->rotate_font(info, vc)) { 2228 if (ops->rotate_font && ops->rotate_font(info, vc)) {
2229 ops->rotate = FB_ROTATE_UR; 2229 ops->rotate = FB_ROTATE_UR;
2230 set_blitting_type(vc, info); 2230 set_blitting_type(vc, info);
2231 } 2231 }
2232 2232
2233 vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1); 2233 vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1);
2234 vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; 2234 vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
2235 2235
2236 if (p->userfont) 2236 if (p->userfont)
2237 charcnt = FNTCHARCNT(vc->vc_font.data); 2237 charcnt = FNTCHARCNT(vc->vc_font.data);
2238 2238
2239 if (charcnt > 256) 2239 if (charcnt > 256)
2240 vc->vc_complement_mask <<= 1; 2240 vc->vc_complement_mask <<= 1;
2241 2241
2242 updatescrollmode(p, info, vc); 2242 updatescrollmode(p, info, vc);
2243 2243
2244 switch (p->scrollmode) { 2244 switch (p->scrollmode) {
2245 case SCROLL_WRAP_MOVE: 2245 case SCROLL_WRAP_MOVE:
2246 scrollback_phys_max = p->vrows - vc->vc_rows; 2246 scrollback_phys_max = p->vrows - vc->vc_rows;
2247 break; 2247 break;
2248 case SCROLL_PAN_MOVE: 2248 case SCROLL_PAN_MOVE:
2249 case SCROLL_PAN_REDRAW: 2249 case SCROLL_PAN_REDRAW:
2250 scrollback_phys_max = p->vrows - 2 * vc->vc_rows; 2250 scrollback_phys_max = p->vrows - 2 * vc->vc_rows;
2251 if (scrollback_phys_max < 0) 2251 if (scrollback_phys_max < 0)
2252 scrollback_phys_max = 0; 2252 scrollback_phys_max = 0;
2253 break; 2253 break;
2254 default: 2254 default:
2255 scrollback_phys_max = 0; 2255 scrollback_phys_max = 0;
2256 break; 2256 break;
2257 } 2257 }
2258 2258
2259 scrollback_max = 0; 2259 scrollback_max = 0;
2260 scrollback_current = 0; 2260 scrollback_current = 0;
2261 2261
2262 if (!fbcon_is_inactive(vc, info)) { 2262 if (!fbcon_is_inactive(vc, info)) {
2263 ops->var.xoffset = ops->var.yoffset = p->yscroll = 0; 2263 ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
2264 ops->update_start(info); 2264 ops->update_start(info);
2265 } 2265 }
2266 2266
2267 fbcon_set_palette(vc, color_table); 2267 fbcon_set_palette(vc, color_table);
2268 fbcon_clear_margins(vc, 0); 2268 fbcon_clear_margins(vc, 0);
2269 2269
2270 if (logo_shown == FBCON_LOGO_DRAW) { 2270 if (logo_shown == FBCON_LOGO_DRAW) {
2271 2271
2272 logo_shown = fg_console; 2272 logo_shown = fg_console;
2273 /* This is protected above by initmem_freed */ 2273 /* This is protected above by initmem_freed */
2274 fb_show_logo(info, ops->rotate); 2274 fb_show_logo(info, ops->rotate);
2275 update_region(vc, 2275 update_region(vc,
2276 vc->vc_origin + vc->vc_size_row * vc->vc_top, 2276 vc->vc_origin + vc->vc_size_row * vc->vc_top,
2277 vc->vc_size_row * (vc->vc_bottom - 2277 vc->vc_size_row * (vc->vc_bottom -
2278 vc->vc_top) / 2); 2278 vc->vc_top) / 2);
2279 return 0; 2279 return 0;
2280 } 2280 }
2281 return 1; 2281 return 1;
2282 } 2282 }
2283 2283
2284 static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info, 2284 static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info,
2285 int blank) 2285 int blank)
2286 { 2286 {
2287 struct fb_event event; 2287 struct fb_event event;
2288 2288
2289 if (blank) { 2289 if (blank) {
2290 unsigned short charmask = vc->vc_hi_font_mask ? 2290 unsigned short charmask = vc->vc_hi_font_mask ?
2291 0x1ff : 0xff; 2291 0x1ff : 0xff;
2292 unsigned short oldc; 2292 unsigned short oldc;
2293 2293
2294 oldc = vc->vc_video_erase_char; 2294 oldc = vc->vc_video_erase_char;
2295 vc->vc_video_erase_char &= charmask; 2295 vc->vc_video_erase_char &= charmask;
2296 fbcon_clear(vc, 0, 0, vc->vc_rows, vc->vc_cols); 2296 fbcon_clear(vc, 0, 0, vc->vc_rows, vc->vc_cols);
2297 vc->vc_video_erase_char = oldc; 2297 vc->vc_video_erase_char = oldc;
2298 } 2298 }
2299 2299
2300 2300
2301 if (!lock_fb_info(info)) 2301 if (!lock_fb_info(info))
2302 return; 2302 return;
2303 event.info = info; 2303 event.info = info;
2304 event.data = &blank; 2304 event.data = &blank;
2305 fb_notifier_call_chain(FB_EVENT_CONBLANK, &event); 2305 fb_notifier_call_chain(FB_EVENT_CONBLANK, &event);
2306 unlock_fb_info(info); 2306 unlock_fb_info(info);
2307 } 2307 }
2308 2308
2309 static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) 2309 static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
2310 { 2310 {
2311 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 2311 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
2312 struct fbcon_ops *ops = info->fbcon_par; 2312 struct fbcon_ops *ops = info->fbcon_par;
2313 2313
2314 if (mode_switch) { 2314 if (mode_switch) {
2315 struct fb_var_screeninfo var = info->var; 2315 struct fb_var_screeninfo var = info->var;
2316 2316
2317 ops->graphics = 1; 2317 ops->graphics = 1;
2318 2318
2319 if (!blank) { 2319 if (!blank) {
2320 var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; 2320 var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
2321 fb_set_var(info, &var); 2321 fb_set_var(info, &var);
2322 ops->graphics = 0; 2322 ops->graphics = 0;
2323 ops->var = info->var; 2323 ops->var = info->var;
2324 } 2324 }
2325 } 2325 }
2326 2326
2327 if (!fbcon_is_inactive(vc, info)) { 2327 if (!fbcon_is_inactive(vc, info)) {
2328 if (ops->blank_state != blank) { 2328 if (ops->blank_state != blank) {
2329 ops->blank_state = blank; 2329 ops->blank_state = blank;
2330 fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW); 2330 fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW);
2331 ops->cursor_flash = (!blank); 2331 ops->cursor_flash = (!blank);
2332 2332
2333 if (!(info->flags & FBINFO_MISC_USEREVENT)) 2333 if (!(info->flags & FBINFO_MISC_USEREVENT))
2334 if (fb_blank(info, blank)) 2334 if (fb_blank(info, blank))
2335 fbcon_generic_blank(vc, info, blank); 2335 fbcon_generic_blank(vc, info, blank);
2336 } 2336 }
2337 2337
2338 if (!blank) 2338 if (!blank)
2339 update_screen(vc); 2339 update_screen(vc);
2340 } 2340 }
2341 2341
2342 if (mode_switch || fbcon_is_inactive(vc, info) || 2342 if (mode_switch || fbcon_is_inactive(vc, info) ||
2343 ops->blank_state != FB_BLANK_UNBLANK) 2343 ops->blank_state != FB_BLANK_UNBLANK)
2344 fbcon_del_cursor_timer(info); 2344 fbcon_del_cursor_timer(info);
2345 else 2345 else
2346 fbcon_add_cursor_timer(info); 2346 fbcon_add_cursor_timer(info);
2347 2347
2348 return 0; 2348 return 0;
2349 } 2349 }
2350 2350
2351 static int fbcon_debug_enter(struct vc_data *vc) 2351 static int fbcon_debug_enter(struct vc_data *vc)
2352 { 2352 {
2353 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 2353 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
2354 struct fbcon_ops *ops = info->fbcon_par; 2354 struct fbcon_ops *ops = info->fbcon_par;
2355 2355
2356 ops->save_graphics = ops->graphics; 2356 ops->save_graphics = ops->graphics;
2357 ops->graphics = 0; 2357 ops->graphics = 0;
2358 if (info->fbops->fb_debug_enter) 2358 if (info->fbops->fb_debug_enter)
2359 info->fbops->fb_debug_enter(info); 2359 info->fbops->fb_debug_enter(info);
2360 fbcon_set_palette(vc, color_table); 2360 fbcon_set_palette(vc, color_table);
2361 return 0; 2361 return 0;
2362 } 2362 }
2363 2363
2364 static int fbcon_debug_leave(struct vc_data *vc) 2364 static int fbcon_debug_leave(struct vc_data *vc)
2365 { 2365 {
2366 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 2366 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
2367 struct fbcon_ops *ops = info->fbcon_par; 2367 struct fbcon_ops *ops = info->fbcon_par;
2368 2368
2369 ops->graphics = ops->save_graphics; 2369 ops->graphics = ops->save_graphics;
2370 if (info->fbops->fb_debug_leave) 2370 if (info->fbops->fb_debug_leave)
2371 info->fbops->fb_debug_leave(info); 2371 info->fbops->fb_debug_leave(info);
2372 return 0; 2372 return 0;
2373 } 2373 }
2374 2374
2375 static int fbcon_get_font(struct vc_data *vc, struct console_font *font) 2375 static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
2376 { 2376 {
2377 u8 *fontdata = vc->vc_font.data; 2377 u8 *fontdata = vc->vc_font.data;
2378 u8 *data = font->data; 2378 u8 *data = font->data;
2379 int i, j; 2379 int i, j;
2380 2380
2381 font->width = vc->vc_font.width; 2381 font->width = vc->vc_font.width;
2382 font->height = vc->vc_font.height; 2382 font->height = vc->vc_font.height;
2383 font->charcount = vc->vc_hi_font_mask ? 512 : 256; 2383 font->charcount = vc->vc_hi_font_mask ? 512 : 256;
2384 if (!font->data) 2384 if (!font->data)
2385 return 0; 2385 return 0;
2386 2386
2387 if (font->width <= 8) { 2387 if (font->width <= 8) {
2388 j = vc->vc_font.height; 2388 j = vc->vc_font.height;
2389 for (i = 0; i < font->charcount; i++) { 2389 for (i = 0; i < font->charcount; i++) {
2390 memcpy(data, fontdata, j); 2390 memcpy(data, fontdata, j);
2391 memset(data + j, 0, 32 - j); 2391 memset(data + j, 0, 32 - j);
2392 data += 32; 2392 data += 32;
2393 fontdata += j; 2393 fontdata += j;
2394 } 2394 }
2395 } else if (font->width <= 16) { 2395 } else if (font->width <= 16) {
2396 j = vc->vc_font.height * 2; 2396 j = vc->vc_font.height * 2;
2397 for (i = 0; i < font->charcount; i++) { 2397 for (i = 0; i < font->charcount; i++) {
2398 memcpy(data, fontdata, j); 2398 memcpy(data, fontdata, j);
2399 memset(data + j, 0, 64 - j); 2399 memset(data + j, 0, 64 - j);
2400 data += 64; 2400 data += 64;
2401 fontdata += j; 2401 fontdata += j;
2402 } 2402 }
2403 } else if (font->width <= 24) { 2403 } else if (font->width <= 24) {
2404 for (i = 0; i < font->charcount; i++) { 2404 for (i = 0; i < font->charcount; i++) {
2405 for (j = 0; j < vc->vc_font.height; j++) { 2405 for (j = 0; j < vc->vc_font.height; j++) {
2406 *data++ = fontdata[0]; 2406 *data++ = fontdata[0];
2407 *data++ = fontdata[1]; 2407 *data++ = fontdata[1];
2408 *data++ = fontdata[2]; 2408 *data++ = fontdata[2];
2409 fontdata += sizeof(u32); 2409 fontdata += sizeof(u32);
2410 } 2410 }
2411 memset(data, 0, 3 * (32 - j)); 2411 memset(data, 0, 3 * (32 - j));
2412 data += 3 * (32 - j); 2412 data += 3 * (32 - j);
2413 } 2413 }
2414 } else { 2414 } else {
2415 j = vc->vc_font.height * 4; 2415 j = vc->vc_font.height * 4;
2416 for (i = 0; i < font->charcount; i++) { 2416 for (i = 0; i < font->charcount; i++) {
2417 memcpy(data, fontdata, j); 2417 memcpy(data, fontdata, j);
2418 memset(data + j, 0, 128 - j); 2418 memset(data + j, 0, 128 - j);
2419 data += 128; 2419 data += 128;
2420 fontdata += j; 2420 fontdata += j;
2421 } 2421 }
2422 } 2422 }
2423 return 0; 2423 return 0;
2424 } 2424 }
2425 2425
2426 static int fbcon_do_set_font(struct vc_data *vc, int w, int h, 2426 static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
2427 const u8 * data, int userfont) 2427 const u8 * data, int userfont)
2428 { 2428 {
2429 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 2429 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
2430 struct fbcon_ops *ops = info->fbcon_par; 2430 struct fbcon_ops *ops = info->fbcon_par;
2431 struct display *p = &fb_display[vc->vc_num]; 2431 struct display *p = &fb_display[vc->vc_num];
2432 int resize; 2432 int resize;
2433 int cnt; 2433 int cnt;
2434 char *old_data = NULL; 2434 char *old_data = NULL;
2435 2435
2436 if (CON_IS_VISIBLE(vc) && softback_lines) 2436 if (CON_IS_VISIBLE(vc) && softback_lines)
2437 fbcon_set_origin(vc); 2437 fbcon_set_origin(vc);
2438 2438
2439 resize = (w != vc->vc_font.width) || (h != vc->vc_font.height); 2439 resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
2440 if (p->userfont) 2440 if (p->userfont)
2441 old_data = vc->vc_font.data; 2441 old_data = vc->vc_font.data;
2442 if (userfont) 2442 if (userfont)
2443 cnt = FNTCHARCNT(data); 2443 cnt = FNTCHARCNT(data);
2444 else 2444 else
2445 cnt = 256; 2445 cnt = 256;
2446 vc->vc_font.data = (void *)(p->fontdata = data); 2446 vc->vc_font.data = (void *)(p->fontdata = data);
2447 if ((p->userfont = userfont)) 2447 if ((p->userfont = userfont))
2448 REFCOUNT(data)++; 2448 REFCOUNT(data)++;
2449 vc->vc_font.width = w; 2449 vc->vc_font.width = w;
2450 vc->vc_font.height = h; 2450 vc->vc_font.height = h;
2451 if (vc->vc_hi_font_mask && cnt == 256) { 2451 if (vc->vc_hi_font_mask && cnt == 256) {
2452 vc->vc_hi_font_mask = 0; 2452 vc->vc_hi_font_mask = 0;
2453 if (vc->vc_can_do_color) { 2453 if (vc->vc_can_do_color) {
2454 vc->vc_complement_mask >>= 1; 2454 vc->vc_complement_mask >>= 1;
2455 vc->vc_s_complement_mask >>= 1; 2455 vc->vc_s_complement_mask >>= 1;
2456 } 2456 }
2457 2457
2458 /* ++Edmund: reorder the attribute bits */ 2458 /* ++Edmund: reorder the attribute bits */
2459 if (vc->vc_can_do_color) { 2459 if (vc->vc_can_do_color) {
2460 unsigned short *cp = 2460 unsigned short *cp =
2461 (unsigned short *) vc->vc_origin; 2461 (unsigned short *) vc->vc_origin;
2462 int count = vc->vc_screenbuf_size / 2; 2462 int count = vc->vc_screenbuf_size / 2;
2463 unsigned short c; 2463 unsigned short c;
2464 for (; count > 0; count--, cp++) { 2464 for (; count > 0; count--, cp++) {
2465 c = scr_readw(cp); 2465 c = scr_readw(cp);
2466 scr_writew(((c & 0xfe00) >> 1) | 2466 scr_writew(((c & 0xfe00) >> 1) |
2467 (c & 0xff), cp); 2467 (c & 0xff), cp);
2468 } 2468 }
2469 c = vc->vc_video_erase_char; 2469 c = vc->vc_video_erase_char;
2470 vc->vc_video_erase_char = 2470 vc->vc_video_erase_char =
2471 ((c & 0xfe00) >> 1) | (c & 0xff); 2471 ((c & 0xfe00) >> 1) | (c & 0xff);
2472 vc->vc_attr >>= 1; 2472 vc->vc_attr >>= 1;
2473 } 2473 }
2474 } else if (!vc->vc_hi_font_mask && cnt == 512) { 2474 } else if (!vc->vc_hi_font_mask && cnt == 512) {
2475 vc->vc_hi_font_mask = 0x100; 2475 vc->vc_hi_font_mask = 0x100;
2476 if (vc->vc_can_do_color) { 2476 if (vc->vc_can_do_color) {
2477 vc->vc_complement_mask <<= 1; 2477 vc->vc_complement_mask <<= 1;
2478 vc->vc_s_complement_mask <<= 1; 2478 vc->vc_s_complement_mask <<= 1;
2479 } 2479 }
2480 2480
2481 /* ++Edmund: reorder the attribute bits */ 2481 /* ++Edmund: reorder the attribute bits */
2482 { 2482 {
2483 unsigned short *cp = 2483 unsigned short *cp =
2484 (unsigned short *) vc->vc_origin; 2484 (unsigned short *) vc->vc_origin;
2485 int count = vc->vc_screenbuf_size / 2; 2485 int count = vc->vc_screenbuf_size / 2;
2486 unsigned short c; 2486 unsigned short c;
2487 for (; count > 0; count--, cp++) { 2487 for (; count > 0; count--, cp++) {
2488 unsigned short newc; 2488 unsigned short newc;
2489 c = scr_readw(cp); 2489 c = scr_readw(cp);
2490 if (vc->vc_can_do_color) 2490 if (vc->vc_can_do_color)
2491 newc = 2491 newc =
2492 ((c & 0xff00) << 1) | (c & 2492 ((c & 0xff00) << 1) | (c &
2493 0xff); 2493 0xff);
2494 else 2494 else
2495 newc = c & ~0x100; 2495 newc = c & ~0x100;
2496 scr_writew(newc, cp); 2496 scr_writew(newc, cp);
2497 } 2497 }
2498 c = vc->vc_video_erase_char; 2498 c = vc->vc_video_erase_char;
2499 if (vc->vc_can_do_color) { 2499 if (vc->vc_can_do_color) {
2500 vc->vc_video_erase_char = 2500 vc->vc_video_erase_char =
2501 ((c & 0xff00) << 1) | (c & 0xff); 2501 ((c & 0xff00) << 1) | (c & 0xff);
2502 vc->vc_attr <<= 1; 2502 vc->vc_attr <<= 1;
2503 } else 2503 } else
2504 vc->vc_video_erase_char = c & ~0x100; 2504 vc->vc_video_erase_char = c & ~0x100;
2505 } 2505 }
2506 2506
2507 } 2507 }
2508 2508
2509 if (resize) { 2509 if (resize) {
2510 int cols, rows; 2510 int cols, rows;
2511 2511
2512 cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); 2512 cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
2513 rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); 2513 rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
2514 cols /= w; 2514 cols /= w;
2515 rows /= h; 2515 rows /= h;
2516 vc_resize(vc, cols, rows); 2516 vc_resize(vc, cols, rows);
2517 if (CON_IS_VISIBLE(vc) && softback_buf) 2517 if (CON_IS_VISIBLE(vc) && softback_buf)
2518 fbcon_update_softback(vc); 2518 fbcon_update_softback(vc);
2519 } else if (CON_IS_VISIBLE(vc) 2519 } else if (CON_IS_VISIBLE(vc)
2520 && vc->vc_mode == KD_TEXT) { 2520 && vc->vc_mode == KD_TEXT) {
2521 fbcon_clear_margins(vc, 0); 2521 fbcon_clear_margins(vc, 0);
2522 update_screen(vc); 2522 update_screen(vc);
2523 } 2523 }
2524 2524
2525 if (old_data && (--REFCOUNT(old_data) == 0)) 2525 if (old_data && (--REFCOUNT(old_data) == 0))
2526 kfree(old_data - FONT_EXTRA_WORDS * sizeof(int)); 2526 kfree(old_data - FONT_EXTRA_WORDS * sizeof(int));
2527 return 0; 2527 return 0;
2528 } 2528 }
2529 2529
2530 static int fbcon_copy_font(struct vc_data *vc, int con) 2530 static int fbcon_copy_font(struct vc_data *vc, int con)
2531 { 2531 {
2532 struct display *od = &fb_display[con]; 2532 struct display *od = &fb_display[con];
2533 struct console_font *f = &vc->vc_font; 2533 struct console_font *f = &vc->vc_font;
2534 2534
2535 if (od->fontdata == f->data) 2535 if (od->fontdata == f->data)
2536 return 0; /* already the same font... */ 2536 return 0; /* already the same font... */
2537 return fbcon_do_set_font(vc, f->width, f->height, od->fontdata, od->userfont); 2537 return fbcon_do_set_font(vc, f->width, f->height, od->fontdata, od->userfont);
2538 } 2538 }
2539 2539
2540 /* 2540 /*
2541 * User asked to set font; we are guaranteed that 2541 * User asked to set font; we are guaranteed that
2542 * a) width and height are in range 1..32 2542 * a) width and height are in range 1..32
2543 * b) charcount does not exceed 512 2543 * b) charcount does not exceed 512
2544 * but lets not assume that, since someone might someday want to use larger 2544 * but lets not assume that, since someone might someday want to use larger
2545 * fonts. And charcount of 512 is small for unicode support. 2545 * fonts. And charcount of 512 is small for unicode support.
2546 * 2546 *
2547 * However, user space gives the font in 32 rows , regardless of 2547 * However, user space gives the font in 32 rows , regardless of
2548 * actual font height. So a new API is needed if support for larger fonts 2548 * actual font height. So a new API is needed if support for larger fonts
2549 * is ever implemented. 2549 * is ever implemented.
2550 */ 2550 */
2551 2551
2552 static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigned flags) 2552 static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigned flags)
2553 { 2553 {
2554 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 2554 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
2555 unsigned charcount = font->charcount; 2555 unsigned charcount = font->charcount;
2556 int w = font->width; 2556 int w = font->width;
2557 int h = font->height; 2557 int h = font->height;
2558 int size; 2558 int size;
2559 int i, csum; 2559 int i, csum;
2560 u8 *new_data, *data = font->data; 2560 u8 *new_data, *data = font->data;
2561 int pitch = (font->width+7) >> 3; 2561 int pitch = (font->width+7) >> 3;
2562 2562
2563 /* Is there a reason why fbconsole couldn't handle any charcount >256? 2563 /* Is there a reason why fbconsole couldn't handle any charcount >256?
2564 * If not this check should be changed to charcount < 256 */ 2564 * If not this check should be changed to charcount < 256 */
2565 if (charcount != 256 && charcount != 512) 2565 if (charcount != 256 && charcount != 512)
2566 return -EINVAL; 2566 return -EINVAL;
2567 2567
2568 /* Make sure drawing engine can handle the font */ 2568 /* Make sure drawing engine can handle the font */
2569 if (!(info->pixmap.blit_x & (1 << (font->width - 1))) || 2569 if (!(info->pixmap.blit_x & (1 << (font->width - 1))) ||
2570 !(info->pixmap.blit_y & (1 << (font->height - 1)))) 2570 !(info->pixmap.blit_y & (1 << (font->height - 1))))
2571 return -EINVAL; 2571 return -EINVAL;
2572 2572
2573 /* Make sure driver can handle the font length */ 2573 /* Make sure driver can handle the font length */
2574 if (fbcon_invalid_charcount(info, charcount)) 2574 if (fbcon_invalid_charcount(info, charcount))
2575 return -EINVAL; 2575 return -EINVAL;
2576 2576
2577 size = h * pitch * charcount; 2577 size = h * pitch * charcount;
2578 2578
2579 new_data = kmalloc(FONT_EXTRA_WORDS * sizeof(int) + size, GFP_USER); 2579 new_data = kmalloc(FONT_EXTRA_WORDS * sizeof(int) + size, GFP_USER);
2580 2580
2581 if (!new_data) 2581 if (!new_data)
2582 return -ENOMEM; 2582 return -ENOMEM;
2583 2583
2584 new_data += FONT_EXTRA_WORDS * sizeof(int); 2584 new_data += FONT_EXTRA_WORDS * sizeof(int);
2585 FNTSIZE(new_data) = size; 2585 FNTSIZE(new_data) = size;
2586 FNTCHARCNT(new_data) = charcount; 2586 FNTCHARCNT(new_data) = charcount;
2587 REFCOUNT(new_data) = 0; /* usage counter */ 2587 REFCOUNT(new_data) = 0; /* usage counter */
2588 for (i=0; i< charcount; i++) { 2588 for (i=0; i< charcount; i++) {
2589 memcpy(new_data + i*h*pitch, data + i*32*pitch, h*pitch); 2589 memcpy(new_data + i*h*pitch, data + i*32*pitch, h*pitch);
2590 } 2590 }
2591 2591
2592 /* Since linux has a nice crc32 function use it for counting font 2592 /* Since linux has a nice crc32 function use it for counting font
2593 * checksums. */ 2593 * checksums. */
2594 csum = crc32(0, new_data, size); 2594 csum = crc32(0, new_data, size);
2595 2595
2596 FNTSUM(new_data) = csum; 2596 FNTSUM(new_data) = csum;
2597 /* Check if the same font is on some other console already */ 2597 /* Check if the same font is on some other console already */
2598 for (i = first_fb_vc; i <= last_fb_vc; i++) { 2598 for (i = first_fb_vc; i <= last_fb_vc; i++) {
2599 struct vc_data *tmp = vc_cons[i].d; 2599 struct vc_data *tmp = vc_cons[i].d;
2600 2600
2601 if (fb_display[i].userfont && 2601 if (fb_display[i].userfont &&
2602 fb_display[i].fontdata && 2602 fb_display[i].fontdata &&
2603 FNTSUM(fb_display[i].fontdata) == csum && 2603 FNTSUM(fb_display[i].fontdata) == csum &&
2604 FNTSIZE(fb_display[i].fontdata) == size && 2604 FNTSIZE(fb_display[i].fontdata) == size &&
2605 tmp->vc_font.width == w && 2605 tmp->vc_font.width == w &&
2606 !memcmp(fb_display[i].fontdata, new_data, size)) { 2606 !memcmp(fb_display[i].fontdata, new_data, size)) {
2607 kfree(new_data - FONT_EXTRA_WORDS * sizeof(int)); 2607 kfree(new_data - FONT_EXTRA_WORDS * sizeof(int));
2608 new_data = (u8 *)fb_display[i].fontdata; 2608 new_data = (u8 *)fb_display[i].fontdata;
2609 break; 2609 break;
2610 } 2610 }
2611 } 2611 }
2612 return fbcon_do_set_font(vc, font->width, font->height, new_data, 1); 2612 return fbcon_do_set_font(vc, font->width, font->height, new_data, 1);
2613 } 2613 }
2614 2614
2615 static int fbcon_set_def_font(struct vc_data *vc, struct console_font *font, char *name) 2615 static int fbcon_set_def_font(struct vc_data *vc, struct console_font *font, char *name)
2616 { 2616 {
2617 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 2617 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
2618 const struct font_desc *f; 2618 const struct font_desc *f;
2619 2619
2620 if (!name) 2620 if (!name)
2621 f = get_default_font(info->var.xres, info->var.yres, 2621 f = get_default_font(info->var.xres, info->var.yres,
2622 info->pixmap.blit_x, info->pixmap.blit_y); 2622 info->pixmap.blit_x, info->pixmap.blit_y);
2623 else if (!(f = find_font(name))) 2623 else if (!(f = find_font(name)))
2624 return -ENOENT; 2624 return -ENOENT;
2625 2625
2626 font->width = f->width; 2626 font->width = f->width;
2627 font->height = f->height; 2627 font->height = f->height;
2628 return fbcon_do_set_font(vc, f->width, f->height, f->data, 0); 2628 return fbcon_do_set_font(vc, f->width, f->height, f->data, 0);
2629 } 2629 }
2630 2630
2631 static u16 palette_red[16]; 2631 static u16 palette_red[16];
2632 static u16 palette_green[16]; 2632 static u16 palette_green[16];
2633 static u16 palette_blue[16]; 2633 static u16 palette_blue[16];
2634 2634
2635 static struct fb_cmap palette_cmap = { 2635 static struct fb_cmap palette_cmap = {
2636 0, 16, palette_red, palette_green, palette_blue, NULL 2636 0, 16, palette_red, palette_green, palette_blue, NULL
2637 }; 2637 };
2638 2638
2639 static int fbcon_set_palette(struct vc_data *vc, unsigned char *table) 2639 static int fbcon_set_palette(struct vc_data *vc, unsigned char *table)
2640 { 2640 {
2641 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 2641 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
2642 int i, j, k, depth; 2642 int i, j, k, depth;
2643 u8 val; 2643 u8 val;
2644 2644
2645 if (fbcon_is_inactive(vc, info)) 2645 if (fbcon_is_inactive(vc, info))
2646 return -EINVAL; 2646 return -EINVAL;
2647 2647
2648 if (!CON_IS_VISIBLE(vc)) 2648 if (!CON_IS_VISIBLE(vc))
2649 return 0; 2649 return 0;
2650 2650
2651 depth = fb_get_color_depth(&info->var, &info->fix); 2651 depth = fb_get_color_depth(&info->var, &info->fix);
2652 if (depth > 3) { 2652 if (depth > 3) {
2653 for (i = j = 0; i < 16; i++) { 2653 for (i = j = 0; i < 16; i++) {
2654 k = table[i]; 2654 k = table[i];
2655 val = vc->vc_palette[j++]; 2655 val = vc->vc_palette[j++];
2656 palette_red[k] = (val << 8) | val; 2656 palette_red[k] = (val << 8) | val;
2657 val = vc->vc_palette[j++]; 2657 val = vc->vc_palette[j++];
2658 palette_green[k] = (val << 8) | val; 2658 palette_green[k] = (val << 8) | val;
2659 val = vc->vc_palette[j++]; 2659 val = vc->vc_palette[j++];
2660 palette_blue[k] = (val << 8) | val; 2660 palette_blue[k] = (val << 8) | val;
2661 } 2661 }
2662 palette_cmap.len = 16; 2662 palette_cmap.len = 16;
2663 palette_cmap.start = 0; 2663 palette_cmap.start = 0;
2664 /* 2664 /*
2665 * If framebuffer is capable of less than 16 colors, 2665 * If framebuffer is capable of less than 16 colors,
2666 * use default palette of fbcon. 2666 * use default palette of fbcon.
2667 */ 2667 */
2668 } else 2668 } else
2669 fb_copy_cmap(fb_default_cmap(1 << depth), &palette_cmap); 2669 fb_copy_cmap(fb_default_cmap(1 << depth), &palette_cmap);
2670 2670
2671 return fb_set_cmap(&palette_cmap, info); 2671 return fb_set_cmap(&palette_cmap, info);
2672 } 2672 }
2673 2673
2674 static u16 *fbcon_screen_pos(struct vc_data *vc, int offset) 2674 static u16 *fbcon_screen_pos(struct vc_data *vc, int offset)
2675 { 2675 {
2676 unsigned long p; 2676 unsigned long p;
2677 int line; 2677 int line;
2678 2678
2679 if (vc->vc_num != fg_console || !softback_lines) 2679 if (vc->vc_num != fg_console || !softback_lines)
2680 return (u16 *) (vc->vc_origin + offset); 2680 return (u16 *) (vc->vc_origin + offset);
2681 line = offset / vc->vc_size_row; 2681 line = offset / vc->vc_size_row;
2682 if (line >= softback_lines) 2682 if (line >= softback_lines)
2683 return (u16 *) (vc->vc_origin + offset - 2683 return (u16 *) (vc->vc_origin + offset -
2684 softback_lines * vc->vc_size_row); 2684 softback_lines * vc->vc_size_row);
2685 p = softback_curr + offset; 2685 p = softback_curr + offset;
2686 if (p >= softback_end) 2686 if (p >= softback_end)
2687 p += softback_buf - softback_end; 2687 p += softback_buf - softback_end;
2688 return (u16 *) p; 2688 return (u16 *) p;
2689 } 2689 }
2690 2690
2691 static unsigned long fbcon_getxy(struct vc_data *vc, unsigned long pos, 2691 static unsigned long fbcon_getxy(struct vc_data *vc, unsigned long pos,
2692 int *px, int *py) 2692 int *px, int *py)
2693 { 2693 {
2694 unsigned long ret; 2694 unsigned long ret;
2695 int x, y; 2695 int x, y;
2696 2696
2697 if (pos >= vc->vc_origin && pos < vc->vc_scr_end) { 2697 if (pos >= vc->vc_origin && pos < vc->vc_scr_end) {
2698 unsigned long offset = (pos - vc->vc_origin) / 2; 2698 unsigned long offset = (pos - vc->vc_origin) / 2;
2699 2699
2700 x = offset % vc->vc_cols; 2700 x = offset % vc->vc_cols;
2701 y = offset / vc->vc_cols; 2701 y = offset / vc->vc_cols;
2702 if (vc->vc_num == fg_console) 2702 if (vc->vc_num == fg_console)
2703 y += softback_lines; 2703 y += softback_lines;
2704 ret = pos + (vc->vc_cols - x) * 2; 2704 ret = pos + (vc->vc_cols - x) * 2;
2705 } else if (vc->vc_num == fg_console && softback_lines) { 2705 } else if (vc->vc_num == fg_console && softback_lines) {
2706 unsigned long offset = pos - softback_curr; 2706 unsigned long offset = pos - softback_curr;
2707 2707
2708 if (pos < softback_curr) 2708 if (pos < softback_curr)
2709 offset += softback_end - softback_buf; 2709 offset += softback_end - softback_buf;
2710 offset /= 2; 2710 offset /= 2;
2711 x = offset % vc->vc_cols; 2711 x = offset % vc->vc_cols;
2712 y = offset / vc->vc_cols; 2712 y = offset / vc->vc_cols;
2713 ret = pos + (vc->vc_cols - x) * 2; 2713 ret = pos + (vc->vc_cols - x) * 2;
2714 if (ret == softback_end) 2714 if (ret == softback_end)
2715 ret = softback_buf; 2715 ret = softback_buf;
2716 if (ret == softback_in) 2716 if (ret == softback_in)
2717 ret = vc->vc_origin; 2717 ret = vc->vc_origin;
2718 } else { 2718 } else {
2719 /* Should not happen */ 2719 /* Should not happen */
2720 x = y = 0; 2720 x = y = 0;
2721 ret = vc->vc_origin; 2721 ret = vc->vc_origin;
2722 } 2722 }
2723 if (px) 2723 if (px)
2724 *px = x; 2724 *px = x;
2725 if (py) 2725 if (py)
2726 *py = y; 2726 *py = y;
2727 return ret; 2727 return ret;
2728 } 2728 }
2729 2729
2730 /* As we might be inside of softback, we may work with non-contiguous buffer, 2730 /* As we might be inside of softback, we may work with non-contiguous buffer,
2731 that's why we have to use a separate routine. */ 2731 that's why we have to use a separate routine. */
2732 static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt) 2732 static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt)
2733 { 2733 {
2734 while (cnt--) { 2734 while (cnt--) {
2735 u16 a = scr_readw(p); 2735 u16 a = scr_readw(p);
2736 if (!vc->vc_can_do_color) 2736 if (!vc->vc_can_do_color)
2737 a ^= 0x0800; 2737 a ^= 0x0800;
2738 else if (vc->vc_hi_font_mask == 0x100) 2738 else if (vc->vc_hi_font_mask == 0x100)
2739 a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | 2739 a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) |
2740 (((a) & 0x0e00) << 4); 2740 (((a) & 0x0e00) << 4);
2741 else 2741 else
2742 a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | 2742 a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
2743 (((a) & 0x0700) << 4); 2743 (((a) & 0x0700) << 4);
2744 scr_writew(a, p++); 2744 scr_writew(a, p++);
2745 if (p == (u16 *) softback_end) 2745 if (p == (u16 *) softback_end)
2746 p = (u16 *) softback_buf; 2746 p = (u16 *) softback_buf;
2747 if (p == (u16 *) softback_in) 2747 if (p == (u16 *) softback_in)
2748 p = (u16 *) vc->vc_origin; 2748 p = (u16 *) vc->vc_origin;
2749 } 2749 }
2750 } 2750 }
2751 2751
2752 static int fbcon_scrolldelta(struct vc_data *vc, int lines) 2752 static int fbcon_scrolldelta(struct vc_data *vc, int lines)
2753 { 2753 {
2754 struct fb_info *info = registered_fb[con2fb_map[fg_console]]; 2754 struct fb_info *info = registered_fb[con2fb_map[fg_console]];
2755 struct fbcon_ops *ops = info->fbcon_par; 2755 struct fbcon_ops *ops = info->fbcon_par;
2756 struct display *disp = &fb_display[fg_console]; 2756 struct display *disp = &fb_display[fg_console];
2757 int offset, limit, scrollback_old; 2757 int offset, limit, scrollback_old;
2758 2758
2759 if (softback_top) { 2759 if (softback_top) {
2760 if (vc->vc_num != fg_console) 2760 if (vc->vc_num != fg_console)
2761 return 0; 2761 return 0;
2762 if (vc->vc_mode != KD_TEXT || !lines) 2762 if (vc->vc_mode != KD_TEXT || !lines)
2763 return 0; 2763 return 0;
2764 if (logo_shown >= 0) { 2764 if (logo_shown >= 0) {
2765 struct vc_data *conp2 = vc_cons[logo_shown].d; 2765 struct vc_data *conp2 = vc_cons[logo_shown].d;
2766 2766
2767 if (conp2->vc_top == logo_lines 2767 if (conp2->vc_top == logo_lines
2768 && conp2->vc_bottom == conp2->vc_rows) 2768 && conp2->vc_bottom == conp2->vc_rows)
2769 conp2->vc_top = 0; 2769 conp2->vc_top = 0;
2770 if (logo_shown == vc->vc_num) { 2770 if (logo_shown == vc->vc_num) {
2771 unsigned long p, q; 2771 unsigned long p, q;
2772 int i; 2772 int i;
2773 2773
2774 p = softback_in; 2774 p = softback_in;
2775 q = vc->vc_origin + 2775 q = vc->vc_origin +
2776 logo_lines * vc->vc_size_row; 2776 logo_lines * vc->vc_size_row;
2777 for (i = 0; i < logo_lines; i++) { 2777 for (i = 0; i < logo_lines; i++) {
2778 if (p == softback_top) 2778 if (p == softback_top)
2779 break; 2779 break;
2780 if (p == softback_buf) 2780 if (p == softback_buf)
2781 p = softback_end; 2781 p = softback_end;
2782 p -= vc->vc_size_row; 2782 p -= vc->vc_size_row;
2783 q -= vc->vc_size_row; 2783 q -= vc->vc_size_row;
2784 scr_memcpyw((u16 *) q, (u16 *) p, 2784 scr_memcpyw((u16 *) q, (u16 *) p,
2785 vc->vc_size_row); 2785 vc->vc_size_row);
2786 } 2786 }
2787 softback_in = softback_curr = p; 2787 softback_in = softback_curr = p;
2788 update_region(vc, vc->vc_origin, 2788 update_region(vc, vc->vc_origin,
2789 logo_lines * vc->vc_cols); 2789 logo_lines * vc->vc_cols);
2790 } 2790 }
2791 logo_shown = FBCON_LOGO_CANSHOW; 2791 logo_shown = FBCON_LOGO_CANSHOW;
2792 } 2792 }
2793 fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK); 2793 fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK);
2794 fbcon_redraw_softback(vc, disp, lines); 2794 fbcon_redraw_softback(vc, disp, lines);
2795 fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK); 2795 fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK);
2796 return 0; 2796 return 0;
2797 } 2797 }
2798 2798
2799 if (!scrollback_phys_max) 2799 if (!scrollback_phys_max)
2800 return -ENOSYS; 2800 return -ENOSYS;
2801 2801
2802 scrollback_old = scrollback_current; 2802 scrollback_old = scrollback_current;
2803 scrollback_current -= lines; 2803 scrollback_current -= lines;
2804 if (scrollback_current < 0) 2804 if (scrollback_current < 0)
2805 scrollback_current = 0; 2805 scrollback_current = 0;
2806 else if (scrollback_current > scrollback_max) 2806 else if (scrollback_current > scrollback_max)
2807 scrollback_current = scrollback_max; 2807 scrollback_current = scrollback_max;
2808 if (scrollback_current == scrollback_old) 2808 if (scrollback_current == scrollback_old)
2809 return 0; 2809 return 0;
2810 2810
2811 if (fbcon_is_inactive(vc, info)) 2811 if (fbcon_is_inactive(vc, info))
2812 return 0; 2812 return 0;
2813 2813
2814 fbcon_cursor(vc, CM_ERASE); 2814 fbcon_cursor(vc, CM_ERASE);
2815 2815
2816 offset = disp->yscroll - scrollback_current; 2816 offset = disp->yscroll - scrollback_current;
2817 limit = disp->vrows; 2817 limit = disp->vrows;
2818 switch (disp->scrollmode) { 2818 switch (disp->scrollmode) {
2819 case SCROLL_WRAP_MOVE: 2819 case SCROLL_WRAP_MOVE:
2820 info->var.vmode |= FB_VMODE_YWRAP; 2820 info->var.vmode |= FB_VMODE_YWRAP;
2821 break; 2821 break;
2822 case SCROLL_PAN_MOVE: 2822 case SCROLL_PAN_MOVE:
2823 case SCROLL_PAN_REDRAW: 2823 case SCROLL_PAN_REDRAW:
2824 limit -= vc->vc_rows; 2824 limit -= vc->vc_rows;
2825 info->var.vmode &= ~FB_VMODE_YWRAP; 2825 info->var.vmode &= ~FB_VMODE_YWRAP;
2826 break; 2826 break;
2827 } 2827 }
2828 if (offset < 0) 2828 if (offset < 0)
2829 offset += limit; 2829 offset += limit;
2830 else if (offset >= limit) 2830 else if (offset >= limit)
2831 offset -= limit; 2831 offset -= limit;
2832 2832
2833 ops->var.xoffset = 0; 2833 ops->var.xoffset = 0;
2834 ops->var.yoffset = offset * vc->vc_font.height; 2834 ops->var.yoffset = offset * vc->vc_font.height;
2835 ops->update_start(info); 2835 ops->update_start(info);
2836 2836
2837 if (!scrollback_current) 2837 if (!scrollback_current)
2838 fbcon_cursor(vc, CM_DRAW); 2838 fbcon_cursor(vc, CM_DRAW);
2839 return 0; 2839 return 0;
2840 } 2840 }
2841 2841
2842 static int fbcon_set_origin(struct vc_data *vc) 2842 static int fbcon_set_origin(struct vc_data *vc)
2843 { 2843 {
2844 if (softback_lines) 2844 if (softback_lines)
2845 fbcon_scrolldelta(vc, softback_lines); 2845 fbcon_scrolldelta(vc, softback_lines);
2846 return 0; 2846 return 0;
2847 } 2847 }
2848 2848
2849 static void fbcon_suspended(struct fb_info *info) 2849 static void fbcon_suspended(struct fb_info *info)
2850 { 2850 {
2851 struct vc_data *vc = NULL; 2851 struct vc_data *vc = NULL;
2852 struct fbcon_ops *ops = info->fbcon_par; 2852 struct fbcon_ops *ops = info->fbcon_par;
2853 2853
2854 if (!ops || ops->currcon < 0) 2854 if (!ops || ops->currcon < 0)
2855 return; 2855 return;
2856 vc = vc_cons[ops->currcon].d; 2856 vc = vc_cons[ops->currcon].d;
2857 2857
2858 /* Clear cursor, restore saved data */ 2858 /* Clear cursor, restore saved data */
2859 fbcon_cursor(vc, CM_ERASE); 2859 fbcon_cursor(vc, CM_ERASE);
2860 } 2860 }
2861 2861
2862 static void fbcon_resumed(struct fb_info *info) 2862 static void fbcon_resumed(struct fb_info *info)
2863 { 2863 {
2864 struct vc_data *vc; 2864 struct vc_data *vc;
2865 struct fbcon_ops *ops = info->fbcon_par; 2865 struct fbcon_ops *ops = info->fbcon_par;
2866 2866
2867 if (!ops || ops->currcon < 0) 2867 if (!ops || ops->currcon < 0)
2868 return; 2868 return;
2869 vc = vc_cons[ops->currcon].d; 2869 vc = vc_cons[ops->currcon].d;
2870 2870
2871 update_screen(vc); 2871 update_screen(vc);
2872 } 2872 }
2873 2873
2874 static void fbcon_modechanged(struct fb_info *info) 2874 static void fbcon_modechanged(struct fb_info *info)
2875 { 2875 {
2876 struct fbcon_ops *ops = info->fbcon_par; 2876 struct fbcon_ops *ops = info->fbcon_par;
2877 struct vc_data *vc; 2877 struct vc_data *vc;
2878 struct display *p; 2878 struct display *p;
2879 int rows, cols; 2879 int rows, cols;
2880 2880
2881 if (!ops || ops->currcon < 0) 2881 if (!ops || ops->currcon < 0)
2882 return; 2882 return;
2883 vc = vc_cons[ops->currcon].d; 2883 vc = vc_cons[ops->currcon].d;
2884 if (vc->vc_mode != KD_TEXT || 2884 if (vc->vc_mode != KD_TEXT ||
2885 registered_fb[con2fb_map[ops->currcon]] != info) 2885 registered_fb[con2fb_map[ops->currcon]] != info)
2886 return; 2886 return;
2887 2887
2888 p = &fb_display[vc->vc_num]; 2888 p = &fb_display[vc->vc_num];
2889 set_blitting_type(vc, info); 2889 set_blitting_type(vc, info);
2890 2890
2891 if (CON_IS_VISIBLE(vc)) { 2891 if (CON_IS_VISIBLE(vc)) {
2892 var_to_display(p, &info->var, info); 2892 var_to_display(p, &info->var, info);
2893 cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); 2893 cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
2894 rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); 2894 rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
2895 cols /= vc->vc_font.width; 2895 cols /= vc->vc_font.width;
2896 rows /= vc->vc_font.height; 2896 rows /= vc->vc_font.height;
2897 vc_resize(vc, cols, rows); 2897 vc_resize(vc, cols, rows);
2898 updatescrollmode(p, info, vc); 2898 updatescrollmode(p, info, vc);
2899 scrollback_max = 0; 2899 scrollback_max = 0;
2900 scrollback_current = 0; 2900 scrollback_current = 0;
2901 2901
2902 if (!fbcon_is_inactive(vc, info)) { 2902 if (!fbcon_is_inactive(vc, info)) {
2903 ops->var.xoffset = ops->var.yoffset = p->yscroll = 0; 2903 ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
2904 ops->update_start(info); 2904 ops->update_start(info);
2905 } 2905 }
2906 2906
2907 fbcon_set_palette(vc, color_table); 2907 fbcon_set_palette(vc, color_table);
2908 update_screen(vc); 2908 update_screen(vc);
2909 if (softback_buf) 2909 if (softback_buf)
2910 fbcon_update_softback(vc); 2910 fbcon_update_softback(vc);
2911 } 2911 }
2912 } 2912 }
2913 2913
2914 static void fbcon_set_all_vcs(struct fb_info *info) 2914 static void fbcon_set_all_vcs(struct fb_info *info)
2915 { 2915 {
2916 struct fbcon_ops *ops = info->fbcon_par; 2916 struct fbcon_ops *ops = info->fbcon_par;
2917 struct vc_data *vc; 2917 struct vc_data *vc;
2918 struct display *p; 2918 struct display *p;
2919 int i, rows, cols, fg = -1; 2919 int i, rows, cols, fg = -1;
2920 2920
2921 if (!ops || ops->currcon < 0) 2921 if (!ops || ops->currcon < 0)
2922 return; 2922 return;
2923 2923
2924 for (i = first_fb_vc; i <= last_fb_vc; i++) { 2924 for (i = first_fb_vc; i <= last_fb_vc; i++) {
2925 vc = vc_cons[i].d; 2925 vc = vc_cons[i].d;
2926 if (!vc || vc->vc_mode != KD_TEXT || 2926 if (!vc || vc->vc_mode != KD_TEXT ||
2927 registered_fb[con2fb_map[i]] != info) 2927 registered_fb[con2fb_map[i]] != info)
2928 continue; 2928 continue;
2929 2929
2930 if (CON_IS_VISIBLE(vc)) { 2930 if (CON_IS_VISIBLE(vc)) {
2931 fg = i; 2931 fg = i;
2932 continue; 2932 continue;
2933 } 2933 }
2934 2934
2935 p = &fb_display[vc->vc_num]; 2935 p = &fb_display[vc->vc_num];
2936 set_blitting_type(vc, info); 2936 set_blitting_type(vc, info);
2937 var_to_display(p, &info->var, info); 2937 var_to_display(p, &info->var, info);
2938 cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); 2938 cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
2939 rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); 2939 rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
2940 cols /= vc->vc_font.width; 2940 cols /= vc->vc_font.width;
2941 rows /= vc->vc_font.height; 2941 rows /= vc->vc_font.height;
2942 vc_resize(vc, cols, rows); 2942 vc_resize(vc, cols, rows);
2943 } 2943 }
2944 2944
2945 if (fg != -1) 2945 if (fg != -1)
2946 fbcon_modechanged(info); 2946 fbcon_modechanged(info);
2947 } 2947 }
2948 2948
2949 static int fbcon_mode_deleted(struct fb_info *info, 2949 static int fbcon_mode_deleted(struct fb_info *info,
2950 struct fb_videomode *mode) 2950 struct fb_videomode *mode)
2951 { 2951 {
2952 struct fb_info *fb_info; 2952 struct fb_info *fb_info;
2953 struct display *p; 2953 struct display *p;
2954 int i, j, found = 0; 2954 int i, j, found = 0;
2955 2955
2956 /* before deletion, ensure that mode is not in use */ 2956 /* before deletion, ensure that mode is not in use */
2957 for (i = first_fb_vc; i <= last_fb_vc; i++) { 2957 for (i = first_fb_vc; i <= last_fb_vc; i++) {
2958 j = con2fb_map[i]; 2958 j = con2fb_map[i];
2959 if (j == -1) 2959 if (j == -1)
2960 continue; 2960 continue;
2961 fb_info = registered_fb[j]; 2961 fb_info = registered_fb[j];
2962 if (fb_info != info) 2962 if (fb_info != info)
2963 continue; 2963 continue;
2964 p = &fb_display[i]; 2964 p = &fb_display[i];
2965 if (!p || !p->mode) 2965 if (!p || !p->mode)
2966 continue; 2966 continue;
2967 if (fb_mode_is_equal(p->mode, mode)) { 2967 if (fb_mode_is_equal(p->mode, mode)) {
2968 found = 1; 2968 found = 1;
2969 break; 2969 break;
2970 } 2970 }
2971 } 2971 }
2972 return found; 2972 return found;
2973 } 2973 }
2974 2974
2975 #ifdef CONFIG_VT_HW_CONSOLE_BINDING 2975 #ifdef CONFIG_VT_HW_CONSOLE_BINDING
2976 static int fbcon_unbind(void) 2976 static int fbcon_unbind(void)
2977 { 2977 {
2978 int ret; 2978 int ret;
2979 2979
2980 ret = unbind_con_driver(&fb_con, first_fb_vc, last_fb_vc, 2980 ret = unbind_con_driver(&fb_con, first_fb_vc, last_fb_vc,
2981 fbcon_is_default); 2981 fbcon_is_default);
2982 2982
2983 if (!ret) 2983 if (!ret)
2984 fbcon_has_console_bind = 0; 2984 fbcon_has_console_bind = 0;
2985 2985
2986 return ret; 2986 return ret;
2987 } 2987 }
2988 #else 2988 #else
2989 static inline int fbcon_unbind(void) 2989 static inline int fbcon_unbind(void)
2990 { 2990 {
2991 return -EINVAL; 2991 return -EINVAL;
2992 } 2992 }
2993 #endif /* CONFIG_VT_HW_CONSOLE_BINDING */ 2993 #endif /* CONFIG_VT_HW_CONSOLE_BINDING */
2994 2994
2995 static int fbcon_fb_unbind(int idx) 2995 static int fbcon_fb_unbind(int idx)
2996 { 2996 {
2997 int i, new_idx = -1, ret = 0; 2997 int i, new_idx = -1, ret = 0;
2998 2998
2999 if (!fbcon_has_console_bind) 2999 if (!fbcon_has_console_bind)
3000 return 0; 3000 return 0;
3001 3001
3002 for (i = first_fb_vc; i <= last_fb_vc; i++) { 3002 for (i = first_fb_vc; i <= last_fb_vc; i++) {
3003 if (con2fb_map[i] != idx && 3003 if (con2fb_map[i] != idx &&
3004 con2fb_map[i] != -1) { 3004 con2fb_map[i] != -1) {
3005 new_idx = i; 3005 new_idx = i;
3006 break; 3006 break;
3007 } 3007 }
3008 } 3008 }
3009 3009
3010 if (new_idx != -1) { 3010 if (new_idx != -1) {
3011 for (i = first_fb_vc; i <= last_fb_vc; i++) { 3011 for (i = first_fb_vc; i <= last_fb_vc; i++) {
3012 if (con2fb_map[i] == idx) 3012 if (con2fb_map[i] == idx)
3013 set_con2fb_map(i, new_idx, 0); 3013 set_con2fb_map(i, new_idx, 0);
3014 } 3014 }
3015 } else 3015 } else
3016 ret = fbcon_unbind(); 3016 ret = fbcon_unbind();
3017 3017
3018 return ret; 3018 return ret;
3019 } 3019 }
3020 3020
3021 static int fbcon_fb_unregistered(struct fb_info *info) 3021 static int fbcon_fb_unregistered(struct fb_info *info)
3022 { 3022 {
3023 int i, idx; 3023 int i, idx;
3024 3024
3025 idx = info->node; 3025 idx = info->node;
3026 for (i = first_fb_vc; i <= last_fb_vc; i++) { 3026 for (i = first_fb_vc; i <= last_fb_vc; i++) {
3027 if (con2fb_map[i] == idx) 3027 if (con2fb_map[i] == idx)
3028 con2fb_map[i] = -1; 3028 con2fb_map[i] = -1;
3029 } 3029 }
3030 3030
3031 if (idx == info_idx) { 3031 if (idx == info_idx) {
3032 info_idx = -1; 3032 info_idx = -1;
3033 3033
3034 for (i = 0; i < FB_MAX; i++) { 3034 for (i = 0; i < FB_MAX; i++) {
3035 if (registered_fb[i] != NULL) { 3035 if (registered_fb[i] != NULL) {
3036 info_idx = i; 3036 info_idx = i;
3037 break; 3037 break;
3038 } 3038 }
3039 } 3039 }
3040 } 3040 }
3041 3041
3042 if (info_idx != -1) { 3042 if (info_idx != -1) {
3043 for (i = first_fb_vc; i <= last_fb_vc; i++) { 3043 for (i = first_fb_vc; i <= last_fb_vc; i++) {
3044 if (con2fb_map[i] == -1) 3044 if (con2fb_map[i] == -1)
3045 con2fb_map[i] = info_idx; 3045 con2fb_map[i] = info_idx;
3046 } 3046 }
3047 } 3047 }
3048 3048
3049 if (primary_device == idx) 3049 if (primary_device == idx)
3050 primary_device = -1; 3050 primary_device = -1;
3051 3051
3052 if (!num_registered_fb) 3052 if (!num_registered_fb)
3053 unregister_con_driver(&fb_con); 3053 unregister_con_driver(&fb_con);
3054 3054
3055 return 0; 3055 return 0;
3056 } 3056 }
3057 3057
3058 static void fbcon_remap_all(int idx) 3058 static void fbcon_remap_all(int idx)
3059 { 3059 {
3060 int i; 3060 int i;
3061 for (i = first_fb_vc; i <= last_fb_vc; i++) 3061 for (i = first_fb_vc; i <= last_fb_vc; i++)
3062 set_con2fb_map(i, idx, 0); 3062 set_con2fb_map(i, idx, 0);
3063 3063
3064 if (con_is_bound(&fb_con)) { 3064 if (con_is_bound(&fb_con)) {
3065 printk(KERN_INFO "fbcon: Remapping primary device, " 3065 printk(KERN_INFO "fbcon: Remapping primary device, "
3066 "fb%i, to tty %i-%i\n", idx, 3066 "fb%i, to tty %i-%i\n", idx,
3067 first_fb_vc + 1, last_fb_vc + 1); 3067 first_fb_vc + 1, last_fb_vc + 1);
3068 info_idx = idx; 3068 info_idx = idx;
3069 } 3069 }
3070 } 3070 }
3071 3071
3072 #ifdef CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY 3072 #ifdef CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
3073 static void fbcon_select_primary(struct fb_info *info) 3073 static void fbcon_select_primary(struct fb_info *info)
3074 { 3074 {
3075 if (!map_override && primary_device == -1 && 3075 if (!map_override && primary_device == -1 &&
3076 fb_is_primary_device(info)) { 3076 fb_is_primary_device(info)) {
3077 int i; 3077 int i;
3078 3078
3079 printk(KERN_INFO "fbcon: %s (fb%i) is primary device\n", 3079 printk(KERN_INFO "fbcon: %s (fb%i) is primary device\n",
3080 info->fix.id, info->node); 3080 info->fix.id, info->node);
3081 primary_device = info->node; 3081 primary_device = info->node;
3082 3082
3083 for (i = first_fb_vc; i <= last_fb_vc; i++) 3083 for (i = first_fb_vc; i <= last_fb_vc; i++)
3084 con2fb_map_boot[i] = primary_device; 3084 con2fb_map_boot[i] = primary_device;
3085 3085
3086 if (con_is_bound(&fb_con)) { 3086 if (con_is_bound(&fb_con)) {
3087 printk(KERN_INFO "fbcon: Remapping primary device, " 3087 printk(KERN_INFO "fbcon: Remapping primary device, "
3088 "fb%i, to tty %i-%i\n", info->node, 3088 "fb%i, to tty %i-%i\n", info->node,
3089 first_fb_vc + 1, last_fb_vc + 1); 3089 first_fb_vc + 1, last_fb_vc + 1);
3090 info_idx = primary_device; 3090 info_idx = primary_device;
3091 } 3091 }
3092 } 3092 }
3093 3093
3094 } 3094 }
3095 #else 3095 #else
3096 static inline void fbcon_select_primary(struct fb_info *info) 3096 static inline void fbcon_select_primary(struct fb_info *info)
3097 { 3097 {
3098 return; 3098 return;
3099 } 3099 }
3100 #endif /* CONFIG_FRAMEBUFFER_DETECT_PRIMARY */ 3100 #endif /* CONFIG_FRAMEBUFFER_DETECT_PRIMARY */
3101 3101
3102 static int fbcon_fb_registered(struct fb_info *info) 3102 static int fbcon_fb_registered(struct fb_info *info)
3103 { 3103 {
3104 int ret = 0, i, idx; 3104 int ret = 0, i, idx;
3105 3105
3106 idx = info->node; 3106 idx = info->node;
3107 fbcon_select_primary(info); 3107 fbcon_select_primary(info);
3108 3108
3109 if (info_idx == -1) { 3109 if (info_idx == -1) {
3110 for (i = first_fb_vc; i <= last_fb_vc; i++) { 3110 for (i = first_fb_vc; i <= last_fb_vc; i++) {
3111 if (con2fb_map_boot[i] == idx) { 3111 if (con2fb_map_boot[i] == idx) {
3112 info_idx = idx; 3112 info_idx = idx;
3113 break; 3113 break;
3114 } 3114 }
3115 } 3115 }
3116 3116
3117 if (info_idx != -1) 3117 if (info_idx != -1)
3118 ret = fbcon_takeover(1); 3118 ret = fbcon_takeover(1);
3119 } else { 3119 } else {
3120 for (i = first_fb_vc; i <= last_fb_vc; i++) { 3120 for (i = first_fb_vc; i <= last_fb_vc; i++) {
3121 if (con2fb_map_boot[i] == idx) 3121 if (con2fb_map_boot[i] == idx)
3122 set_con2fb_map(i, idx, 0); 3122 set_con2fb_map(i, idx, 0);
3123 } 3123 }
3124 } 3124 }
3125 3125
3126 return ret; 3126 return ret;
3127 } 3127 }
3128 3128
3129 static void fbcon_fb_blanked(struct fb_info *info, int blank) 3129 static void fbcon_fb_blanked(struct fb_info *info, int blank)
3130 { 3130 {
3131 struct fbcon_ops *ops = info->fbcon_par; 3131 struct fbcon_ops *ops = info->fbcon_par;
3132 struct vc_data *vc; 3132 struct vc_data *vc;
3133 3133
3134 if (!ops || ops->currcon < 0) 3134 if (!ops || ops->currcon < 0)
3135 return; 3135 return;
3136 3136
3137 vc = vc_cons[ops->currcon].d; 3137 vc = vc_cons[ops->currcon].d;
3138 if (vc->vc_mode != KD_TEXT || 3138 if (vc->vc_mode != KD_TEXT ||
3139 registered_fb[con2fb_map[ops->currcon]] != info) 3139 registered_fb[con2fb_map[ops->currcon]] != info)
3140 return; 3140 return;
3141 3141
3142 if (CON_IS_VISIBLE(vc)) { 3142 if (CON_IS_VISIBLE(vc)) {
3143 if (blank) 3143 if (blank)
3144 do_blank_screen(0); 3144 do_blank_screen(0);
3145 else 3145 else
3146 do_unblank_screen(0); 3146 do_unblank_screen(0);
3147 } 3147 }
3148 ops->blank_state = blank; 3148 ops->blank_state = blank;
3149 } 3149 }
3150 3150
3151 static void fbcon_new_modelist(struct fb_info *info) 3151 static void fbcon_new_modelist(struct fb_info *info)
3152 { 3152 {
3153 int i; 3153 int i;
3154 struct vc_data *vc; 3154 struct vc_data *vc;
3155 struct fb_var_screeninfo var; 3155 struct fb_var_screeninfo var;
3156 const struct fb_videomode *mode; 3156 const struct fb_videomode *mode;
3157 3157
3158 for (i = first_fb_vc; i <= last_fb_vc; i++) { 3158 for (i = first_fb_vc; i <= last_fb_vc; i++) {
3159 if (registered_fb[con2fb_map[i]] != info) 3159 if (registered_fb[con2fb_map[i]] != info)
3160 continue; 3160 continue;
3161 if (!fb_display[i].mode) 3161 if (!fb_display[i].mode)
3162 continue; 3162 continue;
3163 vc = vc_cons[i].d; 3163 vc = vc_cons[i].d;
3164 display_to_var(&var, &fb_display[i]); 3164 display_to_var(&var, &fb_display[i]);
3165 mode = fb_find_nearest_mode(fb_display[i].mode, 3165 mode = fb_find_nearest_mode(fb_display[i].mode,
3166 &info->modelist); 3166 &info->modelist);
3167 fb_videomode_to_var(&var, mode); 3167 fb_videomode_to_var(&var, mode);
3168 fbcon_set_disp(info, &var, vc->vc_num); 3168 fbcon_set_disp(info, &var, vc->vc_num);
3169 } 3169 }
3170 } 3170 }
3171 3171
3172 static void fbcon_get_requirement(struct fb_info *info, 3172 static void fbcon_get_requirement(struct fb_info *info,
3173 struct fb_blit_caps *caps) 3173 struct fb_blit_caps *caps)
3174 { 3174 {
3175 struct vc_data *vc; 3175 struct vc_data *vc;
3176 struct display *p; 3176 struct display *p;
3177 3177
3178 if (caps->flags) { 3178 if (caps->flags) {
3179 int i, charcnt; 3179 int i, charcnt;
3180 3180
3181 for (i = first_fb_vc; i <= last_fb_vc; i++) { 3181 for (i = first_fb_vc; i <= last_fb_vc; i++) {
3182 vc = vc_cons[i].d; 3182 vc = vc_cons[i].d;
3183 if (vc && vc->vc_mode == KD_TEXT && 3183 if (vc && vc->vc_mode == KD_TEXT &&
3184 info->node == con2fb_map[i]) { 3184 info->node == con2fb_map[i]) {
3185 p = &fb_display[i]; 3185 p = &fb_display[i];
3186 caps->x |= 1 << (vc->vc_font.width - 1); 3186 caps->x |= 1 << (vc->vc_font.width - 1);
3187 caps->y |= 1 << (vc->vc_font.height - 1); 3187 caps->y |= 1 << (vc->vc_font.height - 1);
3188 charcnt = (p->userfont) ? 3188 charcnt = (p->userfont) ?
3189 FNTCHARCNT(p->fontdata) : 256; 3189 FNTCHARCNT(p->fontdata) : 256;
3190 if (caps->len < charcnt) 3190 if (caps->len < charcnt)
3191 caps->len = charcnt; 3191 caps->len = charcnt;
3192 } 3192 }
3193 } 3193 }
3194 } else { 3194 } else {
3195 vc = vc_cons[fg_console].d; 3195 vc = vc_cons[fg_console].d;
3196 3196
3197 if (vc && vc->vc_mode == KD_TEXT && 3197 if (vc && vc->vc_mode == KD_TEXT &&
3198 info->node == con2fb_map[fg_console]) { 3198 info->node == con2fb_map[fg_console]) {
3199 p = &fb_display[fg_console]; 3199 p = &fb_display[fg_console];
3200 caps->x = 1 << (vc->vc_font.width - 1); 3200 caps->x = 1 << (vc->vc_font.width - 1);
3201 caps->y = 1 << (vc->vc_font.height - 1); 3201 caps->y = 1 << (vc->vc_font.height - 1);
3202 caps->len = (p->userfont) ? 3202 caps->len = (p->userfont) ?
3203 FNTCHARCNT(p->fontdata) : 256; 3203 FNTCHARCNT(p->fontdata) : 256;
3204 } 3204 }
3205 } 3205 }
3206 } 3206 }
3207 3207
3208 static int fbcon_event_notify(struct notifier_block *self, 3208 static int fbcon_event_notify(struct notifier_block *self,
3209 unsigned long action, void *data) 3209 unsigned long action, void *data)
3210 { 3210 {
3211 struct fb_event *event = data; 3211 struct fb_event *event = data;
3212 struct fb_info *info = event->info; 3212 struct fb_info *info = event->info;
3213 struct fb_videomode *mode; 3213 struct fb_videomode *mode;
3214 struct fb_con2fbmap *con2fb; 3214 struct fb_con2fbmap *con2fb;
3215 struct fb_blit_caps *caps; 3215 struct fb_blit_caps *caps;
3216 int idx, ret = 0; 3216 int idx, ret = 0;
3217 3217
3218 /* 3218 /*
3219 * ignore all events except driver registration and deregistration 3219 * ignore all events except driver registration and deregistration
3220 * if fbcon is not active 3220 * if fbcon is not active
3221 */ 3221 */
3222 if (fbcon_has_exited && !(action == FB_EVENT_FB_REGISTERED || 3222 if (fbcon_has_exited && !(action == FB_EVENT_FB_REGISTERED ||
3223 action == FB_EVENT_FB_UNREGISTERED)) 3223 action == FB_EVENT_FB_UNREGISTERED))
3224 goto done; 3224 goto done;
3225 3225
3226 switch(action) { 3226 switch(action) {
3227 case FB_EVENT_SUSPEND: 3227 case FB_EVENT_SUSPEND:
3228 fbcon_suspended(info); 3228 fbcon_suspended(info);
3229 break; 3229 break;
3230 case FB_EVENT_RESUME: 3230 case FB_EVENT_RESUME:
3231 fbcon_resumed(info); 3231 fbcon_resumed(info);
3232 break; 3232 break;
3233 case FB_EVENT_MODE_CHANGE: 3233 case FB_EVENT_MODE_CHANGE:
3234 fbcon_modechanged(info); 3234 fbcon_modechanged(info);
3235 break; 3235 break;
3236 case FB_EVENT_MODE_CHANGE_ALL: 3236 case FB_EVENT_MODE_CHANGE_ALL:
3237 fbcon_set_all_vcs(info); 3237 fbcon_set_all_vcs(info);
3238 break; 3238 break;
3239 case FB_EVENT_MODE_DELETE: 3239 case FB_EVENT_MODE_DELETE:
3240 mode = event->data; 3240 mode = event->data;
3241 ret = fbcon_mode_deleted(info, mode); 3241 ret = fbcon_mode_deleted(info, mode);
3242 break; 3242 break;
3243 case FB_EVENT_FB_UNBIND: 3243 case FB_EVENT_FB_UNBIND:
3244 idx = info->node; 3244 idx = info->node;
3245 ret = fbcon_fb_unbind(idx); 3245 ret = fbcon_fb_unbind(idx);
3246 break; 3246 break;
3247 case FB_EVENT_FB_REGISTERED: 3247 case FB_EVENT_FB_REGISTERED:
3248 ret = fbcon_fb_registered(info); 3248 ret = fbcon_fb_registered(info);
3249 break; 3249 break;
3250 case FB_EVENT_FB_UNREGISTERED: 3250 case FB_EVENT_FB_UNREGISTERED:
3251 ret = fbcon_fb_unregistered(info); 3251 ret = fbcon_fb_unregistered(info);
3252 break; 3252 break;
3253 case FB_EVENT_SET_CONSOLE_MAP: 3253 case FB_EVENT_SET_CONSOLE_MAP:
3254 con2fb = event->data; 3254 con2fb = event->data;
3255 ret = set_con2fb_map(con2fb->console - 1, 3255 ret = set_con2fb_map(con2fb->console - 1,
3256 con2fb->framebuffer, 1); 3256 con2fb->framebuffer, 1);
3257 break; 3257 break;
3258 case FB_EVENT_GET_CONSOLE_MAP: 3258 case FB_EVENT_GET_CONSOLE_MAP:
3259 con2fb = event->data; 3259 con2fb = event->data;
3260 con2fb->framebuffer = con2fb_map[con2fb->console - 1]; 3260 con2fb->framebuffer = con2fb_map[con2fb->console - 1];
3261 break; 3261 break;
3262 case FB_EVENT_BLANK: 3262 case FB_EVENT_BLANK:
3263 fbcon_fb_blanked(info, *(int *)event->data); 3263 fbcon_fb_blanked(info, *(int *)event->data);
3264 break; 3264 break;
3265 case FB_EVENT_NEW_MODELIST: 3265 case FB_EVENT_NEW_MODELIST:
3266 fbcon_new_modelist(info); 3266 fbcon_new_modelist(info);
3267 break; 3267 break;
3268 case FB_EVENT_GET_REQ: 3268 case FB_EVENT_GET_REQ:
3269 caps = event->data; 3269 caps = event->data;
3270 fbcon_get_requirement(info, caps); 3270 fbcon_get_requirement(info, caps);
3271 break; 3271 break;
3272 case FB_EVENT_REMAP_ALL_CONSOLE: 3272 case FB_EVENT_REMAP_ALL_CONSOLE:
3273 idx = info->node; 3273 idx = info->node;
3274 fbcon_remap_all(idx); 3274 fbcon_remap_all(idx);
3275 break; 3275 break;
3276 } 3276 }
3277 done: 3277 done:
3278 return ret; 3278 return ret;
3279 } 3279 }
3280 3280
3281 /* 3281 /*
3282 * The console `switch' structure for the frame buffer based console 3282 * The console `switch' structure for the frame buffer based console
3283 */ 3283 */
3284 3284
3285 static const struct consw fb_con = { 3285 static const struct consw fb_con = {
3286 .owner = THIS_MODULE, 3286 .owner = THIS_MODULE,
3287 .con_startup = fbcon_startup, 3287 .con_startup = fbcon_startup,
3288 .con_init = fbcon_init, 3288 .con_init = fbcon_init,
3289 .con_deinit = fbcon_deinit, 3289 .con_deinit = fbcon_deinit,
3290 .con_clear = fbcon_clear, 3290 .con_clear = fbcon_clear,
3291 .con_putc = fbcon_putc, 3291 .con_putc = fbcon_putc,
3292 .con_putcs = fbcon_putcs, 3292 .con_putcs = fbcon_putcs,
3293 .con_cursor = fbcon_cursor, 3293 .con_cursor = fbcon_cursor,
3294 .con_scroll = fbcon_scroll, 3294 .con_scroll = fbcon_scroll,
3295 .con_bmove = fbcon_bmove, 3295 .con_bmove = fbcon_bmove,
3296 .con_switch = fbcon_switch, 3296 .con_switch = fbcon_switch,
3297 .con_blank = fbcon_blank, 3297 .con_blank = fbcon_blank,
3298 .con_font_set = fbcon_set_font, 3298 .con_font_set = fbcon_set_font,
3299 .con_font_get = fbcon_get_font, 3299 .con_font_get = fbcon_get_font,
3300 .con_font_default = fbcon_set_def_font, 3300 .con_font_default = fbcon_set_def_font,
3301 .con_font_copy = fbcon_copy_font, 3301 .con_font_copy = fbcon_copy_font,
3302 .con_set_palette = fbcon_set_palette, 3302 .con_set_palette = fbcon_set_palette,
3303 .con_scrolldelta = fbcon_scrolldelta, 3303 .con_scrolldelta = fbcon_scrolldelta,
3304 .con_set_origin = fbcon_set_origin, 3304 .con_set_origin = fbcon_set_origin,
3305 .con_invert_region = fbcon_invert_region, 3305 .con_invert_region = fbcon_invert_region,
3306 .con_screen_pos = fbcon_screen_pos, 3306 .con_screen_pos = fbcon_screen_pos,
3307 .con_getxy = fbcon_getxy, 3307 .con_getxy = fbcon_getxy,
3308 .con_resize = fbcon_resize, 3308 .con_resize = fbcon_resize,
3309 .con_debug_enter = fbcon_debug_enter, 3309 .con_debug_enter = fbcon_debug_enter,
3310 .con_debug_leave = fbcon_debug_leave, 3310 .con_debug_leave = fbcon_debug_leave,
3311 }; 3311 };
3312 3312
3313 static struct notifier_block fbcon_event_notifier = { 3313 static struct notifier_block fbcon_event_notifier = {
3314 .notifier_call = fbcon_event_notify, 3314 .notifier_call = fbcon_event_notify,
3315 }; 3315 };
3316 3316
3317 static ssize_t store_rotate(struct device *device, 3317 static ssize_t store_rotate(struct device *device,
3318 struct device_attribute *attr, const char *buf, 3318 struct device_attribute *attr, const char *buf,
3319 size_t count) 3319 size_t count)
3320 { 3320 {
3321 struct fb_info *info; 3321 struct fb_info *info;
3322 int rotate, idx; 3322 int rotate, idx;
3323 char **last = NULL; 3323 char **last = NULL;
3324 3324
3325 if (fbcon_has_exited) 3325 if (fbcon_has_exited)
3326 return count; 3326 return count;
3327 3327
3328 console_lock(); 3328 console_lock();
3329 idx = con2fb_map[fg_console]; 3329 idx = con2fb_map[fg_console];
3330 3330
3331 if (idx == -1 || registered_fb[idx] == NULL) 3331 if (idx == -1 || registered_fb[idx] == NULL)
3332 goto err; 3332 goto err;
3333 3333
3334 info = registered_fb[idx]; 3334 info = registered_fb[idx];
3335 rotate = simple_strtoul(buf, last, 0); 3335 rotate = simple_strtoul(buf, last, 0);
3336 fbcon_rotate(info, rotate); 3336 fbcon_rotate(info, rotate);
3337 err: 3337 err:
3338 console_unlock(); 3338 console_unlock();
3339 return count; 3339 return count;
3340 } 3340 }
3341 3341
3342 static ssize_t store_rotate_all(struct device *device, 3342 static ssize_t store_rotate_all(struct device *device,
3343 struct device_attribute *attr,const char *buf, 3343 struct device_attribute *attr,const char *buf,
3344 size_t count) 3344 size_t count)
3345 { 3345 {
3346 struct fb_info *info; 3346 struct fb_info *info;
3347 int rotate, idx; 3347 int rotate, idx;
3348 char **last = NULL; 3348 char **last = NULL;
3349 3349
3350 if (fbcon_has_exited) 3350 if (fbcon_has_exited)
3351 return count; 3351 return count;
3352 3352
3353 console_lock(); 3353 console_lock();
3354 idx = con2fb_map[fg_console]; 3354 idx = con2fb_map[fg_console];
3355 3355
3356 if (idx == -1 || registered_fb[idx] == NULL) 3356 if (idx == -1 || registered_fb[idx] == NULL)
3357 goto err; 3357 goto err;
3358 3358
3359 info = registered_fb[idx]; 3359 info = registered_fb[idx];
3360 rotate = simple_strtoul(buf, last, 0); 3360 rotate = simple_strtoul(buf, last, 0);
3361 fbcon_rotate_all(info, rotate); 3361 fbcon_rotate_all(info, rotate);
3362 err: 3362 err:
3363 console_unlock(); 3363 console_unlock();
3364 return count; 3364 return count;
3365 } 3365 }
3366 3366
3367 static ssize_t show_rotate(struct device *device, 3367 static ssize_t show_rotate(struct device *device,
3368 struct device_attribute *attr,char *buf) 3368 struct device_attribute *attr,char *buf)
3369 { 3369 {
3370 struct fb_info *info; 3370 struct fb_info *info;
3371 int rotate = 0, idx; 3371 int rotate = 0, idx;
3372 3372
3373 if (fbcon_has_exited) 3373 if (fbcon_has_exited)
3374 return 0; 3374 return 0;
3375 3375
3376 console_lock(); 3376 console_lock();
3377 idx = con2fb_map[fg_console]; 3377 idx = con2fb_map[fg_console];
3378 3378
3379 if (idx == -1 || registered_fb[idx] == NULL) 3379 if (idx == -1 || registered_fb[idx] == NULL)
3380 goto err; 3380 goto err;
3381 3381
3382 info = registered_fb[idx]; 3382 info = registered_fb[idx];
3383 rotate = fbcon_get_rotate(info); 3383 rotate = fbcon_get_rotate(info);
3384 err: 3384 err:
3385 console_unlock(); 3385 console_unlock();
3386 return snprintf(buf, PAGE_SIZE, "%d\n", rotate); 3386 return snprintf(buf, PAGE_SIZE, "%d\n", rotate);
3387 } 3387 }
3388 3388
3389 static ssize_t show_cursor_blink(struct device *device, 3389 static ssize_t show_cursor_blink(struct device *device,
3390 struct device_attribute *attr, char *buf) 3390 struct device_attribute *attr, char *buf)
3391 { 3391 {
3392 struct fb_info *info; 3392 struct fb_info *info;
3393 struct fbcon_ops *ops; 3393 struct fbcon_ops *ops;
3394 int idx, blink = -1; 3394 int idx, blink = -1;
3395 3395
3396 if (fbcon_has_exited) 3396 if (fbcon_has_exited)
3397 return 0; 3397 return 0;
3398 3398
3399 console_lock(); 3399 console_lock();
3400 idx = con2fb_map[fg_console]; 3400 idx = con2fb_map[fg_console];
3401 3401
3402 if (idx == -1 || registered_fb[idx] == NULL) 3402 if (idx == -1 || registered_fb[idx] == NULL)
3403 goto err; 3403 goto err;
3404 3404
3405 info = registered_fb[idx]; 3405 info = registered_fb[idx];
3406 ops = info->fbcon_par; 3406 ops = info->fbcon_par;
3407 3407
3408 if (!ops) 3408 if (!ops)
3409 goto err; 3409 goto err;
3410 3410
3411 blink = (ops->flags & FBCON_FLAGS_CURSOR_TIMER) ? 1 : 0; 3411 blink = (ops->flags & FBCON_FLAGS_CURSOR_TIMER) ? 1 : 0;
3412 err: 3412 err:
3413 console_unlock(); 3413 console_unlock();
3414 return snprintf(buf, PAGE_SIZE, "%d\n", blink); 3414 return snprintf(buf, PAGE_SIZE, "%d\n", blink);
3415 } 3415 }
3416 3416
3417 static ssize_t store_cursor_blink(struct device *device, 3417 static ssize_t store_cursor_blink(struct device *device,
3418 struct device_attribute *attr, 3418 struct device_attribute *attr,
3419 const char *buf, size_t count) 3419 const char *buf, size_t count)
3420 { 3420 {
3421 struct fb_info *info; 3421 struct fb_info *info;
3422 int blink, idx; 3422 int blink, idx;
3423 char **last = NULL; 3423 char **last = NULL;
3424 3424
3425 if (fbcon_has_exited) 3425 if (fbcon_has_exited)
3426 return count; 3426 return count;
3427 3427
3428 console_lock(); 3428 console_lock();
3429 idx = con2fb_map[fg_console]; 3429 idx = con2fb_map[fg_console];
3430 3430
3431 if (idx == -1 || registered_fb[idx] == NULL) 3431 if (idx == -1 || registered_fb[idx] == NULL)
3432 goto err; 3432 goto err;
3433 3433
3434 info = registered_fb[idx]; 3434 info = registered_fb[idx];
3435 3435
3436 if (!info->fbcon_par) 3436 if (!info->fbcon_par)
3437 goto err; 3437 goto err;
3438 3438
3439 blink = simple_strtoul(buf, last, 0); 3439 blink = simple_strtoul(buf, last, 0);
3440 3440
3441 if (blink) { 3441 if (blink) {
3442 fbcon_cursor_noblink = 0; 3442 fbcon_cursor_noblink = 0;
3443 fbcon_add_cursor_timer(info); 3443 fbcon_add_cursor_timer(info);
3444 } else { 3444 } else {
3445 fbcon_cursor_noblink = 1; 3445 fbcon_cursor_noblink = 1;
3446 fbcon_del_cursor_timer(info); 3446 fbcon_del_cursor_timer(info);
3447 } 3447 }
3448 3448
3449 err: 3449 err:
3450 console_unlock(); 3450 console_unlock();
3451 return count; 3451 return count;
3452 } 3452 }
3453 3453
3454 static struct device_attribute device_attrs[] = { 3454 static struct device_attribute device_attrs[] = {
3455 __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate), 3455 __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate),
3456 __ATTR(rotate_all, S_IWUSR, NULL, store_rotate_all), 3456 __ATTR(rotate_all, S_IWUSR, NULL, store_rotate_all),
3457 __ATTR(cursor_blink, S_IRUGO|S_IWUSR, show_cursor_blink, 3457 __ATTR(cursor_blink, S_IRUGO|S_IWUSR, show_cursor_blink,
3458 store_cursor_blink), 3458 store_cursor_blink),
3459 }; 3459 };
3460 3460
3461 static int fbcon_init_device(void) 3461 static int fbcon_init_device(void)
3462 { 3462 {
3463 int i, error = 0; 3463 int i, error = 0;
3464 3464
3465 fbcon_has_sysfs = 1; 3465 fbcon_has_sysfs = 1;
3466 3466
3467 for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { 3467 for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
3468 error = device_create_file(fbcon_device, &device_attrs[i]); 3468 error = device_create_file(fbcon_device, &device_attrs[i]);
3469 3469
3470 if (error) 3470 if (error)
3471 break; 3471 break;
3472 } 3472 }
3473 3473
3474 if (error) { 3474 if (error) {
3475 while (--i >= 0) 3475 while (--i >= 0)
3476 device_remove_file(fbcon_device, &device_attrs[i]); 3476 device_remove_file(fbcon_device, &device_attrs[i]);
3477 3477
3478 fbcon_has_sysfs = 0; 3478 fbcon_has_sysfs = 0;
3479 } 3479 }
3480 3480
3481 return 0; 3481 return 0;
3482 } 3482 }
3483 3483
3484 static void fbcon_start(void) 3484 static void fbcon_start(void)
3485 { 3485 {
3486 if (num_registered_fb) { 3486 if (num_registered_fb) {
3487 int i; 3487 int i;
3488 3488
3489 console_lock(); 3489 console_lock();
3490 3490
3491 for (i = 0; i < FB_MAX; i++) { 3491 for (i = 0; i < FB_MAX; i++) {
3492 if (registered_fb[i] != NULL) { 3492 if (registered_fb[i] != NULL) {
3493 info_idx = i; 3493 info_idx = i;
3494 break; 3494 break;
3495 } 3495 }
3496 } 3496 }
3497 3497
3498 console_unlock(); 3498 console_unlock();
3499 fbcon_takeover(0); 3499 fbcon_takeover(0);
3500 } 3500 }
3501 } 3501 }
3502 3502
3503 static void fbcon_exit(void) 3503 static void fbcon_exit(void)
3504 { 3504 {
3505 struct fb_info *info; 3505 struct fb_info *info;
3506 int i, j, mapped; 3506 int i, j, mapped;
3507 3507
3508 if (fbcon_has_exited) 3508 if (fbcon_has_exited)
3509 return; 3509 return;
3510 3510
3511 kfree((void *)softback_buf); 3511 kfree((void *)softback_buf);
3512 softback_buf = 0UL; 3512 softback_buf = 0UL;
3513 3513
3514 for (i = 0; i < FB_MAX; i++) { 3514 for (i = 0; i < FB_MAX; i++) {
3515 int pending = 0; 3515 int pending = 0;
3516 3516
3517 mapped = 0; 3517 mapped = 0;
3518 info = registered_fb[i]; 3518 info = registered_fb[i];
3519 3519
3520 if (info == NULL) 3520 if (info == NULL)
3521 continue; 3521 continue;
3522 3522
3523 if (info->queue.func) 3523 if (info->queue.func)
3524 pending = cancel_work_sync(&info->queue); 3524 pending = cancel_work_sync(&info->queue);
3525 DPRINTK("fbcon: %s pending work\n", (pending ? "canceled" : 3525 DPRINTK("fbcon: %s pending work\n", (pending ? "canceled" :
3526 "no")); 3526 "no"));
3527 3527
3528 for (j = first_fb_vc; j <= last_fb_vc; j++) { 3528 for (j = first_fb_vc; j <= last_fb_vc; j++) {
3529 if (con2fb_map[j] == i) 3529 if (con2fb_map[j] == i)
3530 mapped = 1; 3530 mapped = 1;
3531 } 3531 }
3532 3532
3533 if (mapped) { 3533 if (mapped) {
3534 if (info->fbops->fb_release) 3534 if (info->fbops->fb_release)
3535 info->fbops->fb_release(info, 0); 3535 info->fbops->fb_release(info, 0);
3536 module_put(info->fbops->owner); 3536 module_put(info->fbops->owner);
3537 3537
3538 if (info->fbcon_par) { 3538 if (info->fbcon_par) {
3539 struct fbcon_ops *ops = info->fbcon_par; 3539 struct fbcon_ops *ops = info->fbcon_par;
3540 3540
3541 fbcon_del_cursor_timer(info); 3541 fbcon_del_cursor_timer(info);
3542 kfree(ops->cursor_src); 3542 kfree(ops->cursor_src);
3543 kfree(info->fbcon_par); 3543 kfree(info->fbcon_par);
3544 info->fbcon_par = NULL; 3544 info->fbcon_par = NULL;
3545 } 3545 }
3546 3546
3547 if (info->queue.func == fb_flashcursor) 3547 if (info->queue.func == fb_flashcursor)
3548 info->queue.func = NULL; 3548 info->queue.func = NULL;
3549 } 3549 }
3550 } 3550 }
3551 3551
3552 fbcon_has_exited = 1; 3552 fbcon_has_exited = 1;
3553 } 3553 }
3554 3554
3555 static int __init fb_console_init(void) 3555 static int __init fb_console_init(void)
3556 { 3556 {
3557 int i; 3557 int i;
3558 3558
3559 console_lock(); 3559 console_lock();
3560 fb_register_client(&fbcon_event_notifier); 3560 fb_register_client(&fbcon_event_notifier);
3561 fbcon_device = device_create(fb_class, NULL, MKDEV(0, 0), NULL, 3561 fbcon_device = device_create(fb_class, NULL, MKDEV(0, 0), NULL,
3562 "fbcon"); 3562 "fbcon");
3563 3563
3564 if (IS_ERR(fbcon_device)) { 3564 if (IS_ERR(fbcon_device)) {
3565 printk(KERN_WARNING "Unable to create device " 3565 printk(KERN_WARNING "Unable to create device "
3566 "for fbcon; errno = %ld\n", 3566 "for fbcon; errno = %ld\n",
3567 PTR_ERR(fbcon_device)); 3567 PTR_ERR(fbcon_device));
3568 fbcon_device = NULL; 3568 fbcon_device = NULL;
3569 } else 3569 } else
3570 fbcon_init_device(); 3570 fbcon_init_device();
3571 3571
3572 for (i = 0; i < MAX_NR_CONSOLES; i++) 3572 for (i = 0; i < MAX_NR_CONSOLES; i++)
3573 con2fb_map[i] = -1; 3573 con2fb_map[i] = -1;
3574 3574
3575 console_unlock(); 3575 console_unlock();
3576 fbcon_start(); 3576 fbcon_start();
3577 return 0; 3577 return 0;
3578 } 3578 }
3579 3579
3580 module_init(fb_console_init); 3580 module_init(fb_console_init);
3581 3581
3582 #ifdef MODULE 3582 #ifdef MODULE
3583 3583
3584 static void __exit fbcon_deinit_device(void) 3584 static void __exit fbcon_deinit_device(void)
3585 { 3585 {
3586 int i; 3586 int i;
3587 3587
3588 if (fbcon_has_sysfs) { 3588 if (fbcon_has_sysfs) {
3589 for (i = 0; i < ARRAY_SIZE(device_attrs); i++) 3589 for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
3590 device_remove_file(fbcon_device, &device_attrs[i]); 3590 device_remove_file(fbcon_device, &device_attrs[i]);
3591 3591
3592 fbcon_has_sysfs = 0; 3592 fbcon_has_sysfs = 0;
3593 } 3593 }
3594 } 3594 }
3595 3595
3596 static void __exit fb_console_exit(void) 3596 static void __exit fb_console_exit(void)
3597 { 3597 {
3598 console_lock(); 3598 console_lock();
3599 fb_unregister_client(&fbcon_event_notifier); 3599 fb_unregister_client(&fbcon_event_notifier);
3600 fbcon_deinit_device(); 3600 fbcon_deinit_device();
3601 device_destroy(fb_class, MKDEV(0, 0)); 3601 device_destroy(fb_class, MKDEV(0, 0));
3602 fbcon_exit(); 3602 fbcon_exit();
3603 console_unlock(); 3603 console_unlock();
3604 unregister_con_driver(&fb_con); 3604 unregister_con_driver(&fb_con);
3605 } 3605 }
3606 3606
3607 module_exit(fb_console_exit); 3607 module_exit(fb_console_exit);
3608 3608
3609 #endif 3609 #endif
3610 3610
3611 MODULE_LICENSE("GPL"); 3611 MODULE_LICENSE("GPL");
3612 3612
drivers/video/mb862xx/mb862xxfbdrv.c
1 /* 1 /*
2 * drivers/mb862xx/mb862xxfb.c 2 * drivers/mb862xx/mb862xxfb.c
3 * 3 *
4 * Fujitsu Carmine/Coral-P(A)/Lime framebuffer driver 4 * Fujitsu Carmine/Coral-P(A)/Lime framebuffer driver
5 * 5 *
6 * (C) 2008 Anatolij Gustschin <agust@denx.de> 6 * (C) 2008 Anatolij Gustschin <agust@denx.de>
7 * DENX Software Engineering 7 * DENX Software Engineering
8 * 8 *
9 * This program is free software; you can redistribute it and/or modify 9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as 10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation. 11 * published by the Free Software Foundation.
12 * 12 *
13 */ 13 */
14 14
15 #undef DEBUG 15 #undef DEBUG
16 16
17 #include <linux/fb.h> 17 #include <linux/fb.h>
18 #include <linux/delay.h> 18 #include <linux/delay.h>
19 #include <linux/uaccess.h> 19 #include <linux/uaccess.h>
20 #include <linux/module.h> 20 #include <linux/module.h>
21 #include <linux/init.h> 21 #include <linux/init.h>
22 #include <linux/interrupt.h> 22 #include <linux/interrupt.h>
23 #include <linux/pci.h> 23 #include <linux/pci.h>
24 #if defined(CONFIG_OF) 24 #if defined(CONFIG_OF)
25 #include <linux/of_platform.h> 25 #include <linux/of_platform.h>
26 #endif 26 #endif
27 #include "mb862xxfb.h" 27 #include "mb862xxfb.h"
28 #include "mb862xx_reg.h" 28 #include "mb862xx_reg.h"
29 29
30 #define NR_PALETTE 256 30 #define NR_PALETTE 256
31 #define MB862XX_MEM_SIZE 0x1000000 31 #define MB862XX_MEM_SIZE 0x1000000
32 #define CORALP_MEM_SIZE 0x2000000 32 #define CORALP_MEM_SIZE 0x2000000
33 #define CARMINE_MEM_SIZE 0x8000000 33 #define CARMINE_MEM_SIZE 0x8000000
34 #define DRV_NAME "mb862xxfb" 34 #define DRV_NAME "mb862xxfb"
35 35
36 #if defined(CONFIG_SOCRATES) 36 #if defined(CONFIG_SOCRATES)
37 static struct mb862xx_gc_mode socrates_gc_mode = { 37 static struct mb862xx_gc_mode socrates_gc_mode = {
38 /* Mode for Prime View PM070WL4 TFT LCD Panel */ 38 /* Mode for Prime View PM070WL4 TFT LCD Panel */
39 { "800x480", 45, 800, 480, 40000, 86, 42, 33, 10, 128, 2, 0, 0, 0 }, 39 { "800x480", 45, 800, 480, 40000, 86, 42, 33, 10, 128, 2, 0, 0, 0 },
40 /* 16 bits/pixel, 16MB, 133MHz, SDRAM memory mode value */ 40 /* 16 bits/pixel, 16MB, 133MHz, SDRAM memory mode value */
41 16, 0x1000000, GC_CCF_COT_133, 0x4157ba63 41 16, 0x1000000, GC_CCF_COT_133, 0x4157ba63
42 }; 42 };
43 #endif 43 #endif
44 44
45 /* Helpers */ 45 /* Helpers */
46 static inline int h_total(struct fb_var_screeninfo *var) 46 static inline int h_total(struct fb_var_screeninfo *var)
47 { 47 {
48 return var->xres + var->left_margin + 48 return var->xres + var->left_margin +
49 var->right_margin + var->hsync_len; 49 var->right_margin + var->hsync_len;
50 } 50 }
51 51
52 static inline int v_total(struct fb_var_screeninfo *var) 52 static inline int v_total(struct fb_var_screeninfo *var)
53 { 53 {
54 return var->yres + var->upper_margin + 54 return var->yres + var->upper_margin +
55 var->lower_margin + var->vsync_len; 55 var->lower_margin + var->vsync_len;
56 } 56 }
57 57
58 static inline int hsp(struct fb_var_screeninfo *var) 58 static inline int hsp(struct fb_var_screeninfo *var)
59 { 59 {
60 return var->xres + var->right_margin - 1; 60 return var->xres + var->right_margin - 1;
61 } 61 }
62 62
63 static inline int vsp(struct fb_var_screeninfo *var) 63 static inline int vsp(struct fb_var_screeninfo *var)
64 { 64 {
65 return var->yres + var->lower_margin - 1; 65 return var->yres + var->lower_margin - 1;
66 } 66 }
67 67
68 static inline int d_pitch(struct fb_var_screeninfo *var) 68 static inline int d_pitch(struct fb_var_screeninfo *var)
69 { 69 {
70 return var->xres * var->bits_per_pixel / 8; 70 return var->xres * var->bits_per_pixel / 8;
71 } 71 }
72 72
73 static inline unsigned int chan_to_field(unsigned int chan, 73 static inline unsigned int chan_to_field(unsigned int chan,
74 struct fb_bitfield *bf) 74 struct fb_bitfield *bf)
75 { 75 {
76 chan &= 0xffff; 76 chan &= 0xffff;
77 chan >>= 16 - bf->length; 77 chan >>= 16 - bf->length;
78 return chan << bf->offset; 78 return chan << bf->offset;
79 } 79 }
80 80
81 static int mb862xxfb_setcolreg(unsigned regno, 81 static int mb862xxfb_setcolreg(unsigned regno,
82 unsigned red, unsigned green, unsigned blue, 82 unsigned red, unsigned green, unsigned blue,
83 unsigned transp, struct fb_info *info) 83 unsigned transp, struct fb_info *info)
84 { 84 {
85 struct mb862xxfb_par *par = info->par; 85 struct mb862xxfb_par *par = info->par;
86 unsigned int val; 86 unsigned int val;
87 87
88 switch (info->fix.visual) { 88 switch (info->fix.visual) {
89 case FB_VISUAL_TRUECOLOR: 89 case FB_VISUAL_TRUECOLOR:
90 if (regno < 16) { 90 if (regno < 16) {
91 val = chan_to_field(red, &info->var.red); 91 val = chan_to_field(red, &info->var.red);
92 val |= chan_to_field(green, &info->var.green); 92 val |= chan_to_field(green, &info->var.green);
93 val |= chan_to_field(blue, &info->var.blue); 93 val |= chan_to_field(blue, &info->var.blue);
94 par->pseudo_palette[regno] = val; 94 par->pseudo_palette[regno] = val;
95 } 95 }
96 break; 96 break;
97 case FB_VISUAL_PSEUDOCOLOR: 97 case FB_VISUAL_PSEUDOCOLOR:
98 if (regno < 256) { 98 if (regno < 256) {
99 val = (red >> 8) << 16; 99 val = (red >> 8) << 16;
100 val |= (green >> 8) << 8; 100 val |= (green >> 8) << 8;
101 val |= blue >> 8; 101 val |= blue >> 8;
102 outreg(disp, GC_L0PAL0 + (regno * 4), val); 102 outreg(disp, GC_L0PAL0 + (regno * 4), val);
103 } 103 }
104 break; 104 break;
105 default: 105 default:
106 return 1; /* unsupported type */ 106 return 1; /* unsupported type */
107 } 107 }
108 return 0; 108 return 0;
109 } 109 }
110 110
111 static int mb862xxfb_check_var(struct fb_var_screeninfo *var, 111 static int mb862xxfb_check_var(struct fb_var_screeninfo *var,
112 struct fb_info *fbi) 112 struct fb_info *fbi)
113 { 113 {
114 unsigned long tmp; 114 unsigned long tmp;
115 115
116 if (fbi->dev) 116 if (fbi->dev)
117 dev_dbg(fbi->dev, "%s\n", __func__); 117 dev_dbg(fbi->dev, "%s\n", __func__);
118 118
119 /* check if these values fit into the registers */ 119 /* check if these values fit into the registers */
120 if (var->hsync_len > 255 || var->vsync_len > 255) 120 if (var->hsync_len > 255 || var->vsync_len > 255)
121 return -EINVAL; 121 return -EINVAL;
122 122
123 if ((var->xres + var->right_margin) >= 4096) 123 if ((var->xres + var->right_margin) >= 4096)
124 return -EINVAL; 124 return -EINVAL;
125 125
126 if ((var->yres + var->lower_margin) > 4096) 126 if ((var->yres + var->lower_margin) > 4096)
127 return -EINVAL; 127 return -EINVAL;
128 128
129 if (h_total(var) > 4096 || v_total(var) > 4096) 129 if (h_total(var) > 4096 || v_total(var) > 4096)
130 return -EINVAL; 130 return -EINVAL;
131 131
132 if (var->xres_virtual > 4096 || var->yres_virtual > 4096) 132 if (var->xres_virtual > 4096 || var->yres_virtual > 4096)
133 return -EINVAL; 133 return -EINVAL;
134 134
135 if (var->bits_per_pixel <= 8) 135 if (var->bits_per_pixel <= 8)
136 var->bits_per_pixel = 8; 136 var->bits_per_pixel = 8;
137 else if (var->bits_per_pixel <= 16) 137 else if (var->bits_per_pixel <= 16)
138 var->bits_per_pixel = 16; 138 var->bits_per_pixel = 16;
139 else if (var->bits_per_pixel <= 32) 139 else if (var->bits_per_pixel <= 32)
140 var->bits_per_pixel = 32; 140 var->bits_per_pixel = 32;
141 141
142 /* 142 /*
143 * can cope with 8,16 or 24/32bpp if resulting 143 * can cope with 8,16 or 24/32bpp if resulting
144 * pitch is divisible by 64 without remainder 144 * pitch is divisible by 64 without remainder
145 */ 145 */
146 if (d_pitch(&fbi->var) % GC_L0M_L0W_UNIT) { 146 if (d_pitch(&fbi->var) % GC_L0M_L0W_UNIT) {
147 int r; 147 int r;
148 148
149 var->bits_per_pixel = 0; 149 var->bits_per_pixel = 0;
150 do { 150 do {
151 var->bits_per_pixel += 8; 151 var->bits_per_pixel += 8;
152 r = d_pitch(&fbi->var) % GC_L0M_L0W_UNIT; 152 r = d_pitch(&fbi->var) % GC_L0M_L0W_UNIT;
153 } while (r && var->bits_per_pixel <= 32); 153 } while (r && var->bits_per_pixel <= 32);
154 154
155 if (d_pitch(&fbi->var) % GC_L0M_L0W_UNIT) 155 if (d_pitch(&fbi->var) % GC_L0M_L0W_UNIT)
156 return -EINVAL; 156 return -EINVAL;
157 } 157 }
158 158
159 /* line length is going to be 128 bit aligned */ 159 /* line length is going to be 128 bit aligned */
160 tmp = (var->xres * var->bits_per_pixel) / 8; 160 tmp = (var->xres * var->bits_per_pixel) / 8;
161 if ((tmp & 15) != 0) 161 if ((tmp & 15) != 0)
162 return -EINVAL; 162 return -EINVAL;
163 163
164 /* set r/g/b positions and validate bpp */ 164 /* set r/g/b positions and validate bpp */
165 switch (var->bits_per_pixel) { 165 switch (var->bits_per_pixel) {
166 case 8: 166 case 8:
167 var->red.length = var->bits_per_pixel; 167 var->red.length = var->bits_per_pixel;
168 var->green.length = var->bits_per_pixel; 168 var->green.length = var->bits_per_pixel;
169 var->blue.length = var->bits_per_pixel; 169 var->blue.length = var->bits_per_pixel;
170 var->red.offset = 0; 170 var->red.offset = 0;
171 var->green.offset = 0; 171 var->green.offset = 0;
172 var->blue.offset = 0; 172 var->blue.offset = 0;
173 var->transp.length = 0; 173 var->transp.length = 0;
174 break; 174 break;
175 case 16: 175 case 16:
176 var->red.length = 5; 176 var->red.length = 5;
177 var->green.length = 5; 177 var->green.length = 5;
178 var->blue.length = 5; 178 var->blue.length = 5;
179 var->red.offset = 10; 179 var->red.offset = 10;
180 var->green.offset = 5; 180 var->green.offset = 5;
181 var->blue.offset = 0; 181 var->blue.offset = 0;
182 var->transp.length = 0; 182 var->transp.length = 0;
183 break; 183 break;
184 case 24: 184 case 24:
185 case 32: 185 case 32:
186 var->transp.length = 8; 186 var->transp.length = 8;
187 var->red.length = 8; 187 var->red.length = 8;
188 var->green.length = 8; 188 var->green.length = 8;
189 var->blue.length = 8; 189 var->blue.length = 8;
190 var->transp.offset = 24; 190 var->transp.offset = 24;
191 var->red.offset = 16; 191 var->red.offset = 16;
192 var->green.offset = 8; 192 var->green.offset = 8;
193 var->blue.offset = 0; 193 var->blue.offset = 0;
194 break; 194 break;
195 default: 195 default:
196 return -EINVAL; 196 return -EINVAL;
197 } 197 }
198 return 0; 198 return 0;
199 } 199 }
200 200
201 /* 201 /*
202 * set display parameters 202 * set display parameters
203 */ 203 */
204 static int mb862xxfb_set_par(struct fb_info *fbi) 204 static int mb862xxfb_set_par(struct fb_info *fbi)
205 { 205 {
206 struct mb862xxfb_par *par = fbi->par; 206 struct mb862xxfb_par *par = fbi->par;
207 unsigned long reg, sc; 207 unsigned long reg, sc;
208 208
209 dev_dbg(par->dev, "%s\n", __func__); 209 dev_dbg(par->dev, "%s\n", __func__);
210 if (par->type == BT_CORALP) 210 if (par->type == BT_CORALP)
211 mb862xxfb_init_accel(fbi, fbi->var.xres); 211 mb862xxfb_init_accel(fbi, fbi->var.xres);
212 212
213 if (par->pre_init) 213 if (par->pre_init)
214 return 0; 214 return 0;
215 215
216 /* disp off */ 216 /* disp off */
217 reg = inreg(disp, GC_DCM1); 217 reg = inreg(disp, GC_DCM1);
218 reg &= ~GC_DCM01_DEN; 218 reg &= ~GC_DCM01_DEN;
219 outreg(disp, GC_DCM1, reg); 219 outreg(disp, GC_DCM1, reg);
220 220
221 /* set display reference clock div. */ 221 /* set display reference clock div. */
222 sc = par->refclk / (1000000 / fbi->var.pixclock) - 1; 222 sc = par->refclk / (1000000 / fbi->var.pixclock) - 1;
223 reg = inreg(disp, GC_DCM1); 223 reg = inreg(disp, GC_DCM1);
224 reg &= ~(GC_DCM01_CKS | GC_DCM01_RESV | GC_DCM01_SC); 224 reg &= ~(GC_DCM01_CKS | GC_DCM01_RESV | GC_DCM01_SC);
225 reg |= sc << 8; 225 reg |= sc << 8;
226 outreg(disp, GC_DCM1, reg); 226 outreg(disp, GC_DCM1, reg);
227 dev_dbg(par->dev, "SC 0x%lx\n", sc); 227 dev_dbg(par->dev, "SC 0x%lx\n", sc);
228 228
229 /* disp dimension, format */ 229 /* disp dimension, format */
230 reg = pack(d_pitch(&fbi->var) / GC_L0M_L0W_UNIT, 230 reg = pack(d_pitch(&fbi->var) / GC_L0M_L0W_UNIT,
231 (fbi->var.yres - 1)); 231 (fbi->var.yres - 1));
232 if (fbi->var.bits_per_pixel == 16) 232 if (fbi->var.bits_per_pixel == 16)
233 reg |= GC_L0M_L0C_16; 233 reg |= GC_L0M_L0C_16;
234 outreg(disp, GC_L0M, reg); 234 outreg(disp, GC_L0M, reg);
235 235
236 if (fbi->var.bits_per_pixel == 32) { 236 if (fbi->var.bits_per_pixel == 32) {
237 reg = inreg(disp, GC_L0EM); 237 reg = inreg(disp, GC_L0EM);
238 outreg(disp, GC_L0EM, reg | GC_L0EM_L0EC_24); 238 outreg(disp, GC_L0EM, reg | GC_L0EM_L0EC_24);
239 } 239 }
240 outreg(disp, GC_WY_WX, 0); 240 outreg(disp, GC_WY_WX, 0);
241 reg = pack(fbi->var.yres - 1, fbi->var.xres); 241 reg = pack(fbi->var.yres - 1, fbi->var.xres);
242 outreg(disp, GC_WH_WW, reg); 242 outreg(disp, GC_WH_WW, reg);
243 outreg(disp, GC_L0OA0, 0); 243 outreg(disp, GC_L0OA0, 0);
244 outreg(disp, GC_L0DA0, 0); 244 outreg(disp, GC_L0DA0, 0);
245 outreg(disp, GC_L0DY_L0DX, 0); 245 outreg(disp, GC_L0DY_L0DX, 0);
246 outreg(disp, GC_L0WY_L0WX, 0); 246 outreg(disp, GC_L0WY_L0WX, 0);
247 outreg(disp, GC_L0WH_L0WW, reg); 247 outreg(disp, GC_L0WH_L0WW, reg);
248 248
249 /* both HW-cursors off */ 249 /* both HW-cursors off */
250 reg = inreg(disp, GC_CPM_CUTC); 250 reg = inreg(disp, GC_CPM_CUTC);
251 reg &= ~(GC_CPM_CEN0 | GC_CPM_CEN1); 251 reg &= ~(GC_CPM_CEN0 | GC_CPM_CEN1);
252 outreg(disp, GC_CPM_CUTC, reg); 252 outreg(disp, GC_CPM_CUTC, reg);
253 253
254 /* timings */ 254 /* timings */
255 reg = pack(fbi->var.xres - 1, fbi->var.xres - 1); 255 reg = pack(fbi->var.xres - 1, fbi->var.xres - 1);
256 outreg(disp, GC_HDB_HDP, reg); 256 outreg(disp, GC_HDB_HDP, reg);
257 reg = pack((fbi->var.yres - 1), vsp(&fbi->var)); 257 reg = pack((fbi->var.yres - 1), vsp(&fbi->var));
258 outreg(disp, GC_VDP_VSP, reg); 258 outreg(disp, GC_VDP_VSP, reg);
259 reg = ((fbi->var.vsync_len - 1) << 24) | 259 reg = ((fbi->var.vsync_len - 1) << 24) |
260 pack((fbi->var.hsync_len - 1), hsp(&fbi->var)); 260 pack((fbi->var.hsync_len - 1), hsp(&fbi->var));
261 outreg(disp, GC_VSW_HSW_HSP, reg); 261 outreg(disp, GC_VSW_HSW_HSP, reg);
262 outreg(disp, GC_HTP, pack(h_total(&fbi->var) - 1, 0)); 262 outreg(disp, GC_HTP, pack(h_total(&fbi->var) - 1, 0));
263 outreg(disp, GC_VTR, pack(v_total(&fbi->var) - 1, 0)); 263 outreg(disp, GC_VTR, pack(v_total(&fbi->var) - 1, 0));
264 264
265 /* display on */ 265 /* display on */
266 reg = inreg(disp, GC_DCM1); 266 reg = inreg(disp, GC_DCM1);
267 reg |= GC_DCM01_DEN | GC_DCM01_L0E; 267 reg |= GC_DCM01_DEN | GC_DCM01_L0E;
268 reg &= ~GC_DCM01_ESY; 268 reg &= ~GC_DCM01_ESY;
269 outreg(disp, GC_DCM1, reg); 269 outreg(disp, GC_DCM1, reg);
270 return 0; 270 return 0;
271 } 271 }
272 272
273 static int mb862xxfb_pan(struct fb_var_screeninfo *var, 273 static int mb862xxfb_pan(struct fb_var_screeninfo *var,
274 struct fb_info *info) 274 struct fb_info *info)
275 { 275 {
276 struct mb862xxfb_par *par = info->par; 276 struct mb862xxfb_par *par = info->par;
277 unsigned long reg; 277 unsigned long reg;
278 278
279 reg = pack(var->yoffset, var->xoffset); 279 reg = pack(var->yoffset, var->xoffset);
280 outreg(disp, GC_L0WY_L0WX, reg); 280 outreg(disp, GC_L0WY_L0WX, reg);
281 281
282 reg = pack(info->var.yres_virtual, info->var.xres_virtual); 282 reg = pack(info->var.yres_virtual, info->var.xres_virtual);
283 outreg(disp, GC_L0WH_L0WW, reg); 283 outreg(disp, GC_L0WH_L0WW, reg);
284 return 0; 284 return 0;
285 } 285 }
286 286
287 static int mb862xxfb_blank(int mode, struct fb_info *fbi) 287 static int mb862xxfb_blank(int mode, struct fb_info *fbi)
288 { 288 {
289 struct mb862xxfb_par *par = fbi->par; 289 struct mb862xxfb_par *par = fbi->par;
290 unsigned long reg; 290 unsigned long reg;
291 291
292 dev_dbg(fbi->dev, "blank mode=%d\n", mode); 292 dev_dbg(fbi->dev, "blank mode=%d\n", mode);
293 293
294 switch (mode) { 294 switch (mode) {
295 case FB_BLANK_POWERDOWN: 295 case FB_BLANK_POWERDOWN:
296 reg = inreg(disp, GC_DCM1); 296 reg = inreg(disp, GC_DCM1);
297 reg &= ~GC_DCM01_DEN; 297 reg &= ~GC_DCM01_DEN;
298 outreg(disp, GC_DCM1, reg); 298 outreg(disp, GC_DCM1, reg);
299 break; 299 break;
300 case FB_BLANK_UNBLANK: 300 case FB_BLANK_UNBLANK:
301 reg = inreg(disp, GC_DCM1); 301 reg = inreg(disp, GC_DCM1);
302 reg |= GC_DCM01_DEN; 302 reg |= GC_DCM01_DEN;
303 outreg(disp, GC_DCM1, reg); 303 outreg(disp, GC_DCM1, reg);
304 break; 304 break;
305 case FB_BLANK_NORMAL: 305 case FB_BLANK_NORMAL:
306 case FB_BLANK_VSYNC_SUSPEND: 306 case FB_BLANK_VSYNC_SUSPEND:
307 case FB_BLANK_HSYNC_SUSPEND: 307 case FB_BLANK_HSYNC_SUSPEND:
308 default: 308 default:
309 return 1; 309 return 1;
310 } 310 }
311 return 0; 311 return 0;
312 } 312 }
313 313
314 static int mb862xxfb_ioctl(struct fb_info *fbi, unsigned int cmd, 314 static int mb862xxfb_ioctl(struct fb_info *fbi, unsigned int cmd,
315 unsigned long arg) 315 unsigned long arg)
316 { 316 {
317 struct mb862xxfb_par *par = fbi->par; 317 struct mb862xxfb_par *par = fbi->par;
318 struct mb862xx_l1_cfg *l1_cfg = &par->l1_cfg; 318 struct mb862xx_l1_cfg *l1_cfg = &par->l1_cfg;
319 void __user *argp = (void __user *)arg; 319 void __user *argp = (void __user *)arg;
320 int *enable; 320 int *enable;
321 u32 l1em = 0; 321 u32 l1em = 0;
322 322
323 switch (cmd) { 323 switch (cmd) {
324 case MB862XX_L1_GET_CFG: 324 case MB862XX_L1_GET_CFG:
325 if (copy_to_user(argp, l1_cfg, sizeof(*l1_cfg))) 325 if (copy_to_user(argp, l1_cfg, sizeof(*l1_cfg)))
326 return -EFAULT; 326 return -EFAULT;
327 break; 327 break;
328 case MB862XX_L1_SET_CFG: 328 case MB862XX_L1_SET_CFG:
329 if (copy_from_user(l1_cfg, argp, sizeof(*l1_cfg))) 329 if (copy_from_user(l1_cfg, argp, sizeof(*l1_cfg)))
330 return -EFAULT; 330 return -EFAULT;
331 if (l1_cfg->dh == 0 || l1_cfg->dw == 0)
332 return -EINVAL;
331 if ((l1_cfg->sw >= l1_cfg->dw) && (l1_cfg->sh >= l1_cfg->dh)) { 333 if ((l1_cfg->sw >= l1_cfg->dw) && (l1_cfg->sh >= l1_cfg->dh)) {
332 /* downscaling */ 334 /* downscaling */
333 outreg(cap, GC_CAP_CSC, 335 outreg(cap, GC_CAP_CSC,
334 pack((l1_cfg->sh << 11) / l1_cfg->dh, 336 pack((l1_cfg->sh << 11) / l1_cfg->dh,
335 (l1_cfg->sw << 11) / l1_cfg->dw)); 337 (l1_cfg->sw << 11) / l1_cfg->dw));
336 l1em = inreg(disp, GC_L1EM); 338 l1em = inreg(disp, GC_L1EM);
337 l1em &= ~GC_L1EM_DM; 339 l1em &= ~GC_L1EM_DM;
338 } else if ((l1_cfg->sw <= l1_cfg->dw) && 340 } else if ((l1_cfg->sw <= l1_cfg->dw) &&
339 (l1_cfg->sh <= l1_cfg->dh)) { 341 (l1_cfg->sh <= l1_cfg->dh)) {
340 /* upscaling */ 342 /* upscaling */
341 outreg(cap, GC_CAP_CSC, 343 outreg(cap, GC_CAP_CSC,
342 pack((l1_cfg->sh << 11) / l1_cfg->dh, 344 pack((l1_cfg->sh << 11) / l1_cfg->dh,
343 (l1_cfg->sw << 11) / l1_cfg->dw)); 345 (l1_cfg->sw << 11) / l1_cfg->dw));
344 outreg(cap, GC_CAP_CMSS, 346 outreg(cap, GC_CAP_CMSS,
345 pack(l1_cfg->sw >> 1, l1_cfg->sh)); 347 pack(l1_cfg->sw >> 1, l1_cfg->sh));
346 outreg(cap, GC_CAP_CMDS, 348 outreg(cap, GC_CAP_CMDS,
347 pack(l1_cfg->dw >> 1, l1_cfg->dh)); 349 pack(l1_cfg->dw >> 1, l1_cfg->dh));
348 l1em = inreg(disp, GC_L1EM); 350 l1em = inreg(disp, GC_L1EM);
349 l1em |= GC_L1EM_DM; 351 l1em |= GC_L1EM_DM;
350 } 352 }
351 353
352 if (l1_cfg->mirror) { 354 if (l1_cfg->mirror) {
353 outreg(cap, GC_CAP_CBM, 355 outreg(cap, GC_CAP_CBM,
354 inreg(cap, GC_CAP_CBM) | GC_CBM_HRV); 356 inreg(cap, GC_CAP_CBM) | GC_CBM_HRV);
355 l1em |= l1_cfg->dw * 2 - 8; 357 l1em |= l1_cfg->dw * 2 - 8;
356 } else { 358 } else {
357 outreg(cap, GC_CAP_CBM, 359 outreg(cap, GC_CAP_CBM,
358 inreg(cap, GC_CAP_CBM) & ~GC_CBM_HRV); 360 inreg(cap, GC_CAP_CBM) & ~GC_CBM_HRV);
359 l1em &= 0xffff0000; 361 l1em &= 0xffff0000;
360 } 362 }
361 outreg(disp, GC_L1EM, l1em); 363 outreg(disp, GC_L1EM, l1em);
362 break; 364 break;
363 case MB862XX_L1_ENABLE: 365 case MB862XX_L1_ENABLE:
364 enable = (int *)arg; 366 enable = (int *)arg;
365 if (*enable) { 367 if (*enable) {
366 outreg(disp, GC_L1DA, par->cap_buf); 368 outreg(disp, GC_L1DA, par->cap_buf);
367 outreg(cap, GC_CAP_IMG_START, 369 outreg(cap, GC_CAP_IMG_START,
368 pack(l1_cfg->sy >> 1, l1_cfg->sx)); 370 pack(l1_cfg->sy >> 1, l1_cfg->sx));
369 outreg(cap, GC_CAP_IMG_END, 371 outreg(cap, GC_CAP_IMG_END,
370 pack(l1_cfg->sh, l1_cfg->sw)); 372 pack(l1_cfg->sh, l1_cfg->sw));
371 outreg(disp, GC_L1M, GC_L1M_16 | GC_L1M_YC | GC_L1M_CS | 373 outreg(disp, GC_L1M, GC_L1M_16 | GC_L1M_YC | GC_L1M_CS |
372 (par->l1_stride << 16)); 374 (par->l1_stride << 16));
373 outreg(disp, GC_L1WY_L1WX, 375 outreg(disp, GC_L1WY_L1WX,
374 pack(l1_cfg->dy, l1_cfg->dx)); 376 pack(l1_cfg->dy, l1_cfg->dx));
375 outreg(disp, GC_L1WH_L1WW, 377 outreg(disp, GC_L1WH_L1WW,
376 pack(l1_cfg->dh - 1, l1_cfg->dw)); 378 pack(l1_cfg->dh - 1, l1_cfg->dw));
377 outreg(disp, GC_DLS, 1); 379 outreg(disp, GC_DLS, 1);
378 outreg(cap, GC_CAP_VCM, 380 outreg(cap, GC_CAP_VCM,
379 GC_VCM_VIE | GC_VCM_CM | GC_VCM_VS_PAL); 381 GC_VCM_VIE | GC_VCM_CM | GC_VCM_VS_PAL);
380 outreg(disp, GC_DCM1, inreg(disp, GC_DCM1) | 382 outreg(disp, GC_DCM1, inreg(disp, GC_DCM1) |
381 GC_DCM1_DEN | GC_DCM1_L1E); 383 GC_DCM1_DEN | GC_DCM1_L1E);
382 } else { 384 } else {
383 outreg(cap, GC_CAP_VCM, 385 outreg(cap, GC_CAP_VCM,
384 inreg(cap, GC_CAP_VCM) & ~GC_VCM_VIE); 386 inreg(cap, GC_CAP_VCM) & ~GC_VCM_VIE);
385 outreg(disp, GC_DCM1, 387 outreg(disp, GC_DCM1,
386 inreg(disp, GC_DCM1) & ~GC_DCM1_L1E); 388 inreg(disp, GC_DCM1) & ~GC_DCM1_L1E);
387 } 389 }
388 break; 390 break;
389 case MB862XX_L1_CAP_CTL: 391 case MB862XX_L1_CAP_CTL:
390 enable = (int *)arg; 392 enable = (int *)arg;
391 if (*enable) { 393 if (*enable) {
392 outreg(cap, GC_CAP_VCM, 394 outreg(cap, GC_CAP_VCM,
393 inreg(cap, GC_CAP_VCM) | GC_VCM_VIE); 395 inreg(cap, GC_CAP_VCM) | GC_VCM_VIE);
394 } else { 396 } else {
395 outreg(cap, GC_CAP_VCM, 397 outreg(cap, GC_CAP_VCM,
396 inreg(cap, GC_CAP_VCM) & ~GC_VCM_VIE); 398 inreg(cap, GC_CAP_VCM) & ~GC_VCM_VIE);
397 } 399 }
398 break; 400 break;
399 default: 401 default:
400 return -EINVAL; 402 return -EINVAL;
401 } 403 }
402 return 0; 404 return 0;
403 } 405 }
404 406
405 /* framebuffer ops */ 407 /* framebuffer ops */
406 static struct fb_ops mb862xxfb_ops = { 408 static struct fb_ops mb862xxfb_ops = {
407 .owner = THIS_MODULE, 409 .owner = THIS_MODULE,
408 .fb_check_var = mb862xxfb_check_var, 410 .fb_check_var = mb862xxfb_check_var,
409 .fb_set_par = mb862xxfb_set_par, 411 .fb_set_par = mb862xxfb_set_par,
410 .fb_setcolreg = mb862xxfb_setcolreg, 412 .fb_setcolreg = mb862xxfb_setcolreg,
411 .fb_blank = mb862xxfb_blank, 413 .fb_blank = mb862xxfb_blank,
412 .fb_pan_display = mb862xxfb_pan, 414 .fb_pan_display = mb862xxfb_pan,
413 .fb_fillrect = cfb_fillrect, 415 .fb_fillrect = cfb_fillrect,
414 .fb_copyarea = cfb_copyarea, 416 .fb_copyarea = cfb_copyarea,
415 .fb_imageblit = cfb_imageblit, 417 .fb_imageblit = cfb_imageblit,
416 .fb_ioctl = mb862xxfb_ioctl, 418 .fb_ioctl = mb862xxfb_ioctl,
417 }; 419 };
418 420
419 /* initialize fb_info data */ 421 /* initialize fb_info data */
420 static int mb862xxfb_init_fbinfo(struct fb_info *fbi) 422 static int mb862xxfb_init_fbinfo(struct fb_info *fbi)
421 { 423 {
422 struct mb862xxfb_par *par = fbi->par; 424 struct mb862xxfb_par *par = fbi->par;
423 struct mb862xx_gc_mode *mode = par->gc_mode; 425 struct mb862xx_gc_mode *mode = par->gc_mode;
424 unsigned long reg; 426 unsigned long reg;
425 int stride; 427 int stride;
426 428
427 fbi->fbops = &mb862xxfb_ops; 429 fbi->fbops = &mb862xxfb_ops;
428 fbi->pseudo_palette = par->pseudo_palette; 430 fbi->pseudo_palette = par->pseudo_palette;
429 fbi->screen_base = par->fb_base; 431 fbi->screen_base = par->fb_base;
430 fbi->screen_size = par->mapped_vram; 432 fbi->screen_size = par->mapped_vram;
431 433
432 strcpy(fbi->fix.id, DRV_NAME); 434 strcpy(fbi->fix.id, DRV_NAME);
433 fbi->fix.smem_start = (unsigned long)par->fb_base_phys; 435 fbi->fix.smem_start = (unsigned long)par->fb_base_phys;
434 fbi->fix.mmio_start = (unsigned long)par->mmio_base_phys; 436 fbi->fix.mmio_start = (unsigned long)par->mmio_base_phys;
435 fbi->fix.mmio_len = par->mmio_len; 437 fbi->fix.mmio_len = par->mmio_len;
436 fbi->fix.accel = FB_ACCEL_NONE; 438 fbi->fix.accel = FB_ACCEL_NONE;
437 fbi->fix.type = FB_TYPE_PACKED_PIXELS; 439 fbi->fix.type = FB_TYPE_PACKED_PIXELS;
438 fbi->fix.type_aux = 0; 440 fbi->fix.type_aux = 0;
439 fbi->fix.xpanstep = 1; 441 fbi->fix.xpanstep = 1;
440 fbi->fix.ypanstep = 1; 442 fbi->fix.ypanstep = 1;
441 fbi->fix.ywrapstep = 0; 443 fbi->fix.ywrapstep = 0;
442 444
443 reg = inreg(disp, GC_DCM1); 445 reg = inreg(disp, GC_DCM1);
444 if (reg & GC_DCM01_DEN && reg & GC_DCM01_L0E) { 446 if (reg & GC_DCM01_DEN && reg & GC_DCM01_L0E) {
445 /* get the disp mode from active display cfg */ 447 /* get the disp mode from active display cfg */
446 unsigned long sc = ((reg & GC_DCM01_SC) >> 8) + 1; 448 unsigned long sc = ((reg & GC_DCM01_SC) >> 8) + 1;
447 unsigned long hsp, vsp, ht, vt; 449 unsigned long hsp, vsp, ht, vt;
448 450
449 dev_dbg(par->dev, "using bootloader's disp. mode\n"); 451 dev_dbg(par->dev, "using bootloader's disp. mode\n");
450 fbi->var.pixclock = (sc * 1000000) / par->refclk; 452 fbi->var.pixclock = (sc * 1000000) / par->refclk;
451 fbi->var.xres = (inreg(disp, GC_HDB_HDP) & 0x0fff) + 1; 453 fbi->var.xres = (inreg(disp, GC_HDB_HDP) & 0x0fff) + 1;
452 reg = inreg(disp, GC_VDP_VSP); 454 reg = inreg(disp, GC_VDP_VSP);
453 fbi->var.yres = ((reg >> 16) & 0x0fff) + 1; 455 fbi->var.yres = ((reg >> 16) & 0x0fff) + 1;
454 vsp = (reg & 0x0fff) + 1; 456 vsp = (reg & 0x0fff) + 1;
455 fbi->var.xres_virtual = fbi->var.xres; 457 fbi->var.xres_virtual = fbi->var.xres;
456 fbi->var.yres_virtual = fbi->var.yres; 458 fbi->var.yres_virtual = fbi->var.yres;
457 reg = inreg(disp, GC_L0EM); 459 reg = inreg(disp, GC_L0EM);
458 if (reg & GC_L0EM_L0EC_24) { 460 if (reg & GC_L0EM_L0EC_24) {
459 fbi->var.bits_per_pixel = 32; 461 fbi->var.bits_per_pixel = 32;
460 } else { 462 } else {
461 reg = inreg(disp, GC_L0M); 463 reg = inreg(disp, GC_L0M);
462 if (reg & GC_L0M_L0C_16) 464 if (reg & GC_L0M_L0C_16)
463 fbi->var.bits_per_pixel = 16; 465 fbi->var.bits_per_pixel = 16;
464 else 466 else
465 fbi->var.bits_per_pixel = 8; 467 fbi->var.bits_per_pixel = 8;
466 } 468 }
467 reg = inreg(disp, GC_VSW_HSW_HSP); 469 reg = inreg(disp, GC_VSW_HSW_HSP);
468 fbi->var.hsync_len = ((reg & 0xff0000) >> 16) + 1; 470 fbi->var.hsync_len = ((reg & 0xff0000) >> 16) + 1;
469 fbi->var.vsync_len = ((reg & 0x3f000000) >> 24) + 1; 471 fbi->var.vsync_len = ((reg & 0x3f000000) >> 24) + 1;
470 hsp = (reg & 0xffff) + 1; 472 hsp = (reg & 0xffff) + 1;
471 ht = ((inreg(disp, GC_HTP) & 0xfff0000) >> 16) + 1; 473 ht = ((inreg(disp, GC_HTP) & 0xfff0000) >> 16) + 1;
472 fbi->var.right_margin = hsp - fbi->var.xres; 474 fbi->var.right_margin = hsp - fbi->var.xres;
473 fbi->var.left_margin = ht - hsp - fbi->var.hsync_len; 475 fbi->var.left_margin = ht - hsp - fbi->var.hsync_len;
474 vt = ((inreg(disp, GC_VTR) & 0xfff0000) >> 16) + 1; 476 vt = ((inreg(disp, GC_VTR) & 0xfff0000) >> 16) + 1;
475 fbi->var.lower_margin = vsp - fbi->var.yres; 477 fbi->var.lower_margin = vsp - fbi->var.yres;
476 fbi->var.upper_margin = vt - vsp - fbi->var.vsync_len; 478 fbi->var.upper_margin = vt - vsp - fbi->var.vsync_len;
477 } else if (mode) { 479 } else if (mode) {
478 dev_dbg(par->dev, "using supplied mode\n"); 480 dev_dbg(par->dev, "using supplied mode\n");
479 fb_videomode_to_var(&fbi->var, (struct fb_videomode *)mode); 481 fb_videomode_to_var(&fbi->var, (struct fb_videomode *)mode);
480 fbi->var.bits_per_pixel = mode->def_bpp ? mode->def_bpp : 8; 482 fbi->var.bits_per_pixel = mode->def_bpp ? mode->def_bpp : 8;
481 } else { 483 } else {
482 int ret; 484 int ret;
483 485
484 ret = fb_find_mode(&fbi->var, fbi, "640x480-16@60", 486 ret = fb_find_mode(&fbi->var, fbi, "640x480-16@60",
485 NULL, 0, NULL, 16); 487 NULL, 0, NULL, 16);
486 if (ret == 0 || ret == 4) { 488 if (ret == 0 || ret == 4) {
487 dev_err(par->dev, 489 dev_err(par->dev,
488 "failed to get initial mode\n"); 490 "failed to get initial mode\n");
489 return -EINVAL; 491 return -EINVAL;
490 } 492 }
491 } 493 }
492 494
493 fbi->var.xoffset = 0; 495 fbi->var.xoffset = 0;
494 fbi->var.yoffset = 0; 496 fbi->var.yoffset = 0;
495 fbi->var.grayscale = 0; 497 fbi->var.grayscale = 0;
496 fbi->var.nonstd = 0; 498 fbi->var.nonstd = 0;
497 fbi->var.height = -1; 499 fbi->var.height = -1;
498 fbi->var.width = -1; 500 fbi->var.width = -1;
499 fbi->var.accel_flags = 0; 501 fbi->var.accel_flags = 0;
500 fbi->var.vmode = FB_VMODE_NONINTERLACED; 502 fbi->var.vmode = FB_VMODE_NONINTERLACED;
501 fbi->var.activate = FB_ACTIVATE_NOW; 503 fbi->var.activate = FB_ACTIVATE_NOW;
502 fbi->flags = FBINFO_DEFAULT | 504 fbi->flags = FBINFO_DEFAULT |
503 #ifdef __BIG_ENDIAN 505 #ifdef __BIG_ENDIAN
504 FBINFO_FOREIGN_ENDIAN | 506 FBINFO_FOREIGN_ENDIAN |
505 #endif 507 #endif
506 FBINFO_HWACCEL_XPAN | 508 FBINFO_HWACCEL_XPAN |
507 FBINFO_HWACCEL_YPAN; 509 FBINFO_HWACCEL_YPAN;
508 510
509 /* check and possibly fix bpp */ 511 /* check and possibly fix bpp */
510 if ((fbi->fbops->fb_check_var)(&fbi->var, fbi)) 512 if ((fbi->fbops->fb_check_var)(&fbi->var, fbi))
511 dev_err(par->dev, "check_var() failed on initial setup?\n"); 513 dev_err(par->dev, "check_var() failed on initial setup?\n");
512 514
513 fbi->fix.visual = fbi->var.bits_per_pixel == 8 ? 515 fbi->fix.visual = fbi->var.bits_per_pixel == 8 ?
514 FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; 516 FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
515 fbi->fix.line_length = (fbi->var.xres_virtual * 517 fbi->fix.line_length = (fbi->var.xres_virtual *
516 fbi->var.bits_per_pixel) / 8; 518 fbi->var.bits_per_pixel) / 8;
517 fbi->fix.smem_len = fbi->fix.line_length * fbi->var.yres_virtual; 519 fbi->fix.smem_len = fbi->fix.line_length * fbi->var.yres_virtual;
518 520
519 /* 521 /*
520 * reserve space for capture buffers and two cursors 522 * reserve space for capture buffers and two cursors
521 * at the end of vram: 720x576 * 2 * 2.2 + 64x64 * 16. 523 * at the end of vram: 720x576 * 2 * 2.2 + 64x64 * 16.
522 */ 524 */
523 par->cap_buf = par->mapped_vram - 0x1bd800 - 0x10000; 525 par->cap_buf = par->mapped_vram - 0x1bd800 - 0x10000;
524 par->cap_len = 0x1bd800; 526 par->cap_len = 0x1bd800;
525 par->l1_cfg.sx = 0; 527 par->l1_cfg.sx = 0;
526 par->l1_cfg.sy = 0; 528 par->l1_cfg.sy = 0;
527 par->l1_cfg.sw = 720; 529 par->l1_cfg.sw = 720;
528 par->l1_cfg.sh = 576; 530 par->l1_cfg.sh = 576;
529 par->l1_cfg.dx = 0; 531 par->l1_cfg.dx = 0;
530 par->l1_cfg.dy = 0; 532 par->l1_cfg.dy = 0;
531 par->l1_cfg.dw = 720; 533 par->l1_cfg.dw = 720;
532 par->l1_cfg.dh = 576; 534 par->l1_cfg.dh = 576;
533 stride = par->l1_cfg.sw * (fbi->var.bits_per_pixel / 8); 535 stride = par->l1_cfg.sw * (fbi->var.bits_per_pixel / 8);
534 par->l1_stride = stride / 64 + ((stride % 64) ? 1 : 0); 536 par->l1_stride = stride / 64 + ((stride % 64) ? 1 : 0);
535 outreg(cap, GC_CAP_CBM, GC_CBM_OO | GC_CBM_CBST | 537 outreg(cap, GC_CAP_CBM, GC_CBM_OO | GC_CBM_CBST |
536 (par->l1_stride << 16)); 538 (par->l1_stride << 16));
537 outreg(cap, GC_CAP_CBOA, par->cap_buf); 539 outreg(cap, GC_CAP_CBOA, par->cap_buf);
538 outreg(cap, GC_CAP_CBLA, par->cap_buf + par->cap_len); 540 outreg(cap, GC_CAP_CBLA, par->cap_buf + par->cap_len);
539 return 0; 541 return 0;
540 } 542 }
541 543
542 /* 544 /*
543 * show some display controller and cursor registers 545 * show some display controller and cursor registers
544 */ 546 */
545 static ssize_t mb862xxfb_show_dispregs(struct device *dev, 547 static ssize_t mb862xxfb_show_dispregs(struct device *dev,
546 struct device_attribute *attr, char *buf) 548 struct device_attribute *attr, char *buf)
547 { 549 {
548 struct fb_info *fbi = dev_get_drvdata(dev); 550 struct fb_info *fbi = dev_get_drvdata(dev);
549 struct mb862xxfb_par *par = fbi->par; 551 struct mb862xxfb_par *par = fbi->par;
550 char *ptr = buf; 552 char *ptr = buf;
551 unsigned int reg; 553 unsigned int reg;
552 554
553 for (reg = GC_DCM0; reg <= GC_L0DY_L0DX; reg += 4) 555 for (reg = GC_DCM0; reg <= GC_L0DY_L0DX; reg += 4)
554 ptr += sprintf(ptr, "%08x = %08x\n", 556 ptr += sprintf(ptr, "%08x = %08x\n",
555 reg, inreg(disp, reg)); 557 reg, inreg(disp, reg));
556 558
557 for (reg = GC_CPM_CUTC; reg <= GC_CUY1_CUX1; reg += 4) 559 for (reg = GC_CPM_CUTC; reg <= GC_CUY1_CUX1; reg += 4)
558 ptr += sprintf(ptr, "%08x = %08x\n", 560 ptr += sprintf(ptr, "%08x = %08x\n",
559 reg, inreg(disp, reg)); 561 reg, inreg(disp, reg));
560 562
561 for (reg = GC_DCM1; reg <= GC_L0WH_L0WW; reg += 4) 563 for (reg = GC_DCM1; reg <= GC_L0WH_L0WW; reg += 4)
562 ptr += sprintf(ptr, "%08x = %08x\n", 564 ptr += sprintf(ptr, "%08x = %08x\n",
563 reg, inreg(disp, reg)); 565 reg, inreg(disp, reg));
564 566
565 for (reg = 0x400; reg <= 0x410; reg += 4) 567 for (reg = 0x400; reg <= 0x410; reg += 4)
566 ptr += sprintf(ptr, "geo %08x = %08x\n", 568 ptr += sprintf(ptr, "geo %08x = %08x\n",
567 reg, inreg(geo, reg)); 569 reg, inreg(geo, reg));
568 570
569 for (reg = 0x400; reg <= 0x410; reg += 4) 571 for (reg = 0x400; reg <= 0x410; reg += 4)
570 ptr += sprintf(ptr, "draw %08x = %08x\n", 572 ptr += sprintf(ptr, "draw %08x = %08x\n",
571 reg, inreg(draw, reg)); 573 reg, inreg(draw, reg));
572 574
573 for (reg = 0x440; reg <= 0x450; reg += 4) 575 for (reg = 0x440; reg <= 0x450; reg += 4)
574 ptr += sprintf(ptr, "draw %08x = %08x\n", 576 ptr += sprintf(ptr, "draw %08x = %08x\n",
575 reg, inreg(draw, reg)); 577 reg, inreg(draw, reg));
576 578
577 return ptr - buf; 579 return ptr - buf;
578 } 580 }
579 581
580 static DEVICE_ATTR(dispregs, 0444, mb862xxfb_show_dispregs, NULL); 582 static DEVICE_ATTR(dispregs, 0444, mb862xxfb_show_dispregs, NULL);
581 583
582 static irqreturn_t mb862xx_intr(int irq, void *dev_id) 584 static irqreturn_t mb862xx_intr(int irq, void *dev_id)
583 { 585 {
584 struct mb862xxfb_par *par = (struct mb862xxfb_par *) dev_id; 586 struct mb862xxfb_par *par = (struct mb862xxfb_par *) dev_id;
585 unsigned long reg_ist, mask; 587 unsigned long reg_ist, mask;
586 588
587 if (!par) 589 if (!par)
588 return IRQ_NONE; 590 return IRQ_NONE;
589 591
590 if (par->type == BT_CARMINE) { 592 if (par->type == BT_CARMINE) {
591 /* Get Interrupt Status */ 593 /* Get Interrupt Status */
592 reg_ist = inreg(ctrl, GC_CTRL_STATUS); 594 reg_ist = inreg(ctrl, GC_CTRL_STATUS);
593 mask = inreg(ctrl, GC_CTRL_INT_MASK); 595 mask = inreg(ctrl, GC_CTRL_INT_MASK);
594 if (reg_ist == 0) 596 if (reg_ist == 0)
595 return IRQ_HANDLED; 597 return IRQ_HANDLED;
596 598
597 reg_ist &= mask; 599 reg_ist &= mask;
598 if (reg_ist == 0) 600 if (reg_ist == 0)
599 return IRQ_HANDLED; 601 return IRQ_HANDLED;
600 602
601 /* Clear interrupt status */ 603 /* Clear interrupt status */
602 outreg(ctrl, 0x0, reg_ist); 604 outreg(ctrl, 0x0, reg_ist);
603 } else { 605 } else {
604 /* Get status */ 606 /* Get status */
605 reg_ist = inreg(host, GC_IST); 607 reg_ist = inreg(host, GC_IST);
606 mask = inreg(host, GC_IMASK); 608 mask = inreg(host, GC_IMASK);
607 609
608 reg_ist &= mask; 610 reg_ist &= mask;
609 if (reg_ist == 0) 611 if (reg_ist == 0)
610 return IRQ_HANDLED; 612 return IRQ_HANDLED;
611 613
612 /* Clear status */ 614 /* Clear status */
613 outreg(host, GC_IST, ~reg_ist); 615 outreg(host, GC_IST, ~reg_ist);
614 } 616 }
615 return IRQ_HANDLED; 617 return IRQ_HANDLED;
616 } 618 }
617 619
618 #if defined(CONFIG_FB_MB862XX_LIME) 620 #if defined(CONFIG_FB_MB862XX_LIME)
619 /* 621 /*
620 * GDC (Lime, Coral(B/Q), Mint, ...) on host bus 622 * GDC (Lime, Coral(B/Q), Mint, ...) on host bus
621 */ 623 */
622 static int mb862xx_gdc_init(struct mb862xxfb_par *par) 624 static int mb862xx_gdc_init(struct mb862xxfb_par *par)
623 { 625 {
624 unsigned long ccf, mmr; 626 unsigned long ccf, mmr;
625 unsigned long ver, rev; 627 unsigned long ver, rev;
626 628
627 if (!par) 629 if (!par)
628 return -ENODEV; 630 return -ENODEV;
629 631
630 #if defined(CONFIG_FB_PRE_INIT_FB) 632 #if defined(CONFIG_FB_PRE_INIT_FB)
631 par->pre_init = 1; 633 par->pre_init = 1;
632 #endif 634 #endif
633 par->host = par->mmio_base; 635 par->host = par->mmio_base;
634 par->i2c = par->mmio_base + MB862XX_I2C_BASE; 636 par->i2c = par->mmio_base + MB862XX_I2C_BASE;
635 par->disp = par->mmio_base + MB862XX_DISP_BASE; 637 par->disp = par->mmio_base + MB862XX_DISP_BASE;
636 par->cap = par->mmio_base + MB862XX_CAP_BASE; 638 par->cap = par->mmio_base + MB862XX_CAP_BASE;
637 par->draw = par->mmio_base + MB862XX_DRAW_BASE; 639 par->draw = par->mmio_base + MB862XX_DRAW_BASE;
638 par->geo = par->mmio_base + MB862XX_GEO_BASE; 640 par->geo = par->mmio_base + MB862XX_GEO_BASE;
639 par->pio = par->mmio_base + MB862XX_PIO_BASE; 641 par->pio = par->mmio_base + MB862XX_PIO_BASE;
640 642
641 par->refclk = GC_DISP_REFCLK_400; 643 par->refclk = GC_DISP_REFCLK_400;
642 644
643 ver = inreg(host, GC_CID); 645 ver = inreg(host, GC_CID);
644 rev = inreg(pio, GC_REVISION); 646 rev = inreg(pio, GC_REVISION);
645 if ((ver == 0x303) && (rev & 0xffffff00) == 0x20050100) { 647 if ((ver == 0x303) && (rev & 0xffffff00) == 0x20050100) {
646 dev_info(par->dev, "Fujitsu Lime v1.%d found\n", 648 dev_info(par->dev, "Fujitsu Lime v1.%d found\n",
647 (int)rev & 0xff); 649 (int)rev & 0xff);
648 par->type = BT_LIME; 650 par->type = BT_LIME;
649 ccf = par->gc_mode ? par->gc_mode->ccf : GC_CCF_COT_100; 651 ccf = par->gc_mode ? par->gc_mode->ccf : GC_CCF_COT_100;
650 mmr = par->gc_mode ? par->gc_mode->mmr : 0x414fb7f2; 652 mmr = par->gc_mode ? par->gc_mode->mmr : 0x414fb7f2;
651 } else { 653 } else {
652 dev_info(par->dev, "? GDC, CID/Rev.: 0x%lx/0x%lx \n", ver, rev); 654 dev_info(par->dev, "? GDC, CID/Rev.: 0x%lx/0x%lx \n", ver, rev);
653 return -ENODEV; 655 return -ENODEV;
654 } 656 }
655 657
656 if (!par->pre_init) { 658 if (!par->pre_init) {
657 outreg(host, GC_CCF, ccf); 659 outreg(host, GC_CCF, ccf);
658 udelay(200); 660 udelay(200);
659 outreg(host, GC_MMR, mmr); 661 outreg(host, GC_MMR, mmr);
660 udelay(10); 662 udelay(10);
661 } 663 }
662 664
663 /* interrupt status */ 665 /* interrupt status */
664 outreg(host, GC_IST, 0); 666 outreg(host, GC_IST, 0);
665 outreg(host, GC_IMASK, GC_INT_EN); 667 outreg(host, GC_IMASK, GC_INT_EN);
666 return 0; 668 return 0;
667 } 669 }
668 670
669 static int __devinit of_platform_mb862xx_probe(struct platform_device *ofdev) 671 static int __devinit of_platform_mb862xx_probe(struct platform_device *ofdev)
670 { 672 {
671 struct device_node *np = ofdev->dev.of_node; 673 struct device_node *np = ofdev->dev.of_node;
672 struct device *dev = &ofdev->dev; 674 struct device *dev = &ofdev->dev;
673 struct mb862xxfb_par *par; 675 struct mb862xxfb_par *par;
674 struct fb_info *info; 676 struct fb_info *info;
675 struct resource res; 677 struct resource res;
676 resource_size_t res_size; 678 resource_size_t res_size;
677 unsigned long ret = -ENODEV; 679 unsigned long ret = -ENODEV;
678 680
679 if (of_address_to_resource(np, 0, &res)) { 681 if (of_address_to_resource(np, 0, &res)) {
680 dev_err(dev, "Invalid address\n"); 682 dev_err(dev, "Invalid address\n");
681 return -ENXIO; 683 return -ENXIO;
682 } 684 }
683 685
684 info = framebuffer_alloc(sizeof(struct mb862xxfb_par), dev); 686 info = framebuffer_alloc(sizeof(struct mb862xxfb_par), dev);
685 if (info == NULL) { 687 if (info == NULL) {
686 dev_err(dev, "cannot allocate framebuffer\n"); 688 dev_err(dev, "cannot allocate framebuffer\n");
687 return -ENOMEM; 689 return -ENOMEM;
688 } 690 }
689 691
690 par = info->par; 692 par = info->par;
691 par->info = info; 693 par->info = info;
692 par->dev = dev; 694 par->dev = dev;
693 695
694 par->irq = irq_of_parse_and_map(np, 0); 696 par->irq = irq_of_parse_and_map(np, 0);
695 if (par->irq == NO_IRQ) { 697 if (par->irq == NO_IRQ) {
696 dev_err(dev, "failed to map irq\n"); 698 dev_err(dev, "failed to map irq\n");
697 ret = -ENODEV; 699 ret = -ENODEV;
698 goto fbrel; 700 goto fbrel;
699 } 701 }
700 702
701 res_size = resource_size(&res); 703 res_size = resource_size(&res);
702 par->res = request_mem_region(res.start, res_size, DRV_NAME); 704 par->res = request_mem_region(res.start, res_size, DRV_NAME);
703 if (par->res == NULL) { 705 if (par->res == NULL) {
704 dev_err(dev, "Cannot claim framebuffer/mmio\n"); 706 dev_err(dev, "Cannot claim framebuffer/mmio\n");
705 ret = -ENXIO; 707 ret = -ENXIO;
706 goto irqdisp; 708 goto irqdisp;
707 } 709 }
708 710
709 #if defined(CONFIG_SOCRATES) 711 #if defined(CONFIG_SOCRATES)
710 par->gc_mode = &socrates_gc_mode; 712 par->gc_mode = &socrates_gc_mode;
711 #endif 713 #endif
712 714
713 par->fb_base_phys = res.start; 715 par->fb_base_phys = res.start;
714 par->mmio_base_phys = res.start + MB862XX_MMIO_BASE; 716 par->mmio_base_phys = res.start + MB862XX_MMIO_BASE;
715 par->mmio_len = MB862XX_MMIO_SIZE; 717 par->mmio_len = MB862XX_MMIO_SIZE;
716 if (par->gc_mode) 718 if (par->gc_mode)
717 par->mapped_vram = par->gc_mode->max_vram; 719 par->mapped_vram = par->gc_mode->max_vram;
718 else 720 else
719 par->mapped_vram = MB862XX_MEM_SIZE; 721 par->mapped_vram = MB862XX_MEM_SIZE;
720 722
721 par->fb_base = ioremap(par->fb_base_phys, par->mapped_vram); 723 par->fb_base = ioremap(par->fb_base_phys, par->mapped_vram);
722 if (par->fb_base == NULL) { 724 if (par->fb_base == NULL) {
723 dev_err(dev, "Cannot map framebuffer\n"); 725 dev_err(dev, "Cannot map framebuffer\n");
724 goto rel_reg; 726 goto rel_reg;
725 } 727 }
726 728
727 par->mmio_base = ioremap(par->mmio_base_phys, par->mmio_len); 729 par->mmio_base = ioremap(par->mmio_base_phys, par->mmio_len);
728 if (par->mmio_base == NULL) { 730 if (par->mmio_base == NULL) {
729 dev_err(dev, "Cannot map registers\n"); 731 dev_err(dev, "Cannot map registers\n");
730 goto fb_unmap; 732 goto fb_unmap;
731 } 733 }
732 734
733 dev_dbg(dev, "fb phys 0x%llx 0x%lx\n", 735 dev_dbg(dev, "fb phys 0x%llx 0x%lx\n",
734 (u64)par->fb_base_phys, (ulong)par->mapped_vram); 736 (u64)par->fb_base_phys, (ulong)par->mapped_vram);
735 dev_dbg(dev, "mmio phys 0x%llx 0x%lx, (irq = %d)\n", 737 dev_dbg(dev, "mmio phys 0x%llx 0x%lx, (irq = %d)\n",
736 (u64)par->mmio_base_phys, (ulong)par->mmio_len, par->irq); 738 (u64)par->mmio_base_phys, (ulong)par->mmio_len, par->irq);
737 739
738 if (mb862xx_gdc_init(par)) 740 if (mb862xx_gdc_init(par))
739 goto io_unmap; 741 goto io_unmap;
740 742
741 if (request_irq(par->irq, mb862xx_intr, 0, 743 if (request_irq(par->irq, mb862xx_intr, 0,
742 DRV_NAME, (void *)par)) { 744 DRV_NAME, (void *)par)) {
743 dev_err(dev, "Cannot request irq\n"); 745 dev_err(dev, "Cannot request irq\n");
744 goto io_unmap; 746 goto io_unmap;
745 } 747 }
746 748
747 mb862xxfb_init_fbinfo(info); 749 mb862xxfb_init_fbinfo(info);
748 750
749 if (fb_alloc_cmap(&info->cmap, NR_PALETTE, 0) < 0) { 751 if (fb_alloc_cmap(&info->cmap, NR_PALETTE, 0) < 0) {
750 dev_err(dev, "Could not allocate cmap for fb_info.\n"); 752 dev_err(dev, "Could not allocate cmap for fb_info.\n");
751 goto free_irq; 753 goto free_irq;
752 } 754 }
753 755
754 if ((info->fbops->fb_set_par)(info)) 756 if ((info->fbops->fb_set_par)(info))
755 dev_err(dev, "set_var() failed on initial setup?\n"); 757 dev_err(dev, "set_var() failed on initial setup?\n");
756 758
757 if (register_framebuffer(info)) { 759 if (register_framebuffer(info)) {
758 dev_err(dev, "failed to register framebuffer\n"); 760 dev_err(dev, "failed to register framebuffer\n");
759 goto rel_cmap; 761 goto rel_cmap;
760 } 762 }
761 763
762 dev_set_drvdata(dev, info); 764 dev_set_drvdata(dev, info);
763 765
764 if (device_create_file(dev, &dev_attr_dispregs)) 766 if (device_create_file(dev, &dev_attr_dispregs))
765 dev_err(dev, "Can't create sysfs regdump file\n"); 767 dev_err(dev, "Can't create sysfs regdump file\n");
766 return 0; 768 return 0;
767 769
768 rel_cmap: 770 rel_cmap:
769 fb_dealloc_cmap(&info->cmap); 771 fb_dealloc_cmap(&info->cmap);
770 free_irq: 772 free_irq:
771 outreg(host, GC_IMASK, 0); 773 outreg(host, GC_IMASK, 0);
772 free_irq(par->irq, (void *)par); 774 free_irq(par->irq, (void *)par);
773 io_unmap: 775 io_unmap:
774 iounmap(par->mmio_base); 776 iounmap(par->mmio_base);
775 fb_unmap: 777 fb_unmap:
776 iounmap(par->fb_base); 778 iounmap(par->fb_base);
777 rel_reg: 779 rel_reg:
778 release_mem_region(res.start, res_size); 780 release_mem_region(res.start, res_size);
779 irqdisp: 781 irqdisp:
780 irq_dispose_mapping(par->irq); 782 irq_dispose_mapping(par->irq);
781 fbrel: 783 fbrel:
782 dev_set_drvdata(dev, NULL); 784 dev_set_drvdata(dev, NULL);
783 framebuffer_release(info); 785 framebuffer_release(info);
784 return ret; 786 return ret;
785 } 787 }
786 788
787 static int __devexit of_platform_mb862xx_remove(struct platform_device *ofdev) 789 static int __devexit of_platform_mb862xx_remove(struct platform_device *ofdev)
788 { 790 {
789 struct fb_info *fbi = dev_get_drvdata(&ofdev->dev); 791 struct fb_info *fbi = dev_get_drvdata(&ofdev->dev);
790 struct mb862xxfb_par *par = fbi->par; 792 struct mb862xxfb_par *par = fbi->par;
791 resource_size_t res_size = resource_size(par->res); 793 resource_size_t res_size = resource_size(par->res);
792 unsigned long reg; 794 unsigned long reg;
793 795
794 dev_dbg(fbi->dev, "%s release\n", fbi->fix.id); 796 dev_dbg(fbi->dev, "%s release\n", fbi->fix.id);
795 797
796 /* display off */ 798 /* display off */
797 reg = inreg(disp, GC_DCM1); 799 reg = inreg(disp, GC_DCM1);
798 reg &= ~(GC_DCM01_DEN | GC_DCM01_L0E); 800 reg &= ~(GC_DCM01_DEN | GC_DCM01_L0E);
799 outreg(disp, GC_DCM1, reg); 801 outreg(disp, GC_DCM1, reg);
800 802
801 /* disable interrupts */ 803 /* disable interrupts */
802 outreg(host, GC_IMASK, 0); 804 outreg(host, GC_IMASK, 0);
803 805
804 free_irq(par->irq, (void *)par); 806 free_irq(par->irq, (void *)par);
805 irq_dispose_mapping(par->irq); 807 irq_dispose_mapping(par->irq);
806 808
807 device_remove_file(&ofdev->dev, &dev_attr_dispregs); 809 device_remove_file(&ofdev->dev, &dev_attr_dispregs);
808 810
809 unregister_framebuffer(fbi); 811 unregister_framebuffer(fbi);
810 fb_dealloc_cmap(&fbi->cmap); 812 fb_dealloc_cmap(&fbi->cmap);
811 813
812 iounmap(par->mmio_base); 814 iounmap(par->mmio_base);
813 iounmap(par->fb_base); 815 iounmap(par->fb_base);
814 816
815 dev_set_drvdata(&ofdev->dev, NULL); 817 dev_set_drvdata(&ofdev->dev, NULL);
816 release_mem_region(par->res->start, res_size); 818 release_mem_region(par->res->start, res_size);
817 framebuffer_release(fbi); 819 framebuffer_release(fbi);
818 return 0; 820 return 0;
819 } 821 }
820 822
821 /* 823 /*
822 * common types 824 * common types
823 */ 825 */
824 static struct of_device_id __devinitdata of_platform_mb862xx_tbl[] = { 826 static struct of_device_id __devinitdata of_platform_mb862xx_tbl[] = {
825 { .compatible = "fujitsu,MB86276", }, 827 { .compatible = "fujitsu,MB86276", },
826 { .compatible = "fujitsu,lime", }, 828 { .compatible = "fujitsu,lime", },
827 { .compatible = "fujitsu,MB86277", }, 829 { .compatible = "fujitsu,MB86277", },
828 { .compatible = "fujitsu,mint", }, 830 { .compatible = "fujitsu,mint", },
829 { .compatible = "fujitsu,MB86293", }, 831 { .compatible = "fujitsu,MB86293", },
830 { .compatible = "fujitsu,MB86294", }, 832 { .compatible = "fujitsu,MB86294", },
831 { .compatible = "fujitsu,coral", }, 833 { .compatible = "fujitsu,coral", },
832 { /* end */ } 834 { /* end */ }
833 }; 835 };
834 836
835 static struct platform_driver of_platform_mb862xxfb_driver = { 837 static struct platform_driver of_platform_mb862xxfb_driver = {
836 .driver = { 838 .driver = {
837 .name = DRV_NAME, 839 .name = DRV_NAME,
838 .owner = THIS_MODULE, 840 .owner = THIS_MODULE,
839 .of_match_table = of_platform_mb862xx_tbl, 841 .of_match_table = of_platform_mb862xx_tbl,
840 }, 842 },
841 .probe = of_platform_mb862xx_probe, 843 .probe = of_platform_mb862xx_probe,
842 .remove = __devexit_p(of_platform_mb862xx_remove), 844 .remove = __devexit_p(of_platform_mb862xx_remove),
843 }; 845 };
844 #endif 846 #endif
845 847
846 #if defined(CONFIG_FB_MB862XX_PCI_GDC) 848 #if defined(CONFIG_FB_MB862XX_PCI_GDC)
847 static int coralp_init(struct mb862xxfb_par *par) 849 static int coralp_init(struct mb862xxfb_par *par)
848 { 850 {
849 int cn, ver; 851 int cn, ver;
850 852
851 par->host = par->mmio_base; 853 par->host = par->mmio_base;
852 par->i2c = par->mmio_base + MB862XX_I2C_BASE; 854 par->i2c = par->mmio_base + MB862XX_I2C_BASE;
853 par->disp = par->mmio_base + MB862XX_DISP_BASE; 855 par->disp = par->mmio_base + MB862XX_DISP_BASE;
854 par->cap = par->mmio_base + MB862XX_CAP_BASE; 856 par->cap = par->mmio_base + MB862XX_CAP_BASE;
855 par->draw = par->mmio_base + MB862XX_DRAW_BASE; 857 par->draw = par->mmio_base + MB862XX_DRAW_BASE;
856 par->geo = par->mmio_base + MB862XX_GEO_BASE; 858 par->geo = par->mmio_base + MB862XX_GEO_BASE;
857 par->pio = par->mmio_base + MB862XX_PIO_BASE; 859 par->pio = par->mmio_base + MB862XX_PIO_BASE;
858 860
859 par->refclk = GC_DISP_REFCLK_400; 861 par->refclk = GC_DISP_REFCLK_400;
860 862
861 if (par->mapped_vram >= 0x2000000) { 863 if (par->mapped_vram >= 0x2000000) {
862 /* relocate gdc registers space */ 864 /* relocate gdc registers space */
863 writel(1, par->fb_base + MB862XX_MMIO_BASE + GC_RSW); 865 writel(1, par->fb_base + MB862XX_MMIO_BASE + GC_RSW);
864 udelay(1); /* wait at least 20 bus cycles */ 866 udelay(1); /* wait at least 20 bus cycles */
865 } 867 }
866 868
867 ver = inreg(host, GC_CID); 869 ver = inreg(host, GC_CID);
868 cn = (ver & GC_CID_CNAME_MSK) >> 8; 870 cn = (ver & GC_CID_CNAME_MSK) >> 8;
869 ver = ver & GC_CID_VERSION_MSK; 871 ver = ver & GC_CID_VERSION_MSK;
870 if (cn == 3) { 872 if (cn == 3) {
871 unsigned long reg; 873 unsigned long reg;
872 874
873 dev_info(par->dev, "Fujitsu Coral-%s GDC Rev.%d found\n",\ 875 dev_info(par->dev, "Fujitsu Coral-%s GDC Rev.%d found\n",\
874 (ver == 6) ? "P" : (ver == 8) ? "PA" : "?", 876 (ver == 6) ? "P" : (ver == 8) ? "PA" : "?",
875 par->pdev->revision); 877 par->pdev->revision);
876 reg = inreg(disp, GC_DCM1); 878 reg = inreg(disp, GC_DCM1);
877 if (reg & GC_DCM01_DEN && reg & GC_DCM01_L0E) 879 if (reg & GC_DCM01_DEN && reg & GC_DCM01_L0E)
878 par->pre_init = 1; 880 par->pre_init = 1;
879 881
880 if (!par->pre_init) { 882 if (!par->pre_init) {
881 outreg(host, GC_CCF, GC_CCF_CGE_166 | GC_CCF_COT_133); 883 outreg(host, GC_CCF, GC_CCF_CGE_166 | GC_CCF_COT_133);
882 udelay(200); 884 udelay(200);
883 outreg(host, GC_MMR, GC_MMR_CORALP_EVB_VAL); 885 outreg(host, GC_MMR, GC_MMR_CORALP_EVB_VAL);
884 udelay(10); 886 udelay(10);
885 } 887 }
886 /* Clear interrupt status */ 888 /* Clear interrupt status */
887 outreg(host, GC_IST, 0); 889 outreg(host, GC_IST, 0);
888 } else { 890 } else {
889 return -ENODEV; 891 return -ENODEV;
890 } 892 }
891 893
892 mb862xx_i2c_init(par); 894 mb862xx_i2c_init(par);
893 return 0; 895 return 0;
894 } 896 }
895 897
896 static int init_dram_ctrl(struct mb862xxfb_par *par) 898 static int init_dram_ctrl(struct mb862xxfb_par *par)
897 { 899 {
898 unsigned long i = 0; 900 unsigned long i = 0;
899 901
900 /* 902 /*
901 * Set io mode first! Spec. says IC may be destroyed 903 * Set io mode first! Spec. says IC may be destroyed
902 * if not set to SSTL2/LVCMOS before init. 904 * if not set to SSTL2/LVCMOS before init.
903 */ 905 */
904 outreg(dram_ctrl, GC_DCTL_IOCONT1_IOCONT0, GC_EVB_DCTL_IOCONT1_IOCONT0); 906 outreg(dram_ctrl, GC_DCTL_IOCONT1_IOCONT0, GC_EVB_DCTL_IOCONT1_IOCONT0);
905 907
906 /* DRAM init */ 908 /* DRAM init */
907 outreg(dram_ctrl, GC_DCTL_MODE_ADD, GC_EVB_DCTL_MODE_ADD); 909 outreg(dram_ctrl, GC_DCTL_MODE_ADD, GC_EVB_DCTL_MODE_ADD);
908 outreg(dram_ctrl, GC_DCTL_SETTIME1_EMODE, GC_EVB_DCTL_SETTIME1_EMODE); 910 outreg(dram_ctrl, GC_DCTL_SETTIME1_EMODE, GC_EVB_DCTL_SETTIME1_EMODE);
909 outreg(dram_ctrl, GC_DCTL_REFRESH_SETTIME2, 911 outreg(dram_ctrl, GC_DCTL_REFRESH_SETTIME2,
910 GC_EVB_DCTL_REFRESH_SETTIME2); 912 GC_EVB_DCTL_REFRESH_SETTIME2);
911 outreg(dram_ctrl, GC_DCTL_RSV2_RSV1, GC_EVB_DCTL_RSV2_RSV1); 913 outreg(dram_ctrl, GC_DCTL_RSV2_RSV1, GC_EVB_DCTL_RSV2_RSV1);
912 outreg(dram_ctrl, GC_DCTL_DDRIF2_DDRIF1, GC_EVB_DCTL_DDRIF2_DDRIF1); 914 outreg(dram_ctrl, GC_DCTL_DDRIF2_DDRIF1, GC_EVB_DCTL_DDRIF2_DDRIF1);
913 outreg(dram_ctrl, GC_DCTL_RSV0_STATES, GC_EVB_DCTL_RSV0_STATES); 915 outreg(dram_ctrl, GC_DCTL_RSV0_STATES, GC_EVB_DCTL_RSV0_STATES);
914 916
915 /* DLL reset done? */ 917 /* DLL reset done? */
916 while ((inreg(dram_ctrl, GC_DCTL_RSV0_STATES) & GC_DCTL_STATES_MSK)) { 918 while ((inreg(dram_ctrl, GC_DCTL_RSV0_STATES) & GC_DCTL_STATES_MSK)) {
917 udelay(GC_DCTL_INIT_WAIT_INTERVAL); 919 udelay(GC_DCTL_INIT_WAIT_INTERVAL);
918 if (i++ > GC_DCTL_INIT_WAIT_CNT) { 920 if (i++ > GC_DCTL_INIT_WAIT_CNT) {
919 dev_err(par->dev, "VRAM init failed.\n"); 921 dev_err(par->dev, "VRAM init failed.\n");
920 return -EINVAL; 922 return -EINVAL;
921 } 923 }
922 } 924 }
923 outreg(dram_ctrl, GC_DCTL_MODE_ADD, GC_EVB_DCTL_MODE_ADD_AFT_RST); 925 outreg(dram_ctrl, GC_DCTL_MODE_ADD, GC_EVB_DCTL_MODE_ADD_AFT_RST);
924 outreg(dram_ctrl, GC_DCTL_RSV0_STATES, GC_EVB_DCTL_RSV0_STATES_AFT_RST); 926 outreg(dram_ctrl, GC_DCTL_RSV0_STATES, GC_EVB_DCTL_RSV0_STATES_AFT_RST);
925 return 0; 927 return 0;
926 } 928 }
927 929
928 static int carmine_init(struct mb862xxfb_par *par) 930 static int carmine_init(struct mb862xxfb_par *par)
929 { 931 {
930 unsigned long reg; 932 unsigned long reg;
931 933
932 par->ctrl = par->mmio_base + MB86297_CTRL_BASE; 934 par->ctrl = par->mmio_base + MB86297_CTRL_BASE;
933 par->i2c = par->mmio_base + MB86297_I2C_BASE; 935 par->i2c = par->mmio_base + MB86297_I2C_BASE;
934 par->disp = par->mmio_base + MB86297_DISP0_BASE; 936 par->disp = par->mmio_base + MB86297_DISP0_BASE;
935 par->disp1 = par->mmio_base + MB86297_DISP1_BASE; 937 par->disp1 = par->mmio_base + MB86297_DISP1_BASE;
936 par->cap = par->mmio_base + MB86297_CAP0_BASE; 938 par->cap = par->mmio_base + MB86297_CAP0_BASE;
937 par->cap1 = par->mmio_base + MB86297_CAP1_BASE; 939 par->cap1 = par->mmio_base + MB86297_CAP1_BASE;
938 par->draw = par->mmio_base + MB86297_DRAW_BASE; 940 par->draw = par->mmio_base + MB86297_DRAW_BASE;
939 par->dram_ctrl = par->mmio_base + MB86297_DRAMCTRL_BASE; 941 par->dram_ctrl = par->mmio_base + MB86297_DRAMCTRL_BASE;
940 par->wrback = par->mmio_base + MB86297_WRBACK_BASE; 942 par->wrback = par->mmio_base + MB86297_WRBACK_BASE;
941 943
942 par->refclk = GC_DISP_REFCLK_533; 944 par->refclk = GC_DISP_REFCLK_533;
943 945
944 /* warm up */ 946 /* warm up */
945 reg = GC_CTRL_CLK_EN_DRAM | GC_CTRL_CLK_EN_2D3D | GC_CTRL_CLK_EN_DISP0; 947 reg = GC_CTRL_CLK_EN_DRAM | GC_CTRL_CLK_EN_2D3D | GC_CTRL_CLK_EN_DISP0;
946 outreg(ctrl, GC_CTRL_CLK_ENABLE, reg); 948 outreg(ctrl, GC_CTRL_CLK_ENABLE, reg);
947 949
948 /* check for engine module revision */ 950 /* check for engine module revision */
949 if (inreg(draw, GC_2D3D_REV) == GC_RE_REVISION) 951 if (inreg(draw, GC_2D3D_REV) == GC_RE_REVISION)
950 dev_info(par->dev, "Fujitsu Carmine GDC Rev.%d found\n", 952 dev_info(par->dev, "Fujitsu Carmine GDC Rev.%d found\n",
951 par->pdev->revision); 953 par->pdev->revision);
952 else 954 else
953 goto err_init; 955 goto err_init;
954 956
955 reg &= ~GC_CTRL_CLK_EN_2D3D; 957 reg &= ~GC_CTRL_CLK_EN_2D3D;
956 outreg(ctrl, GC_CTRL_CLK_ENABLE, reg); 958 outreg(ctrl, GC_CTRL_CLK_ENABLE, reg);
957 959
958 /* set up vram */ 960 /* set up vram */
959 if (init_dram_ctrl(par) < 0) 961 if (init_dram_ctrl(par) < 0)
960 goto err_init; 962 goto err_init;
961 963
962 outreg(ctrl, GC_CTRL_INT_MASK, 0); 964 outreg(ctrl, GC_CTRL_INT_MASK, 0);
963 return 0; 965 return 0;
964 966
965 err_init: 967 err_init:
966 outreg(ctrl, GC_CTRL_CLK_ENABLE, 0); 968 outreg(ctrl, GC_CTRL_CLK_ENABLE, 0);
967 return -EINVAL; 969 return -EINVAL;
968 } 970 }
969 971
970 static inline int mb862xx_pci_gdc_init(struct mb862xxfb_par *par) 972 static inline int mb862xx_pci_gdc_init(struct mb862xxfb_par *par)
971 { 973 {
972 switch (par->type) { 974 switch (par->type) {
973 case BT_CORALP: 975 case BT_CORALP:
974 return coralp_init(par); 976 return coralp_init(par);
975 case BT_CARMINE: 977 case BT_CARMINE:
976 return carmine_init(par); 978 return carmine_init(par);
977 default: 979 default:
978 return -ENODEV; 980 return -ENODEV;
979 } 981 }
980 } 982 }
981 983
982 #define CHIP_ID(id) \ 984 #define CHIP_ID(id) \
983 { PCI_DEVICE(PCI_VENDOR_ID_FUJITSU_LIMITED, id) } 985 { PCI_DEVICE(PCI_VENDOR_ID_FUJITSU_LIMITED, id) }
984 986
985 static struct pci_device_id mb862xx_pci_tbl[] __devinitdata = { 987 static struct pci_device_id mb862xx_pci_tbl[] __devinitdata = {
986 /* MB86295/MB86296 */ 988 /* MB86295/MB86296 */
987 CHIP_ID(PCI_DEVICE_ID_FUJITSU_CORALP), 989 CHIP_ID(PCI_DEVICE_ID_FUJITSU_CORALP),
988 CHIP_ID(PCI_DEVICE_ID_FUJITSU_CORALPA), 990 CHIP_ID(PCI_DEVICE_ID_FUJITSU_CORALPA),
989 /* MB86297 */ 991 /* MB86297 */
990 CHIP_ID(PCI_DEVICE_ID_FUJITSU_CARMINE), 992 CHIP_ID(PCI_DEVICE_ID_FUJITSU_CARMINE),
991 { 0, } 993 { 0, }
992 }; 994 };
993 995
994 MODULE_DEVICE_TABLE(pci, mb862xx_pci_tbl); 996 MODULE_DEVICE_TABLE(pci, mb862xx_pci_tbl);
995 997
996 static int __devinit mb862xx_pci_probe(struct pci_dev *pdev, 998 static int __devinit mb862xx_pci_probe(struct pci_dev *pdev,
997 const struct pci_device_id *ent) 999 const struct pci_device_id *ent)
998 { 1000 {
999 struct mb862xxfb_par *par; 1001 struct mb862xxfb_par *par;
1000 struct fb_info *info; 1002 struct fb_info *info;
1001 struct device *dev = &pdev->dev; 1003 struct device *dev = &pdev->dev;
1002 int ret; 1004 int ret;
1003 1005
1004 ret = pci_enable_device(pdev); 1006 ret = pci_enable_device(pdev);
1005 if (ret < 0) { 1007 if (ret < 0) {
1006 dev_err(dev, "Cannot enable PCI device\n"); 1008 dev_err(dev, "Cannot enable PCI device\n");
1007 goto out; 1009 goto out;
1008 } 1010 }
1009 1011
1010 info = framebuffer_alloc(sizeof(struct mb862xxfb_par), dev); 1012 info = framebuffer_alloc(sizeof(struct mb862xxfb_par), dev);
1011 if (!info) { 1013 if (!info) {
1012 dev_err(dev, "framebuffer alloc failed\n"); 1014 dev_err(dev, "framebuffer alloc failed\n");
1013 ret = -ENOMEM; 1015 ret = -ENOMEM;
1014 goto dis_dev; 1016 goto dis_dev;
1015 } 1017 }
1016 1018
1017 par = info->par; 1019 par = info->par;
1018 par->info = info; 1020 par->info = info;
1019 par->dev = dev; 1021 par->dev = dev;
1020 par->pdev = pdev; 1022 par->pdev = pdev;
1021 par->irq = pdev->irq; 1023 par->irq = pdev->irq;
1022 1024
1023 ret = pci_request_regions(pdev, DRV_NAME); 1025 ret = pci_request_regions(pdev, DRV_NAME);
1024 if (ret < 0) { 1026 if (ret < 0) {
1025 dev_err(dev, "Cannot reserve region(s) for PCI device\n"); 1027 dev_err(dev, "Cannot reserve region(s) for PCI device\n");
1026 goto rel_fb; 1028 goto rel_fb;
1027 } 1029 }
1028 1030
1029 switch (pdev->device) { 1031 switch (pdev->device) {
1030 case PCI_DEVICE_ID_FUJITSU_CORALP: 1032 case PCI_DEVICE_ID_FUJITSU_CORALP:
1031 case PCI_DEVICE_ID_FUJITSU_CORALPA: 1033 case PCI_DEVICE_ID_FUJITSU_CORALPA:
1032 par->fb_base_phys = pci_resource_start(par->pdev, 0); 1034 par->fb_base_phys = pci_resource_start(par->pdev, 0);
1033 par->mapped_vram = CORALP_MEM_SIZE; 1035 par->mapped_vram = CORALP_MEM_SIZE;
1034 if (par->mapped_vram >= 0x2000000) { 1036 if (par->mapped_vram >= 0x2000000) {
1035 par->mmio_base_phys = par->fb_base_phys + 1037 par->mmio_base_phys = par->fb_base_phys +
1036 MB862XX_MMIO_HIGH_BASE; 1038 MB862XX_MMIO_HIGH_BASE;
1037 } else { 1039 } else {
1038 par->mmio_base_phys = par->fb_base_phys + 1040 par->mmio_base_phys = par->fb_base_phys +
1039 MB862XX_MMIO_BASE; 1041 MB862XX_MMIO_BASE;
1040 } 1042 }
1041 par->mmio_len = MB862XX_MMIO_SIZE; 1043 par->mmio_len = MB862XX_MMIO_SIZE;
1042 par->type = BT_CORALP; 1044 par->type = BT_CORALP;
1043 break; 1045 break;
1044 case PCI_DEVICE_ID_FUJITSU_CARMINE: 1046 case PCI_DEVICE_ID_FUJITSU_CARMINE:
1045 par->fb_base_phys = pci_resource_start(par->pdev, 2); 1047 par->fb_base_phys = pci_resource_start(par->pdev, 2);
1046 par->mmio_base_phys = pci_resource_start(par->pdev, 3); 1048 par->mmio_base_phys = pci_resource_start(par->pdev, 3);
1047 par->mmio_len = pci_resource_len(par->pdev, 3); 1049 par->mmio_len = pci_resource_len(par->pdev, 3);
1048 par->mapped_vram = CARMINE_MEM_SIZE; 1050 par->mapped_vram = CARMINE_MEM_SIZE;
1049 par->type = BT_CARMINE; 1051 par->type = BT_CARMINE;
1050 break; 1052 break;
1051 default: 1053 default:
1052 /* should never occur */ 1054 /* should never occur */
1053 goto rel_reg; 1055 goto rel_reg;
1054 } 1056 }
1055 1057
1056 par->fb_base = ioremap(par->fb_base_phys, par->mapped_vram); 1058 par->fb_base = ioremap(par->fb_base_phys, par->mapped_vram);
1057 if (par->fb_base == NULL) { 1059 if (par->fb_base == NULL) {
1058 dev_err(dev, "Cannot map framebuffer\n"); 1060 dev_err(dev, "Cannot map framebuffer\n");
1059 goto rel_reg; 1061 goto rel_reg;
1060 } 1062 }
1061 1063
1062 par->mmio_base = ioremap(par->mmio_base_phys, par->mmio_len); 1064 par->mmio_base = ioremap(par->mmio_base_phys, par->mmio_len);
1063 if (par->mmio_base == NULL) { 1065 if (par->mmio_base == NULL) {
1064 dev_err(dev, "Cannot map registers\n"); 1066 dev_err(dev, "Cannot map registers\n");
1065 ret = -EIO; 1067 ret = -EIO;
1066 goto fb_unmap; 1068 goto fb_unmap;
1067 } 1069 }
1068 1070
1069 dev_dbg(dev, "fb phys 0x%llx 0x%lx\n", 1071 dev_dbg(dev, "fb phys 0x%llx 0x%lx\n",
1070 (unsigned long long)par->fb_base_phys, (ulong)par->mapped_vram); 1072 (unsigned long long)par->fb_base_phys, (ulong)par->mapped_vram);
1071 dev_dbg(dev, "mmio phys 0x%llx 0x%lx\n", 1073 dev_dbg(dev, "mmio phys 0x%llx 0x%lx\n",
1072 (unsigned long long)par->mmio_base_phys, (ulong)par->mmio_len); 1074 (unsigned long long)par->mmio_base_phys, (ulong)par->mmio_len);
1073 1075
1074 if (mb862xx_pci_gdc_init(par)) 1076 if (mb862xx_pci_gdc_init(par))
1075 goto io_unmap; 1077 goto io_unmap;
1076 1078
1077 if (request_irq(par->irq, mb862xx_intr, IRQF_SHARED, 1079 if (request_irq(par->irq, mb862xx_intr, IRQF_SHARED,
1078 DRV_NAME, (void *)par)) { 1080 DRV_NAME, (void *)par)) {
1079 dev_err(dev, "Cannot request irq\n"); 1081 dev_err(dev, "Cannot request irq\n");
1080 goto io_unmap; 1082 goto io_unmap;
1081 } 1083 }
1082 1084
1083 mb862xxfb_init_fbinfo(info); 1085 mb862xxfb_init_fbinfo(info);
1084 1086
1085 if (fb_alloc_cmap(&info->cmap, NR_PALETTE, 0) < 0) { 1087 if (fb_alloc_cmap(&info->cmap, NR_PALETTE, 0) < 0) {
1086 dev_err(dev, "Could not allocate cmap for fb_info.\n"); 1088 dev_err(dev, "Could not allocate cmap for fb_info.\n");
1087 ret = -ENOMEM; 1089 ret = -ENOMEM;
1088 goto free_irq; 1090 goto free_irq;
1089 } 1091 }
1090 1092
1091 if ((info->fbops->fb_set_par)(info)) 1093 if ((info->fbops->fb_set_par)(info))
1092 dev_err(dev, "set_var() failed on initial setup?\n"); 1094 dev_err(dev, "set_var() failed on initial setup?\n");
1093 1095
1094 ret = register_framebuffer(info); 1096 ret = register_framebuffer(info);
1095 if (ret < 0) { 1097 if (ret < 0) {
1096 dev_err(dev, "failed to register framebuffer\n"); 1098 dev_err(dev, "failed to register framebuffer\n");
1097 goto rel_cmap; 1099 goto rel_cmap;
1098 } 1100 }
1099 1101
1100 pci_set_drvdata(pdev, info); 1102 pci_set_drvdata(pdev, info);
1101 1103
1102 if (device_create_file(dev, &dev_attr_dispregs)) 1104 if (device_create_file(dev, &dev_attr_dispregs))
1103 dev_err(dev, "Can't create sysfs regdump file\n"); 1105 dev_err(dev, "Can't create sysfs regdump file\n");
1104 1106
1105 if (par->type == BT_CARMINE) 1107 if (par->type == BT_CARMINE)
1106 outreg(ctrl, GC_CTRL_INT_MASK, GC_CARMINE_INT_EN); 1108 outreg(ctrl, GC_CTRL_INT_MASK, GC_CARMINE_INT_EN);
1107 else 1109 else
1108 outreg(host, GC_IMASK, GC_INT_EN); 1110 outreg(host, GC_IMASK, GC_INT_EN);
1109 1111
1110 return 0; 1112 return 0;
1111 1113
1112 rel_cmap: 1114 rel_cmap:
1113 fb_dealloc_cmap(&info->cmap); 1115 fb_dealloc_cmap(&info->cmap);
1114 free_irq: 1116 free_irq:
1115 free_irq(par->irq, (void *)par); 1117 free_irq(par->irq, (void *)par);
1116 io_unmap: 1118 io_unmap:
1117 iounmap(par->mmio_base); 1119 iounmap(par->mmio_base);
1118 fb_unmap: 1120 fb_unmap:
1119 iounmap(par->fb_base); 1121 iounmap(par->fb_base);
1120 rel_reg: 1122 rel_reg:
1121 pci_release_regions(pdev); 1123 pci_release_regions(pdev);
1122 rel_fb: 1124 rel_fb:
1123 framebuffer_release(info); 1125 framebuffer_release(info);
1124 dis_dev: 1126 dis_dev:
1125 pci_disable_device(pdev); 1127 pci_disable_device(pdev);
1126 out: 1128 out:
1127 return ret; 1129 return ret;
1128 } 1130 }
1129 1131
1130 static void __devexit mb862xx_pci_remove(struct pci_dev *pdev) 1132 static void __devexit mb862xx_pci_remove(struct pci_dev *pdev)
1131 { 1133 {
1132 struct fb_info *fbi = pci_get_drvdata(pdev); 1134 struct fb_info *fbi = pci_get_drvdata(pdev);
1133 struct mb862xxfb_par *par = fbi->par; 1135 struct mb862xxfb_par *par = fbi->par;
1134 unsigned long reg; 1136 unsigned long reg;
1135 1137
1136 dev_dbg(fbi->dev, "%s release\n", fbi->fix.id); 1138 dev_dbg(fbi->dev, "%s release\n", fbi->fix.id);
1137 1139
1138 /* display off */ 1140 /* display off */
1139 reg = inreg(disp, GC_DCM1); 1141 reg = inreg(disp, GC_DCM1);
1140 reg &= ~(GC_DCM01_DEN | GC_DCM01_L0E); 1142 reg &= ~(GC_DCM01_DEN | GC_DCM01_L0E);
1141 outreg(disp, GC_DCM1, reg); 1143 outreg(disp, GC_DCM1, reg);
1142 1144
1143 if (par->type == BT_CARMINE) { 1145 if (par->type == BT_CARMINE) {
1144 outreg(ctrl, GC_CTRL_INT_MASK, 0); 1146 outreg(ctrl, GC_CTRL_INT_MASK, 0);
1145 outreg(ctrl, GC_CTRL_CLK_ENABLE, 0); 1147 outreg(ctrl, GC_CTRL_CLK_ENABLE, 0);
1146 } else { 1148 } else {
1147 outreg(host, GC_IMASK, 0); 1149 outreg(host, GC_IMASK, 0);
1148 } 1150 }
1149 1151
1150 mb862xx_i2c_exit(par); 1152 mb862xx_i2c_exit(par);
1151 1153
1152 device_remove_file(&pdev->dev, &dev_attr_dispregs); 1154 device_remove_file(&pdev->dev, &dev_attr_dispregs);
1153 1155
1154 pci_set_drvdata(pdev, NULL); 1156 pci_set_drvdata(pdev, NULL);
1155 unregister_framebuffer(fbi); 1157 unregister_framebuffer(fbi);
1156 fb_dealloc_cmap(&fbi->cmap); 1158 fb_dealloc_cmap(&fbi->cmap);
1157 1159
1158 free_irq(par->irq, (void *)par); 1160 free_irq(par->irq, (void *)par);
1159 iounmap(par->mmio_base); 1161 iounmap(par->mmio_base);
1160 iounmap(par->fb_base); 1162 iounmap(par->fb_base);
1161 1163
1162 pci_release_regions(pdev); 1164 pci_release_regions(pdev);
1163 framebuffer_release(fbi); 1165 framebuffer_release(fbi);
1164 pci_disable_device(pdev); 1166 pci_disable_device(pdev);
1165 } 1167 }
1166 1168
1167 static struct pci_driver mb862xxfb_pci_driver = { 1169 static struct pci_driver mb862xxfb_pci_driver = {
1168 .name = DRV_NAME, 1170 .name = DRV_NAME,
1169 .id_table = mb862xx_pci_tbl, 1171 .id_table = mb862xx_pci_tbl,
1170 .probe = mb862xx_pci_probe, 1172 .probe = mb862xx_pci_probe,
1171 .remove = __devexit_p(mb862xx_pci_remove), 1173 .remove = __devexit_p(mb862xx_pci_remove),
1172 }; 1174 };
1173 #endif 1175 #endif
1174 1176
1175 static int __devinit mb862xxfb_init(void) 1177 static int __devinit mb862xxfb_init(void)
1176 { 1178 {
1177 int ret = -ENODEV; 1179 int ret = -ENODEV;
1178 1180
1179 #if defined(CONFIG_FB_MB862XX_LIME) 1181 #if defined(CONFIG_FB_MB862XX_LIME)
1180 ret = platform_driver_register(&of_platform_mb862xxfb_driver); 1182 ret = platform_driver_register(&of_platform_mb862xxfb_driver);
1181 #endif 1183 #endif
1182 #if defined(CONFIG_FB_MB862XX_PCI_GDC) 1184 #if defined(CONFIG_FB_MB862XX_PCI_GDC)
1183 ret = pci_register_driver(&mb862xxfb_pci_driver); 1185 ret = pci_register_driver(&mb862xxfb_pci_driver);
1184 #endif 1186 #endif
1185 return ret; 1187 return ret;
1186 } 1188 }
1187 1189
1188 static void __exit mb862xxfb_exit(void) 1190 static void __exit mb862xxfb_exit(void)
1189 { 1191 {
1190 #if defined(CONFIG_FB_MB862XX_LIME) 1192 #if defined(CONFIG_FB_MB862XX_LIME)
1191 platform_driver_unregister(&of_platform_mb862xxfb_driver); 1193 platform_driver_unregister(&of_platform_mb862xxfb_driver);
1192 #endif 1194 #endif
1193 #if defined(CONFIG_FB_MB862XX_PCI_GDC) 1195 #if defined(CONFIG_FB_MB862XX_PCI_GDC)
1194 pci_unregister_driver(&mb862xxfb_pci_driver); 1196 pci_unregister_driver(&mb862xxfb_pci_driver);
1195 #endif 1197 #endif
1196 } 1198 }
1197 1199
1198 module_init(mb862xxfb_init); 1200 module_init(mb862xxfb_init);
1199 module_exit(mb862xxfb_exit); 1201 module_exit(mb862xxfb_exit);
1200 1202
1201 MODULE_DESCRIPTION("Fujitsu MB862xx Framebuffer driver"); 1203 MODULE_DESCRIPTION("Fujitsu MB862xx Framebuffer driver");
1202 MODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>"); 1204 MODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>");
1203 MODULE_LICENSE("GPL v2"); 1205 MODULE_LICENSE("GPL v2");
1204 1206
drivers/video/omap2/dss/sdi.c
1 /* 1 /*
2 * linux/drivers/video/omap2/dss/sdi.c 2 * linux/drivers/video/omap2/dss/sdi.c
3 * 3 *
4 * Copyright (C) 2009 Nokia Corporation 4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> 5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 * 6 *
7 * This program is free software; you can redistribute it and/or modify it 7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by 8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation. 9 * the Free Software Foundation.
10 * 10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT 11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details. 14 * more details.
15 * 15 *
16 * You should have received a copy of the GNU General Public License along with 16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>. 17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 */ 18 */
19 19
20 #define DSS_SUBSYS_NAME "SDI" 20 #define DSS_SUBSYS_NAME "SDI"
21 21
22 #include <linux/kernel.h> 22 #include <linux/kernel.h>
23 #include <linux/delay.h> 23 #include <linux/delay.h>
24 #include <linux/err.h> 24 #include <linux/err.h>
25 #include <linux/regulator/consumer.h> 25 #include <linux/regulator/consumer.h>
26 #include <linux/export.h> 26 #include <linux/export.h>
27 #include <linux/platform_device.h> 27 #include <linux/platform_device.h>
28 28
29 #include <video/omapdss.h> 29 #include <video/omapdss.h>
30 #include "dss.h" 30 #include "dss.h"
31 31
32 static struct { 32 static struct {
33 bool update_enabled; 33 bool update_enabled;
34 struct regulator *vdds_sdi_reg; 34 struct regulator *vdds_sdi_reg;
35 35
36 struct dss_lcd_mgr_config mgr_config; 36 struct dss_lcd_mgr_config mgr_config;
37 } sdi; 37 } sdi;
38 38
39 static void sdi_config_lcd_manager(struct omap_dss_device *dssdev) 39 static void sdi_config_lcd_manager(struct omap_dss_device *dssdev)
40 { 40 {
41 sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; 41 sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
42 42
43 sdi.mgr_config.stallmode = false; 43 sdi.mgr_config.stallmode = false;
44 sdi.mgr_config.fifohandcheck = false; 44 sdi.mgr_config.fifohandcheck = false;
45 45
46 sdi.mgr_config.video_port_width = 24; 46 sdi.mgr_config.video_port_width = 24;
47 sdi.mgr_config.lcden_sig_polarity = 1; 47 sdi.mgr_config.lcden_sig_polarity = 1;
48 48
49 dss_mgr_set_lcd_config(dssdev->manager, &sdi.mgr_config); 49 dss_mgr_set_lcd_config(dssdev->manager, &sdi.mgr_config);
50 } 50 }
51 51
52 int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) 52 int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
53 { 53 {
54 struct omap_video_timings *t = &dssdev->panel.timings; 54 struct omap_video_timings *t = &dssdev->panel.timings;
55 struct dss_clock_info dss_cinfo; 55 struct dss_clock_info dss_cinfo;
56 struct dispc_clock_info dispc_cinfo; 56 struct dispc_clock_info dispc_cinfo;
57 unsigned long pck; 57 unsigned long pck;
58 int r; 58 int r;
59 59
60 if (dssdev->manager == NULL) { 60 if (dssdev->manager == NULL) {
61 DSSERR("failed to enable display: no manager\n"); 61 DSSERR("failed to enable display: no manager\n");
62 return -ENODEV; 62 return -ENODEV;
63 } 63 }
64 64
65 r = omap_dss_start_device(dssdev); 65 r = omap_dss_start_device(dssdev);
66 if (r) { 66 if (r) {
67 DSSERR("failed to start device\n"); 67 DSSERR("failed to start device\n");
68 goto err_start_dev; 68 goto err_start_dev;
69 } 69 }
70 70
71 r = regulator_enable(sdi.vdds_sdi_reg); 71 r = regulator_enable(sdi.vdds_sdi_reg);
72 if (r) 72 if (r)
73 goto err_reg_enable; 73 goto err_reg_enable;
74 74
75 r = dispc_runtime_get(); 75 r = dispc_runtime_get();
76 if (r) 76 if (r)
77 goto err_get_dispc; 77 goto err_get_dispc;
78 78
79 /* 15.5.9.1.2 */ 79 /* 15.5.9.1.2 */
80 dssdev->panel.timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; 80 dssdev->panel.timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
81 dssdev->panel.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; 81 dssdev->panel.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
82 82
83 r = dss_calc_clock_div(t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo); 83 r = dss_calc_clock_div(t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo);
84 if (r) 84 if (r)
85 goto err_calc_clock_div; 85 goto err_calc_clock_div;
86 86
87 sdi.mgr_config.clock_info = dispc_cinfo; 87 sdi.mgr_config.clock_info = dispc_cinfo;
88 88
89 pck = dss_cinfo.fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div / 1000; 89 pck = dss_cinfo.fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div / 1000;
90 90
91 if (pck != t->pixel_clock) { 91 if (pck != t->pixel_clock) {
92 DSSWARN("Could not find exact pixel clock. Requested %d kHz, " 92 DSSWARN("Could not find exact pixel clock. Requested %d kHz, "
93 "got %lu kHz\n", 93 "got %lu kHz\n",
94 t->pixel_clock, pck); 94 t->pixel_clock, pck);
95 95
96 t->pixel_clock = pck; 96 t->pixel_clock = pck;
97 } 97 }
98 98
99 99
100 dss_mgr_set_timings(dssdev->manager, t); 100 dss_mgr_set_timings(dssdev->manager, t);
101 101
102 r = dss_set_clock_div(&dss_cinfo); 102 r = dss_set_clock_div(&dss_cinfo);
103 if (r) 103 if (r)
104 goto err_set_dss_clock_div; 104 goto err_set_dss_clock_div;
105 105
106 sdi_config_lcd_manager(dssdev); 106 sdi_config_lcd_manager(dssdev);
107 107
108 /*
109 * LCLK and PCLK divisors are located in shadow registers, and we
110 * normally write them to DISPC registers when enabling the output.
111 * However, SDI uses pck-free as source clock for its PLL, and pck-free
112 * is affected by the divisors. And as we need the PLL before enabling
113 * the output, we need to write the divisors early.
114 *
115 * It seems just writing to the DISPC register is enough, and we don't
116 * need to care about the shadow register mechanism for pck-free. The
117 * exact reason for this is unknown.
118 */
119 dispc_mgr_set_clock_div(dssdev->manager->id,
120 &sdi.mgr_config.clock_info);
121
108 dss_sdi_init(dssdev->phy.sdi.datapairs); 122 dss_sdi_init(dssdev->phy.sdi.datapairs);
109 r = dss_sdi_enable(); 123 r = dss_sdi_enable();
110 if (r) 124 if (r)
111 goto err_sdi_enable; 125 goto err_sdi_enable;
112 mdelay(2); 126 mdelay(2);
113 127
114 r = dss_mgr_enable(dssdev->manager); 128 r = dss_mgr_enable(dssdev->manager);
115 if (r) 129 if (r)
116 goto err_mgr_enable; 130 goto err_mgr_enable;
117 131
118 return 0; 132 return 0;
119 133
120 err_mgr_enable: 134 err_mgr_enable:
121 dss_sdi_disable(); 135 dss_sdi_disable();
122 err_sdi_enable: 136 err_sdi_enable:
123 err_set_dss_clock_div: 137 err_set_dss_clock_div:
124 err_calc_clock_div: 138 err_calc_clock_div:
125 dispc_runtime_put(); 139 dispc_runtime_put();
126 err_get_dispc: 140 err_get_dispc:
127 regulator_disable(sdi.vdds_sdi_reg); 141 regulator_disable(sdi.vdds_sdi_reg);
128 err_reg_enable: 142 err_reg_enable:
129 omap_dss_stop_device(dssdev); 143 omap_dss_stop_device(dssdev);
130 err_start_dev: 144 err_start_dev:
131 return r; 145 return r;
132 } 146 }
133 EXPORT_SYMBOL(omapdss_sdi_display_enable); 147 EXPORT_SYMBOL(omapdss_sdi_display_enable);
134 148
135 void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) 149 void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
136 { 150 {
137 dss_mgr_disable(dssdev->manager); 151 dss_mgr_disable(dssdev->manager);
138 152
139 dss_sdi_disable(); 153 dss_sdi_disable();
140 154
141 dispc_runtime_put(); 155 dispc_runtime_put();
142 156
143 regulator_disable(sdi.vdds_sdi_reg); 157 regulator_disable(sdi.vdds_sdi_reg);
144 158
145 omap_dss_stop_device(dssdev); 159 omap_dss_stop_device(dssdev);
146 } 160 }
147 EXPORT_SYMBOL(omapdss_sdi_display_disable); 161 EXPORT_SYMBOL(omapdss_sdi_display_disable);
148 162
149 static int __init sdi_init_display(struct omap_dss_device *dssdev) 163 static int __init sdi_init_display(struct omap_dss_device *dssdev)
150 { 164 {
151 DSSDBG("SDI init\n"); 165 DSSDBG("SDI init\n");
152 166
153 if (sdi.vdds_sdi_reg == NULL) { 167 if (sdi.vdds_sdi_reg == NULL) {
154 struct regulator *vdds_sdi; 168 struct regulator *vdds_sdi;
155 169
156 vdds_sdi = dss_get_vdds_sdi(); 170 vdds_sdi = dss_get_vdds_sdi();
157 171
158 if (IS_ERR(vdds_sdi)) { 172 if (IS_ERR(vdds_sdi)) {
159 DSSERR("can't get VDDS_SDI regulator\n"); 173 DSSERR("can't get VDDS_SDI regulator\n");
160 return PTR_ERR(vdds_sdi); 174 return PTR_ERR(vdds_sdi);
161 } 175 }
162 176
163 sdi.vdds_sdi_reg = vdds_sdi; 177 sdi.vdds_sdi_reg = vdds_sdi;
164 } 178 }
165 179
166 return 0; 180 return 0;
167 } 181 }
168 182
169 static void __init sdi_probe_pdata(struct platform_device *pdev) 183 static void __init sdi_probe_pdata(struct platform_device *pdev)
170 { 184 {
171 struct omap_dss_board_info *pdata = pdev->dev.platform_data; 185 struct omap_dss_board_info *pdata = pdev->dev.platform_data;
172 int i, r; 186 int i, r;
173 187
174 for (i = 0; i < pdata->num_devices; ++i) { 188 for (i = 0; i < pdata->num_devices; ++i) {
175 struct omap_dss_device *dssdev = pdata->devices[i]; 189 struct omap_dss_device *dssdev = pdata->devices[i];
176 190
177 if (dssdev->type != OMAP_DISPLAY_TYPE_SDI) 191 if (dssdev->type != OMAP_DISPLAY_TYPE_SDI)
178 continue; 192 continue;
179 193
180 r = sdi_init_display(dssdev); 194 r = sdi_init_display(dssdev);
181 if (r) { 195 if (r) {
182 DSSERR("device %s init failed: %d\n", dssdev->name, r); 196 DSSERR("device %s init failed: %d\n", dssdev->name, r);
183 continue; 197 continue;
184 } 198 }
185 199
186 r = omap_dss_register_device(dssdev, &pdev->dev, i); 200 r = omap_dss_register_device(dssdev, &pdev->dev, i);
187 if (r) 201 if (r)
188 DSSERR("device %s register failed: %d\n", 202 DSSERR("device %s register failed: %d\n",
189 dssdev->name, r); 203 dssdev->name, r);
190 } 204 }
191 } 205 }
192 206
193 static int __init omap_sdi_probe(struct platform_device *pdev) 207 static int __init omap_sdi_probe(struct platform_device *pdev)
194 { 208 {
195 sdi_probe_pdata(pdev); 209 sdi_probe_pdata(pdev);
196 210
197 return 0; 211 return 0;
198 } 212 }
199 213
200 static int __exit omap_sdi_remove(struct platform_device *pdev) 214 static int __exit omap_sdi_remove(struct platform_device *pdev)
201 { 215 {
202 omap_dss_unregister_child_devices(&pdev->dev); 216 omap_dss_unregister_child_devices(&pdev->dev);
203 217
204 return 0; 218 return 0;
205 } 219 }
206 220
207 static struct platform_driver omap_sdi_driver = { 221 static struct platform_driver omap_sdi_driver = {
208 .remove = __exit_p(omap_sdi_remove), 222 .remove = __exit_p(omap_sdi_remove),
209 .driver = { 223 .driver = {
210 .name = "omapdss_sdi", 224 .name = "omapdss_sdi",
211 .owner = THIS_MODULE, 225 .owner = THIS_MODULE,
212 }, 226 },
213 }; 227 };
214 228
215 int __init sdi_init_platform_driver(void) 229 int __init sdi_init_platform_driver(void)
216 { 230 {
217 return platform_driver_probe(&omap_sdi_driver, omap_sdi_probe); 231 return platform_driver_probe(&omap_sdi_driver, omap_sdi_probe);
218 } 232 }
219 233
220 void __exit sdi_uninit_platform_driver(void) 234 void __exit sdi_uninit_platform_driver(void)
221 { 235 {
222 platform_driver_unregister(&omap_sdi_driver); 236 platform_driver_unregister(&omap_sdi_driver);
223 } 237 }
224 238
drivers/video/omap2/omapfb/omapfb-main.c
1 /* 1 /*
2 * linux/drivers/video/omap2/omapfb-main.c 2 * linux/drivers/video/omap2/omapfb-main.c
3 * 3 *
4 * Copyright (C) 2008 Nokia Corporation 4 * Copyright (C) 2008 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> 5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 * 6 *
7 * Some code and ideas taken from drivers/video/omap/ driver 7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak. 8 * by Imre Deak.
9 * 9 *
10 * This program is free software; you can redistribute it and/or modify it 10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by 11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation. 12 * the Free Software Foundation.
13 * 13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT 14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details. 17 * more details.
18 * 18 *
19 * You should have received a copy of the GNU General Public License along with 19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>. 20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */ 21 */
22 22
23 #include <linux/module.h> 23 #include <linux/module.h>
24 #include <linux/delay.h> 24 #include <linux/delay.h>
25 #include <linux/slab.h> 25 #include <linux/slab.h>
26 #include <linux/fb.h> 26 #include <linux/fb.h>
27 #include <linux/dma-mapping.h> 27 #include <linux/dma-mapping.h>
28 #include <linux/vmalloc.h> 28 #include <linux/vmalloc.h>
29 #include <linux/device.h> 29 #include <linux/device.h>
30 #include <linux/platform_device.h> 30 #include <linux/platform_device.h>
31 #include <linux/omapfb.h> 31 #include <linux/omapfb.h>
32 32
33 #include <video/omapdss.h> 33 #include <video/omapdss.h>
34 #include <plat/vram.h> 34 #include <plat/vram.h>
35 #include <plat/vrfb.h> 35 #include <plat/vrfb.h>
36 36
37 #include "omapfb.h" 37 #include "omapfb.h"
38 38
39 #define MODULE_NAME "omapfb" 39 #define MODULE_NAME "omapfb"
40 40
41 #define OMAPFB_PLANE_XRES_MIN 8 41 #define OMAPFB_PLANE_XRES_MIN 8
42 #define OMAPFB_PLANE_YRES_MIN 8 42 #define OMAPFB_PLANE_YRES_MIN 8
43 43
44 static char *def_mode; 44 static char *def_mode;
45 static char *def_vram; 45 static char *def_vram;
46 static bool def_vrfb; 46 static bool def_vrfb;
47 static int def_rotate; 47 static int def_rotate;
48 static bool def_mirror; 48 static bool def_mirror;
49 static bool auto_update; 49 static bool auto_update;
50 static unsigned int auto_update_freq; 50 static unsigned int auto_update_freq;
51 module_param(auto_update, bool, 0); 51 module_param(auto_update, bool, 0);
52 module_param(auto_update_freq, uint, 0644); 52 module_param(auto_update_freq, uint, 0644);
53 53
54 #ifdef DEBUG 54 #ifdef DEBUG
55 bool omapfb_debug; 55 bool omapfb_debug;
56 module_param_named(debug, omapfb_debug, bool, 0644); 56 module_param_named(debug, omapfb_debug, bool, 0644);
57 static bool omapfb_test_pattern; 57 static bool omapfb_test_pattern;
58 module_param_named(test, omapfb_test_pattern, bool, 0644); 58 module_param_named(test, omapfb_test_pattern, bool, 0644);
59 #endif 59 #endif
60 60
61 static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi); 61 static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi);
62 static int omapfb_get_recommended_bpp(struct omapfb2_device *fbdev, 62 static int omapfb_get_recommended_bpp(struct omapfb2_device *fbdev,
63 struct omap_dss_device *dssdev); 63 struct omap_dss_device *dssdev);
64 64
65 #ifdef DEBUG 65 #ifdef DEBUG
66 static void draw_pixel(struct fb_info *fbi, int x, int y, unsigned color) 66 static void draw_pixel(struct fb_info *fbi, int x, int y, unsigned color)
67 { 67 {
68 struct fb_var_screeninfo *var = &fbi->var; 68 struct fb_var_screeninfo *var = &fbi->var;
69 struct fb_fix_screeninfo *fix = &fbi->fix; 69 struct fb_fix_screeninfo *fix = &fbi->fix;
70 void __iomem *addr = fbi->screen_base; 70 void __iomem *addr = fbi->screen_base;
71 const unsigned bytespp = var->bits_per_pixel >> 3; 71 const unsigned bytespp = var->bits_per_pixel >> 3;
72 const unsigned line_len = fix->line_length / bytespp; 72 const unsigned line_len = fix->line_length / bytespp;
73 73
74 int r = (color >> 16) & 0xff; 74 int r = (color >> 16) & 0xff;
75 int g = (color >> 8) & 0xff; 75 int g = (color >> 8) & 0xff;
76 int b = (color >> 0) & 0xff; 76 int b = (color >> 0) & 0xff;
77 77
78 if (var->bits_per_pixel == 16) { 78 if (var->bits_per_pixel == 16) {
79 u16 __iomem *p = (u16 __iomem *)addr; 79 u16 __iomem *p = (u16 __iomem *)addr;
80 p += y * line_len + x; 80 p += y * line_len + x;
81 81
82 r = r * 32 / 256; 82 r = r * 32 / 256;
83 g = g * 64 / 256; 83 g = g * 64 / 256;
84 b = b * 32 / 256; 84 b = b * 32 / 256;
85 85
86 __raw_writew((r << 11) | (g << 5) | (b << 0), p); 86 __raw_writew((r << 11) | (g << 5) | (b << 0), p);
87 } else if (var->bits_per_pixel == 24) { 87 } else if (var->bits_per_pixel == 24) {
88 u8 __iomem *p = (u8 __iomem *)addr; 88 u8 __iomem *p = (u8 __iomem *)addr;
89 p += (y * line_len + x) * 3; 89 p += (y * line_len + x) * 3;
90 90
91 __raw_writeb(b, p + 0); 91 __raw_writeb(b, p + 0);
92 __raw_writeb(g, p + 1); 92 __raw_writeb(g, p + 1);
93 __raw_writeb(r, p + 2); 93 __raw_writeb(r, p + 2);
94 } else if (var->bits_per_pixel == 32) { 94 } else if (var->bits_per_pixel == 32) {
95 u32 __iomem *p = (u32 __iomem *)addr; 95 u32 __iomem *p = (u32 __iomem *)addr;
96 p += y * line_len + x; 96 p += y * line_len + x;
97 __raw_writel(color, p); 97 __raw_writel(color, p);
98 } 98 }
99 } 99 }
100 100
101 static void fill_fb(struct fb_info *fbi) 101 static void fill_fb(struct fb_info *fbi)
102 { 102 {
103 struct fb_var_screeninfo *var = &fbi->var; 103 struct fb_var_screeninfo *var = &fbi->var;
104 const short w = var->xres_virtual; 104 const short w = var->xres_virtual;
105 const short h = var->yres_virtual; 105 const short h = var->yres_virtual;
106 void __iomem *addr = fbi->screen_base; 106 void __iomem *addr = fbi->screen_base;
107 int y, x; 107 int y, x;
108 108
109 if (!addr) 109 if (!addr)
110 return; 110 return;
111 111
112 DBG("fill_fb %dx%d, line_len %d bytes\n", w, h, fbi->fix.line_length); 112 DBG("fill_fb %dx%d, line_len %d bytes\n", w, h, fbi->fix.line_length);
113 113
114 for (y = 0; y < h; y++) { 114 for (y = 0; y < h; y++) {
115 for (x = 0; x < w; x++) { 115 for (x = 0; x < w; x++) {
116 if (x < 20 && y < 20) 116 if (x < 20 && y < 20)
117 draw_pixel(fbi, x, y, 0xffffff); 117 draw_pixel(fbi, x, y, 0xffffff);
118 else if (x < 20 && (y > 20 && y < h - 20)) 118 else if (x < 20 && (y > 20 && y < h - 20))
119 draw_pixel(fbi, x, y, 0xff); 119 draw_pixel(fbi, x, y, 0xff);
120 else if (y < 20 && (x > 20 && x < w - 20)) 120 else if (y < 20 && (x > 20 && x < w - 20))
121 draw_pixel(fbi, x, y, 0xff00); 121 draw_pixel(fbi, x, y, 0xff00);
122 else if (x > w - 20 && (y > 20 && y < h - 20)) 122 else if (x > w - 20 && (y > 20 && y < h - 20))
123 draw_pixel(fbi, x, y, 0xff0000); 123 draw_pixel(fbi, x, y, 0xff0000);
124 else if (y > h - 20 && (x > 20 && x < w - 20)) 124 else if (y > h - 20 && (x > 20 && x < w - 20))
125 draw_pixel(fbi, x, y, 0xffff00); 125 draw_pixel(fbi, x, y, 0xffff00);
126 else if (x == 20 || x == w - 20 || 126 else if (x == 20 || x == w - 20 ||
127 y == 20 || y == h - 20) 127 y == 20 || y == h - 20)
128 draw_pixel(fbi, x, y, 0xffffff); 128 draw_pixel(fbi, x, y, 0xffffff);
129 else if (x == y || w - x == h - y) 129 else if (x == y || w - x == h - y)
130 draw_pixel(fbi, x, y, 0xff00ff); 130 draw_pixel(fbi, x, y, 0xff00ff);
131 else if (w - x == y || x == h - y) 131 else if (w - x == y || x == h - y)
132 draw_pixel(fbi, x, y, 0x00ffff); 132 draw_pixel(fbi, x, y, 0x00ffff);
133 else if (x > 20 && y > 20 && x < w - 20 && y < h - 20) { 133 else if (x > 20 && y > 20 && x < w - 20 && y < h - 20) {
134 int t = x * 3 / w; 134 int t = x * 3 / w;
135 unsigned r = 0, g = 0, b = 0; 135 unsigned r = 0, g = 0, b = 0;
136 unsigned c; 136 unsigned c;
137 if (var->bits_per_pixel == 16) { 137 if (var->bits_per_pixel == 16) {
138 if (t == 0) 138 if (t == 0)
139 b = (y % 32) * 256 / 32; 139 b = (y % 32) * 256 / 32;
140 else if (t == 1) 140 else if (t == 1)
141 g = (y % 64) * 256 / 64; 141 g = (y % 64) * 256 / 64;
142 else if (t == 2) 142 else if (t == 2)
143 r = (y % 32) * 256 / 32; 143 r = (y % 32) * 256 / 32;
144 } else { 144 } else {
145 if (t == 0) 145 if (t == 0)
146 b = (y % 256); 146 b = (y % 256);
147 else if (t == 1) 147 else if (t == 1)
148 g = (y % 256); 148 g = (y % 256);
149 else if (t == 2) 149 else if (t == 2)
150 r = (y % 256); 150 r = (y % 256);
151 } 151 }
152 c = (r << 16) | (g << 8) | (b << 0); 152 c = (r << 16) | (g << 8) | (b << 0);
153 draw_pixel(fbi, x, y, c); 153 draw_pixel(fbi, x, y, c);
154 } else { 154 } else {
155 draw_pixel(fbi, x, y, 0); 155 draw_pixel(fbi, x, y, 0);
156 } 156 }
157 } 157 }
158 } 158 }
159 } 159 }
160 #endif 160 #endif
161 161
162 static unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot) 162 static unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot)
163 { 163 {
164 const struct vrfb *vrfb = &ofbi->region->vrfb; 164 const struct vrfb *vrfb = &ofbi->region->vrfb;
165 unsigned offset; 165 unsigned offset;
166 166
167 switch (rot) { 167 switch (rot) {
168 case FB_ROTATE_UR: 168 case FB_ROTATE_UR:
169 offset = 0; 169 offset = 0;
170 break; 170 break;
171 case FB_ROTATE_CW: 171 case FB_ROTATE_CW:
172 offset = vrfb->yoffset; 172 offset = vrfb->yoffset;
173 break; 173 break;
174 case FB_ROTATE_UD: 174 case FB_ROTATE_UD:
175 offset = vrfb->yoffset * OMAP_VRFB_LINE_LEN + vrfb->xoffset; 175 offset = vrfb->yoffset * OMAP_VRFB_LINE_LEN + vrfb->xoffset;
176 break; 176 break;
177 case FB_ROTATE_CCW: 177 case FB_ROTATE_CCW:
178 offset = vrfb->xoffset * OMAP_VRFB_LINE_LEN; 178 offset = vrfb->xoffset * OMAP_VRFB_LINE_LEN;
179 break; 179 break;
180 default: 180 default:
181 BUG(); 181 BUG();
182 return 0; 182 return 0;
183 } 183 }
184 184
185 offset *= vrfb->bytespp; 185 offset *= vrfb->bytespp;
186 186
187 return offset; 187 return offset;
188 } 188 }
189 189
190 static u32 omapfb_get_region_rot_paddr(const struct omapfb_info *ofbi, int rot) 190 static u32 omapfb_get_region_rot_paddr(const struct omapfb_info *ofbi, int rot)
191 { 191 {
192 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { 192 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
193 return ofbi->region->vrfb.paddr[rot] 193 return ofbi->region->vrfb.paddr[rot]
194 + omapfb_get_vrfb_offset(ofbi, rot); 194 + omapfb_get_vrfb_offset(ofbi, rot);
195 } else { 195 } else {
196 return ofbi->region->paddr; 196 return ofbi->region->paddr;
197 } 197 }
198 } 198 }
199 199
200 static u32 omapfb_get_region_paddr(const struct omapfb_info *ofbi) 200 static u32 omapfb_get_region_paddr(const struct omapfb_info *ofbi)
201 { 201 {
202 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) 202 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
203 return ofbi->region->vrfb.paddr[0]; 203 return ofbi->region->vrfb.paddr[0];
204 else 204 else
205 return ofbi->region->paddr; 205 return ofbi->region->paddr;
206 } 206 }
207 207
208 static void __iomem *omapfb_get_region_vaddr(const struct omapfb_info *ofbi) 208 static void __iomem *omapfb_get_region_vaddr(const struct omapfb_info *ofbi)
209 { 209 {
210 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) 210 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
211 return ofbi->region->vrfb.vaddr[0]; 211 return ofbi->region->vrfb.vaddr[0];
212 else 212 else
213 return ofbi->region->vaddr; 213 return ofbi->region->vaddr;
214 } 214 }
215 215
216 static struct omapfb_colormode omapfb_colormodes[] = { 216 static struct omapfb_colormode omapfb_colormodes[] = {
217 { 217 {
218 .dssmode = OMAP_DSS_COLOR_UYVY, 218 .dssmode = OMAP_DSS_COLOR_UYVY,
219 .bits_per_pixel = 16, 219 .bits_per_pixel = 16,
220 .nonstd = OMAPFB_COLOR_YUV422, 220 .nonstd = OMAPFB_COLOR_YUV422,
221 }, { 221 }, {
222 .dssmode = OMAP_DSS_COLOR_YUV2, 222 .dssmode = OMAP_DSS_COLOR_YUV2,
223 .bits_per_pixel = 16, 223 .bits_per_pixel = 16,
224 .nonstd = OMAPFB_COLOR_YUY422, 224 .nonstd = OMAPFB_COLOR_YUY422,
225 }, { 225 }, {
226 .dssmode = OMAP_DSS_COLOR_ARGB16, 226 .dssmode = OMAP_DSS_COLOR_ARGB16,
227 .bits_per_pixel = 16, 227 .bits_per_pixel = 16,
228 .red = { .length = 4, .offset = 8, .msb_right = 0 }, 228 .red = { .length = 4, .offset = 8, .msb_right = 0 },
229 .green = { .length = 4, .offset = 4, .msb_right = 0 }, 229 .green = { .length = 4, .offset = 4, .msb_right = 0 },
230 .blue = { .length = 4, .offset = 0, .msb_right = 0 }, 230 .blue = { .length = 4, .offset = 0, .msb_right = 0 },
231 .transp = { .length = 4, .offset = 12, .msb_right = 0 }, 231 .transp = { .length = 4, .offset = 12, .msb_right = 0 },
232 }, { 232 }, {
233 .dssmode = OMAP_DSS_COLOR_RGB16, 233 .dssmode = OMAP_DSS_COLOR_RGB16,
234 .bits_per_pixel = 16, 234 .bits_per_pixel = 16,
235 .red = { .length = 5, .offset = 11, .msb_right = 0 }, 235 .red = { .length = 5, .offset = 11, .msb_right = 0 },
236 .green = { .length = 6, .offset = 5, .msb_right = 0 }, 236 .green = { .length = 6, .offset = 5, .msb_right = 0 },
237 .blue = { .length = 5, .offset = 0, .msb_right = 0 }, 237 .blue = { .length = 5, .offset = 0, .msb_right = 0 },
238 .transp = { .length = 0, .offset = 0, .msb_right = 0 }, 238 .transp = { .length = 0, .offset = 0, .msb_right = 0 },
239 }, { 239 }, {
240 .dssmode = OMAP_DSS_COLOR_RGB24P, 240 .dssmode = OMAP_DSS_COLOR_RGB24P,
241 .bits_per_pixel = 24, 241 .bits_per_pixel = 24,
242 .red = { .length = 8, .offset = 16, .msb_right = 0 }, 242 .red = { .length = 8, .offset = 16, .msb_right = 0 },
243 .green = { .length = 8, .offset = 8, .msb_right = 0 }, 243 .green = { .length = 8, .offset = 8, .msb_right = 0 },
244 .blue = { .length = 8, .offset = 0, .msb_right = 0 }, 244 .blue = { .length = 8, .offset = 0, .msb_right = 0 },
245 .transp = { .length = 0, .offset = 0, .msb_right = 0 }, 245 .transp = { .length = 0, .offset = 0, .msb_right = 0 },
246 }, { 246 }, {
247 .dssmode = OMAP_DSS_COLOR_RGB24U, 247 .dssmode = OMAP_DSS_COLOR_RGB24U,
248 .bits_per_pixel = 32, 248 .bits_per_pixel = 32,
249 .red = { .length = 8, .offset = 16, .msb_right = 0 }, 249 .red = { .length = 8, .offset = 16, .msb_right = 0 },
250 .green = { .length = 8, .offset = 8, .msb_right = 0 }, 250 .green = { .length = 8, .offset = 8, .msb_right = 0 },
251 .blue = { .length = 8, .offset = 0, .msb_right = 0 }, 251 .blue = { .length = 8, .offset = 0, .msb_right = 0 },
252 .transp = { .length = 0, .offset = 0, .msb_right = 0 }, 252 .transp = { .length = 0, .offset = 0, .msb_right = 0 },
253 }, { 253 }, {
254 .dssmode = OMAP_DSS_COLOR_ARGB32, 254 .dssmode = OMAP_DSS_COLOR_ARGB32,
255 .bits_per_pixel = 32, 255 .bits_per_pixel = 32,
256 .red = { .length = 8, .offset = 16, .msb_right = 0 }, 256 .red = { .length = 8, .offset = 16, .msb_right = 0 },
257 .green = { .length = 8, .offset = 8, .msb_right = 0 }, 257 .green = { .length = 8, .offset = 8, .msb_right = 0 },
258 .blue = { .length = 8, .offset = 0, .msb_right = 0 }, 258 .blue = { .length = 8, .offset = 0, .msb_right = 0 },
259 .transp = { .length = 8, .offset = 24, .msb_right = 0 }, 259 .transp = { .length = 8, .offset = 24, .msb_right = 0 },
260 }, { 260 }, {
261 .dssmode = OMAP_DSS_COLOR_RGBA32, 261 .dssmode = OMAP_DSS_COLOR_RGBA32,
262 .bits_per_pixel = 32, 262 .bits_per_pixel = 32,
263 .red = { .length = 8, .offset = 24, .msb_right = 0 }, 263 .red = { .length = 8, .offset = 24, .msb_right = 0 },
264 .green = { .length = 8, .offset = 16, .msb_right = 0 }, 264 .green = { .length = 8, .offset = 16, .msb_right = 0 },
265 .blue = { .length = 8, .offset = 8, .msb_right = 0 }, 265 .blue = { .length = 8, .offset = 8, .msb_right = 0 },
266 .transp = { .length = 8, .offset = 0, .msb_right = 0 }, 266 .transp = { .length = 8, .offset = 0, .msb_right = 0 },
267 }, { 267 }, {
268 .dssmode = OMAP_DSS_COLOR_RGBX32, 268 .dssmode = OMAP_DSS_COLOR_RGBX32,
269 .bits_per_pixel = 32, 269 .bits_per_pixel = 32,
270 .red = { .length = 8, .offset = 24, .msb_right = 0 }, 270 .red = { .length = 8, .offset = 24, .msb_right = 0 },
271 .green = { .length = 8, .offset = 16, .msb_right = 0 }, 271 .green = { .length = 8, .offset = 16, .msb_right = 0 },
272 .blue = { .length = 8, .offset = 8, .msb_right = 0 }, 272 .blue = { .length = 8, .offset = 8, .msb_right = 0 },
273 .transp = { .length = 0, .offset = 0, .msb_right = 0 }, 273 .transp = { .length = 0, .offset = 0, .msb_right = 0 },
274 }, 274 },
275 }; 275 };
276 276
277 static bool cmp_var_to_colormode(struct fb_var_screeninfo *var, 277 static bool cmp_var_to_colormode(struct fb_var_screeninfo *var,
278 struct omapfb_colormode *color) 278 struct omapfb_colormode *color)
279 { 279 {
280 bool cmp_component(struct fb_bitfield *f1, struct fb_bitfield *f2) 280 bool cmp_component(struct fb_bitfield *f1, struct fb_bitfield *f2)
281 { 281 {
282 return f1->length == f2->length && 282 return f1->length == f2->length &&
283 f1->offset == f2->offset && 283 f1->offset == f2->offset &&
284 f1->msb_right == f2->msb_right; 284 f1->msb_right == f2->msb_right;
285 } 285 }
286 286
287 if (var->bits_per_pixel == 0 || 287 if (var->bits_per_pixel == 0 ||
288 var->red.length == 0 || 288 var->red.length == 0 ||
289 var->blue.length == 0 || 289 var->blue.length == 0 ||
290 var->green.length == 0) 290 var->green.length == 0)
291 return 0; 291 return 0;
292 292
293 return var->bits_per_pixel == color->bits_per_pixel && 293 return var->bits_per_pixel == color->bits_per_pixel &&
294 cmp_component(&var->red, &color->red) && 294 cmp_component(&var->red, &color->red) &&
295 cmp_component(&var->green, &color->green) && 295 cmp_component(&var->green, &color->green) &&
296 cmp_component(&var->blue, &color->blue) && 296 cmp_component(&var->blue, &color->blue) &&
297 cmp_component(&var->transp, &color->transp); 297 cmp_component(&var->transp, &color->transp);
298 } 298 }
299 299
300 static void assign_colormode_to_var(struct fb_var_screeninfo *var, 300 static void assign_colormode_to_var(struct fb_var_screeninfo *var,
301 struct omapfb_colormode *color) 301 struct omapfb_colormode *color)
302 { 302 {
303 var->bits_per_pixel = color->bits_per_pixel; 303 var->bits_per_pixel = color->bits_per_pixel;
304 var->nonstd = color->nonstd; 304 var->nonstd = color->nonstd;
305 var->red = color->red; 305 var->red = color->red;
306 var->green = color->green; 306 var->green = color->green;
307 var->blue = color->blue; 307 var->blue = color->blue;
308 var->transp = color->transp; 308 var->transp = color->transp;
309 } 309 }
310 310
311 static int fb_mode_to_dss_mode(struct fb_var_screeninfo *var, 311 static int fb_mode_to_dss_mode(struct fb_var_screeninfo *var,
312 enum omap_color_mode *mode) 312 enum omap_color_mode *mode)
313 { 313 {
314 enum omap_color_mode dssmode; 314 enum omap_color_mode dssmode;
315 int i; 315 int i;
316 316
317 /* first match with nonstd field */ 317 /* first match with nonstd field */
318 if (var->nonstd) { 318 if (var->nonstd) {
319 for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) { 319 for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
320 struct omapfb_colormode *m = &omapfb_colormodes[i]; 320 struct omapfb_colormode *m = &omapfb_colormodes[i];
321 if (var->nonstd == m->nonstd) { 321 if (var->nonstd == m->nonstd) {
322 assign_colormode_to_var(var, m); 322 assign_colormode_to_var(var, m);
323 *mode = m->dssmode; 323 *mode = m->dssmode;
324 return 0; 324 return 0;
325 } 325 }
326 } 326 }
327 327
328 return -EINVAL; 328 return -EINVAL;
329 } 329 }
330 330
331 /* then try exact match of bpp and colors */ 331 /* then try exact match of bpp and colors */
332 for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) { 332 for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
333 struct omapfb_colormode *m = &omapfb_colormodes[i]; 333 struct omapfb_colormode *m = &omapfb_colormodes[i];
334 if (cmp_var_to_colormode(var, m)) { 334 if (cmp_var_to_colormode(var, m)) {
335 assign_colormode_to_var(var, m); 335 assign_colormode_to_var(var, m);
336 *mode = m->dssmode; 336 *mode = m->dssmode;
337 return 0; 337 return 0;
338 } 338 }
339 } 339 }
340 340
341 /* match with bpp if user has not filled color fields 341 /* match with bpp if user has not filled color fields
342 * properly */ 342 * properly */
343 switch (var->bits_per_pixel) { 343 switch (var->bits_per_pixel) {
344 case 1: 344 case 1:
345 dssmode = OMAP_DSS_COLOR_CLUT1; 345 dssmode = OMAP_DSS_COLOR_CLUT1;
346 break; 346 break;
347 case 2: 347 case 2:
348 dssmode = OMAP_DSS_COLOR_CLUT2; 348 dssmode = OMAP_DSS_COLOR_CLUT2;
349 break; 349 break;
350 case 4: 350 case 4:
351 dssmode = OMAP_DSS_COLOR_CLUT4; 351 dssmode = OMAP_DSS_COLOR_CLUT4;
352 break; 352 break;
353 case 8: 353 case 8:
354 dssmode = OMAP_DSS_COLOR_CLUT8; 354 dssmode = OMAP_DSS_COLOR_CLUT8;
355 break; 355 break;
356 case 12: 356 case 12:
357 dssmode = OMAP_DSS_COLOR_RGB12U; 357 dssmode = OMAP_DSS_COLOR_RGB12U;
358 break; 358 break;
359 case 16: 359 case 16:
360 dssmode = OMAP_DSS_COLOR_RGB16; 360 dssmode = OMAP_DSS_COLOR_RGB16;
361 break; 361 break;
362 case 24: 362 case 24:
363 dssmode = OMAP_DSS_COLOR_RGB24P; 363 dssmode = OMAP_DSS_COLOR_RGB24P;
364 break; 364 break;
365 case 32: 365 case 32:
366 dssmode = OMAP_DSS_COLOR_RGB24U; 366 dssmode = OMAP_DSS_COLOR_RGB24U;
367 break; 367 break;
368 default: 368 default:
369 return -EINVAL; 369 return -EINVAL;
370 } 370 }
371 371
372 for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) { 372 for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
373 struct omapfb_colormode *m = &omapfb_colormodes[i]; 373 struct omapfb_colormode *m = &omapfb_colormodes[i];
374 if (dssmode == m->dssmode) { 374 if (dssmode == m->dssmode) {
375 assign_colormode_to_var(var, m); 375 assign_colormode_to_var(var, m);
376 *mode = m->dssmode; 376 *mode = m->dssmode;
377 return 0; 377 return 0;
378 } 378 }
379 } 379 }
380 380
381 return -EINVAL; 381 return -EINVAL;
382 } 382 }
383 383
384 static int check_fb_res_bounds(struct fb_var_screeninfo *var) 384 static int check_fb_res_bounds(struct fb_var_screeninfo *var)
385 { 385 {
386 int xres_min = OMAPFB_PLANE_XRES_MIN; 386 int xres_min = OMAPFB_PLANE_XRES_MIN;
387 int xres_max = 2048; 387 int xres_max = 2048;
388 int yres_min = OMAPFB_PLANE_YRES_MIN; 388 int yres_min = OMAPFB_PLANE_YRES_MIN;
389 int yres_max = 2048; 389 int yres_max = 2048;
390 390
391 /* XXX: some applications seem to set virtual res to 0. */ 391 /* XXX: some applications seem to set virtual res to 0. */
392 if (var->xres_virtual == 0) 392 if (var->xres_virtual == 0)
393 var->xres_virtual = var->xres; 393 var->xres_virtual = var->xres;
394 394
395 if (var->yres_virtual == 0) 395 if (var->yres_virtual == 0)
396 var->yres_virtual = var->yres; 396 var->yres_virtual = var->yres;
397 397
398 if (var->xres_virtual < xres_min || var->yres_virtual < yres_min) 398 if (var->xres_virtual < xres_min || var->yres_virtual < yres_min)
399 return -EINVAL; 399 return -EINVAL;
400 400
401 if (var->xres < xres_min) 401 if (var->xres < xres_min)
402 var->xres = xres_min; 402 var->xres = xres_min;
403 if (var->yres < yres_min) 403 if (var->yres < yres_min)
404 var->yres = yres_min; 404 var->yres = yres_min;
405 if (var->xres > xres_max) 405 if (var->xres > xres_max)
406 var->xres = xres_max; 406 var->xres = xres_max;
407 if (var->yres > yres_max) 407 if (var->yres > yres_max)
408 var->yres = yres_max; 408 var->yres = yres_max;
409 409
410 if (var->xres > var->xres_virtual) 410 if (var->xres > var->xres_virtual)
411 var->xres = var->xres_virtual; 411 var->xres = var->xres_virtual;
412 if (var->yres > var->yres_virtual) 412 if (var->yres > var->yres_virtual)
413 var->yres = var->yres_virtual; 413 var->yres = var->yres_virtual;
414 414
415 return 0; 415 return 0;
416 } 416 }
417 417
418 static void shrink_height(unsigned long max_frame_size, 418 static void shrink_height(unsigned long max_frame_size,
419 struct fb_var_screeninfo *var) 419 struct fb_var_screeninfo *var)
420 { 420 {
421 DBG("can't fit FB into memory, reducing y\n"); 421 DBG("can't fit FB into memory, reducing y\n");
422 var->yres_virtual = max_frame_size / 422 var->yres_virtual = max_frame_size /
423 (var->xres_virtual * var->bits_per_pixel >> 3); 423 (var->xres_virtual * var->bits_per_pixel >> 3);
424 424
425 if (var->yres_virtual < OMAPFB_PLANE_YRES_MIN) 425 if (var->yres_virtual < OMAPFB_PLANE_YRES_MIN)
426 var->yres_virtual = OMAPFB_PLANE_YRES_MIN; 426 var->yres_virtual = OMAPFB_PLANE_YRES_MIN;
427 427
428 if (var->yres > var->yres_virtual) 428 if (var->yres > var->yres_virtual)
429 var->yres = var->yres_virtual; 429 var->yres = var->yres_virtual;
430 } 430 }
431 431
432 static void shrink_width(unsigned long max_frame_size, 432 static void shrink_width(unsigned long max_frame_size,
433 struct fb_var_screeninfo *var) 433 struct fb_var_screeninfo *var)
434 { 434 {
435 DBG("can't fit FB into memory, reducing x\n"); 435 DBG("can't fit FB into memory, reducing x\n");
436 var->xres_virtual = max_frame_size / var->yres_virtual / 436 var->xres_virtual = max_frame_size / var->yres_virtual /
437 (var->bits_per_pixel >> 3); 437 (var->bits_per_pixel >> 3);
438 438
439 if (var->xres_virtual < OMAPFB_PLANE_XRES_MIN) 439 if (var->xres_virtual < OMAPFB_PLANE_XRES_MIN)
440 var->xres_virtual = OMAPFB_PLANE_XRES_MIN; 440 var->xres_virtual = OMAPFB_PLANE_XRES_MIN;
441 441
442 if (var->xres > var->xres_virtual) 442 if (var->xres > var->xres_virtual)
443 var->xres = var->xres_virtual; 443 var->xres = var->xres_virtual;
444 } 444 }
445 445
446 static int check_vrfb_fb_size(unsigned long region_size, 446 static int check_vrfb_fb_size(unsigned long region_size,
447 const struct fb_var_screeninfo *var) 447 const struct fb_var_screeninfo *var)
448 { 448 {
449 unsigned long min_phys_size = omap_vrfb_min_phys_size(var->xres_virtual, 449 unsigned long min_phys_size = omap_vrfb_min_phys_size(var->xres_virtual,
450 var->yres_virtual, var->bits_per_pixel >> 3); 450 var->yres_virtual, var->bits_per_pixel >> 3);
451 451
452 return min_phys_size > region_size ? -EINVAL : 0; 452 return min_phys_size > region_size ? -EINVAL : 0;
453 } 453 }
454 454
455 static int check_fb_size(const struct omapfb_info *ofbi, 455 static int check_fb_size(const struct omapfb_info *ofbi,
456 struct fb_var_screeninfo *var) 456 struct fb_var_screeninfo *var)
457 { 457 {
458 unsigned long max_frame_size = ofbi->region->size; 458 unsigned long max_frame_size = ofbi->region->size;
459 int bytespp = var->bits_per_pixel >> 3; 459 int bytespp = var->bits_per_pixel >> 3;
460 unsigned long line_size = var->xres_virtual * bytespp; 460 unsigned long line_size = var->xres_virtual * bytespp;
461 461
462 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { 462 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
463 /* One needs to check for both VRFB and OMAPFB limitations. */ 463 /* One needs to check for both VRFB and OMAPFB limitations. */
464 if (check_vrfb_fb_size(max_frame_size, var)) 464 if (check_vrfb_fb_size(max_frame_size, var))
465 shrink_height(omap_vrfb_max_height( 465 shrink_height(omap_vrfb_max_height(
466 max_frame_size, var->xres_virtual, bytespp) * 466 max_frame_size, var->xres_virtual, bytespp) *
467 line_size, var); 467 line_size, var);
468 468
469 if (check_vrfb_fb_size(max_frame_size, var)) { 469 if (check_vrfb_fb_size(max_frame_size, var)) {
470 DBG("cannot fit FB to memory\n"); 470 DBG("cannot fit FB to memory\n");
471 return -EINVAL; 471 return -EINVAL;
472 } 472 }
473 473
474 return 0; 474 return 0;
475 } 475 }
476 476
477 DBG("max frame size %lu, line size %lu\n", max_frame_size, line_size); 477 DBG("max frame size %lu, line size %lu\n", max_frame_size, line_size);
478 478
479 if (line_size * var->yres_virtual > max_frame_size) 479 if (line_size * var->yres_virtual > max_frame_size)
480 shrink_height(max_frame_size, var); 480 shrink_height(max_frame_size, var);
481 481
482 if (line_size * var->yres_virtual > max_frame_size) { 482 if (line_size * var->yres_virtual > max_frame_size) {
483 shrink_width(max_frame_size, var); 483 shrink_width(max_frame_size, var);
484 line_size = var->xres_virtual * bytespp; 484 line_size = var->xres_virtual * bytespp;
485 } 485 }
486 486
487 if (line_size * var->yres_virtual > max_frame_size) { 487 if (line_size * var->yres_virtual > max_frame_size) {
488 DBG("cannot fit FB to memory\n"); 488 DBG("cannot fit FB to memory\n");
489 return -EINVAL; 489 return -EINVAL;
490 } 490 }
491 491
492 return 0; 492 return 0;
493 } 493 }
494 494
495 /* 495 /*
496 * Consider if VRFB assisted rotation is in use and if the virtual space for 496 * Consider if VRFB assisted rotation is in use and if the virtual space for
497 * the zero degree view needs to be mapped. The need for mapping also acts as 497 * the zero degree view needs to be mapped. The need for mapping also acts as
498 * the trigger for setting up the hardware on the context in question. This 498 * the trigger for setting up the hardware on the context in question. This
499 * ensures that one does not attempt to access the virtual view before the 499 * ensures that one does not attempt to access the virtual view before the
500 * hardware is serving the address translations. 500 * hardware is serving the address translations.
501 */ 501 */
502 static int setup_vrfb_rotation(struct fb_info *fbi) 502 static int setup_vrfb_rotation(struct fb_info *fbi)
503 { 503 {
504 struct omapfb_info *ofbi = FB2OFB(fbi); 504 struct omapfb_info *ofbi = FB2OFB(fbi);
505 struct omapfb2_mem_region *rg = ofbi->region; 505 struct omapfb2_mem_region *rg = ofbi->region;
506 struct vrfb *vrfb = &rg->vrfb; 506 struct vrfb *vrfb = &rg->vrfb;
507 struct fb_var_screeninfo *var = &fbi->var; 507 struct fb_var_screeninfo *var = &fbi->var;
508 struct fb_fix_screeninfo *fix = &fbi->fix; 508 struct fb_fix_screeninfo *fix = &fbi->fix;
509 unsigned bytespp; 509 unsigned bytespp;
510 bool yuv_mode; 510 bool yuv_mode;
511 enum omap_color_mode mode; 511 enum omap_color_mode mode;
512 int r; 512 int r;
513 bool reconf; 513 bool reconf;
514 514
515 if (!rg->size || ofbi->rotation_type != OMAP_DSS_ROT_VRFB) 515 if (!rg->size || ofbi->rotation_type != OMAP_DSS_ROT_VRFB)
516 return 0; 516 return 0;
517 517
518 DBG("setup_vrfb_rotation\n"); 518 DBG("setup_vrfb_rotation\n");
519 519
520 r = fb_mode_to_dss_mode(var, &mode); 520 r = fb_mode_to_dss_mode(var, &mode);
521 if (r) 521 if (r)
522 return r; 522 return r;
523 523
524 bytespp = var->bits_per_pixel >> 3; 524 bytespp = var->bits_per_pixel >> 3;
525 525
526 yuv_mode = mode == OMAP_DSS_COLOR_YUV2 || mode == OMAP_DSS_COLOR_UYVY; 526 yuv_mode = mode == OMAP_DSS_COLOR_YUV2 || mode == OMAP_DSS_COLOR_UYVY;
527 527
528 /* We need to reconfigure VRFB if the resolution changes, if yuv mode 528 /* We need to reconfigure VRFB if the resolution changes, if yuv mode
529 * is enabled/disabled, or if bytes per pixel changes */ 529 * is enabled/disabled, or if bytes per pixel changes */
530 530
531 /* XXX we shouldn't allow this when framebuffer is mmapped */ 531 /* XXX we shouldn't allow this when framebuffer is mmapped */
532 532
533 reconf = false; 533 reconf = false;
534 534
535 if (yuv_mode != vrfb->yuv_mode) 535 if (yuv_mode != vrfb->yuv_mode)
536 reconf = true; 536 reconf = true;
537 else if (bytespp != vrfb->bytespp) 537 else if (bytespp != vrfb->bytespp)
538 reconf = true; 538 reconf = true;
539 else if (vrfb->xres != var->xres_virtual || 539 else if (vrfb->xres != var->xres_virtual ||
540 vrfb->yres != var->yres_virtual) 540 vrfb->yres != var->yres_virtual)
541 reconf = true; 541 reconf = true;
542 542
543 if (vrfb->vaddr[0] && reconf) { 543 if (vrfb->vaddr[0] && reconf) {
544 fbi->screen_base = NULL; 544 fbi->screen_base = NULL;
545 fix->smem_start = 0; 545 fix->smem_start = 0;
546 fix->smem_len = 0; 546 fix->smem_len = 0;
547 iounmap(vrfb->vaddr[0]); 547 iounmap(vrfb->vaddr[0]);
548 vrfb->vaddr[0] = NULL; 548 vrfb->vaddr[0] = NULL;
549 DBG("setup_vrfb_rotation: reset fb\n"); 549 DBG("setup_vrfb_rotation: reset fb\n");
550 } 550 }
551 551
552 if (vrfb->vaddr[0]) 552 if (vrfb->vaddr[0])
553 return 0; 553 return 0;
554 554
555 omap_vrfb_setup(&rg->vrfb, rg->paddr, 555 omap_vrfb_setup(&rg->vrfb, rg->paddr,
556 var->xres_virtual, 556 var->xres_virtual,
557 var->yres_virtual, 557 var->yres_virtual,
558 bytespp, yuv_mode); 558 bytespp, yuv_mode);
559 559
560 /* Now one can ioremap the 0 angle view */ 560 /* Now one can ioremap the 0 angle view */
561 r = omap_vrfb_map_angle(vrfb, var->yres_virtual, 0); 561 r = omap_vrfb_map_angle(vrfb, var->yres_virtual, 0);
562 if (r) 562 if (r)
563 return r; 563 return r;
564 564
565 /* used by open/write in fbmem.c */ 565 /* used by open/write in fbmem.c */
566 fbi->screen_base = ofbi->region->vrfb.vaddr[0]; 566 fbi->screen_base = ofbi->region->vrfb.vaddr[0];
567 567
568 fix->smem_start = ofbi->region->vrfb.paddr[0]; 568 fix->smem_start = ofbi->region->vrfb.paddr[0];
569 569
570 switch (var->nonstd) { 570 switch (var->nonstd) {
571 case OMAPFB_COLOR_YUV422: 571 case OMAPFB_COLOR_YUV422:
572 case OMAPFB_COLOR_YUY422: 572 case OMAPFB_COLOR_YUY422:
573 fix->line_length = 573 fix->line_length =
574 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 2; 574 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 2;
575 break; 575 break;
576 default: 576 default:
577 fix->line_length = 577 fix->line_length =
578 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3; 578 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3;
579 break; 579 break;
580 } 580 }
581 581
582 fix->smem_len = var->yres_virtual * fix->line_length; 582 fix->smem_len = var->yres_virtual * fix->line_length;
583 583
584 return 0; 584 return 0;
585 } 585 }
586 586
587 int dss_mode_to_fb_mode(enum omap_color_mode dssmode, 587 int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
588 struct fb_var_screeninfo *var) 588 struct fb_var_screeninfo *var)
589 { 589 {
590 int i; 590 int i;
591 591
592 for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) { 592 for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
593 struct omapfb_colormode *mode = &omapfb_colormodes[i]; 593 struct omapfb_colormode *mode = &omapfb_colormodes[i];
594 if (dssmode == mode->dssmode) { 594 if (dssmode == mode->dssmode) {
595 assign_colormode_to_var(var, mode); 595 assign_colormode_to_var(var, mode);
596 return 0; 596 return 0;
597 } 597 }
598 } 598 }
599 return -ENOENT; 599 return -ENOENT;
600 } 600 }
601 601
602 void set_fb_fix(struct fb_info *fbi) 602 void set_fb_fix(struct fb_info *fbi)
603 { 603 {
604 struct fb_fix_screeninfo *fix = &fbi->fix; 604 struct fb_fix_screeninfo *fix = &fbi->fix;
605 struct fb_var_screeninfo *var = &fbi->var; 605 struct fb_var_screeninfo *var = &fbi->var;
606 struct omapfb_info *ofbi = FB2OFB(fbi); 606 struct omapfb_info *ofbi = FB2OFB(fbi);
607 struct omapfb2_mem_region *rg = ofbi->region; 607 struct omapfb2_mem_region *rg = ofbi->region;
608 608
609 DBG("set_fb_fix\n"); 609 DBG("set_fb_fix\n");
610 610
611 /* used by open/write in fbmem.c */ 611 /* used by open/write in fbmem.c */
612 fbi->screen_base = (char __iomem *)omapfb_get_region_vaddr(ofbi); 612 fbi->screen_base = (char __iomem *)omapfb_get_region_vaddr(ofbi);
613 613
614 /* used by mmap in fbmem.c */ 614 /* used by mmap in fbmem.c */
615 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { 615 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
616 switch (var->nonstd) { 616 switch (var->nonstd) {
617 case OMAPFB_COLOR_YUV422: 617 case OMAPFB_COLOR_YUV422:
618 case OMAPFB_COLOR_YUY422: 618 case OMAPFB_COLOR_YUY422:
619 fix->line_length = 619 fix->line_length =
620 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 2; 620 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 2;
621 break; 621 break;
622 default: 622 default:
623 fix->line_length = 623 fix->line_length =
624 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3; 624 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3;
625 break; 625 break;
626 } 626 }
627 627
628 fix->smem_len = var->yres_virtual * fix->line_length; 628 fix->smem_len = var->yres_virtual * fix->line_length;
629 } else { 629 } else {
630 fix->line_length = 630 fix->line_length =
631 (var->xres_virtual * var->bits_per_pixel) >> 3; 631 (var->xres_virtual * var->bits_per_pixel) >> 3;
632 fix->smem_len = rg->size; 632 fix->smem_len = rg->size;
633 } 633 }
634 634
635 fix->smem_start = omapfb_get_region_paddr(ofbi); 635 fix->smem_start = omapfb_get_region_paddr(ofbi);
636 636
637 fix->type = FB_TYPE_PACKED_PIXELS; 637 fix->type = FB_TYPE_PACKED_PIXELS;
638 638
639 if (var->nonstd) 639 if (var->nonstd)
640 fix->visual = FB_VISUAL_PSEUDOCOLOR; 640 fix->visual = FB_VISUAL_PSEUDOCOLOR;
641 else { 641 else {
642 switch (var->bits_per_pixel) { 642 switch (var->bits_per_pixel) {
643 case 32: 643 case 32:
644 case 24: 644 case 24:
645 case 16: 645 case 16:
646 case 12: 646 case 12:
647 fix->visual = FB_VISUAL_TRUECOLOR; 647 fix->visual = FB_VISUAL_TRUECOLOR;
648 /* 12bpp is stored in 16 bits */ 648 /* 12bpp is stored in 16 bits */
649 break; 649 break;
650 case 1: 650 case 1:
651 case 2: 651 case 2:
652 case 4: 652 case 4:
653 case 8: 653 case 8:
654 fix->visual = FB_VISUAL_PSEUDOCOLOR; 654 fix->visual = FB_VISUAL_PSEUDOCOLOR;
655 break; 655 break;
656 } 656 }
657 } 657 }
658 658
659 fix->accel = FB_ACCEL_NONE; 659 fix->accel = FB_ACCEL_NONE;
660 660
661 fix->xpanstep = 1; 661 fix->xpanstep = 1;
662 fix->ypanstep = 1; 662 fix->ypanstep = 1;
663 } 663 }
664 664
665 /* check new var and possibly modify it to be ok */ 665 /* check new var and possibly modify it to be ok */
666 int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var) 666 int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
667 { 667 {
668 struct omapfb_info *ofbi = FB2OFB(fbi); 668 struct omapfb_info *ofbi = FB2OFB(fbi);
669 struct omap_dss_device *display = fb2display(fbi); 669 struct omap_dss_device *display = fb2display(fbi);
670 enum omap_color_mode mode = 0; 670 enum omap_color_mode mode = 0;
671 int i; 671 int i;
672 int r; 672 int r;
673 673
674 DBG("check_fb_var %d\n", ofbi->id); 674 DBG("check_fb_var %d\n", ofbi->id);
675 675
676 WARN_ON(!atomic_read(&ofbi->region->lock_count)); 676 WARN_ON(!atomic_read(&ofbi->region->lock_count));
677 677
678 r = fb_mode_to_dss_mode(var, &mode); 678 r = fb_mode_to_dss_mode(var, &mode);
679 if (r) { 679 if (r) {
680 DBG("cannot convert var to omap dss mode\n"); 680 DBG("cannot convert var to omap dss mode\n");
681 return r; 681 return r;
682 } 682 }
683 683
684 for (i = 0; i < ofbi->num_overlays; ++i) { 684 for (i = 0; i < ofbi->num_overlays; ++i) {
685 if ((ofbi->overlays[i]->supported_modes & mode) == 0) { 685 if ((ofbi->overlays[i]->supported_modes & mode) == 0) {
686 DBG("invalid mode\n"); 686 DBG("invalid mode\n");
687 return -EINVAL; 687 return -EINVAL;
688 } 688 }
689 } 689 }
690 690
691 if (var->rotate > 3) 691 if (var->rotate > 3)
692 return -EINVAL; 692 return -EINVAL;
693 693
694 if (check_fb_res_bounds(var)) 694 if (check_fb_res_bounds(var))
695 return -EINVAL; 695 return -EINVAL;
696 696
697 /* When no memory is allocated ignore the size check */ 697 /* When no memory is allocated ignore the size check */
698 if (ofbi->region->size != 0 && check_fb_size(ofbi, var)) 698 if (ofbi->region->size != 0 && check_fb_size(ofbi, var))
699 return -EINVAL; 699 return -EINVAL;
700 700
701 if (var->xres + var->xoffset > var->xres_virtual) 701 if (var->xres + var->xoffset > var->xres_virtual)
702 var->xoffset = var->xres_virtual - var->xres; 702 var->xoffset = var->xres_virtual - var->xres;
703 if (var->yres + var->yoffset > var->yres_virtual) 703 if (var->yres + var->yoffset > var->yres_virtual)
704 var->yoffset = var->yres_virtual - var->yres; 704 var->yoffset = var->yres_virtual - var->yres;
705 705
706 DBG("xres = %d, yres = %d, vxres = %d, vyres = %d\n", 706 DBG("xres = %d, yres = %d, vxres = %d, vyres = %d\n",
707 var->xres, var->yres, 707 var->xres, var->yres,
708 var->xres_virtual, var->yres_virtual); 708 var->xres_virtual, var->yres_virtual);
709 709
710 if (display && display->driver->get_dimensions) { 710 if (display && display->driver->get_dimensions) {
711 u32 w, h; 711 u32 w, h;
712 display->driver->get_dimensions(display, &w, &h); 712 display->driver->get_dimensions(display, &w, &h);
713 var->width = DIV_ROUND_CLOSEST(w, 1000); 713 var->width = DIV_ROUND_CLOSEST(w, 1000);
714 var->height = DIV_ROUND_CLOSEST(h, 1000); 714 var->height = DIV_ROUND_CLOSEST(h, 1000);
715 } else { 715 } else {
716 var->height = -1; 716 var->height = -1;
717 var->width = -1; 717 var->width = -1;
718 } 718 }
719 719
720 var->grayscale = 0; 720 var->grayscale = 0;
721 721
722 if (display && display->driver->get_timings) { 722 if (display && display->driver->get_timings) {
723 struct omap_video_timings timings; 723 struct omap_video_timings timings;
724 display->driver->get_timings(display, &timings); 724 display->driver->get_timings(display, &timings);
725 725
726 /* pixclock in ps, the rest in pixclock */ 726 /* pixclock in ps, the rest in pixclock */
727 var->pixclock = timings.pixel_clock != 0 ? 727 var->pixclock = timings.pixel_clock != 0 ?
728 KHZ2PICOS(timings.pixel_clock) : 728 KHZ2PICOS(timings.pixel_clock) :
729 0; 729 0;
730 var->left_margin = timings.hbp; 730 var->left_margin = timings.hbp;
731 var->right_margin = timings.hfp; 731 var->right_margin = timings.hfp;
732 var->upper_margin = timings.vbp; 732 var->upper_margin = timings.vbp;
733 var->lower_margin = timings.vfp; 733 var->lower_margin = timings.vfp;
734 var->hsync_len = timings.hsw; 734 var->hsync_len = timings.hsw;
735 var->vsync_len = timings.vsw; 735 var->vsync_len = timings.vsw;
736 var->sync |= timings.hsync_level == OMAPDSS_SIG_ACTIVE_HIGH ? 736 var->sync |= timings.hsync_level == OMAPDSS_SIG_ACTIVE_HIGH ?
737 FB_SYNC_HOR_HIGH_ACT : 0; 737 FB_SYNC_HOR_HIGH_ACT : 0;
738 var->sync |= timings.vsync_level == OMAPDSS_SIG_ACTIVE_HIGH ? 738 var->sync |= timings.vsync_level == OMAPDSS_SIG_ACTIVE_HIGH ?
739 FB_SYNC_VERT_HIGH_ACT : 0; 739 FB_SYNC_VERT_HIGH_ACT : 0;
740 var->vmode = timings.interlace ? 740 var->vmode = timings.interlace ?
741 FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED; 741 FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED;
742 } else { 742 } else {
743 var->pixclock = 0; 743 var->pixclock = 0;
744 var->left_margin = 0; 744 var->left_margin = 0;
745 var->right_margin = 0; 745 var->right_margin = 0;
746 var->upper_margin = 0; 746 var->upper_margin = 0;
747 var->lower_margin = 0; 747 var->lower_margin = 0;
748 var->hsync_len = 0; 748 var->hsync_len = 0;
749 var->vsync_len = 0; 749 var->vsync_len = 0;
750 var->sync = 0; 750 var->sync = 0;
751 var->vmode = FB_VMODE_NONINTERLACED; 751 var->vmode = FB_VMODE_NONINTERLACED;
752 } 752 }
753 753
754 return 0; 754 return 0;
755 } 755 }
756 756
757 /* 757 /*
758 * --------------------------------------------------------------------------- 758 * ---------------------------------------------------------------------------
759 * fbdev framework callbacks 759 * fbdev framework callbacks
760 * --------------------------------------------------------------------------- 760 * ---------------------------------------------------------------------------
761 */ 761 */
762 static int omapfb_open(struct fb_info *fbi, int user) 762 static int omapfb_open(struct fb_info *fbi, int user)
763 { 763 {
764 return 0; 764 return 0;
765 } 765 }
766 766
767 static int omapfb_release(struct fb_info *fbi, int user) 767 static int omapfb_release(struct fb_info *fbi, int user)
768 { 768 {
769 return 0; 769 return 0;
770 } 770 }
771 771
772 static unsigned calc_rotation_offset_dma(const struct fb_var_screeninfo *var, 772 static unsigned calc_rotation_offset_dma(const struct fb_var_screeninfo *var,
773 const struct fb_fix_screeninfo *fix, int rotation) 773 const struct fb_fix_screeninfo *fix, int rotation)
774 { 774 {
775 unsigned offset; 775 unsigned offset;
776 776
777 offset = var->yoffset * fix->line_length + 777 offset = var->yoffset * fix->line_length +
778 var->xoffset * (var->bits_per_pixel >> 3); 778 var->xoffset * (var->bits_per_pixel >> 3);
779 779
780 return offset; 780 return offset;
781 } 781 }
782 782
783 static unsigned calc_rotation_offset_vrfb(const struct fb_var_screeninfo *var, 783 static unsigned calc_rotation_offset_vrfb(const struct fb_var_screeninfo *var,
784 const struct fb_fix_screeninfo *fix, int rotation) 784 const struct fb_fix_screeninfo *fix, int rotation)
785 { 785 {
786 unsigned offset; 786 unsigned offset;
787 787
788 if (rotation == FB_ROTATE_UD) 788 if (rotation == FB_ROTATE_UD)
789 offset = (var->yres_virtual - var->yres) * 789 offset = (var->yres_virtual - var->yres) *
790 fix->line_length; 790 fix->line_length;
791 else if (rotation == FB_ROTATE_CW) 791 else if (rotation == FB_ROTATE_CW)
792 offset = (var->yres_virtual - var->yres) * 792 offset = (var->yres_virtual - var->yres) *
793 (var->bits_per_pixel >> 3); 793 (var->bits_per_pixel >> 3);
794 else 794 else
795 offset = 0; 795 offset = 0;
796 796
797 if (rotation == FB_ROTATE_UR) 797 if (rotation == FB_ROTATE_UR)
798 offset += var->yoffset * fix->line_length + 798 offset += var->yoffset * fix->line_length +
799 var->xoffset * (var->bits_per_pixel >> 3); 799 var->xoffset * (var->bits_per_pixel >> 3);
800 else if (rotation == FB_ROTATE_UD) 800 else if (rotation == FB_ROTATE_UD)
801 offset -= var->yoffset * fix->line_length + 801 offset -= var->yoffset * fix->line_length +
802 var->xoffset * (var->bits_per_pixel >> 3); 802 var->xoffset * (var->bits_per_pixel >> 3);
803 else if (rotation == FB_ROTATE_CW) 803 else if (rotation == FB_ROTATE_CW)
804 offset -= var->xoffset * fix->line_length + 804 offset -= var->xoffset * fix->line_length +
805 var->yoffset * (var->bits_per_pixel >> 3); 805 var->yoffset * (var->bits_per_pixel >> 3);
806 else if (rotation == FB_ROTATE_CCW) 806 else if (rotation == FB_ROTATE_CCW)
807 offset += var->xoffset * fix->line_length + 807 offset += var->xoffset * fix->line_length +
808 var->yoffset * (var->bits_per_pixel >> 3); 808 var->yoffset * (var->bits_per_pixel >> 3);
809 809
810 return offset; 810 return offset;
811 } 811 }
812 812
813 static void omapfb_calc_addr(const struct omapfb_info *ofbi, 813 static void omapfb_calc_addr(const struct omapfb_info *ofbi,
814 const struct fb_var_screeninfo *var, 814 const struct fb_var_screeninfo *var,
815 const struct fb_fix_screeninfo *fix, 815 const struct fb_fix_screeninfo *fix,
816 int rotation, u32 *paddr) 816 int rotation, u32 *paddr)
817 { 817 {
818 u32 data_start_p; 818 u32 data_start_p;
819 int offset; 819 int offset;
820 820
821 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) 821 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
822 data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation); 822 data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation);
823 else 823 else
824 data_start_p = omapfb_get_region_paddr(ofbi); 824 data_start_p = omapfb_get_region_paddr(ofbi);
825 825
826 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) 826 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
827 offset = calc_rotation_offset_vrfb(var, fix, rotation); 827 offset = calc_rotation_offset_vrfb(var, fix, rotation);
828 else 828 else
829 offset = calc_rotation_offset_dma(var, fix, rotation); 829 offset = calc_rotation_offset_dma(var, fix, rotation);
830 830
831 data_start_p += offset; 831 data_start_p += offset;
832 832
833 if (offset) 833 if (offset)
834 DBG("offset %d, %d = %d\n", 834 DBG("offset %d, %d = %d\n",
835 var->xoffset, var->yoffset, offset); 835 var->xoffset, var->yoffset, offset);
836 836
837 DBG("paddr %x\n", data_start_p); 837 DBG("paddr %x\n", data_start_p);
838 838
839 *paddr = data_start_p; 839 *paddr = data_start_p;
840 } 840 }
841 841
842 /* setup overlay according to the fb */ 842 /* setup overlay according to the fb */
843 int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, 843 int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
844 u16 posx, u16 posy, u16 outw, u16 outh) 844 u16 posx, u16 posy, u16 outw, u16 outh)
845 { 845 {
846 int r = 0; 846 int r = 0;
847 struct omapfb_info *ofbi = FB2OFB(fbi); 847 struct omapfb_info *ofbi = FB2OFB(fbi);
848 struct fb_var_screeninfo *var = &fbi->var; 848 struct fb_var_screeninfo *var = &fbi->var;
849 struct fb_fix_screeninfo *fix = &fbi->fix; 849 struct fb_fix_screeninfo *fix = &fbi->fix;
850 enum omap_color_mode mode = 0; 850 enum omap_color_mode mode = 0;
851 u32 data_start_p = 0; 851 u32 data_start_p = 0;
852 struct omap_overlay_info info; 852 struct omap_overlay_info info;
853 int xres, yres; 853 int xres, yres;
854 int screen_width; 854 int screen_width;
855 int mirror; 855 int mirror;
856 int rotation = var->rotate; 856 int rotation = var->rotate;
857 int i; 857 int i;
858 858
859 WARN_ON(!atomic_read(&ofbi->region->lock_count)); 859 WARN_ON(!atomic_read(&ofbi->region->lock_count));
860 860
861 for (i = 0; i < ofbi->num_overlays; i++) { 861 for (i = 0; i < ofbi->num_overlays; i++) {
862 if (ovl != ofbi->overlays[i]) 862 if (ovl != ofbi->overlays[i])
863 continue; 863 continue;
864 864
865 rotation = (rotation + ofbi->rotation[i]) % 4; 865 rotation = (rotation + ofbi->rotation[i]) % 4;
866 break; 866 break;
867 } 867 }
868 868
869 DBG("setup_overlay %d, posx %d, posy %d, outw %d, outh %d\n", ofbi->id, 869 DBG("setup_overlay %d, posx %d, posy %d, outw %d, outh %d\n", ofbi->id,
870 posx, posy, outw, outh); 870 posx, posy, outw, outh);
871 871
872 if (rotation == FB_ROTATE_CW || rotation == FB_ROTATE_CCW) { 872 if (rotation == FB_ROTATE_CW || rotation == FB_ROTATE_CCW) {
873 xres = var->yres; 873 xres = var->yres;
874 yres = var->xres; 874 yres = var->xres;
875 } else { 875 } else {
876 xres = var->xres; 876 xres = var->xres;
877 yres = var->yres; 877 yres = var->yres;
878 } 878 }
879 879
880 if (ofbi->region->size) 880 if (ofbi->region->size)
881 omapfb_calc_addr(ofbi, var, fix, rotation, &data_start_p); 881 omapfb_calc_addr(ofbi, var, fix, rotation, &data_start_p);
882 882
883 r = fb_mode_to_dss_mode(var, &mode); 883 r = fb_mode_to_dss_mode(var, &mode);
884 if (r) { 884 if (r) {
885 DBG("fb_mode_to_dss_mode failed"); 885 DBG("fb_mode_to_dss_mode failed");
886 goto err; 886 goto err;
887 } 887 }
888 888
889 switch (var->nonstd) { 889 switch (var->nonstd) {
890 case OMAPFB_COLOR_YUV422: 890 case OMAPFB_COLOR_YUV422:
891 case OMAPFB_COLOR_YUY422: 891 case OMAPFB_COLOR_YUY422:
892 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { 892 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
893 screen_width = fix->line_length 893 screen_width = fix->line_length
894 / (var->bits_per_pixel >> 2); 894 / (var->bits_per_pixel >> 2);
895 break; 895 break;
896 } 896 }
897 default: 897 default:
898 screen_width = fix->line_length / (var->bits_per_pixel >> 3); 898 screen_width = fix->line_length / (var->bits_per_pixel >> 3);
899 break; 899 break;
900 } 900 }
901 901
902 ovl->get_overlay_info(ovl, &info); 902 ovl->get_overlay_info(ovl, &info);
903 903
904 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) 904 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
905 mirror = 0; 905 mirror = 0;
906 else 906 else
907 mirror = ofbi->mirror; 907 mirror = ofbi->mirror;
908 908
909 info.paddr = data_start_p; 909 info.paddr = data_start_p;
910 info.screen_width = screen_width; 910 info.screen_width = screen_width;
911 info.width = xres; 911 info.width = xres;
912 info.height = yres; 912 info.height = yres;
913 info.color_mode = mode; 913 info.color_mode = mode;
914 info.rotation_type = ofbi->rotation_type; 914 info.rotation_type = ofbi->rotation_type;
915 info.rotation = rotation; 915 info.rotation = rotation;
916 info.mirror = mirror; 916 info.mirror = mirror;
917 917
918 info.pos_x = posx; 918 info.pos_x = posx;
919 info.pos_y = posy; 919 info.pos_y = posy;
920 info.out_width = outw; 920 info.out_width = outw;
921 info.out_height = outh; 921 info.out_height = outh;
922 922
923 r = ovl->set_overlay_info(ovl, &info); 923 r = ovl->set_overlay_info(ovl, &info);
924 if (r) { 924 if (r) {
925 DBG("ovl->setup_overlay_info failed\n"); 925 DBG("ovl->setup_overlay_info failed\n");
926 goto err; 926 goto err;
927 } 927 }
928 928
929 return 0; 929 return 0;
930 930
931 err: 931 err:
932 DBG("setup_overlay failed\n"); 932 DBG("setup_overlay failed\n");
933 return r; 933 return r;
934 } 934 }
935 935
936 /* apply var to the overlay */ 936 /* apply var to the overlay */
937 int omapfb_apply_changes(struct fb_info *fbi, int init) 937 int omapfb_apply_changes(struct fb_info *fbi, int init)
938 { 938 {
939 int r = 0; 939 int r = 0;
940 struct omapfb_info *ofbi = FB2OFB(fbi); 940 struct omapfb_info *ofbi = FB2OFB(fbi);
941 struct fb_var_screeninfo *var = &fbi->var; 941 struct fb_var_screeninfo *var = &fbi->var;
942 struct omap_overlay *ovl; 942 struct omap_overlay *ovl;
943 u16 posx, posy; 943 u16 posx, posy;
944 u16 outw, outh; 944 u16 outw, outh;
945 int i; 945 int i;
946 946
947 #ifdef DEBUG 947 #ifdef DEBUG
948 if (omapfb_test_pattern) 948 if (omapfb_test_pattern)
949 fill_fb(fbi); 949 fill_fb(fbi);
950 #endif 950 #endif
951 951
952 WARN_ON(!atomic_read(&ofbi->region->lock_count)); 952 WARN_ON(!atomic_read(&ofbi->region->lock_count));
953 953
954 for (i = 0; i < ofbi->num_overlays; i++) { 954 for (i = 0; i < ofbi->num_overlays; i++) {
955 ovl = ofbi->overlays[i]; 955 ovl = ofbi->overlays[i];
956 956
957 DBG("apply_changes, fb %d, ovl %d\n", ofbi->id, ovl->id); 957 DBG("apply_changes, fb %d, ovl %d\n", ofbi->id, ovl->id);
958 958
959 if (ofbi->region->size == 0) { 959 if (ofbi->region->size == 0) {
960 /* the fb is not available. disable the overlay */ 960 /* the fb is not available. disable the overlay */
961 omapfb_overlay_enable(ovl, 0); 961 omapfb_overlay_enable(ovl, 0);
962 if (!init && ovl->manager) 962 if (!init && ovl->manager)
963 ovl->manager->apply(ovl->manager); 963 ovl->manager->apply(ovl->manager);
964 continue; 964 continue;
965 } 965 }
966 966
967 if (init || (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { 967 if (init || (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
968 int rotation = (var->rotate + ofbi->rotation[i]) % 4; 968 int rotation = (var->rotate + ofbi->rotation[i]) % 4;
969 if (rotation == FB_ROTATE_CW || 969 if (rotation == FB_ROTATE_CW ||
970 rotation == FB_ROTATE_CCW) { 970 rotation == FB_ROTATE_CCW) {
971 outw = var->yres; 971 outw = var->yres;
972 outh = var->xres; 972 outh = var->xres;
973 } else { 973 } else {
974 outw = var->xres; 974 outw = var->xres;
975 outh = var->yres; 975 outh = var->yres;
976 } 976 }
977 } else { 977 } else {
978 struct omap_overlay_info info; 978 struct omap_overlay_info info;
979 ovl->get_overlay_info(ovl, &info); 979 ovl->get_overlay_info(ovl, &info);
980 outw = info.out_width; 980 outw = info.out_width;
981 outh = info.out_height; 981 outh = info.out_height;
982 } 982 }
983 983
984 if (init) { 984 if (init) {
985 posx = 0; 985 posx = 0;
986 posy = 0; 986 posy = 0;
987 } else { 987 } else {
988 struct omap_overlay_info info; 988 struct omap_overlay_info info;
989 ovl->get_overlay_info(ovl, &info); 989 ovl->get_overlay_info(ovl, &info);
990 posx = info.pos_x; 990 posx = info.pos_x;
991 posy = info.pos_y; 991 posy = info.pos_y;
992 } 992 }
993 993
994 r = omapfb_setup_overlay(fbi, ovl, posx, posy, outw, outh); 994 r = omapfb_setup_overlay(fbi, ovl, posx, posy, outw, outh);
995 if (r) 995 if (r)
996 goto err; 996 goto err;
997 997
998 if (!init && ovl->manager) 998 if (!init && ovl->manager)
999 ovl->manager->apply(ovl->manager); 999 ovl->manager->apply(ovl->manager);
1000 } 1000 }
1001 return 0; 1001 return 0;
1002 err: 1002 err:
1003 DBG("apply_changes failed\n"); 1003 DBG("apply_changes failed\n");
1004 return r; 1004 return r;
1005 } 1005 }
1006 1006
1007 /* checks var and eventually tweaks it to something supported, 1007 /* checks var and eventually tweaks it to something supported,
1008 * DO NOT MODIFY PAR */ 1008 * DO NOT MODIFY PAR */
1009 static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi) 1009 static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
1010 { 1010 {
1011 struct omapfb_info *ofbi = FB2OFB(fbi); 1011 struct omapfb_info *ofbi = FB2OFB(fbi);
1012 int r; 1012 int r;
1013 1013
1014 DBG("check_var(%d)\n", FB2OFB(fbi)->id); 1014 DBG("check_var(%d)\n", FB2OFB(fbi)->id);
1015 1015
1016 omapfb_get_mem_region(ofbi->region); 1016 omapfb_get_mem_region(ofbi->region);
1017 1017
1018 r = check_fb_var(fbi, var); 1018 r = check_fb_var(fbi, var);
1019 1019
1020 omapfb_put_mem_region(ofbi->region); 1020 omapfb_put_mem_region(ofbi->region);
1021 1021
1022 return r; 1022 return r;
1023 } 1023 }
1024 1024
1025 /* set the video mode according to info->var */ 1025 /* set the video mode according to info->var */
1026 static int omapfb_set_par(struct fb_info *fbi) 1026 static int omapfb_set_par(struct fb_info *fbi)
1027 { 1027 {
1028 struct omapfb_info *ofbi = FB2OFB(fbi); 1028 struct omapfb_info *ofbi = FB2OFB(fbi);
1029 int r; 1029 int r;
1030 1030
1031 DBG("set_par(%d)\n", FB2OFB(fbi)->id); 1031 DBG("set_par(%d)\n", FB2OFB(fbi)->id);
1032 1032
1033 omapfb_get_mem_region(ofbi->region); 1033 omapfb_get_mem_region(ofbi->region);
1034 1034
1035 set_fb_fix(fbi); 1035 set_fb_fix(fbi);
1036 1036
1037 r = setup_vrfb_rotation(fbi); 1037 r = setup_vrfb_rotation(fbi);
1038 if (r) 1038 if (r)
1039 goto out; 1039 goto out;
1040 1040
1041 r = omapfb_apply_changes(fbi, 0); 1041 r = omapfb_apply_changes(fbi, 0);
1042 1042
1043 out: 1043 out:
1044 omapfb_put_mem_region(ofbi->region); 1044 omapfb_put_mem_region(ofbi->region);
1045 1045
1046 return r; 1046 return r;
1047 } 1047 }
1048 1048
1049 static int omapfb_pan_display(struct fb_var_screeninfo *var, 1049 static int omapfb_pan_display(struct fb_var_screeninfo *var,
1050 struct fb_info *fbi) 1050 struct fb_info *fbi)
1051 { 1051 {
1052 struct omapfb_info *ofbi = FB2OFB(fbi); 1052 struct omapfb_info *ofbi = FB2OFB(fbi);
1053 struct fb_var_screeninfo new_var; 1053 struct fb_var_screeninfo new_var;
1054 int r; 1054 int r;
1055 1055
1056 DBG("pan_display(%d)\n", FB2OFB(fbi)->id); 1056 DBG("pan_display(%d)\n", FB2OFB(fbi)->id);
1057 1057
1058 if (var->xoffset == fbi->var.xoffset && 1058 if (var->xoffset == fbi->var.xoffset &&
1059 var->yoffset == fbi->var.yoffset) 1059 var->yoffset == fbi->var.yoffset)
1060 return 0; 1060 return 0;
1061 1061
1062 new_var = fbi->var; 1062 new_var = fbi->var;
1063 new_var.xoffset = var->xoffset; 1063 new_var.xoffset = var->xoffset;
1064 new_var.yoffset = var->yoffset; 1064 new_var.yoffset = var->yoffset;
1065 1065
1066 fbi->var = new_var; 1066 fbi->var = new_var;
1067 1067
1068 omapfb_get_mem_region(ofbi->region); 1068 omapfb_get_mem_region(ofbi->region);
1069 1069
1070 r = omapfb_apply_changes(fbi, 0); 1070 r = omapfb_apply_changes(fbi, 0);
1071 1071
1072 omapfb_put_mem_region(ofbi->region); 1072 omapfb_put_mem_region(ofbi->region);
1073 1073
1074 return r; 1074 return r;
1075 } 1075 }
1076 1076
1077 static void mmap_user_open(struct vm_area_struct *vma) 1077 static void mmap_user_open(struct vm_area_struct *vma)
1078 { 1078 {
1079 struct omapfb2_mem_region *rg = vma->vm_private_data; 1079 struct omapfb2_mem_region *rg = vma->vm_private_data;
1080 1080
1081 omapfb_get_mem_region(rg); 1081 omapfb_get_mem_region(rg);
1082 atomic_inc(&rg->map_count); 1082 atomic_inc(&rg->map_count);
1083 omapfb_put_mem_region(rg); 1083 omapfb_put_mem_region(rg);
1084 } 1084 }
1085 1085
1086 static void mmap_user_close(struct vm_area_struct *vma) 1086 static void mmap_user_close(struct vm_area_struct *vma)
1087 { 1087 {
1088 struct omapfb2_mem_region *rg = vma->vm_private_data; 1088 struct omapfb2_mem_region *rg = vma->vm_private_data;
1089 1089
1090 omapfb_get_mem_region(rg); 1090 omapfb_get_mem_region(rg);
1091 atomic_dec(&rg->map_count); 1091 atomic_dec(&rg->map_count);
1092 omapfb_put_mem_region(rg); 1092 omapfb_put_mem_region(rg);
1093 } 1093 }
1094 1094
1095 static struct vm_operations_struct mmap_user_ops = { 1095 static struct vm_operations_struct mmap_user_ops = {
1096 .open = mmap_user_open, 1096 .open = mmap_user_open,
1097 .close = mmap_user_close, 1097 .close = mmap_user_close,
1098 }; 1098 };
1099 1099
1100 static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) 1100 static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
1101 { 1101 {
1102 struct omapfb_info *ofbi = FB2OFB(fbi); 1102 struct omapfb_info *ofbi = FB2OFB(fbi);
1103 struct fb_fix_screeninfo *fix = &fbi->fix; 1103 struct fb_fix_screeninfo *fix = &fbi->fix;
1104 struct omapfb2_mem_region *rg; 1104 struct omapfb2_mem_region *rg;
1105 unsigned long off; 1105 unsigned long off;
1106 unsigned long start; 1106 unsigned long start;
1107 u32 len; 1107 u32 len;
1108 int r = -EINVAL; 1108 int r = -EINVAL;
1109 1109
1110 if (vma->vm_end - vma->vm_start == 0) 1110 if (vma->vm_end - vma->vm_start == 0)
1111 return 0; 1111 return 0;
1112 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) 1112 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
1113 return -EINVAL; 1113 return -EINVAL;
1114 off = vma->vm_pgoff << PAGE_SHIFT; 1114 off = vma->vm_pgoff << PAGE_SHIFT;
1115 1115
1116 rg = omapfb_get_mem_region(ofbi->region); 1116 rg = omapfb_get_mem_region(ofbi->region);
1117 1117
1118 start = omapfb_get_region_paddr(ofbi); 1118 start = omapfb_get_region_paddr(ofbi);
1119 len = fix->smem_len; 1119 len = fix->smem_len;
1120 if (off >= len) 1120 if (off >= len)
1121 goto error; 1121 goto error;
1122 if ((vma->vm_end - vma->vm_start + off) > len) 1122 if ((vma->vm_end - vma->vm_start + off) > len)
1123 goto error; 1123 goto error;
1124 1124
1125 off += start; 1125 off += start;
1126 1126
1127 DBG("user mmap region start %lx, len %d, off %lx\n", start, len, off); 1127 DBG("user mmap region start %lx, len %d, off %lx\n", start, len, off);
1128 1128
1129 vma->vm_pgoff = off >> PAGE_SHIFT; 1129 vma->vm_pgoff = off >> PAGE_SHIFT;
1130 vma->vm_flags |= VM_IO | VM_RESERVED; 1130 vma->vm_flags |= VM_IO | VM_RESERVED;
1131 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); 1131 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
1132 vma->vm_ops = &mmap_user_ops; 1132 vma->vm_ops = &mmap_user_ops;
1133 vma->vm_private_data = rg; 1133 vma->vm_private_data = rg;
1134 if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, 1134 if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
1135 vma->vm_end - vma->vm_start, 1135 vma->vm_end - vma->vm_start,
1136 vma->vm_page_prot)) { 1136 vma->vm_page_prot)) {
1137 r = -EAGAIN; 1137 r = -EAGAIN;
1138 goto error; 1138 goto error;
1139 } 1139 }
1140 1140
1141 /* vm_ops.open won't be called for mmap itself. */ 1141 /* vm_ops.open won't be called for mmap itself. */
1142 atomic_inc(&rg->map_count); 1142 atomic_inc(&rg->map_count);
1143 1143
1144 omapfb_put_mem_region(rg); 1144 omapfb_put_mem_region(rg);
1145 1145
1146 return 0; 1146 return 0;
1147 1147
1148 error: 1148 error:
1149 omapfb_put_mem_region(ofbi->region); 1149 omapfb_put_mem_region(ofbi->region);
1150 1150
1151 return r; 1151 return r;
1152 } 1152 }
1153 1153
1154 /* Store a single color palette entry into a pseudo palette or the hardware 1154 /* Store a single color palette entry into a pseudo palette or the hardware
1155 * palette if one is available. For now we support only 16bpp and thus store 1155 * palette if one is available. For now we support only 16bpp and thus store
1156 * the entry only to the pseudo palette. 1156 * the entry only to the pseudo palette.
1157 */ 1157 */
1158 static int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green, 1158 static int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green,
1159 u_int blue, u_int transp, int update_hw_pal) 1159 u_int blue, u_int transp, int update_hw_pal)
1160 { 1160 {
1161 /*struct omapfb_info *ofbi = FB2OFB(fbi);*/ 1161 /*struct omapfb_info *ofbi = FB2OFB(fbi);*/
1162 /*struct omapfb2_device *fbdev = ofbi->fbdev;*/ 1162 /*struct omapfb2_device *fbdev = ofbi->fbdev;*/
1163 struct fb_var_screeninfo *var = &fbi->var; 1163 struct fb_var_screeninfo *var = &fbi->var;
1164 int r = 0; 1164 int r = 0;
1165 1165
1166 enum omapfb_color_format mode = OMAPFB_COLOR_RGB24U; /* XXX */ 1166 enum omapfb_color_format mode = OMAPFB_COLOR_RGB24U; /* XXX */
1167 1167
1168 /*switch (plane->color_mode) {*/ 1168 /*switch (plane->color_mode) {*/
1169 switch (mode) { 1169 switch (mode) {
1170 case OMAPFB_COLOR_YUV422: 1170 case OMAPFB_COLOR_YUV422:
1171 case OMAPFB_COLOR_YUV420: 1171 case OMAPFB_COLOR_YUV420:
1172 case OMAPFB_COLOR_YUY422: 1172 case OMAPFB_COLOR_YUY422:
1173 r = -EINVAL; 1173 r = -EINVAL;
1174 break; 1174 break;
1175 case OMAPFB_COLOR_CLUT_8BPP: 1175 case OMAPFB_COLOR_CLUT_8BPP:
1176 case OMAPFB_COLOR_CLUT_4BPP: 1176 case OMAPFB_COLOR_CLUT_4BPP:
1177 case OMAPFB_COLOR_CLUT_2BPP: 1177 case OMAPFB_COLOR_CLUT_2BPP:
1178 case OMAPFB_COLOR_CLUT_1BPP: 1178 case OMAPFB_COLOR_CLUT_1BPP:
1179 /* 1179 /*
1180 if (fbdev->ctrl->setcolreg) 1180 if (fbdev->ctrl->setcolreg)
1181 r = fbdev->ctrl->setcolreg(regno, red, green, blue, 1181 r = fbdev->ctrl->setcolreg(regno, red, green, blue,
1182 transp, update_hw_pal); 1182 transp, update_hw_pal);
1183 */ 1183 */
1184 /* Fallthrough */ 1184 /* Fallthrough */
1185 r = -EINVAL; 1185 r = -EINVAL;
1186 break; 1186 break;
1187 case OMAPFB_COLOR_RGB565: 1187 case OMAPFB_COLOR_RGB565:
1188 case OMAPFB_COLOR_RGB444: 1188 case OMAPFB_COLOR_RGB444:
1189 case OMAPFB_COLOR_RGB24P: 1189 case OMAPFB_COLOR_RGB24P:
1190 case OMAPFB_COLOR_RGB24U: 1190 case OMAPFB_COLOR_RGB24U:
1191 if (r != 0) 1191 if (r != 0)
1192 break; 1192 break;
1193 1193
1194 if (regno < 16) { 1194 if (regno < 16) {
1195 u16 pal; 1195 u32 pal;
1196 pal = ((red >> (16 - var->red.length)) << 1196 pal = ((red >> (16 - var->red.length)) <<
1197 var->red.offset) | 1197 var->red.offset) |
1198 ((green >> (16 - var->green.length)) << 1198 ((green >> (16 - var->green.length)) <<
1199 var->green.offset) | 1199 var->green.offset) |
1200 (blue >> (16 - var->blue.length)); 1200 (blue >> (16 - var->blue.length));
1201 ((u32 *)(fbi->pseudo_palette))[regno] = pal; 1201 ((u32 *)(fbi->pseudo_palette))[regno] = pal;
1202 } 1202 }
1203 break; 1203 break;
1204 default: 1204 default:
1205 BUG(); 1205 BUG();
1206 } 1206 }
1207 return r; 1207 return r;
1208 } 1208 }
1209 1209
1210 static int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 1210 static int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
1211 u_int transp, struct fb_info *info) 1211 u_int transp, struct fb_info *info)
1212 { 1212 {
1213 DBG("setcolreg\n"); 1213 DBG("setcolreg\n");
1214 1214
1215 return _setcolreg(info, regno, red, green, blue, transp, 1); 1215 return _setcolreg(info, regno, red, green, blue, transp, 1);
1216 } 1216 }
1217 1217
1218 static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info) 1218 static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
1219 { 1219 {
1220 int count, index, r; 1220 int count, index, r;
1221 u16 *red, *green, *blue, *transp; 1221 u16 *red, *green, *blue, *transp;
1222 u16 trans = 0xffff; 1222 u16 trans = 0xffff;
1223 1223
1224 DBG("setcmap\n"); 1224 DBG("setcmap\n");
1225 1225
1226 red = cmap->red; 1226 red = cmap->red;
1227 green = cmap->green; 1227 green = cmap->green;
1228 blue = cmap->blue; 1228 blue = cmap->blue;
1229 transp = cmap->transp; 1229 transp = cmap->transp;
1230 index = cmap->start; 1230 index = cmap->start;
1231 1231
1232 for (count = 0; count < cmap->len; count++) { 1232 for (count = 0; count < cmap->len; count++) {
1233 if (transp) 1233 if (transp)
1234 trans = *transp++; 1234 trans = *transp++;
1235 r = _setcolreg(info, index++, *red++, *green++, *blue++, trans, 1235 r = _setcolreg(info, index++, *red++, *green++, *blue++, trans,
1236 count == cmap->len - 1); 1236 count == cmap->len - 1);
1237 if (r != 0) 1237 if (r != 0)
1238 return r; 1238 return r;
1239 } 1239 }
1240 1240
1241 return 0; 1241 return 0;
1242 } 1242 }
1243 1243
1244 static int omapfb_blank(int blank, struct fb_info *fbi) 1244 static int omapfb_blank(int blank, struct fb_info *fbi)
1245 { 1245 {
1246 struct omapfb_info *ofbi = FB2OFB(fbi); 1246 struct omapfb_info *ofbi = FB2OFB(fbi);
1247 struct omapfb2_device *fbdev = ofbi->fbdev; 1247 struct omapfb2_device *fbdev = ofbi->fbdev;
1248 struct omap_dss_device *display = fb2display(fbi); 1248 struct omap_dss_device *display = fb2display(fbi);
1249 struct omapfb_display_data *d; 1249 struct omapfb_display_data *d;
1250 int r = 0; 1250 int r = 0;
1251 1251
1252 if (!display) 1252 if (!display)
1253 return -EINVAL; 1253 return -EINVAL;
1254 1254
1255 omapfb_lock(fbdev); 1255 omapfb_lock(fbdev);
1256 1256
1257 d = get_display_data(fbdev, display); 1257 d = get_display_data(fbdev, display);
1258 1258
1259 switch (blank) { 1259 switch (blank) {
1260 case FB_BLANK_UNBLANK: 1260 case FB_BLANK_UNBLANK:
1261 if (display->state != OMAP_DSS_DISPLAY_SUSPENDED) 1261 if (display->state != OMAP_DSS_DISPLAY_SUSPENDED)
1262 goto exit; 1262 goto exit;
1263 1263
1264 if (display->driver->resume) 1264 if (display->driver->resume)
1265 r = display->driver->resume(display); 1265 r = display->driver->resume(display);
1266 1266
1267 if ((display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) && 1267 if ((display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) &&
1268 d->update_mode == OMAPFB_AUTO_UPDATE && 1268 d->update_mode == OMAPFB_AUTO_UPDATE &&
1269 !d->auto_update_work_enabled) 1269 !d->auto_update_work_enabled)
1270 omapfb_start_auto_update(fbdev, display); 1270 omapfb_start_auto_update(fbdev, display);
1271 1271
1272 break; 1272 break;
1273 1273
1274 case FB_BLANK_NORMAL: 1274 case FB_BLANK_NORMAL:
1275 /* FB_BLANK_NORMAL could be implemented. 1275 /* FB_BLANK_NORMAL could be implemented.
1276 * Needs DSS additions. */ 1276 * Needs DSS additions. */
1277 case FB_BLANK_VSYNC_SUSPEND: 1277 case FB_BLANK_VSYNC_SUSPEND:
1278 case FB_BLANK_HSYNC_SUSPEND: 1278 case FB_BLANK_HSYNC_SUSPEND:
1279 case FB_BLANK_POWERDOWN: 1279 case FB_BLANK_POWERDOWN:
1280 if (display->state != OMAP_DSS_DISPLAY_ACTIVE) 1280 if (display->state != OMAP_DSS_DISPLAY_ACTIVE)
1281 goto exit; 1281 goto exit;
1282 1282
1283 if (d->auto_update_work_enabled) 1283 if (d->auto_update_work_enabled)
1284 omapfb_stop_auto_update(fbdev, display); 1284 omapfb_stop_auto_update(fbdev, display);
1285 1285
1286 if (display->driver->suspend) 1286 if (display->driver->suspend)
1287 r = display->driver->suspend(display); 1287 r = display->driver->suspend(display);
1288 1288
1289 break; 1289 break;
1290 1290
1291 default: 1291 default:
1292 r = -EINVAL; 1292 r = -EINVAL;
1293 } 1293 }
1294 1294
1295 exit: 1295 exit:
1296 omapfb_unlock(fbdev); 1296 omapfb_unlock(fbdev);
1297 1297
1298 return r; 1298 return r;
1299 } 1299 }
1300 1300
1301 #if 0 1301 #if 0
1302 /* XXX fb_read and fb_write are needed for VRFB */ 1302 /* XXX fb_read and fb_write are needed for VRFB */
1303 ssize_t omapfb_write(struct fb_info *info, const char __user *buf, 1303 ssize_t omapfb_write(struct fb_info *info, const char __user *buf,
1304 size_t count, loff_t *ppos) 1304 size_t count, loff_t *ppos)
1305 { 1305 {
1306 DBG("omapfb_write %d, %lu\n", count, (unsigned long)*ppos); 1306 DBG("omapfb_write %d, %lu\n", count, (unsigned long)*ppos);
1307 /* XXX needed for VRFB */ 1307 /* XXX needed for VRFB */
1308 return count; 1308 return count;
1309 } 1309 }
1310 #endif 1310 #endif
1311 1311
1312 static struct fb_ops omapfb_ops = { 1312 static struct fb_ops omapfb_ops = {
1313 .owner = THIS_MODULE, 1313 .owner = THIS_MODULE,
1314 .fb_open = omapfb_open, 1314 .fb_open = omapfb_open,
1315 .fb_release = omapfb_release, 1315 .fb_release = omapfb_release,
1316 .fb_fillrect = cfb_fillrect, 1316 .fb_fillrect = cfb_fillrect,
1317 .fb_copyarea = cfb_copyarea, 1317 .fb_copyarea = cfb_copyarea,
1318 .fb_imageblit = cfb_imageblit, 1318 .fb_imageblit = cfb_imageblit,
1319 .fb_blank = omapfb_blank, 1319 .fb_blank = omapfb_blank,
1320 .fb_ioctl = omapfb_ioctl, 1320 .fb_ioctl = omapfb_ioctl,
1321 .fb_check_var = omapfb_check_var, 1321 .fb_check_var = omapfb_check_var,
1322 .fb_set_par = omapfb_set_par, 1322 .fb_set_par = omapfb_set_par,
1323 .fb_pan_display = omapfb_pan_display, 1323 .fb_pan_display = omapfb_pan_display,
1324 .fb_mmap = omapfb_mmap, 1324 .fb_mmap = omapfb_mmap,
1325 .fb_setcolreg = omapfb_setcolreg, 1325 .fb_setcolreg = omapfb_setcolreg,
1326 .fb_setcmap = omapfb_setcmap, 1326 .fb_setcmap = omapfb_setcmap,
1327 /*.fb_write = omapfb_write,*/ 1327 /*.fb_write = omapfb_write,*/
1328 }; 1328 };
1329 1329
1330 static void omapfb_free_fbmem(struct fb_info *fbi) 1330 static void omapfb_free_fbmem(struct fb_info *fbi)
1331 { 1331 {
1332 struct omapfb_info *ofbi = FB2OFB(fbi); 1332 struct omapfb_info *ofbi = FB2OFB(fbi);
1333 struct omapfb2_device *fbdev = ofbi->fbdev; 1333 struct omapfb2_device *fbdev = ofbi->fbdev;
1334 struct omapfb2_mem_region *rg; 1334 struct omapfb2_mem_region *rg;
1335 1335
1336 rg = ofbi->region; 1336 rg = ofbi->region;
1337 1337
1338 WARN_ON(atomic_read(&rg->map_count)); 1338 WARN_ON(atomic_read(&rg->map_count));
1339 1339
1340 if (rg->paddr) 1340 if (rg->paddr)
1341 if (omap_vram_free(rg->paddr, rg->size)) 1341 if (omap_vram_free(rg->paddr, rg->size))
1342 dev_err(fbdev->dev, "VRAM FREE failed\n"); 1342 dev_err(fbdev->dev, "VRAM FREE failed\n");
1343 1343
1344 if (rg->vaddr) 1344 if (rg->vaddr)
1345 iounmap(rg->vaddr); 1345 iounmap(rg->vaddr);
1346 1346
1347 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { 1347 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
1348 /* unmap the 0 angle rotation */ 1348 /* unmap the 0 angle rotation */
1349 if (rg->vrfb.vaddr[0]) { 1349 if (rg->vrfb.vaddr[0]) {
1350 iounmap(rg->vrfb.vaddr[0]); 1350 iounmap(rg->vrfb.vaddr[0]);
1351 omap_vrfb_release_ctx(&rg->vrfb); 1351 omap_vrfb_release_ctx(&rg->vrfb);
1352 rg->vrfb.vaddr[0] = NULL; 1352 rg->vrfb.vaddr[0] = NULL;
1353 } 1353 }
1354 } 1354 }
1355 1355
1356 rg->vaddr = NULL; 1356 rg->vaddr = NULL;
1357 rg->paddr = 0; 1357 rg->paddr = 0;
1358 rg->alloc = 0; 1358 rg->alloc = 0;
1359 rg->size = 0; 1359 rg->size = 0;
1360 } 1360 }
1361 1361
1362 static void clear_fb_info(struct fb_info *fbi) 1362 static void clear_fb_info(struct fb_info *fbi)
1363 { 1363 {
1364 memset(&fbi->var, 0, sizeof(fbi->var)); 1364 memset(&fbi->var, 0, sizeof(fbi->var));
1365 memset(&fbi->fix, 0, sizeof(fbi->fix)); 1365 memset(&fbi->fix, 0, sizeof(fbi->fix));
1366 strlcpy(fbi->fix.id, MODULE_NAME, sizeof(fbi->fix.id)); 1366 strlcpy(fbi->fix.id, MODULE_NAME, sizeof(fbi->fix.id));
1367 } 1367 }
1368 1368
1369 static int omapfb_free_all_fbmem(struct omapfb2_device *fbdev) 1369 static int omapfb_free_all_fbmem(struct omapfb2_device *fbdev)
1370 { 1370 {
1371 int i; 1371 int i;
1372 1372
1373 DBG("free all fbmem\n"); 1373 DBG("free all fbmem\n");
1374 1374
1375 for (i = 0; i < fbdev->num_fbs; i++) { 1375 for (i = 0; i < fbdev->num_fbs; i++) {
1376 struct fb_info *fbi = fbdev->fbs[i]; 1376 struct fb_info *fbi = fbdev->fbs[i];
1377 omapfb_free_fbmem(fbi); 1377 omapfb_free_fbmem(fbi);
1378 clear_fb_info(fbi); 1378 clear_fb_info(fbi);
1379 } 1379 }
1380 1380
1381 return 0; 1381 return 0;
1382 } 1382 }
1383 1383
1384 static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size, 1384 static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
1385 unsigned long paddr) 1385 unsigned long paddr)
1386 { 1386 {
1387 struct omapfb_info *ofbi = FB2OFB(fbi); 1387 struct omapfb_info *ofbi = FB2OFB(fbi);
1388 struct omapfb2_device *fbdev = ofbi->fbdev; 1388 struct omapfb2_device *fbdev = ofbi->fbdev;
1389 struct omapfb2_mem_region *rg; 1389 struct omapfb2_mem_region *rg;
1390 void __iomem *vaddr; 1390 void __iomem *vaddr;
1391 int r; 1391 int r;
1392 1392
1393 rg = ofbi->region; 1393 rg = ofbi->region;
1394 1394
1395 rg->paddr = 0; 1395 rg->paddr = 0;
1396 rg->vaddr = NULL; 1396 rg->vaddr = NULL;
1397 memset(&rg->vrfb, 0, sizeof rg->vrfb); 1397 memset(&rg->vrfb, 0, sizeof rg->vrfb);
1398 rg->size = 0; 1398 rg->size = 0;
1399 rg->type = 0; 1399 rg->type = 0;
1400 rg->alloc = false; 1400 rg->alloc = false;
1401 rg->map = false; 1401 rg->map = false;
1402 1402
1403 size = PAGE_ALIGN(size); 1403 size = PAGE_ALIGN(size);
1404 1404
1405 if (!paddr) { 1405 if (!paddr) {
1406 DBG("allocating %lu bytes for fb %d\n", size, ofbi->id); 1406 DBG("allocating %lu bytes for fb %d\n", size, ofbi->id);
1407 r = omap_vram_alloc(size, &paddr); 1407 r = omap_vram_alloc(size, &paddr);
1408 } else { 1408 } else {
1409 DBG("reserving %lu bytes at %lx for fb %d\n", size, paddr, 1409 DBG("reserving %lu bytes at %lx for fb %d\n", size, paddr,
1410 ofbi->id); 1410 ofbi->id);
1411 r = omap_vram_reserve(paddr, size); 1411 r = omap_vram_reserve(paddr, size);
1412 } 1412 }
1413 1413
1414 if (r) { 1414 if (r) {
1415 dev_err(fbdev->dev, "failed to allocate framebuffer\n"); 1415 dev_err(fbdev->dev, "failed to allocate framebuffer\n");
1416 return -ENOMEM; 1416 return -ENOMEM;
1417 } 1417 }
1418 1418
1419 if (ofbi->rotation_type != OMAP_DSS_ROT_VRFB) { 1419 if (ofbi->rotation_type != OMAP_DSS_ROT_VRFB) {
1420 vaddr = ioremap_wc(paddr, size); 1420 vaddr = ioremap_wc(paddr, size);
1421 1421
1422 if (!vaddr) { 1422 if (!vaddr) {
1423 dev_err(fbdev->dev, "failed to ioremap framebuffer\n"); 1423 dev_err(fbdev->dev, "failed to ioremap framebuffer\n");
1424 omap_vram_free(paddr, size); 1424 omap_vram_free(paddr, size);
1425 return -ENOMEM; 1425 return -ENOMEM;
1426 } 1426 }
1427 1427
1428 DBG("allocated VRAM paddr %lx, vaddr %p\n", paddr, vaddr); 1428 DBG("allocated VRAM paddr %lx, vaddr %p\n", paddr, vaddr);
1429 } else { 1429 } else {
1430 r = omap_vrfb_request_ctx(&rg->vrfb); 1430 r = omap_vrfb_request_ctx(&rg->vrfb);
1431 if (r) { 1431 if (r) {
1432 dev_err(fbdev->dev, "vrfb create ctx failed\n"); 1432 dev_err(fbdev->dev, "vrfb create ctx failed\n");
1433 return r; 1433 return r;
1434 } 1434 }
1435 1435
1436 vaddr = NULL; 1436 vaddr = NULL;
1437 } 1437 }
1438 1438
1439 rg->paddr = paddr; 1439 rg->paddr = paddr;
1440 rg->vaddr = vaddr; 1440 rg->vaddr = vaddr;
1441 rg->size = size; 1441 rg->size = size;
1442 rg->alloc = 1; 1442 rg->alloc = 1;
1443 1443
1444 return 0; 1444 return 0;
1445 } 1445 }
1446 1446
1447 /* allocate fbmem using display resolution as reference */ 1447 /* allocate fbmem using display resolution as reference */
1448 static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size, 1448 static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size,
1449 unsigned long paddr) 1449 unsigned long paddr)
1450 { 1450 {
1451 struct omapfb_info *ofbi = FB2OFB(fbi); 1451 struct omapfb_info *ofbi = FB2OFB(fbi);
1452 struct omapfb2_device *fbdev = ofbi->fbdev; 1452 struct omapfb2_device *fbdev = ofbi->fbdev;
1453 struct omap_dss_device *display; 1453 struct omap_dss_device *display;
1454 int bytespp; 1454 int bytespp;
1455 1455
1456 display = fb2display(fbi); 1456 display = fb2display(fbi);
1457 1457
1458 if (!display) 1458 if (!display)
1459 return 0; 1459 return 0;
1460 1460
1461 switch (omapfb_get_recommended_bpp(fbdev, display)) { 1461 switch (omapfb_get_recommended_bpp(fbdev, display)) {
1462 case 16: 1462 case 16:
1463 bytespp = 2; 1463 bytespp = 2;
1464 break; 1464 break;
1465 case 24: 1465 case 24:
1466 bytespp = 4; 1466 bytespp = 4;
1467 break; 1467 break;
1468 default: 1468 default:
1469 bytespp = 4; 1469 bytespp = 4;
1470 break; 1470 break;
1471 } 1471 }
1472 1472
1473 if (!size) { 1473 if (!size) {
1474 u16 w, h; 1474 u16 w, h;
1475 1475
1476 display->driver->get_resolution(display, &w, &h); 1476 display->driver->get_resolution(display, &w, &h);
1477 1477
1478 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { 1478 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
1479 size = max(omap_vrfb_min_phys_size(w, h, bytespp), 1479 size = max(omap_vrfb_min_phys_size(w, h, bytespp),
1480 omap_vrfb_min_phys_size(h, w, bytespp)); 1480 omap_vrfb_min_phys_size(h, w, bytespp));
1481 1481
1482 DBG("adjusting fb mem size for VRFB, %u -> %lu\n", 1482 DBG("adjusting fb mem size for VRFB, %u -> %lu\n",
1483 w * h * bytespp, size); 1483 w * h * bytespp, size);
1484 } else { 1484 } else {
1485 size = w * h * bytespp; 1485 size = w * h * bytespp;
1486 } 1486 }
1487 } 1487 }
1488 1488
1489 if (!size) 1489 if (!size)
1490 return 0; 1490 return 0;
1491 1491
1492 return omapfb_alloc_fbmem(fbi, size, paddr); 1492 return omapfb_alloc_fbmem(fbi, size, paddr);
1493 } 1493 }
1494 1494
1495 static int omapfb_parse_vram_param(const char *param, int max_entries, 1495 static int omapfb_parse_vram_param(const char *param, int max_entries,
1496 unsigned long *sizes, unsigned long *paddrs) 1496 unsigned long *sizes, unsigned long *paddrs)
1497 { 1497 {
1498 int fbnum; 1498 int fbnum;
1499 unsigned long size; 1499 unsigned long size;
1500 unsigned long paddr = 0; 1500 unsigned long paddr = 0;
1501 char *p, *start; 1501 char *p, *start;
1502 1502
1503 start = (char *)param; 1503 start = (char *)param;
1504 1504
1505 while (1) { 1505 while (1) {
1506 p = start; 1506 p = start;
1507 1507
1508 fbnum = simple_strtoul(p, &p, 10); 1508 fbnum = simple_strtoul(p, &p, 10);
1509 1509
1510 if (p == start) 1510 if (p == start)
1511 return -EINVAL; 1511 return -EINVAL;
1512 1512
1513 if (*p != ':') 1513 if (*p != ':')
1514 return -EINVAL; 1514 return -EINVAL;
1515 1515
1516 if (fbnum >= max_entries) 1516 if (fbnum >= max_entries)
1517 return -EINVAL; 1517 return -EINVAL;
1518 1518
1519 size = memparse(p + 1, &p); 1519 size = memparse(p + 1, &p);
1520 1520
1521 if (!size) 1521 if (!size)
1522 return -EINVAL; 1522 return -EINVAL;
1523 1523
1524 paddr = 0; 1524 paddr = 0;
1525 1525
1526 if (*p == '@') { 1526 if (*p == '@') {
1527 paddr = simple_strtoul(p + 1, &p, 16); 1527 paddr = simple_strtoul(p + 1, &p, 16);
1528 1528
1529 if (!paddr) 1529 if (!paddr)
1530 return -EINVAL; 1530 return -EINVAL;
1531 1531
1532 } 1532 }
1533 1533
1534 paddrs[fbnum] = paddr; 1534 paddrs[fbnum] = paddr;
1535 sizes[fbnum] = size; 1535 sizes[fbnum] = size;
1536 1536
1537 if (*p == 0) 1537 if (*p == 0)
1538 break; 1538 break;
1539 1539
1540 if (*p != ',') 1540 if (*p != ',')
1541 return -EINVAL; 1541 return -EINVAL;
1542 1542
1543 ++p; 1543 ++p;
1544 1544
1545 start = p; 1545 start = p;
1546 } 1546 }
1547 1547
1548 return 0; 1548 return 0;
1549 } 1549 }
1550 1550
1551 static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev) 1551 static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev)
1552 { 1552 {
1553 int i, r; 1553 int i, r;
1554 unsigned long vram_sizes[10]; 1554 unsigned long vram_sizes[10];
1555 unsigned long vram_paddrs[10]; 1555 unsigned long vram_paddrs[10];
1556 1556
1557 memset(&vram_sizes, 0, sizeof(vram_sizes)); 1557 memset(&vram_sizes, 0, sizeof(vram_sizes));
1558 memset(&vram_paddrs, 0, sizeof(vram_paddrs)); 1558 memset(&vram_paddrs, 0, sizeof(vram_paddrs));
1559 1559
1560 if (def_vram && omapfb_parse_vram_param(def_vram, 10, 1560 if (def_vram && omapfb_parse_vram_param(def_vram, 10,
1561 vram_sizes, vram_paddrs)) { 1561 vram_sizes, vram_paddrs)) {
1562 dev_err(fbdev->dev, "failed to parse vram parameter\n"); 1562 dev_err(fbdev->dev, "failed to parse vram parameter\n");
1563 1563
1564 memset(&vram_sizes, 0, sizeof(vram_sizes)); 1564 memset(&vram_sizes, 0, sizeof(vram_sizes));
1565 memset(&vram_paddrs, 0, sizeof(vram_paddrs)); 1565 memset(&vram_paddrs, 0, sizeof(vram_paddrs));
1566 } 1566 }
1567 1567
1568 for (i = 0; i < fbdev->num_fbs; i++) { 1568 for (i = 0; i < fbdev->num_fbs; i++) {
1569 /* allocate memory automatically only for fb0, or if 1569 /* allocate memory automatically only for fb0, or if
1570 * excplicitly defined with vram or plat data option */ 1570 * excplicitly defined with vram or plat data option */
1571 if (i == 0 || vram_sizes[i] != 0) { 1571 if (i == 0 || vram_sizes[i] != 0) {
1572 r = omapfb_alloc_fbmem_display(fbdev->fbs[i], 1572 r = omapfb_alloc_fbmem_display(fbdev->fbs[i],
1573 vram_sizes[i], vram_paddrs[i]); 1573 vram_sizes[i], vram_paddrs[i]);
1574 1574
1575 if (r) 1575 if (r)
1576 return r; 1576 return r;
1577 } 1577 }
1578 } 1578 }
1579 1579
1580 for (i = 0; i < fbdev->num_fbs; i++) { 1580 for (i = 0; i < fbdev->num_fbs; i++) {
1581 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]); 1581 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
1582 struct omapfb2_mem_region *rg; 1582 struct omapfb2_mem_region *rg;
1583 rg = ofbi->region; 1583 rg = ofbi->region;
1584 1584
1585 DBG("region%d phys %08x virt %p size=%lu\n", 1585 DBG("region%d phys %08x virt %p size=%lu\n",
1586 i, 1586 i,
1587 rg->paddr, 1587 rg->paddr,
1588 rg->vaddr, 1588 rg->vaddr,
1589 rg->size); 1589 rg->size);
1590 } 1590 }
1591 1591
1592 return 0; 1592 return 0;
1593 } 1593 }
1594 1594
1595 int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type) 1595 int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
1596 { 1596 {
1597 struct omapfb_info *ofbi = FB2OFB(fbi); 1597 struct omapfb_info *ofbi = FB2OFB(fbi);
1598 struct omapfb2_device *fbdev = ofbi->fbdev; 1598 struct omapfb2_device *fbdev = ofbi->fbdev;
1599 struct omap_dss_device *display = fb2display(fbi); 1599 struct omap_dss_device *display = fb2display(fbi);
1600 struct omapfb2_mem_region *rg = ofbi->region; 1600 struct omapfb2_mem_region *rg = ofbi->region;
1601 unsigned long old_size = rg->size; 1601 unsigned long old_size = rg->size;
1602 unsigned long old_paddr = rg->paddr; 1602 unsigned long old_paddr = rg->paddr;
1603 int old_type = rg->type; 1603 int old_type = rg->type;
1604 int r; 1604 int r;
1605 1605
1606 if (type != OMAPFB_MEMTYPE_SDRAM) 1606 if (type != OMAPFB_MEMTYPE_SDRAM)
1607 return -EINVAL; 1607 return -EINVAL;
1608 1608
1609 size = PAGE_ALIGN(size); 1609 size = PAGE_ALIGN(size);
1610 1610
1611 if (old_size == size && old_type == type) 1611 if (old_size == size && old_type == type)
1612 return 0; 1612 return 0;
1613 1613
1614 if (display && display->driver->sync) 1614 if (display && display->driver->sync)
1615 display->driver->sync(display); 1615 display->driver->sync(display);
1616 1616
1617 omapfb_free_fbmem(fbi); 1617 omapfb_free_fbmem(fbi);
1618 1618
1619 if (size == 0) { 1619 if (size == 0) {
1620 clear_fb_info(fbi); 1620 clear_fb_info(fbi);
1621 return 0; 1621 return 0;
1622 } 1622 }
1623 1623
1624 r = omapfb_alloc_fbmem(fbi, size, 0); 1624 r = omapfb_alloc_fbmem(fbi, size, 0);
1625 1625
1626 if (r) { 1626 if (r) {
1627 if (old_size) 1627 if (old_size)
1628 omapfb_alloc_fbmem(fbi, old_size, old_paddr); 1628 omapfb_alloc_fbmem(fbi, old_size, old_paddr);
1629 1629
1630 if (rg->size == 0) 1630 if (rg->size == 0)
1631 clear_fb_info(fbi); 1631 clear_fb_info(fbi);
1632 1632
1633 return r; 1633 return r;
1634 } 1634 }
1635 1635
1636 if (old_size == size) 1636 if (old_size == size)
1637 return 0; 1637 return 0;
1638 1638
1639 if (old_size == 0) { 1639 if (old_size == 0) {
1640 DBG("initializing fb %d\n", ofbi->id); 1640 DBG("initializing fb %d\n", ofbi->id);
1641 r = omapfb_fb_init(fbdev, fbi); 1641 r = omapfb_fb_init(fbdev, fbi);
1642 if (r) { 1642 if (r) {
1643 DBG("omapfb_fb_init failed\n"); 1643 DBG("omapfb_fb_init failed\n");
1644 goto err; 1644 goto err;
1645 } 1645 }
1646 r = omapfb_apply_changes(fbi, 1); 1646 r = omapfb_apply_changes(fbi, 1);
1647 if (r) { 1647 if (r) {
1648 DBG("omapfb_apply_changes failed\n"); 1648 DBG("omapfb_apply_changes failed\n");
1649 goto err; 1649 goto err;
1650 } 1650 }
1651 } else { 1651 } else {
1652 struct fb_var_screeninfo new_var; 1652 struct fb_var_screeninfo new_var;
1653 memcpy(&new_var, &fbi->var, sizeof(new_var)); 1653 memcpy(&new_var, &fbi->var, sizeof(new_var));
1654 r = check_fb_var(fbi, &new_var); 1654 r = check_fb_var(fbi, &new_var);
1655 if (r) 1655 if (r)
1656 goto err; 1656 goto err;
1657 memcpy(&fbi->var, &new_var, sizeof(fbi->var)); 1657 memcpy(&fbi->var, &new_var, sizeof(fbi->var));
1658 set_fb_fix(fbi); 1658 set_fb_fix(fbi);
1659 r = setup_vrfb_rotation(fbi); 1659 r = setup_vrfb_rotation(fbi);
1660 if (r) 1660 if (r)
1661 goto err; 1661 goto err;
1662 } 1662 }
1663 1663
1664 return 0; 1664 return 0;
1665 err: 1665 err:
1666 omapfb_free_fbmem(fbi); 1666 omapfb_free_fbmem(fbi);
1667 clear_fb_info(fbi); 1667 clear_fb_info(fbi);
1668 return r; 1668 return r;
1669 } 1669 }
1670 1670
1671 static void omapfb_auto_update_work(struct work_struct *work) 1671 static void omapfb_auto_update_work(struct work_struct *work)
1672 { 1672 {
1673 struct omap_dss_device *dssdev; 1673 struct omap_dss_device *dssdev;
1674 struct omap_dss_driver *dssdrv; 1674 struct omap_dss_driver *dssdrv;
1675 struct omapfb_display_data *d; 1675 struct omapfb_display_data *d;
1676 u16 w, h; 1676 u16 w, h;
1677 unsigned int freq; 1677 unsigned int freq;
1678 struct omapfb2_device *fbdev; 1678 struct omapfb2_device *fbdev;
1679 1679
1680 d = container_of(work, struct omapfb_display_data, 1680 d = container_of(work, struct omapfb_display_data,
1681 auto_update_work.work); 1681 auto_update_work.work);
1682 1682
1683 dssdev = d->dssdev; 1683 dssdev = d->dssdev;
1684 dssdrv = dssdev->driver; 1684 dssdrv = dssdev->driver;
1685 fbdev = d->fbdev; 1685 fbdev = d->fbdev;
1686 1686
1687 if (!dssdrv || !dssdrv->update) 1687 if (!dssdrv || !dssdrv->update)
1688 return; 1688 return;
1689 1689
1690 if (dssdrv->sync) 1690 if (dssdrv->sync)
1691 dssdrv->sync(dssdev); 1691 dssdrv->sync(dssdev);
1692 1692
1693 dssdrv->get_resolution(dssdev, &w, &h); 1693 dssdrv->get_resolution(dssdev, &w, &h);
1694 dssdrv->update(dssdev, 0, 0, w, h); 1694 dssdrv->update(dssdev, 0, 0, w, h);
1695 1695
1696 freq = auto_update_freq; 1696 freq = auto_update_freq;
1697 if (freq == 0) 1697 if (freq == 0)
1698 freq = 20; 1698 freq = 20;
1699 queue_delayed_work(fbdev->auto_update_wq, 1699 queue_delayed_work(fbdev->auto_update_wq,
1700 &d->auto_update_work, HZ / freq); 1700 &d->auto_update_work, HZ / freq);
1701 } 1701 }
1702 1702
1703 void omapfb_start_auto_update(struct omapfb2_device *fbdev, 1703 void omapfb_start_auto_update(struct omapfb2_device *fbdev,
1704 struct omap_dss_device *display) 1704 struct omap_dss_device *display)
1705 { 1705 {
1706 struct omapfb_display_data *d; 1706 struct omapfb_display_data *d;
1707 1707
1708 if (fbdev->auto_update_wq == NULL) { 1708 if (fbdev->auto_update_wq == NULL) {
1709 struct workqueue_struct *wq; 1709 struct workqueue_struct *wq;
1710 1710
1711 wq = create_singlethread_workqueue("omapfb_auto_update"); 1711 wq = create_singlethread_workqueue("omapfb_auto_update");
1712 1712
1713 if (wq == NULL) { 1713 if (wq == NULL) {
1714 dev_err(fbdev->dev, "Failed to create workqueue for " 1714 dev_err(fbdev->dev, "Failed to create workqueue for "
1715 "auto-update\n"); 1715 "auto-update\n");
1716 return; 1716 return;
1717 } 1717 }
1718 1718
1719 fbdev->auto_update_wq = wq; 1719 fbdev->auto_update_wq = wq;
1720 } 1720 }
1721 1721
1722 d = get_display_data(fbdev, display); 1722 d = get_display_data(fbdev, display);
1723 1723
1724 INIT_DELAYED_WORK(&d->auto_update_work, omapfb_auto_update_work); 1724 INIT_DELAYED_WORK(&d->auto_update_work, omapfb_auto_update_work);
1725 1725
1726 d->auto_update_work_enabled = true; 1726 d->auto_update_work_enabled = true;
1727 1727
1728 omapfb_auto_update_work(&d->auto_update_work.work); 1728 omapfb_auto_update_work(&d->auto_update_work.work);
1729 } 1729 }
1730 1730
1731 void omapfb_stop_auto_update(struct omapfb2_device *fbdev, 1731 void omapfb_stop_auto_update(struct omapfb2_device *fbdev,
1732 struct omap_dss_device *display) 1732 struct omap_dss_device *display)
1733 { 1733 {
1734 struct omapfb_display_data *d; 1734 struct omapfb_display_data *d;
1735 1735
1736 d = get_display_data(fbdev, display); 1736 d = get_display_data(fbdev, display);
1737 1737
1738 cancel_delayed_work_sync(&d->auto_update_work); 1738 cancel_delayed_work_sync(&d->auto_update_work);
1739 1739
1740 d->auto_update_work_enabled = false; 1740 d->auto_update_work_enabled = false;
1741 } 1741 }
1742 1742
1743 /* initialize fb_info, var, fix to something sane based on the display */ 1743 /* initialize fb_info, var, fix to something sane based on the display */
1744 static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi) 1744 static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
1745 { 1745 {
1746 struct fb_var_screeninfo *var = &fbi->var; 1746 struct fb_var_screeninfo *var = &fbi->var;
1747 struct omap_dss_device *display = fb2display(fbi); 1747 struct omap_dss_device *display = fb2display(fbi);
1748 struct omapfb_info *ofbi = FB2OFB(fbi); 1748 struct omapfb_info *ofbi = FB2OFB(fbi);
1749 int r = 0; 1749 int r = 0;
1750 1750
1751 fbi->fbops = &omapfb_ops; 1751 fbi->fbops = &omapfb_ops;
1752 fbi->flags = FBINFO_FLAG_DEFAULT; 1752 fbi->flags = FBINFO_FLAG_DEFAULT;
1753 fbi->pseudo_palette = fbdev->pseudo_palette; 1753 fbi->pseudo_palette = fbdev->pseudo_palette;
1754 1754
1755 if (ofbi->region->size == 0) { 1755 if (ofbi->region->size == 0) {
1756 clear_fb_info(fbi); 1756 clear_fb_info(fbi);
1757 return 0; 1757 return 0;
1758 } 1758 }
1759 1759
1760 var->nonstd = 0; 1760 var->nonstd = 0;
1761 var->bits_per_pixel = 0; 1761 var->bits_per_pixel = 0;
1762 1762
1763 var->rotate = def_rotate; 1763 var->rotate = def_rotate;
1764 1764
1765 if (display) { 1765 if (display) {
1766 u16 w, h; 1766 u16 w, h;
1767 int rotation = (var->rotate + ofbi->rotation[0]) % 4; 1767 int rotation = (var->rotate + ofbi->rotation[0]) % 4;
1768 1768
1769 display->driver->get_resolution(display, &w, &h); 1769 display->driver->get_resolution(display, &w, &h);
1770 1770
1771 if (rotation == FB_ROTATE_CW || 1771 if (rotation == FB_ROTATE_CW ||
1772 rotation == FB_ROTATE_CCW) { 1772 rotation == FB_ROTATE_CCW) {
1773 var->xres = h; 1773 var->xres = h;
1774 var->yres = w; 1774 var->yres = w;
1775 } else { 1775 } else {
1776 var->xres = w; 1776 var->xres = w;
1777 var->yres = h; 1777 var->yres = h;
1778 } 1778 }
1779 1779
1780 var->xres_virtual = var->xres; 1780 var->xres_virtual = var->xres;
1781 var->yres_virtual = var->yres; 1781 var->yres_virtual = var->yres;
1782 1782
1783 if (!var->bits_per_pixel) { 1783 if (!var->bits_per_pixel) {
1784 switch (omapfb_get_recommended_bpp(fbdev, display)) { 1784 switch (omapfb_get_recommended_bpp(fbdev, display)) {
1785 case 16: 1785 case 16:
1786 var->bits_per_pixel = 16; 1786 var->bits_per_pixel = 16;
1787 break; 1787 break;
1788 case 24: 1788 case 24:
1789 var->bits_per_pixel = 32; 1789 var->bits_per_pixel = 32;
1790 break; 1790 break;
1791 default: 1791 default:
1792 dev_err(fbdev->dev, "illegal display " 1792 dev_err(fbdev->dev, "illegal display "
1793 "bpp\n"); 1793 "bpp\n");
1794 return -EINVAL; 1794 return -EINVAL;
1795 } 1795 }
1796 } 1796 }
1797 } else { 1797 } else {
1798 /* if there's no display, let's just guess some basic values */ 1798 /* if there's no display, let's just guess some basic values */
1799 var->xres = 320; 1799 var->xres = 320;
1800 var->yres = 240; 1800 var->yres = 240;
1801 var->xres_virtual = var->xres; 1801 var->xres_virtual = var->xres;
1802 var->yres_virtual = var->yres; 1802 var->yres_virtual = var->yres;
1803 if (!var->bits_per_pixel) 1803 if (!var->bits_per_pixel)
1804 var->bits_per_pixel = 16; 1804 var->bits_per_pixel = 16;
1805 } 1805 }
1806 1806
1807 r = check_fb_var(fbi, var); 1807 r = check_fb_var(fbi, var);
1808 if (r) 1808 if (r)
1809 goto err; 1809 goto err;
1810 1810
1811 set_fb_fix(fbi); 1811 set_fb_fix(fbi);
1812 r = setup_vrfb_rotation(fbi); 1812 r = setup_vrfb_rotation(fbi);
1813 if (r) 1813 if (r)
1814 goto err; 1814 goto err;
1815 1815
1816 r = fb_alloc_cmap(&fbi->cmap, 256, 0); 1816 r = fb_alloc_cmap(&fbi->cmap, 256, 0);
1817 if (r) 1817 if (r)
1818 dev_err(fbdev->dev, "unable to allocate color map memory\n"); 1818 dev_err(fbdev->dev, "unable to allocate color map memory\n");
1819 1819
1820 err: 1820 err:
1821 return r; 1821 return r;
1822 } 1822 }
1823 1823
1824 static void fbinfo_cleanup(struct omapfb2_device *fbdev, struct fb_info *fbi) 1824 static void fbinfo_cleanup(struct omapfb2_device *fbdev, struct fb_info *fbi)
1825 { 1825 {
1826 fb_dealloc_cmap(&fbi->cmap); 1826 fb_dealloc_cmap(&fbi->cmap);
1827 } 1827 }
1828 1828
1829 1829
1830 static void omapfb_free_resources(struct omapfb2_device *fbdev) 1830 static void omapfb_free_resources(struct omapfb2_device *fbdev)
1831 { 1831 {
1832 int i; 1832 int i;
1833 1833
1834 DBG("free_resources\n"); 1834 DBG("free_resources\n");
1835 1835
1836 if (fbdev == NULL) 1836 if (fbdev == NULL)
1837 return; 1837 return;
1838 1838
1839 for (i = 0; i < fbdev->num_fbs; i++) 1839 for (i = 0; i < fbdev->num_fbs; i++)
1840 unregister_framebuffer(fbdev->fbs[i]); 1840 unregister_framebuffer(fbdev->fbs[i]);
1841 1841
1842 /* free the reserved fbmem */ 1842 /* free the reserved fbmem */
1843 omapfb_free_all_fbmem(fbdev); 1843 omapfb_free_all_fbmem(fbdev);
1844 1844
1845 for (i = 0; i < fbdev->num_fbs; i++) { 1845 for (i = 0; i < fbdev->num_fbs; i++) {
1846 fbinfo_cleanup(fbdev, fbdev->fbs[i]); 1846 fbinfo_cleanup(fbdev, fbdev->fbs[i]);
1847 framebuffer_release(fbdev->fbs[i]); 1847 framebuffer_release(fbdev->fbs[i]);
1848 } 1848 }
1849 1849
1850 for (i = 0; i < fbdev->num_displays; i++) { 1850 for (i = 0; i < fbdev->num_displays; i++) {
1851 struct omap_dss_device *dssdev = fbdev->displays[i].dssdev; 1851 struct omap_dss_device *dssdev = fbdev->displays[i].dssdev;
1852 1852
1853 if (fbdev->displays[i].auto_update_work_enabled) 1853 if (fbdev->displays[i].auto_update_work_enabled)
1854 omapfb_stop_auto_update(fbdev, dssdev); 1854 omapfb_stop_auto_update(fbdev, dssdev);
1855 1855
1856 if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) 1856 if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)
1857 dssdev->driver->disable(dssdev); 1857 dssdev->driver->disable(dssdev);
1858 1858
1859 omap_dss_put_device(dssdev); 1859 omap_dss_put_device(dssdev);
1860 } 1860 }
1861 1861
1862 if (fbdev->auto_update_wq != NULL) { 1862 if (fbdev->auto_update_wq != NULL) {
1863 flush_workqueue(fbdev->auto_update_wq); 1863 flush_workqueue(fbdev->auto_update_wq);
1864 destroy_workqueue(fbdev->auto_update_wq); 1864 destroy_workqueue(fbdev->auto_update_wq);
1865 fbdev->auto_update_wq = NULL; 1865 fbdev->auto_update_wq = NULL;
1866 } 1866 }
1867 1867
1868 dev_set_drvdata(fbdev->dev, NULL); 1868 dev_set_drvdata(fbdev->dev, NULL);
1869 kfree(fbdev); 1869 kfree(fbdev);
1870 } 1870 }
1871 1871
1872 static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) 1872 static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
1873 { 1873 {
1874 int r, i; 1874 int r, i;
1875 1875
1876 fbdev->num_fbs = 0; 1876 fbdev->num_fbs = 0;
1877 1877
1878 DBG("create %d framebuffers\n", CONFIG_FB_OMAP2_NUM_FBS); 1878 DBG("create %d framebuffers\n", CONFIG_FB_OMAP2_NUM_FBS);
1879 1879
1880 /* allocate fb_infos */ 1880 /* allocate fb_infos */
1881 for (i = 0; i < CONFIG_FB_OMAP2_NUM_FBS; i++) { 1881 for (i = 0; i < CONFIG_FB_OMAP2_NUM_FBS; i++) {
1882 struct fb_info *fbi; 1882 struct fb_info *fbi;
1883 struct omapfb_info *ofbi; 1883 struct omapfb_info *ofbi;
1884 1884
1885 fbi = framebuffer_alloc(sizeof(struct omapfb_info), 1885 fbi = framebuffer_alloc(sizeof(struct omapfb_info),
1886 fbdev->dev); 1886 fbdev->dev);
1887 1887
1888 if (fbi == NULL) { 1888 if (fbi == NULL) {
1889 dev_err(fbdev->dev, 1889 dev_err(fbdev->dev,
1890 "unable to allocate memory for plane info\n"); 1890 "unable to allocate memory for plane info\n");
1891 return -ENOMEM; 1891 return -ENOMEM;
1892 } 1892 }
1893 1893
1894 clear_fb_info(fbi); 1894 clear_fb_info(fbi);
1895 1895
1896 fbdev->fbs[i] = fbi; 1896 fbdev->fbs[i] = fbi;
1897 1897
1898 ofbi = FB2OFB(fbi); 1898 ofbi = FB2OFB(fbi);
1899 ofbi->fbdev = fbdev; 1899 ofbi->fbdev = fbdev;
1900 ofbi->id = i; 1900 ofbi->id = i;
1901 1901
1902 ofbi->region = &fbdev->regions[i]; 1902 ofbi->region = &fbdev->regions[i];
1903 ofbi->region->id = i; 1903 ofbi->region->id = i;
1904 init_rwsem(&ofbi->region->lock); 1904 init_rwsem(&ofbi->region->lock);
1905 1905
1906 /* assign these early, so that fb alloc can use them */ 1906 /* assign these early, so that fb alloc can use them */
1907 ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB : 1907 ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB :
1908 OMAP_DSS_ROT_DMA; 1908 OMAP_DSS_ROT_DMA;
1909 ofbi->mirror = def_mirror; 1909 ofbi->mirror = def_mirror;
1910 1910
1911 fbdev->num_fbs++; 1911 fbdev->num_fbs++;
1912 } 1912 }
1913 1913
1914 DBG("fb_infos allocated\n"); 1914 DBG("fb_infos allocated\n");
1915 1915
1916 /* assign overlays for the fbs */ 1916 /* assign overlays for the fbs */
1917 for (i = 0; i < min(fbdev->num_fbs, fbdev->num_overlays); i++) { 1917 for (i = 0; i < min(fbdev->num_fbs, fbdev->num_overlays); i++) {
1918 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]); 1918 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
1919 1919
1920 ofbi->overlays[0] = fbdev->overlays[i]; 1920 ofbi->overlays[0] = fbdev->overlays[i];
1921 ofbi->num_overlays = 1; 1921 ofbi->num_overlays = 1;
1922 } 1922 }
1923 1923
1924 /* allocate fb memories */ 1924 /* allocate fb memories */
1925 r = omapfb_allocate_all_fbs(fbdev); 1925 r = omapfb_allocate_all_fbs(fbdev);
1926 if (r) { 1926 if (r) {
1927 dev_err(fbdev->dev, "failed to allocate fbmem\n"); 1927 dev_err(fbdev->dev, "failed to allocate fbmem\n");
1928 return r; 1928 return r;
1929 } 1929 }
1930 1930
1931 DBG("fbmems allocated\n"); 1931 DBG("fbmems allocated\n");
1932 1932
1933 /* setup fb_infos */ 1933 /* setup fb_infos */
1934 for (i = 0; i < fbdev->num_fbs; i++) { 1934 for (i = 0; i < fbdev->num_fbs; i++) {
1935 struct fb_info *fbi = fbdev->fbs[i]; 1935 struct fb_info *fbi = fbdev->fbs[i];
1936 struct omapfb_info *ofbi = FB2OFB(fbi); 1936 struct omapfb_info *ofbi = FB2OFB(fbi);
1937 1937
1938 omapfb_get_mem_region(ofbi->region); 1938 omapfb_get_mem_region(ofbi->region);
1939 r = omapfb_fb_init(fbdev, fbi); 1939 r = omapfb_fb_init(fbdev, fbi);
1940 omapfb_put_mem_region(ofbi->region); 1940 omapfb_put_mem_region(ofbi->region);
1941 1941
1942 if (r) { 1942 if (r) {
1943 dev_err(fbdev->dev, "failed to setup fb_info\n"); 1943 dev_err(fbdev->dev, "failed to setup fb_info\n");
1944 return r; 1944 return r;
1945 } 1945 }
1946 } 1946 }
1947 1947
1948 DBG("fb_infos initialized\n"); 1948 DBG("fb_infos initialized\n");
1949 1949
1950 for (i = 0; i < fbdev->num_fbs; i++) { 1950 for (i = 0; i < fbdev->num_fbs; i++) {
1951 r = register_framebuffer(fbdev->fbs[i]); 1951 r = register_framebuffer(fbdev->fbs[i]);
1952 if (r != 0) { 1952 if (r != 0) {
1953 dev_err(fbdev->dev, 1953 dev_err(fbdev->dev,
1954 "registering framebuffer %d failed\n", i); 1954 "registering framebuffer %d failed\n", i);
1955 return r; 1955 return r;
1956 } 1956 }
1957 } 1957 }
1958 1958
1959 DBG("framebuffers registered\n"); 1959 DBG("framebuffers registered\n");
1960 1960
1961 for (i = 0; i < fbdev->num_fbs; i++) { 1961 for (i = 0; i < fbdev->num_fbs; i++) {
1962 struct fb_info *fbi = fbdev->fbs[i]; 1962 struct fb_info *fbi = fbdev->fbs[i];
1963 struct omapfb_info *ofbi = FB2OFB(fbi); 1963 struct omapfb_info *ofbi = FB2OFB(fbi);
1964 1964
1965 omapfb_get_mem_region(ofbi->region); 1965 omapfb_get_mem_region(ofbi->region);
1966 r = omapfb_apply_changes(fbi, 1); 1966 r = omapfb_apply_changes(fbi, 1);
1967 omapfb_put_mem_region(ofbi->region); 1967 omapfb_put_mem_region(ofbi->region);
1968 1968
1969 if (r) { 1969 if (r) {
1970 dev_err(fbdev->dev, "failed to change mode\n"); 1970 dev_err(fbdev->dev, "failed to change mode\n");
1971 return r; 1971 return r;
1972 } 1972 }
1973 } 1973 }
1974 1974
1975 /* Enable fb0 */ 1975 /* Enable fb0 */
1976 if (fbdev->num_fbs > 0) { 1976 if (fbdev->num_fbs > 0) {
1977 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[0]); 1977 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[0]);
1978 1978
1979 if (ofbi->num_overlays > 0) { 1979 if (ofbi->num_overlays > 0) {
1980 struct omap_overlay *ovl = ofbi->overlays[0]; 1980 struct omap_overlay *ovl = ofbi->overlays[0];
1981 1981
1982 ovl->manager->apply(ovl->manager); 1982 ovl->manager->apply(ovl->manager);
1983 1983
1984 r = omapfb_overlay_enable(ovl, 1); 1984 r = omapfb_overlay_enable(ovl, 1);
1985 1985
1986 if (r) { 1986 if (r) {
1987 dev_err(fbdev->dev, 1987 dev_err(fbdev->dev,
1988 "failed to enable overlay\n"); 1988 "failed to enable overlay\n");
1989 return r; 1989 return r;
1990 } 1990 }
1991 } 1991 }
1992 } 1992 }
1993 1993
1994 DBG("create_framebuffers done\n"); 1994 DBG("create_framebuffers done\n");
1995 1995
1996 return 0; 1996 return 0;
1997 } 1997 }
1998 1998
1999 static int omapfb_mode_to_timings(const char *mode_str, 1999 static int omapfb_mode_to_timings(const char *mode_str,
2000 struct omap_dss_device *display, 2000 struct omap_dss_device *display,
2001 struct omap_video_timings *timings, u8 *bpp) 2001 struct omap_video_timings *timings, u8 *bpp)
2002 { 2002 {
2003 struct fb_info *fbi; 2003 struct fb_info *fbi;
2004 struct fb_var_screeninfo *var; 2004 struct fb_var_screeninfo *var;
2005 struct fb_ops *fbops; 2005 struct fb_ops *fbops;
2006 int r; 2006 int r;
2007 2007
2008 #ifdef CONFIG_OMAP2_DSS_VENC 2008 #ifdef CONFIG_OMAP2_DSS_VENC
2009 if (strcmp(mode_str, "pal") == 0) { 2009 if (strcmp(mode_str, "pal") == 0) {
2010 *timings = omap_dss_pal_timings; 2010 *timings = omap_dss_pal_timings;
2011 *bpp = 24; 2011 *bpp = 24;
2012 return 0; 2012 return 0;
2013 } else if (strcmp(mode_str, "ntsc") == 0) { 2013 } else if (strcmp(mode_str, "ntsc") == 0) {
2014 *timings = omap_dss_ntsc_timings; 2014 *timings = omap_dss_ntsc_timings;
2015 *bpp = 24; 2015 *bpp = 24;
2016 return 0; 2016 return 0;
2017 } 2017 }
2018 #endif 2018 #endif
2019 2019
2020 /* this is quite a hack, but I wanted to use the modedb and for 2020 /* this is quite a hack, but I wanted to use the modedb and for
2021 * that we need fb_info and var, so we create dummy ones */ 2021 * that we need fb_info and var, so we create dummy ones */
2022 2022
2023 *bpp = 0; 2023 *bpp = 0;
2024 fbi = NULL; 2024 fbi = NULL;
2025 var = NULL; 2025 var = NULL;
2026 fbops = NULL; 2026 fbops = NULL;
2027 2027
2028 fbi = kzalloc(sizeof(*fbi), GFP_KERNEL); 2028 fbi = kzalloc(sizeof(*fbi), GFP_KERNEL);
2029 if (fbi == NULL) { 2029 if (fbi == NULL) {
2030 r = -ENOMEM; 2030 r = -ENOMEM;
2031 goto err; 2031 goto err;
2032 } 2032 }
2033 2033
2034 var = kzalloc(sizeof(*var), GFP_KERNEL); 2034 var = kzalloc(sizeof(*var), GFP_KERNEL);
2035 if (var == NULL) { 2035 if (var == NULL) {
2036 r = -ENOMEM; 2036 r = -ENOMEM;
2037 goto err; 2037 goto err;
2038 } 2038 }
2039 2039
2040 fbops = kzalloc(sizeof(*fbops), GFP_KERNEL); 2040 fbops = kzalloc(sizeof(*fbops), GFP_KERNEL);
2041 if (fbops == NULL) { 2041 if (fbops == NULL) {
2042 r = -ENOMEM; 2042 r = -ENOMEM;
2043 goto err; 2043 goto err;
2044 } 2044 }
2045 2045
2046 fbi->fbops = fbops; 2046 fbi->fbops = fbops;
2047 2047
2048 r = fb_find_mode(var, fbi, mode_str, NULL, 0, NULL, 24); 2048 r = fb_find_mode(var, fbi, mode_str, NULL, 0, NULL, 24);
2049 if (r == 0) { 2049 if (r == 0) {
2050 r = -EINVAL; 2050 r = -EINVAL;
2051 goto err; 2051 goto err;
2052 } 2052 }
2053 2053
2054 if (display->driver->get_timings) { 2054 if (display->driver->get_timings) {
2055 display->driver->get_timings(display, timings); 2055 display->driver->get_timings(display, timings);
2056 } else { 2056 } else {
2057 timings->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; 2057 timings->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
2058 timings->de_level = OMAPDSS_SIG_ACTIVE_HIGH; 2058 timings->de_level = OMAPDSS_SIG_ACTIVE_HIGH;
2059 timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; 2059 timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES;
2060 } 2060 }
2061 2061
2062 timings->pixel_clock = PICOS2KHZ(var->pixclock); 2062 timings->pixel_clock = PICOS2KHZ(var->pixclock);
2063 timings->hbp = var->left_margin; 2063 timings->hbp = var->left_margin;
2064 timings->hfp = var->right_margin; 2064 timings->hfp = var->right_margin;
2065 timings->vbp = var->upper_margin; 2065 timings->vbp = var->upper_margin;
2066 timings->vfp = var->lower_margin; 2066 timings->vfp = var->lower_margin;
2067 timings->hsw = var->hsync_len; 2067 timings->hsw = var->hsync_len;
2068 timings->vsw = var->vsync_len; 2068 timings->vsw = var->vsync_len;
2069 timings->x_res = var->xres; 2069 timings->x_res = var->xres;
2070 timings->y_res = var->yres; 2070 timings->y_res = var->yres;
2071 timings->hsync_level = var->sync & FB_SYNC_HOR_HIGH_ACT ? 2071 timings->hsync_level = var->sync & FB_SYNC_HOR_HIGH_ACT ?
2072 OMAPDSS_SIG_ACTIVE_HIGH : 2072 OMAPDSS_SIG_ACTIVE_HIGH :
2073 OMAPDSS_SIG_ACTIVE_LOW; 2073 OMAPDSS_SIG_ACTIVE_LOW;
2074 timings->vsync_level = var->sync & FB_SYNC_VERT_HIGH_ACT ? 2074 timings->vsync_level = var->sync & FB_SYNC_VERT_HIGH_ACT ?
2075 OMAPDSS_SIG_ACTIVE_HIGH : 2075 OMAPDSS_SIG_ACTIVE_HIGH :
2076 OMAPDSS_SIG_ACTIVE_LOW; 2076 OMAPDSS_SIG_ACTIVE_LOW;
2077 timings->interlace = var->vmode & FB_VMODE_INTERLACED; 2077 timings->interlace = var->vmode & FB_VMODE_INTERLACED;
2078 2078
2079 switch (var->bits_per_pixel) { 2079 switch (var->bits_per_pixel) {
2080 case 16: 2080 case 16:
2081 *bpp = 16; 2081 *bpp = 16;
2082 break; 2082 break;
2083 case 24: 2083 case 24:
2084 case 32: 2084 case 32:
2085 default: 2085 default:
2086 *bpp = 24; 2086 *bpp = 24;
2087 break; 2087 break;
2088 } 2088 }
2089 2089
2090 r = 0; 2090 r = 0;
2091 2091
2092 err: 2092 err:
2093 kfree(fbi); 2093 kfree(fbi);
2094 kfree(var); 2094 kfree(var);
2095 kfree(fbops); 2095 kfree(fbops);
2096 2096
2097 return r; 2097 return r;
2098 } 2098 }
2099 2099
2100 static int omapfb_set_def_mode(struct omapfb2_device *fbdev, 2100 static int omapfb_set_def_mode(struct omapfb2_device *fbdev,
2101 struct omap_dss_device *display, char *mode_str) 2101 struct omap_dss_device *display, char *mode_str)
2102 { 2102 {
2103 int r; 2103 int r;
2104 u8 bpp; 2104 u8 bpp;
2105 struct omap_video_timings timings, temp_timings; 2105 struct omap_video_timings timings, temp_timings;
2106 struct omapfb_display_data *d; 2106 struct omapfb_display_data *d;
2107 2107
2108 r = omapfb_mode_to_timings(mode_str, display, &timings, &bpp); 2108 r = omapfb_mode_to_timings(mode_str, display, &timings, &bpp);
2109 if (r) 2109 if (r)
2110 return r; 2110 return r;
2111 2111
2112 d = get_display_data(fbdev, display); 2112 d = get_display_data(fbdev, display);
2113 d->bpp_override = bpp; 2113 d->bpp_override = bpp;
2114 2114
2115 if (display->driver->check_timings) { 2115 if (display->driver->check_timings) {
2116 r = display->driver->check_timings(display, &timings); 2116 r = display->driver->check_timings(display, &timings);
2117 if (r) 2117 if (r)
2118 return r; 2118 return r;
2119 } else { 2119 } else {
2120 /* If check_timings is not present compare xres and yres */ 2120 /* If check_timings is not present compare xres and yres */
2121 if (display->driver->get_timings) { 2121 if (display->driver->get_timings) {
2122 display->driver->get_timings(display, &temp_timings); 2122 display->driver->get_timings(display, &temp_timings);
2123 2123
2124 if (temp_timings.x_res != timings.x_res || 2124 if (temp_timings.x_res != timings.x_res ||
2125 temp_timings.y_res != timings.y_res) 2125 temp_timings.y_res != timings.y_res)
2126 return -EINVAL; 2126 return -EINVAL;
2127 } 2127 }
2128 } 2128 }
2129 2129
2130 if (display->driver->set_timings) 2130 if (display->driver->set_timings)
2131 display->driver->set_timings(display, &timings); 2131 display->driver->set_timings(display, &timings);
2132 2132
2133 return 0; 2133 return 0;
2134 } 2134 }
2135 2135
2136 static int omapfb_get_recommended_bpp(struct omapfb2_device *fbdev, 2136 static int omapfb_get_recommended_bpp(struct omapfb2_device *fbdev,
2137 struct omap_dss_device *dssdev) 2137 struct omap_dss_device *dssdev)
2138 { 2138 {
2139 struct omapfb_display_data *d; 2139 struct omapfb_display_data *d;
2140 2140
2141 BUG_ON(dssdev->driver->get_recommended_bpp == NULL); 2141 BUG_ON(dssdev->driver->get_recommended_bpp == NULL);
2142 2142
2143 d = get_display_data(fbdev, dssdev); 2143 d = get_display_data(fbdev, dssdev);
2144 2144
2145 if (d->bpp_override != 0) 2145 if (d->bpp_override != 0)
2146 return d->bpp_override; 2146 return d->bpp_override;
2147 2147
2148 return dssdev->driver->get_recommended_bpp(dssdev); 2148 return dssdev->driver->get_recommended_bpp(dssdev);
2149 } 2149 }
2150 2150
2151 static int omapfb_parse_def_modes(struct omapfb2_device *fbdev) 2151 static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
2152 { 2152 {
2153 char *str, *options, *this_opt; 2153 char *str, *options, *this_opt;
2154 int r = 0; 2154 int r = 0;
2155 2155
2156 str = kstrdup(def_mode, GFP_KERNEL); 2156 str = kstrdup(def_mode, GFP_KERNEL);
2157 if (!str) 2157 if (!str)
2158 return -ENOMEM; 2158 return -ENOMEM;
2159 options = str; 2159 options = str;
2160 2160
2161 while (!r && (this_opt = strsep(&options, ",")) != NULL) { 2161 while (!r && (this_opt = strsep(&options, ",")) != NULL) {
2162 char *p, *display_str, *mode_str; 2162 char *p, *display_str, *mode_str;
2163 struct omap_dss_device *display; 2163 struct omap_dss_device *display;
2164 int i; 2164 int i;
2165 2165
2166 p = strchr(this_opt, ':'); 2166 p = strchr(this_opt, ':');
2167 if (!p) { 2167 if (!p) {
2168 r = -EINVAL; 2168 r = -EINVAL;
2169 break; 2169 break;
2170 } 2170 }
2171 2171
2172 *p = 0; 2172 *p = 0;
2173 display_str = this_opt; 2173 display_str = this_opt;
2174 mode_str = p + 1; 2174 mode_str = p + 1;
2175 2175
2176 display = NULL; 2176 display = NULL;
2177 for (i = 0; i < fbdev->num_displays; ++i) { 2177 for (i = 0; i < fbdev->num_displays; ++i) {
2178 if (strcmp(fbdev->displays[i].dssdev->name, 2178 if (strcmp(fbdev->displays[i].dssdev->name,
2179 display_str) == 0) { 2179 display_str) == 0) {
2180 display = fbdev->displays[i].dssdev; 2180 display = fbdev->displays[i].dssdev;
2181 break; 2181 break;
2182 } 2182 }
2183 } 2183 }
2184 2184
2185 if (!display) { 2185 if (!display) {
2186 r = -EINVAL; 2186 r = -EINVAL;
2187 break; 2187 break;
2188 } 2188 }
2189 2189
2190 r = omapfb_set_def_mode(fbdev, display, mode_str); 2190 r = omapfb_set_def_mode(fbdev, display, mode_str);
2191 if (r) 2191 if (r)
2192 break; 2192 break;
2193 } 2193 }
2194 2194
2195 kfree(str); 2195 kfree(str);
2196 2196
2197 return r; 2197 return r;
2198 } 2198 }
2199 2199
2200 static void fb_videomode_to_omap_timings(struct fb_videomode *m, 2200 static void fb_videomode_to_omap_timings(struct fb_videomode *m,
2201 struct omap_dss_device *display, 2201 struct omap_dss_device *display,
2202 struct omap_video_timings *t) 2202 struct omap_video_timings *t)
2203 { 2203 {
2204 if (display->driver->get_timings) { 2204 if (display->driver->get_timings) {
2205 display->driver->get_timings(display, t); 2205 display->driver->get_timings(display, t);
2206 } else { 2206 } else {
2207 t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; 2207 t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
2208 t->de_level = OMAPDSS_SIG_ACTIVE_HIGH; 2208 t->de_level = OMAPDSS_SIG_ACTIVE_HIGH;
2209 t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; 2209 t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES;
2210 } 2210 }
2211 2211
2212 t->x_res = m->xres; 2212 t->x_res = m->xres;
2213 t->y_res = m->yres; 2213 t->y_res = m->yres;
2214 t->pixel_clock = PICOS2KHZ(m->pixclock); 2214 t->pixel_clock = PICOS2KHZ(m->pixclock);
2215 t->hsw = m->hsync_len; 2215 t->hsw = m->hsync_len;
2216 t->hfp = m->right_margin; 2216 t->hfp = m->right_margin;
2217 t->hbp = m->left_margin; 2217 t->hbp = m->left_margin;
2218 t->vsw = m->vsync_len; 2218 t->vsw = m->vsync_len;
2219 t->vfp = m->lower_margin; 2219 t->vfp = m->lower_margin;
2220 t->vbp = m->upper_margin; 2220 t->vbp = m->upper_margin;
2221 t->hsync_level = m->sync & FB_SYNC_HOR_HIGH_ACT ? 2221 t->hsync_level = m->sync & FB_SYNC_HOR_HIGH_ACT ?
2222 OMAPDSS_SIG_ACTIVE_HIGH : 2222 OMAPDSS_SIG_ACTIVE_HIGH :
2223 OMAPDSS_SIG_ACTIVE_LOW; 2223 OMAPDSS_SIG_ACTIVE_LOW;
2224 t->vsync_level = m->sync & FB_SYNC_VERT_HIGH_ACT ? 2224 t->vsync_level = m->sync & FB_SYNC_VERT_HIGH_ACT ?
2225 OMAPDSS_SIG_ACTIVE_HIGH : 2225 OMAPDSS_SIG_ACTIVE_HIGH :
2226 OMAPDSS_SIG_ACTIVE_LOW; 2226 OMAPDSS_SIG_ACTIVE_LOW;
2227 t->interlace = m->vmode & FB_VMODE_INTERLACED; 2227 t->interlace = m->vmode & FB_VMODE_INTERLACED;
2228 } 2228 }
2229 2229
2230 static int omapfb_find_best_mode(struct omap_dss_device *display, 2230 static int omapfb_find_best_mode(struct omap_dss_device *display,
2231 struct omap_video_timings *timings) 2231 struct omap_video_timings *timings)
2232 { 2232 {
2233 struct fb_monspecs *specs; 2233 struct fb_monspecs *specs;
2234 u8 *edid; 2234 u8 *edid;
2235 int r, i, best_xres, best_idx, len; 2235 int r, i, best_xres, best_idx, len;
2236 2236
2237 if (!display->driver->read_edid) 2237 if (!display->driver->read_edid)
2238 return -ENODEV; 2238 return -ENODEV;
2239 2239
2240 len = 0x80 * 2; 2240 len = 0x80 * 2;
2241 edid = kmalloc(len, GFP_KERNEL); 2241 edid = kmalloc(len, GFP_KERNEL);
2242 2242
2243 r = display->driver->read_edid(display, edid, len); 2243 r = display->driver->read_edid(display, edid, len);
2244 if (r < 0) 2244 if (r < 0)
2245 goto err1; 2245 goto err1;
2246 2246
2247 specs = kzalloc(sizeof(*specs), GFP_KERNEL); 2247 specs = kzalloc(sizeof(*specs), GFP_KERNEL);
2248 2248
2249 fb_edid_to_monspecs(edid, specs); 2249 fb_edid_to_monspecs(edid, specs);
2250 2250
2251 if (edid[126] > 0) 2251 if (edid[126] > 0)
2252 fb_edid_add_monspecs(edid + 0x80, specs); 2252 fb_edid_add_monspecs(edid + 0x80, specs);
2253 2253
2254 best_xres = 0; 2254 best_xres = 0;
2255 best_idx = -1; 2255 best_idx = -1;
2256 2256
2257 for (i = 0; i < specs->modedb_len; ++i) { 2257 for (i = 0; i < specs->modedb_len; ++i) {
2258 struct fb_videomode *m; 2258 struct fb_videomode *m;
2259 struct omap_video_timings t; 2259 struct omap_video_timings t;
2260 2260
2261 m = &specs->modedb[i]; 2261 m = &specs->modedb[i];
2262 2262
2263 if (m->pixclock == 0) 2263 if (m->pixclock == 0)
2264 continue; 2264 continue;
2265 2265
2266 /* skip repeated pixel modes */ 2266 /* skip repeated pixel modes */
2267 if (m->xres == 2880 || m->xres == 1440) 2267 if (m->xres == 2880 || m->xres == 1440)
2268 continue; 2268 continue;
2269 2269
2270 fb_videomode_to_omap_timings(m, display, &t); 2270 fb_videomode_to_omap_timings(m, display, &t);
2271 2271
2272 r = display->driver->check_timings(display, &t); 2272 r = display->driver->check_timings(display, &t);
2273 if (r == 0 && best_xres < m->xres) { 2273 if (r == 0 && best_xres < m->xres) {
2274 best_xres = m->xres; 2274 best_xres = m->xres;
2275 best_idx = i; 2275 best_idx = i;
2276 } 2276 }
2277 } 2277 }
2278 2278
2279 if (best_xres == 0) { 2279 if (best_xres == 0) {
2280 r = -ENOENT; 2280 r = -ENOENT;
2281 goto err2; 2281 goto err2;
2282 } 2282 }
2283 2283
2284 fb_videomode_to_omap_timings(&specs->modedb[best_idx], display, 2284 fb_videomode_to_omap_timings(&specs->modedb[best_idx], display,
2285 timings); 2285 timings);
2286 2286
2287 r = 0; 2287 r = 0;
2288 2288
2289 err2: 2289 err2:
2290 fb_destroy_modedb(specs->modedb); 2290 fb_destroy_modedb(specs->modedb);
2291 kfree(specs); 2291 kfree(specs);
2292 err1: 2292 err1:
2293 kfree(edid); 2293 kfree(edid);
2294 2294
2295 return r; 2295 return r;
2296 } 2296 }
2297 2297
2298 static int omapfb_init_display(struct omapfb2_device *fbdev, 2298 static int omapfb_init_display(struct omapfb2_device *fbdev,
2299 struct omap_dss_device *dssdev) 2299 struct omap_dss_device *dssdev)
2300 { 2300 {
2301 struct omap_dss_driver *dssdrv = dssdev->driver; 2301 struct omap_dss_driver *dssdrv = dssdev->driver;
2302 struct omapfb_display_data *d; 2302 struct omapfb_display_data *d;
2303 int r; 2303 int r;
2304 2304
2305 r = dssdrv->enable(dssdev); 2305 r = dssdrv->enable(dssdev);
2306 if (r) { 2306 if (r) {
2307 dev_warn(fbdev->dev, "Failed to enable display '%s'\n", 2307 dev_warn(fbdev->dev, "Failed to enable display '%s'\n",
2308 dssdev->name); 2308 dssdev->name);
2309 return r; 2309 return r;
2310 } 2310 }
2311 2311
2312 d = get_display_data(fbdev, dssdev); 2312 d = get_display_data(fbdev, dssdev);
2313 2313
2314 d->fbdev = fbdev; 2314 d->fbdev = fbdev;
2315 2315
2316 if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { 2316 if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
2317 u16 w, h; 2317 u16 w, h;
2318 2318
2319 if (auto_update) { 2319 if (auto_update) {
2320 omapfb_start_auto_update(fbdev, dssdev); 2320 omapfb_start_auto_update(fbdev, dssdev);
2321 d->update_mode = OMAPFB_AUTO_UPDATE; 2321 d->update_mode = OMAPFB_AUTO_UPDATE;
2322 } else { 2322 } else {
2323 d->update_mode = OMAPFB_MANUAL_UPDATE; 2323 d->update_mode = OMAPFB_MANUAL_UPDATE;
2324 } 2324 }
2325 2325
2326 if (dssdrv->enable_te) { 2326 if (dssdrv->enable_te) {
2327 r = dssdrv->enable_te(dssdev, 1); 2327 r = dssdrv->enable_te(dssdev, 1);
2328 if (r) { 2328 if (r) {
2329 dev_err(fbdev->dev, "Failed to set TE\n"); 2329 dev_err(fbdev->dev, "Failed to set TE\n");
2330 return r; 2330 return r;
2331 } 2331 }
2332 } 2332 }
2333 2333
2334 dssdrv->get_resolution(dssdev, &w, &h); 2334 dssdrv->get_resolution(dssdev, &w, &h);
2335 r = dssdrv->update(dssdev, 0, 0, w, h); 2335 r = dssdrv->update(dssdev, 0, 0, w, h);
2336 if (r) { 2336 if (r) {
2337 dev_err(fbdev->dev, 2337 dev_err(fbdev->dev,
2338 "Failed to update display\n"); 2338 "Failed to update display\n");
2339 return r; 2339 return r;
2340 } 2340 }
2341 } else { 2341 } else {
2342 d->update_mode = OMAPFB_AUTO_UPDATE; 2342 d->update_mode = OMAPFB_AUTO_UPDATE;
2343 } 2343 }
2344 2344
2345 return 0; 2345 return 0;
2346 } 2346 }
2347 2347
2348 static int __init omapfb_probe(struct platform_device *pdev) 2348 static int __init omapfb_probe(struct platform_device *pdev)
2349 { 2349 {
2350 struct omapfb2_device *fbdev = NULL; 2350 struct omapfb2_device *fbdev = NULL;
2351 int r = 0; 2351 int r = 0;
2352 int i; 2352 int i;
2353 struct omap_overlay *ovl; 2353 struct omap_overlay *ovl;
2354 struct omap_dss_device *def_display; 2354 struct omap_dss_device *def_display;
2355 struct omap_dss_device *dssdev; 2355 struct omap_dss_device *dssdev;
2356 2356
2357 DBG("omapfb_probe\n"); 2357 DBG("omapfb_probe\n");
2358 2358
2359 if (pdev->num_resources != 0) { 2359 if (pdev->num_resources != 0) {
2360 dev_err(&pdev->dev, "probed for an unknown device\n"); 2360 dev_err(&pdev->dev, "probed for an unknown device\n");
2361 r = -ENODEV; 2361 r = -ENODEV;
2362 goto err0; 2362 goto err0;
2363 } 2363 }
2364 2364
2365 fbdev = kzalloc(sizeof(struct omapfb2_device), GFP_KERNEL); 2365 fbdev = kzalloc(sizeof(struct omapfb2_device), GFP_KERNEL);
2366 if (fbdev == NULL) { 2366 if (fbdev == NULL) {
2367 r = -ENOMEM; 2367 r = -ENOMEM;
2368 goto err0; 2368 goto err0;
2369 } 2369 }
2370 2370
2371 /* TODO : Replace cpu check with omap_has_vrfb once HAS_FEATURE 2371 /* TODO : Replace cpu check with omap_has_vrfb once HAS_FEATURE
2372 * available for OMAP2 and OMAP3 2372 * available for OMAP2 and OMAP3
2373 */ 2373 */
2374 if (def_vrfb && !cpu_is_omap24xx() && !cpu_is_omap34xx()) { 2374 if (def_vrfb && !cpu_is_omap24xx() && !cpu_is_omap34xx()) {
2375 def_vrfb = 0; 2375 def_vrfb = 0;
2376 dev_warn(&pdev->dev, "VRFB is not supported on this hardware, " 2376 dev_warn(&pdev->dev, "VRFB is not supported on this hardware, "
2377 "ignoring the module parameter vrfb=y\n"); 2377 "ignoring the module parameter vrfb=y\n");
2378 } 2378 }
2379 2379
2380 2380
2381 mutex_init(&fbdev->mtx); 2381 mutex_init(&fbdev->mtx);
2382 2382
2383 fbdev->dev = &pdev->dev; 2383 fbdev->dev = &pdev->dev;
2384 platform_set_drvdata(pdev, fbdev); 2384 platform_set_drvdata(pdev, fbdev);
2385 2385
2386 r = 0; 2386 r = 0;
2387 fbdev->num_displays = 0; 2387 fbdev->num_displays = 0;
2388 dssdev = NULL; 2388 dssdev = NULL;
2389 for_each_dss_dev(dssdev) { 2389 for_each_dss_dev(dssdev) {
2390 struct omapfb_display_data *d; 2390 struct omapfb_display_data *d;
2391 2391
2392 omap_dss_get_device(dssdev); 2392 omap_dss_get_device(dssdev);
2393 2393
2394 if (!dssdev->driver) { 2394 if (!dssdev->driver) {
2395 dev_warn(&pdev->dev, "no driver for display: %s\n", 2395 dev_warn(&pdev->dev, "no driver for display: %s\n",
2396 dssdev->name); 2396 dssdev->name);
2397 omap_dss_put_device(dssdev); 2397 omap_dss_put_device(dssdev);
2398 continue; 2398 continue;
2399 } 2399 }
2400 2400
2401 d = &fbdev->displays[fbdev->num_displays++]; 2401 d = &fbdev->displays[fbdev->num_displays++];
2402 d->dssdev = dssdev; 2402 d->dssdev = dssdev;
2403 if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) 2403 if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
2404 d->update_mode = OMAPFB_MANUAL_UPDATE; 2404 d->update_mode = OMAPFB_MANUAL_UPDATE;
2405 else 2405 else
2406 d->update_mode = OMAPFB_AUTO_UPDATE; 2406 d->update_mode = OMAPFB_AUTO_UPDATE;
2407 } 2407 }
2408 2408
2409 if (r) 2409 if (r)
2410 goto cleanup; 2410 goto cleanup;
2411 2411
2412 if (fbdev->num_displays == 0) { 2412 if (fbdev->num_displays == 0) {
2413 dev_err(&pdev->dev, "no displays\n"); 2413 dev_err(&pdev->dev, "no displays\n");
2414 r = -EINVAL; 2414 r = -EINVAL;
2415 goto cleanup; 2415 goto cleanup;
2416 } 2416 }
2417 2417
2418 fbdev->num_overlays = omap_dss_get_num_overlays(); 2418 fbdev->num_overlays = omap_dss_get_num_overlays();
2419 for (i = 0; i < fbdev->num_overlays; i++) 2419 for (i = 0; i < fbdev->num_overlays; i++)
2420 fbdev->overlays[i] = omap_dss_get_overlay(i); 2420 fbdev->overlays[i] = omap_dss_get_overlay(i);
2421 2421
2422 fbdev->num_managers = omap_dss_get_num_overlay_managers(); 2422 fbdev->num_managers = omap_dss_get_num_overlay_managers();
2423 for (i = 0; i < fbdev->num_managers; i++) 2423 for (i = 0; i < fbdev->num_managers; i++)
2424 fbdev->managers[i] = omap_dss_get_overlay_manager(i); 2424 fbdev->managers[i] = omap_dss_get_overlay_manager(i);
2425 2425
2426 /* gfx overlay should be the default one. find a display 2426 /* gfx overlay should be the default one. find a display
2427 * connected to that, and use it as default display */ 2427 * connected to that, and use it as default display */
2428 ovl = omap_dss_get_overlay(0); 2428 ovl = omap_dss_get_overlay(0);
2429 if (ovl->manager && ovl->manager->device) { 2429 if (ovl->manager && ovl->manager->device) {
2430 def_display = ovl->manager->device; 2430 def_display = ovl->manager->device;
2431 } else { 2431 } else {
2432 dev_warn(&pdev->dev, "cannot find default display\n"); 2432 dev_warn(&pdev->dev, "cannot find default display\n");
2433 def_display = NULL; 2433 def_display = NULL;
2434 } 2434 }
2435 2435
2436 if (def_mode && strlen(def_mode) > 0) { 2436 if (def_mode && strlen(def_mode) > 0) {
2437 if (omapfb_parse_def_modes(fbdev)) 2437 if (omapfb_parse_def_modes(fbdev))
2438 dev_warn(&pdev->dev, "cannot parse default modes\n"); 2438 dev_warn(&pdev->dev, "cannot parse default modes\n");
2439 } else if (def_display && def_display->driver->set_timings && 2439 } else if (def_display && def_display->driver->set_timings &&
2440 def_display->driver->check_timings) { 2440 def_display->driver->check_timings) {
2441 struct omap_video_timings t; 2441 struct omap_video_timings t;
2442 2442
2443 r = omapfb_find_best_mode(def_display, &t); 2443 r = omapfb_find_best_mode(def_display, &t);
2444 2444
2445 if (r == 0) 2445 if (r == 0)
2446 def_display->driver->set_timings(def_display, &t); 2446 def_display->driver->set_timings(def_display, &t);
2447 } 2447 }
2448 2448
2449 r = omapfb_create_framebuffers(fbdev); 2449 r = omapfb_create_framebuffers(fbdev);
2450 if (r) 2450 if (r)
2451 goto cleanup; 2451 goto cleanup;
2452 2452
2453 for (i = 0; i < fbdev->num_managers; i++) { 2453 for (i = 0; i < fbdev->num_managers; i++) {
2454 struct omap_overlay_manager *mgr; 2454 struct omap_overlay_manager *mgr;
2455 mgr = fbdev->managers[i]; 2455 mgr = fbdev->managers[i];
2456 r = mgr->apply(mgr); 2456 r = mgr->apply(mgr);
2457 if (r) 2457 if (r)
2458 dev_warn(fbdev->dev, "failed to apply dispc config\n"); 2458 dev_warn(fbdev->dev, "failed to apply dispc config\n");
2459 } 2459 }
2460 2460
2461 DBG("mgr->apply'ed\n"); 2461 DBG("mgr->apply'ed\n");
2462 2462
2463 if (def_display) { 2463 if (def_display) {
2464 r = omapfb_init_display(fbdev, def_display); 2464 r = omapfb_init_display(fbdev, def_display);
2465 if (r) { 2465 if (r) {
2466 dev_err(fbdev->dev, 2466 dev_err(fbdev->dev,
2467 "failed to initialize default " 2467 "failed to initialize default "
2468 "display\n"); 2468 "display\n");
2469 goto cleanup; 2469 goto cleanup;
2470 } 2470 }
2471 } 2471 }
2472 2472
2473 DBG("create sysfs for fbs\n"); 2473 DBG("create sysfs for fbs\n");
2474 r = omapfb_create_sysfs(fbdev); 2474 r = omapfb_create_sysfs(fbdev);
2475 if (r) { 2475 if (r) {
2476 dev_err(fbdev->dev, "failed to create sysfs entries\n"); 2476 dev_err(fbdev->dev, "failed to create sysfs entries\n");
2477 goto cleanup; 2477 goto cleanup;
2478 } 2478 }
2479 2479
2480 return 0; 2480 return 0;
2481 2481
2482 cleanup: 2482 cleanup:
2483 omapfb_free_resources(fbdev); 2483 omapfb_free_resources(fbdev);
2484 err0: 2484 err0:
2485 dev_err(&pdev->dev, "failed to setup omapfb\n"); 2485 dev_err(&pdev->dev, "failed to setup omapfb\n");
2486 return r; 2486 return r;
2487 } 2487 }
2488 2488
2489 static int __exit omapfb_remove(struct platform_device *pdev) 2489 static int __exit omapfb_remove(struct platform_device *pdev)
2490 { 2490 {
2491 struct omapfb2_device *fbdev = platform_get_drvdata(pdev); 2491 struct omapfb2_device *fbdev = platform_get_drvdata(pdev);
2492 2492
2493 /* FIXME: wait till completion of pending events */ 2493 /* FIXME: wait till completion of pending events */
2494 2494
2495 omapfb_remove_sysfs(fbdev); 2495 omapfb_remove_sysfs(fbdev);
2496 2496
2497 omapfb_free_resources(fbdev); 2497 omapfb_free_resources(fbdev);
2498 2498
2499 return 0; 2499 return 0;
2500 } 2500 }
2501 2501
2502 static struct platform_driver omapfb_driver = { 2502 static struct platform_driver omapfb_driver = {
2503 .remove = __exit_p(omapfb_remove), 2503 .remove = __exit_p(omapfb_remove),
2504 .driver = { 2504 .driver = {
2505 .name = "omapfb", 2505 .name = "omapfb",
2506 .owner = THIS_MODULE, 2506 .owner = THIS_MODULE,
2507 }, 2507 },
2508 }; 2508 };
2509 2509
2510 static int __init omapfb_init(void) 2510 static int __init omapfb_init(void)
2511 { 2511 {
2512 DBG("omapfb_init\n"); 2512 DBG("omapfb_init\n");
2513 2513
2514 if (platform_driver_probe(&omapfb_driver, omapfb_probe)) { 2514 if (platform_driver_probe(&omapfb_driver, omapfb_probe)) {
2515 printk(KERN_ERR "failed to register omapfb driver\n"); 2515 printk(KERN_ERR "failed to register omapfb driver\n");
2516 return -ENODEV; 2516 return -ENODEV;
2517 } 2517 }
2518 2518
2519 return 0; 2519 return 0;
2520 } 2520 }
2521 2521
2522 static void __exit omapfb_exit(void) 2522 static void __exit omapfb_exit(void)
2523 { 2523 {
2524 DBG("omapfb_exit\n"); 2524 DBG("omapfb_exit\n");
2525 platform_driver_unregister(&omapfb_driver); 2525 platform_driver_unregister(&omapfb_driver);
2526 } 2526 }
2527 2527
2528 module_param_named(mode, def_mode, charp, 0); 2528 module_param_named(mode, def_mode, charp, 0);
2529 module_param_named(vram, def_vram, charp, 0); 2529 module_param_named(vram, def_vram, charp, 0);
2530 module_param_named(rotate, def_rotate, int, 0); 2530 module_param_named(rotate, def_rotate, int, 0);
2531 module_param_named(vrfb, def_vrfb, bool, 0); 2531 module_param_named(vrfb, def_vrfb, bool, 0);
2532 module_param_named(mirror, def_mirror, bool, 0); 2532 module_param_named(mirror, def_mirror, bool, 0);
2533 2533
2534 /* late_initcall to let panel/ctrl drivers loaded first. 2534 /* late_initcall to let panel/ctrl drivers loaded first.
2535 * I guess better option would be a more dynamic approach, 2535 * I guess better option would be a more dynamic approach,
2536 * so that omapfb reacts to new panels when they are loaded */ 2536 * so that omapfb reacts to new panels when they are loaded */
2537 late_initcall(omapfb_init); 2537 late_initcall(omapfb_init);
2538 /*module_init(omapfb_init);*/ 2538 /*module_init(omapfb_init);*/
2539 module_exit(omapfb_exit); 2539 module_exit(omapfb_exit);
2540 2540
2541 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>"); 2541 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
2542 MODULE_DESCRIPTION("OMAP2/3 Framebuffer"); 2542 MODULE_DESCRIPTION("OMAP2/3 Framebuffer");
2543 MODULE_LICENSE("GPL v2"); 2543 MODULE_LICENSE("GPL v2");
2544 2544