diff options
author | Imre Deak <imre.deak@solidboot.com> | 2007-07-17 07:06:01 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-17 13:23:14 -0400 |
commit | 1d381b894d24d7642aec85df1cf281400ac87a18 (patch) | |
tree | 911d07969f7c1ecc00660967c00284090b41a540 /drivers/video/omap | |
parent | aae76ef13e348cebac225407ea2c452f8d0ff862 (diff) |
OMAP: add external Epson Blizzard LCD controller support
- Adds Epson Blizzard lcd controller driver; used in Nokia Internet Tablet
products.
Signed-off-by: Trilok Soni <soni.trilok@gmail.com>
Cc: Tony Lindgren <tony@atomide.com>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/video/omap')
-rw-r--r-- | drivers/video/omap/Kconfig | 6 | ||||
-rw-r--r-- | drivers/video/omap/Makefile | 1 | ||||
-rw-r--r-- | drivers/video/omap/blizzard.c | 1568 |
3 files changed, 1575 insertions, 0 deletions
diff --git a/drivers/video/omap/Kconfig b/drivers/video/omap/Kconfig index 3d36e62897ff..7f4d25b8a184 100644 --- a/drivers/video/omap/Kconfig +++ b/drivers/video/omap/Kconfig | |||
@@ -50,3 +50,9 @@ config FB_OMAP_LCDC_HWA742 | |||
50 | Say Y here if you want to have support for the external | 50 | Say Y here if you want to have support for the external |
51 | Epson HWA742 LCD controller. | 51 | Epson HWA742 LCD controller. |
52 | 52 | ||
53 | config FB_OMAP_LCDC_BLIZZARD | ||
54 | bool "Epson Blizzard LCD controller support" | ||
55 | depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL | ||
56 | help | ||
57 | Say Y here if you want to have support for the external | ||
58 | Epson Blizzard LCD controller. | ||
diff --git a/drivers/video/omap/Makefile b/drivers/video/omap/Makefile index d1cc4709fc41..41610505d282 100644 --- a/drivers/video/omap/Makefile +++ b/drivers/video/omap/Makefile | |||
@@ -13,6 +13,7 @@ objs-$(CONFIG_ARCH_OMAP1)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += sossi.o | |||
13 | objs-$(CONFIG_ARCH_OMAP2)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += rfbi.o | 13 | objs-$(CONFIG_ARCH_OMAP2)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += rfbi.o |
14 | 14 | ||
15 | objs-y$(CONFIG_FB_OMAP_LCDC_HWA742) += hwa742.o | 15 | objs-y$(CONFIG_FB_OMAP_LCDC_HWA742) += hwa742.o |
16 | objs-y$(CONFIG_FB_OMAP_LCDC_BLIZZARD) += blizzard.o | ||
16 | 17 | ||
17 | omapfb-objs := $(objs-yy) | 18 | omapfb-objs := $(objs-yy) |
18 | 19 | ||
diff --git a/drivers/video/omap/blizzard.c b/drivers/video/omap/blizzard.c new file mode 100644 index 000000000000..e682940a97a4 --- /dev/null +++ b/drivers/video/omap/blizzard.c | |||
@@ -0,0 +1,1568 @@ | |||
1 | /* | ||
2 | * Epson Blizzard LCD controller driver | ||
3 | * | ||
4 | * Copyright (C) 2004-2005 Nokia Corporation | ||
5 | * Authors: Juha Yrjola <juha.yrjola@nokia.com> | ||
6 | * Imre Deak <imre.deak@nokia.com> | ||
7 | * YUV support: Jussi Laako <jussi.laako@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along | ||
20 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
21 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
22 | */ | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/mm.h> | ||
25 | #include <linux/fb.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/clk.h> | ||
28 | |||
29 | #include <asm/arch/dma.h> | ||
30 | #include <asm/arch/omapfb.h> | ||
31 | #include <asm/arch/blizzard.h> | ||
32 | |||
33 | #include "dispc.h" | ||
34 | |||
35 | #define MODULE_NAME "blizzard" | ||
36 | |||
37 | #define BLIZZARD_REV_CODE 0x00 | ||
38 | #define BLIZZARD_CONFIG 0x02 | ||
39 | #define BLIZZARD_PLL_DIV 0x04 | ||
40 | #define BLIZZARD_PLL_LOCK_RANGE 0x06 | ||
41 | #define BLIZZARD_PLL_CLOCK_SYNTH_0 0x08 | ||
42 | #define BLIZZARD_PLL_CLOCK_SYNTH_1 0x0a | ||
43 | #define BLIZZARD_PLL_MODE 0x0c | ||
44 | #define BLIZZARD_CLK_SRC 0x0e | ||
45 | #define BLIZZARD_MEM_BANK0_ACTIVATE 0x10 | ||
46 | #define BLIZZARD_MEM_BANK0_STATUS 0x14 | ||
47 | #define BLIZZARD_HDISP 0x2a | ||
48 | #define BLIZZARD_HNDP 0x2c | ||
49 | #define BLIZZARD_VDISP0 0x2e | ||
50 | #define BLIZZARD_VDISP1 0x30 | ||
51 | #define BLIZZARD_VNDP 0x32 | ||
52 | #define BLIZZARD_HSW 0x34 | ||
53 | #define BLIZZARD_VSW 0x38 | ||
54 | #define BLIZZARD_DISPLAY_MODE 0x68 | ||
55 | #define BLIZZARD_INPUT_WIN_X_START_0 0x6c | ||
56 | #define BLIZZARD_DATA_SOURCE_SELECT 0x8e | ||
57 | #define BLIZZARD_DISP_MEM_DATA_PORT 0x90 | ||
58 | #define BLIZZARD_DISP_MEM_READ_ADDR0 0x92 | ||
59 | #define BLIZZARD_POWER_SAVE 0xE6 | ||
60 | #define BLIZZARD_NDISP_CTRL_STATUS 0xE8 | ||
61 | |||
62 | /* Data source select */ | ||
63 | /* For S1D13745 */ | ||
64 | #define BLIZZARD_SRC_WRITE_LCD_BACKGROUND 0x00 | ||
65 | #define BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE 0x01 | ||
66 | #define BLIZZARD_SRC_WRITE_OVERLAY_ENABLE 0x04 | ||
67 | #define BLIZZARD_SRC_DISABLE_OVERLAY 0x05 | ||
68 | /* For S1D13744 */ | ||
69 | #define BLIZZARD_SRC_WRITE_LCD 0x00 | ||
70 | #define BLIZZARD_SRC_BLT_LCD 0x06 | ||
71 | |||
72 | #define BLIZZARD_COLOR_RGB565 0x01 | ||
73 | #define BLIZZARD_COLOR_YUV420 0x09 | ||
74 | |||
75 | #define BLIZZARD_VERSION_S1D13745 0x01 /* Hailstorm */ | ||
76 | #define BLIZZARD_VERSION_S1D13744 0x02 /* Blizzard */ | ||
77 | |||
78 | #define BLIZZARD_AUTO_UPDATE_TIME (HZ / 20) | ||
79 | |||
80 | /* Reserve 4 request slots for requests in irq context */ | ||
81 | #define REQ_POOL_SIZE 24 | ||
82 | #define IRQ_REQ_POOL_SIZE 4 | ||
83 | |||
84 | #define REQ_FROM_IRQ_POOL 0x01 | ||
85 | |||
86 | #define REQ_COMPLETE 0 | ||
87 | #define REQ_PENDING 1 | ||
88 | |||
89 | struct blizzard_reg_list { | ||
90 | int start; | ||
91 | int end; | ||
92 | }; | ||
93 | |||
94 | /* These need to be saved / restored separately from the rest. */ | ||
95 | static struct blizzard_reg_list blizzard_pll_regs[] = { | ||
96 | { | ||
97 | .start = 0x04, /* Don't save PLL ctrl (0x0C) */ | ||
98 | .end = 0x0a, | ||
99 | }, | ||
100 | { | ||
101 | .start = 0x0e, /* Clock configuration */ | ||
102 | .end = 0x0e, | ||
103 | }, | ||
104 | }; | ||
105 | |||
106 | static struct blizzard_reg_list blizzard_gen_regs[] = { | ||
107 | { | ||
108 | .start = 0x18, /* SDRAM control */ | ||
109 | .end = 0x20, | ||
110 | }, | ||
111 | { | ||
112 | .start = 0x28, /* LCD Panel configuration */ | ||
113 | .end = 0x5a, /* HSSI interface, TV configuration */ | ||
114 | }, | ||
115 | }; | ||
116 | |||
117 | static u8 blizzard_reg_cache[0x5a / 2]; | ||
118 | |||
119 | struct update_param { | ||
120 | int plane; | ||
121 | int x, y, width, height; | ||
122 | int out_x, out_y; | ||
123 | int out_width, out_height; | ||
124 | int color_mode; | ||
125 | int bpp; | ||
126 | int flags; | ||
127 | }; | ||
128 | |||
129 | struct blizzard_request { | ||
130 | struct list_head entry; | ||
131 | unsigned int flags; | ||
132 | |||
133 | int (*handler)(struct blizzard_request *req); | ||
134 | void (*complete)(void *data); | ||
135 | void *complete_data; | ||
136 | |||
137 | union { | ||
138 | struct update_param update; | ||
139 | struct completion *sync; | ||
140 | } par; | ||
141 | }; | ||
142 | |||
143 | struct plane_info { | ||
144 | unsigned long offset; | ||
145 | int pos_x, pos_y; | ||
146 | int width, height; | ||
147 | int out_width, out_height; | ||
148 | int scr_width; | ||
149 | int color_mode; | ||
150 | int bpp; | ||
151 | }; | ||
152 | |||
153 | struct blizzard_struct { | ||
154 | enum omapfb_update_mode update_mode; | ||
155 | enum omapfb_update_mode update_mode_before_suspend; | ||
156 | |||
157 | struct timer_list auto_update_timer; | ||
158 | int stop_auto_update; | ||
159 | struct omapfb_update_window auto_update_window; | ||
160 | int enabled_planes; | ||
161 | int vid_nonstd_color; | ||
162 | int vid_scaled; | ||
163 | int last_color_mode; | ||
164 | int zoom_on; | ||
165 | int screen_width; | ||
166 | int screen_height; | ||
167 | unsigned te_connected:1; | ||
168 | unsigned vsync_only:1; | ||
169 | |||
170 | struct plane_info plane[OMAPFB_PLANE_NUM]; | ||
171 | |||
172 | struct blizzard_request req_pool[REQ_POOL_SIZE]; | ||
173 | struct list_head pending_req_list; | ||
174 | struct list_head free_req_list; | ||
175 | struct semaphore req_sema; | ||
176 | spinlock_t req_lock; | ||
177 | |||
178 | unsigned long sys_ck_rate; | ||
179 | struct extif_timings reg_timings, lut_timings; | ||
180 | |||
181 | u32 max_transmit_size; | ||
182 | u32 extif_clk_period; | ||
183 | int extif_clk_div; | ||
184 | unsigned long pix_tx_time; | ||
185 | unsigned long line_upd_time; | ||
186 | |||
187 | struct omapfb_device *fbdev; | ||
188 | struct lcd_ctrl_extif *extif; | ||
189 | struct lcd_ctrl *int_ctrl; | ||
190 | |||
191 | void (*power_up)(struct device *dev); | ||
192 | void (*power_down)(struct device *dev); | ||
193 | |||
194 | int version; | ||
195 | } blizzard; | ||
196 | |||
197 | struct lcd_ctrl blizzard_ctrl; | ||
198 | |||
199 | static u8 blizzard_read_reg(u8 reg) | ||
200 | { | ||
201 | u8 data; | ||
202 | |||
203 | blizzard.extif->set_bits_per_cycle(8); | ||
204 | blizzard.extif->write_command(®, 1); | ||
205 | blizzard.extif->read_data(&data, 1); | ||
206 | |||
207 | return data; | ||
208 | } | ||
209 | |||
210 | static void blizzard_write_reg(u8 reg, u8 val) | ||
211 | { | ||
212 | blizzard.extif->set_bits_per_cycle(8); | ||
213 | blizzard.extif->write_command(®, 1); | ||
214 | blizzard.extif->write_data(&val, 1); | ||
215 | } | ||
216 | |||
217 | static void blizzard_restart_sdram(void) | ||
218 | { | ||
219 | unsigned long tmo; | ||
220 | |||
221 | blizzard_write_reg(BLIZZARD_MEM_BANK0_ACTIVATE, 0); | ||
222 | udelay(50); | ||
223 | blizzard_write_reg(BLIZZARD_MEM_BANK0_ACTIVATE, 1); | ||
224 | tmo = jiffies + msecs_to_jiffies(200); | ||
225 | while (!(blizzard_read_reg(BLIZZARD_MEM_BANK0_STATUS) & 0x01)) { | ||
226 | if (time_after(jiffies, tmo)) { | ||
227 | dev_err(blizzard.fbdev->dev, | ||
228 | "s1d1374x: SDRAM not ready"); | ||
229 | break; | ||
230 | } | ||
231 | msleep(1); | ||
232 | } | ||
233 | } | ||
234 | |||
235 | static void blizzard_stop_sdram(void) | ||
236 | { | ||
237 | blizzard_write_reg(BLIZZARD_MEM_BANK0_ACTIVATE, 0); | ||
238 | } | ||
239 | |||
240 | /* Wait until the last window was completely written into the controllers | ||
241 | * SDRAM and we can start transferring the next window. | ||
242 | */ | ||
243 | static void blizzard_wait_line_buffer(void) | ||
244 | { | ||
245 | unsigned long tmo = jiffies + msecs_to_jiffies(30); | ||
246 | |||
247 | while (blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS) & (1 << 7)) { | ||
248 | if (time_after(jiffies, tmo)) { | ||
249 | if (printk_ratelimit()) | ||
250 | dev_err(blizzard.fbdev->dev, | ||
251 | "s1d1374x: line buffer not ready\n"); | ||
252 | break; | ||
253 | } | ||
254 | } | ||
255 | } | ||
256 | |||
257 | /* Wait until the YYC color space converter is idle. */ | ||
258 | static void blizzard_wait_yyc(void) | ||
259 | { | ||
260 | unsigned long tmo = jiffies + msecs_to_jiffies(30); | ||
261 | |||
262 | while (blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS) & (1 << 4)) { | ||
263 | if (time_after(jiffies, tmo)) { | ||
264 | if (printk_ratelimit()) | ||
265 | dev_err(blizzard.fbdev->dev, | ||
266 | "s1d1374x: YYC not ready\n"); | ||
267 | break; | ||
268 | } | ||
269 | } | ||
270 | } | ||
271 | |||
272 | static void disable_overlay(void) | ||
273 | { | ||
274 | blizzard_write_reg(BLIZZARD_DATA_SOURCE_SELECT, | ||
275 | BLIZZARD_SRC_DISABLE_OVERLAY); | ||
276 | } | ||
277 | |||
278 | static void set_window_regs(int x_start, int y_start, int x_end, int y_end, | ||
279 | int x_out_start, int y_out_start, | ||
280 | int x_out_end, int y_out_end, int color_mode, | ||
281 | int zoom_off, int flags) | ||
282 | { | ||
283 | u8 tmp[18]; | ||
284 | u8 cmd; | ||
285 | |||
286 | x_end--; | ||
287 | y_end--; | ||
288 | tmp[0] = x_start; | ||
289 | tmp[1] = x_start >> 8; | ||
290 | tmp[2] = y_start; | ||
291 | tmp[3] = y_start >> 8; | ||
292 | tmp[4] = x_end; | ||
293 | tmp[5] = x_end >> 8; | ||
294 | tmp[6] = y_end; | ||
295 | tmp[7] = y_end >> 8; | ||
296 | |||
297 | x_out_end--; | ||
298 | y_out_end--; | ||
299 | tmp[8] = x_out_start; | ||
300 | tmp[9] = x_out_start >> 8; | ||
301 | tmp[10] = y_out_start; | ||
302 | tmp[11] = y_out_start >> 8; | ||
303 | tmp[12] = x_out_end; | ||
304 | tmp[13] = x_out_end >> 8; | ||
305 | tmp[14] = y_out_end; | ||
306 | tmp[15] = y_out_end >> 8; | ||
307 | |||
308 | tmp[16] = color_mode; | ||
309 | if (zoom_off && blizzard.version == BLIZZARD_VERSION_S1D13745) | ||
310 | tmp[17] = BLIZZARD_SRC_WRITE_LCD_BACKGROUND; | ||
311 | else if (flags & OMAPFB_FORMAT_FLAG_ENABLE_OVERLAY) | ||
312 | tmp[17] = BLIZZARD_SRC_WRITE_OVERLAY_ENABLE; | ||
313 | else | ||
314 | tmp[17] = blizzard.version == BLIZZARD_VERSION_S1D13744 ? | ||
315 | BLIZZARD_SRC_WRITE_LCD : | ||
316 | BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE; | ||
317 | |||
318 | blizzard.extif->set_bits_per_cycle(8); | ||
319 | cmd = BLIZZARD_INPUT_WIN_X_START_0; | ||
320 | blizzard.extif->write_command(&cmd, 1); | ||
321 | blizzard.extif->write_data(tmp, 18); | ||
322 | } | ||
323 | |||
324 | static void enable_tearsync(int y, int width, int height, int screen_height, | ||
325 | int out_height, int force_vsync) | ||
326 | { | ||
327 | u8 b; | ||
328 | |||
329 | b = blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS); | ||
330 | b |= 1 << 3; | ||
331 | blizzard_write_reg(BLIZZARD_NDISP_CTRL_STATUS, b); | ||
332 | |||
333 | if (likely(blizzard.vsync_only || force_vsync)) { | ||
334 | blizzard.extif->enable_tearsync(1, 0); | ||
335 | return; | ||
336 | } | ||
337 | |||
338 | if (width * blizzard.pix_tx_time < blizzard.line_upd_time) { | ||
339 | blizzard.extif->enable_tearsync(1, 0); | ||
340 | return; | ||
341 | } | ||
342 | |||
343 | if ((width * blizzard.pix_tx_time / 1000) * height < | ||
344 | (y + out_height) * (blizzard.line_upd_time / 1000)) { | ||
345 | blizzard.extif->enable_tearsync(1, 0); | ||
346 | return; | ||
347 | } | ||
348 | |||
349 | blizzard.extif->enable_tearsync(1, y + 1); | ||
350 | } | ||
351 | |||
352 | static void disable_tearsync(void) | ||
353 | { | ||
354 | u8 b; | ||
355 | |||
356 | blizzard.extif->enable_tearsync(0, 0); | ||
357 | b = blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS); | ||
358 | b &= ~(1 << 3); | ||
359 | blizzard_write_reg(BLIZZARD_NDISP_CTRL_STATUS, b); | ||
360 | b = blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS); | ||
361 | } | ||
362 | |||
363 | static inline void set_extif_timings(const struct extif_timings *t); | ||
364 | |||
365 | static inline struct blizzard_request *alloc_req(void) | ||
366 | { | ||
367 | unsigned long flags; | ||
368 | struct blizzard_request *req; | ||
369 | int req_flags = 0; | ||
370 | |||
371 | if (!in_interrupt()) | ||
372 | down(&blizzard.req_sema); | ||
373 | else | ||
374 | req_flags = REQ_FROM_IRQ_POOL; | ||
375 | |||
376 | spin_lock_irqsave(&blizzard.req_lock, flags); | ||
377 | BUG_ON(list_empty(&blizzard.free_req_list)); | ||
378 | req = list_entry(blizzard.free_req_list.next, | ||
379 | struct blizzard_request, entry); | ||
380 | list_del(&req->entry); | ||
381 | spin_unlock_irqrestore(&blizzard.req_lock, flags); | ||
382 | |||
383 | INIT_LIST_HEAD(&req->entry); | ||
384 | req->flags = req_flags; | ||
385 | |||
386 | return req; | ||
387 | } | ||
388 | |||
389 | static inline void free_req(struct blizzard_request *req) | ||
390 | { | ||
391 | unsigned long flags; | ||
392 | |||
393 | spin_lock_irqsave(&blizzard.req_lock, flags); | ||
394 | |||
395 | list_del(&req->entry); | ||
396 | list_add(&req->entry, &blizzard.free_req_list); | ||
397 | if (!(req->flags & REQ_FROM_IRQ_POOL)) | ||
398 | up(&blizzard.req_sema); | ||
399 | |||
400 | spin_unlock_irqrestore(&blizzard.req_lock, flags); | ||
401 | } | ||
402 | |||
403 | static void process_pending_requests(void) | ||
404 | { | ||
405 | unsigned long flags; | ||
406 | |||
407 | spin_lock_irqsave(&blizzard.req_lock, flags); | ||
408 | |||
409 | while (!list_empty(&blizzard.pending_req_list)) { | ||
410 | struct blizzard_request *req; | ||
411 | void (*complete)(void *); | ||
412 | void *complete_data; | ||
413 | |||
414 | req = list_entry(blizzard.pending_req_list.next, | ||
415 | struct blizzard_request, entry); | ||
416 | spin_unlock_irqrestore(&blizzard.req_lock, flags); | ||
417 | |||
418 | if (req->handler(req) == REQ_PENDING) | ||
419 | return; | ||
420 | |||
421 | complete = req->complete; | ||
422 | complete_data = req->complete_data; | ||
423 | free_req(req); | ||
424 | |||
425 | if (complete) | ||
426 | complete(complete_data); | ||
427 | |||
428 | spin_lock_irqsave(&blizzard.req_lock, flags); | ||
429 | } | ||
430 | |||
431 | spin_unlock_irqrestore(&blizzard.req_lock, flags); | ||
432 | } | ||
433 | |||
434 | static void submit_req_list(struct list_head *head) | ||
435 | { | ||
436 | unsigned long flags; | ||
437 | int process = 1; | ||
438 | |||
439 | spin_lock_irqsave(&blizzard.req_lock, flags); | ||
440 | if (likely(!list_empty(&blizzard.pending_req_list))) | ||
441 | process = 0; | ||
442 | list_splice_init(head, blizzard.pending_req_list.prev); | ||
443 | spin_unlock_irqrestore(&blizzard.req_lock, flags); | ||
444 | |||
445 | if (process) | ||
446 | process_pending_requests(); | ||
447 | } | ||
448 | |||
449 | static void request_complete(void *data) | ||
450 | { | ||
451 | struct blizzard_request *req = (struct blizzard_request *)data; | ||
452 | void (*complete)(void *); | ||
453 | void *complete_data; | ||
454 | |||
455 | complete = req->complete; | ||
456 | complete_data = req->complete_data; | ||
457 | |||
458 | free_req(req); | ||
459 | |||
460 | if (complete) | ||
461 | complete(complete_data); | ||
462 | |||
463 | process_pending_requests(); | ||
464 | } | ||
465 | |||
466 | |||
467 | static int do_full_screen_update(struct blizzard_request *req) | ||
468 | { | ||
469 | int i; | ||
470 | int flags; | ||
471 | |||
472 | for (i = 0; i < 3; i++) { | ||
473 | struct plane_info *p = &blizzard.plane[i]; | ||
474 | if (!(blizzard.enabled_planes & (1 << i))) { | ||
475 | blizzard.int_ctrl->enable_plane(i, 0); | ||
476 | continue; | ||
477 | } | ||
478 | dev_dbg(blizzard.fbdev->dev, "pw %d ph %d\n", | ||
479 | p->width, p->height); | ||
480 | blizzard.int_ctrl->setup_plane(i, | ||
481 | OMAPFB_CHANNEL_OUT_LCD, p->offset, | ||
482 | p->scr_width, p->pos_x, p->pos_y, | ||
483 | p->width, p->height, | ||
484 | p->color_mode); | ||
485 | blizzard.int_ctrl->enable_plane(i, 1); | ||
486 | } | ||
487 | |||
488 | dev_dbg(blizzard.fbdev->dev, "sw %d sh %d\n", | ||
489 | blizzard.screen_width, blizzard.screen_height); | ||
490 | blizzard_wait_line_buffer(); | ||
491 | flags = req->par.update.flags; | ||
492 | if (flags & OMAPFB_FORMAT_FLAG_TEARSYNC) | ||
493 | enable_tearsync(0, blizzard.screen_width, | ||
494 | blizzard.screen_height, | ||
495 | blizzard.screen_height, | ||
496 | blizzard.screen_height, | ||
497 | flags & OMAPFB_FORMAT_FLAG_FORCE_VSYNC); | ||
498 | else | ||
499 | disable_tearsync(); | ||
500 | |||
501 | set_window_regs(0, 0, blizzard.screen_width, blizzard.screen_height, | ||
502 | 0, 0, blizzard.screen_width, blizzard.screen_height, | ||
503 | BLIZZARD_COLOR_RGB565, blizzard.zoom_on, flags); | ||
504 | blizzard.zoom_on = 0; | ||
505 | |||
506 | blizzard.extif->set_bits_per_cycle(16); | ||
507 | /* set_window_regs has left the register index at the right | ||
508 | * place, so no need to set it here. | ||
509 | */ | ||
510 | blizzard.extif->transfer_area(blizzard.screen_width, | ||
511 | blizzard.screen_height, | ||
512 | request_complete, req); | ||
513 | return REQ_PENDING; | ||
514 | } | ||
515 | |||
516 | /* Setup all planes with an overlapping area with the update window. */ | ||
517 | static int do_partial_update(struct blizzard_request *req, int plane, | ||
518 | int x, int y, int w, int h, | ||
519 | int x_out, int y_out, int w_out, int h_out, | ||
520 | int wnd_color_mode, int bpp) | ||
521 | { | ||
522 | int i; | ||
523 | int gx1, gy1, gx2, gy2; | ||
524 | int gx1_out, gy1_out, gx2_out, gy2_out; | ||
525 | int color_mode; | ||
526 | int flags; | ||
527 | int zoom_off; | ||
528 | |||
529 | /* Global coordinates, relative to pixel 0,0 of the LCD */ | ||
530 | gx1 = x + blizzard.plane[plane].pos_x; | ||
531 | gy1 = y + blizzard.plane[plane].pos_y; | ||
532 | gx2 = gx1 + w; | ||
533 | gy2 = gy1 + h; | ||
534 | |||
535 | flags = req->par.update.flags; | ||
536 | if (flags & OMAPFB_FORMAT_FLAG_DOUBLE) { | ||
537 | gx1_out = gx1; | ||
538 | gy1_out = gy1; | ||
539 | gx2_out = gx1 + w * 2; | ||
540 | gy2_out = gy1 + h * 2; | ||
541 | } else { | ||
542 | gx1_out = x_out + blizzard.plane[plane].pos_x; | ||
543 | gy1_out = y_out + blizzard.plane[plane].pos_y; | ||
544 | gx2_out = gx1_out + w_out; | ||
545 | gy2_out = gy1_out + h_out; | ||
546 | } | ||
547 | zoom_off = blizzard.zoom_on && gx1 == 0 && gy1 == 0 && | ||
548 | w == blizzard.screen_width && h == blizzard.screen_height; | ||
549 | blizzard.zoom_on = (!zoom_off && blizzard.zoom_on) || | ||
550 | (w < w_out || h < h_out); | ||
551 | |||
552 | for (i = 0; i < OMAPFB_PLANE_NUM; i++) { | ||
553 | struct plane_info *p = &blizzard.plane[i]; | ||
554 | int px1, py1; | ||
555 | int px2, py2; | ||
556 | int pw, ph; | ||
557 | int pposx, pposy; | ||
558 | unsigned long offset; | ||
559 | |||
560 | if (!(blizzard.enabled_planes & (1 << i)) || | ||
561 | (wnd_color_mode && i != plane)) { | ||
562 | blizzard.int_ctrl->enable_plane(i, 0); | ||
563 | continue; | ||
564 | } | ||
565 | /* Plane coordinates */ | ||
566 | if (i == plane) { | ||
567 | /* Plane in which we are doing the update. | ||
568 | * Local coordinates are the one in the update | ||
569 | * request. | ||
570 | */ | ||
571 | px1 = x; | ||
572 | py1 = y; | ||
573 | px2 = x + w; | ||
574 | py2 = y + h; | ||
575 | pposx = 0; | ||
576 | pposy = 0; | ||
577 | } else { | ||
578 | /* Check if this plane has an overlapping part */ | ||
579 | px1 = gx1 - p->pos_x; | ||
580 | py1 = gy1 - p->pos_y; | ||
581 | px2 = gx2 - p->pos_x; | ||
582 | py2 = gy2 - p->pos_y; | ||
583 | if (px1 >= p->width || py1 >= p->height || | ||
584 | px2 <= 0 || py2 <= 0) { | ||
585 | blizzard.int_ctrl->enable_plane(i, 0); | ||
586 | continue; | ||
587 | } | ||
588 | /* Calculate the coordinates for the overlapping | ||
589 | * part in the plane's local coordinates. | ||
590 | */ | ||
591 | pposx = -px1; | ||
592 | pposy = -py1; | ||
593 | if (px1 < 0) | ||
594 | px1 = 0; | ||
595 | if (py1 < 0) | ||
596 | py1 = 0; | ||
597 | if (px2 > p->width) | ||
598 | px2 = p->width; | ||
599 | if (py2 > p->height) | ||
600 | py2 = p->height; | ||
601 | if (pposx < 0) | ||
602 | pposx = 0; | ||
603 | if (pposy < 0) | ||
604 | pposy = 0; | ||
605 | } | ||
606 | pw = px2 - px1; | ||
607 | ph = py2 - py1; | ||
608 | offset = p->offset + (p->scr_width * py1 + px1) * p->bpp / 8; | ||
609 | if (wnd_color_mode) | ||
610 | /* Window embedded in the plane with a differing | ||
611 | * color mode / bpp. Calculate the number of DMA | ||
612 | * transfer elements in terms of the plane's bpp. | ||
613 | */ | ||
614 | pw = (pw + 1) * bpp / p->bpp; | ||
615 | #ifdef VERBOSE | ||
616 | dev_dbg(blizzard.fbdev->dev, | ||
617 | "plane %d offset %#08lx pposx %d pposy %d " | ||
618 | "px1 %d py1 %d pw %d ph %d\n", | ||
619 | i, offset, pposx, pposy, px1, py1, pw, ph); | ||
620 | #endif | ||
621 | blizzard.int_ctrl->setup_plane(i, | ||
622 | OMAPFB_CHANNEL_OUT_LCD, offset, | ||
623 | p->scr_width, | ||
624 | pposx, pposy, pw, ph, | ||
625 | p->color_mode); | ||
626 | |||
627 | blizzard.int_ctrl->enable_plane(i, 1); | ||
628 | } | ||
629 | |||
630 | switch (wnd_color_mode) { | ||
631 | case OMAPFB_COLOR_YUV420: | ||
632 | color_mode = BLIZZARD_COLOR_YUV420; | ||
633 | /* Currently only the 16 bits/pixel cycle format is | ||
634 | * supported on the external interface. Adjust the number | ||
635 | * of transfer elements per line for 12bpp format. | ||
636 | */ | ||
637 | w = (w + 1) * 3 / 4; | ||
638 | break; | ||
639 | default: | ||
640 | color_mode = BLIZZARD_COLOR_RGB565; | ||
641 | break; | ||
642 | } | ||
643 | |||
644 | blizzard_wait_line_buffer(); | ||
645 | if (blizzard.last_color_mode == BLIZZARD_COLOR_YUV420) | ||
646 | blizzard_wait_yyc(); | ||
647 | blizzard.last_color_mode = color_mode; | ||
648 | if (flags & OMAPFB_FORMAT_FLAG_TEARSYNC) | ||
649 | enable_tearsync(gy1, w, h, | ||
650 | blizzard.screen_height, | ||
651 | h_out, | ||
652 | flags & OMAPFB_FORMAT_FLAG_FORCE_VSYNC); | ||
653 | else | ||
654 | disable_tearsync(); | ||
655 | |||
656 | set_window_regs(gx1, gy1, gx2, gy2, gx1_out, gy1_out, gx2_out, gy2_out, | ||
657 | color_mode, zoom_off, flags); | ||
658 | |||
659 | blizzard.extif->set_bits_per_cycle(16); | ||
660 | /* set_window_regs has left the register index at the right | ||
661 | * place, so no need to set it here. | ||
662 | */ | ||
663 | blizzard.extif->transfer_area(w, h, request_complete, req); | ||
664 | |||
665 | return REQ_PENDING; | ||
666 | } | ||
667 | |||
668 | static int send_frame_handler(struct blizzard_request *req) | ||
669 | { | ||
670 | struct update_param *par = &req->par.update; | ||
671 | int plane = par->plane; | ||
672 | |||
673 | #ifdef VERBOSE | ||
674 | dev_dbg(blizzard.fbdev->dev, | ||
675 | "send_frame: x %d y %d w %d h %d " | ||
676 | "x_out %d y_out %d w_out %d h_out %d " | ||
677 | "color_mode %04x flags %04x planes %01x\n", | ||
678 | par->x, par->y, par->width, par->height, | ||
679 | par->out_x, par->out_y, par->out_width, par->out_height, | ||
680 | par->color_mode, par->flags, blizzard.enabled_planes); | ||
681 | #endif | ||
682 | if (par->flags & OMAPFB_FORMAT_FLAG_DISABLE_OVERLAY) | ||
683 | disable_overlay(); | ||
684 | |||
685 | if ((blizzard.enabled_planes & blizzard.vid_nonstd_color) || | ||
686 | (blizzard.enabled_planes & blizzard.vid_scaled)) | ||
687 | return do_full_screen_update(req); | ||
688 | |||
689 | return do_partial_update(req, plane, par->x, par->y, | ||
690 | par->width, par->height, | ||
691 | par->out_x, par->out_y, | ||
692 | par->out_width, par->out_height, | ||
693 | par->color_mode, par->bpp); | ||
694 | } | ||
695 | |||
696 | static void send_frame_complete(void *data) | ||
697 | { | ||
698 | } | ||
699 | |||
700 | #define ADD_PREQ(_x, _y, _w, _h, _x_out, _y_out, _w_out, _h_out) do { \ | ||
701 | req = alloc_req(); \ | ||
702 | req->handler = send_frame_handler; \ | ||
703 | req->complete = send_frame_complete; \ | ||
704 | req->par.update.plane = plane_idx; \ | ||
705 | req->par.update.x = _x; \ | ||
706 | req->par.update.y = _y; \ | ||
707 | req->par.update.width = _w; \ | ||
708 | req->par.update.height = _h; \ | ||
709 | req->par.update.out_x = _x_out; \ | ||
710 | req->par.update.out_y = _y_out; \ | ||
711 | req->par.update.out_width = _w_out; \ | ||
712 | req->par.update.out_height = _h_out; \ | ||
713 | req->par.update.bpp = bpp; \ | ||
714 | req->par.update.color_mode = color_mode;\ | ||
715 | req->par.update.flags = flags; \ | ||
716 | list_add_tail(&req->entry, req_head); \ | ||
717 | } while(0) | ||
718 | |||
719 | static void create_req_list(int plane_idx, | ||
720 | struct omapfb_update_window *win, | ||
721 | struct list_head *req_head) | ||
722 | { | ||
723 | struct blizzard_request *req; | ||
724 | int x = win->x; | ||
725 | int y = win->y; | ||
726 | int width = win->width; | ||
727 | int height = win->height; | ||
728 | int x_out = win->out_x; | ||
729 | int y_out = win->out_y; | ||
730 | int width_out = win->out_width; | ||
731 | int height_out = win->out_height; | ||
732 | int color_mode; | ||
733 | int bpp; | ||
734 | int flags; | ||
735 | unsigned int ystart = y; | ||
736 | unsigned int yspan = height; | ||
737 | unsigned int ystart_out = y_out; | ||
738 | unsigned int yspan_out = height_out; | ||
739 | |||
740 | flags = win->format & ~OMAPFB_FORMAT_MASK; | ||
741 | color_mode = win->format & OMAPFB_FORMAT_MASK; | ||
742 | switch (color_mode) { | ||
743 | case OMAPFB_COLOR_YUV420: | ||
744 | /* Embedded window with different color mode */ | ||
745 | bpp = 12; | ||
746 | /* X, Y, height must be aligned at 2, width at 4 pixels */ | ||
747 | x &= ~1; | ||
748 | y &= ~1; | ||
749 | height = yspan = height & ~1; | ||
750 | width = width & ~3; | ||
751 | break; | ||
752 | default: | ||
753 | /* Same as the plane color mode */ | ||
754 | bpp = blizzard.plane[plane_idx].bpp; | ||
755 | break; | ||
756 | } | ||
757 | if (width * height * bpp / 8 > blizzard.max_transmit_size) { | ||
758 | yspan = blizzard.max_transmit_size / (width * bpp / 8); | ||
759 | yspan_out = yspan * height_out / height; | ||
760 | ADD_PREQ(x, ystart, width, yspan, x_out, ystart_out, | ||
761 | width_out, yspan_out); | ||
762 | ystart += yspan; | ||
763 | ystart_out += yspan_out; | ||
764 | yspan = height - yspan; | ||
765 | yspan_out = height_out - yspan_out; | ||
766 | flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC; | ||
767 | } | ||
768 | |||
769 | ADD_PREQ(x, ystart, width, yspan, x_out, ystart_out, | ||
770 | width_out, yspan_out); | ||
771 | } | ||
772 | |||
773 | static void auto_update_complete(void *data) | ||
774 | { | ||
775 | if (!blizzard.stop_auto_update) | ||
776 | mod_timer(&blizzard.auto_update_timer, | ||
777 | jiffies + BLIZZARD_AUTO_UPDATE_TIME); | ||
778 | } | ||
779 | |||
780 | static void blizzard_update_window_auto(unsigned long arg) | ||
781 | { | ||
782 | LIST_HEAD(req_list); | ||
783 | struct blizzard_request *last; | ||
784 | struct omapfb_plane_struct *plane; | ||
785 | |||
786 | plane = blizzard.fbdev->fb_info[0]->par; | ||
787 | create_req_list(plane->idx, | ||
788 | &blizzard.auto_update_window, &req_list); | ||
789 | last = list_entry(req_list.prev, struct blizzard_request, entry); | ||
790 | |||
791 | last->complete = auto_update_complete; | ||
792 | last->complete_data = NULL; | ||
793 | |||
794 | submit_req_list(&req_list); | ||
795 | } | ||
796 | |||
797 | int blizzard_update_window_async(struct fb_info *fbi, | ||
798 | struct omapfb_update_window *win, | ||
799 | void (*complete_callback)(void *arg), | ||
800 | void *complete_callback_data) | ||
801 | { | ||
802 | LIST_HEAD(req_list); | ||
803 | struct blizzard_request *last; | ||
804 | struct omapfb_plane_struct *plane = fbi->par; | ||
805 | |||
806 | if (unlikely(blizzard.update_mode != OMAPFB_MANUAL_UPDATE)) | ||
807 | return -EINVAL; | ||
808 | if (unlikely(!blizzard.te_connected && | ||
809 | (win->format & OMAPFB_FORMAT_FLAG_TEARSYNC))) | ||
810 | return -EINVAL; | ||
811 | |||
812 | create_req_list(plane->idx, win, &req_list); | ||
813 | last = list_entry(req_list.prev, struct blizzard_request, entry); | ||
814 | |||
815 | last->complete = complete_callback; | ||
816 | last->complete_data = (void *)complete_callback_data; | ||
817 | |||
818 | submit_req_list(&req_list); | ||
819 | |||
820 | return 0; | ||
821 | } | ||
822 | EXPORT_SYMBOL(blizzard_update_window_async); | ||
823 | |||
824 | static int update_full_screen(void) | ||
825 | { | ||
826 | return blizzard_update_window_async(blizzard.fbdev->fb_info[0], | ||
827 | &blizzard.auto_update_window, NULL, NULL); | ||
828 | |||
829 | } | ||
830 | |||
831 | static int blizzard_setup_plane(int plane, int channel_out, | ||
832 | unsigned long offset, int screen_width, | ||
833 | int pos_x, int pos_y, int width, int height, | ||
834 | int color_mode) | ||
835 | { | ||
836 | struct plane_info *p; | ||
837 | |||
838 | #ifdef VERBOSE | ||
839 | dev_dbg(blizzard.fbdev->dev, | ||
840 | "plane %d ch_out %d offset %#08lx scr_width %d " | ||
841 | "pos_x %d pos_y %d width %d height %d color_mode %d\n", | ||
842 | plane, channel_out, offset, screen_width, | ||
843 | pos_x, pos_y, width, height, color_mode); | ||
844 | #endif | ||
845 | if ((unsigned)plane > OMAPFB_PLANE_NUM) | ||
846 | return -EINVAL; | ||
847 | p = &blizzard.plane[plane]; | ||
848 | |||
849 | switch (color_mode) { | ||
850 | case OMAPFB_COLOR_YUV422: | ||
851 | case OMAPFB_COLOR_YUY422: | ||
852 | p->bpp = 16; | ||
853 | blizzard.vid_nonstd_color &= ~(1 << plane); | ||
854 | break; | ||
855 | case OMAPFB_COLOR_YUV420: | ||
856 | p->bpp = 12; | ||
857 | blizzard.vid_nonstd_color |= 1 << plane; | ||
858 | break; | ||
859 | case OMAPFB_COLOR_RGB565: | ||
860 | p->bpp = 16; | ||
861 | blizzard.vid_nonstd_color &= ~(1 << plane); | ||
862 | break; | ||
863 | default: | ||
864 | return -EINVAL; | ||
865 | } | ||
866 | |||
867 | p->offset = offset; | ||
868 | p->pos_x = pos_x; | ||
869 | p->pos_y = pos_y; | ||
870 | p->width = width; | ||
871 | p->height = height; | ||
872 | p->scr_width = screen_width; | ||
873 | if (!p->out_width) | ||
874 | p->out_width = width; | ||
875 | if (!p->out_height) | ||
876 | p->out_height = height; | ||
877 | |||
878 | p->color_mode = color_mode; | ||
879 | |||
880 | return 0; | ||
881 | } | ||
882 | |||
883 | static int blizzard_set_scale(int plane, int orig_w, int orig_h, | ||
884 | int out_w, int out_h) | ||
885 | { | ||
886 | struct plane_info *p = &blizzard.plane[plane]; | ||
887 | int r; | ||
888 | |||
889 | dev_dbg(blizzard.fbdev->dev, | ||
890 | "plane %d orig_w %d orig_h %d out_w %d out_h %d\n", | ||
891 | plane, orig_w, orig_h, out_w, out_h); | ||
892 | if ((unsigned)plane > OMAPFB_PLANE_NUM) | ||
893 | return -ENODEV; | ||
894 | |||
895 | r = blizzard.int_ctrl->set_scale(plane, orig_w, orig_h, out_w, out_h); | ||
896 | if (r < 0) | ||
897 | return r; | ||
898 | |||
899 | p->width = orig_w; | ||
900 | p->height = orig_h; | ||
901 | p->out_width = out_w; | ||
902 | p->out_height = out_h; | ||
903 | if (orig_w == out_w && orig_h == out_h) | ||
904 | blizzard.vid_scaled &= ~(1 << plane); | ||
905 | else | ||
906 | blizzard.vid_scaled |= 1 << plane; | ||
907 | |||
908 | return 0; | ||
909 | } | ||
910 | |||
911 | static int blizzard_enable_plane(int plane, int enable) | ||
912 | { | ||
913 | if (enable) | ||
914 | blizzard.enabled_planes |= 1 << plane; | ||
915 | else | ||
916 | blizzard.enabled_planes &= ~(1 << plane); | ||
917 | |||
918 | return 0; | ||
919 | } | ||
920 | |||
921 | static int sync_handler(struct blizzard_request *req) | ||
922 | { | ||
923 | complete(req->par.sync); | ||
924 | return REQ_COMPLETE; | ||
925 | } | ||
926 | |||
927 | static void blizzard_sync(void) | ||
928 | { | ||
929 | LIST_HEAD(req_list); | ||
930 | struct blizzard_request *req; | ||
931 | struct completion comp; | ||
932 | |||
933 | req = alloc_req(); | ||
934 | |||
935 | req->handler = sync_handler; | ||
936 | req->complete = NULL; | ||
937 | init_completion(&comp); | ||
938 | req->par.sync = ∁ | ||
939 | |||
940 | list_add(&req->entry, &req_list); | ||
941 | submit_req_list(&req_list); | ||
942 | |||
943 | wait_for_completion(&comp); | ||
944 | } | ||
945 | |||
946 | |||
947 | static void blizzard_bind_client(struct omapfb_notifier_block *nb) | ||
948 | { | ||
949 | if (blizzard.update_mode == OMAPFB_MANUAL_UPDATE) { | ||
950 | omapfb_notify_clients(blizzard.fbdev, OMAPFB_EVENT_READY); | ||
951 | } | ||
952 | } | ||
953 | |||
954 | static int blizzard_set_update_mode(enum omapfb_update_mode mode) | ||
955 | { | ||
956 | if (unlikely(mode != OMAPFB_MANUAL_UPDATE && | ||
957 | mode != OMAPFB_AUTO_UPDATE && | ||
958 | mode != OMAPFB_UPDATE_DISABLED)) | ||
959 | return -EINVAL; | ||
960 | |||
961 | if (mode == blizzard.update_mode) | ||
962 | return 0; | ||
963 | |||
964 | dev_info(blizzard.fbdev->dev, "s1d1374x: setting update mode to %s\n", | ||
965 | mode == OMAPFB_UPDATE_DISABLED ? "disabled" : | ||
966 | (mode == OMAPFB_AUTO_UPDATE ? "auto" : "manual")); | ||
967 | |||
968 | switch (blizzard.update_mode) { | ||
969 | case OMAPFB_MANUAL_UPDATE: | ||
970 | omapfb_notify_clients(blizzard.fbdev, OMAPFB_EVENT_DISABLED); | ||
971 | break; | ||
972 | case OMAPFB_AUTO_UPDATE: | ||
973 | blizzard.stop_auto_update = 1; | ||
974 | del_timer_sync(&blizzard.auto_update_timer); | ||
975 | break; | ||
976 | case OMAPFB_UPDATE_DISABLED: | ||
977 | break; | ||
978 | } | ||
979 | |||
980 | blizzard.update_mode = mode; | ||
981 | blizzard_sync(); | ||
982 | blizzard.stop_auto_update = 0; | ||
983 | |||
984 | switch (mode) { | ||
985 | case OMAPFB_MANUAL_UPDATE: | ||
986 | omapfb_notify_clients(blizzard.fbdev, OMAPFB_EVENT_READY); | ||
987 | break; | ||
988 | case OMAPFB_AUTO_UPDATE: | ||
989 | blizzard_update_window_auto(0); | ||
990 | break; | ||
991 | case OMAPFB_UPDATE_DISABLED: | ||
992 | break; | ||
993 | } | ||
994 | |||
995 | return 0; | ||
996 | } | ||
997 | |||
998 | static enum omapfb_update_mode blizzard_get_update_mode(void) | ||
999 | { | ||
1000 | return blizzard.update_mode; | ||
1001 | } | ||
1002 | |||
1003 | static inline void set_extif_timings(const struct extif_timings *t) | ||
1004 | { | ||
1005 | blizzard.extif->set_timings(t); | ||
1006 | } | ||
1007 | |||
1008 | static inline unsigned long round_to_extif_ticks(unsigned long ps, int div) | ||
1009 | { | ||
1010 | int bus_tick = blizzard.extif_clk_period * div; | ||
1011 | return (ps + bus_tick - 1) / bus_tick * bus_tick; | ||
1012 | } | ||
1013 | |||
1014 | static int calc_reg_timing(unsigned long sysclk, int div) | ||
1015 | { | ||
1016 | struct extif_timings *t; | ||
1017 | unsigned long systim; | ||
1018 | |||
1019 | /* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns, | ||
1020 | * AccessTime 2 ns + 12.2 ns (regs), | ||
1021 | * WEOffTime = WEOnTime + 1 ns, | ||
1022 | * REOffTime = REOnTime + 12 ns (regs), | ||
1023 | * CSOffTime = REOffTime + 1 ns | ||
1024 | * ReadCycle = 2ns + 2*SYSCLK (regs), | ||
1025 | * WriteCycle = 2*SYSCLK + 2 ns, | ||
1026 | * CSPulseWidth = 10 ns */ | ||
1027 | |||
1028 | systim = 1000000000 / (sysclk / 1000); | ||
1029 | dev_dbg(blizzard.fbdev->dev, | ||
1030 | "Blizzard systim %lu ps extif_clk_period %u div %d\n", | ||
1031 | systim, blizzard.extif_clk_period, div); | ||
1032 | |||
1033 | t = &blizzard.reg_timings; | ||
1034 | memset(t, 0, sizeof(*t)); | ||
1035 | |||
1036 | t->clk_div = div; | ||
1037 | |||
1038 | t->cs_on_time = 0; | ||
1039 | t->we_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
1040 | t->re_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
1041 | t->access_time = round_to_extif_ticks(t->re_on_time + 12200, div); | ||
1042 | t->we_off_time = round_to_extif_ticks(t->we_on_time + 1000, div); | ||
1043 | t->re_off_time = round_to_extif_ticks(t->re_on_time + 13000, div); | ||
1044 | t->cs_off_time = round_to_extif_ticks(t->re_off_time + 1000, div); | ||
1045 | t->we_cycle_time = round_to_extif_ticks(2 * systim + 2000, div); | ||
1046 | if (t->we_cycle_time < t->we_off_time) | ||
1047 | t->we_cycle_time = t->we_off_time; | ||
1048 | t->re_cycle_time = round_to_extif_ticks(2 * systim + 2000, div); | ||
1049 | if (t->re_cycle_time < t->re_off_time) | ||
1050 | t->re_cycle_time = t->re_off_time; | ||
1051 | t->cs_pulse_width = 0; | ||
1052 | |||
1053 | dev_dbg(blizzard.fbdev->dev, "[reg]cson %d csoff %d reon %d reoff %d\n", | ||
1054 | t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time); | ||
1055 | dev_dbg(blizzard.fbdev->dev, "[reg]weon %d weoff %d recyc %d wecyc %d\n", | ||
1056 | t->we_on_time, t->we_off_time, t->re_cycle_time, | ||
1057 | t->we_cycle_time); | ||
1058 | dev_dbg(blizzard.fbdev->dev, "[reg]rdaccess %d cspulse %d\n", | ||
1059 | t->access_time, t->cs_pulse_width); | ||
1060 | |||
1061 | return blizzard.extif->convert_timings(t); | ||
1062 | } | ||
1063 | |||
1064 | static int calc_lut_timing(unsigned long sysclk, int div) | ||
1065 | { | ||
1066 | struct extif_timings *t; | ||
1067 | unsigned long systim; | ||
1068 | |||
1069 | /* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns, | ||
1070 | * AccessTime 2 ns + 4 * SYSCLK + 26 (lut), | ||
1071 | * WEOffTime = WEOnTime + 1 ns, | ||
1072 | * REOffTime = REOnTime + 4*SYSCLK + 26 ns (lut), | ||
1073 | * CSOffTime = REOffTime + 1 ns | ||
1074 | * ReadCycle = 2ns + 4*SYSCLK + 26 ns (lut), | ||
1075 | * WriteCycle = 2*SYSCLK + 2 ns, | ||
1076 | * CSPulseWidth = 10 ns */ | ||
1077 | |||
1078 | systim = 1000000000 / (sysclk / 1000); | ||
1079 | dev_dbg(blizzard.fbdev->dev, | ||
1080 | "Blizzard systim %lu ps extif_clk_period %u div %d\n", | ||
1081 | systim, blizzard.extif_clk_period, div); | ||
1082 | |||
1083 | t = &blizzard.lut_timings; | ||
1084 | memset(t, 0, sizeof(*t)); | ||
1085 | |||
1086 | t->clk_div = div; | ||
1087 | |||
1088 | t->cs_on_time = 0; | ||
1089 | t->we_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
1090 | t->re_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
1091 | t->access_time = round_to_extif_ticks(t->re_on_time + 4 * systim + | ||
1092 | 26000, div); | ||
1093 | t->we_off_time = round_to_extif_ticks(t->we_on_time + 1000, div); | ||
1094 | t->re_off_time = round_to_extif_ticks(t->re_on_time + 4 * systim + | ||
1095 | 26000, div); | ||
1096 | t->cs_off_time = round_to_extif_ticks(t->re_off_time + 1000, div); | ||
1097 | t->we_cycle_time = round_to_extif_ticks(2 * systim + 2000, div); | ||
1098 | if (t->we_cycle_time < t->we_off_time) | ||
1099 | t->we_cycle_time = t->we_off_time; | ||
1100 | t->re_cycle_time = round_to_extif_ticks(2000 + 4 * systim + 26000, div); | ||
1101 | if (t->re_cycle_time < t->re_off_time) | ||
1102 | t->re_cycle_time = t->re_off_time; | ||
1103 | t->cs_pulse_width = 0; | ||
1104 | |||
1105 | dev_dbg(blizzard.fbdev->dev, | ||
1106 | "[lut]cson %d csoff %d reon %d reoff %d\n", | ||
1107 | t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time); | ||
1108 | dev_dbg(blizzard.fbdev->dev, | ||
1109 | "[lut]weon %d weoff %d recyc %d wecyc %d\n", | ||
1110 | t->we_on_time, t->we_off_time, t->re_cycle_time, | ||
1111 | t->we_cycle_time); | ||
1112 | dev_dbg(blizzard.fbdev->dev, "[lut]rdaccess %d cspulse %d\n", | ||
1113 | t->access_time, t->cs_pulse_width); | ||
1114 | |||
1115 | return blizzard.extif->convert_timings(t); | ||
1116 | } | ||
1117 | |||
1118 | static int calc_extif_timings(unsigned long sysclk, int *extif_mem_div) | ||
1119 | { | ||
1120 | int max_clk_div; | ||
1121 | int div; | ||
1122 | |||
1123 | blizzard.extif->get_clk_info(&blizzard.extif_clk_period, &max_clk_div); | ||
1124 | for (div = 1; div <= max_clk_div; div++) { | ||
1125 | if (calc_reg_timing(sysclk, div) == 0) | ||
1126 | break; | ||
1127 | } | ||
1128 | if (div > max_clk_div) { | ||
1129 | dev_dbg(blizzard.fbdev->dev, "reg timing failed\n"); | ||
1130 | goto err; | ||
1131 | } | ||
1132 | *extif_mem_div = div; | ||
1133 | |||
1134 | for (div = 1; div <= max_clk_div; div++) { | ||
1135 | if (calc_lut_timing(sysclk, div) == 0) | ||
1136 | break; | ||
1137 | } | ||
1138 | |||
1139 | if (div > max_clk_div) | ||
1140 | goto err; | ||
1141 | |||
1142 | blizzard.extif_clk_div = div; | ||
1143 | |||
1144 | return 0; | ||
1145 | err: | ||
1146 | dev_err(blizzard.fbdev->dev, "can't setup timings\n"); | ||
1147 | return -1; | ||
1148 | } | ||
1149 | |||
1150 | static void calc_blizzard_clk_rates(unsigned long ext_clk, | ||
1151 | unsigned long *sys_clk, unsigned long *pix_clk) | ||
1152 | { | ||
1153 | int pix_clk_src; | ||
1154 | int sys_div = 0, sys_mul = 0; | ||
1155 | int pix_div; | ||
1156 | |||
1157 | pix_clk_src = blizzard_read_reg(BLIZZARD_CLK_SRC); | ||
1158 | pix_div = ((pix_clk_src >> 3) & 0x1f) + 1; | ||
1159 | if ((pix_clk_src & (0x3 << 1)) == 0) { | ||
1160 | /* Source is the PLL */ | ||
1161 | sys_div = (blizzard_read_reg(BLIZZARD_PLL_DIV) & 0x3f) + 1; | ||
1162 | sys_mul = blizzard_read_reg(BLIZZARD_PLL_CLOCK_SYNTH_0); | ||
1163 | sys_mul |= ((blizzard_read_reg(BLIZZARD_PLL_CLOCK_SYNTH_1) | ||
1164 | & 0x0f) << 11); | ||
1165 | *sys_clk = ext_clk * sys_mul / sys_div; | ||
1166 | } else /* else source is ext clk, or oscillator */ | ||
1167 | *sys_clk = ext_clk; | ||
1168 | |||
1169 | *pix_clk = *sys_clk / pix_div; /* HZ */ | ||
1170 | dev_dbg(blizzard.fbdev->dev, | ||
1171 | "ext_clk %ld pix_src %d pix_div %d sys_div %d sys_mul %d\n", | ||
1172 | ext_clk, pix_clk_src & (0x3 << 1), pix_div, sys_div, sys_mul); | ||
1173 | dev_dbg(blizzard.fbdev->dev, "sys_clk %ld pix_clk %ld\n", | ||
1174 | *sys_clk, *pix_clk); | ||
1175 | } | ||
1176 | |||
1177 | static int setup_tearsync(unsigned long pix_clk, int extif_div) | ||
1178 | { | ||
1179 | int hdisp, vdisp; | ||
1180 | int hndp, vndp; | ||
1181 | int hsw, vsw; | ||
1182 | int hs, vs; | ||
1183 | int hs_pol_inv, vs_pol_inv; | ||
1184 | int use_hsvs, use_ndp; | ||
1185 | u8 b; | ||
1186 | |||
1187 | hsw = blizzard_read_reg(BLIZZARD_HSW); | ||
1188 | vsw = blizzard_read_reg(BLIZZARD_VSW); | ||
1189 | hs_pol_inv = !(hsw & 0x80); | ||
1190 | vs_pol_inv = !(vsw & 0x80); | ||
1191 | hsw = hsw & 0x7f; | ||
1192 | vsw = vsw & 0x3f; | ||
1193 | |||
1194 | hdisp = blizzard_read_reg(BLIZZARD_HDISP) * 8; | ||
1195 | vdisp = blizzard_read_reg(BLIZZARD_VDISP0) + | ||
1196 | ((blizzard_read_reg(BLIZZARD_VDISP1) & 0x3) << 8); | ||
1197 | |||
1198 | hndp = blizzard_read_reg(BLIZZARD_HNDP) & 0x3f; | ||
1199 | vndp = blizzard_read_reg(BLIZZARD_VNDP); | ||
1200 | |||
1201 | /* time to transfer one pixel (16bpp) in ps */ | ||
1202 | blizzard.pix_tx_time = blizzard.reg_timings.we_cycle_time; | ||
1203 | if (blizzard.extif->get_max_tx_rate != NULL) { | ||
1204 | /* The external interface might have a rate limitation, | ||
1205 | * if so, we have to maximize our transfer rate. | ||
1206 | */ | ||
1207 | unsigned long min_tx_time; | ||
1208 | unsigned long max_tx_rate = blizzard.extif->get_max_tx_rate(); | ||
1209 | |||
1210 | dev_dbg(blizzard.fbdev->dev, "max_tx_rate %ld HZ\n", | ||
1211 | max_tx_rate); | ||
1212 | min_tx_time = 1000000000 / (max_tx_rate / 1000); /* ps */ | ||
1213 | if (blizzard.pix_tx_time < min_tx_time) | ||
1214 | blizzard.pix_tx_time = min_tx_time; | ||
1215 | } | ||
1216 | |||
1217 | /* time to update one line in ps */ | ||
1218 | blizzard.line_upd_time = (hdisp + hndp) * 1000000 / (pix_clk / 1000); | ||
1219 | blizzard.line_upd_time *= 1000; | ||
1220 | if (hdisp * blizzard.pix_tx_time > blizzard.line_upd_time) | ||
1221 | /* transfer speed too low, we might have to use both | ||
1222 | * HS and VS */ | ||
1223 | use_hsvs = 1; | ||
1224 | else | ||
1225 | /* decent transfer speed, we'll always use only VS */ | ||
1226 | use_hsvs = 0; | ||
1227 | |||
1228 | if (use_hsvs && (hs_pol_inv || vs_pol_inv)) { | ||
1229 | /* HS or'ed with VS doesn't work, use the active high | ||
1230 | * TE signal based on HNDP / VNDP */ | ||
1231 | use_ndp = 1; | ||
1232 | hs_pol_inv = 0; | ||
1233 | vs_pol_inv = 0; | ||
1234 | hs = hndp; | ||
1235 | vs = vndp; | ||
1236 | } else { | ||
1237 | /* Use HS or'ed with VS as a TE signal if both are needed | ||
1238 | * or VNDP if only vsync is needed. */ | ||
1239 | use_ndp = 0; | ||
1240 | hs = hsw; | ||
1241 | vs = vsw; | ||
1242 | if (!use_hsvs) { | ||
1243 | hs_pol_inv = 0; | ||
1244 | vs_pol_inv = 0; | ||
1245 | } | ||
1246 | } | ||
1247 | |||
1248 | hs = hs * 1000000 / (pix_clk / 1000); /* ps */ | ||
1249 | hs *= 1000; | ||
1250 | |||
1251 | vs = vs * (hdisp + hndp) * 1000000 / (pix_clk / 1000); /* ps */ | ||
1252 | vs *= 1000; | ||
1253 | |||
1254 | if (vs <= hs) | ||
1255 | return -EDOM; | ||
1256 | /* set VS to 120% of HS to minimize VS detection time */ | ||
1257 | vs = hs * 12 / 10; | ||
1258 | /* minimize HS too */ | ||
1259 | if (hs > 10000) | ||
1260 | hs = 10000; | ||
1261 | |||
1262 | b = blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS); | ||
1263 | b &= ~0x3; | ||
1264 | b |= use_hsvs ? 1 : 0; | ||
1265 | b |= (use_ndp && use_hsvs) ? 0 : 2; | ||
1266 | blizzard_write_reg(BLIZZARD_NDISP_CTRL_STATUS, b); | ||
1267 | |||
1268 | blizzard.vsync_only = !use_hsvs; | ||
1269 | |||
1270 | dev_dbg(blizzard.fbdev->dev, | ||
1271 | "pix_clk %ld HZ pix_tx_time %ld ps line_upd_time %ld ps\n", | ||
1272 | pix_clk, blizzard.pix_tx_time, blizzard.line_upd_time); | ||
1273 | dev_dbg(blizzard.fbdev->dev, | ||
1274 | "hs %d ps vs %d ps mode %d vsync_only %d\n", | ||
1275 | hs, vs, b & 0x3, !use_hsvs); | ||
1276 | |||
1277 | return blizzard.extif->setup_tearsync(1, hs, vs, | ||
1278 | hs_pol_inv, vs_pol_inv, | ||
1279 | extif_div); | ||
1280 | } | ||
1281 | |||
1282 | static void blizzard_get_caps(int plane, struct omapfb_caps *caps) | ||
1283 | { | ||
1284 | blizzard.int_ctrl->get_caps(plane, caps); | ||
1285 | caps->ctrl |= OMAPFB_CAPS_MANUAL_UPDATE | | ||
1286 | OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE | | ||
1287 | OMAPFB_CAPS_WINDOW_SCALE | | ||
1288 | OMAPFB_CAPS_WINDOW_OVERLAY; | ||
1289 | if (blizzard.te_connected) | ||
1290 | caps->ctrl |= OMAPFB_CAPS_TEARSYNC; | ||
1291 | caps->wnd_color |= (1 << OMAPFB_COLOR_RGB565) | | ||
1292 | (1 << OMAPFB_COLOR_YUV420); | ||
1293 | } | ||
1294 | |||
1295 | static void _save_regs(struct blizzard_reg_list *list, int cnt) | ||
1296 | { | ||
1297 | int i; | ||
1298 | |||
1299 | for (i = 0; i < cnt; i++, list++) { | ||
1300 | int reg; | ||
1301 | for (reg = list->start; reg <= list->end; reg += 2) | ||
1302 | blizzard_reg_cache[reg / 2] = blizzard_read_reg(reg); | ||
1303 | } | ||
1304 | } | ||
1305 | |||
1306 | static void _restore_regs(struct blizzard_reg_list *list, int cnt) | ||
1307 | { | ||
1308 | int i; | ||
1309 | |||
1310 | for (i = 0; i < cnt; i++, list++) { | ||
1311 | int reg; | ||
1312 | for (reg = list->start; reg <= list->end; reg += 2) | ||
1313 | blizzard_write_reg(reg, blizzard_reg_cache[reg / 2]); | ||
1314 | } | ||
1315 | } | ||
1316 | |||
1317 | static void blizzard_save_all_regs(void) | ||
1318 | { | ||
1319 | _save_regs(blizzard_pll_regs, ARRAY_SIZE(blizzard_pll_regs)); | ||
1320 | _save_regs(blizzard_gen_regs, ARRAY_SIZE(blizzard_gen_regs)); | ||
1321 | } | ||
1322 | |||
1323 | static void blizzard_restore_pll_regs(void) | ||
1324 | { | ||
1325 | _restore_regs(blizzard_pll_regs, ARRAY_SIZE(blizzard_pll_regs)); | ||
1326 | } | ||
1327 | |||
1328 | static void blizzard_restore_gen_regs(void) | ||
1329 | { | ||
1330 | _restore_regs(blizzard_gen_regs, ARRAY_SIZE(blizzard_gen_regs)); | ||
1331 | } | ||
1332 | |||
1333 | static void blizzard_suspend(void) | ||
1334 | { | ||
1335 | u32 l; | ||
1336 | unsigned long tmo; | ||
1337 | |||
1338 | if (blizzard.last_color_mode) { | ||
1339 | update_full_screen(); | ||
1340 | blizzard_sync(); | ||
1341 | } | ||
1342 | blizzard.update_mode_before_suspend = blizzard.update_mode; | ||
1343 | /* the following will disable clocks as well */ | ||
1344 | blizzard_set_update_mode(OMAPFB_UPDATE_DISABLED); | ||
1345 | |||
1346 | blizzard_save_all_regs(); | ||
1347 | |||
1348 | blizzard_stop_sdram(); | ||
1349 | |||
1350 | l = blizzard_read_reg(BLIZZARD_POWER_SAVE); | ||
1351 | /* Standby, Sleep. We assume we use an external clock. */ | ||
1352 | l |= 0x03; | ||
1353 | blizzard_write_reg(BLIZZARD_POWER_SAVE, l); | ||
1354 | |||
1355 | tmo = jiffies + msecs_to_jiffies(100); | ||
1356 | while (!(blizzard_read_reg(BLIZZARD_PLL_MODE) & (1 << 1))) { | ||
1357 | if (time_after(jiffies, tmo)) { | ||
1358 | dev_err(blizzard.fbdev->dev, | ||
1359 | "s1d1374x: sleep timeout, stopping PLL manually\n"); | ||
1360 | l = blizzard_read_reg(BLIZZARD_PLL_MODE); | ||
1361 | l &= ~0x03; | ||
1362 | /* Disable PLL, counter function */ | ||
1363 | l |= 0x2; | ||
1364 | blizzard_write_reg(BLIZZARD_PLL_MODE, l); | ||
1365 | break; | ||
1366 | } | ||
1367 | msleep(1); | ||
1368 | } | ||
1369 | |||
1370 | if (blizzard.power_down != NULL) | ||
1371 | blizzard.power_down(blizzard.fbdev->dev); | ||
1372 | } | ||
1373 | |||
1374 | static void blizzard_resume(void) | ||
1375 | { | ||
1376 | u32 l; | ||
1377 | |||
1378 | if (blizzard.power_up != NULL) | ||
1379 | blizzard.power_up(blizzard.fbdev->dev); | ||
1380 | |||
1381 | l = blizzard_read_reg(BLIZZARD_POWER_SAVE); | ||
1382 | /* Standby, Sleep */ | ||
1383 | l &= ~0x03; | ||
1384 | blizzard_write_reg(BLIZZARD_POWER_SAVE, l); | ||
1385 | |||
1386 | blizzard_restore_pll_regs(); | ||
1387 | l = blizzard_read_reg(BLIZZARD_PLL_MODE); | ||
1388 | l &= ~0x03; | ||
1389 | /* Enable PLL, counter function */ | ||
1390 | l |= 0x1; | ||
1391 | blizzard_write_reg(BLIZZARD_PLL_MODE, l); | ||
1392 | |||
1393 | while (!(blizzard_read_reg(BLIZZARD_PLL_DIV) & (1 << 7))) | ||
1394 | msleep(1); | ||
1395 | |||
1396 | blizzard_restart_sdram(); | ||
1397 | |||
1398 | blizzard_restore_gen_regs(); | ||
1399 | |||
1400 | /* Enable display */ | ||
1401 | blizzard_write_reg(BLIZZARD_DISPLAY_MODE, 0x01); | ||
1402 | |||
1403 | /* the following will enable clocks as necessary */ | ||
1404 | blizzard_set_update_mode(blizzard.update_mode_before_suspend); | ||
1405 | |||
1406 | /* Force a background update */ | ||
1407 | blizzard.zoom_on = 1; | ||
1408 | update_full_screen(); | ||
1409 | blizzard_sync(); | ||
1410 | } | ||
1411 | |||
1412 | static int blizzard_init(struct omapfb_device *fbdev, int ext_mode, | ||
1413 | struct omapfb_mem_desc *req_vram) | ||
1414 | { | ||
1415 | int r = 0, i; | ||
1416 | u8 rev, conf; | ||
1417 | unsigned long ext_clk; | ||
1418 | int extif_div; | ||
1419 | unsigned long sys_clk, pix_clk; | ||
1420 | struct omapfb_platform_data *omapfb_conf; | ||
1421 | struct blizzard_platform_data *ctrl_conf; | ||
1422 | |||
1423 | blizzard.fbdev = fbdev; | ||
1424 | |||
1425 | BUG_ON(!fbdev->ext_if || !fbdev->int_ctrl); | ||
1426 | |||
1427 | blizzard.fbdev = fbdev; | ||
1428 | blizzard.extif = fbdev->ext_if; | ||
1429 | blizzard.int_ctrl = fbdev->int_ctrl; | ||
1430 | |||
1431 | omapfb_conf = fbdev->dev->platform_data; | ||
1432 | ctrl_conf = omapfb_conf->ctrl_platform_data; | ||
1433 | if (ctrl_conf == NULL || ctrl_conf->get_clock_rate == NULL) { | ||
1434 | dev_err(fbdev->dev, "s1d1374x: missing platform data\n"); | ||
1435 | r = -ENOENT; | ||
1436 | goto err1; | ||
1437 | } | ||
1438 | |||
1439 | blizzard.power_down = ctrl_conf->power_down; | ||
1440 | blizzard.power_up = ctrl_conf->power_up; | ||
1441 | |||
1442 | spin_lock_init(&blizzard.req_lock); | ||
1443 | |||
1444 | if ((r = blizzard.int_ctrl->init(fbdev, 1, req_vram)) < 0) | ||
1445 | goto err1; | ||
1446 | |||
1447 | if ((r = blizzard.extif->init(fbdev)) < 0) | ||
1448 | goto err2; | ||
1449 | |||
1450 | blizzard_ctrl.set_color_key = blizzard.int_ctrl->set_color_key; | ||
1451 | blizzard_ctrl.get_color_key = blizzard.int_ctrl->get_color_key; | ||
1452 | blizzard_ctrl.setup_mem = blizzard.int_ctrl->setup_mem; | ||
1453 | blizzard_ctrl.mmap = blizzard.int_ctrl->mmap; | ||
1454 | |||
1455 | ext_clk = ctrl_conf->get_clock_rate(fbdev->dev); | ||
1456 | if ((r = calc_extif_timings(ext_clk, &extif_div)) < 0) | ||
1457 | goto err3; | ||
1458 | |||
1459 | set_extif_timings(&blizzard.reg_timings); | ||
1460 | |||
1461 | if (blizzard.power_up != NULL) | ||
1462 | blizzard.power_up(fbdev->dev); | ||
1463 | |||
1464 | calc_blizzard_clk_rates(ext_clk, &sys_clk, &pix_clk); | ||
1465 | |||
1466 | if ((r = calc_extif_timings(sys_clk, &extif_div)) < 0) | ||
1467 | goto err3; | ||
1468 | set_extif_timings(&blizzard.reg_timings); | ||
1469 | |||
1470 | if (!(blizzard_read_reg(BLIZZARD_PLL_DIV) & 0x80)) { | ||
1471 | dev_err(fbdev->dev, | ||
1472 | "controller not initialized by the bootloader\n"); | ||
1473 | r = -ENODEV; | ||
1474 | goto err3; | ||
1475 | } | ||
1476 | |||
1477 | if (ctrl_conf->te_connected) { | ||
1478 | if ((r = setup_tearsync(pix_clk, extif_div)) < 0) | ||
1479 | goto err3; | ||
1480 | blizzard.te_connected = 1; | ||
1481 | } | ||
1482 | |||
1483 | rev = blizzard_read_reg(BLIZZARD_REV_CODE); | ||
1484 | conf = blizzard_read_reg(BLIZZARD_CONFIG); | ||
1485 | |||
1486 | switch (rev & 0xfc) { | ||
1487 | case 0x9c: | ||
1488 | blizzard.version = BLIZZARD_VERSION_S1D13744; | ||
1489 | pr_info("omapfb: s1d13744 LCD controller rev %d " | ||
1490 | "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07); | ||
1491 | break; | ||
1492 | case 0xa4: | ||
1493 | blizzard.version = BLIZZARD_VERSION_S1D13745; | ||
1494 | pr_info("omapfb: s1d13745 LCD controller rev %d " | ||
1495 | "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07); | ||
1496 | break; | ||
1497 | default: | ||
1498 | dev_err(fbdev->dev, "invalid s1d1374x revision %02x\n", | ||
1499 | rev); | ||
1500 | r = -ENODEV; | ||
1501 | goto err3; | ||
1502 | } | ||
1503 | |||
1504 | blizzard.max_transmit_size = blizzard.extif->max_transmit_size; | ||
1505 | |||
1506 | blizzard.update_mode = OMAPFB_UPDATE_DISABLED; | ||
1507 | |||
1508 | blizzard.auto_update_window.x = 0; | ||
1509 | blizzard.auto_update_window.y = 0; | ||
1510 | blizzard.auto_update_window.width = fbdev->panel->x_res; | ||
1511 | blizzard.auto_update_window.height = fbdev->panel->y_res; | ||
1512 | blizzard.auto_update_window.out_x = 0; | ||
1513 | blizzard.auto_update_window.out_x = 0; | ||
1514 | blizzard.auto_update_window.out_width = fbdev->panel->x_res; | ||
1515 | blizzard.auto_update_window.out_height = fbdev->panel->y_res; | ||
1516 | blizzard.auto_update_window.format = 0; | ||
1517 | |||
1518 | blizzard.screen_width = fbdev->panel->x_res; | ||
1519 | blizzard.screen_height = fbdev->panel->y_res; | ||
1520 | |||
1521 | init_timer(&blizzard.auto_update_timer); | ||
1522 | blizzard.auto_update_timer.function = blizzard_update_window_auto; | ||
1523 | blizzard.auto_update_timer.data = 0; | ||
1524 | |||
1525 | INIT_LIST_HEAD(&blizzard.free_req_list); | ||
1526 | INIT_LIST_HEAD(&blizzard.pending_req_list); | ||
1527 | for (i = 0; i < ARRAY_SIZE(blizzard.req_pool); i++) | ||
1528 | list_add(&blizzard.req_pool[i].entry, &blizzard.free_req_list); | ||
1529 | BUG_ON(i <= IRQ_REQ_POOL_SIZE); | ||
1530 | sema_init(&blizzard.req_sema, i - IRQ_REQ_POOL_SIZE); | ||
1531 | |||
1532 | return 0; | ||
1533 | err3: | ||
1534 | if (blizzard.power_down != NULL) | ||
1535 | blizzard.power_down(fbdev->dev); | ||
1536 | blizzard.extif->cleanup(); | ||
1537 | err2: | ||
1538 | blizzard.int_ctrl->cleanup(); | ||
1539 | err1: | ||
1540 | return r; | ||
1541 | } | ||
1542 | |||
1543 | static void blizzard_cleanup(void) | ||
1544 | { | ||
1545 | blizzard_set_update_mode(OMAPFB_UPDATE_DISABLED); | ||
1546 | blizzard.extif->cleanup(); | ||
1547 | blizzard.int_ctrl->cleanup(); | ||
1548 | if (blizzard.power_down != NULL) | ||
1549 | blizzard.power_down(blizzard.fbdev->dev); | ||
1550 | } | ||
1551 | |||
1552 | struct lcd_ctrl blizzard_ctrl = { | ||
1553 | .name = "blizzard", | ||
1554 | .init = blizzard_init, | ||
1555 | .cleanup = blizzard_cleanup, | ||
1556 | .bind_client = blizzard_bind_client, | ||
1557 | .get_caps = blizzard_get_caps, | ||
1558 | .set_update_mode = blizzard_set_update_mode, | ||
1559 | .get_update_mode = blizzard_get_update_mode, | ||
1560 | .setup_plane = blizzard_setup_plane, | ||
1561 | .set_scale = blizzard_set_scale, | ||
1562 | .enable_plane = blizzard_enable_plane, | ||
1563 | .update_window = blizzard_update_window_async, | ||
1564 | .sync = blizzard_sync, | ||
1565 | .suspend = blizzard_suspend, | ||
1566 | .resume = blizzard_resume, | ||
1567 | }; | ||
1568 | |||