diff options
author | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2014-02-13 08:31:38 -0500 |
---|---|---|
committer | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2014-04-17 01:10:19 -0400 |
commit | f7018c21350204c4cf628462f229d44d03545254 (patch) | |
tree | 408787177164cf51cc06f7aabdb04fcff8d2b6aa /drivers/video/omap | |
parent | c26ef3eb3c11274bad1b64498d0a134f85755250 (diff) |
video: move fbdev to drivers/video/fbdev
The drivers/video directory is a mess. It contains generic video related
files, directories for backlight, console, linux logo, lots of fbdev
device drivers, fbdev framework files.
Make some order into the chaos by creating drivers/video/fbdev
directory, and move all fbdev related files there.
No functionality is changed, although I guess it is possible that some
subtle Makefile build order related issue could be created by this
patch.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>
Acked-by: Rob Clark <robdclark@gmail.com>
Acked-by: Jingoo Han <jg1.han@samsung.com>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/video/omap')
-rw-r--r-- | drivers/video/omap/Kconfig | 52 | ||||
-rw-r--r-- | drivers/video/omap/Makefile | 26 | ||||
-rw-r--r-- | drivers/video/omap/hwa742.c | 1059 | ||||
-rw-r--r-- | drivers/video/omap/lcd_ams_delta.c | 225 | ||||
-rw-r--r-- | drivers/video/omap/lcd_h3.c | 127 | ||||
-rw-r--r-- | drivers/video/omap/lcd_htcherald.c | 118 | ||||
-rw-r--r-- | drivers/video/omap/lcd_inn1510.c | 113 | ||||
-rw-r--r-- | drivers/video/omap/lcd_inn1610.c | 134 | ||||
-rw-r--r-- | drivers/video/omap/lcd_mipid.c | 615 | ||||
-rw-r--r-- | drivers/video/omap/lcd_osk.c | 133 | ||||
-rw-r--r-- | drivers/video/omap/lcd_palmte.c | 110 | ||||
-rw-r--r-- | drivers/video/omap/lcd_palmtt.c | 116 | ||||
-rw-r--r-- | drivers/video/omap/lcd_palmz71.c | 112 | ||||
-rw-r--r-- | drivers/video/omap/lcdc.c | 856 | ||||
-rw-r--r-- | drivers/video/omap/lcdc.h | 9 | ||||
-rw-r--r-- | drivers/video/omap/omapfb.h | 246 | ||||
-rw-r--r-- | drivers/video/omap/omapfb_main.c | 1971 | ||||
-rw-r--r-- | drivers/video/omap/sossi.c | 693 |
18 files changed, 0 insertions, 6715 deletions
diff --git a/drivers/video/omap/Kconfig b/drivers/video/omap/Kconfig deleted file mode 100644 index 0bc3a936ce2b..000000000000 --- a/drivers/video/omap/Kconfig +++ /dev/null | |||
@@ -1,52 +0,0 @@ | |||
1 | config FB_OMAP | ||
2 | tristate "OMAP frame buffer support" | ||
3 | depends on FB | ||
4 | depends on ARCH_OMAP1 | ||
5 | select FB_CFB_FILLRECT | ||
6 | select FB_CFB_COPYAREA | ||
7 | select FB_CFB_IMAGEBLIT | ||
8 | help | ||
9 | Frame buffer driver for OMAP based boards. | ||
10 | |||
11 | config FB_OMAP_LCDC_EXTERNAL | ||
12 | bool "External LCD controller support" | ||
13 | depends on FB_OMAP | ||
14 | help | ||
15 | Say Y here, if you want to have support for boards with an | ||
16 | external LCD controller connected to the SoSSI/RFBI interface. | ||
17 | |||
18 | config FB_OMAP_LCDC_HWA742 | ||
19 | bool "Epson HWA742 LCD controller support" | ||
20 | depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL | ||
21 | help | ||
22 | Say Y here if you want to have support for the external | ||
23 | Epson HWA742 LCD controller. | ||
24 | |||
25 | config FB_OMAP_MANUAL_UPDATE | ||
26 | bool "Default to manual update mode" | ||
27 | depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL | ||
28 | help | ||
29 | Say Y here, if your user-space applications are capable of | ||
30 | notifying the frame buffer driver when a change has occurred in | ||
31 | the frame buffer content and thus a reload of the image data to | ||
32 | the external frame buffer is required. If unsure, say N. | ||
33 | |||
34 | config FB_OMAP_LCD_MIPID | ||
35 | bool "MIPI DBI-C/DCS compatible LCD support" | ||
36 | depends on FB_OMAP && SPI_MASTER | ||
37 | help | ||
38 | Say Y here if you want to have support for LCDs compatible with | ||
39 | the Mobile Industry Processor Interface DBI-C/DCS | ||
40 | specification. (Supported LCDs: Philips LPH8923, Sharp LS041Y3) | ||
41 | |||
42 | config FB_OMAP_DMA_TUNE | ||
43 | bool "Set DMA SDRAM access priority high" | ||
44 | depends on FB_OMAP | ||
45 | help | ||
46 | On systems in which video memory is in system memory | ||
47 | (SDRAM) this will speed up graphics DMA operations. | ||
48 | If you have such a system and want to use rotation | ||
49 | answer yes. Answer no if you have a dedicated video | ||
50 | memory, or don't use any of the accelerated features. | ||
51 | |||
52 | |||
diff --git a/drivers/video/omap/Makefile b/drivers/video/omap/Makefile deleted file mode 100644 index 1927faffb5bc..000000000000 --- a/drivers/video/omap/Makefile +++ /dev/null | |||
@@ -1,26 +0,0 @@ | |||
1 | # | ||
2 | # Makefile for the OMAP1 framebuffer device driver | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_FB_OMAP) += omapfb.o | ||
6 | |||
7 | objs-yy := omapfb_main.o lcdc.o | ||
8 | |||
9 | objs-y$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += sossi.o | ||
10 | |||
11 | objs-y$(CONFIG_FB_OMAP_LCDC_HWA742) += hwa742.o | ||
12 | |||
13 | objs-y$(CONFIG_MACH_AMS_DELTA) += lcd_ams_delta.o | ||
14 | objs-y$(CONFIG_MACH_OMAP_H3) += lcd_h3.o | ||
15 | objs-y$(CONFIG_MACH_OMAP_PALMTE) += lcd_palmte.o | ||
16 | objs-y$(CONFIG_MACH_OMAP_PALMTT) += lcd_palmtt.o | ||
17 | objs-y$(CONFIG_MACH_OMAP_PALMZ71) += lcd_palmz71.o | ||
18 | objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1610.o | ||
19 | objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1510.o | ||
20 | objs-y$(CONFIG_MACH_OMAP_OSK) += lcd_osk.o | ||
21 | |||
22 | objs-y$(CONFIG_FB_OMAP_LCD_MIPID) += lcd_mipid.o | ||
23 | objs-y$(CONFIG_MACH_HERALD) += lcd_htcherald.o | ||
24 | |||
25 | omapfb-objs := $(objs-yy) | ||
26 | |||
diff --git a/drivers/video/omap/hwa742.c b/drivers/video/omap/hwa742.c deleted file mode 100644 index a4ee65b8f918..000000000000 --- a/drivers/video/omap/hwa742.c +++ /dev/null | |||
@@ -1,1059 +0,0 @@ | |||
1 | /* | ||
2 | * Epson HWA742 LCD controller driver | ||
3 | * | ||
4 | * Copyright (C) 2004-2005 Nokia Corporation | ||
5 | * Authors: Juha Yrjölä <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 | #include <linux/interrupt.h> | ||
29 | |||
30 | #include "omapfb.h" | ||
31 | |||
32 | #define HWA742_REV_CODE_REG 0x0 | ||
33 | #define HWA742_CONFIG_REG 0x2 | ||
34 | #define HWA742_PLL_DIV_REG 0x4 | ||
35 | #define HWA742_PLL_0_REG 0x6 | ||
36 | #define HWA742_PLL_1_REG 0x8 | ||
37 | #define HWA742_PLL_2_REG 0xa | ||
38 | #define HWA742_PLL_3_REG 0xc | ||
39 | #define HWA742_PLL_4_REG 0xe | ||
40 | #define HWA742_CLK_SRC_REG 0x12 | ||
41 | #define HWA742_PANEL_TYPE_REG 0x14 | ||
42 | #define HWA742_H_DISP_REG 0x16 | ||
43 | #define HWA742_H_NDP_REG 0x18 | ||
44 | #define HWA742_V_DISP_1_REG 0x1a | ||
45 | #define HWA742_V_DISP_2_REG 0x1c | ||
46 | #define HWA742_V_NDP_REG 0x1e | ||
47 | #define HWA742_HS_W_REG 0x20 | ||
48 | #define HWA742_HP_S_REG 0x22 | ||
49 | #define HWA742_VS_W_REG 0x24 | ||
50 | #define HWA742_VP_S_REG 0x26 | ||
51 | #define HWA742_PCLK_POL_REG 0x28 | ||
52 | #define HWA742_INPUT_MODE_REG 0x2a | ||
53 | #define HWA742_TRANSL_MODE_REG1 0x2e | ||
54 | #define HWA742_DISP_MODE_REG 0x34 | ||
55 | #define HWA742_WINDOW_TYPE 0x36 | ||
56 | #define HWA742_WINDOW_X_START_0 0x38 | ||
57 | #define HWA742_WINDOW_X_START_1 0x3a | ||
58 | #define HWA742_WINDOW_Y_START_0 0x3c | ||
59 | #define HWA742_WINDOW_Y_START_1 0x3e | ||
60 | #define HWA742_WINDOW_X_END_0 0x40 | ||
61 | #define HWA742_WINDOW_X_END_1 0x42 | ||
62 | #define HWA742_WINDOW_Y_END_0 0x44 | ||
63 | #define HWA742_WINDOW_Y_END_1 0x46 | ||
64 | #define HWA742_MEMORY_WRITE_LSB 0x48 | ||
65 | #define HWA742_MEMORY_WRITE_MSB 0x49 | ||
66 | #define HWA742_MEMORY_READ_0 0x4a | ||
67 | #define HWA742_MEMORY_READ_1 0x4c | ||
68 | #define HWA742_MEMORY_READ_2 0x4e | ||
69 | #define HWA742_POWER_SAVE 0x56 | ||
70 | #define HWA742_NDP_CTRL 0x58 | ||
71 | |||
72 | #define HWA742_AUTO_UPDATE_TIME (HZ / 20) | ||
73 | |||
74 | /* Reserve 4 request slots for requests in irq context */ | ||
75 | #define REQ_POOL_SIZE 24 | ||
76 | #define IRQ_REQ_POOL_SIZE 4 | ||
77 | |||
78 | #define REQ_FROM_IRQ_POOL 0x01 | ||
79 | |||
80 | #define REQ_COMPLETE 0 | ||
81 | #define REQ_PENDING 1 | ||
82 | |||
83 | struct update_param { | ||
84 | int x, y, width, height; | ||
85 | int color_mode; | ||
86 | int flags; | ||
87 | }; | ||
88 | |||
89 | struct hwa742_request { | ||
90 | struct list_head entry; | ||
91 | unsigned int flags; | ||
92 | |||
93 | int (*handler)(struct hwa742_request *req); | ||
94 | void (*complete)(void *data); | ||
95 | void *complete_data; | ||
96 | |||
97 | union { | ||
98 | struct update_param update; | ||
99 | struct completion *sync; | ||
100 | } par; | ||
101 | }; | ||
102 | |||
103 | struct { | ||
104 | enum omapfb_update_mode update_mode; | ||
105 | enum omapfb_update_mode update_mode_before_suspend; | ||
106 | |||
107 | struct timer_list auto_update_timer; | ||
108 | int stop_auto_update; | ||
109 | struct omapfb_update_window auto_update_window; | ||
110 | unsigned te_connected:1; | ||
111 | unsigned vsync_only:1; | ||
112 | |||
113 | struct hwa742_request req_pool[REQ_POOL_SIZE]; | ||
114 | struct list_head pending_req_list; | ||
115 | struct list_head free_req_list; | ||
116 | struct semaphore req_sema; | ||
117 | spinlock_t req_lock; | ||
118 | |||
119 | struct extif_timings reg_timings, lut_timings; | ||
120 | |||
121 | int prev_color_mode; | ||
122 | int prev_flags; | ||
123 | int window_type; | ||
124 | |||
125 | u32 max_transmit_size; | ||
126 | u32 extif_clk_period; | ||
127 | unsigned long pix_tx_time; | ||
128 | unsigned long line_upd_time; | ||
129 | |||
130 | |||
131 | struct omapfb_device *fbdev; | ||
132 | struct lcd_ctrl_extif *extif; | ||
133 | const struct lcd_ctrl *int_ctrl; | ||
134 | |||
135 | struct clk *sys_ck; | ||
136 | } hwa742; | ||
137 | |||
138 | struct lcd_ctrl hwa742_ctrl; | ||
139 | |||
140 | static u8 hwa742_read_reg(u8 reg) | ||
141 | { | ||
142 | u8 data; | ||
143 | |||
144 | hwa742.extif->set_bits_per_cycle(8); | ||
145 | hwa742.extif->write_command(®, 1); | ||
146 | hwa742.extif->read_data(&data, 1); | ||
147 | |||
148 | return data; | ||
149 | } | ||
150 | |||
151 | static void hwa742_write_reg(u8 reg, u8 data) | ||
152 | { | ||
153 | hwa742.extif->set_bits_per_cycle(8); | ||
154 | hwa742.extif->write_command(®, 1); | ||
155 | hwa742.extif->write_data(&data, 1); | ||
156 | } | ||
157 | |||
158 | static void set_window_regs(int x_start, int y_start, int x_end, int y_end) | ||
159 | { | ||
160 | u8 tmp[8]; | ||
161 | u8 cmd; | ||
162 | |||
163 | x_end--; | ||
164 | y_end--; | ||
165 | tmp[0] = x_start; | ||
166 | tmp[1] = x_start >> 8; | ||
167 | tmp[2] = y_start; | ||
168 | tmp[3] = y_start >> 8; | ||
169 | tmp[4] = x_end; | ||
170 | tmp[5] = x_end >> 8; | ||
171 | tmp[6] = y_end; | ||
172 | tmp[7] = y_end >> 8; | ||
173 | |||
174 | hwa742.extif->set_bits_per_cycle(8); | ||
175 | cmd = HWA742_WINDOW_X_START_0; | ||
176 | |||
177 | hwa742.extif->write_command(&cmd, 1); | ||
178 | |||
179 | hwa742.extif->write_data(tmp, 8); | ||
180 | } | ||
181 | |||
182 | static void set_format_regs(int conv, int transl, int flags) | ||
183 | { | ||
184 | if (flags & OMAPFB_FORMAT_FLAG_DOUBLE) { | ||
185 | hwa742.window_type = ((hwa742.window_type & 0xfc) | 0x01); | ||
186 | #ifdef VERBOSE | ||
187 | dev_dbg(hwa742.fbdev->dev, "hwa742: enabled pixel doubling\n"); | ||
188 | #endif | ||
189 | } else { | ||
190 | hwa742.window_type = (hwa742.window_type & 0xfc); | ||
191 | #ifdef VERBOSE | ||
192 | dev_dbg(hwa742.fbdev->dev, "hwa742: disabled pixel doubling\n"); | ||
193 | #endif | ||
194 | } | ||
195 | |||
196 | hwa742_write_reg(HWA742_INPUT_MODE_REG, conv); | ||
197 | hwa742_write_reg(HWA742_TRANSL_MODE_REG1, transl); | ||
198 | hwa742_write_reg(HWA742_WINDOW_TYPE, hwa742.window_type); | ||
199 | } | ||
200 | |||
201 | static void enable_tearsync(int y, int width, int height, int screen_height, | ||
202 | int force_vsync) | ||
203 | { | ||
204 | u8 b; | ||
205 | |||
206 | b = hwa742_read_reg(HWA742_NDP_CTRL); | ||
207 | b |= 1 << 2; | ||
208 | hwa742_write_reg(HWA742_NDP_CTRL, b); | ||
209 | |||
210 | if (likely(hwa742.vsync_only || force_vsync)) { | ||
211 | hwa742.extif->enable_tearsync(1, 0); | ||
212 | return; | ||
213 | } | ||
214 | |||
215 | if (width * hwa742.pix_tx_time < hwa742.line_upd_time) { | ||
216 | hwa742.extif->enable_tearsync(1, 0); | ||
217 | return; | ||
218 | } | ||
219 | |||
220 | if ((width * hwa742.pix_tx_time / 1000) * height < | ||
221 | (y + height) * (hwa742.line_upd_time / 1000)) { | ||
222 | hwa742.extif->enable_tearsync(1, 0); | ||
223 | return; | ||
224 | } | ||
225 | |||
226 | hwa742.extif->enable_tearsync(1, y + 1); | ||
227 | } | ||
228 | |||
229 | static void disable_tearsync(void) | ||
230 | { | ||
231 | u8 b; | ||
232 | |||
233 | hwa742.extif->enable_tearsync(0, 0); | ||
234 | |||
235 | b = hwa742_read_reg(HWA742_NDP_CTRL); | ||
236 | b &= ~(1 << 2); | ||
237 | hwa742_write_reg(HWA742_NDP_CTRL, b); | ||
238 | } | ||
239 | |||
240 | static inline struct hwa742_request *alloc_req(void) | ||
241 | { | ||
242 | unsigned long flags; | ||
243 | struct hwa742_request *req; | ||
244 | int req_flags = 0; | ||
245 | |||
246 | if (!in_interrupt()) | ||
247 | down(&hwa742.req_sema); | ||
248 | else | ||
249 | req_flags = REQ_FROM_IRQ_POOL; | ||
250 | |||
251 | spin_lock_irqsave(&hwa742.req_lock, flags); | ||
252 | BUG_ON(list_empty(&hwa742.free_req_list)); | ||
253 | req = list_entry(hwa742.free_req_list.next, | ||
254 | struct hwa742_request, entry); | ||
255 | list_del(&req->entry); | ||
256 | spin_unlock_irqrestore(&hwa742.req_lock, flags); | ||
257 | |||
258 | INIT_LIST_HEAD(&req->entry); | ||
259 | req->flags = req_flags; | ||
260 | |||
261 | return req; | ||
262 | } | ||
263 | |||
264 | static inline void free_req(struct hwa742_request *req) | ||
265 | { | ||
266 | unsigned long flags; | ||
267 | |||
268 | spin_lock_irqsave(&hwa742.req_lock, flags); | ||
269 | |||
270 | list_move(&req->entry, &hwa742.free_req_list); | ||
271 | if (!(req->flags & REQ_FROM_IRQ_POOL)) | ||
272 | up(&hwa742.req_sema); | ||
273 | |||
274 | spin_unlock_irqrestore(&hwa742.req_lock, flags); | ||
275 | } | ||
276 | |||
277 | static void process_pending_requests(void) | ||
278 | { | ||
279 | unsigned long flags; | ||
280 | |||
281 | spin_lock_irqsave(&hwa742.req_lock, flags); | ||
282 | |||
283 | while (!list_empty(&hwa742.pending_req_list)) { | ||
284 | struct hwa742_request *req; | ||
285 | void (*complete)(void *); | ||
286 | void *complete_data; | ||
287 | |||
288 | req = list_entry(hwa742.pending_req_list.next, | ||
289 | struct hwa742_request, entry); | ||
290 | spin_unlock_irqrestore(&hwa742.req_lock, flags); | ||
291 | |||
292 | if (req->handler(req) == REQ_PENDING) | ||
293 | return; | ||
294 | |||
295 | complete = req->complete; | ||
296 | complete_data = req->complete_data; | ||
297 | free_req(req); | ||
298 | |||
299 | if (complete) | ||
300 | complete(complete_data); | ||
301 | |||
302 | spin_lock_irqsave(&hwa742.req_lock, flags); | ||
303 | } | ||
304 | |||
305 | spin_unlock_irqrestore(&hwa742.req_lock, flags); | ||
306 | } | ||
307 | |||
308 | static void submit_req_list(struct list_head *head) | ||
309 | { | ||
310 | unsigned long flags; | ||
311 | int process = 1; | ||
312 | |||
313 | spin_lock_irqsave(&hwa742.req_lock, flags); | ||
314 | if (likely(!list_empty(&hwa742.pending_req_list))) | ||
315 | process = 0; | ||
316 | list_splice_init(head, hwa742.pending_req_list.prev); | ||
317 | spin_unlock_irqrestore(&hwa742.req_lock, flags); | ||
318 | |||
319 | if (process) | ||
320 | process_pending_requests(); | ||
321 | } | ||
322 | |||
323 | static void request_complete(void *data) | ||
324 | { | ||
325 | struct hwa742_request *req = (struct hwa742_request *)data; | ||
326 | void (*complete)(void *); | ||
327 | void *complete_data; | ||
328 | |||
329 | complete = req->complete; | ||
330 | complete_data = req->complete_data; | ||
331 | |||
332 | free_req(req); | ||
333 | |||
334 | if (complete) | ||
335 | complete(complete_data); | ||
336 | |||
337 | process_pending_requests(); | ||
338 | } | ||
339 | |||
340 | static int send_frame_handler(struct hwa742_request *req) | ||
341 | { | ||
342 | struct update_param *par = &req->par.update; | ||
343 | int x = par->x; | ||
344 | int y = par->y; | ||
345 | int w = par->width; | ||
346 | int h = par->height; | ||
347 | int bpp; | ||
348 | int conv, transl; | ||
349 | unsigned long offset; | ||
350 | int color_mode = par->color_mode; | ||
351 | int flags = par->flags; | ||
352 | int scr_width = hwa742.fbdev->panel->x_res; | ||
353 | int scr_height = hwa742.fbdev->panel->y_res; | ||
354 | |||
355 | #ifdef VERBOSE | ||
356 | dev_dbg(hwa742.fbdev->dev, "x %d y %d w %d h %d scr_width %d " | ||
357 | "color_mode %d flags %d\n", | ||
358 | x, y, w, h, scr_width, color_mode, flags); | ||
359 | #endif | ||
360 | |||
361 | switch (color_mode) { | ||
362 | case OMAPFB_COLOR_YUV422: | ||
363 | bpp = 16; | ||
364 | conv = 0x08; | ||
365 | transl = 0x25; | ||
366 | break; | ||
367 | case OMAPFB_COLOR_YUV420: | ||
368 | bpp = 12; | ||
369 | conv = 0x09; | ||
370 | transl = 0x25; | ||
371 | break; | ||
372 | case OMAPFB_COLOR_RGB565: | ||
373 | bpp = 16; | ||
374 | conv = 0x01; | ||
375 | transl = 0x05; | ||
376 | break; | ||
377 | default: | ||
378 | return -EINVAL; | ||
379 | } | ||
380 | |||
381 | if (hwa742.prev_flags != flags || | ||
382 | hwa742.prev_color_mode != color_mode) { | ||
383 | set_format_regs(conv, transl, flags); | ||
384 | hwa742.prev_color_mode = color_mode; | ||
385 | hwa742.prev_flags = flags; | ||
386 | } | ||
387 | flags = req->par.update.flags; | ||
388 | if (flags & OMAPFB_FORMAT_FLAG_TEARSYNC) | ||
389 | enable_tearsync(y, scr_width, h, scr_height, | ||
390 | flags & OMAPFB_FORMAT_FLAG_FORCE_VSYNC); | ||
391 | else | ||
392 | disable_tearsync(); | ||
393 | |||
394 | set_window_regs(x, y, x + w, y + h); | ||
395 | |||
396 | offset = (scr_width * y + x) * bpp / 8; | ||
397 | |||
398 | hwa742.int_ctrl->setup_plane(OMAPFB_PLANE_GFX, | ||
399 | OMAPFB_CHANNEL_OUT_LCD, offset, scr_width, 0, 0, w, h, | ||
400 | color_mode); | ||
401 | |||
402 | hwa742.extif->set_bits_per_cycle(16); | ||
403 | |||
404 | hwa742.int_ctrl->enable_plane(OMAPFB_PLANE_GFX, 1); | ||
405 | hwa742.extif->transfer_area(w, h, request_complete, req); | ||
406 | |||
407 | return REQ_PENDING; | ||
408 | } | ||
409 | |||
410 | static void send_frame_complete(void *data) | ||
411 | { | ||
412 | hwa742.int_ctrl->enable_plane(OMAPFB_PLANE_GFX, 0); | ||
413 | } | ||
414 | |||
415 | #define ADD_PREQ(_x, _y, _w, _h) do { \ | ||
416 | req = alloc_req(); \ | ||
417 | req->handler = send_frame_handler; \ | ||
418 | req->complete = send_frame_complete; \ | ||
419 | req->par.update.x = _x; \ | ||
420 | req->par.update.y = _y; \ | ||
421 | req->par.update.width = _w; \ | ||
422 | req->par.update.height = _h; \ | ||
423 | req->par.update.color_mode = color_mode;\ | ||
424 | req->par.update.flags = flags; \ | ||
425 | list_add_tail(&req->entry, req_head); \ | ||
426 | } while(0) | ||
427 | |||
428 | static void create_req_list(struct omapfb_update_window *win, | ||
429 | struct list_head *req_head) | ||
430 | { | ||
431 | struct hwa742_request *req; | ||
432 | int x = win->x; | ||
433 | int y = win->y; | ||
434 | int width = win->width; | ||
435 | int height = win->height; | ||
436 | int color_mode; | ||
437 | int flags; | ||
438 | |||
439 | flags = win->format & ~OMAPFB_FORMAT_MASK; | ||
440 | color_mode = win->format & OMAPFB_FORMAT_MASK; | ||
441 | |||
442 | if (x & 1) { | ||
443 | ADD_PREQ(x, y, 1, height); | ||
444 | width--; | ||
445 | x++; | ||
446 | flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC; | ||
447 | } | ||
448 | if (width & ~1) { | ||
449 | unsigned int xspan = width & ~1; | ||
450 | unsigned int ystart = y; | ||
451 | unsigned int yspan = height; | ||
452 | |||
453 | if (xspan * height * 2 > hwa742.max_transmit_size) { | ||
454 | yspan = hwa742.max_transmit_size / (xspan * 2); | ||
455 | ADD_PREQ(x, ystart, xspan, yspan); | ||
456 | ystart += yspan; | ||
457 | yspan = height - yspan; | ||
458 | flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC; | ||
459 | } | ||
460 | |||
461 | ADD_PREQ(x, ystart, xspan, yspan); | ||
462 | x += xspan; | ||
463 | width -= xspan; | ||
464 | flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC; | ||
465 | } | ||
466 | if (width) | ||
467 | ADD_PREQ(x, y, 1, height); | ||
468 | } | ||
469 | |||
470 | static void auto_update_complete(void *data) | ||
471 | { | ||
472 | if (!hwa742.stop_auto_update) | ||
473 | mod_timer(&hwa742.auto_update_timer, | ||
474 | jiffies + HWA742_AUTO_UPDATE_TIME); | ||
475 | } | ||
476 | |||
477 | static void hwa742_update_window_auto(unsigned long arg) | ||
478 | { | ||
479 | LIST_HEAD(req_list); | ||
480 | struct hwa742_request *last; | ||
481 | |||
482 | create_req_list(&hwa742.auto_update_window, &req_list); | ||
483 | last = list_entry(req_list.prev, struct hwa742_request, entry); | ||
484 | |||
485 | last->complete = auto_update_complete; | ||
486 | last->complete_data = NULL; | ||
487 | |||
488 | submit_req_list(&req_list); | ||
489 | } | ||
490 | |||
491 | int hwa742_update_window_async(struct fb_info *fbi, | ||
492 | struct omapfb_update_window *win, | ||
493 | void (*complete_callback)(void *arg), | ||
494 | void *complete_callback_data) | ||
495 | { | ||
496 | LIST_HEAD(req_list); | ||
497 | struct hwa742_request *last; | ||
498 | int r = 0; | ||
499 | |||
500 | if (hwa742.update_mode != OMAPFB_MANUAL_UPDATE) { | ||
501 | dev_dbg(hwa742.fbdev->dev, "invalid update mode\n"); | ||
502 | r = -EINVAL; | ||
503 | goto out; | ||
504 | } | ||
505 | if (unlikely(win->format & | ||
506 | ~(0x03 | OMAPFB_FORMAT_FLAG_DOUBLE | | ||
507 | OMAPFB_FORMAT_FLAG_TEARSYNC | OMAPFB_FORMAT_FLAG_FORCE_VSYNC))) { | ||
508 | dev_dbg(hwa742.fbdev->dev, "invalid window flag\n"); | ||
509 | r = -EINVAL; | ||
510 | goto out; | ||
511 | } | ||
512 | |||
513 | create_req_list(win, &req_list); | ||
514 | last = list_entry(req_list.prev, struct hwa742_request, entry); | ||
515 | |||
516 | last->complete = complete_callback; | ||
517 | last->complete_data = (void *)complete_callback_data; | ||
518 | |||
519 | submit_req_list(&req_list); | ||
520 | |||
521 | out: | ||
522 | return r; | ||
523 | } | ||
524 | EXPORT_SYMBOL(hwa742_update_window_async); | ||
525 | |||
526 | static int hwa742_setup_plane(int plane, int channel_out, | ||
527 | unsigned long offset, int screen_width, | ||
528 | int pos_x, int pos_y, int width, int height, | ||
529 | int color_mode) | ||
530 | { | ||
531 | if (plane != OMAPFB_PLANE_GFX || | ||
532 | channel_out != OMAPFB_CHANNEL_OUT_LCD) | ||
533 | return -EINVAL; | ||
534 | |||
535 | return 0; | ||
536 | } | ||
537 | |||
538 | static int hwa742_enable_plane(int plane, int enable) | ||
539 | { | ||
540 | if (plane != 0) | ||
541 | return -EINVAL; | ||
542 | |||
543 | hwa742.int_ctrl->enable_plane(plane, enable); | ||
544 | |||
545 | return 0; | ||
546 | } | ||
547 | |||
548 | static int sync_handler(struct hwa742_request *req) | ||
549 | { | ||
550 | complete(req->par.sync); | ||
551 | return REQ_COMPLETE; | ||
552 | } | ||
553 | |||
554 | static void hwa742_sync(void) | ||
555 | { | ||
556 | LIST_HEAD(req_list); | ||
557 | struct hwa742_request *req; | ||
558 | struct completion comp; | ||
559 | |||
560 | req = alloc_req(); | ||
561 | |||
562 | req->handler = sync_handler; | ||
563 | req->complete = NULL; | ||
564 | init_completion(&comp); | ||
565 | req->par.sync = ∁ | ||
566 | |||
567 | list_add(&req->entry, &req_list); | ||
568 | submit_req_list(&req_list); | ||
569 | |||
570 | wait_for_completion(&comp); | ||
571 | } | ||
572 | |||
573 | static void hwa742_bind_client(struct omapfb_notifier_block *nb) | ||
574 | { | ||
575 | dev_dbg(hwa742.fbdev->dev, "update_mode %d\n", hwa742.update_mode); | ||
576 | if (hwa742.update_mode == OMAPFB_MANUAL_UPDATE) { | ||
577 | omapfb_notify_clients(hwa742.fbdev, OMAPFB_EVENT_READY); | ||
578 | } | ||
579 | } | ||
580 | |||
581 | static int hwa742_set_update_mode(enum omapfb_update_mode mode) | ||
582 | { | ||
583 | if (mode != OMAPFB_MANUAL_UPDATE && mode != OMAPFB_AUTO_UPDATE && | ||
584 | mode != OMAPFB_UPDATE_DISABLED) | ||
585 | return -EINVAL; | ||
586 | |||
587 | if (mode == hwa742.update_mode) | ||
588 | return 0; | ||
589 | |||
590 | dev_info(hwa742.fbdev->dev, "HWA742: setting update mode to %s\n", | ||
591 | mode == OMAPFB_UPDATE_DISABLED ? "disabled" : | ||
592 | (mode == OMAPFB_AUTO_UPDATE ? "auto" : "manual")); | ||
593 | |||
594 | switch (hwa742.update_mode) { | ||
595 | case OMAPFB_MANUAL_UPDATE: | ||
596 | omapfb_notify_clients(hwa742.fbdev, OMAPFB_EVENT_DISABLED); | ||
597 | break; | ||
598 | case OMAPFB_AUTO_UPDATE: | ||
599 | hwa742.stop_auto_update = 1; | ||
600 | del_timer_sync(&hwa742.auto_update_timer); | ||
601 | break; | ||
602 | case OMAPFB_UPDATE_DISABLED: | ||
603 | break; | ||
604 | } | ||
605 | |||
606 | hwa742.update_mode = mode; | ||
607 | hwa742_sync(); | ||
608 | hwa742.stop_auto_update = 0; | ||
609 | |||
610 | switch (mode) { | ||
611 | case OMAPFB_MANUAL_UPDATE: | ||
612 | omapfb_notify_clients(hwa742.fbdev, OMAPFB_EVENT_READY); | ||
613 | break; | ||
614 | case OMAPFB_AUTO_UPDATE: | ||
615 | hwa742_update_window_auto(0); | ||
616 | break; | ||
617 | case OMAPFB_UPDATE_DISABLED: | ||
618 | break; | ||
619 | } | ||
620 | |||
621 | return 0; | ||
622 | } | ||
623 | |||
624 | static enum omapfb_update_mode hwa742_get_update_mode(void) | ||
625 | { | ||
626 | return hwa742.update_mode; | ||
627 | } | ||
628 | |||
629 | static unsigned long round_to_extif_ticks(unsigned long ps, int div) | ||
630 | { | ||
631 | int bus_tick = hwa742.extif_clk_period * div; | ||
632 | return (ps + bus_tick - 1) / bus_tick * bus_tick; | ||
633 | } | ||
634 | |||
635 | static int calc_reg_timing(unsigned long sysclk, int div) | ||
636 | { | ||
637 | struct extif_timings *t; | ||
638 | unsigned long systim; | ||
639 | |||
640 | /* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns, | ||
641 | * AccessTime 2 ns + 12.2 ns (regs), | ||
642 | * WEOffTime = WEOnTime + 1 ns, | ||
643 | * REOffTime = REOnTime + 16 ns (regs), | ||
644 | * CSOffTime = REOffTime + 1 ns | ||
645 | * ReadCycle = 2ns + 2*SYSCLK (regs), | ||
646 | * WriteCycle = 2*SYSCLK + 2 ns, | ||
647 | * CSPulseWidth = 10 ns */ | ||
648 | systim = 1000000000 / (sysclk / 1000); | ||
649 | dev_dbg(hwa742.fbdev->dev, "HWA742 systim %lu ps extif_clk_period %u ps" | ||
650 | "extif_clk_div %d\n", systim, hwa742.extif_clk_period, div); | ||
651 | |||
652 | t = &hwa742.reg_timings; | ||
653 | memset(t, 0, sizeof(*t)); | ||
654 | t->clk_div = div; | ||
655 | t->cs_on_time = 0; | ||
656 | t->we_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
657 | t->re_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
658 | t->access_time = round_to_extif_ticks(t->re_on_time + 12200, div); | ||
659 | t->we_off_time = round_to_extif_ticks(t->we_on_time + 1000, div); | ||
660 | t->re_off_time = round_to_extif_ticks(t->re_on_time + 16000, div); | ||
661 | t->cs_off_time = round_to_extif_ticks(t->re_off_time + 1000, div); | ||
662 | t->we_cycle_time = round_to_extif_ticks(2 * systim + 2000, div); | ||
663 | if (t->we_cycle_time < t->we_off_time) | ||
664 | t->we_cycle_time = t->we_off_time; | ||
665 | t->re_cycle_time = round_to_extif_ticks(2 * systim + 2000, div); | ||
666 | if (t->re_cycle_time < t->re_off_time) | ||
667 | t->re_cycle_time = t->re_off_time; | ||
668 | t->cs_pulse_width = 0; | ||
669 | |||
670 | dev_dbg(hwa742.fbdev->dev, "[reg]cson %d csoff %d reon %d reoff %d\n", | ||
671 | t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time); | ||
672 | dev_dbg(hwa742.fbdev->dev, "[reg]weon %d weoff %d recyc %d wecyc %d\n", | ||
673 | t->we_on_time, t->we_off_time, t->re_cycle_time, | ||
674 | t->we_cycle_time); | ||
675 | dev_dbg(hwa742.fbdev->dev, "[reg]rdaccess %d cspulse %d\n", | ||
676 | t->access_time, t->cs_pulse_width); | ||
677 | |||
678 | return hwa742.extif->convert_timings(t); | ||
679 | } | ||
680 | |||
681 | static int calc_lut_timing(unsigned long sysclk, int div) | ||
682 | { | ||
683 | struct extif_timings *t; | ||
684 | unsigned long systim; | ||
685 | |||
686 | /* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns, | ||
687 | * AccessTime 2 ns + 4 * SYSCLK + 26 (lut), | ||
688 | * WEOffTime = WEOnTime + 1 ns, | ||
689 | * REOffTime = REOnTime + 4*SYSCLK + 26 ns (lut), | ||
690 | * CSOffTime = REOffTime + 1 ns | ||
691 | * ReadCycle = 2ns + 4*SYSCLK + 26 ns (lut), | ||
692 | * WriteCycle = 2*SYSCLK + 2 ns, | ||
693 | * CSPulseWidth = 10 ns | ||
694 | */ | ||
695 | systim = 1000000000 / (sysclk / 1000); | ||
696 | dev_dbg(hwa742.fbdev->dev, "HWA742 systim %lu ps extif_clk_period %u ps" | ||
697 | "extif_clk_div %d\n", systim, hwa742.extif_clk_period, div); | ||
698 | |||
699 | t = &hwa742.lut_timings; | ||
700 | memset(t, 0, sizeof(*t)); | ||
701 | |||
702 | t->clk_div = div; | ||
703 | |||
704 | t->cs_on_time = 0; | ||
705 | t->we_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
706 | t->re_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
707 | t->access_time = round_to_extif_ticks(t->re_on_time + 4 * systim + | ||
708 | 26000, div); | ||
709 | t->we_off_time = round_to_extif_ticks(t->we_on_time + 1000, div); | ||
710 | t->re_off_time = round_to_extif_ticks(t->re_on_time + 4 * systim + | ||
711 | 26000, div); | ||
712 | t->cs_off_time = round_to_extif_ticks(t->re_off_time + 1000, div); | ||
713 | t->we_cycle_time = round_to_extif_ticks(2 * systim + 2000, div); | ||
714 | if (t->we_cycle_time < t->we_off_time) | ||
715 | t->we_cycle_time = t->we_off_time; | ||
716 | t->re_cycle_time = round_to_extif_ticks(2000 + 4 * systim + 26000, div); | ||
717 | if (t->re_cycle_time < t->re_off_time) | ||
718 | t->re_cycle_time = t->re_off_time; | ||
719 | t->cs_pulse_width = 0; | ||
720 | |||
721 | dev_dbg(hwa742.fbdev->dev, "[lut]cson %d csoff %d reon %d reoff %d\n", | ||
722 | t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time); | ||
723 | dev_dbg(hwa742.fbdev->dev, "[lut]weon %d weoff %d recyc %d wecyc %d\n", | ||
724 | t->we_on_time, t->we_off_time, t->re_cycle_time, | ||
725 | t->we_cycle_time); | ||
726 | dev_dbg(hwa742.fbdev->dev, "[lut]rdaccess %d cspulse %d\n", | ||
727 | t->access_time, t->cs_pulse_width); | ||
728 | |||
729 | return hwa742.extif->convert_timings(t); | ||
730 | } | ||
731 | |||
732 | static int calc_extif_timings(unsigned long sysclk, int *extif_mem_div) | ||
733 | { | ||
734 | int max_clk_div; | ||
735 | int div; | ||
736 | |||
737 | hwa742.extif->get_clk_info(&hwa742.extif_clk_period, &max_clk_div); | ||
738 | for (div = 1; div < max_clk_div; div++) { | ||
739 | if (calc_reg_timing(sysclk, div) == 0) | ||
740 | break; | ||
741 | } | ||
742 | if (div >= max_clk_div) | ||
743 | goto err; | ||
744 | |||
745 | *extif_mem_div = div; | ||
746 | |||
747 | for (div = 1; div < max_clk_div; div++) { | ||
748 | if (calc_lut_timing(sysclk, div) == 0) | ||
749 | break; | ||
750 | } | ||
751 | |||
752 | if (div >= max_clk_div) | ||
753 | goto err; | ||
754 | |||
755 | return 0; | ||
756 | |||
757 | err: | ||
758 | dev_err(hwa742.fbdev->dev, "can't setup timings\n"); | ||
759 | return -1; | ||
760 | } | ||
761 | |||
762 | static void calc_hwa742_clk_rates(unsigned long ext_clk, | ||
763 | unsigned long *sys_clk, unsigned long *pix_clk) | ||
764 | { | ||
765 | int pix_clk_src; | ||
766 | int sys_div = 0, sys_mul = 0; | ||
767 | int pix_div; | ||
768 | |||
769 | pix_clk_src = hwa742_read_reg(HWA742_CLK_SRC_REG); | ||
770 | pix_div = ((pix_clk_src >> 3) & 0x1f) + 1; | ||
771 | if ((pix_clk_src & (0x3 << 1)) == 0) { | ||
772 | /* Source is the PLL */ | ||
773 | sys_div = (hwa742_read_reg(HWA742_PLL_DIV_REG) & 0x3f) + 1; | ||
774 | sys_mul = (hwa742_read_reg(HWA742_PLL_4_REG) & 0x7f) + 1; | ||
775 | *sys_clk = ext_clk * sys_mul / sys_div; | ||
776 | } else /* else source is ext clk, or oscillator */ | ||
777 | *sys_clk = ext_clk; | ||
778 | |||
779 | *pix_clk = *sys_clk / pix_div; /* HZ */ | ||
780 | dev_dbg(hwa742.fbdev->dev, | ||
781 | "ext_clk %ld pix_src %d pix_div %d sys_div %d sys_mul %d\n", | ||
782 | ext_clk, pix_clk_src & (0x3 << 1), pix_div, sys_div, sys_mul); | ||
783 | dev_dbg(hwa742.fbdev->dev, "sys_clk %ld pix_clk %ld\n", | ||
784 | *sys_clk, *pix_clk); | ||
785 | } | ||
786 | |||
787 | |||
788 | static int setup_tearsync(unsigned long pix_clk, int extif_div) | ||
789 | { | ||
790 | int hdisp, vdisp; | ||
791 | int hndp, vndp; | ||
792 | int hsw, vsw; | ||
793 | int hs, vs; | ||
794 | int hs_pol_inv, vs_pol_inv; | ||
795 | int use_hsvs, use_ndp; | ||
796 | u8 b; | ||
797 | |||
798 | hsw = hwa742_read_reg(HWA742_HS_W_REG); | ||
799 | vsw = hwa742_read_reg(HWA742_VS_W_REG); | ||
800 | hs_pol_inv = !(hsw & 0x80); | ||
801 | vs_pol_inv = !(vsw & 0x80); | ||
802 | hsw = hsw & 0x7f; | ||
803 | vsw = vsw & 0x3f; | ||
804 | |||
805 | hdisp = (hwa742_read_reg(HWA742_H_DISP_REG) & 0x7f) * 8; | ||
806 | vdisp = hwa742_read_reg(HWA742_V_DISP_1_REG) + | ||
807 | ((hwa742_read_reg(HWA742_V_DISP_2_REG) & 0x3) << 8); | ||
808 | |||
809 | hndp = hwa742_read_reg(HWA742_H_NDP_REG) & 0x7f; | ||
810 | vndp = hwa742_read_reg(HWA742_V_NDP_REG); | ||
811 | |||
812 | /* time to transfer one pixel (16bpp) in ps */ | ||
813 | hwa742.pix_tx_time = hwa742.reg_timings.we_cycle_time; | ||
814 | if (hwa742.extif->get_max_tx_rate != NULL) { | ||
815 | /* | ||
816 | * The external interface might have a rate limitation, | ||
817 | * if so, we have to maximize our transfer rate. | ||
818 | */ | ||
819 | unsigned long min_tx_time; | ||
820 | unsigned long max_tx_rate = hwa742.extif->get_max_tx_rate(); | ||
821 | |||
822 | dev_dbg(hwa742.fbdev->dev, "max_tx_rate %ld HZ\n", | ||
823 | max_tx_rate); | ||
824 | min_tx_time = 1000000000 / (max_tx_rate / 1000); /* ps */ | ||
825 | if (hwa742.pix_tx_time < min_tx_time) | ||
826 | hwa742.pix_tx_time = min_tx_time; | ||
827 | } | ||
828 | |||
829 | /* time to update one line in ps */ | ||
830 | hwa742.line_upd_time = (hdisp + hndp) * 1000000 / (pix_clk / 1000); | ||
831 | hwa742.line_upd_time *= 1000; | ||
832 | if (hdisp * hwa742.pix_tx_time > hwa742.line_upd_time) | ||
833 | /* | ||
834 | * transfer speed too low, we might have to use both | ||
835 | * HS and VS | ||
836 | */ | ||
837 | use_hsvs = 1; | ||
838 | else | ||
839 | /* decent transfer speed, we'll always use only VS */ | ||
840 | use_hsvs = 0; | ||
841 | |||
842 | if (use_hsvs && (hs_pol_inv || vs_pol_inv)) { | ||
843 | /* | ||
844 | * HS or'ed with VS doesn't work, use the active high | ||
845 | * TE signal based on HNDP / VNDP | ||
846 | */ | ||
847 | use_ndp = 1; | ||
848 | hs_pol_inv = 0; | ||
849 | vs_pol_inv = 0; | ||
850 | hs = hndp; | ||
851 | vs = vndp; | ||
852 | } else { | ||
853 | /* | ||
854 | * Use HS or'ed with VS as a TE signal if both are needed | ||
855 | * or VNDP if only vsync is needed. | ||
856 | */ | ||
857 | use_ndp = 0; | ||
858 | hs = hsw; | ||
859 | vs = vsw; | ||
860 | if (!use_hsvs) { | ||
861 | hs_pol_inv = 0; | ||
862 | vs_pol_inv = 0; | ||
863 | } | ||
864 | } | ||
865 | |||
866 | hs = hs * 1000000 / (pix_clk / 1000); /* ps */ | ||
867 | hs *= 1000; | ||
868 | |||
869 | vs = vs * (hdisp + hndp) * 1000000 / (pix_clk / 1000); /* ps */ | ||
870 | vs *= 1000; | ||
871 | |||
872 | if (vs <= hs) | ||
873 | return -EDOM; | ||
874 | /* set VS to 120% of HS to minimize VS detection time */ | ||
875 | vs = hs * 12 / 10; | ||
876 | /* minimize HS too */ | ||
877 | hs = 10000; | ||
878 | |||
879 | b = hwa742_read_reg(HWA742_NDP_CTRL); | ||
880 | b &= ~0x3; | ||
881 | b |= use_hsvs ? 1 : 0; | ||
882 | b |= (use_ndp && use_hsvs) ? 0 : 2; | ||
883 | hwa742_write_reg(HWA742_NDP_CTRL, b); | ||
884 | |||
885 | hwa742.vsync_only = !use_hsvs; | ||
886 | |||
887 | dev_dbg(hwa742.fbdev->dev, | ||
888 | "pix_clk %ld HZ pix_tx_time %ld ps line_upd_time %ld ps\n", | ||
889 | pix_clk, hwa742.pix_tx_time, hwa742.line_upd_time); | ||
890 | dev_dbg(hwa742.fbdev->dev, | ||
891 | "hs %d ps vs %d ps mode %d vsync_only %d\n", | ||
892 | hs, vs, (b & 0x3), !use_hsvs); | ||
893 | |||
894 | return hwa742.extif->setup_tearsync(1, hs, vs, | ||
895 | hs_pol_inv, vs_pol_inv, extif_div); | ||
896 | } | ||
897 | |||
898 | static void hwa742_get_caps(int plane, struct omapfb_caps *caps) | ||
899 | { | ||
900 | hwa742.int_ctrl->get_caps(plane, caps); | ||
901 | caps->ctrl |= OMAPFB_CAPS_MANUAL_UPDATE | | ||
902 | OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE; | ||
903 | if (hwa742.te_connected) | ||
904 | caps->ctrl |= OMAPFB_CAPS_TEARSYNC; | ||
905 | caps->wnd_color |= (1 << OMAPFB_COLOR_RGB565) | | ||
906 | (1 << OMAPFB_COLOR_YUV420); | ||
907 | } | ||
908 | |||
909 | static void hwa742_suspend(void) | ||
910 | { | ||
911 | hwa742.update_mode_before_suspend = hwa742.update_mode; | ||
912 | hwa742_set_update_mode(OMAPFB_UPDATE_DISABLED); | ||
913 | /* Enable sleep mode */ | ||
914 | hwa742_write_reg(HWA742_POWER_SAVE, 1 << 1); | ||
915 | clk_disable(hwa742.sys_ck); | ||
916 | } | ||
917 | |||
918 | static void hwa742_resume(void) | ||
919 | { | ||
920 | clk_enable(hwa742.sys_ck); | ||
921 | |||
922 | /* Disable sleep mode */ | ||
923 | hwa742_write_reg(HWA742_POWER_SAVE, 0); | ||
924 | while (1) { | ||
925 | /* Loop until PLL output is stabilized */ | ||
926 | if (hwa742_read_reg(HWA742_PLL_DIV_REG) & (1 << 7)) | ||
927 | break; | ||
928 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
929 | schedule_timeout(msecs_to_jiffies(5)); | ||
930 | } | ||
931 | hwa742_set_update_mode(hwa742.update_mode_before_suspend); | ||
932 | } | ||
933 | |||
934 | static int hwa742_init(struct omapfb_device *fbdev, int ext_mode, | ||
935 | struct omapfb_mem_desc *req_vram) | ||
936 | { | ||
937 | int r = 0, i; | ||
938 | u8 rev, conf; | ||
939 | unsigned long ext_clk; | ||
940 | unsigned long sys_clk, pix_clk; | ||
941 | int extif_mem_div; | ||
942 | struct omapfb_platform_data *omapfb_conf; | ||
943 | |||
944 | BUG_ON(!fbdev->ext_if || !fbdev->int_ctrl); | ||
945 | |||
946 | hwa742.fbdev = fbdev; | ||
947 | hwa742.extif = fbdev->ext_if; | ||
948 | hwa742.int_ctrl = fbdev->int_ctrl; | ||
949 | |||
950 | omapfb_conf = dev_get_platdata(fbdev->dev); | ||
951 | |||
952 | hwa742.sys_ck = clk_get(NULL, "hwa_sys_ck"); | ||
953 | |||
954 | spin_lock_init(&hwa742.req_lock); | ||
955 | |||
956 | if ((r = hwa742.int_ctrl->init(fbdev, 1, req_vram)) < 0) | ||
957 | goto err1; | ||
958 | |||
959 | if ((r = hwa742.extif->init(fbdev)) < 0) | ||
960 | goto err2; | ||
961 | |||
962 | ext_clk = clk_get_rate(hwa742.sys_ck); | ||
963 | if ((r = calc_extif_timings(ext_clk, &extif_mem_div)) < 0) | ||
964 | goto err3; | ||
965 | hwa742.extif->set_timings(&hwa742.reg_timings); | ||
966 | clk_enable(hwa742.sys_ck); | ||
967 | |||
968 | calc_hwa742_clk_rates(ext_clk, &sys_clk, &pix_clk); | ||
969 | if ((r = calc_extif_timings(sys_clk, &extif_mem_div)) < 0) | ||
970 | goto err4; | ||
971 | hwa742.extif->set_timings(&hwa742.reg_timings); | ||
972 | |||
973 | rev = hwa742_read_reg(HWA742_REV_CODE_REG); | ||
974 | if ((rev & 0xfc) != 0x80) { | ||
975 | dev_err(fbdev->dev, "HWA742: invalid revision %02x\n", rev); | ||
976 | r = -ENODEV; | ||
977 | goto err4; | ||
978 | } | ||
979 | |||
980 | |||
981 | if (!(hwa742_read_reg(HWA742_PLL_DIV_REG) & 0x80)) { | ||
982 | dev_err(fbdev->dev, | ||
983 | "HWA742: controller not initialized by the bootloader\n"); | ||
984 | r = -ENODEV; | ||
985 | goto err4; | ||
986 | } | ||
987 | |||
988 | if ((r = setup_tearsync(pix_clk, extif_mem_div)) < 0) { | ||
989 | dev_err(hwa742.fbdev->dev, | ||
990 | "HWA742: can't setup tearing synchronization\n"); | ||
991 | goto err4; | ||
992 | } | ||
993 | hwa742.te_connected = 1; | ||
994 | |||
995 | hwa742.max_transmit_size = hwa742.extif->max_transmit_size; | ||
996 | |||
997 | hwa742.update_mode = OMAPFB_UPDATE_DISABLED; | ||
998 | |||
999 | hwa742.auto_update_window.x = 0; | ||
1000 | hwa742.auto_update_window.y = 0; | ||
1001 | hwa742.auto_update_window.width = fbdev->panel->x_res; | ||
1002 | hwa742.auto_update_window.height = fbdev->panel->y_res; | ||
1003 | hwa742.auto_update_window.format = 0; | ||
1004 | |||
1005 | init_timer(&hwa742.auto_update_timer); | ||
1006 | hwa742.auto_update_timer.function = hwa742_update_window_auto; | ||
1007 | hwa742.auto_update_timer.data = 0; | ||
1008 | |||
1009 | hwa742.prev_color_mode = -1; | ||
1010 | hwa742.prev_flags = 0; | ||
1011 | |||
1012 | hwa742.fbdev = fbdev; | ||
1013 | |||
1014 | INIT_LIST_HEAD(&hwa742.free_req_list); | ||
1015 | INIT_LIST_HEAD(&hwa742.pending_req_list); | ||
1016 | for (i = 0; i < ARRAY_SIZE(hwa742.req_pool); i++) | ||
1017 | list_add(&hwa742.req_pool[i].entry, &hwa742.free_req_list); | ||
1018 | BUG_ON(i <= IRQ_REQ_POOL_SIZE); | ||
1019 | sema_init(&hwa742.req_sema, i - IRQ_REQ_POOL_SIZE); | ||
1020 | |||
1021 | conf = hwa742_read_reg(HWA742_CONFIG_REG); | ||
1022 | dev_info(fbdev->dev, ": Epson HWA742 LCD controller rev %d " | ||
1023 | "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07); | ||
1024 | |||
1025 | return 0; | ||
1026 | err4: | ||
1027 | clk_disable(hwa742.sys_ck); | ||
1028 | err3: | ||
1029 | hwa742.extif->cleanup(); | ||
1030 | err2: | ||
1031 | hwa742.int_ctrl->cleanup(); | ||
1032 | err1: | ||
1033 | return r; | ||
1034 | } | ||
1035 | |||
1036 | static void hwa742_cleanup(void) | ||
1037 | { | ||
1038 | hwa742_set_update_mode(OMAPFB_UPDATE_DISABLED); | ||
1039 | hwa742.extif->cleanup(); | ||
1040 | hwa742.int_ctrl->cleanup(); | ||
1041 | clk_disable(hwa742.sys_ck); | ||
1042 | } | ||
1043 | |||
1044 | struct lcd_ctrl hwa742_ctrl = { | ||
1045 | .name = "hwa742", | ||
1046 | .init = hwa742_init, | ||
1047 | .cleanup = hwa742_cleanup, | ||
1048 | .bind_client = hwa742_bind_client, | ||
1049 | .get_caps = hwa742_get_caps, | ||
1050 | .set_update_mode = hwa742_set_update_mode, | ||
1051 | .get_update_mode = hwa742_get_update_mode, | ||
1052 | .setup_plane = hwa742_setup_plane, | ||
1053 | .enable_plane = hwa742_enable_plane, | ||
1054 | .update_window = hwa742_update_window_async, | ||
1055 | .sync = hwa742_sync, | ||
1056 | .suspend = hwa742_suspend, | ||
1057 | .resume = hwa742_resume, | ||
1058 | }; | ||
1059 | |||
diff --git a/drivers/video/omap/lcd_ams_delta.c b/drivers/video/omap/lcd_ams_delta.c deleted file mode 100644 index 4a5f2cd3d3bf..000000000000 --- a/drivers/video/omap/lcd_ams_delta.c +++ /dev/null | |||
@@ -1,225 +0,0 @@ | |||
1 | /* | ||
2 | * Based on drivers/video/omap/lcd_inn1510.c | ||
3 | * | ||
4 | * LCD panel support for the Amstrad E3 (Delta) videophone. | ||
5 | * | ||
6 | * Copyright (C) 2006 Jonathan McDowell <noodles@earth.li> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/io.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/lcd.h> | ||
28 | #include <linux/gpio.h> | ||
29 | |||
30 | #include <mach/hardware.h> | ||
31 | #include <mach/board-ams-delta.h> | ||
32 | |||
33 | #include "omapfb.h" | ||
34 | |||
35 | #define AMS_DELTA_DEFAULT_CONTRAST 112 | ||
36 | |||
37 | #define AMS_DELTA_MAX_CONTRAST 0x00FF | ||
38 | #define AMS_DELTA_LCD_POWER 0x0100 | ||
39 | |||
40 | |||
41 | /* LCD class device section */ | ||
42 | |||
43 | static int ams_delta_lcd; | ||
44 | |||
45 | static int ams_delta_lcd_set_power(struct lcd_device *dev, int power) | ||
46 | { | ||
47 | if (power == FB_BLANK_UNBLANK) { | ||
48 | if (!(ams_delta_lcd & AMS_DELTA_LCD_POWER)) { | ||
49 | omap_writeb(ams_delta_lcd & AMS_DELTA_MAX_CONTRAST, | ||
50 | OMAP_PWL_ENABLE); | ||
51 | omap_writeb(1, OMAP_PWL_CLK_ENABLE); | ||
52 | ams_delta_lcd |= AMS_DELTA_LCD_POWER; | ||
53 | } | ||
54 | } else { | ||
55 | if (ams_delta_lcd & AMS_DELTA_LCD_POWER) { | ||
56 | omap_writeb(0, OMAP_PWL_ENABLE); | ||
57 | omap_writeb(0, OMAP_PWL_CLK_ENABLE); | ||
58 | ams_delta_lcd &= ~AMS_DELTA_LCD_POWER; | ||
59 | } | ||
60 | } | ||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | static int ams_delta_lcd_set_contrast(struct lcd_device *dev, int value) | ||
65 | { | ||
66 | if ((value >= 0) && (value <= AMS_DELTA_MAX_CONTRAST)) { | ||
67 | omap_writeb(value, OMAP_PWL_ENABLE); | ||
68 | ams_delta_lcd &= ~AMS_DELTA_MAX_CONTRAST; | ||
69 | ams_delta_lcd |= value; | ||
70 | } | ||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | #ifdef CONFIG_LCD_CLASS_DEVICE | ||
75 | static int ams_delta_lcd_get_power(struct lcd_device *dev) | ||
76 | { | ||
77 | if (ams_delta_lcd & AMS_DELTA_LCD_POWER) | ||
78 | return FB_BLANK_UNBLANK; | ||
79 | else | ||
80 | return FB_BLANK_POWERDOWN; | ||
81 | } | ||
82 | |||
83 | static int ams_delta_lcd_get_contrast(struct lcd_device *dev) | ||
84 | { | ||
85 | if (!(ams_delta_lcd & AMS_DELTA_LCD_POWER)) | ||
86 | return 0; | ||
87 | |||
88 | return ams_delta_lcd & AMS_DELTA_MAX_CONTRAST; | ||
89 | } | ||
90 | |||
91 | static struct lcd_ops ams_delta_lcd_ops = { | ||
92 | .get_power = ams_delta_lcd_get_power, | ||
93 | .set_power = ams_delta_lcd_set_power, | ||
94 | .get_contrast = ams_delta_lcd_get_contrast, | ||
95 | .set_contrast = ams_delta_lcd_set_contrast, | ||
96 | }; | ||
97 | #endif | ||
98 | |||
99 | |||
100 | /* omapfb panel section */ | ||
101 | |||
102 | static const struct gpio _gpios[] = { | ||
103 | { | ||
104 | .gpio = AMS_DELTA_GPIO_PIN_LCD_VBLEN, | ||
105 | .flags = GPIOF_OUT_INIT_LOW, | ||
106 | .label = "lcd_vblen", | ||
107 | }, | ||
108 | { | ||
109 | .gpio = AMS_DELTA_GPIO_PIN_LCD_NDISP, | ||
110 | .flags = GPIOF_OUT_INIT_LOW, | ||
111 | .label = "lcd_ndisp", | ||
112 | }, | ||
113 | }; | ||
114 | |||
115 | static int ams_delta_panel_init(struct lcd_panel *panel, | ||
116 | struct omapfb_device *fbdev) | ||
117 | { | ||
118 | return gpio_request_array(_gpios, ARRAY_SIZE(_gpios)); | ||
119 | } | ||
120 | |||
121 | static void ams_delta_panel_cleanup(struct lcd_panel *panel) | ||
122 | { | ||
123 | gpio_free_array(_gpios, ARRAY_SIZE(_gpios)); | ||
124 | } | ||
125 | |||
126 | static int ams_delta_panel_enable(struct lcd_panel *panel) | ||
127 | { | ||
128 | gpio_set_value(AMS_DELTA_GPIO_PIN_LCD_NDISP, 1); | ||
129 | gpio_set_value(AMS_DELTA_GPIO_PIN_LCD_VBLEN, 1); | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static void ams_delta_panel_disable(struct lcd_panel *panel) | ||
134 | { | ||
135 | gpio_set_value(AMS_DELTA_GPIO_PIN_LCD_VBLEN, 0); | ||
136 | gpio_set_value(AMS_DELTA_GPIO_PIN_LCD_NDISP, 0); | ||
137 | } | ||
138 | |||
139 | static unsigned long ams_delta_panel_get_caps(struct lcd_panel *panel) | ||
140 | { | ||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static struct lcd_panel ams_delta_panel = { | ||
145 | .name = "ams-delta", | ||
146 | .config = 0, | ||
147 | |||
148 | .bpp = 12, | ||
149 | .data_lines = 16, | ||
150 | .x_res = 480, | ||
151 | .y_res = 320, | ||
152 | .pixel_clock = 4687, | ||
153 | .hsw = 3, | ||
154 | .hfp = 1, | ||
155 | .hbp = 1, | ||
156 | .vsw = 1, | ||
157 | .vfp = 0, | ||
158 | .vbp = 0, | ||
159 | .pcd = 0, | ||
160 | .acb = 37, | ||
161 | |||
162 | .init = ams_delta_panel_init, | ||
163 | .cleanup = ams_delta_panel_cleanup, | ||
164 | .enable = ams_delta_panel_enable, | ||
165 | .disable = ams_delta_panel_disable, | ||
166 | .get_caps = ams_delta_panel_get_caps, | ||
167 | }; | ||
168 | |||
169 | |||
170 | /* platform driver section */ | ||
171 | |||
172 | static int ams_delta_panel_probe(struct platform_device *pdev) | ||
173 | { | ||
174 | struct lcd_device *lcd_device = NULL; | ||
175 | #ifdef CONFIG_LCD_CLASS_DEVICE | ||
176 | int ret; | ||
177 | |||
178 | lcd_device = lcd_device_register("omapfb", &pdev->dev, NULL, | ||
179 | &ams_delta_lcd_ops); | ||
180 | |||
181 | if (IS_ERR(lcd_device)) { | ||
182 | ret = PTR_ERR(lcd_device); | ||
183 | dev_err(&pdev->dev, "failed to register device\n"); | ||
184 | return ret; | ||
185 | } | ||
186 | |||
187 | platform_set_drvdata(pdev, lcd_device); | ||
188 | lcd_device->props.max_contrast = AMS_DELTA_MAX_CONTRAST; | ||
189 | #endif | ||
190 | |||
191 | ams_delta_lcd_set_contrast(lcd_device, AMS_DELTA_DEFAULT_CONTRAST); | ||
192 | ams_delta_lcd_set_power(lcd_device, FB_BLANK_UNBLANK); | ||
193 | |||
194 | omapfb_register_panel(&ams_delta_panel); | ||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | static int ams_delta_panel_remove(struct platform_device *pdev) | ||
199 | { | ||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | static int ams_delta_panel_suspend(struct platform_device *pdev, | ||
204 | pm_message_t mesg) | ||
205 | { | ||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | static int ams_delta_panel_resume(struct platform_device *pdev) | ||
210 | { | ||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | static struct platform_driver ams_delta_panel_driver = { | ||
215 | .probe = ams_delta_panel_probe, | ||
216 | .remove = ams_delta_panel_remove, | ||
217 | .suspend = ams_delta_panel_suspend, | ||
218 | .resume = ams_delta_panel_resume, | ||
219 | .driver = { | ||
220 | .name = "lcd_ams_delta", | ||
221 | .owner = THIS_MODULE, | ||
222 | }, | ||
223 | }; | ||
224 | |||
225 | module_platform_driver(ams_delta_panel_driver); | ||
diff --git a/drivers/video/omap/lcd_h3.c b/drivers/video/omap/lcd_h3.c deleted file mode 100644 index 49bdeca81e50..000000000000 --- a/drivers/video/omap/lcd_h3.c +++ /dev/null | |||
@@ -1,127 +0,0 @@ | |||
1 | /* | ||
2 | * LCD panel support for the TI OMAP H3 board | ||
3 | * | ||
4 | * Copyright (C) 2004 Nokia Corporation | ||
5 | * Author: Imre Deak <imre.deak@nokia.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/i2c/tps65010.h> | ||
25 | |||
26 | #include <asm/gpio.h> | ||
27 | #include "omapfb.h" | ||
28 | |||
29 | #define MODULE_NAME "omapfb-lcd_h3" | ||
30 | |||
31 | static int h3_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev) | ||
32 | { | ||
33 | return 0; | ||
34 | } | ||
35 | |||
36 | static void h3_panel_cleanup(struct lcd_panel *panel) | ||
37 | { | ||
38 | } | ||
39 | |||
40 | static int h3_panel_enable(struct lcd_panel *panel) | ||
41 | { | ||
42 | int r = 0; | ||
43 | |||
44 | /* GPIO1 and GPIO2 of TPS65010 send LCD_ENBKL and LCD_ENVDD signals */ | ||
45 | r = tps65010_set_gpio_out_value(GPIO1, HIGH); | ||
46 | if (!r) | ||
47 | r = tps65010_set_gpio_out_value(GPIO2, HIGH); | ||
48 | if (r) | ||
49 | pr_err(MODULE_NAME ": Unable to turn on LCD panel\n"); | ||
50 | |||
51 | return r; | ||
52 | } | ||
53 | |||
54 | static void h3_panel_disable(struct lcd_panel *panel) | ||
55 | { | ||
56 | int r = 0; | ||
57 | |||
58 | /* GPIO1 and GPIO2 of TPS65010 send LCD_ENBKL and LCD_ENVDD signals */ | ||
59 | r = tps65010_set_gpio_out_value(GPIO1, LOW); | ||
60 | if (!r) | ||
61 | tps65010_set_gpio_out_value(GPIO2, LOW); | ||
62 | if (r) | ||
63 | pr_err(MODULE_NAME ": Unable to turn off LCD panel\n"); | ||
64 | } | ||
65 | |||
66 | static unsigned long h3_panel_get_caps(struct lcd_panel *panel) | ||
67 | { | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | struct lcd_panel h3_panel = { | ||
72 | .name = "h3", | ||
73 | .config = OMAP_LCDC_PANEL_TFT, | ||
74 | |||
75 | .data_lines = 16, | ||
76 | .bpp = 16, | ||
77 | .x_res = 240, | ||
78 | .y_res = 320, | ||
79 | .pixel_clock = 12000, | ||
80 | .hsw = 12, | ||
81 | .hfp = 14, | ||
82 | .hbp = 72 - 12, | ||
83 | .vsw = 1, | ||
84 | .vfp = 1, | ||
85 | .vbp = 0, | ||
86 | .pcd = 0, | ||
87 | |||
88 | .init = h3_panel_init, | ||
89 | .cleanup = h3_panel_cleanup, | ||
90 | .enable = h3_panel_enable, | ||
91 | .disable = h3_panel_disable, | ||
92 | .get_caps = h3_panel_get_caps, | ||
93 | }; | ||
94 | |||
95 | static int h3_panel_probe(struct platform_device *pdev) | ||
96 | { | ||
97 | omapfb_register_panel(&h3_panel); | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static int h3_panel_remove(struct platform_device *pdev) | ||
102 | { | ||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | static int h3_panel_suspend(struct platform_device *pdev, pm_message_t mesg) | ||
107 | { | ||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static int h3_panel_resume(struct platform_device *pdev) | ||
112 | { | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static struct platform_driver h3_panel_driver = { | ||
117 | .probe = h3_panel_probe, | ||
118 | .remove = h3_panel_remove, | ||
119 | .suspend = h3_panel_suspend, | ||
120 | .resume = h3_panel_resume, | ||
121 | .driver = { | ||
122 | .name = "lcd_h3", | ||
123 | .owner = THIS_MODULE, | ||
124 | }, | ||
125 | }; | ||
126 | |||
127 | module_platform_driver(h3_panel_driver); | ||
diff --git a/drivers/video/omap/lcd_htcherald.c b/drivers/video/omap/lcd_htcherald.c deleted file mode 100644 index 20f477851d54..000000000000 --- a/drivers/video/omap/lcd_htcherald.c +++ /dev/null | |||
@@ -1,118 +0,0 @@ | |||
1 | /* | ||
2 | * File: drivers/video/omap/lcd-htcherald.c | ||
3 | * | ||
4 | * LCD panel support for the HTC Herald | ||
5 | * | ||
6 | * Copyright (C) 2009 Cory Maccarrone <darkstar6262@gmail.com> | ||
7 | * Copyright (C) 2009 Wing Linux | ||
8 | * | ||
9 | * Based on the lcd_htcwizard.c file from the linwizard project: | ||
10 | * Copyright (C) linwizard.sourceforge.net | ||
11 | * Author: Angelo Arrifano <miknix@gmail.com> | ||
12 | * Based on lcd_h4 by Imre Deak <imre.deak@nokia.com> | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify it | ||
15 | * under the terms of the GNU General Public License as published by the | ||
16 | * Free Software Foundation; either version 2 of the License, or (at your | ||
17 | * option) any later version. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, but | ||
20 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
22 | * General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License along | ||
25 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
26 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
27 | */ | ||
28 | |||
29 | #include <linux/module.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | |||
32 | #include "omapfb.h" | ||
33 | |||
34 | static int htcherald_panel_init(struct lcd_panel *panel, | ||
35 | struct omapfb_device *fbdev) | ||
36 | { | ||
37 | return 0; | ||
38 | } | ||
39 | |||
40 | static void htcherald_panel_cleanup(struct lcd_panel *panel) | ||
41 | { | ||
42 | } | ||
43 | |||
44 | static int htcherald_panel_enable(struct lcd_panel *panel) | ||
45 | { | ||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | static void htcherald_panel_disable(struct lcd_panel *panel) | ||
50 | { | ||
51 | } | ||
52 | |||
53 | static unsigned long htcherald_panel_get_caps(struct lcd_panel *panel) | ||
54 | { | ||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | /* Found on WIZ200 (miknix) and some HERA110 models (darkstar62) */ | ||
59 | struct lcd_panel htcherald_panel_1 = { | ||
60 | .name = "lcd_herald", | ||
61 | .config = OMAP_LCDC_PANEL_TFT | | ||
62 | OMAP_LCDC_INV_HSYNC | | ||
63 | OMAP_LCDC_INV_VSYNC | | ||
64 | OMAP_LCDC_INV_PIX_CLOCK, | ||
65 | .bpp = 16, | ||
66 | .data_lines = 16, | ||
67 | .x_res = 240, | ||
68 | .y_res = 320, | ||
69 | .pixel_clock = 6093, | ||
70 | .pcd = 0, /* 15 */ | ||
71 | .hsw = 10, | ||
72 | .hfp = 10, | ||
73 | .hbp = 20, | ||
74 | .vsw = 3, | ||
75 | .vfp = 2, | ||
76 | .vbp = 2, | ||
77 | |||
78 | .init = htcherald_panel_init, | ||
79 | .cleanup = htcherald_panel_cleanup, | ||
80 | .enable = htcherald_panel_enable, | ||
81 | .disable = htcherald_panel_disable, | ||
82 | .get_caps = htcherald_panel_get_caps, | ||
83 | }; | ||
84 | |||
85 | static int htcherald_panel_probe(struct platform_device *pdev) | ||
86 | { | ||
87 | omapfb_register_panel(&htcherald_panel_1); | ||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static int htcherald_panel_remove(struct platform_device *pdev) | ||
92 | { | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static int htcherald_panel_suspend(struct platform_device *pdev, | ||
97 | pm_message_t mesg) | ||
98 | { | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static int htcherald_panel_resume(struct platform_device *pdev) | ||
103 | { | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static struct platform_driver htcherald_panel_driver = { | ||
108 | .probe = htcherald_panel_probe, | ||
109 | .remove = htcherald_panel_remove, | ||
110 | .suspend = htcherald_panel_suspend, | ||
111 | .resume = htcherald_panel_resume, | ||
112 | .driver = { | ||
113 | .name = "lcd_htcherald", | ||
114 | .owner = THIS_MODULE, | ||
115 | }, | ||
116 | }; | ||
117 | |||
118 | module_platform_driver(htcherald_panel_driver); | ||
diff --git a/drivers/video/omap/lcd_inn1510.c b/drivers/video/omap/lcd_inn1510.c deleted file mode 100644 index 2ee423279e35..000000000000 --- a/drivers/video/omap/lcd_inn1510.c +++ /dev/null | |||
@@ -1,113 +0,0 @@ | |||
1 | /* | ||
2 | * LCD panel support for the TI OMAP1510 Innovator board | ||
3 | * | ||
4 | * Copyright (C) 2004 Nokia Corporation | ||
5 | * Author: Imre Deak <imre.deak@nokia.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/io.h> | ||
25 | |||
26 | #include <mach/hardware.h> | ||
27 | |||
28 | #include "omapfb.h" | ||
29 | |||
30 | static int innovator1510_panel_init(struct lcd_panel *panel, | ||
31 | struct omapfb_device *fbdev) | ||
32 | { | ||
33 | return 0; | ||
34 | } | ||
35 | |||
36 | static void innovator1510_panel_cleanup(struct lcd_panel *panel) | ||
37 | { | ||
38 | } | ||
39 | |||
40 | static int innovator1510_panel_enable(struct lcd_panel *panel) | ||
41 | { | ||
42 | __raw_writeb(0x7, OMAP1510_FPGA_LCD_PANEL_CONTROL); | ||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | static void innovator1510_panel_disable(struct lcd_panel *panel) | ||
47 | { | ||
48 | __raw_writeb(0x0, OMAP1510_FPGA_LCD_PANEL_CONTROL); | ||
49 | } | ||
50 | |||
51 | static unsigned long innovator1510_panel_get_caps(struct lcd_panel *panel) | ||
52 | { | ||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | struct lcd_panel innovator1510_panel = { | ||
57 | .name = "inn1510", | ||
58 | .config = OMAP_LCDC_PANEL_TFT, | ||
59 | |||
60 | .bpp = 16, | ||
61 | .data_lines = 16, | ||
62 | .x_res = 240, | ||
63 | .y_res = 320, | ||
64 | .pixel_clock = 12500, | ||
65 | .hsw = 40, | ||
66 | .hfp = 40, | ||
67 | .hbp = 72, | ||
68 | .vsw = 1, | ||
69 | .vfp = 1, | ||
70 | .vbp = 0, | ||
71 | .pcd = 12, | ||
72 | |||
73 | .init = innovator1510_panel_init, | ||
74 | .cleanup = innovator1510_panel_cleanup, | ||
75 | .enable = innovator1510_panel_enable, | ||
76 | .disable = innovator1510_panel_disable, | ||
77 | .get_caps = innovator1510_panel_get_caps, | ||
78 | }; | ||
79 | |||
80 | static int innovator1510_panel_probe(struct platform_device *pdev) | ||
81 | { | ||
82 | omapfb_register_panel(&innovator1510_panel); | ||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static int innovator1510_panel_remove(struct platform_device *pdev) | ||
87 | { | ||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static int innovator1510_panel_suspend(struct platform_device *pdev, | ||
92 | pm_message_t mesg) | ||
93 | { | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static int innovator1510_panel_resume(struct platform_device *pdev) | ||
98 | { | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static struct platform_driver innovator1510_panel_driver = { | ||
103 | .probe = innovator1510_panel_probe, | ||
104 | .remove = innovator1510_panel_remove, | ||
105 | .suspend = innovator1510_panel_suspend, | ||
106 | .resume = innovator1510_panel_resume, | ||
107 | .driver = { | ||
108 | .name = "lcd_inn1510", | ||
109 | .owner = THIS_MODULE, | ||
110 | }, | ||
111 | }; | ||
112 | |||
113 | module_platform_driver(innovator1510_panel_driver); | ||
diff --git a/drivers/video/omap/lcd_inn1610.c b/drivers/video/omap/lcd_inn1610.c deleted file mode 100644 index e3d3d135aa48..000000000000 --- a/drivers/video/omap/lcd_inn1610.c +++ /dev/null | |||
@@ -1,134 +0,0 @@ | |||
1 | /* | ||
2 | * LCD panel support for the TI OMAP1610 Innovator board | ||
3 | * | ||
4 | * Copyright (C) 2004 Nokia Corporation | ||
5 | * Author: Imre Deak <imre.deak@nokia.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | |||
25 | #include <linux/gpio.h> | ||
26 | #include "omapfb.h" | ||
27 | |||
28 | #define MODULE_NAME "omapfb-lcd_h3" | ||
29 | |||
30 | static int innovator1610_panel_init(struct lcd_panel *panel, | ||
31 | struct omapfb_device *fbdev) | ||
32 | { | ||
33 | int r = 0; | ||
34 | |||
35 | /* configure GPIO(14, 15) as outputs */ | ||
36 | if (gpio_request_one(14, GPIOF_OUT_INIT_LOW, "lcd_en0")) { | ||
37 | pr_err(MODULE_NAME ": can't request GPIO 14\n"); | ||
38 | r = -1; | ||
39 | goto exit; | ||
40 | } | ||
41 | if (gpio_request_one(15, GPIOF_OUT_INIT_LOW, "lcd_en1")) { | ||
42 | pr_err(MODULE_NAME ": can't request GPIO 15\n"); | ||
43 | gpio_free(14); | ||
44 | r = -1; | ||
45 | goto exit; | ||
46 | } | ||
47 | exit: | ||
48 | return r; | ||
49 | } | ||
50 | |||
51 | static void innovator1610_panel_cleanup(struct lcd_panel *panel) | ||
52 | { | ||
53 | gpio_free(15); | ||
54 | gpio_free(14); | ||
55 | } | ||
56 | |||
57 | static int innovator1610_panel_enable(struct lcd_panel *panel) | ||
58 | { | ||
59 | /* set GPIO14 and GPIO15 high */ | ||
60 | gpio_set_value(14, 1); | ||
61 | gpio_set_value(15, 1); | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static void innovator1610_panel_disable(struct lcd_panel *panel) | ||
66 | { | ||
67 | /* set GPIO13, GPIO14 and GPIO15 low */ | ||
68 | gpio_set_value(14, 0); | ||
69 | gpio_set_value(15, 0); | ||
70 | } | ||
71 | |||
72 | static unsigned long innovator1610_panel_get_caps(struct lcd_panel *panel) | ||
73 | { | ||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | struct lcd_panel innovator1610_panel = { | ||
78 | .name = "inn1610", | ||
79 | .config = OMAP_LCDC_PANEL_TFT, | ||
80 | |||
81 | .bpp = 16, | ||
82 | .data_lines = 16, | ||
83 | .x_res = 320, | ||
84 | .y_res = 240, | ||
85 | .pixel_clock = 12500, | ||
86 | .hsw = 40, | ||
87 | .hfp = 40, | ||
88 | .hbp = 72, | ||
89 | .vsw = 1, | ||
90 | .vfp = 1, | ||
91 | .vbp = 0, | ||
92 | .pcd = 12, | ||
93 | |||
94 | .init = innovator1610_panel_init, | ||
95 | .cleanup = innovator1610_panel_cleanup, | ||
96 | .enable = innovator1610_panel_enable, | ||
97 | .disable = innovator1610_panel_disable, | ||
98 | .get_caps = innovator1610_panel_get_caps, | ||
99 | }; | ||
100 | |||
101 | static int innovator1610_panel_probe(struct platform_device *pdev) | ||
102 | { | ||
103 | omapfb_register_panel(&innovator1610_panel); | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static int innovator1610_panel_remove(struct platform_device *pdev) | ||
108 | { | ||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | static int innovator1610_panel_suspend(struct platform_device *pdev, | ||
113 | pm_message_t mesg) | ||
114 | { | ||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | static int innovator1610_panel_resume(struct platform_device *pdev) | ||
119 | { | ||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | static struct platform_driver innovator1610_panel_driver = { | ||
124 | .probe = innovator1610_panel_probe, | ||
125 | .remove = innovator1610_panel_remove, | ||
126 | .suspend = innovator1610_panel_suspend, | ||
127 | .resume = innovator1610_panel_resume, | ||
128 | .driver = { | ||
129 | .name = "lcd_inn1610", | ||
130 | .owner = THIS_MODULE, | ||
131 | }, | ||
132 | }; | ||
133 | |||
134 | module_platform_driver(innovator1610_panel_driver); | ||
diff --git a/drivers/video/omap/lcd_mipid.c b/drivers/video/omap/lcd_mipid.c deleted file mode 100644 index 803fee618d57..000000000000 --- a/drivers/video/omap/lcd_mipid.c +++ /dev/null | |||
@@ -1,615 +0,0 @@ | |||
1 | /* | ||
2 | * LCD driver for MIPI DBI-C / DCS compatible LCDs | ||
3 | * | ||
4 | * Copyright (C) 2006 Nokia Corporation | ||
5 | * Author: Imre Deak <imre.deak@nokia.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | #include <linux/device.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/workqueue.h> | ||
25 | #include <linux/spi/spi.h> | ||
26 | #include <linux/module.h> | ||
27 | |||
28 | #include <linux/platform_data/lcd-mipid.h> | ||
29 | |||
30 | #include "omapfb.h" | ||
31 | |||
32 | #define MIPID_MODULE_NAME "lcd_mipid" | ||
33 | |||
34 | #define MIPID_CMD_READ_DISP_ID 0x04 | ||
35 | #define MIPID_CMD_READ_RED 0x06 | ||
36 | #define MIPID_CMD_READ_GREEN 0x07 | ||
37 | #define MIPID_CMD_READ_BLUE 0x08 | ||
38 | #define MIPID_CMD_READ_DISP_STATUS 0x09 | ||
39 | #define MIPID_CMD_RDDSDR 0x0F | ||
40 | #define MIPID_CMD_SLEEP_IN 0x10 | ||
41 | #define MIPID_CMD_SLEEP_OUT 0x11 | ||
42 | #define MIPID_CMD_DISP_OFF 0x28 | ||
43 | #define MIPID_CMD_DISP_ON 0x29 | ||
44 | |||
45 | #define MIPID_ESD_CHECK_PERIOD msecs_to_jiffies(5000) | ||
46 | |||
47 | #define to_mipid_device(p) container_of(p, struct mipid_device, \ | ||
48 | panel) | ||
49 | struct mipid_device { | ||
50 | int enabled; | ||
51 | int revision; | ||
52 | unsigned int saved_bklight_level; | ||
53 | unsigned long hw_guard_end; /* next value of jiffies | ||
54 | when we can issue the | ||
55 | next sleep in/out command */ | ||
56 | unsigned long hw_guard_wait; /* max guard time in jiffies */ | ||
57 | |||
58 | struct omapfb_device *fbdev; | ||
59 | struct spi_device *spi; | ||
60 | struct mutex mutex; | ||
61 | struct lcd_panel panel; | ||
62 | |||
63 | struct workqueue_struct *esd_wq; | ||
64 | struct delayed_work esd_work; | ||
65 | void (*esd_check)(struct mipid_device *m); | ||
66 | }; | ||
67 | |||
68 | static void mipid_transfer(struct mipid_device *md, int cmd, const u8 *wbuf, | ||
69 | int wlen, u8 *rbuf, int rlen) | ||
70 | { | ||
71 | struct spi_message m; | ||
72 | struct spi_transfer *x, xfer[4]; | ||
73 | u16 w; | ||
74 | int r; | ||
75 | |||
76 | BUG_ON(md->spi == NULL); | ||
77 | |||
78 | spi_message_init(&m); | ||
79 | |||
80 | memset(xfer, 0, sizeof(xfer)); | ||
81 | x = &xfer[0]; | ||
82 | |||
83 | cmd &= 0xff; | ||
84 | x->tx_buf = &cmd; | ||
85 | x->bits_per_word = 9; | ||
86 | x->len = 2; | ||
87 | spi_message_add_tail(x, &m); | ||
88 | |||
89 | if (wlen) { | ||
90 | x++; | ||
91 | x->tx_buf = wbuf; | ||
92 | x->len = wlen; | ||
93 | x->bits_per_word = 9; | ||
94 | spi_message_add_tail(x, &m); | ||
95 | } | ||
96 | |||
97 | if (rlen) { | ||
98 | x++; | ||
99 | x->rx_buf = &w; | ||
100 | x->len = 1; | ||
101 | spi_message_add_tail(x, &m); | ||
102 | |||
103 | if (rlen > 1) { | ||
104 | /* Arrange for the extra clock before the first | ||
105 | * data bit. | ||
106 | */ | ||
107 | x->bits_per_word = 9; | ||
108 | x->len = 2; | ||
109 | |||
110 | x++; | ||
111 | x->rx_buf = &rbuf[1]; | ||
112 | x->len = rlen - 1; | ||
113 | spi_message_add_tail(x, &m); | ||
114 | } | ||
115 | } | ||
116 | |||
117 | r = spi_sync(md->spi, &m); | ||
118 | if (r < 0) | ||
119 | dev_dbg(&md->spi->dev, "spi_sync %d\n", r); | ||
120 | |||
121 | if (rlen) | ||
122 | rbuf[0] = w & 0xff; | ||
123 | } | ||
124 | |||
125 | static inline void mipid_cmd(struct mipid_device *md, int cmd) | ||
126 | { | ||
127 | mipid_transfer(md, cmd, NULL, 0, NULL, 0); | ||
128 | } | ||
129 | |||
130 | static inline void mipid_write(struct mipid_device *md, | ||
131 | int reg, const u8 *buf, int len) | ||
132 | { | ||
133 | mipid_transfer(md, reg, buf, len, NULL, 0); | ||
134 | } | ||
135 | |||
136 | static inline void mipid_read(struct mipid_device *md, | ||
137 | int reg, u8 *buf, int len) | ||
138 | { | ||
139 | mipid_transfer(md, reg, NULL, 0, buf, len); | ||
140 | } | ||
141 | |||
142 | static void set_data_lines(struct mipid_device *md, int data_lines) | ||
143 | { | ||
144 | u16 par; | ||
145 | |||
146 | switch (data_lines) { | ||
147 | case 16: | ||
148 | par = 0x150; | ||
149 | break; | ||
150 | case 18: | ||
151 | par = 0x160; | ||
152 | break; | ||
153 | case 24: | ||
154 | par = 0x170; | ||
155 | break; | ||
156 | } | ||
157 | mipid_write(md, 0x3a, (u8 *)&par, 2); | ||
158 | } | ||
159 | |||
160 | static void send_init_string(struct mipid_device *md) | ||
161 | { | ||
162 | u16 initpar[] = { 0x0102, 0x0100, 0x0100 }; | ||
163 | |||
164 | mipid_write(md, 0xc2, (u8 *)initpar, sizeof(initpar)); | ||
165 | set_data_lines(md, md->panel.data_lines); | ||
166 | } | ||
167 | |||
168 | static void hw_guard_start(struct mipid_device *md, int guard_msec) | ||
169 | { | ||
170 | md->hw_guard_wait = msecs_to_jiffies(guard_msec); | ||
171 | md->hw_guard_end = jiffies + md->hw_guard_wait; | ||
172 | } | ||
173 | |||
174 | static void hw_guard_wait(struct mipid_device *md) | ||
175 | { | ||
176 | unsigned long wait = md->hw_guard_end - jiffies; | ||
177 | |||
178 | if ((long)wait > 0 && wait <= md->hw_guard_wait) { | ||
179 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
180 | schedule_timeout(wait); | ||
181 | } | ||
182 | } | ||
183 | |||
184 | static void set_sleep_mode(struct mipid_device *md, int on) | ||
185 | { | ||
186 | int cmd, sleep_time = 50; | ||
187 | |||
188 | if (on) | ||
189 | cmd = MIPID_CMD_SLEEP_IN; | ||
190 | else | ||
191 | cmd = MIPID_CMD_SLEEP_OUT; | ||
192 | hw_guard_wait(md); | ||
193 | mipid_cmd(md, cmd); | ||
194 | hw_guard_start(md, 120); | ||
195 | /* | ||
196 | * When we enable the panel, it seems we _have_ to sleep | ||
197 | * 120 ms before sending the init string. When disabling the | ||
198 | * panel we'll sleep for the duration of 2 frames, so that the | ||
199 | * controller can still provide the PCLK,HS,VS signals. | ||
200 | */ | ||
201 | if (!on) | ||
202 | sleep_time = 120; | ||
203 | msleep(sleep_time); | ||
204 | } | ||
205 | |||
206 | static void set_display_state(struct mipid_device *md, int enabled) | ||
207 | { | ||
208 | int cmd = enabled ? MIPID_CMD_DISP_ON : MIPID_CMD_DISP_OFF; | ||
209 | |||
210 | mipid_cmd(md, cmd); | ||
211 | } | ||
212 | |||
213 | static int mipid_set_bklight_level(struct lcd_panel *panel, unsigned int level) | ||
214 | { | ||
215 | struct mipid_device *md = to_mipid_device(panel); | ||
216 | struct mipid_platform_data *pd = md->spi->dev.platform_data; | ||
217 | |||
218 | if (pd->get_bklight_max == NULL || pd->set_bklight_level == NULL) | ||
219 | return -ENODEV; | ||
220 | if (level > pd->get_bklight_max(pd)) | ||
221 | return -EINVAL; | ||
222 | if (!md->enabled) { | ||
223 | md->saved_bklight_level = level; | ||
224 | return 0; | ||
225 | } | ||
226 | pd->set_bklight_level(pd, level); | ||
227 | |||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static unsigned int mipid_get_bklight_level(struct lcd_panel *panel) | ||
232 | { | ||
233 | struct mipid_device *md = to_mipid_device(panel); | ||
234 | struct mipid_platform_data *pd = md->spi->dev.platform_data; | ||
235 | |||
236 | if (pd->get_bklight_level == NULL) | ||
237 | return -ENODEV; | ||
238 | return pd->get_bklight_level(pd); | ||
239 | } | ||
240 | |||
241 | static unsigned int mipid_get_bklight_max(struct lcd_panel *panel) | ||
242 | { | ||
243 | struct mipid_device *md = to_mipid_device(panel); | ||
244 | struct mipid_platform_data *pd = md->spi->dev.platform_data; | ||
245 | |||
246 | if (pd->get_bklight_max == NULL) | ||
247 | return -ENODEV; | ||
248 | |||
249 | return pd->get_bklight_max(pd); | ||
250 | } | ||
251 | |||
252 | static unsigned long mipid_get_caps(struct lcd_panel *panel) | ||
253 | { | ||
254 | return OMAPFB_CAPS_SET_BACKLIGHT; | ||
255 | } | ||
256 | |||
257 | static u16 read_first_pixel(struct mipid_device *md) | ||
258 | { | ||
259 | u16 pixel; | ||
260 | u8 red, green, blue; | ||
261 | |||
262 | mutex_lock(&md->mutex); | ||
263 | mipid_read(md, MIPID_CMD_READ_RED, &red, 1); | ||
264 | mipid_read(md, MIPID_CMD_READ_GREEN, &green, 1); | ||
265 | mipid_read(md, MIPID_CMD_READ_BLUE, &blue, 1); | ||
266 | mutex_unlock(&md->mutex); | ||
267 | |||
268 | switch (md->panel.data_lines) { | ||
269 | case 16: | ||
270 | pixel = ((red >> 1) << 11) | (green << 5) | (blue >> 1); | ||
271 | break; | ||
272 | case 24: | ||
273 | /* 24 bit -> 16 bit */ | ||
274 | pixel = ((red >> 3) << 11) | ((green >> 2) << 5) | | ||
275 | (blue >> 3); | ||
276 | break; | ||
277 | default: | ||
278 | pixel = 0; | ||
279 | BUG(); | ||
280 | } | ||
281 | |||
282 | return pixel; | ||
283 | } | ||
284 | |||
285 | static int mipid_run_test(struct lcd_panel *panel, int test_num) | ||
286 | { | ||
287 | struct mipid_device *md = to_mipid_device(panel); | ||
288 | static const u16 test_values[4] = { | ||
289 | 0x0000, 0xffff, 0xaaaa, 0x5555, | ||
290 | }; | ||
291 | int i; | ||
292 | |||
293 | if (test_num != MIPID_TEST_RGB_LINES) | ||
294 | return MIPID_TEST_INVALID; | ||
295 | |||
296 | for (i = 0; i < ARRAY_SIZE(test_values); i++) { | ||
297 | int delay; | ||
298 | unsigned long tmo; | ||
299 | |||
300 | omapfb_write_first_pixel(md->fbdev, test_values[i]); | ||
301 | tmo = jiffies + msecs_to_jiffies(100); | ||
302 | delay = 25; | ||
303 | while (1) { | ||
304 | u16 pixel; | ||
305 | |||
306 | msleep(delay); | ||
307 | pixel = read_first_pixel(md); | ||
308 | if (pixel == test_values[i]) | ||
309 | break; | ||
310 | if (time_after(jiffies, tmo)) { | ||
311 | dev_err(&md->spi->dev, | ||
312 | "MIPI LCD RGB I/F test failed: " | ||
313 | "expecting %04x, got %04x\n", | ||
314 | test_values[i], pixel); | ||
315 | return MIPID_TEST_FAILED; | ||
316 | } | ||
317 | delay = 10; | ||
318 | } | ||
319 | } | ||
320 | |||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | static void ls041y3_esd_recover(struct mipid_device *md) | ||
325 | { | ||
326 | dev_err(&md->spi->dev, "performing LCD ESD recovery\n"); | ||
327 | set_sleep_mode(md, 1); | ||
328 | set_sleep_mode(md, 0); | ||
329 | } | ||
330 | |||
331 | static void ls041y3_esd_check_mode1(struct mipid_device *md) | ||
332 | { | ||
333 | u8 state1, state2; | ||
334 | |||
335 | mipid_read(md, MIPID_CMD_RDDSDR, &state1, 1); | ||
336 | set_sleep_mode(md, 0); | ||
337 | mipid_read(md, MIPID_CMD_RDDSDR, &state2, 1); | ||
338 | dev_dbg(&md->spi->dev, "ESD mode 1 state1 %02x state2 %02x\n", | ||
339 | state1, state2); | ||
340 | /* Each sleep out command will trigger a self diagnostic and flip | ||
341 | * Bit6 if the test passes. | ||
342 | */ | ||
343 | if (!((state1 ^ state2) & (1 << 6))) | ||
344 | ls041y3_esd_recover(md); | ||
345 | } | ||
346 | |||
347 | static void ls041y3_esd_check_mode2(struct mipid_device *md) | ||
348 | { | ||
349 | int i; | ||
350 | u8 rbuf[2]; | ||
351 | static const struct { | ||
352 | int cmd; | ||
353 | int wlen; | ||
354 | u16 wbuf[3]; | ||
355 | } *rd, rd_ctrl[7] = { | ||
356 | { 0xb0, 4, { 0x0101, 0x01fe, } }, | ||
357 | { 0xb1, 4, { 0x01de, 0x0121, } }, | ||
358 | { 0xc2, 4, { 0x0100, 0x0100, } }, | ||
359 | { 0xbd, 2, { 0x0100, } }, | ||
360 | { 0xc2, 4, { 0x01fc, 0x0103, } }, | ||
361 | { 0xb4, 0, }, | ||
362 | { 0x00, 0, }, | ||
363 | }; | ||
364 | |||
365 | rd = rd_ctrl; | ||
366 | for (i = 0; i < 3; i++, rd++) | ||
367 | mipid_write(md, rd->cmd, (u8 *)rd->wbuf, rd->wlen); | ||
368 | |||
369 | udelay(10); | ||
370 | mipid_read(md, rd->cmd, rbuf, 2); | ||
371 | rd++; | ||
372 | |||
373 | for (i = 0; i < 3; i++, rd++) { | ||
374 | udelay(10); | ||
375 | mipid_write(md, rd->cmd, (u8 *)rd->wbuf, rd->wlen); | ||
376 | } | ||
377 | |||
378 | dev_dbg(&md->spi->dev, "ESD mode 2 state %02x\n", rbuf[1]); | ||
379 | if (rbuf[1] == 0x00) | ||
380 | ls041y3_esd_recover(md); | ||
381 | } | ||
382 | |||
383 | static void ls041y3_esd_check(struct mipid_device *md) | ||
384 | { | ||
385 | ls041y3_esd_check_mode1(md); | ||
386 | if (md->revision >= 0x88) | ||
387 | ls041y3_esd_check_mode2(md); | ||
388 | } | ||
389 | |||
390 | static void mipid_esd_start_check(struct mipid_device *md) | ||
391 | { | ||
392 | if (md->esd_check != NULL) | ||
393 | queue_delayed_work(md->esd_wq, &md->esd_work, | ||
394 | MIPID_ESD_CHECK_PERIOD); | ||
395 | } | ||
396 | |||
397 | static void mipid_esd_stop_check(struct mipid_device *md) | ||
398 | { | ||
399 | if (md->esd_check != NULL) | ||
400 | cancel_delayed_work_sync(&md->esd_work); | ||
401 | } | ||
402 | |||
403 | static void mipid_esd_work(struct work_struct *work) | ||
404 | { | ||
405 | struct mipid_device *md = container_of(work, struct mipid_device, | ||
406 | esd_work.work); | ||
407 | |||
408 | mutex_lock(&md->mutex); | ||
409 | md->esd_check(md); | ||
410 | mutex_unlock(&md->mutex); | ||
411 | mipid_esd_start_check(md); | ||
412 | } | ||
413 | |||
414 | static int mipid_enable(struct lcd_panel *panel) | ||
415 | { | ||
416 | struct mipid_device *md = to_mipid_device(panel); | ||
417 | |||
418 | mutex_lock(&md->mutex); | ||
419 | |||
420 | if (md->enabled) { | ||
421 | mutex_unlock(&md->mutex); | ||
422 | return 0; | ||
423 | } | ||
424 | set_sleep_mode(md, 0); | ||
425 | md->enabled = 1; | ||
426 | send_init_string(md); | ||
427 | set_display_state(md, 1); | ||
428 | mipid_set_bklight_level(panel, md->saved_bklight_level); | ||
429 | mipid_esd_start_check(md); | ||
430 | |||
431 | mutex_unlock(&md->mutex); | ||
432 | return 0; | ||
433 | } | ||
434 | |||
435 | static void mipid_disable(struct lcd_panel *panel) | ||
436 | { | ||
437 | struct mipid_device *md = to_mipid_device(panel); | ||
438 | |||
439 | /* | ||
440 | * A final ESD work might be called before returning, | ||
441 | * so do this without holding the lock. | ||
442 | */ | ||
443 | mipid_esd_stop_check(md); | ||
444 | mutex_lock(&md->mutex); | ||
445 | |||
446 | if (!md->enabled) { | ||
447 | mutex_unlock(&md->mutex); | ||
448 | return; | ||
449 | } | ||
450 | md->saved_bklight_level = mipid_get_bklight_level(panel); | ||
451 | mipid_set_bklight_level(panel, 0); | ||
452 | set_display_state(md, 0); | ||
453 | set_sleep_mode(md, 1); | ||
454 | md->enabled = 0; | ||
455 | |||
456 | mutex_unlock(&md->mutex); | ||
457 | } | ||
458 | |||
459 | static int panel_enabled(struct mipid_device *md) | ||
460 | { | ||
461 | u32 disp_status; | ||
462 | int enabled; | ||
463 | |||
464 | mipid_read(md, MIPID_CMD_READ_DISP_STATUS, (u8 *)&disp_status, 4); | ||
465 | disp_status = __be32_to_cpu(disp_status); | ||
466 | enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10)); | ||
467 | dev_dbg(&md->spi->dev, | ||
468 | "LCD panel %senabled by bootloader (status 0x%04x)\n", | ||
469 | enabled ? "" : "not ", disp_status); | ||
470 | return enabled; | ||
471 | } | ||
472 | |||
473 | static int mipid_init(struct lcd_panel *panel, | ||
474 | struct omapfb_device *fbdev) | ||
475 | { | ||
476 | struct mipid_device *md = to_mipid_device(panel); | ||
477 | |||
478 | md->fbdev = fbdev; | ||
479 | md->esd_wq = create_singlethread_workqueue("mipid_esd"); | ||
480 | if (md->esd_wq == NULL) { | ||
481 | dev_err(&md->spi->dev, "can't create ESD workqueue\n"); | ||
482 | return -ENOMEM; | ||
483 | } | ||
484 | INIT_DELAYED_WORK(&md->esd_work, mipid_esd_work); | ||
485 | mutex_init(&md->mutex); | ||
486 | |||
487 | md->enabled = panel_enabled(md); | ||
488 | |||
489 | if (md->enabled) | ||
490 | mipid_esd_start_check(md); | ||
491 | else | ||
492 | md->saved_bklight_level = mipid_get_bklight_level(panel); | ||
493 | |||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | static void mipid_cleanup(struct lcd_panel *panel) | ||
498 | { | ||
499 | struct mipid_device *md = to_mipid_device(panel); | ||
500 | |||
501 | if (md->enabled) | ||
502 | mipid_esd_stop_check(md); | ||
503 | destroy_workqueue(md->esd_wq); | ||
504 | } | ||
505 | |||
506 | static struct lcd_panel mipid_panel = { | ||
507 | .config = OMAP_LCDC_PANEL_TFT, | ||
508 | |||
509 | .bpp = 16, | ||
510 | .x_res = 800, | ||
511 | .y_res = 480, | ||
512 | .pixel_clock = 21940, | ||
513 | .hsw = 50, | ||
514 | .hfp = 20, | ||
515 | .hbp = 15, | ||
516 | .vsw = 2, | ||
517 | .vfp = 1, | ||
518 | .vbp = 3, | ||
519 | |||
520 | .init = mipid_init, | ||
521 | .cleanup = mipid_cleanup, | ||
522 | .enable = mipid_enable, | ||
523 | .disable = mipid_disable, | ||
524 | .get_caps = mipid_get_caps, | ||
525 | .set_bklight_level = mipid_set_bklight_level, | ||
526 | .get_bklight_level = mipid_get_bklight_level, | ||
527 | .get_bklight_max = mipid_get_bklight_max, | ||
528 | .run_test = mipid_run_test, | ||
529 | }; | ||
530 | |||
531 | static int mipid_detect(struct mipid_device *md) | ||
532 | { | ||
533 | struct mipid_platform_data *pdata; | ||
534 | u8 display_id[3]; | ||
535 | |||
536 | pdata = md->spi->dev.platform_data; | ||
537 | if (pdata == NULL) { | ||
538 | dev_err(&md->spi->dev, "missing platform data\n"); | ||
539 | return -ENOENT; | ||
540 | } | ||
541 | |||
542 | mipid_read(md, MIPID_CMD_READ_DISP_ID, display_id, 3); | ||
543 | dev_dbg(&md->spi->dev, "MIPI display ID: %02x%02x%02x\n", | ||
544 | display_id[0], display_id[1], display_id[2]); | ||
545 | |||
546 | switch (display_id[0]) { | ||
547 | case 0x45: | ||
548 | md->panel.name = "lph8923"; | ||
549 | break; | ||
550 | case 0x83: | ||
551 | md->panel.name = "ls041y3"; | ||
552 | md->esd_check = ls041y3_esd_check; | ||
553 | break; | ||
554 | default: | ||
555 | md->panel.name = "unknown"; | ||
556 | dev_err(&md->spi->dev, "invalid display ID\n"); | ||
557 | return -ENODEV; | ||
558 | } | ||
559 | |||
560 | md->revision = display_id[1]; | ||
561 | md->panel.data_lines = pdata->data_lines; | ||
562 | pr_info("omapfb: %s rev %02x LCD detected, %d data lines\n", | ||
563 | md->panel.name, md->revision, md->panel.data_lines); | ||
564 | |||
565 | return 0; | ||
566 | } | ||
567 | |||
568 | static int mipid_spi_probe(struct spi_device *spi) | ||
569 | { | ||
570 | struct mipid_device *md; | ||
571 | int r; | ||
572 | |||
573 | md = kzalloc(sizeof(*md), GFP_KERNEL); | ||
574 | if (md == NULL) { | ||
575 | dev_err(&spi->dev, "out of memory\n"); | ||
576 | return -ENOMEM; | ||
577 | } | ||
578 | |||
579 | spi->mode = SPI_MODE_0; | ||
580 | md->spi = spi; | ||
581 | dev_set_drvdata(&spi->dev, md); | ||
582 | md->panel = mipid_panel; | ||
583 | |||
584 | r = mipid_detect(md); | ||
585 | if (r < 0) | ||
586 | return r; | ||
587 | |||
588 | omapfb_register_panel(&md->panel); | ||
589 | |||
590 | return 0; | ||
591 | } | ||
592 | |||
593 | static int mipid_spi_remove(struct spi_device *spi) | ||
594 | { | ||
595 | struct mipid_device *md = dev_get_drvdata(&spi->dev); | ||
596 | |||
597 | mipid_disable(&md->panel); | ||
598 | kfree(md); | ||
599 | |||
600 | return 0; | ||
601 | } | ||
602 | |||
603 | static struct spi_driver mipid_spi_driver = { | ||
604 | .driver = { | ||
605 | .name = MIPID_MODULE_NAME, | ||
606 | .owner = THIS_MODULE, | ||
607 | }, | ||
608 | .probe = mipid_spi_probe, | ||
609 | .remove = mipid_spi_remove, | ||
610 | }; | ||
611 | |||
612 | module_spi_driver(mipid_spi_driver); | ||
613 | |||
614 | MODULE_DESCRIPTION("MIPI display driver"); | ||
615 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap/lcd_osk.c b/drivers/video/omap/lcd_osk.c deleted file mode 100644 index 7fbe04bce0ed..000000000000 --- a/drivers/video/omap/lcd_osk.c +++ /dev/null | |||
@@ -1,133 +0,0 @@ | |||
1 | /* | ||
2 | * LCD panel support for the TI OMAP OSK board | ||
3 | * | ||
4 | * Copyright (C) 2004 Nokia Corporation | ||
5 | * Author: Imre Deak <imre.deak@nokia.com> | ||
6 | * Adapted for OSK by <dirk.behme@de.bosch.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | |||
26 | #include <asm/gpio.h> | ||
27 | |||
28 | #include <mach/hardware.h> | ||
29 | #include <mach/mux.h> | ||
30 | |||
31 | #include "omapfb.h" | ||
32 | |||
33 | static int osk_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev) | ||
34 | { | ||
35 | /* gpio2 was allocated in board init */ | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | static void osk_panel_cleanup(struct lcd_panel *panel) | ||
40 | { | ||
41 | } | ||
42 | |||
43 | static int osk_panel_enable(struct lcd_panel *panel) | ||
44 | { | ||
45 | /* configure PWL pin */ | ||
46 | omap_cfg_reg(PWL); | ||
47 | |||
48 | /* Enable PWL unit */ | ||
49 | omap_writeb(0x01, OMAP_PWL_CLK_ENABLE); | ||
50 | |||
51 | /* Set PWL level */ | ||
52 | omap_writeb(0xFF, OMAP_PWL_ENABLE); | ||
53 | |||
54 | /* set GPIO2 high (lcd power enabled) */ | ||
55 | gpio_set_value(2, 1); | ||
56 | |||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | static void osk_panel_disable(struct lcd_panel *panel) | ||
61 | { | ||
62 | /* Set PWL level to zero */ | ||
63 | omap_writeb(0x00, OMAP_PWL_ENABLE); | ||
64 | |||
65 | /* Disable PWL unit */ | ||
66 | omap_writeb(0x00, OMAP_PWL_CLK_ENABLE); | ||
67 | |||
68 | /* set GPIO2 low */ | ||
69 | gpio_set_value(2, 0); | ||
70 | } | ||
71 | |||
72 | static unsigned long osk_panel_get_caps(struct lcd_panel *panel) | ||
73 | { | ||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | struct lcd_panel osk_panel = { | ||
78 | .name = "osk", | ||
79 | .config = OMAP_LCDC_PANEL_TFT, | ||
80 | |||
81 | .bpp = 16, | ||
82 | .data_lines = 16, | ||
83 | .x_res = 240, | ||
84 | .y_res = 320, | ||
85 | .pixel_clock = 12500, | ||
86 | .hsw = 40, | ||
87 | .hfp = 40, | ||
88 | .hbp = 72, | ||
89 | .vsw = 1, | ||
90 | .vfp = 1, | ||
91 | .vbp = 0, | ||
92 | .pcd = 12, | ||
93 | |||
94 | .init = osk_panel_init, | ||
95 | .cleanup = osk_panel_cleanup, | ||
96 | .enable = osk_panel_enable, | ||
97 | .disable = osk_panel_disable, | ||
98 | .get_caps = osk_panel_get_caps, | ||
99 | }; | ||
100 | |||
101 | static int osk_panel_probe(struct platform_device *pdev) | ||
102 | { | ||
103 | omapfb_register_panel(&osk_panel); | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static int osk_panel_remove(struct platform_device *pdev) | ||
108 | { | ||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | static int osk_panel_suspend(struct platform_device *pdev, pm_message_t mesg) | ||
113 | { | ||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | static int osk_panel_resume(struct platform_device *pdev) | ||
118 | { | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | static struct platform_driver osk_panel_driver = { | ||
123 | .probe = osk_panel_probe, | ||
124 | .remove = osk_panel_remove, | ||
125 | .suspend = osk_panel_suspend, | ||
126 | .resume = osk_panel_resume, | ||
127 | .driver = { | ||
128 | .name = "lcd_osk", | ||
129 | .owner = THIS_MODULE, | ||
130 | }, | ||
131 | }; | ||
132 | |||
133 | module_platform_driver(osk_panel_driver); | ||
diff --git a/drivers/video/omap/lcd_palmte.c b/drivers/video/omap/lcd_palmte.c deleted file mode 100644 index ff4fb624b904..000000000000 --- a/drivers/video/omap/lcd_palmte.c +++ /dev/null | |||
@@ -1,110 +0,0 @@ | |||
1 | /* | ||
2 | * LCD panel support for the Palm Tungsten E | ||
3 | * | ||
4 | * Original version : Romain Goyet <r.goyet@gmail.com> | ||
5 | * Current version : Laurent Gonzalez <palmte.linux@free.fr> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/io.h> | ||
25 | |||
26 | #include "omapfb.h" | ||
27 | |||
28 | static int palmte_panel_init(struct lcd_panel *panel, | ||
29 | struct omapfb_device *fbdev) | ||
30 | { | ||
31 | return 0; | ||
32 | } | ||
33 | |||
34 | static void palmte_panel_cleanup(struct lcd_panel *panel) | ||
35 | { | ||
36 | } | ||
37 | |||
38 | static int palmte_panel_enable(struct lcd_panel *panel) | ||
39 | { | ||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | static void palmte_panel_disable(struct lcd_panel *panel) | ||
44 | { | ||
45 | } | ||
46 | |||
47 | static unsigned long palmte_panel_get_caps(struct lcd_panel *panel) | ||
48 | { | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | struct lcd_panel palmte_panel = { | ||
53 | .name = "palmte", | ||
54 | .config = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC | | ||
55 | OMAP_LCDC_INV_HSYNC | OMAP_LCDC_HSVS_RISING_EDGE | | ||
56 | OMAP_LCDC_HSVS_OPPOSITE, | ||
57 | |||
58 | .data_lines = 16, | ||
59 | .bpp = 8, | ||
60 | .pixel_clock = 12000, | ||
61 | .x_res = 320, | ||
62 | .y_res = 320, | ||
63 | .hsw = 4, | ||
64 | .hfp = 8, | ||
65 | .hbp = 28, | ||
66 | .vsw = 1, | ||
67 | .vfp = 8, | ||
68 | .vbp = 7, | ||
69 | .pcd = 0, | ||
70 | |||
71 | .init = palmte_panel_init, | ||
72 | .cleanup = palmte_panel_cleanup, | ||
73 | .enable = palmte_panel_enable, | ||
74 | .disable = palmte_panel_disable, | ||
75 | .get_caps = palmte_panel_get_caps, | ||
76 | }; | ||
77 | |||
78 | static int palmte_panel_probe(struct platform_device *pdev) | ||
79 | { | ||
80 | omapfb_register_panel(&palmte_panel); | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static int palmte_panel_remove(struct platform_device *pdev) | ||
85 | { | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static int palmte_panel_suspend(struct platform_device *pdev, pm_message_t mesg) | ||
90 | { | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | static int palmte_panel_resume(struct platform_device *pdev) | ||
95 | { | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | static struct platform_driver palmte_panel_driver = { | ||
100 | .probe = palmte_panel_probe, | ||
101 | .remove = palmte_panel_remove, | ||
102 | .suspend = palmte_panel_suspend, | ||
103 | .resume = palmte_panel_resume, | ||
104 | .driver = { | ||
105 | .name = "lcd_palmte", | ||
106 | .owner = THIS_MODULE, | ||
107 | }, | ||
108 | }; | ||
109 | |||
110 | module_platform_driver(palmte_panel_driver); | ||
diff --git a/drivers/video/omap/lcd_palmtt.c b/drivers/video/omap/lcd_palmtt.c deleted file mode 100644 index aaf3c8ba1243..000000000000 --- a/drivers/video/omap/lcd_palmtt.c +++ /dev/null | |||
@@ -1,116 +0,0 @@ | |||
1 | /* | ||
2 | * LCD panel support for Palm Tungsten|T | ||
3 | * Current version : Marek Vasut <marek.vasut@gmail.com> | ||
4 | * | ||
5 | * Modified from lcd_inn1510.c | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | |||
22 | /* | ||
23 | GPIO11 - backlight | ||
24 | GPIO12 - screen blanking | ||
25 | GPIO13 - screen blanking | ||
26 | */ | ||
27 | |||
28 | #include <linux/platform_device.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/io.h> | ||
31 | |||
32 | #include <asm/gpio.h> | ||
33 | #include "omapfb.h" | ||
34 | |||
35 | static int palmtt_panel_init(struct lcd_panel *panel, | ||
36 | struct omapfb_device *fbdev) | ||
37 | { | ||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | static void palmtt_panel_cleanup(struct lcd_panel *panel) | ||
42 | { | ||
43 | } | ||
44 | |||
45 | static int palmtt_panel_enable(struct lcd_panel *panel) | ||
46 | { | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | static void palmtt_panel_disable(struct lcd_panel *panel) | ||
51 | { | ||
52 | } | ||
53 | |||
54 | static unsigned long palmtt_panel_get_caps(struct lcd_panel *panel) | ||
55 | { | ||
56 | return OMAPFB_CAPS_SET_BACKLIGHT; | ||
57 | } | ||
58 | |||
59 | struct lcd_panel palmtt_panel = { | ||
60 | .name = "palmtt", | ||
61 | .config = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC | | ||
62 | OMAP_LCDC_INV_HSYNC | OMAP_LCDC_HSVS_RISING_EDGE | | ||
63 | OMAP_LCDC_HSVS_OPPOSITE, | ||
64 | .bpp = 16, | ||
65 | .data_lines = 16, | ||
66 | .x_res = 320, | ||
67 | .y_res = 320, | ||
68 | .pixel_clock = 10000, | ||
69 | .hsw = 4, | ||
70 | .hfp = 8, | ||
71 | .hbp = 28, | ||
72 | .vsw = 1, | ||
73 | .vfp = 8, | ||
74 | .vbp = 7, | ||
75 | .pcd = 0, | ||
76 | |||
77 | .init = palmtt_panel_init, | ||
78 | .cleanup = palmtt_panel_cleanup, | ||
79 | .enable = palmtt_panel_enable, | ||
80 | .disable = palmtt_panel_disable, | ||
81 | .get_caps = palmtt_panel_get_caps, | ||
82 | }; | ||
83 | |||
84 | static int palmtt_panel_probe(struct platform_device *pdev) | ||
85 | { | ||
86 | omapfb_register_panel(&palmtt_panel); | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static int palmtt_panel_remove(struct platform_device *pdev) | ||
91 | { | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static int palmtt_panel_suspend(struct platform_device *pdev, pm_message_t mesg) | ||
96 | { | ||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | static int palmtt_panel_resume(struct platform_device *pdev) | ||
101 | { | ||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static struct platform_driver palmtt_panel_driver = { | ||
106 | .probe = palmtt_panel_probe, | ||
107 | .remove = palmtt_panel_remove, | ||
108 | .suspend = palmtt_panel_suspend, | ||
109 | .resume = palmtt_panel_resume, | ||
110 | .driver = { | ||
111 | .name = "lcd_palmtt", | ||
112 | .owner = THIS_MODULE, | ||
113 | }, | ||
114 | }; | ||
115 | |||
116 | module_platform_driver(palmtt_panel_driver); | ||
diff --git a/drivers/video/omap/lcd_palmz71.c b/drivers/video/omap/lcd_palmz71.c deleted file mode 100644 index 3b7d8aa1cf34..000000000000 --- a/drivers/video/omap/lcd_palmz71.c +++ /dev/null | |||
@@ -1,112 +0,0 @@ | |||
1 | /* | ||
2 | * LCD panel support for the Palm Zire71 | ||
3 | * | ||
4 | * Original version : Romain Goyet | ||
5 | * Current version : Laurent Gonzalez | ||
6 | * Modified for zire71 : Marek Vasut | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/io.h> | ||
26 | |||
27 | #include "omapfb.h" | ||
28 | |||
29 | static int palmz71_panel_init(struct lcd_panel *panel, | ||
30 | struct omapfb_device *fbdev) | ||
31 | { | ||
32 | return 0; | ||
33 | } | ||
34 | |||
35 | static void palmz71_panel_cleanup(struct lcd_panel *panel) | ||
36 | { | ||
37 | |||
38 | } | ||
39 | |||
40 | static int palmz71_panel_enable(struct lcd_panel *panel) | ||
41 | { | ||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | static void palmz71_panel_disable(struct lcd_panel *panel) | ||
46 | { | ||
47 | } | ||
48 | |||
49 | static unsigned long palmz71_panel_get_caps(struct lcd_panel *panel) | ||
50 | { | ||
51 | return OMAPFB_CAPS_SET_BACKLIGHT; | ||
52 | } | ||
53 | |||
54 | struct lcd_panel palmz71_panel = { | ||
55 | .name = "palmz71", | ||
56 | .config = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC | | ||
57 | OMAP_LCDC_INV_HSYNC | OMAP_LCDC_HSVS_RISING_EDGE | | ||
58 | OMAP_LCDC_HSVS_OPPOSITE, | ||
59 | .data_lines = 16, | ||
60 | .bpp = 16, | ||
61 | .pixel_clock = 24000, | ||
62 | .x_res = 320, | ||
63 | .y_res = 320, | ||
64 | .hsw = 4, | ||
65 | .hfp = 8, | ||
66 | .hbp = 28, | ||
67 | .vsw = 1, | ||
68 | .vfp = 8, | ||
69 | .vbp = 7, | ||
70 | .pcd = 0, | ||
71 | |||
72 | .init = palmz71_panel_init, | ||
73 | .cleanup = palmz71_panel_cleanup, | ||
74 | .enable = palmz71_panel_enable, | ||
75 | .disable = palmz71_panel_disable, | ||
76 | .get_caps = palmz71_panel_get_caps, | ||
77 | }; | ||
78 | |||
79 | static int palmz71_panel_probe(struct platform_device *pdev) | ||
80 | { | ||
81 | omapfb_register_panel(&palmz71_panel); | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static int palmz71_panel_remove(struct platform_device *pdev) | ||
86 | { | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static int palmz71_panel_suspend(struct platform_device *pdev, | ||
91 | pm_message_t mesg) | ||
92 | { | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static int palmz71_panel_resume(struct platform_device *pdev) | ||
97 | { | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static struct platform_driver palmz71_panel_driver = { | ||
102 | .probe = palmz71_panel_probe, | ||
103 | .remove = palmz71_panel_remove, | ||
104 | .suspend = palmz71_panel_suspend, | ||
105 | .resume = palmz71_panel_resume, | ||
106 | .driver = { | ||
107 | .name = "lcd_palmz71", | ||
108 | .owner = THIS_MODULE, | ||
109 | }, | ||
110 | }; | ||
111 | |||
112 | module_platform_driver(palmz71_panel_driver); | ||
diff --git a/drivers/video/omap/lcdc.c b/drivers/video/omap/lcdc.c deleted file mode 100644 index b52f62595f65..000000000000 --- a/drivers/video/omap/lcdc.c +++ /dev/null | |||
@@ -1,856 +0,0 @@ | |||
1 | /* | ||
2 | * OMAP1 internal LCD controller | ||
3 | * | ||
4 | * Copyright (C) 2004 Nokia Corporation | ||
5 | * Author: Imre Deak <imre.deak@nokia.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/device.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/spinlock.h> | ||
25 | #include <linux/err.h> | ||
26 | #include <linux/mm.h> | ||
27 | #include <linux/fb.h> | ||
28 | #include <linux/dma-mapping.h> | ||
29 | #include <linux/vmalloc.h> | ||
30 | #include <linux/clk.h> | ||
31 | #include <linux/gfp.h> | ||
32 | |||
33 | #include <mach/lcdc.h> | ||
34 | #include <linux/omap-dma.h> | ||
35 | |||
36 | #include <asm/mach-types.h> | ||
37 | |||
38 | #include "omapfb.h" | ||
39 | |||
40 | #include "lcdc.h" | ||
41 | |||
42 | #define MODULE_NAME "lcdc" | ||
43 | |||
44 | #define MAX_PALETTE_SIZE PAGE_SIZE | ||
45 | |||
46 | enum lcdc_load_mode { | ||
47 | OMAP_LCDC_LOAD_PALETTE, | ||
48 | OMAP_LCDC_LOAD_FRAME, | ||
49 | OMAP_LCDC_LOAD_PALETTE_AND_FRAME | ||
50 | }; | ||
51 | |||
52 | static struct omap_lcd_controller { | ||
53 | enum omapfb_update_mode update_mode; | ||
54 | int ext_mode; | ||
55 | |||
56 | unsigned long frame_offset; | ||
57 | int screen_width; | ||
58 | int xres; | ||
59 | int yres; | ||
60 | |||
61 | enum omapfb_color_format color_mode; | ||
62 | int bpp; | ||
63 | void *palette_virt; | ||
64 | dma_addr_t palette_phys; | ||
65 | int palette_code; | ||
66 | int palette_size; | ||
67 | |||
68 | unsigned int irq_mask; | ||
69 | struct completion last_frame_complete; | ||
70 | struct completion palette_load_complete; | ||
71 | struct clk *lcd_ck; | ||
72 | struct omapfb_device *fbdev; | ||
73 | |||
74 | void (*dma_callback)(void *data); | ||
75 | void *dma_callback_data; | ||
76 | |||
77 | int fbmem_allocated; | ||
78 | dma_addr_t vram_phys; | ||
79 | void *vram_virt; | ||
80 | unsigned long vram_size; | ||
81 | } lcdc; | ||
82 | |||
83 | static void inline enable_irqs(int mask) | ||
84 | { | ||
85 | lcdc.irq_mask |= mask; | ||
86 | } | ||
87 | |||
88 | static void inline disable_irqs(int mask) | ||
89 | { | ||
90 | lcdc.irq_mask &= ~mask; | ||
91 | } | ||
92 | |||
93 | static void set_load_mode(enum lcdc_load_mode mode) | ||
94 | { | ||
95 | u32 l; | ||
96 | |||
97 | l = omap_readl(OMAP_LCDC_CONTROL); | ||
98 | l &= ~(3 << 20); | ||
99 | switch (mode) { | ||
100 | case OMAP_LCDC_LOAD_PALETTE: | ||
101 | l |= 1 << 20; | ||
102 | break; | ||
103 | case OMAP_LCDC_LOAD_FRAME: | ||
104 | l |= 2 << 20; | ||
105 | break; | ||
106 | case OMAP_LCDC_LOAD_PALETTE_AND_FRAME: | ||
107 | break; | ||
108 | default: | ||
109 | BUG(); | ||
110 | } | ||
111 | omap_writel(l, OMAP_LCDC_CONTROL); | ||
112 | } | ||
113 | |||
114 | static void enable_controller(void) | ||
115 | { | ||
116 | u32 l; | ||
117 | |||
118 | l = omap_readl(OMAP_LCDC_CONTROL); | ||
119 | l |= OMAP_LCDC_CTRL_LCD_EN; | ||
120 | l &= ~OMAP_LCDC_IRQ_MASK; | ||
121 | l |= lcdc.irq_mask | OMAP_LCDC_IRQ_DONE; /* enabled IRQs */ | ||
122 | omap_writel(l, OMAP_LCDC_CONTROL); | ||
123 | } | ||
124 | |||
125 | static void disable_controller_async(void) | ||
126 | { | ||
127 | u32 l; | ||
128 | u32 mask; | ||
129 | |||
130 | l = omap_readl(OMAP_LCDC_CONTROL); | ||
131 | mask = OMAP_LCDC_CTRL_LCD_EN | OMAP_LCDC_IRQ_MASK; | ||
132 | /* | ||
133 | * Preserve the DONE mask, since we still want to get the | ||
134 | * final DONE irq. It will be disabled in the IRQ handler. | ||
135 | */ | ||
136 | mask &= ~OMAP_LCDC_IRQ_DONE; | ||
137 | l &= ~mask; | ||
138 | omap_writel(l, OMAP_LCDC_CONTROL); | ||
139 | } | ||
140 | |||
141 | static void disable_controller(void) | ||
142 | { | ||
143 | init_completion(&lcdc.last_frame_complete); | ||
144 | disable_controller_async(); | ||
145 | if (!wait_for_completion_timeout(&lcdc.last_frame_complete, | ||
146 | msecs_to_jiffies(500))) | ||
147 | dev_err(lcdc.fbdev->dev, "timeout waiting for FRAME DONE\n"); | ||
148 | } | ||
149 | |||
150 | static void reset_controller(u32 status) | ||
151 | { | ||
152 | static unsigned long reset_count; | ||
153 | static unsigned long last_jiffies; | ||
154 | |||
155 | disable_controller_async(); | ||
156 | reset_count++; | ||
157 | if (reset_count == 1 || time_after(jiffies, last_jiffies + HZ)) { | ||
158 | dev_err(lcdc.fbdev->dev, | ||
159 | "resetting (status %#010x,reset count %lu)\n", | ||
160 | status, reset_count); | ||
161 | last_jiffies = jiffies; | ||
162 | } | ||
163 | if (reset_count < 100) { | ||
164 | enable_controller(); | ||
165 | } else { | ||
166 | reset_count = 0; | ||
167 | dev_err(lcdc.fbdev->dev, | ||
168 | "too many reset attempts, giving up.\n"); | ||
169 | } | ||
170 | } | ||
171 | |||
172 | /* | ||
173 | * Configure the LCD DMA according to the current mode specified by parameters | ||
174 | * in lcdc.fbdev and fbdev->var. | ||
175 | */ | ||
176 | static void setup_lcd_dma(void) | ||
177 | { | ||
178 | static const int dma_elem_type[] = { | ||
179 | 0, | ||
180 | OMAP_DMA_DATA_TYPE_S8, | ||
181 | OMAP_DMA_DATA_TYPE_S16, | ||
182 | 0, | ||
183 | OMAP_DMA_DATA_TYPE_S32, | ||
184 | }; | ||
185 | struct omapfb_plane_struct *plane = lcdc.fbdev->fb_info[0]->par; | ||
186 | struct fb_var_screeninfo *var = &lcdc.fbdev->fb_info[0]->var; | ||
187 | unsigned long src; | ||
188 | int esize, xelem, yelem; | ||
189 | |||
190 | src = lcdc.vram_phys + lcdc.frame_offset; | ||
191 | |||
192 | switch (var->rotate) { | ||
193 | case 0: | ||
194 | if (plane->info.mirror || (src & 3) || | ||
195 | lcdc.color_mode == OMAPFB_COLOR_YUV420 || | ||
196 | (lcdc.xres & 1)) | ||
197 | esize = 2; | ||
198 | else | ||
199 | esize = 4; | ||
200 | xelem = lcdc.xres * lcdc.bpp / 8 / esize; | ||
201 | yelem = lcdc.yres; | ||
202 | break; | ||
203 | case 90: | ||
204 | case 180: | ||
205 | case 270: | ||
206 | if (cpu_is_omap15xx()) { | ||
207 | BUG(); | ||
208 | } | ||
209 | esize = 2; | ||
210 | xelem = lcdc.yres * lcdc.bpp / 16; | ||
211 | yelem = lcdc.xres; | ||
212 | break; | ||
213 | default: | ||
214 | BUG(); | ||
215 | return; | ||
216 | } | ||
217 | #ifdef VERBOSE | ||
218 | dev_dbg(lcdc.fbdev->dev, | ||
219 | "setup_dma: src %#010lx esize %d xelem %d yelem %d\n", | ||
220 | src, esize, xelem, yelem); | ||
221 | #endif | ||
222 | omap_set_lcd_dma_b1(src, xelem, yelem, dma_elem_type[esize]); | ||
223 | if (!cpu_is_omap15xx()) { | ||
224 | int bpp = lcdc.bpp; | ||
225 | |||
226 | /* | ||
227 | * YUV support is only for external mode when we have the | ||
228 | * YUV window embedded in a 16bpp frame buffer. | ||
229 | */ | ||
230 | if (lcdc.color_mode == OMAPFB_COLOR_YUV420) | ||
231 | bpp = 16; | ||
232 | /* Set virtual xres elem size */ | ||
233 | omap_set_lcd_dma_b1_vxres( | ||
234 | lcdc.screen_width * bpp / 8 / esize); | ||
235 | /* Setup transformations */ | ||
236 | omap_set_lcd_dma_b1_rotation(var->rotate); | ||
237 | omap_set_lcd_dma_b1_mirror(plane->info.mirror); | ||
238 | } | ||
239 | omap_setup_lcd_dma(); | ||
240 | } | ||
241 | |||
242 | static irqreturn_t lcdc_irq_handler(int irq, void *dev_id) | ||
243 | { | ||
244 | u32 status; | ||
245 | |||
246 | status = omap_readl(OMAP_LCDC_STATUS); | ||
247 | |||
248 | if (status & (OMAP_LCDC_STAT_FUF | OMAP_LCDC_STAT_SYNC_LOST)) | ||
249 | reset_controller(status); | ||
250 | else { | ||
251 | if (status & OMAP_LCDC_STAT_DONE) { | ||
252 | u32 l; | ||
253 | |||
254 | /* | ||
255 | * Disable IRQ_DONE. The status bit will be cleared | ||
256 | * only when the controller is reenabled and we don't | ||
257 | * want to get more interrupts. | ||
258 | */ | ||
259 | l = omap_readl(OMAP_LCDC_CONTROL); | ||
260 | l &= ~OMAP_LCDC_IRQ_DONE; | ||
261 | omap_writel(l, OMAP_LCDC_CONTROL); | ||
262 | complete(&lcdc.last_frame_complete); | ||
263 | } | ||
264 | if (status & OMAP_LCDC_STAT_LOADED_PALETTE) { | ||
265 | disable_controller_async(); | ||
266 | complete(&lcdc.palette_load_complete); | ||
267 | } | ||
268 | } | ||
269 | |||
270 | /* | ||
271 | * Clear these interrupt status bits. | ||
272 | * Sync_lost, FUF bits were cleared by disabling the LCD controller | ||
273 | * LOADED_PALETTE can be cleared this way only in palette only | ||
274 | * load mode. In other load modes it's cleared by disabling the | ||
275 | * controller. | ||
276 | */ | ||
277 | status &= ~(OMAP_LCDC_STAT_VSYNC | | ||
278 | OMAP_LCDC_STAT_LOADED_PALETTE | | ||
279 | OMAP_LCDC_STAT_ABC | | ||
280 | OMAP_LCDC_STAT_LINE_INT); | ||
281 | omap_writel(status, OMAP_LCDC_STATUS); | ||
282 | return IRQ_HANDLED; | ||
283 | } | ||
284 | |||
285 | /* | ||
286 | * Change to a new video mode. We defer this to a later time to avoid any | ||
287 | * flicker and not to mess up the current LCD DMA context. For this we disable | ||
288 | * the LCD controller, which will generate a DONE irq after the last frame has | ||
289 | * been transferred. Then it'll be safe to reconfigure both the LCD controller | ||
290 | * as well as the LCD DMA. | ||
291 | */ | ||
292 | static int omap_lcdc_setup_plane(int plane, int channel_out, | ||
293 | unsigned long offset, int screen_width, | ||
294 | int pos_x, int pos_y, int width, int height, | ||
295 | int color_mode) | ||
296 | { | ||
297 | struct fb_var_screeninfo *var = &lcdc.fbdev->fb_info[0]->var; | ||
298 | struct lcd_panel *panel = lcdc.fbdev->panel; | ||
299 | int rot_x, rot_y; | ||
300 | |||
301 | if (var->rotate == 0) { | ||
302 | rot_x = panel->x_res; | ||
303 | rot_y = panel->y_res; | ||
304 | } else { | ||
305 | rot_x = panel->y_res; | ||
306 | rot_y = panel->x_res; | ||
307 | } | ||
308 | if (plane != 0 || channel_out != 0 || pos_x != 0 || pos_y != 0 || | ||
309 | width > rot_x || height > rot_y) { | ||
310 | #ifdef VERBOSE | ||
311 | dev_dbg(lcdc.fbdev->dev, | ||
312 | "invalid plane params plane %d pos_x %d pos_y %d " | ||
313 | "w %d h %d\n", plane, pos_x, pos_y, width, height); | ||
314 | #endif | ||
315 | return -EINVAL; | ||
316 | } | ||
317 | |||
318 | lcdc.frame_offset = offset; | ||
319 | lcdc.xres = width; | ||
320 | lcdc.yres = height; | ||
321 | lcdc.screen_width = screen_width; | ||
322 | lcdc.color_mode = color_mode; | ||
323 | |||
324 | switch (color_mode) { | ||
325 | case OMAPFB_COLOR_CLUT_8BPP: | ||
326 | lcdc.bpp = 8; | ||
327 | lcdc.palette_code = 0x3000; | ||
328 | lcdc.palette_size = 512; | ||
329 | break; | ||
330 | case OMAPFB_COLOR_RGB565: | ||
331 | lcdc.bpp = 16; | ||
332 | lcdc.palette_code = 0x4000; | ||
333 | lcdc.palette_size = 32; | ||
334 | break; | ||
335 | case OMAPFB_COLOR_RGB444: | ||
336 | lcdc.bpp = 16; | ||
337 | lcdc.palette_code = 0x4000; | ||
338 | lcdc.palette_size = 32; | ||
339 | break; | ||
340 | case OMAPFB_COLOR_YUV420: | ||
341 | if (lcdc.ext_mode) { | ||
342 | lcdc.bpp = 12; | ||
343 | break; | ||
344 | } | ||
345 | /* fallthrough */ | ||
346 | case OMAPFB_COLOR_YUV422: | ||
347 | if (lcdc.ext_mode) { | ||
348 | lcdc.bpp = 16; | ||
349 | break; | ||
350 | } | ||
351 | /* fallthrough */ | ||
352 | default: | ||
353 | /* FIXME: other BPPs. | ||
354 | * bpp1: code 0, size 256 | ||
355 | * bpp2: code 0x1000 size 256 | ||
356 | * bpp4: code 0x2000 size 256 | ||
357 | * bpp12: code 0x4000 size 32 | ||
358 | */ | ||
359 | dev_dbg(lcdc.fbdev->dev, "invalid color mode %d\n", color_mode); | ||
360 | BUG(); | ||
361 | return -1; | ||
362 | } | ||
363 | |||
364 | if (lcdc.ext_mode) { | ||
365 | setup_lcd_dma(); | ||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | if (lcdc.update_mode == OMAPFB_AUTO_UPDATE) { | ||
370 | disable_controller(); | ||
371 | omap_stop_lcd_dma(); | ||
372 | setup_lcd_dma(); | ||
373 | enable_controller(); | ||
374 | } | ||
375 | |||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | static int omap_lcdc_enable_plane(int plane, int enable) | ||
380 | { | ||
381 | dev_dbg(lcdc.fbdev->dev, | ||
382 | "plane %d enable %d update_mode %d ext_mode %d\n", | ||
383 | plane, enable, lcdc.update_mode, lcdc.ext_mode); | ||
384 | if (plane != OMAPFB_PLANE_GFX) | ||
385 | return -EINVAL; | ||
386 | |||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | /* | ||
391 | * Configure the LCD DMA for a palette load operation and do the palette | ||
392 | * downloading synchronously. We don't use the frame+palette load mode of | ||
393 | * the controller, since the palette can always be downloaded separately. | ||
394 | */ | ||
395 | static void load_palette(void) | ||
396 | { | ||
397 | u16 *palette; | ||
398 | |||
399 | palette = (u16 *)lcdc.palette_virt; | ||
400 | |||
401 | *(u16 *)palette &= 0x0fff; | ||
402 | *(u16 *)palette |= lcdc.palette_code; | ||
403 | |||
404 | omap_set_lcd_dma_b1(lcdc.palette_phys, | ||
405 | lcdc.palette_size / 4 + 1, 1, OMAP_DMA_DATA_TYPE_S32); | ||
406 | |||
407 | omap_set_lcd_dma_single_transfer(1); | ||
408 | omap_setup_lcd_dma(); | ||
409 | |||
410 | init_completion(&lcdc.palette_load_complete); | ||
411 | enable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE); | ||
412 | set_load_mode(OMAP_LCDC_LOAD_PALETTE); | ||
413 | enable_controller(); | ||
414 | if (!wait_for_completion_timeout(&lcdc.palette_load_complete, | ||
415 | msecs_to_jiffies(500))) | ||
416 | dev_err(lcdc.fbdev->dev, "timeout waiting for FRAME DONE\n"); | ||
417 | /* The controller gets disabled in the irq handler */ | ||
418 | disable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE); | ||
419 | omap_stop_lcd_dma(); | ||
420 | |||
421 | omap_set_lcd_dma_single_transfer(lcdc.ext_mode); | ||
422 | } | ||
423 | |||
424 | /* Used only in internal controller mode */ | ||
425 | static int omap_lcdc_setcolreg(u_int regno, u16 red, u16 green, u16 blue, | ||
426 | u16 transp, int update_hw_pal) | ||
427 | { | ||
428 | u16 *palette; | ||
429 | |||
430 | if (lcdc.color_mode != OMAPFB_COLOR_CLUT_8BPP || regno > 255) | ||
431 | return -EINVAL; | ||
432 | |||
433 | palette = (u16 *)lcdc.palette_virt; | ||
434 | |||
435 | palette[regno] &= ~0x0fff; | ||
436 | palette[regno] |= ((red >> 12) << 8) | ((green >> 12) << 4 ) | | ||
437 | (blue >> 12); | ||
438 | |||
439 | if (update_hw_pal) { | ||
440 | disable_controller(); | ||
441 | omap_stop_lcd_dma(); | ||
442 | load_palette(); | ||
443 | setup_lcd_dma(); | ||
444 | set_load_mode(OMAP_LCDC_LOAD_FRAME); | ||
445 | enable_controller(); | ||
446 | } | ||
447 | |||
448 | return 0; | ||
449 | } | ||
450 | |||
451 | static void calc_ck_div(int is_tft, int pck, int *pck_div) | ||
452 | { | ||
453 | unsigned long lck; | ||
454 | |||
455 | pck = max(1, pck); | ||
456 | lck = clk_get_rate(lcdc.lcd_ck); | ||
457 | *pck_div = (lck + pck - 1) / pck; | ||
458 | if (is_tft) | ||
459 | *pck_div = max(2, *pck_div); | ||
460 | else | ||
461 | *pck_div = max(3, *pck_div); | ||
462 | if (*pck_div > 255) { | ||
463 | /* FIXME: try to adjust logic clock divider as well */ | ||
464 | *pck_div = 255; | ||
465 | dev_warn(lcdc.fbdev->dev, "pixclock %d kHz too low.\n", | ||
466 | pck / 1000); | ||
467 | } | ||
468 | } | ||
469 | |||
470 | static void inline setup_regs(void) | ||
471 | { | ||
472 | u32 l; | ||
473 | struct lcd_panel *panel = lcdc.fbdev->panel; | ||
474 | int is_tft = panel->config & OMAP_LCDC_PANEL_TFT; | ||
475 | unsigned long lck; | ||
476 | int pcd; | ||
477 | |||
478 | l = omap_readl(OMAP_LCDC_CONTROL); | ||
479 | l &= ~OMAP_LCDC_CTRL_LCD_TFT; | ||
480 | l |= is_tft ? OMAP_LCDC_CTRL_LCD_TFT : 0; | ||
481 | #ifdef CONFIG_MACH_OMAP_PALMTE | ||
482 | /* FIXME:if (machine_is_omap_palmte()) { */ | ||
483 | /* PalmTE uses alternate TFT setting in 8BPP mode */ | ||
484 | l |= (is_tft && panel->bpp == 8) ? 0x810000 : 0; | ||
485 | /* } */ | ||
486 | #endif | ||
487 | omap_writel(l, OMAP_LCDC_CONTROL); | ||
488 | |||
489 | l = omap_readl(OMAP_LCDC_TIMING2); | ||
490 | l &= ~(((1 << 6) - 1) << 20); | ||
491 | l |= (panel->config & OMAP_LCDC_SIGNAL_MASK) << 20; | ||
492 | omap_writel(l, OMAP_LCDC_TIMING2); | ||
493 | |||
494 | l = panel->x_res - 1; | ||
495 | l |= (panel->hsw - 1) << 10; | ||
496 | l |= (panel->hfp - 1) << 16; | ||
497 | l |= (panel->hbp - 1) << 24; | ||
498 | omap_writel(l, OMAP_LCDC_TIMING0); | ||
499 | |||
500 | l = panel->y_res - 1; | ||
501 | l |= (panel->vsw - 1) << 10; | ||
502 | l |= panel->vfp << 16; | ||
503 | l |= panel->vbp << 24; | ||
504 | omap_writel(l, OMAP_LCDC_TIMING1); | ||
505 | |||
506 | l = omap_readl(OMAP_LCDC_TIMING2); | ||
507 | l &= ~0xff; | ||
508 | |||
509 | lck = clk_get_rate(lcdc.lcd_ck); | ||
510 | |||
511 | if (!panel->pcd) | ||
512 | calc_ck_div(is_tft, panel->pixel_clock * 1000, &pcd); | ||
513 | else { | ||
514 | dev_warn(lcdc.fbdev->dev, | ||
515 | "Pixel clock divider value is obsolete.\n" | ||
516 | "Try to set pixel_clock to %lu and pcd to 0 " | ||
517 | "in drivers/video/omap/lcd_%s.c and submit a patch.\n", | ||
518 | lck / panel->pcd / 1000, panel->name); | ||
519 | |||
520 | pcd = panel->pcd; | ||
521 | } | ||
522 | l |= pcd & 0xff; | ||
523 | l |= panel->acb << 8; | ||
524 | omap_writel(l, OMAP_LCDC_TIMING2); | ||
525 | |||
526 | /* update panel info with the exact clock */ | ||
527 | panel->pixel_clock = lck / pcd / 1000; | ||
528 | } | ||
529 | |||
530 | /* | ||
531 | * Configure the LCD controller, download the color palette and start a looped | ||
532 | * DMA transfer of the frame image data. Called only in internal | ||
533 | * controller mode. | ||
534 | */ | ||
535 | static int omap_lcdc_set_update_mode(enum omapfb_update_mode mode) | ||
536 | { | ||
537 | int r = 0; | ||
538 | |||
539 | if (mode != lcdc.update_mode) { | ||
540 | switch (mode) { | ||
541 | case OMAPFB_AUTO_UPDATE: | ||
542 | setup_regs(); | ||
543 | load_palette(); | ||
544 | |||
545 | /* Setup and start LCD DMA */ | ||
546 | setup_lcd_dma(); | ||
547 | |||
548 | set_load_mode(OMAP_LCDC_LOAD_FRAME); | ||
549 | enable_irqs(OMAP_LCDC_IRQ_DONE); | ||
550 | /* This will start the actual DMA transfer */ | ||
551 | enable_controller(); | ||
552 | lcdc.update_mode = mode; | ||
553 | break; | ||
554 | case OMAPFB_UPDATE_DISABLED: | ||
555 | disable_controller(); | ||
556 | omap_stop_lcd_dma(); | ||
557 | lcdc.update_mode = mode; | ||
558 | break; | ||
559 | default: | ||
560 | r = -EINVAL; | ||
561 | } | ||
562 | } | ||
563 | |||
564 | return r; | ||
565 | } | ||
566 | |||
567 | static enum omapfb_update_mode omap_lcdc_get_update_mode(void) | ||
568 | { | ||
569 | return lcdc.update_mode; | ||
570 | } | ||
571 | |||
572 | /* PM code called only in internal controller mode */ | ||
573 | static void omap_lcdc_suspend(void) | ||
574 | { | ||
575 | omap_lcdc_set_update_mode(OMAPFB_UPDATE_DISABLED); | ||
576 | } | ||
577 | |||
578 | static void omap_lcdc_resume(void) | ||
579 | { | ||
580 | omap_lcdc_set_update_mode(OMAPFB_AUTO_UPDATE); | ||
581 | } | ||
582 | |||
583 | static void omap_lcdc_get_caps(int plane, struct omapfb_caps *caps) | ||
584 | { | ||
585 | return; | ||
586 | } | ||
587 | |||
588 | int omap_lcdc_set_dma_callback(void (*callback)(void *data), void *data) | ||
589 | { | ||
590 | BUG_ON(callback == NULL); | ||
591 | |||
592 | if (lcdc.dma_callback) | ||
593 | return -EBUSY; | ||
594 | else { | ||
595 | lcdc.dma_callback = callback; | ||
596 | lcdc.dma_callback_data = data; | ||
597 | } | ||
598 | return 0; | ||
599 | } | ||
600 | EXPORT_SYMBOL(omap_lcdc_set_dma_callback); | ||
601 | |||
602 | void omap_lcdc_free_dma_callback(void) | ||
603 | { | ||
604 | lcdc.dma_callback = NULL; | ||
605 | } | ||
606 | EXPORT_SYMBOL(omap_lcdc_free_dma_callback); | ||
607 | |||
608 | static void lcdc_dma_handler(u16 status, void *data) | ||
609 | { | ||
610 | if (lcdc.dma_callback) | ||
611 | lcdc.dma_callback(lcdc.dma_callback_data); | ||
612 | } | ||
613 | |||
614 | static int mmap_kern(void) | ||
615 | { | ||
616 | struct vm_struct *kvma; | ||
617 | struct vm_area_struct vma; | ||
618 | pgprot_t pgprot; | ||
619 | unsigned long vaddr; | ||
620 | |||
621 | kvma = get_vm_area(lcdc.vram_size, VM_IOREMAP); | ||
622 | if (kvma == NULL) { | ||
623 | dev_err(lcdc.fbdev->dev, "can't get kernel vm area\n"); | ||
624 | return -ENOMEM; | ||
625 | } | ||
626 | vma.vm_mm = &init_mm; | ||
627 | |||
628 | vaddr = (unsigned long)kvma->addr; | ||
629 | vma.vm_start = vaddr; | ||
630 | vma.vm_end = vaddr + lcdc.vram_size; | ||
631 | |||
632 | pgprot = pgprot_writecombine(pgprot_kernel); | ||
633 | if (io_remap_pfn_range(&vma, vaddr, | ||
634 | lcdc.vram_phys >> PAGE_SHIFT, | ||
635 | lcdc.vram_size, pgprot) < 0) { | ||
636 | dev_err(lcdc.fbdev->dev, "kernel mmap for FB memory failed\n"); | ||
637 | return -EAGAIN; | ||
638 | } | ||
639 | |||
640 | lcdc.vram_virt = (void *)vaddr; | ||
641 | |||
642 | return 0; | ||
643 | } | ||
644 | |||
645 | static void unmap_kern(void) | ||
646 | { | ||
647 | vunmap(lcdc.vram_virt); | ||
648 | } | ||
649 | |||
650 | static int alloc_palette_ram(void) | ||
651 | { | ||
652 | lcdc.palette_virt = dma_alloc_writecombine(lcdc.fbdev->dev, | ||
653 | MAX_PALETTE_SIZE, &lcdc.palette_phys, GFP_KERNEL); | ||
654 | if (lcdc.palette_virt == NULL) { | ||
655 | dev_err(lcdc.fbdev->dev, "failed to alloc palette memory\n"); | ||
656 | return -ENOMEM; | ||
657 | } | ||
658 | memset(lcdc.palette_virt, 0, MAX_PALETTE_SIZE); | ||
659 | |||
660 | return 0; | ||
661 | } | ||
662 | |||
663 | static void free_palette_ram(void) | ||
664 | { | ||
665 | dma_free_writecombine(lcdc.fbdev->dev, MAX_PALETTE_SIZE, | ||
666 | lcdc.palette_virt, lcdc.palette_phys); | ||
667 | } | ||
668 | |||
669 | static int alloc_fbmem(struct omapfb_mem_region *region) | ||
670 | { | ||
671 | int bpp; | ||
672 | int frame_size; | ||
673 | struct lcd_panel *panel = lcdc.fbdev->panel; | ||
674 | |||
675 | bpp = panel->bpp; | ||
676 | if (bpp == 12) | ||
677 | bpp = 16; | ||
678 | frame_size = PAGE_ALIGN(panel->x_res * bpp / 8 * panel->y_res); | ||
679 | if (region->size > frame_size) | ||
680 | frame_size = region->size; | ||
681 | lcdc.vram_size = frame_size; | ||
682 | lcdc.vram_virt = dma_alloc_writecombine(lcdc.fbdev->dev, | ||
683 | lcdc.vram_size, &lcdc.vram_phys, GFP_KERNEL); | ||
684 | if (lcdc.vram_virt == NULL) { | ||
685 | dev_err(lcdc.fbdev->dev, "unable to allocate FB DMA memory\n"); | ||
686 | return -ENOMEM; | ||
687 | } | ||
688 | region->size = frame_size; | ||
689 | region->paddr = lcdc.vram_phys; | ||
690 | region->vaddr = lcdc.vram_virt; | ||
691 | region->alloc = 1; | ||
692 | |||
693 | memset(lcdc.vram_virt, 0, lcdc.vram_size); | ||
694 | |||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | static void free_fbmem(void) | ||
699 | { | ||
700 | dma_free_writecombine(lcdc.fbdev->dev, lcdc.vram_size, | ||
701 | lcdc.vram_virt, lcdc.vram_phys); | ||
702 | } | ||
703 | |||
704 | static int setup_fbmem(struct omapfb_mem_desc *req_md) | ||
705 | { | ||
706 | int r; | ||
707 | |||
708 | if (!req_md->region_cnt) { | ||
709 | dev_err(lcdc.fbdev->dev, "no memory regions defined\n"); | ||
710 | return -EINVAL; | ||
711 | } | ||
712 | |||
713 | if (req_md->region_cnt > 1) { | ||
714 | dev_err(lcdc.fbdev->dev, "only one plane is supported\n"); | ||
715 | req_md->region_cnt = 1; | ||
716 | } | ||
717 | |||
718 | if (req_md->region[0].paddr == 0) { | ||
719 | lcdc.fbmem_allocated = 1; | ||
720 | if ((r = alloc_fbmem(&req_md->region[0])) < 0) | ||
721 | return r; | ||
722 | return 0; | ||
723 | } | ||
724 | |||
725 | lcdc.vram_phys = req_md->region[0].paddr; | ||
726 | lcdc.vram_size = req_md->region[0].size; | ||
727 | |||
728 | if ((r = mmap_kern()) < 0) | ||
729 | return r; | ||
730 | |||
731 | dev_dbg(lcdc.fbdev->dev, "vram at %08x size %08lx mapped to 0x%p\n", | ||
732 | lcdc.vram_phys, lcdc.vram_size, lcdc.vram_virt); | ||
733 | |||
734 | return 0; | ||
735 | } | ||
736 | |||
737 | static void cleanup_fbmem(void) | ||
738 | { | ||
739 | if (lcdc.fbmem_allocated) | ||
740 | free_fbmem(); | ||
741 | else | ||
742 | unmap_kern(); | ||
743 | } | ||
744 | |||
745 | static int omap_lcdc_init(struct omapfb_device *fbdev, int ext_mode, | ||
746 | struct omapfb_mem_desc *req_vram) | ||
747 | { | ||
748 | int r; | ||
749 | u32 l; | ||
750 | int rate; | ||
751 | struct clk *tc_ck; | ||
752 | |||
753 | lcdc.irq_mask = 0; | ||
754 | |||
755 | lcdc.fbdev = fbdev; | ||
756 | lcdc.ext_mode = ext_mode; | ||
757 | |||
758 | l = 0; | ||
759 | omap_writel(l, OMAP_LCDC_CONTROL); | ||
760 | |||
761 | /* FIXME: | ||
762 | * According to errata some platforms have a clock rate limitiation | ||
763 | */ | ||
764 | lcdc.lcd_ck = clk_get(fbdev->dev, "lcd_ck"); | ||
765 | if (IS_ERR(lcdc.lcd_ck)) { | ||
766 | dev_err(fbdev->dev, "unable to access LCD clock\n"); | ||
767 | r = PTR_ERR(lcdc.lcd_ck); | ||
768 | goto fail0; | ||
769 | } | ||
770 | |||
771 | tc_ck = clk_get(fbdev->dev, "tc_ck"); | ||
772 | if (IS_ERR(tc_ck)) { | ||
773 | dev_err(fbdev->dev, "unable to access TC clock\n"); | ||
774 | r = PTR_ERR(tc_ck); | ||
775 | goto fail1; | ||
776 | } | ||
777 | |||
778 | rate = clk_get_rate(tc_ck); | ||
779 | clk_put(tc_ck); | ||
780 | |||
781 | if (machine_is_ams_delta()) | ||
782 | rate /= 4; | ||
783 | if (machine_is_omap_h3()) | ||
784 | rate /= 3; | ||
785 | r = clk_set_rate(lcdc.lcd_ck, rate); | ||
786 | if (r) { | ||
787 | dev_err(fbdev->dev, "failed to adjust LCD rate\n"); | ||
788 | goto fail1; | ||
789 | } | ||
790 | clk_enable(lcdc.lcd_ck); | ||
791 | |||
792 | r = request_irq(OMAP_LCDC_IRQ, lcdc_irq_handler, 0, MODULE_NAME, fbdev); | ||
793 | if (r) { | ||
794 | dev_err(fbdev->dev, "unable to get IRQ\n"); | ||
795 | goto fail2; | ||
796 | } | ||
797 | |||
798 | r = omap_request_lcd_dma(lcdc_dma_handler, NULL); | ||
799 | if (r) { | ||
800 | dev_err(fbdev->dev, "unable to get LCD DMA\n"); | ||
801 | goto fail3; | ||
802 | } | ||
803 | |||
804 | omap_set_lcd_dma_single_transfer(ext_mode); | ||
805 | omap_set_lcd_dma_ext_controller(ext_mode); | ||
806 | |||
807 | if (!ext_mode) | ||
808 | if ((r = alloc_palette_ram()) < 0) | ||
809 | goto fail4; | ||
810 | |||
811 | if ((r = setup_fbmem(req_vram)) < 0) | ||
812 | goto fail5; | ||
813 | |||
814 | pr_info("omapfb: LCDC initialized\n"); | ||
815 | |||
816 | return 0; | ||
817 | fail5: | ||
818 | if (!ext_mode) | ||
819 | free_palette_ram(); | ||
820 | fail4: | ||
821 | omap_free_lcd_dma(); | ||
822 | fail3: | ||
823 | free_irq(OMAP_LCDC_IRQ, lcdc.fbdev); | ||
824 | fail2: | ||
825 | clk_disable(lcdc.lcd_ck); | ||
826 | fail1: | ||
827 | clk_put(lcdc.lcd_ck); | ||
828 | fail0: | ||
829 | return r; | ||
830 | } | ||
831 | |||
832 | static void omap_lcdc_cleanup(void) | ||
833 | { | ||
834 | if (!lcdc.ext_mode) | ||
835 | free_palette_ram(); | ||
836 | cleanup_fbmem(); | ||
837 | omap_free_lcd_dma(); | ||
838 | free_irq(OMAP_LCDC_IRQ, lcdc.fbdev); | ||
839 | clk_disable(lcdc.lcd_ck); | ||
840 | clk_put(lcdc.lcd_ck); | ||
841 | } | ||
842 | |||
843 | const struct lcd_ctrl omap1_int_ctrl = { | ||
844 | .name = "internal", | ||
845 | .init = omap_lcdc_init, | ||
846 | .cleanup = omap_lcdc_cleanup, | ||
847 | .get_caps = omap_lcdc_get_caps, | ||
848 | .set_update_mode = omap_lcdc_set_update_mode, | ||
849 | .get_update_mode = omap_lcdc_get_update_mode, | ||
850 | .update_window = NULL, | ||
851 | .suspend = omap_lcdc_suspend, | ||
852 | .resume = omap_lcdc_resume, | ||
853 | .setup_plane = omap_lcdc_setup_plane, | ||
854 | .enable_plane = omap_lcdc_enable_plane, | ||
855 | .setcolreg = omap_lcdc_setcolreg, | ||
856 | }; | ||
diff --git a/drivers/video/omap/lcdc.h b/drivers/video/omap/lcdc.h deleted file mode 100644 index 845222270db3..000000000000 --- a/drivers/video/omap/lcdc.h +++ /dev/null | |||
@@ -1,9 +0,0 @@ | |||
1 | #ifndef LCDC_H | ||
2 | #define LCDC_H | ||
3 | |||
4 | int omap_lcdc_set_dma_callback(void (*callback)(void *data), void *data); | ||
5 | void omap_lcdc_free_dma_callback(void); | ||
6 | |||
7 | extern const struct lcd_ctrl omap1_int_ctrl; | ||
8 | |||
9 | #endif | ||
diff --git a/drivers/video/omap/omapfb.h b/drivers/video/omap/omapfb.h deleted file mode 100644 index 2921d20e4fba..000000000000 --- a/drivers/video/omap/omapfb.h +++ /dev/null | |||
@@ -1,246 +0,0 @@ | |||
1 | /* | ||
2 | * File: drivers/video/omap/omapfb.h | ||
3 | * | ||
4 | * Framebuffer driver for TI OMAP boards | ||
5 | * | ||
6 | * Copyright (C) 2004 Nokia Corporation | ||
7 | * Author: Imre Deak <imre.deak@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 | |||
24 | #ifndef __OMAPFB_H | ||
25 | #define __OMAPFB_H | ||
26 | |||
27 | #include <linux/fb.h> | ||
28 | #include <linux/mutex.h> | ||
29 | #include <linux/omapfb.h> | ||
30 | |||
31 | #define OMAPFB_EVENT_READY 1 | ||
32 | #define OMAPFB_EVENT_DISABLED 2 | ||
33 | |||
34 | #define OMAP_LCDC_INV_VSYNC 0x0001 | ||
35 | #define OMAP_LCDC_INV_HSYNC 0x0002 | ||
36 | #define OMAP_LCDC_INV_PIX_CLOCK 0x0004 | ||
37 | #define OMAP_LCDC_INV_OUTPUT_EN 0x0008 | ||
38 | #define OMAP_LCDC_HSVS_RISING_EDGE 0x0010 | ||
39 | #define OMAP_LCDC_HSVS_OPPOSITE 0x0020 | ||
40 | |||
41 | #define OMAP_LCDC_SIGNAL_MASK 0x003f | ||
42 | |||
43 | #define OMAP_LCDC_PANEL_TFT 0x0100 | ||
44 | |||
45 | #define OMAPFB_PLANE_XRES_MIN 8 | ||
46 | #define OMAPFB_PLANE_YRES_MIN 8 | ||
47 | |||
48 | struct omapfb_device; | ||
49 | |||
50 | #define OMAPFB_PLANE_NUM 1 | ||
51 | |||
52 | struct omapfb_mem_region { | ||
53 | u32 paddr; | ||
54 | void __iomem *vaddr; | ||
55 | unsigned long size; | ||
56 | u8 type; /* OMAPFB_PLANE_MEM_* */ | ||
57 | enum omapfb_color_format format;/* OMAPFB_COLOR_* */ | ||
58 | unsigned format_used:1; /* Must be set when format is set. | ||
59 | * Needed b/c of the badly chosen 0 | ||
60 | * base for OMAPFB_COLOR_* values | ||
61 | */ | ||
62 | unsigned alloc:1; /* allocated by the driver */ | ||
63 | unsigned map:1; /* kernel mapped by the driver */ | ||
64 | }; | ||
65 | |||
66 | struct omapfb_mem_desc { | ||
67 | int region_cnt; | ||
68 | struct omapfb_mem_region region[OMAPFB_PLANE_NUM]; | ||
69 | }; | ||
70 | |||
71 | struct lcd_panel { | ||
72 | const char *name; | ||
73 | int config; /* TFT/STN, signal inversion */ | ||
74 | int bpp; /* Pixel format in fb mem */ | ||
75 | int data_lines; /* Lines on LCD HW interface */ | ||
76 | |||
77 | int x_res, y_res; | ||
78 | int pixel_clock; /* In kHz */ | ||
79 | int hsw; /* Horizontal synchronization | ||
80 | pulse width */ | ||
81 | int hfp; /* Horizontal front porch */ | ||
82 | int hbp; /* Horizontal back porch */ | ||
83 | int vsw; /* Vertical synchronization | ||
84 | pulse width */ | ||
85 | int vfp; /* Vertical front porch */ | ||
86 | int vbp; /* Vertical back porch */ | ||
87 | int acb; /* ac-bias pin frequency */ | ||
88 | int pcd; /* pixel clock divider. | ||
89 | Obsolete use pixel_clock instead */ | ||
90 | |||
91 | int (*init) (struct lcd_panel *panel, | ||
92 | struct omapfb_device *fbdev); | ||
93 | void (*cleanup) (struct lcd_panel *panel); | ||
94 | int (*enable) (struct lcd_panel *panel); | ||
95 | void (*disable) (struct lcd_panel *panel); | ||
96 | unsigned long (*get_caps) (struct lcd_panel *panel); | ||
97 | int (*set_bklight_level)(struct lcd_panel *panel, | ||
98 | unsigned int level); | ||
99 | unsigned int (*get_bklight_level)(struct lcd_panel *panel); | ||
100 | unsigned int (*get_bklight_max) (struct lcd_panel *panel); | ||
101 | int (*run_test) (struct lcd_panel *panel, int test_num); | ||
102 | }; | ||
103 | |||
104 | struct extif_timings { | ||
105 | int cs_on_time; | ||
106 | int cs_off_time; | ||
107 | int we_on_time; | ||
108 | int we_off_time; | ||
109 | int re_on_time; | ||
110 | int re_off_time; | ||
111 | int we_cycle_time; | ||
112 | int re_cycle_time; | ||
113 | int cs_pulse_width; | ||
114 | int access_time; | ||
115 | |||
116 | int clk_div; | ||
117 | |||
118 | u32 tim[5]; /* set by extif->convert_timings */ | ||
119 | |||
120 | int converted; | ||
121 | }; | ||
122 | |||
123 | struct lcd_ctrl_extif { | ||
124 | int (*init) (struct omapfb_device *fbdev); | ||
125 | void (*cleanup) (void); | ||
126 | void (*get_clk_info) (u32 *clk_period, u32 *max_clk_div); | ||
127 | unsigned long (*get_max_tx_rate)(void); | ||
128 | int (*convert_timings) (struct extif_timings *timings); | ||
129 | void (*set_timings) (const struct extif_timings *timings); | ||
130 | void (*set_bits_per_cycle)(int bpc); | ||
131 | void (*write_command) (const void *buf, unsigned int len); | ||
132 | void (*read_data) (void *buf, unsigned int len); | ||
133 | void (*write_data) (const void *buf, unsigned int len); | ||
134 | void (*transfer_area) (int width, int height, | ||
135 | void (callback)(void *data), void *data); | ||
136 | int (*setup_tearsync) (unsigned pin_cnt, | ||
137 | unsigned hs_pulse_time, unsigned vs_pulse_time, | ||
138 | int hs_pol_inv, int vs_pol_inv, int div); | ||
139 | int (*enable_tearsync) (int enable, unsigned line); | ||
140 | |||
141 | unsigned long max_transmit_size; | ||
142 | }; | ||
143 | |||
144 | struct omapfb_notifier_block { | ||
145 | struct notifier_block nb; | ||
146 | void *data; | ||
147 | int plane_idx; | ||
148 | }; | ||
149 | |||
150 | typedef int (*omapfb_notifier_callback_t)(struct notifier_block *, | ||
151 | unsigned long event, | ||
152 | void *fbi); | ||
153 | |||
154 | struct lcd_ctrl { | ||
155 | const char *name; | ||
156 | void *data; | ||
157 | |||
158 | int (*init) (struct omapfb_device *fbdev, | ||
159 | int ext_mode, | ||
160 | struct omapfb_mem_desc *req_md); | ||
161 | void (*cleanup) (void); | ||
162 | void (*bind_client) (struct omapfb_notifier_block *nb); | ||
163 | void (*get_caps) (int plane, struct omapfb_caps *caps); | ||
164 | int (*set_update_mode)(enum omapfb_update_mode mode); | ||
165 | enum omapfb_update_mode (*get_update_mode)(void); | ||
166 | int (*setup_plane) (int plane, int channel_out, | ||
167 | unsigned long offset, | ||
168 | int screen_width, | ||
169 | int pos_x, int pos_y, int width, | ||
170 | int height, int color_mode); | ||
171 | int (*set_rotate) (int angle); | ||
172 | int (*setup_mem) (int plane, size_t size, | ||
173 | int mem_type, unsigned long *paddr); | ||
174 | int (*mmap) (struct fb_info *info, | ||
175 | struct vm_area_struct *vma); | ||
176 | int (*set_scale) (int plane, | ||
177 | int orig_width, int orig_height, | ||
178 | int out_width, int out_height); | ||
179 | int (*enable_plane) (int plane, int enable); | ||
180 | int (*update_window) (struct fb_info *fbi, | ||
181 | struct omapfb_update_window *win, | ||
182 | void (*callback)(void *), | ||
183 | void *callback_data); | ||
184 | void (*sync) (void); | ||
185 | void (*suspend) (void); | ||
186 | void (*resume) (void); | ||
187 | int (*run_test) (int test_num); | ||
188 | int (*setcolreg) (u_int regno, u16 red, u16 green, | ||
189 | u16 blue, u16 transp, | ||
190 | int update_hw_mem); | ||
191 | int (*set_color_key) (struct omapfb_color_key *ck); | ||
192 | int (*get_color_key) (struct omapfb_color_key *ck); | ||
193 | }; | ||
194 | |||
195 | enum omapfb_state { | ||
196 | OMAPFB_DISABLED = 0, | ||
197 | OMAPFB_SUSPENDED = 99, | ||
198 | OMAPFB_ACTIVE = 100 | ||
199 | }; | ||
200 | |||
201 | struct omapfb_plane_struct { | ||
202 | int idx; | ||
203 | struct omapfb_plane_info info; | ||
204 | enum omapfb_color_format color_mode; | ||
205 | struct omapfb_device *fbdev; | ||
206 | }; | ||
207 | |||
208 | struct omapfb_device { | ||
209 | int state; | ||
210 | int ext_lcdc; /* Using external | ||
211 | LCD controller */ | ||
212 | struct mutex rqueue_mutex; | ||
213 | |||
214 | int palette_size; | ||
215 | u32 pseudo_palette[17]; | ||
216 | |||
217 | struct lcd_panel *panel; /* LCD panel */ | ||
218 | const struct lcd_ctrl *ctrl; /* LCD controller */ | ||
219 | const struct lcd_ctrl *int_ctrl; /* internal LCD ctrl */ | ||
220 | struct lcd_ctrl_extif *ext_if; /* LCD ctrl external | ||
221 | interface */ | ||
222 | struct device *dev; | ||
223 | struct fb_var_screeninfo new_var; /* for mode changes */ | ||
224 | |||
225 | struct omapfb_mem_desc mem_desc; | ||
226 | struct fb_info *fb_info[OMAPFB_PLANE_NUM]; | ||
227 | |||
228 | struct platform_device *dssdev; /* dummy dev for clocks */ | ||
229 | }; | ||
230 | |||
231 | extern struct lcd_ctrl omap1_lcd_ctrl; | ||
232 | |||
233 | extern void omapfb_register_panel(struct lcd_panel *panel); | ||
234 | extern void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval); | ||
235 | extern void omapfb_notify_clients(struct omapfb_device *fbdev, | ||
236 | unsigned long event); | ||
237 | extern int omapfb_register_client(struct omapfb_notifier_block *nb, | ||
238 | omapfb_notifier_callback_t callback, | ||
239 | void *callback_data); | ||
240 | extern int omapfb_unregister_client(struct omapfb_notifier_block *nb); | ||
241 | extern int omapfb_update_window_async(struct fb_info *fbi, | ||
242 | struct omapfb_update_window *win, | ||
243 | void (*callback)(void *), | ||
244 | void *callback_data); | ||
245 | |||
246 | #endif /* __OMAPFB_H */ | ||
diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c deleted file mode 100644 index e4fc6d9b5371..000000000000 --- a/drivers/video/omap/omapfb_main.c +++ /dev/null | |||
@@ -1,1971 +0,0 @@ | |||
1 | /* | ||
2 | * Framebuffer driver for TI OMAP boards | ||
3 | * | ||
4 | * Copyright (C) 2004 Nokia Corporation | ||
5 | * Author: Imre Deak <imre.deak@nokia.com> | ||
6 | * | ||
7 | * Acknowledgements: | ||
8 | * Alex McMains <aam@ridgerun.com> - Original driver | ||
9 | * Juha Yrjola <juha.yrjola@nokia.com> - Original driver and improvements | ||
10 | * Dirk Behme <dirk.behme@de.bosch.com> - changes for 2.6 kernel API | ||
11 | * Texas Instruments - H3 support | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License as published by the | ||
15 | * Free Software Foundation; either version 2 of the License, or (at your | ||
16 | * option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, but | ||
19 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
21 | * General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License along | ||
24 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
25 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
26 | */ | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/mm.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/uaccess.h> | ||
31 | #include <linux/module.h> | ||
32 | |||
33 | #include <linux/omap-dma.h> | ||
34 | |||
35 | #include <mach/hardware.h> | ||
36 | |||
37 | #include "omapfb.h" | ||
38 | #include "lcdc.h" | ||
39 | |||
40 | #define MODULE_NAME "omapfb" | ||
41 | |||
42 | static unsigned int def_accel; | ||
43 | static unsigned long def_vram[OMAPFB_PLANE_NUM]; | ||
44 | static unsigned int def_vram_cnt; | ||
45 | static unsigned long def_vxres; | ||
46 | static unsigned long def_vyres; | ||
47 | static unsigned int def_rotate; | ||
48 | static unsigned int def_mirror; | ||
49 | |||
50 | #ifdef CONFIG_FB_OMAP_MANUAL_UPDATE | ||
51 | static bool manual_update = 1; | ||
52 | #else | ||
53 | static bool manual_update; | ||
54 | #endif | ||
55 | |||
56 | static struct platform_device *fbdev_pdev; | ||
57 | static struct lcd_panel *fbdev_panel; | ||
58 | static struct omapfb_device *omapfb_dev; | ||
59 | |||
60 | struct caps_table_struct { | ||
61 | unsigned long flag; | ||
62 | const char *name; | ||
63 | }; | ||
64 | |||
65 | static struct caps_table_struct ctrl_caps[] = { | ||
66 | { OMAPFB_CAPS_MANUAL_UPDATE, "manual update" }, | ||
67 | { OMAPFB_CAPS_TEARSYNC, "tearing synchronization" }, | ||
68 | { OMAPFB_CAPS_PLANE_RELOCATE_MEM, "relocate plane memory" }, | ||
69 | { OMAPFB_CAPS_PLANE_SCALE, "scale plane" }, | ||
70 | { OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE, "pixel double window" }, | ||
71 | { OMAPFB_CAPS_WINDOW_SCALE, "scale window" }, | ||
72 | { OMAPFB_CAPS_WINDOW_OVERLAY, "overlay window" }, | ||
73 | { OMAPFB_CAPS_WINDOW_ROTATE, "rotate window" }, | ||
74 | { OMAPFB_CAPS_SET_BACKLIGHT, "backlight setting" }, | ||
75 | }; | ||
76 | |||
77 | static struct caps_table_struct color_caps[] = { | ||
78 | { 1 << OMAPFB_COLOR_RGB565, "RGB565", }, | ||
79 | { 1 << OMAPFB_COLOR_YUV422, "YUV422", }, | ||
80 | { 1 << OMAPFB_COLOR_YUV420, "YUV420", }, | ||
81 | { 1 << OMAPFB_COLOR_CLUT_8BPP, "CLUT8", }, | ||
82 | { 1 << OMAPFB_COLOR_CLUT_4BPP, "CLUT4", }, | ||
83 | { 1 << OMAPFB_COLOR_CLUT_2BPP, "CLUT2", }, | ||
84 | { 1 << OMAPFB_COLOR_CLUT_1BPP, "CLUT1", }, | ||
85 | { 1 << OMAPFB_COLOR_RGB444, "RGB444", }, | ||
86 | { 1 << OMAPFB_COLOR_YUY422, "YUY422", }, | ||
87 | }; | ||
88 | |||
89 | static void omapdss_release(struct device *dev) | ||
90 | { | ||
91 | } | ||
92 | |||
93 | /* dummy device for clocks */ | ||
94 | static struct platform_device omapdss_device = { | ||
95 | .name = "omapdss_dss", | ||
96 | .id = -1, | ||
97 | .dev = { | ||
98 | .release = omapdss_release, | ||
99 | }, | ||
100 | }; | ||
101 | |||
102 | /* | ||
103 | * --------------------------------------------------------------------------- | ||
104 | * LCD panel | ||
105 | * --------------------------------------------------------------------------- | ||
106 | */ | ||
107 | extern struct lcd_ctrl hwa742_ctrl; | ||
108 | |||
109 | static const struct lcd_ctrl *ctrls[] = { | ||
110 | &omap1_int_ctrl, | ||
111 | |||
112 | #ifdef CONFIG_FB_OMAP_LCDC_HWA742 | ||
113 | &hwa742_ctrl, | ||
114 | #endif | ||
115 | }; | ||
116 | |||
117 | #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL | ||
118 | extern struct lcd_ctrl_extif omap1_ext_if; | ||
119 | #endif | ||
120 | |||
121 | static void omapfb_rqueue_lock(struct omapfb_device *fbdev) | ||
122 | { | ||
123 | mutex_lock(&fbdev->rqueue_mutex); | ||
124 | } | ||
125 | |||
126 | static void omapfb_rqueue_unlock(struct omapfb_device *fbdev) | ||
127 | { | ||
128 | mutex_unlock(&fbdev->rqueue_mutex); | ||
129 | } | ||
130 | |||
131 | /* | ||
132 | * --------------------------------------------------------------------------- | ||
133 | * LCD controller and LCD DMA | ||
134 | * --------------------------------------------------------------------------- | ||
135 | */ | ||
136 | /* | ||
137 | * Allocate resources needed for LCD controller and LCD DMA operations. Video | ||
138 | * memory is allocated from system memory according to the virtual display | ||
139 | * size, except if a bigger memory size is specified explicitly as a kernel | ||
140 | * parameter. | ||
141 | */ | ||
142 | static int ctrl_init(struct omapfb_device *fbdev) | ||
143 | { | ||
144 | int r; | ||
145 | int i; | ||
146 | |||
147 | /* kernel/module vram parameters override boot tags/board config */ | ||
148 | if (def_vram_cnt) { | ||
149 | for (i = 0; i < def_vram_cnt; i++) | ||
150 | fbdev->mem_desc.region[i].size = | ||
151 | PAGE_ALIGN(def_vram[i]); | ||
152 | fbdev->mem_desc.region_cnt = i; | ||
153 | } | ||
154 | |||
155 | if (!fbdev->mem_desc.region_cnt) { | ||
156 | struct lcd_panel *panel = fbdev->panel; | ||
157 | int def_size; | ||
158 | int bpp = panel->bpp; | ||
159 | |||
160 | /* 12 bpp is packed in 16 bits */ | ||
161 | if (bpp == 12) | ||
162 | bpp = 16; | ||
163 | def_size = def_vxres * def_vyres * bpp / 8; | ||
164 | fbdev->mem_desc.region_cnt = 1; | ||
165 | fbdev->mem_desc.region[0].size = PAGE_ALIGN(def_size); | ||
166 | } | ||
167 | r = fbdev->ctrl->init(fbdev, 0, &fbdev->mem_desc); | ||
168 | if (r < 0) { | ||
169 | dev_err(fbdev->dev, "controller initialization failed (%d)\n", | ||
170 | r); | ||
171 | return r; | ||
172 | } | ||
173 | |||
174 | #ifdef DEBUG | ||
175 | for (i = 0; i < fbdev->mem_desc.region_cnt; i++) { | ||
176 | dev_dbg(fbdev->dev, "region%d phys %08x virt %p size=%lu\n", | ||
177 | i, | ||
178 | fbdev->mem_desc.region[i].paddr, | ||
179 | fbdev->mem_desc.region[i].vaddr, | ||
180 | fbdev->mem_desc.region[i].size); | ||
181 | } | ||
182 | #endif | ||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | static void ctrl_cleanup(struct omapfb_device *fbdev) | ||
187 | { | ||
188 | fbdev->ctrl->cleanup(); | ||
189 | } | ||
190 | |||
191 | /* Must be called with fbdev->rqueue_mutex held. */ | ||
192 | static int ctrl_change_mode(struct fb_info *fbi) | ||
193 | { | ||
194 | int r; | ||
195 | unsigned long offset; | ||
196 | struct omapfb_plane_struct *plane = fbi->par; | ||
197 | struct omapfb_device *fbdev = plane->fbdev; | ||
198 | struct fb_var_screeninfo *var = &fbi->var; | ||
199 | |||
200 | offset = var->yoffset * fbi->fix.line_length + | ||
201 | var->xoffset * var->bits_per_pixel / 8; | ||
202 | |||
203 | if (fbdev->ctrl->sync) | ||
204 | fbdev->ctrl->sync(); | ||
205 | r = fbdev->ctrl->setup_plane(plane->idx, plane->info.channel_out, | ||
206 | offset, var->xres_virtual, | ||
207 | plane->info.pos_x, plane->info.pos_y, | ||
208 | var->xres, var->yres, plane->color_mode); | ||
209 | if (r < 0) | ||
210 | return r; | ||
211 | |||
212 | if (fbdev->ctrl->set_rotate != NULL) { | ||
213 | r = fbdev->ctrl->set_rotate(var->rotate); | ||
214 | if (r < 0) | ||
215 | return r; | ||
216 | } | ||
217 | |||
218 | if (fbdev->ctrl->set_scale != NULL) | ||
219 | r = fbdev->ctrl->set_scale(plane->idx, | ||
220 | var->xres, var->yres, | ||
221 | plane->info.out_width, | ||
222 | plane->info.out_height); | ||
223 | |||
224 | return r; | ||
225 | } | ||
226 | |||
227 | /* | ||
228 | * --------------------------------------------------------------------------- | ||
229 | * fbdev framework callbacks and the ioctl interface | ||
230 | * --------------------------------------------------------------------------- | ||
231 | */ | ||
232 | /* Called each time the omapfb device is opened */ | ||
233 | static int omapfb_open(struct fb_info *info, int user) | ||
234 | { | ||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | static void omapfb_sync(struct fb_info *info); | ||
239 | |||
240 | /* Called when the omapfb device is closed. We make sure that any pending | ||
241 | * gfx DMA operations are ended, before we return. */ | ||
242 | static int omapfb_release(struct fb_info *info, int user) | ||
243 | { | ||
244 | omapfb_sync(info); | ||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | /* Store a single color palette entry into a pseudo palette or the hardware | ||
249 | * palette if one is available. For now we support only 16bpp and thus store | ||
250 | * the entry only to the pseudo palette. | ||
251 | */ | ||
252 | static int _setcolreg(struct fb_info *info, u_int regno, u_int red, u_int green, | ||
253 | u_int blue, u_int transp, int update_hw_pal) | ||
254 | { | ||
255 | struct omapfb_plane_struct *plane = info->par; | ||
256 | struct omapfb_device *fbdev = plane->fbdev; | ||
257 | struct fb_var_screeninfo *var = &info->var; | ||
258 | int r = 0; | ||
259 | |||
260 | switch (plane->color_mode) { | ||
261 | case OMAPFB_COLOR_YUV422: | ||
262 | case OMAPFB_COLOR_YUV420: | ||
263 | case OMAPFB_COLOR_YUY422: | ||
264 | r = -EINVAL; | ||
265 | break; | ||
266 | case OMAPFB_COLOR_CLUT_8BPP: | ||
267 | case OMAPFB_COLOR_CLUT_4BPP: | ||
268 | case OMAPFB_COLOR_CLUT_2BPP: | ||
269 | case OMAPFB_COLOR_CLUT_1BPP: | ||
270 | if (fbdev->ctrl->setcolreg) | ||
271 | r = fbdev->ctrl->setcolreg(regno, red, green, blue, | ||
272 | transp, update_hw_pal); | ||
273 | /* Fallthrough */ | ||
274 | case OMAPFB_COLOR_RGB565: | ||
275 | case OMAPFB_COLOR_RGB444: | ||
276 | if (r != 0) | ||
277 | break; | ||
278 | |||
279 | if (regno < 0) { | ||
280 | r = -EINVAL; | ||
281 | break; | ||
282 | } | ||
283 | |||
284 | if (regno < 16) { | ||
285 | u16 pal; | ||
286 | pal = ((red >> (16 - var->red.length)) << | ||
287 | var->red.offset) | | ||
288 | ((green >> (16 - var->green.length)) << | ||
289 | var->green.offset) | | ||
290 | (blue >> (16 - var->blue.length)); | ||
291 | ((u32 *)(info->pseudo_palette))[regno] = pal; | ||
292 | } | ||
293 | break; | ||
294 | default: | ||
295 | BUG(); | ||
296 | } | ||
297 | return r; | ||
298 | } | ||
299 | |||
300 | static int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, | ||
301 | u_int transp, struct fb_info *info) | ||
302 | { | ||
303 | return _setcolreg(info, regno, red, green, blue, transp, 1); | ||
304 | } | ||
305 | |||
306 | static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info) | ||
307 | { | ||
308 | int count, index, r; | ||
309 | u16 *red, *green, *blue, *transp; | ||
310 | u16 trans = 0xffff; | ||
311 | |||
312 | red = cmap->red; | ||
313 | green = cmap->green; | ||
314 | blue = cmap->blue; | ||
315 | transp = cmap->transp; | ||
316 | index = cmap->start; | ||
317 | |||
318 | for (count = 0; count < cmap->len; count++) { | ||
319 | if (transp) | ||
320 | trans = *transp++; | ||
321 | r = _setcolreg(info, index++, *red++, *green++, *blue++, trans, | ||
322 | count == cmap->len - 1); | ||
323 | if (r != 0) | ||
324 | return r; | ||
325 | } | ||
326 | |||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | static int omapfb_update_full_screen(struct fb_info *fbi); | ||
331 | |||
332 | static int omapfb_blank(int blank, struct fb_info *fbi) | ||
333 | { | ||
334 | struct omapfb_plane_struct *plane = fbi->par; | ||
335 | struct omapfb_device *fbdev = plane->fbdev; | ||
336 | int do_update = 0; | ||
337 | int r = 0; | ||
338 | |||
339 | omapfb_rqueue_lock(fbdev); | ||
340 | switch (blank) { | ||
341 | case FB_BLANK_UNBLANK: | ||
342 | if (fbdev->state == OMAPFB_SUSPENDED) { | ||
343 | if (fbdev->ctrl->resume) | ||
344 | fbdev->ctrl->resume(); | ||
345 | fbdev->panel->enable(fbdev->panel); | ||
346 | fbdev->state = OMAPFB_ACTIVE; | ||
347 | if (fbdev->ctrl->get_update_mode() == | ||
348 | OMAPFB_MANUAL_UPDATE) | ||
349 | do_update = 1; | ||
350 | } | ||
351 | break; | ||
352 | case FB_BLANK_POWERDOWN: | ||
353 | if (fbdev->state == OMAPFB_ACTIVE) { | ||
354 | fbdev->panel->disable(fbdev->panel); | ||
355 | if (fbdev->ctrl->suspend) | ||
356 | fbdev->ctrl->suspend(); | ||
357 | fbdev->state = OMAPFB_SUSPENDED; | ||
358 | } | ||
359 | break; | ||
360 | default: | ||
361 | r = -EINVAL; | ||
362 | } | ||
363 | omapfb_rqueue_unlock(fbdev); | ||
364 | |||
365 | if (r == 0 && do_update) | ||
366 | r = omapfb_update_full_screen(fbi); | ||
367 | |||
368 | return r; | ||
369 | } | ||
370 | |||
371 | static void omapfb_sync(struct fb_info *fbi) | ||
372 | { | ||
373 | struct omapfb_plane_struct *plane = fbi->par; | ||
374 | struct omapfb_device *fbdev = plane->fbdev; | ||
375 | |||
376 | omapfb_rqueue_lock(fbdev); | ||
377 | if (fbdev->ctrl->sync) | ||
378 | fbdev->ctrl->sync(); | ||
379 | omapfb_rqueue_unlock(fbdev); | ||
380 | } | ||
381 | |||
382 | /* | ||
383 | * Set fb_info.fix fields and also updates fbdev. | ||
384 | * When calling this fb_info.var must be set up already. | ||
385 | */ | ||
386 | static void set_fb_fix(struct fb_info *fbi, int from_init) | ||
387 | { | ||
388 | struct fb_fix_screeninfo *fix = &fbi->fix; | ||
389 | struct fb_var_screeninfo *var = &fbi->var; | ||
390 | struct omapfb_plane_struct *plane = fbi->par; | ||
391 | struct omapfb_mem_region *rg; | ||
392 | int bpp; | ||
393 | |||
394 | rg = &plane->fbdev->mem_desc.region[plane->idx]; | ||
395 | fbi->screen_base = rg->vaddr; | ||
396 | |||
397 | if (!from_init) { | ||
398 | mutex_lock(&fbi->mm_lock); | ||
399 | fix->smem_start = rg->paddr; | ||
400 | fix->smem_len = rg->size; | ||
401 | mutex_unlock(&fbi->mm_lock); | ||
402 | } else { | ||
403 | fix->smem_start = rg->paddr; | ||
404 | fix->smem_len = rg->size; | ||
405 | } | ||
406 | |||
407 | fix->type = FB_TYPE_PACKED_PIXELS; | ||
408 | bpp = var->bits_per_pixel; | ||
409 | if (var->nonstd) | ||
410 | fix->visual = FB_VISUAL_PSEUDOCOLOR; | ||
411 | else switch (var->bits_per_pixel) { | ||
412 | case 16: | ||
413 | case 12: | ||
414 | fix->visual = FB_VISUAL_TRUECOLOR; | ||
415 | /* 12bpp is stored in 16 bits */ | ||
416 | bpp = 16; | ||
417 | break; | ||
418 | case 1: | ||
419 | case 2: | ||
420 | case 4: | ||
421 | case 8: | ||
422 | fix->visual = FB_VISUAL_PSEUDOCOLOR; | ||
423 | break; | ||
424 | } | ||
425 | fix->accel = FB_ACCEL_OMAP1610; | ||
426 | fix->line_length = var->xres_virtual * bpp / 8; | ||
427 | } | ||
428 | |||
429 | static int set_color_mode(struct omapfb_plane_struct *plane, | ||
430 | struct fb_var_screeninfo *var) | ||
431 | { | ||
432 | switch (var->nonstd) { | ||
433 | case 0: | ||
434 | break; | ||
435 | case OMAPFB_COLOR_YUV422: | ||
436 | var->bits_per_pixel = 16; | ||
437 | plane->color_mode = var->nonstd; | ||
438 | return 0; | ||
439 | case OMAPFB_COLOR_YUV420: | ||
440 | var->bits_per_pixel = 12; | ||
441 | plane->color_mode = var->nonstd; | ||
442 | return 0; | ||
443 | case OMAPFB_COLOR_YUY422: | ||
444 | var->bits_per_pixel = 16; | ||
445 | plane->color_mode = var->nonstd; | ||
446 | return 0; | ||
447 | default: | ||
448 | return -EINVAL; | ||
449 | } | ||
450 | |||
451 | switch (var->bits_per_pixel) { | ||
452 | case 1: | ||
453 | plane->color_mode = OMAPFB_COLOR_CLUT_1BPP; | ||
454 | return 0; | ||
455 | case 2: | ||
456 | plane->color_mode = OMAPFB_COLOR_CLUT_2BPP; | ||
457 | return 0; | ||
458 | case 4: | ||
459 | plane->color_mode = OMAPFB_COLOR_CLUT_4BPP; | ||
460 | return 0; | ||
461 | case 8: | ||
462 | plane->color_mode = OMAPFB_COLOR_CLUT_8BPP; | ||
463 | return 0; | ||
464 | case 12: | ||
465 | var->bits_per_pixel = 16; | ||
466 | case 16: | ||
467 | if (plane->fbdev->panel->bpp == 12) | ||
468 | plane->color_mode = OMAPFB_COLOR_RGB444; | ||
469 | else | ||
470 | plane->color_mode = OMAPFB_COLOR_RGB565; | ||
471 | return 0; | ||
472 | default: | ||
473 | return -EINVAL; | ||
474 | } | ||
475 | } | ||
476 | |||
477 | /* | ||
478 | * Check the values in var against our capabilities and in case of out of | ||
479 | * bound values try to adjust them. | ||
480 | */ | ||
481 | static int set_fb_var(struct fb_info *fbi, | ||
482 | struct fb_var_screeninfo *var) | ||
483 | { | ||
484 | int bpp; | ||
485 | unsigned long max_frame_size; | ||
486 | unsigned long line_size; | ||
487 | int xres_min, xres_max; | ||
488 | int yres_min, yres_max; | ||
489 | struct omapfb_plane_struct *plane = fbi->par; | ||
490 | struct omapfb_device *fbdev = plane->fbdev; | ||
491 | struct lcd_panel *panel = fbdev->panel; | ||
492 | |||
493 | if (set_color_mode(plane, var) < 0) | ||
494 | return -EINVAL; | ||
495 | |||
496 | bpp = var->bits_per_pixel; | ||
497 | if (plane->color_mode == OMAPFB_COLOR_RGB444) | ||
498 | bpp = 16; | ||
499 | |||
500 | switch (var->rotate) { | ||
501 | case 0: | ||
502 | case 180: | ||
503 | xres_min = OMAPFB_PLANE_XRES_MIN; | ||
504 | xres_max = panel->x_res; | ||
505 | yres_min = OMAPFB_PLANE_YRES_MIN; | ||
506 | yres_max = panel->y_res; | ||
507 | if (cpu_is_omap15xx()) { | ||
508 | var->xres = panel->x_res; | ||
509 | var->yres = panel->y_res; | ||
510 | } | ||
511 | break; | ||
512 | case 90: | ||
513 | case 270: | ||
514 | xres_min = OMAPFB_PLANE_YRES_MIN; | ||
515 | xres_max = panel->y_res; | ||
516 | yres_min = OMAPFB_PLANE_XRES_MIN; | ||
517 | yres_max = panel->x_res; | ||
518 | if (cpu_is_omap15xx()) { | ||
519 | var->xres = panel->y_res; | ||
520 | var->yres = panel->x_res; | ||
521 | } | ||
522 | break; | ||
523 | default: | ||
524 | return -EINVAL; | ||
525 | } | ||
526 | |||
527 | if (var->xres < xres_min) | ||
528 | var->xres = xres_min; | ||
529 | if (var->yres < yres_min) | ||
530 | var->yres = yres_min; | ||
531 | if (var->xres > xres_max) | ||
532 | var->xres = xres_max; | ||
533 | if (var->yres > yres_max) | ||
534 | var->yres = yres_max; | ||
535 | |||
536 | if (var->xres_virtual < var->xres) | ||
537 | var->xres_virtual = var->xres; | ||
538 | if (var->yres_virtual < var->yres) | ||
539 | var->yres_virtual = var->yres; | ||
540 | max_frame_size = fbdev->mem_desc.region[plane->idx].size; | ||
541 | line_size = var->xres_virtual * bpp / 8; | ||
542 | if (line_size * var->yres_virtual > max_frame_size) { | ||
543 | /* Try to keep yres_virtual first */ | ||
544 | line_size = max_frame_size / var->yres_virtual; | ||
545 | var->xres_virtual = line_size * 8 / bpp; | ||
546 | if (var->xres_virtual < var->xres) { | ||
547 | /* Still doesn't fit. Shrink yres_virtual too */ | ||
548 | var->xres_virtual = var->xres; | ||
549 | line_size = var->xres * bpp / 8; | ||
550 | var->yres_virtual = max_frame_size / line_size; | ||
551 | } | ||
552 | /* Recheck this, as the virtual size changed. */ | ||
553 | if (var->xres_virtual < var->xres) | ||
554 | var->xres = var->xres_virtual; | ||
555 | if (var->yres_virtual < var->yres) | ||
556 | var->yres = var->yres_virtual; | ||
557 | if (var->xres < xres_min || var->yres < yres_min) | ||
558 | return -EINVAL; | ||
559 | } | ||
560 | if (var->xres + var->xoffset > var->xres_virtual) | ||
561 | var->xoffset = var->xres_virtual - var->xres; | ||
562 | if (var->yres + var->yoffset > var->yres_virtual) | ||
563 | var->yoffset = var->yres_virtual - var->yres; | ||
564 | |||
565 | if (plane->color_mode == OMAPFB_COLOR_RGB444) { | ||
566 | var->red.offset = 8; var->red.length = 4; | ||
567 | var->red.msb_right = 0; | ||
568 | var->green.offset = 4; var->green.length = 4; | ||
569 | var->green.msb_right = 0; | ||
570 | var->blue.offset = 0; var->blue.length = 4; | ||
571 | var->blue.msb_right = 0; | ||
572 | } else { | ||
573 | var->red.offset = 11; var->red.length = 5; | ||
574 | var->red.msb_right = 0; | ||
575 | var->green.offset = 5; var->green.length = 6; | ||
576 | var->green.msb_right = 0; | ||
577 | var->blue.offset = 0; var->blue.length = 5; | ||
578 | var->blue.msb_right = 0; | ||
579 | } | ||
580 | |||
581 | var->height = -1; | ||
582 | var->width = -1; | ||
583 | var->grayscale = 0; | ||
584 | |||
585 | /* pixclock in ps, the rest in pixclock */ | ||
586 | var->pixclock = 10000000 / (panel->pixel_clock / 100); | ||
587 | var->left_margin = panel->hfp; | ||
588 | var->right_margin = panel->hbp; | ||
589 | var->upper_margin = panel->vfp; | ||
590 | var->lower_margin = panel->vbp; | ||
591 | var->hsync_len = panel->hsw; | ||
592 | var->vsync_len = panel->vsw; | ||
593 | |||
594 | /* TODO: get these from panel->config */ | ||
595 | var->vmode = FB_VMODE_NONINTERLACED; | ||
596 | var->sync = 0; | ||
597 | |||
598 | return 0; | ||
599 | } | ||
600 | |||
601 | |||
602 | /* Set rotation (0, 90, 180, 270 degree), and switch to the new mode. */ | ||
603 | static void omapfb_rotate(struct fb_info *fbi, int rotate) | ||
604 | { | ||
605 | struct omapfb_plane_struct *plane = fbi->par; | ||
606 | struct omapfb_device *fbdev = plane->fbdev; | ||
607 | |||
608 | omapfb_rqueue_lock(fbdev); | ||
609 | if (rotate != fbi->var.rotate) { | ||
610 | struct fb_var_screeninfo *new_var = &fbdev->new_var; | ||
611 | |||
612 | memcpy(new_var, &fbi->var, sizeof(*new_var)); | ||
613 | new_var->rotate = rotate; | ||
614 | if (set_fb_var(fbi, new_var) == 0 && | ||
615 | memcmp(new_var, &fbi->var, sizeof(*new_var))) { | ||
616 | memcpy(&fbi->var, new_var, sizeof(*new_var)); | ||
617 | ctrl_change_mode(fbi); | ||
618 | } | ||
619 | } | ||
620 | omapfb_rqueue_unlock(fbdev); | ||
621 | } | ||
622 | |||
623 | /* | ||
624 | * Set new x,y offsets in the virtual display for the visible area and switch | ||
625 | * to the new mode. | ||
626 | */ | ||
627 | static int omapfb_pan_display(struct fb_var_screeninfo *var, | ||
628 | struct fb_info *fbi) | ||
629 | { | ||
630 | struct omapfb_plane_struct *plane = fbi->par; | ||
631 | struct omapfb_device *fbdev = plane->fbdev; | ||
632 | int r = 0; | ||
633 | |||
634 | omapfb_rqueue_lock(fbdev); | ||
635 | if (var->xoffset != fbi->var.xoffset || | ||
636 | var->yoffset != fbi->var.yoffset) { | ||
637 | struct fb_var_screeninfo *new_var = &fbdev->new_var; | ||
638 | |||
639 | memcpy(new_var, &fbi->var, sizeof(*new_var)); | ||
640 | new_var->xoffset = var->xoffset; | ||
641 | new_var->yoffset = var->yoffset; | ||
642 | if (set_fb_var(fbi, new_var)) | ||
643 | r = -EINVAL; | ||
644 | else { | ||
645 | memcpy(&fbi->var, new_var, sizeof(*new_var)); | ||
646 | ctrl_change_mode(fbi); | ||
647 | } | ||
648 | } | ||
649 | omapfb_rqueue_unlock(fbdev); | ||
650 | |||
651 | return r; | ||
652 | } | ||
653 | |||
654 | /* Set mirror to vertical axis and switch to the new mode. */ | ||
655 | static int omapfb_mirror(struct fb_info *fbi, int mirror) | ||
656 | { | ||
657 | struct omapfb_plane_struct *plane = fbi->par; | ||
658 | struct omapfb_device *fbdev = plane->fbdev; | ||
659 | int r = 0; | ||
660 | |||
661 | omapfb_rqueue_lock(fbdev); | ||
662 | mirror = mirror ? 1 : 0; | ||
663 | if (cpu_is_omap15xx()) | ||
664 | r = -EINVAL; | ||
665 | else if (mirror != plane->info.mirror) { | ||
666 | plane->info.mirror = mirror; | ||
667 | r = ctrl_change_mode(fbi); | ||
668 | } | ||
669 | omapfb_rqueue_unlock(fbdev); | ||
670 | |||
671 | return r; | ||
672 | } | ||
673 | |||
674 | /* | ||
675 | * Check values in var, try to adjust them in case of out of bound values if | ||
676 | * possible, or return error. | ||
677 | */ | ||
678 | static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi) | ||
679 | { | ||
680 | struct omapfb_plane_struct *plane = fbi->par; | ||
681 | struct omapfb_device *fbdev = plane->fbdev; | ||
682 | int r; | ||
683 | |||
684 | omapfb_rqueue_lock(fbdev); | ||
685 | if (fbdev->ctrl->sync != NULL) | ||
686 | fbdev->ctrl->sync(); | ||
687 | r = set_fb_var(fbi, var); | ||
688 | omapfb_rqueue_unlock(fbdev); | ||
689 | |||
690 | return r; | ||
691 | } | ||
692 | |||
693 | /* | ||
694 | * Switch to a new mode. The parameters for it has been check already by | ||
695 | * omapfb_check_var. | ||
696 | */ | ||
697 | static int omapfb_set_par(struct fb_info *fbi) | ||
698 | { | ||
699 | struct omapfb_plane_struct *plane = fbi->par; | ||
700 | struct omapfb_device *fbdev = plane->fbdev; | ||
701 | int r = 0; | ||
702 | |||
703 | omapfb_rqueue_lock(fbdev); | ||
704 | set_fb_fix(fbi, 0); | ||
705 | r = ctrl_change_mode(fbi); | ||
706 | omapfb_rqueue_unlock(fbdev); | ||
707 | |||
708 | return r; | ||
709 | } | ||
710 | |||
711 | int omapfb_update_window_async(struct fb_info *fbi, | ||
712 | struct omapfb_update_window *win, | ||
713 | void (*callback)(void *), | ||
714 | void *callback_data) | ||
715 | { | ||
716 | int xres, yres; | ||
717 | struct omapfb_plane_struct *plane = fbi->par; | ||
718 | struct omapfb_device *fbdev = plane->fbdev; | ||
719 | struct fb_var_screeninfo *var = &fbi->var; | ||
720 | |||
721 | switch (var->rotate) { | ||
722 | case 0: | ||
723 | case 180: | ||
724 | xres = fbdev->panel->x_res; | ||
725 | yres = fbdev->panel->y_res; | ||
726 | break; | ||
727 | case 90: | ||
728 | case 270: | ||
729 | xres = fbdev->panel->y_res; | ||
730 | yres = fbdev->panel->x_res; | ||
731 | break; | ||
732 | default: | ||
733 | return -EINVAL; | ||
734 | } | ||
735 | |||
736 | if (win->x >= xres || win->y >= yres || | ||
737 | win->out_x > xres || win->out_y > yres) | ||
738 | return -EINVAL; | ||
739 | |||
740 | if (!fbdev->ctrl->update_window || | ||
741 | fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE) | ||
742 | return -ENODEV; | ||
743 | |||
744 | if (win->x + win->width > xres) | ||
745 | win->width = xres - win->x; | ||
746 | if (win->y + win->height > yres) | ||
747 | win->height = yres - win->y; | ||
748 | if (win->out_x + win->out_width > xres) | ||
749 | win->out_width = xres - win->out_x; | ||
750 | if (win->out_y + win->out_height > yres) | ||
751 | win->out_height = yres - win->out_y; | ||
752 | if (!win->width || !win->height || !win->out_width || !win->out_height) | ||
753 | return 0; | ||
754 | |||
755 | return fbdev->ctrl->update_window(fbi, win, callback, callback_data); | ||
756 | } | ||
757 | EXPORT_SYMBOL(omapfb_update_window_async); | ||
758 | |||
759 | static int omapfb_update_win(struct fb_info *fbi, | ||
760 | struct omapfb_update_window *win) | ||
761 | { | ||
762 | struct omapfb_plane_struct *plane = fbi->par; | ||
763 | int ret; | ||
764 | |||
765 | omapfb_rqueue_lock(plane->fbdev); | ||
766 | ret = omapfb_update_window_async(fbi, win, NULL, NULL); | ||
767 | omapfb_rqueue_unlock(plane->fbdev); | ||
768 | |||
769 | return ret; | ||
770 | } | ||
771 | |||
772 | static int omapfb_update_full_screen(struct fb_info *fbi) | ||
773 | { | ||
774 | struct omapfb_plane_struct *plane = fbi->par; | ||
775 | struct omapfb_device *fbdev = plane->fbdev; | ||
776 | struct omapfb_update_window win; | ||
777 | int r; | ||
778 | |||
779 | if (!fbdev->ctrl->update_window || | ||
780 | fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE) | ||
781 | return -ENODEV; | ||
782 | |||
783 | win.x = 0; | ||
784 | win.y = 0; | ||
785 | win.width = fbi->var.xres; | ||
786 | win.height = fbi->var.yres; | ||
787 | win.out_x = 0; | ||
788 | win.out_y = 0; | ||
789 | win.out_width = fbi->var.xres; | ||
790 | win.out_height = fbi->var.yres; | ||
791 | win.format = 0; | ||
792 | |||
793 | omapfb_rqueue_lock(fbdev); | ||
794 | r = fbdev->ctrl->update_window(fbi, &win, NULL, NULL); | ||
795 | omapfb_rqueue_unlock(fbdev); | ||
796 | |||
797 | return r; | ||
798 | } | ||
799 | |||
800 | static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) | ||
801 | { | ||
802 | struct omapfb_plane_struct *plane = fbi->par; | ||
803 | struct omapfb_device *fbdev = plane->fbdev; | ||
804 | struct lcd_panel *panel = fbdev->panel; | ||
805 | struct omapfb_plane_info old_info; | ||
806 | int r = 0; | ||
807 | |||
808 | if (pi->pos_x + pi->out_width > panel->x_res || | ||
809 | pi->pos_y + pi->out_height > panel->y_res) | ||
810 | return -EINVAL; | ||
811 | |||
812 | omapfb_rqueue_lock(fbdev); | ||
813 | if (pi->enabled && !fbdev->mem_desc.region[plane->idx].size) { | ||
814 | /* | ||
815 | * This plane's memory was freed, can't enable it | ||
816 | * until it's reallocated. | ||
817 | */ | ||
818 | r = -EINVAL; | ||
819 | goto out; | ||
820 | } | ||
821 | old_info = plane->info; | ||
822 | plane->info = *pi; | ||
823 | if (pi->enabled) { | ||
824 | r = ctrl_change_mode(fbi); | ||
825 | if (r < 0) { | ||
826 | plane->info = old_info; | ||
827 | goto out; | ||
828 | } | ||
829 | } | ||
830 | r = fbdev->ctrl->enable_plane(plane->idx, pi->enabled); | ||
831 | if (r < 0) { | ||
832 | plane->info = old_info; | ||
833 | goto out; | ||
834 | } | ||
835 | out: | ||
836 | omapfb_rqueue_unlock(fbdev); | ||
837 | return r; | ||
838 | } | ||
839 | |||
840 | static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) | ||
841 | { | ||
842 | struct omapfb_plane_struct *plane = fbi->par; | ||
843 | |||
844 | *pi = plane->info; | ||
845 | return 0; | ||
846 | } | ||
847 | |||
848 | static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) | ||
849 | { | ||
850 | struct omapfb_plane_struct *plane = fbi->par; | ||
851 | struct omapfb_device *fbdev = plane->fbdev; | ||
852 | struct omapfb_mem_region *rg = &fbdev->mem_desc.region[plane->idx]; | ||
853 | size_t size; | ||
854 | int r = 0; | ||
855 | |||
856 | if (fbdev->ctrl->setup_mem == NULL) | ||
857 | return -ENODEV; | ||
858 | if (mi->type != OMAPFB_MEMTYPE_SDRAM) | ||
859 | return -EINVAL; | ||
860 | |||
861 | size = PAGE_ALIGN(mi->size); | ||
862 | omapfb_rqueue_lock(fbdev); | ||
863 | if (plane->info.enabled) { | ||
864 | r = -EBUSY; | ||
865 | goto out; | ||
866 | } | ||
867 | if (rg->size != size || rg->type != mi->type) { | ||
868 | struct fb_var_screeninfo *new_var = &fbdev->new_var; | ||
869 | unsigned long old_size = rg->size; | ||
870 | u8 old_type = rg->type; | ||
871 | unsigned long paddr; | ||
872 | |||
873 | rg->size = size; | ||
874 | rg->type = mi->type; | ||
875 | /* | ||
876 | * size == 0 is a special case, for which we | ||
877 | * don't check / adjust the screen parameters. | ||
878 | * This isn't a problem since the plane can't | ||
879 | * be reenabled unless its size is > 0. | ||
880 | */ | ||
881 | if (old_size != size && size) { | ||
882 | if (size) { | ||
883 | memcpy(new_var, &fbi->var, sizeof(*new_var)); | ||
884 | r = set_fb_var(fbi, new_var); | ||
885 | if (r < 0) | ||
886 | goto out; | ||
887 | } | ||
888 | } | ||
889 | |||
890 | if (fbdev->ctrl->sync) | ||
891 | fbdev->ctrl->sync(); | ||
892 | r = fbdev->ctrl->setup_mem(plane->idx, size, mi->type, &paddr); | ||
893 | if (r < 0) { | ||
894 | /* Revert changes. */ | ||
895 | rg->size = old_size; | ||
896 | rg->type = old_type; | ||
897 | goto out; | ||
898 | } | ||
899 | rg->paddr = paddr; | ||
900 | |||
901 | if (old_size != size) { | ||
902 | if (size) { | ||
903 | memcpy(&fbi->var, new_var, sizeof(fbi->var)); | ||
904 | set_fb_fix(fbi, 0); | ||
905 | } else { | ||
906 | /* | ||
907 | * Set these explicitly to indicate that the | ||
908 | * plane memory is dealloce'd, the other | ||
909 | * screen parameters in var / fix are invalid. | ||
910 | */ | ||
911 | mutex_lock(&fbi->mm_lock); | ||
912 | fbi->fix.smem_start = 0; | ||
913 | fbi->fix.smem_len = 0; | ||
914 | mutex_unlock(&fbi->mm_lock); | ||
915 | } | ||
916 | } | ||
917 | } | ||
918 | out: | ||
919 | omapfb_rqueue_unlock(fbdev); | ||
920 | |||
921 | return r; | ||
922 | } | ||
923 | |||
924 | static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) | ||
925 | { | ||
926 | struct omapfb_plane_struct *plane = fbi->par; | ||
927 | struct omapfb_device *fbdev = plane->fbdev; | ||
928 | struct omapfb_mem_region *rg; | ||
929 | |||
930 | rg = &fbdev->mem_desc.region[plane->idx]; | ||
931 | memset(mi, 0, sizeof(*mi)); | ||
932 | mi->size = rg->size; | ||
933 | mi->type = rg->type; | ||
934 | |||
935 | return 0; | ||
936 | } | ||
937 | |||
938 | static int omapfb_set_color_key(struct omapfb_device *fbdev, | ||
939 | struct omapfb_color_key *ck) | ||
940 | { | ||
941 | int r; | ||
942 | |||
943 | if (!fbdev->ctrl->set_color_key) | ||
944 | return -ENODEV; | ||
945 | |||
946 | omapfb_rqueue_lock(fbdev); | ||
947 | r = fbdev->ctrl->set_color_key(ck); | ||
948 | omapfb_rqueue_unlock(fbdev); | ||
949 | |||
950 | return r; | ||
951 | } | ||
952 | |||
953 | static int omapfb_get_color_key(struct omapfb_device *fbdev, | ||
954 | struct omapfb_color_key *ck) | ||
955 | { | ||
956 | int r; | ||
957 | |||
958 | if (!fbdev->ctrl->get_color_key) | ||
959 | return -ENODEV; | ||
960 | |||
961 | omapfb_rqueue_lock(fbdev); | ||
962 | r = fbdev->ctrl->get_color_key(ck); | ||
963 | omapfb_rqueue_unlock(fbdev); | ||
964 | |||
965 | return r; | ||
966 | } | ||
967 | |||
968 | static struct blocking_notifier_head omapfb_client_list[OMAPFB_PLANE_NUM]; | ||
969 | static int notifier_inited; | ||
970 | |||
971 | static void omapfb_init_notifier(void) | ||
972 | { | ||
973 | int i; | ||
974 | |||
975 | for (i = 0; i < OMAPFB_PLANE_NUM; i++) | ||
976 | BLOCKING_INIT_NOTIFIER_HEAD(&omapfb_client_list[i]); | ||
977 | } | ||
978 | |||
979 | int omapfb_register_client(struct omapfb_notifier_block *omapfb_nb, | ||
980 | omapfb_notifier_callback_t callback, | ||
981 | void *callback_data) | ||
982 | { | ||
983 | int r; | ||
984 | |||
985 | if ((unsigned)omapfb_nb->plane_idx > OMAPFB_PLANE_NUM) | ||
986 | return -EINVAL; | ||
987 | |||
988 | if (!notifier_inited) { | ||
989 | omapfb_init_notifier(); | ||
990 | notifier_inited = 1; | ||
991 | } | ||
992 | |||
993 | omapfb_nb->nb.notifier_call = (int (*)(struct notifier_block *, | ||
994 | unsigned long, void *))callback; | ||
995 | omapfb_nb->data = callback_data; | ||
996 | r = blocking_notifier_chain_register( | ||
997 | &omapfb_client_list[omapfb_nb->plane_idx], | ||
998 | &omapfb_nb->nb); | ||
999 | if (r) | ||
1000 | return r; | ||
1001 | if (omapfb_dev != NULL && | ||
1002 | omapfb_dev->ctrl && omapfb_dev->ctrl->bind_client) { | ||
1003 | omapfb_dev->ctrl->bind_client(omapfb_nb); | ||
1004 | } | ||
1005 | |||
1006 | return 0; | ||
1007 | } | ||
1008 | EXPORT_SYMBOL(omapfb_register_client); | ||
1009 | |||
1010 | int omapfb_unregister_client(struct omapfb_notifier_block *omapfb_nb) | ||
1011 | { | ||
1012 | return blocking_notifier_chain_unregister( | ||
1013 | &omapfb_client_list[omapfb_nb->plane_idx], &omapfb_nb->nb); | ||
1014 | } | ||
1015 | EXPORT_SYMBOL(omapfb_unregister_client); | ||
1016 | |||
1017 | void omapfb_notify_clients(struct omapfb_device *fbdev, unsigned long event) | ||
1018 | { | ||
1019 | int i; | ||
1020 | |||
1021 | if (!notifier_inited) | ||
1022 | /* no client registered yet */ | ||
1023 | return; | ||
1024 | |||
1025 | for (i = 0; i < OMAPFB_PLANE_NUM; i++) | ||
1026 | blocking_notifier_call_chain(&omapfb_client_list[i], event, | ||
1027 | fbdev->fb_info[i]); | ||
1028 | } | ||
1029 | EXPORT_SYMBOL(omapfb_notify_clients); | ||
1030 | |||
1031 | static int omapfb_set_update_mode(struct omapfb_device *fbdev, | ||
1032 | enum omapfb_update_mode mode) | ||
1033 | { | ||
1034 | int r; | ||
1035 | |||
1036 | omapfb_rqueue_lock(fbdev); | ||
1037 | r = fbdev->ctrl->set_update_mode(mode); | ||
1038 | omapfb_rqueue_unlock(fbdev); | ||
1039 | |||
1040 | return r; | ||
1041 | } | ||
1042 | |||
1043 | static enum omapfb_update_mode omapfb_get_update_mode(struct omapfb_device *fbdev) | ||
1044 | { | ||
1045 | int r; | ||
1046 | |||
1047 | omapfb_rqueue_lock(fbdev); | ||
1048 | r = fbdev->ctrl->get_update_mode(); | ||
1049 | omapfb_rqueue_unlock(fbdev); | ||
1050 | |||
1051 | return r; | ||
1052 | } | ||
1053 | |||
1054 | static void omapfb_get_caps(struct omapfb_device *fbdev, int plane, | ||
1055 | struct omapfb_caps *caps) | ||
1056 | { | ||
1057 | memset(caps, 0, sizeof(*caps)); | ||
1058 | fbdev->ctrl->get_caps(plane, caps); | ||
1059 | caps->ctrl |= fbdev->panel->get_caps(fbdev->panel); | ||
1060 | } | ||
1061 | |||
1062 | /* For lcd testing */ | ||
1063 | void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval) | ||
1064 | { | ||
1065 | omapfb_rqueue_lock(fbdev); | ||
1066 | *(u16 *)fbdev->mem_desc.region[0].vaddr = pixval; | ||
1067 | if (fbdev->ctrl->get_update_mode() == OMAPFB_MANUAL_UPDATE) { | ||
1068 | struct omapfb_update_window win; | ||
1069 | |||
1070 | memset(&win, 0, sizeof(win)); | ||
1071 | win.width = 2; | ||
1072 | win.height = 2; | ||
1073 | win.out_width = 2; | ||
1074 | win.out_height = 2; | ||
1075 | fbdev->ctrl->update_window(fbdev->fb_info[0], &win, NULL, NULL); | ||
1076 | } | ||
1077 | omapfb_rqueue_unlock(fbdev); | ||
1078 | } | ||
1079 | EXPORT_SYMBOL(omapfb_write_first_pixel); | ||
1080 | |||
1081 | /* | ||
1082 | * Ioctl interface. Part of the kernel mode frame buffer API is duplicated | ||
1083 | * here to be accessible by user mode code. | ||
1084 | */ | ||
1085 | static int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, | ||
1086 | unsigned long arg) | ||
1087 | { | ||
1088 | struct omapfb_plane_struct *plane = fbi->par; | ||
1089 | struct omapfb_device *fbdev = plane->fbdev; | ||
1090 | struct fb_ops *ops = fbi->fbops; | ||
1091 | union { | ||
1092 | struct omapfb_update_window update_window; | ||
1093 | struct omapfb_plane_info plane_info; | ||
1094 | struct omapfb_mem_info mem_info; | ||
1095 | struct omapfb_color_key color_key; | ||
1096 | enum omapfb_update_mode update_mode; | ||
1097 | struct omapfb_caps caps; | ||
1098 | unsigned int mirror; | ||
1099 | int plane_out; | ||
1100 | int enable_plane; | ||
1101 | } p; | ||
1102 | int r = 0; | ||
1103 | |||
1104 | BUG_ON(!ops); | ||
1105 | switch (cmd) { | ||
1106 | case OMAPFB_MIRROR: | ||
1107 | if (get_user(p.mirror, (int __user *)arg)) | ||
1108 | r = -EFAULT; | ||
1109 | else | ||
1110 | omapfb_mirror(fbi, p.mirror); | ||
1111 | break; | ||
1112 | case OMAPFB_SYNC_GFX: | ||
1113 | omapfb_sync(fbi); | ||
1114 | break; | ||
1115 | case OMAPFB_VSYNC: | ||
1116 | break; | ||
1117 | case OMAPFB_SET_UPDATE_MODE: | ||
1118 | if (get_user(p.update_mode, (int __user *)arg)) | ||
1119 | r = -EFAULT; | ||
1120 | else | ||
1121 | r = omapfb_set_update_mode(fbdev, p.update_mode); | ||
1122 | break; | ||
1123 | case OMAPFB_GET_UPDATE_MODE: | ||
1124 | p.update_mode = omapfb_get_update_mode(fbdev); | ||
1125 | if (put_user(p.update_mode, | ||
1126 | (enum omapfb_update_mode __user *)arg)) | ||
1127 | r = -EFAULT; | ||
1128 | break; | ||
1129 | case OMAPFB_UPDATE_WINDOW_OLD: | ||
1130 | if (copy_from_user(&p.update_window, (void __user *)arg, | ||
1131 | sizeof(struct omapfb_update_window_old))) | ||
1132 | r = -EFAULT; | ||
1133 | else { | ||
1134 | struct omapfb_update_window *u = &p.update_window; | ||
1135 | u->out_x = u->x; | ||
1136 | u->out_y = u->y; | ||
1137 | u->out_width = u->width; | ||
1138 | u->out_height = u->height; | ||
1139 | memset(u->reserved, 0, sizeof(u->reserved)); | ||
1140 | r = omapfb_update_win(fbi, u); | ||
1141 | } | ||
1142 | break; | ||
1143 | case OMAPFB_UPDATE_WINDOW: | ||
1144 | if (copy_from_user(&p.update_window, (void __user *)arg, | ||
1145 | sizeof(p.update_window))) | ||
1146 | r = -EFAULT; | ||
1147 | else | ||
1148 | r = omapfb_update_win(fbi, &p.update_window); | ||
1149 | break; | ||
1150 | case OMAPFB_SETUP_PLANE: | ||
1151 | if (copy_from_user(&p.plane_info, (void __user *)arg, | ||
1152 | sizeof(p.plane_info))) | ||
1153 | r = -EFAULT; | ||
1154 | else | ||
1155 | r = omapfb_setup_plane(fbi, &p.plane_info); | ||
1156 | break; | ||
1157 | case OMAPFB_QUERY_PLANE: | ||
1158 | if ((r = omapfb_query_plane(fbi, &p.plane_info)) < 0) | ||
1159 | break; | ||
1160 | if (copy_to_user((void __user *)arg, &p.plane_info, | ||
1161 | sizeof(p.plane_info))) | ||
1162 | r = -EFAULT; | ||
1163 | break; | ||
1164 | case OMAPFB_SETUP_MEM: | ||
1165 | if (copy_from_user(&p.mem_info, (void __user *)arg, | ||
1166 | sizeof(p.mem_info))) | ||
1167 | r = -EFAULT; | ||
1168 | else | ||
1169 | r = omapfb_setup_mem(fbi, &p.mem_info); | ||
1170 | break; | ||
1171 | case OMAPFB_QUERY_MEM: | ||
1172 | if ((r = omapfb_query_mem(fbi, &p.mem_info)) < 0) | ||
1173 | break; | ||
1174 | if (copy_to_user((void __user *)arg, &p.mem_info, | ||
1175 | sizeof(p.mem_info))) | ||
1176 | r = -EFAULT; | ||
1177 | break; | ||
1178 | case OMAPFB_SET_COLOR_KEY: | ||
1179 | if (copy_from_user(&p.color_key, (void __user *)arg, | ||
1180 | sizeof(p.color_key))) | ||
1181 | r = -EFAULT; | ||
1182 | else | ||
1183 | r = omapfb_set_color_key(fbdev, &p.color_key); | ||
1184 | break; | ||
1185 | case OMAPFB_GET_COLOR_KEY: | ||
1186 | if ((r = omapfb_get_color_key(fbdev, &p.color_key)) < 0) | ||
1187 | break; | ||
1188 | if (copy_to_user((void __user *)arg, &p.color_key, | ||
1189 | sizeof(p.color_key))) | ||
1190 | r = -EFAULT; | ||
1191 | break; | ||
1192 | case OMAPFB_GET_CAPS: | ||
1193 | omapfb_get_caps(fbdev, plane->idx, &p.caps); | ||
1194 | if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps))) | ||
1195 | r = -EFAULT; | ||
1196 | break; | ||
1197 | case OMAPFB_LCD_TEST: | ||
1198 | { | ||
1199 | int test_num; | ||
1200 | |||
1201 | if (get_user(test_num, (int __user *)arg)) { | ||
1202 | r = -EFAULT; | ||
1203 | break; | ||
1204 | } | ||
1205 | if (!fbdev->panel->run_test) { | ||
1206 | r = -EINVAL; | ||
1207 | break; | ||
1208 | } | ||
1209 | r = fbdev->panel->run_test(fbdev->panel, test_num); | ||
1210 | break; | ||
1211 | } | ||
1212 | case OMAPFB_CTRL_TEST: | ||
1213 | { | ||
1214 | int test_num; | ||
1215 | |||
1216 | if (get_user(test_num, (int __user *)arg)) { | ||
1217 | r = -EFAULT; | ||
1218 | break; | ||
1219 | } | ||
1220 | if (!fbdev->ctrl->run_test) { | ||
1221 | r = -EINVAL; | ||
1222 | break; | ||
1223 | } | ||
1224 | r = fbdev->ctrl->run_test(test_num); | ||
1225 | break; | ||
1226 | } | ||
1227 | default: | ||
1228 | r = -EINVAL; | ||
1229 | } | ||
1230 | |||
1231 | return r; | ||
1232 | } | ||
1233 | |||
1234 | static int omapfb_mmap(struct fb_info *info, struct vm_area_struct *vma) | ||
1235 | { | ||
1236 | struct omapfb_plane_struct *plane = info->par; | ||
1237 | struct omapfb_device *fbdev = plane->fbdev; | ||
1238 | int r; | ||
1239 | |||
1240 | omapfb_rqueue_lock(fbdev); | ||
1241 | r = fbdev->ctrl->mmap(info, vma); | ||
1242 | omapfb_rqueue_unlock(fbdev); | ||
1243 | |||
1244 | return r; | ||
1245 | } | ||
1246 | |||
1247 | /* | ||
1248 | * Callback table for the frame buffer framework. Some of these pointers | ||
1249 | * will be changed according to the current setting of fb_info->accel_flags. | ||
1250 | */ | ||
1251 | static struct fb_ops omapfb_ops = { | ||
1252 | .owner = THIS_MODULE, | ||
1253 | .fb_open = omapfb_open, | ||
1254 | .fb_release = omapfb_release, | ||
1255 | .fb_setcolreg = omapfb_setcolreg, | ||
1256 | .fb_setcmap = omapfb_setcmap, | ||
1257 | .fb_fillrect = cfb_fillrect, | ||
1258 | .fb_copyarea = cfb_copyarea, | ||
1259 | .fb_imageblit = cfb_imageblit, | ||
1260 | .fb_blank = omapfb_blank, | ||
1261 | .fb_ioctl = omapfb_ioctl, | ||
1262 | .fb_check_var = omapfb_check_var, | ||
1263 | .fb_set_par = omapfb_set_par, | ||
1264 | .fb_rotate = omapfb_rotate, | ||
1265 | .fb_pan_display = omapfb_pan_display, | ||
1266 | }; | ||
1267 | |||
1268 | /* | ||
1269 | * --------------------------------------------------------------------------- | ||
1270 | * Sysfs interface | ||
1271 | * --------------------------------------------------------------------------- | ||
1272 | */ | ||
1273 | /* omapfbX sysfs entries */ | ||
1274 | static ssize_t omapfb_show_caps_num(struct device *dev, | ||
1275 | struct device_attribute *attr, char *buf) | ||
1276 | { | ||
1277 | struct omapfb_device *fbdev = dev_get_drvdata(dev); | ||
1278 | int plane; | ||
1279 | size_t size; | ||
1280 | struct omapfb_caps caps; | ||
1281 | |||
1282 | plane = 0; | ||
1283 | size = 0; | ||
1284 | while (size < PAGE_SIZE && plane < OMAPFB_PLANE_NUM) { | ||
1285 | omapfb_get_caps(fbdev, plane, &caps); | ||
1286 | size += snprintf(&buf[size], PAGE_SIZE - size, | ||
1287 | "plane#%d %#010x %#010x %#010x\n", | ||
1288 | plane, caps.ctrl, caps.plane_color, caps.wnd_color); | ||
1289 | plane++; | ||
1290 | } | ||
1291 | return size; | ||
1292 | } | ||
1293 | |||
1294 | static ssize_t omapfb_show_caps_text(struct device *dev, | ||
1295 | struct device_attribute *attr, char *buf) | ||
1296 | { | ||
1297 | struct omapfb_device *fbdev = dev_get_drvdata(dev); | ||
1298 | int i; | ||
1299 | struct omapfb_caps caps; | ||
1300 | int plane; | ||
1301 | size_t size; | ||
1302 | |||
1303 | plane = 0; | ||
1304 | size = 0; | ||
1305 | while (size < PAGE_SIZE && plane < OMAPFB_PLANE_NUM) { | ||
1306 | omapfb_get_caps(fbdev, plane, &caps); | ||
1307 | size += snprintf(&buf[size], PAGE_SIZE - size, | ||
1308 | "plane#%d:\n", plane); | ||
1309 | for (i = 0; i < ARRAY_SIZE(ctrl_caps) && | ||
1310 | size < PAGE_SIZE; i++) { | ||
1311 | if (ctrl_caps[i].flag & caps.ctrl) | ||
1312 | size += snprintf(&buf[size], PAGE_SIZE - size, | ||
1313 | " %s\n", ctrl_caps[i].name); | ||
1314 | } | ||
1315 | size += snprintf(&buf[size], PAGE_SIZE - size, | ||
1316 | " plane colors:\n"); | ||
1317 | for (i = 0; i < ARRAY_SIZE(color_caps) && | ||
1318 | size < PAGE_SIZE; i++) { | ||
1319 | if (color_caps[i].flag & caps.plane_color) | ||
1320 | size += snprintf(&buf[size], PAGE_SIZE - size, | ||
1321 | " %s\n", color_caps[i].name); | ||
1322 | } | ||
1323 | size += snprintf(&buf[size], PAGE_SIZE - size, | ||
1324 | " window colors:\n"); | ||
1325 | for (i = 0; i < ARRAY_SIZE(color_caps) && | ||
1326 | size < PAGE_SIZE; i++) { | ||
1327 | if (color_caps[i].flag & caps.wnd_color) | ||
1328 | size += snprintf(&buf[size], PAGE_SIZE - size, | ||
1329 | " %s\n", color_caps[i].name); | ||
1330 | } | ||
1331 | |||
1332 | plane++; | ||
1333 | } | ||
1334 | return size; | ||
1335 | } | ||
1336 | |||
1337 | static DEVICE_ATTR(caps_num, 0444, omapfb_show_caps_num, NULL); | ||
1338 | static DEVICE_ATTR(caps_text, 0444, omapfb_show_caps_text, NULL); | ||
1339 | |||
1340 | /* panel sysfs entries */ | ||
1341 | static ssize_t omapfb_show_panel_name(struct device *dev, | ||
1342 | struct device_attribute *attr, char *buf) | ||
1343 | { | ||
1344 | struct omapfb_device *fbdev = dev_get_drvdata(dev); | ||
1345 | |||
1346 | return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->panel->name); | ||
1347 | } | ||
1348 | |||
1349 | static ssize_t omapfb_show_bklight_level(struct device *dev, | ||
1350 | struct device_attribute *attr, | ||
1351 | char *buf) | ||
1352 | { | ||
1353 | struct omapfb_device *fbdev = dev_get_drvdata(dev); | ||
1354 | int r; | ||
1355 | |||
1356 | if (fbdev->panel->get_bklight_level) { | ||
1357 | r = snprintf(buf, PAGE_SIZE, "%d\n", | ||
1358 | fbdev->panel->get_bklight_level(fbdev->panel)); | ||
1359 | } else | ||
1360 | r = -ENODEV; | ||
1361 | return r; | ||
1362 | } | ||
1363 | |||
1364 | static ssize_t omapfb_store_bklight_level(struct device *dev, | ||
1365 | struct device_attribute *attr, | ||
1366 | const char *buf, size_t size) | ||
1367 | { | ||
1368 | struct omapfb_device *fbdev = dev_get_drvdata(dev); | ||
1369 | int r; | ||
1370 | |||
1371 | if (fbdev->panel->set_bklight_level) { | ||
1372 | unsigned int level; | ||
1373 | |||
1374 | if (sscanf(buf, "%10d", &level) == 1) { | ||
1375 | r = fbdev->panel->set_bklight_level(fbdev->panel, | ||
1376 | level); | ||
1377 | } else | ||
1378 | r = -EINVAL; | ||
1379 | } else | ||
1380 | r = -ENODEV; | ||
1381 | return r ? r : size; | ||
1382 | } | ||
1383 | |||
1384 | static ssize_t omapfb_show_bklight_max(struct device *dev, | ||
1385 | struct device_attribute *attr, char *buf) | ||
1386 | { | ||
1387 | struct omapfb_device *fbdev = dev_get_drvdata(dev); | ||
1388 | int r; | ||
1389 | |||
1390 | if (fbdev->panel->get_bklight_level) { | ||
1391 | r = snprintf(buf, PAGE_SIZE, "%d\n", | ||
1392 | fbdev->panel->get_bklight_max(fbdev->panel)); | ||
1393 | } else | ||
1394 | r = -ENODEV; | ||
1395 | return r; | ||
1396 | } | ||
1397 | |||
1398 | static struct device_attribute dev_attr_panel_name = | ||
1399 | __ATTR(name, 0444, omapfb_show_panel_name, NULL); | ||
1400 | static DEVICE_ATTR(backlight_level, 0664, | ||
1401 | omapfb_show_bklight_level, omapfb_store_bklight_level); | ||
1402 | static DEVICE_ATTR(backlight_max, 0444, omapfb_show_bklight_max, NULL); | ||
1403 | |||
1404 | static struct attribute *panel_attrs[] = { | ||
1405 | &dev_attr_panel_name.attr, | ||
1406 | &dev_attr_backlight_level.attr, | ||
1407 | &dev_attr_backlight_max.attr, | ||
1408 | NULL, | ||
1409 | }; | ||
1410 | |||
1411 | static struct attribute_group panel_attr_grp = { | ||
1412 | .name = "panel", | ||
1413 | .attrs = panel_attrs, | ||
1414 | }; | ||
1415 | |||
1416 | /* ctrl sysfs entries */ | ||
1417 | static ssize_t omapfb_show_ctrl_name(struct device *dev, | ||
1418 | struct device_attribute *attr, char *buf) | ||
1419 | { | ||
1420 | struct omapfb_device *fbdev = dev_get_drvdata(dev); | ||
1421 | |||
1422 | return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->ctrl->name); | ||
1423 | } | ||
1424 | |||
1425 | static struct device_attribute dev_attr_ctrl_name = | ||
1426 | __ATTR(name, 0444, omapfb_show_ctrl_name, NULL); | ||
1427 | |||
1428 | static struct attribute *ctrl_attrs[] = { | ||
1429 | &dev_attr_ctrl_name.attr, | ||
1430 | NULL, | ||
1431 | }; | ||
1432 | |||
1433 | static struct attribute_group ctrl_attr_grp = { | ||
1434 | .name = "ctrl", | ||
1435 | .attrs = ctrl_attrs, | ||
1436 | }; | ||
1437 | |||
1438 | static int omapfb_register_sysfs(struct omapfb_device *fbdev) | ||
1439 | { | ||
1440 | int r; | ||
1441 | |||
1442 | if ((r = device_create_file(fbdev->dev, &dev_attr_caps_num))) | ||
1443 | goto fail0; | ||
1444 | |||
1445 | if ((r = device_create_file(fbdev->dev, &dev_attr_caps_text))) | ||
1446 | goto fail1; | ||
1447 | |||
1448 | if ((r = sysfs_create_group(&fbdev->dev->kobj, &panel_attr_grp))) | ||
1449 | goto fail2; | ||
1450 | |||
1451 | if ((r = sysfs_create_group(&fbdev->dev->kobj, &ctrl_attr_grp))) | ||
1452 | goto fail3; | ||
1453 | |||
1454 | return 0; | ||
1455 | fail3: | ||
1456 | sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp); | ||
1457 | fail2: | ||
1458 | device_remove_file(fbdev->dev, &dev_attr_caps_text); | ||
1459 | fail1: | ||
1460 | device_remove_file(fbdev->dev, &dev_attr_caps_num); | ||
1461 | fail0: | ||
1462 | dev_err(fbdev->dev, "unable to register sysfs interface\n"); | ||
1463 | return r; | ||
1464 | } | ||
1465 | |||
1466 | static void omapfb_unregister_sysfs(struct omapfb_device *fbdev) | ||
1467 | { | ||
1468 | sysfs_remove_group(&fbdev->dev->kobj, &ctrl_attr_grp); | ||
1469 | sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp); | ||
1470 | device_remove_file(fbdev->dev, &dev_attr_caps_num); | ||
1471 | device_remove_file(fbdev->dev, &dev_attr_caps_text); | ||
1472 | } | ||
1473 | |||
1474 | /* | ||
1475 | * --------------------------------------------------------------------------- | ||
1476 | * LDM callbacks | ||
1477 | * --------------------------------------------------------------------------- | ||
1478 | */ | ||
1479 | /* Initialize system fb_info object and set the default video mode. | ||
1480 | * The frame buffer memory already allocated by lcddma_init | ||
1481 | */ | ||
1482 | static int fbinfo_init(struct omapfb_device *fbdev, struct fb_info *info) | ||
1483 | { | ||
1484 | struct fb_var_screeninfo *var = &info->var; | ||
1485 | struct fb_fix_screeninfo *fix = &info->fix; | ||
1486 | int r = 0; | ||
1487 | |||
1488 | info->fbops = &omapfb_ops; | ||
1489 | info->flags = FBINFO_FLAG_DEFAULT; | ||
1490 | |||
1491 | strncpy(fix->id, MODULE_NAME, sizeof(fix->id)); | ||
1492 | |||
1493 | info->pseudo_palette = fbdev->pseudo_palette; | ||
1494 | |||
1495 | var->accel_flags = def_accel ? FB_ACCELF_TEXT : 0; | ||
1496 | var->xres = def_vxres; | ||
1497 | var->yres = def_vyres; | ||
1498 | var->xres_virtual = def_vxres; | ||
1499 | var->yres_virtual = def_vyres; | ||
1500 | var->rotate = def_rotate; | ||
1501 | var->bits_per_pixel = fbdev->panel->bpp; | ||
1502 | |||
1503 | set_fb_var(info, var); | ||
1504 | set_fb_fix(info, 1); | ||
1505 | |||
1506 | r = fb_alloc_cmap(&info->cmap, 16, 0); | ||
1507 | if (r != 0) | ||
1508 | dev_err(fbdev->dev, "unable to allocate color map memory\n"); | ||
1509 | |||
1510 | return r; | ||
1511 | } | ||
1512 | |||
1513 | /* Release the fb_info object */ | ||
1514 | static void fbinfo_cleanup(struct omapfb_device *fbdev, struct fb_info *fbi) | ||
1515 | { | ||
1516 | fb_dealloc_cmap(&fbi->cmap); | ||
1517 | } | ||
1518 | |||
1519 | static void planes_cleanup(struct omapfb_device *fbdev) | ||
1520 | { | ||
1521 | int i; | ||
1522 | |||
1523 | for (i = 0; i < fbdev->mem_desc.region_cnt; i++) { | ||
1524 | if (fbdev->fb_info[i] == NULL) | ||
1525 | break; | ||
1526 | fbinfo_cleanup(fbdev, fbdev->fb_info[i]); | ||
1527 | framebuffer_release(fbdev->fb_info[i]); | ||
1528 | } | ||
1529 | } | ||
1530 | |||
1531 | static int planes_init(struct omapfb_device *fbdev) | ||
1532 | { | ||
1533 | struct fb_info *fbi; | ||
1534 | int i; | ||
1535 | int r; | ||
1536 | |||
1537 | for (i = 0; i < fbdev->mem_desc.region_cnt; i++) { | ||
1538 | struct omapfb_plane_struct *plane; | ||
1539 | fbi = framebuffer_alloc(sizeof(struct omapfb_plane_struct), | ||
1540 | fbdev->dev); | ||
1541 | if (fbi == NULL) { | ||
1542 | dev_err(fbdev->dev, | ||
1543 | "unable to allocate memory for plane info\n"); | ||
1544 | planes_cleanup(fbdev); | ||
1545 | return -ENOMEM; | ||
1546 | } | ||
1547 | plane = fbi->par; | ||
1548 | plane->idx = i; | ||
1549 | plane->fbdev = fbdev; | ||
1550 | plane->info.mirror = def_mirror; | ||
1551 | fbdev->fb_info[i] = fbi; | ||
1552 | |||
1553 | if ((r = fbinfo_init(fbdev, fbi)) < 0) { | ||
1554 | framebuffer_release(fbi); | ||
1555 | planes_cleanup(fbdev); | ||
1556 | return r; | ||
1557 | } | ||
1558 | plane->info.out_width = fbi->var.xres; | ||
1559 | plane->info.out_height = fbi->var.yres; | ||
1560 | } | ||
1561 | return 0; | ||
1562 | } | ||
1563 | |||
1564 | /* | ||
1565 | * Free driver resources. Can be called to rollback an aborted initialization | ||
1566 | * sequence. | ||
1567 | */ | ||
1568 | static void omapfb_free_resources(struct omapfb_device *fbdev, int state) | ||
1569 | { | ||
1570 | int i; | ||
1571 | |||
1572 | switch (state) { | ||
1573 | case OMAPFB_ACTIVE: | ||
1574 | for (i = 0; i < fbdev->mem_desc.region_cnt; i++) | ||
1575 | unregister_framebuffer(fbdev->fb_info[i]); | ||
1576 | case 7: | ||
1577 | omapfb_unregister_sysfs(fbdev); | ||
1578 | case 6: | ||
1579 | fbdev->panel->disable(fbdev->panel); | ||
1580 | case 5: | ||
1581 | omapfb_set_update_mode(fbdev, OMAPFB_UPDATE_DISABLED); | ||
1582 | case 4: | ||
1583 | planes_cleanup(fbdev); | ||
1584 | case 3: | ||
1585 | ctrl_cleanup(fbdev); | ||
1586 | case 2: | ||
1587 | fbdev->panel->cleanup(fbdev->panel); | ||
1588 | case 1: | ||
1589 | dev_set_drvdata(fbdev->dev, NULL); | ||
1590 | kfree(fbdev); | ||
1591 | case 0: | ||
1592 | /* nothing to free */ | ||
1593 | break; | ||
1594 | default: | ||
1595 | BUG(); | ||
1596 | } | ||
1597 | } | ||
1598 | |||
1599 | static int omapfb_find_ctrl(struct omapfb_device *fbdev) | ||
1600 | { | ||
1601 | struct omapfb_platform_data *conf; | ||
1602 | char name[17]; | ||
1603 | int i; | ||
1604 | |||
1605 | conf = dev_get_platdata(fbdev->dev); | ||
1606 | |||
1607 | fbdev->ctrl = NULL; | ||
1608 | |||
1609 | strncpy(name, conf->lcd.ctrl_name, sizeof(name) - 1); | ||
1610 | name[sizeof(name) - 1] = '\0'; | ||
1611 | |||
1612 | if (strcmp(name, "internal") == 0) { | ||
1613 | fbdev->ctrl = fbdev->int_ctrl; | ||
1614 | return 0; | ||
1615 | } | ||
1616 | |||
1617 | for (i = 0; i < ARRAY_SIZE(ctrls); i++) { | ||
1618 | dev_dbg(fbdev->dev, "ctrl %s\n", ctrls[i]->name); | ||
1619 | if (strcmp(ctrls[i]->name, name) == 0) { | ||
1620 | fbdev->ctrl = ctrls[i]; | ||
1621 | break; | ||
1622 | } | ||
1623 | } | ||
1624 | |||
1625 | if (fbdev->ctrl == NULL) { | ||
1626 | dev_dbg(fbdev->dev, "ctrl %s not supported\n", name); | ||
1627 | return -1; | ||
1628 | } | ||
1629 | |||
1630 | return 0; | ||
1631 | } | ||
1632 | |||
1633 | static void check_required_callbacks(struct omapfb_device *fbdev) | ||
1634 | { | ||
1635 | #define _C(x) (fbdev->ctrl->x != NULL) | ||
1636 | #define _P(x) (fbdev->panel->x != NULL) | ||
1637 | BUG_ON(fbdev->ctrl == NULL || fbdev->panel == NULL); | ||
1638 | BUG_ON(!(_C(init) && _C(cleanup) && _C(get_caps) && | ||
1639 | _C(set_update_mode) && _C(setup_plane) && _C(enable_plane) && | ||
1640 | _P(init) && _P(cleanup) && _P(enable) && _P(disable) && | ||
1641 | _P(get_caps))); | ||
1642 | #undef _P | ||
1643 | #undef _C | ||
1644 | } | ||
1645 | |||
1646 | /* | ||
1647 | * Called by LDM binding to probe and attach a new device. | ||
1648 | * Initialization sequence: | ||
1649 | * 1. allocate system omapfb_device structure | ||
1650 | * 2. select controller type according to platform configuration | ||
1651 | * init LCD panel | ||
1652 | * 3. init LCD controller and LCD DMA | ||
1653 | * 4. init system fb_info structure for all planes | ||
1654 | * 5. setup video mode for first plane and enable it | ||
1655 | * 6. enable LCD panel | ||
1656 | * 7. register sysfs attributes | ||
1657 | * OMAPFB_ACTIVE: register system fb_info structure for all planes | ||
1658 | */ | ||
1659 | static int omapfb_do_probe(struct platform_device *pdev, | ||
1660 | struct lcd_panel *panel) | ||
1661 | { | ||
1662 | struct omapfb_device *fbdev = NULL; | ||
1663 | int init_state; | ||
1664 | unsigned long phz, hhz, vhz; | ||
1665 | unsigned long vram; | ||
1666 | int i; | ||
1667 | int r = 0; | ||
1668 | |||
1669 | init_state = 0; | ||
1670 | |||
1671 | if (pdev->num_resources != 0) { | ||
1672 | dev_err(&pdev->dev, "probed for an unknown device\n"); | ||
1673 | r = -ENODEV; | ||
1674 | goto cleanup; | ||
1675 | } | ||
1676 | |||
1677 | if (dev_get_platdata(&pdev->dev) == NULL) { | ||
1678 | dev_err(&pdev->dev, "missing platform data\n"); | ||
1679 | r = -ENOENT; | ||
1680 | goto cleanup; | ||
1681 | } | ||
1682 | |||
1683 | fbdev = kzalloc(sizeof(struct omapfb_device), GFP_KERNEL); | ||
1684 | if (fbdev == NULL) { | ||
1685 | dev_err(&pdev->dev, | ||
1686 | "unable to allocate memory for device info\n"); | ||
1687 | r = -ENOMEM; | ||
1688 | goto cleanup; | ||
1689 | } | ||
1690 | init_state++; | ||
1691 | |||
1692 | fbdev->dev = &pdev->dev; | ||
1693 | fbdev->panel = panel; | ||
1694 | fbdev->dssdev = &omapdss_device; | ||
1695 | platform_set_drvdata(pdev, fbdev); | ||
1696 | |||
1697 | mutex_init(&fbdev->rqueue_mutex); | ||
1698 | |||
1699 | fbdev->int_ctrl = &omap1_int_ctrl; | ||
1700 | #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL | ||
1701 | fbdev->ext_if = &omap1_ext_if; | ||
1702 | #endif | ||
1703 | if (omapfb_find_ctrl(fbdev) < 0) { | ||
1704 | dev_err(fbdev->dev, | ||
1705 | "LCD controller not found, board not supported\n"); | ||
1706 | r = -ENODEV; | ||
1707 | goto cleanup; | ||
1708 | } | ||
1709 | |||
1710 | r = fbdev->panel->init(fbdev->panel, fbdev); | ||
1711 | if (r) | ||
1712 | goto cleanup; | ||
1713 | |||
1714 | pr_info("omapfb: configured for panel %s\n", fbdev->panel->name); | ||
1715 | |||
1716 | def_vxres = def_vxres ? def_vxres : fbdev->panel->x_res; | ||
1717 | def_vyres = def_vyres ? def_vyres : fbdev->panel->y_res; | ||
1718 | |||
1719 | init_state++; | ||
1720 | |||
1721 | r = ctrl_init(fbdev); | ||
1722 | if (r) | ||
1723 | goto cleanup; | ||
1724 | if (fbdev->ctrl->mmap != NULL) | ||
1725 | omapfb_ops.fb_mmap = omapfb_mmap; | ||
1726 | init_state++; | ||
1727 | |||
1728 | check_required_callbacks(fbdev); | ||
1729 | |||
1730 | r = planes_init(fbdev); | ||
1731 | if (r) | ||
1732 | goto cleanup; | ||
1733 | init_state++; | ||
1734 | |||
1735 | #ifdef CONFIG_FB_OMAP_DMA_TUNE | ||
1736 | /* Set DMA priority for EMIFF access to highest */ | ||
1737 | omap_set_dma_priority(0, OMAP_DMA_PORT_EMIFF, 15); | ||
1738 | #endif | ||
1739 | |||
1740 | r = ctrl_change_mode(fbdev->fb_info[0]); | ||
1741 | if (r) { | ||
1742 | dev_err(fbdev->dev, "mode setting failed\n"); | ||
1743 | goto cleanup; | ||
1744 | } | ||
1745 | |||
1746 | /* GFX plane is enabled by default */ | ||
1747 | r = fbdev->ctrl->enable_plane(OMAPFB_PLANE_GFX, 1); | ||
1748 | if (r) | ||
1749 | goto cleanup; | ||
1750 | |||
1751 | omapfb_set_update_mode(fbdev, manual_update ? | ||
1752 | OMAPFB_MANUAL_UPDATE : OMAPFB_AUTO_UPDATE); | ||
1753 | init_state++; | ||
1754 | |||
1755 | r = fbdev->panel->enable(fbdev->panel); | ||
1756 | if (r) | ||
1757 | goto cleanup; | ||
1758 | init_state++; | ||
1759 | |||
1760 | r = omapfb_register_sysfs(fbdev); | ||
1761 | if (r) | ||
1762 | goto cleanup; | ||
1763 | init_state++; | ||
1764 | |||
1765 | vram = 0; | ||
1766 | for (i = 0; i < fbdev->mem_desc.region_cnt; i++) { | ||
1767 | r = register_framebuffer(fbdev->fb_info[i]); | ||
1768 | if (r != 0) { | ||
1769 | dev_err(fbdev->dev, | ||
1770 | "registering framebuffer %d failed\n", i); | ||
1771 | goto cleanup; | ||
1772 | } | ||
1773 | vram += fbdev->mem_desc.region[i].size; | ||
1774 | } | ||
1775 | |||
1776 | fbdev->state = OMAPFB_ACTIVE; | ||
1777 | |||
1778 | panel = fbdev->panel; | ||
1779 | phz = panel->pixel_clock * 1000; | ||
1780 | hhz = phz * 10 / (panel->hfp + panel->x_res + panel->hbp + panel->hsw); | ||
1781 | vhz = hhz / (panel->vfp + panel->y_res + panel->vbp + panel->vsw); | ||
1782 | |||
1783 | omapfb_dev = fbdev; | ||
1784 | |||
1785 | pr_info("omapfb: Framebuffer initialized. Total vram %lu planes %d\n", | ||
1786 | vram, fbdev->mem_desc.region_cnt); | ||
1787 | pr_info("omapfb: Pixclock %lu kHz hfreq %lu.%lu kHz " | ||
1788 | "vfreq %lu.%lu Hz\n", | ||
1789 | phz / 1000, hhz / 10000, hhz % 10, vhz / 10, vhz % 10); | ||
1790 | |||
1791 | return 0; | ||
1792 | |||
1793 | cleanup: | ||
1794 | omapfb_free_resources(fbdev, init_state); | ||
1795 | |||
1796 | return r; | ||
1797 | } | ||
1798 | |||
1799 | static int omapfb_probe(struct platform_device *pdev) | ||
1800 | { | ||
1801 | int r; | ||
1802 | |||
1803 | BUG_ON(fbdev_pdev != NULL); | ||
1804 | |||
1805 | r = platform_device_register(&omapdss_device); | ||
1806 | if (r) { | ||
1807 | dev_err(&pdev->dev, "can't register omapdss device\n"); | ||
1808 | return r; | ||
1809 | } | ||
1810 | |||
1811 | /* Delay actual initialization until the LCD is registered */ | ||
1812 | fbdev_pdev = pdev; | ||
1813 | if (fbdev_panel != NULL) | ||
1814 | omapfb_do_probe(fbdev_pdev, fbdev_panel); | ||
1815 | return 0; | ||
1816 | } | ||
1817 | |||
1818 | void omapfb_register_panel(struct lcd_panel *panel) | ||
1819 | { | ||
1820 | BUG_ON(fbdev_panel != NULL); | ||
1821 | |||
1822 | fbdev_panel = panel; | ||
1823 | if (fbdev_pdev != NULL) | ||
1824 | omapfb_do_probe(fbdev_pdev, fbdev_panel); | ||
1825 | } | ||
1826 | |||
1827 | /* Called when the device is being detached from the driver */ | ||
1828 | static int omapfb_remove(struct platform_device *pdev) | ||
1829 | { | ||
1830 | struct omapfb_device *fbdev = platform_get_drvdata(pdev); | ||
1831 | enum omapfb_state saved_state = fbdev->state; | ||
1832 | |||
1833 | /* FIXME: wait till completion of pending events */ | ||
1834 | |||
1835 | fbdev->state = OMAPFB_DISABLED; | ||
1836 | omapfb_free_resources(fbdev, saved_state); | ||
1837 | |||
1838 | platform_device_unregister(&omapdss_device); | ||
1839 | fbdev->dssdev = NULL; | ||
1840 | |||
1841 | return 0; | ||
1842 | } | ||
1843 | |||
1844 | /* PM suspend */ | ||
1845 | static int omapfb_suspend(struct platform_device *pdev, pm_message_t mesg) | ||
1846 | { | ||
1847 | struct omapfb_device *fbdev = platform_get_drvdata(pdev); | ||
1848 | |||
1849 | if (fbdev != NULL) | ||
1850 | omapfb_blank(FB_BLANK_POWERDOWN, fbdev->fb_info[0]); | ||
1851 | return 0; | ||
1852 | } | ||
1853 | |||
1854 | /* PM resume */ | ||
1855 | static int omapfb_resume(struct platform_device *pdev) | ||
1856 | { | ||
1857 | struct omapfb_device *fbdev = platform_get_drvdata(pdev); | ||
1858 | |||
1859 | if (fbdev != NULL) | ||
1860 | omapfb_blank(FB_BLANK_UNBLANK, fbdev->fb_info[0]); | ||
1861 | return 0; | ||
1862 | } | ||
1863 | |||
1864 | static struct platform_driver omapfb_driver = { | ||
1865 | .probe = omapfb_probe, | ||
1866 | .remove = omapfb_remove, | ||
1867 | .suspend = omapfb_suspend, | ||
1868 | .resume = omapfb_resume, | ||
1869 | .driver = { | ||
1870 | .name = MODULE_NAME, | ||
1871 | .owner = THIS_MODULE, | ||
1872 | }, | ||
1873 | }; | ||
1874 | |||
1875 | #ifndef MODULE | ||
1876 | |||
1877 | /* Process kernel command line parameters */ | ||
1878 | static int __init omapfb_setup(char *options) | ||
1879 | { | ||
1880 | char *this_opt = NULL; | ||
1881 | int r = 0; | ||
1882 | |||
1883 | pr_debug("omapfb: options %s\n", options); | ||
1884 | |||
1885 | if (!options || !*options) | ||
1886 | return 0; | ||
1887 | |||
1888 | while (!r && (this_opt = strsep(&options, ",")) != NULL) { | ||
1889 | if (!strncmp(this_opt, "accel", 5)) | ||
1890 | def_accel = 1; | ||
1891 | else if (!strncmp(this_opt, "vram:", 5)) { | ||
1892 | char *suffix; | ||
1893 | unsigned long vram; | ||
1894 | vram = (simple_strtoul(this_opt + 5, &suffix, 0)); | ||
1895 | switch (suffix[0]) { | ||
1896 | case '\0': | ||
1897 | break; | ||
1898 | case 'm': | ||
1899 | case 'M': | ||
1900 | vram *= 1024; | ||
1901 | /* Fall through */ | ||
1902 | case 'k': | ||
1903 | case 'K': | ||
1904 | vram *= 1024; | ||
1905 | break; | ||
1906 | default: | ||
1907 | pr_debug("omapfb: invalid vram suffix %c\n", | ||
1908 | suffix[0]); | ||
1909 | r = -1; | ||
1910 | } | ||
1911 | def_vram[def_vram_cnt++] = vram; | ||
1912 | } | ||
1913 | else if (!strncmp(this_opt, "vxres:", 6)) | ||
1914 | def_vxres = simple_strtoul(this_opt + 6, NULL, 0); | ||
1915 | else if (!strncmp(this_opt, "vyres:", 6)) | ||
1916 | def_vyres = simple_strtoul(this_opt + 6, NULL, 0); | ||
1917 | else if (!strncmp(this_opt, "rotate:", 7)) | ||
1918 | def_rotate = (simple_strtoul(this_opt + 7, NULL, 0)); | ||
1919 | else if (!strncmp(this_opt, "mirror:", 7)) | ||
1920 | def_mirror = (simple_strtoul(this_opt + 7, NULL, 0)); | ||
1921 | else if (!strncmp(this_opt, "manual_update", 13)) | ||
1922 | manual_update = 1; | ||
1923 | else { | ||
1924 | pr_debug("omapfb: invalid option\n"); | ||
1925 | r = -1; | ||
1926 | } | ||
1927 | } | ||
1928 | |||
1929 | return r; | ||
1930 | } | ||
1931 | |||
1932 | #endif | ||
1933 | |||
1934 | /* Register both the driver and the device */ | ||
1935 | static int __init omapfb_init(void) | ||
1936 | { | ||
1937 | #ifndef MODULE | ||
1938 | char *option; | ||
1939 | |||
1940 | if (fb_get_options("omapfb", &option)) | ||
1941 | return -ENODEV; | ||
1942 | omapfb_setup(option); | ||
1943 | #endif | ||
1944 | /* Register the driver with LDM */ | ||
1945 | if (platform_driver_register(&omapfb_driver)) { | ||
1946 | pr_debug("failed to register omapfb driver\n"); | ||
1947 | return -ENODEV; | ||
1948 | } | ||
1949 | |||
1950 | return 0; | ||
1951 | } | ||
1952 | |||
1953 | static void __exit omapfb_cleanup(void) | ||
1954 | { | ||
1955 | platform_driver_unregister(&omapfb_driver); | ||
1956 | } | ||
1957 | |||
1958 | module_param_named(accel, def_accel, uint, 0664); | ||
1959 | module_param_array_named(vram, def_vram, ulong, &def_vram_cnt, 0664); | ||
1960 | module_param_named(vxres, def_vxres, long, 0664); | ||
1961 | module_param_named(vyres, def_vyres, long, 0664); | ||
1962 | module_param_named(rotate, def_rotate, uint, 0664); | ||
1963 | module_param_named(mirror, def_mirror, uint, 0664); | ||
1964 | module_param_named(manual_update, manual_update, bool, 0664); | ||
1965 | |||
1966 | module_init(omapfb_init); | ||
1967 | module_exit(omapfb_cleanup); | ||
1968 | |||
1969 | MODULE_DESCRIPTION("TI OMAP framebuffer driver"); | ||
1970 | MODULE_AUTHOR("Imre Deak <imre.deak@nokia.com>"); | ||
1971 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap/sossi.c b/drivers/video/omap/sossi.c deleted file mode 100644 index d4e7684e7045..000000000000 --- a/drivers/video/omap/sossi.c +++ /dev/null | |||
@@ -1,693 +0,0 @@ | |||
1 | /* | ||
2 | * OMAP1 Special OptimiSed Screen Interface support | ||
3 | * | ||
4 | * Copyright (C) 2004-2005 Nokia Corporation | ||
5 | * Author: Juha Yrjölä <juha.yrjola@nokia.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/mm.h> | ||
23 | #include <linux/clk.h> | ||
24 | #include <linux/irq.h> | ||
25 | #include <linux/io.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | |||
28 | #include <linux/omap-dma.h> | ||
29 | |||
30 | #include "omapfb.h" | ||
31 | #include "lcdc.h" | ||
32 | |||
33 | #define MODULE_NAME "omapfb-sossi" | ||
34 | |||
35 | #define OMAP_SOSSI_BASE 0xfffbac00 | ||
36 | #define SOSSI_ID_REG 0x00 | ||
37 | #define SOSSI_INIT1_REG 0x04 | ||
38 | #define SOSSI_INIT2_REG 0x08 | ||
39 | #define SOSSI_INIT3_REG 0x0c | ||
40 | #define SOSSI_FIFO_REG 0x10 | ||
41 | #define SOSSI_REOTABLE_REG 0x14 | ||
42 | #define SOSSI_TEARING_REG 0x18 | ||
43 | #define SOSSI_INIT1B_REG 0x1c | ||
44 | #define SOSSI_FIFOB_REG 0x20 | ||
45 | |||
46 | #define DMA_GSCR 0xfffedc04 | ||
47 | #define DMA_LCD_CCR 0xfffee3c2 | ||
48 | #define DMA_LCD_CTRL 0xfffee3c4 | ||
49 | #define DMA_LCD_LCH_CTRL 0xfffee3ea | ||
50 | |||
51 | #define CONF_SOSSI_RESET_R (1 << 23) | ||
52 | |||
53 | #define RD_ACCESS 0 | ||
54 | #define WR_ACCESS 1 | ||
55 | |||
56 | #define SOSSI_MAX_XMIT_BYTES (512 * 1024) | ||
57 | |||
58 | static struct { | ||
59 | void __iomem *base; | ||
60 | struct clk *fck; | ||
61 | unsigned long fck_hz; | ||
62 | spinlock_t lock; | ||
63 | int bus_pick_count; | ||
64 | int bus_pick_width; | ||
65 | int tearsync_mode; | ||
66 | int tearsync_line; | ||
67 | void (*lcdc_callback)(void *data); | ||
68 | void *lcdc_callback_data; | ||
69 | int vsync_dma_pending; | ||
70 | /* timing for read and write access */ | ||
71 | int clk_div; | ||
72 | u8 clk_tw0[2]; | ||
73 | u8 clk_tw1[2]; | ||
74 | /* | ||
75 | * if last_access is the same as current we don't have to change | ||
76 | * the timings | ||
77 | */ | ||
78 | int last_access; | ||
79 | |||
80 | struct omapfb_device *fbdev; | ||
81 | } sossi; | ||
82 | |||
83 | static inline u32 sossi_read_reg(int reg) | ||
84 | { | ||
85 | return readl(sossi.base + reg); | ||
86 | } | ||
87 | |||
88 | static inline u16 sossi_read_reg16(int reg) | ||
89 | { | ||
90 | return readw(sossi.base + reg); | ||
91 | } | ||
92 | |||
93 | static inline u8 sossi_read_reg8(int reg) | ||
94 | { | ||
95 | return readb(sossi.base + reg); | ||
96 | } | ||
97 | |||
98 | static inline void sossi_write_reg(int reg, u32 value) | ||
99 | { | ||
100 | writel(value, sossi.base + reg); | ||
101 | } | ||
102 | |||
103 | static inline void sossi_write_reg16(int reg, u16 value) | ||
104 | { | ||
105 | writew(value, sossi.base + reg); | ||
106 | } | ||
107 | |||
108 | static inline void sossi_write_reg8(int reg, u8 value) | ||
109 | { | ||
110 | writeb(value, sossi.base + reg); | ||
111 | } | ||
112 | |||
113 | static void sossi_set_bits(int reg, u32 bits) | ||
114 | { | ||
115 | sossi_write_reg(reg, sossi_read_reg(reg) | bits); | ||
116 | } | ||
117 | |||
118 | static void sossi_clear_bits(int reg, u32 bits) | ||
119 | { | ||
120 | sossi_write_reg(reg, sossi_read_reg(reg) & ~bits); | ||
121 | } | ||
122 | |||
123 | #define HZ_TO_PS(x) (1000000000 / (x / 1000)) | ||
124 | |||
125 | static u32 ps_to_sossi_ticks(u32 ps, int div) | ||
126 | { | ||
127 | u32 clk_period = HZ_TO_PS(sossi.fck_hz) * div; | ||
128 | return (clk_period + ps - 1) / clk_period; | ||
129 | } | ||
130 | |||
131 | static int calc_rd_timings(struct extif_timings *t) | ||
132 | { | ||
133 | u32 tw0, tw1; | ||
134 | int reon, reoff, recyc, actim; | ||
135 | int div = t->clk_div; | ||
136 | |||
137 | /* | ||
138 | * Make sure that after conversion it still holds that: | ||
139 | * reoff > reon, recyc >= reoff, actim > reon | ||
140 | */ | ||
141 | reon = ps_to_sossi_ticks(t->re_on_time, div); | ||
142 | /* reon will be exactly one sossi tick */ | ||
143 | if (reon > 1) | ||
144 | return -1; | ||
145 | |||
146 | reoff = ps_to_sossi_ticks(t->re_off_time, div); | ||
147 | |||
148 | if (reoff <= reon) | ||
149 | reoff = reon + 1; | ||
150 | |||
151 | tw0 = reoff - reon; | ||
152 | if (tw0 > 0x10) | ||
153 | return -1; | ||
154 | |||
155 | recyc = ps_to_sossi_ticks(t->re_cycle_time, div); | ||
156 | if (recyc <= reoff) | ||
157 | recyc = reoff + 1; | ||
158 | |||
159 | tw1 = recyc - tw0; | ||
160 | /* values less then 3 result in the SOSSI block resetting itself */ | ||
161 | if (tw1 < 3) | ||
162 | tw1 = 3; | ||
163 | if (tw1 > 0x40) | ||
164 | return -1; | ||
165 | |||
166 | actim = ps_to_sossi_ticks(t->access_time, div); | ||
167 | if (actim < reoff) | ||
168 | actim++; | ||
169 | /* | ||
170 | * access time (data hold time) will be exactly one sossi | ||
171 | * tick | ||
172 | */ | ||
173 | if (actim - reoff > 1) | ||
174 | return -1; | ||
175 | |||
176 | t->tim[0] = tw0 - 1; | ||
177 | t->tim[1] = tw1 - 1; | ||
178 | |||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | static int calc_wr_timings(struct extif_timings *t) | ||
183 | { | ||
184 | u32 tw0, tw1; | ||
185 | int weon, weoff, wecyc; | ||
186 | int div = t->clk_div; | ||
187 | |||
188 | /* | ||
189 | * Make sure that after conversion it still holds that: | ||
190 | * weoff > weon, wecyc >= weoff | ||
191 | */ | ||
192 | weon = ps_to_sossi_ticks(t->we_on_time, div); | ||
193 | /* weon will be exactly one sossi tick */ | ||
194 | if (weon > 1) | ||
195 | return -1; | ||
196 | |||
197 | weoff = ps_to_sossi_ticks(t->we_off_time, div); | ||
198 | if (weoff <= weon) | ||
199 | weoff = weon + 1; | ||
200 | tw0 = weoff - weon; | ||
201 | if (tw0 > 0x10) | ||
202 | return -1; | ||
203 | |||
204 | wecyc = ps_to_sossi_ticks(t->we_cycle_time, div); | ||
205 | if (wecyc <= weoff) | ||
206 | wecyc = weoff + 1; | ||
207 | |||
208 | tw1 = wecyc - tw0; | ||
209 | /* values less then 3 result in the SOSSI block resetting itself */ | ||
210 | if (tw1 < 3) | ||
211 | tw1 = 3; | ||
212 | if (tw1 > 0x40) | ||
213 | return -1; | ||
214 | |||
215 | t->tim[2] = tw0 - 1; | ||
216 | t->tim[3] = tw1 - 1; | ||
217 | |||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | static void _set_timing(int div, int tw0, int tw1) | ||
222 | { | ||
223 | u32 l; | ||
224 | |||
225 | #ifdef VERBOSE | ||
226 | dev_dbg(sossi.fbdev->dev, "Using TW0 = %d, TW1 = %d, div = %d\n", | ||
227 | tw0 + 1, tw1 + 1, div); | ||
228 | #endif | ||
229 | |||
230 | clk_set_rate(sossi.fck, sossi.fck_hz / div); | ||
231 | clk_enable(sossi.fck); | ||
232 | l = sossi_read_reg(SOSSI_INIT1_REG); | ||
233 | l &= ~((0x0f << 20) | (0x3f << 24)); | ||
234 | l |= (tw0 << 20) | (tw1 << 24); | ||
235 | sossi_write_reg(SOSSI_INIT1_REG, l); | ||
236 | clk_disable(sossi.fck); | ||
237 | } | ||
238 | |||
239 | static void _set_bits_per_cycle(int bus_pick_count, int bus_pick_width) | ||
240 | { | ||
241 | u32 l; | ||
242 | |||
243 | l = sossi_read_reg(SOSSI_INIT3_REG); | ||
244 | l &= ~0x3ff; | ||
245 | l |= ((bus_pick_count - 1) << 5) | ((bus_pick_width - 1) & 0x1f); | ||
246 | sossi_write_reg(SOSSI_INIT3_REG, l); | ||
247 | } | ||
248 | |||
249 | static void _set_tearsync_mode(int mode, unsigned line) | ||
250 | { | ||
251 | u32 l; | ||
252 | |||
253 | l = sossi_read_reg(SOSSI_TEARING_REG); | ||
254 | l &= ~(((1 << 11) - 1) << 15); | ||
255 | l |= line << 15; | ||
256 | l &= ~(0x3 << 26); | ||
257 | l |= mode << 26; | ||
258 | sossi_write_reg(SOSSI_TEARING_REG, l); | ||
259 | if (mode) | ||
260 | sossi_set_bits(SOSSI_INIT2_REG, 1 << 6); /* TE logic */ | ||
261 | else | ||
262 | sossi_clear_bits(SOSSI_INIT2_REG, 1 << 6); | ||
263 | } | ||
264 | |||
265 | static inline void set_timing(int access) | ||
266 | { | ||
267 | if (access != sossi.last_access) { | ||
268 | sossi.last_access = access; | ||
269 | _set_timing(sossi.clk_div, | ||
270 | sossi.clk_tw0[access], sossi.clk_tw1[access]); | ||
271 | } | ||
272 | } | ||
273 | |||
274 | static void sossi_start_transfer(void) | ||
275 | { | ||
276 | /* WE */ | ||
277 | sossi_clear_bits(SOSSI_INIT2_REG, 1 << 4); | ||
278 | /* CS active low */ | ||
279 | sossi_clear_bits(SOSSI_INIT1_REG, 1 << 30); | ||
280 | } | ||
281 | |||
282 | static void sossi_stop_transfer(void) | ||
283 | { | ||
284 | /* WE */ | ||
285 | sossi_set_bits(SOSSI_INIT2_REG, 1 << 4); | ||
286 | /* CS active low */ | ||
287 | sossi_set_bits(SOSSI_INIT1_REG, 1 << 30); | ||
288 | } | ||
289 | |||
290 | static void wait_end_of_write(void) | ||
291 | { | ||
292 | /* Before reading we must check if some writings are going on */ | ||
293 | while (!(sossi_read_reg(SOSSI_INIT2_REG) & (1 << 3))); | ||
294 | } | ||
295 | |||
296 | static void send_data(const void *data, unsigned int len) | ||
297 | { | ||
298 | while (len >= 4) { | ||
299 | sossi_write_reg(SOSSI_FIFO_REG, *(const u32 *) data); | ||
300 | len -= 4; | ||
301 | data += 4; | ||
302 | } | ||
303 | while (len >= 2) { | ||
304 | sossi_write_reg16(SOSSI_FIFO_REG, *(const u16 *) data); | ||
305 | len -= 2; | ||
306 | data += 2; | ||
307 | } | ||
308 | while (len) { | ||
309 | sossi_write_reg8(SOSSI_FIFO_REG, *(const u8 *) data); | ||
310 | len--; | ||
311 | data++; | ||
312 | } | ||
313 | } | ||
314 | |||
315 | static void set_cycles(unsigned int len) | ||
316 | { | ||
317 | unsigned long nr_cycles = len / (sossi.bus_pick_width / 8); | ||
318 | |||
319 | BUG_ON((nr_cycles - 1) & ~0x3ffff); | ||
320 | |||
321 | sossi_clear_bits(SOSSI_INIT1_REG, 0x3ffff); | ||
322 | sossi_set_bits(SOSSI_INIT1_REG, (nr_cycles - 1) & 0x3ffff); | ||
323 | } | ||
324 | |||
325 | static int sossi_convert_timings(struct extif_timings *t) | ||
326 | { | ||
327 | int r = 0; | ||
328 | int div = t->clk_div; | ||
329 | |||
330 | t->converted = 0; | ||
331 | |||
332 | if (div <= 0 || div > 8) | ||
333 | return -1; | ||
334 | |||
335 | /* no CS on SOSSI, so ignore cson, csoff, cs_pulsewidth */ | ||
336 | if ((r = calc_rd_timings(t)) < 0) | ||
337 | return r; | ||
338 | |||
339 | if ((r = calc_wr_timings(t)) < 0) | ||
340 | return r; | ||
341 | |||
342 | t->tim[4] = div; | ||
343 | |||
344 | t->converted = 1; | ||
345 | |||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | static void sossi_set_timings(const struct extif_timings *t) | ||
350 | { | ||
351 | BUG_ON(!t->converted); | ||
352 | |||
353 | sossi.clk_tw0[RD_ACCESS] = t->tim[0]; | ||
354 | sossi.clk_tw1[RD_ACCESS] = t->tim[1]; | ||
355 | |||
356 | sossi.clk_tw0[WR_ACCESS] = t->tim[2]; | ||
357 | sossi.clk_tw1[WR_ACCESS] = t->tim[3]; | ||
358 | |||
359 | sossi.clk_div = t->tim[4]; | ||
360 | } | ||
361 | |||
362 | static void sossi_get_clk_info(u32 *clk_period, u32 *max_clk_div) | ||
363 | { | ||
364 | *clk_period = HZ_TO_PS(sossi.fck_hz); | ||
365 | *max_clk_div = 8; | ||
366 | } | ||
367 | |||
368 | static void sossi_set_bits_per_cycle(int bpc) | ||
369 | { | ||
370 | int bus_pick_count, bus_pick_width; | ||
371 | |||
372 | /* | ||
373 | * We set explicitly the the bus_pick_count as well, although | ||
374 | * with remapping/reordering disabled it will be calculated by HW | ||
375 | * as (32 / bus_pick_width). | ||
376 | */ | ||
377 | switch (bpc) { | ||
378 | case 8: | ||
379 | bus_pick_count = 4; | ||
380 | bus_pick_width = 8; | ||
381 | break; | ||
382 | case 16: | ||
383 | bus_pick_count = 2; | ||
384 | bus_pick_width = 16; | ||
385 | break; | ||
386 | default: | ||
387 | BUG(); | ||
388 | return; | ||
389 | } | ||
390 | sossi.bus_pick_width = bus_pick_width; | ||
391 | sossi.bus_pick_count = bus_pick_count; | ||
392 | } | ||
393 | |||
394 | static int sossi_setup_tearsync(unsigned pin_cnt, | ||
395 | unsigned hs_pulse_time, unsigned vs_pulse_time, | ||
396 | int hs_pol_inv, int vs_pol_inv, int div) | ||
397 | { | ||
398 | int hs, vs; | ||
399 | u32 l; | ||
400 | |||
401 | if (pin_cnt != 1 || div < 1 || div > 8) | ||
402 | return -EINVAL; | ||
403 | |||
404 | hs = ps_to_sossi_ticks(hs_pulse_time, div); | ||
405 | vs = ps_to_sossi_ticks(vs_pulse_time, div); | ||
406 | if (vs < 8 || vs <= hs || vs >= (1 << 12)) | ||
407 | return -EDOM; | ||
408 | vs /= 8; | ||
409 | vs--; | ||
410 | if (hs > 8) | ||
411 | hs = 8; | ||
412 | if (hs) | ||
413 | hs--; | ||
414 | |||
415 | dev_dbg(sossi.fbdev->dev, | ||
416 | "setup_tearsync: hs %d vs %d hs_inv %d vs_inv %d\n", | ||
417 | hs, vs, hs_pol_inv, vs_pol_inv); | ||
418 | |||
419 | clk_enable(sossi.fck); | ||
420 | l = sossi_read_reg(SOSSI_TEARING_REG); | ||
421 | l &= ~((1 << 15) - 1); | ||
422 | l |= vs << 3; | ||
423 | l |= hs; | ||
424 | if (hs_pol_inv) | ||
425 | l |= 1 << 29; | ||
426 | else | ||
427 | l &= ~(1 << 29); | ||
428 | if (vs_pol_inv) | ||
429 | l |= 1 << 28; | ||
430 | else | ||
431 | l &= ~(1 << 28); | ||
432 | sossi_write_reg(SOSSI_TEARING_REG, l); | ||
433 | clk_disable(sossi.fck); | ||
434 | |||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | static int sossi_enable_tearsync(int enable, unsigned line) | ||
439 | { | ||
440 | int mode; | ||
441 | |||
442 | dev_dbg(sossi.fbdev->dev, "tearsync %d line %d\n", enable, line); | ||
443 | if (line >= 1 << 11) | ||
444 | return -EINVAL; | ||
445 | if (enable) { | ||
446 | if (line) | ||
447 | mode = 2; /* HS or VS */ | ||
448 | else | ||
449 | mode = 3; /* VS only */ | ||
450 | } else | ||
451 | mode = 0; | ||
452 | sossi.tearsync_line = line; | ||
453 | sossi.tearsync_mode = mode; | ||
454 | |||
455 | return 0; | ||
456 | } | ||
457 | |||
458 | static void sossi_write_command(const void *data, unsigned int len) | ||
459 | { | ||
460 | clk_enable(sossi.fck); | ||
461 | set_timing(WR_ACCESS); | ||
462 | _set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width); | ||
463 | /* CMD#/DATA */ | ||
464 | sossi_clear_bits(SOSSI_INIT1_REG, 1 << 18); | ||
465 | set_cycles(len); | ||
466 | sossi_start_transfer(); | ||
467 | send_data(data, len); | ||
468 | sossi_stop_transfer(); | ||
469 | wait_end_of_write(); | ||
470 | clk_disable(sossi.fck); | ||
471 | } | ||
472 | |||
473 | static void sossi_write_data(const void *data, unsigned int len) | ||
474 | { | ||
475 | clk_enable(sossi.fck); | ||
476 | set_timing(WR_ACCESS); | ||
477 | _set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width); | ||
478 | /* CMD#/DATA */ | ||
479 | sossi_set_bits(SOSSI_INIT1_REG, 1 << 18); | ||
480 | set_cycles(len); | ||
481 | sossi_start_transfer(); | ||
482 | send_data(data, len); | ||
483 | sossi_stop_transfer(); | ||
484 | wait_end_of_write(); | ||
485 | clk_disable(sossi.fck); | ||
486 | } | ||
487 | |||
488 | static void sossi_transfer_area(int width, int height, | ||
489 | void (callback)(void *data), void *data) | ||
490 | { | ||
491 | BUG_ON(callback == NULL); | ||
492 | |||
493 | sossi.lcdc_callback = callback; | ||
494 | sossi.lcdc_callback_data = data; | ||
495 | |||
496 | clk_enable(sossi.fck); | ||
497 | set_timing(WR_ACCESS); | ||
498 | _set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width); | ||
499 | _set_tearsync_mode(sossi.tearsync_mode, sossi.tearsync_line); | ||
500 | /* CMD#/DATA */ | ||
501 | sossi_set_bits(SOSSI_INIT1_REG, 1 << 18); | ||
502 | set_cycles(width * height * sossi.bus_pick_width / 8); | ||
503 | |||
504 | sossi_start_transfer(); | ||
505 | if (sossi.tearsync_mode) { | ||
506 | /* | ||
507 | * Wait for the sync signal and start the transfer only | ||
508 | * then. We can't seem to be able to use HW sync DMA for | ||
509 | * this since LCD DMA shows huge latencies, as if it | ||
510 | * would ignore some of the DMA requests from SoSSI. | ||
511 | */ | ||
512 | unsigned long flags; | ||
513 | |||
514 | spin_lock_irqsave(&sossi.lock, flags); | ||
515 | sossi.vsync_dma_pending++; | ||
516 | spin_unlock_irqrestore(&sossi.lock, flags); | ||
517 | } else | ||
518 | /* Just start the transfer right away. */ | ||
519 | omap_enable_lcd_dma(); | ||
520 | } | ||
521 | |||
522 | static void sossi_dma_callback(void *data) | ||
523 | { | ||
524 | omap_stop_lcd_dma(); | ||
525 | sossi_stop_transfer(); | ||
526 | clk_disable(sossi.fck); | ||
527 | sossi.lcdc_callback(sossi.lcdc_callback_data); | ||
528 | } | ||
529 | |||
530 | static void sossi_read_data(void *data, unsigned int len) | ||
531 | { | ||
532 | clk_enable(sossi.fck); | ||
533 | set_timing(RD_ACCESS); | ||
534 | _set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width); | ||
535 | /* CMD#/DATA */ | ||
536 | sossi_set_bits(SOSSI_INIT1_REG, 1 << 18); | ||
537 | set_cycles(len); | ||
538 | sossi_start_transfer(); | ||
539 | while (len >= 4) { | ||
540 | *(u32 *) data = sossi_read_reg(SOSSI_FIFO_REG); | ||
541 | len -= 4; | ||
542 | data += 4; | ||
543 | } | ||
544 | while (len >= 2) { | ||
545 | *(u16 *) data = sossi_read_reg16(SOSSI_FIFO_REG); | ||
546 | len -= 2; | ||
547 | data += 2; | ||
548 | } | ||
549 | while (len) { | ||
550 | *(u8 *) data = sossi_read_reg8(SOSSI_FIFO_REG); | ||
551 | len--; | ||
552 | data++; | ||
553 | } | ||
554 | sossi_stop_transfer(); | ||
555 | clk_disable(sossi.fck); | ||
556 | } | ||
557 | |||
558 | static irqreturn_t sossi_match_irq(int irq, void *data) | ||
559 | { | ||
560 | unsigned long flags; | ||
561 | |||
562 | spin_lock_irqsave(&sossi.lock, flags); | ||
563 | if (sossi.vsync_dma_pending) { | ||
564 | sossi.vsync_dma_pending--; | ||
565 | omap_enable_lcd_dma(); | ||
566 | } | ||
567 | spin_unlock_irqrestore(&sossi.lock, flags); | ||
568 | return IRQ_HANDLED; | ||
569 | } | ||
570 | |||
571 | static int sossi_init(struct omapfb_device *fbdev) | ||
572 | { | ||
573 | u32 l, k; | ||
574 | struct clk *fck; | ||
575 | struct clk *dpll1out_ck; | ||
576 | int r; | ||
577 | |||
578 | sossi.base = ioremap(OMAP_SOSSI_BASE, SZ_1K); | ||
579 | if (!sossi.base) { | ||
580 | dev_err(fbdev->dev, "can't ioremap SoSSI\n"); | ||
581 | return -ENOMEM; | ||
582 | } | ||
583 | |||
584 | sossi.fbdev = fbdev; | ||
585 | spin_lock_init(&sossi.lock); | ||
586 | |||
587 | dpll1out_ck = clk_get(fbdev->dev, "ck_dpll1out"); | ||
588 | if (IS_ERR(dpll1out_ck)) { | ||
589 | dev_err(fbdev->dev, "can't get DPLL1OUT clock\n"); | ||
590 | return PTR_ERR(dpll1out_ck); | ||
591 | } | ||
592 | /* | ||
593 | * We need the parent clock rate, which we might divide further | ||
594 | * depending on the timing requirements of the controller. See | ||
595 | * _set_timings. | ||
596 | */ | ||
597 | sossi.fck_hz = clk_get_rate(dpll1out_ck); | ||
598 | clk_put(dpll1out_ck); | ||
599 | |||
600 | fck = clk_get(fbdev->dev, "ck_sossi"); | ||
601 | if (IS_ERR(fck)) { | ||
602 | dev_err(fbdev->dev, "can't get SoSSI functional clock\n"); | ||
603 | return PTR_ERR(fck); | ||
604 | } | ||
605 | sossi.fck = fck; | ||
606 | |||
607 | /* Reset and enable the SoSSI module */ | ||
608 | l = omap_readl(MOD_CONF_CTRL_1); | ||
609 | l |= CONF_SOSSI_RESET_R; | ||
610 | omap_writel(l, MOD_CONF_CTRL_1); | ||
611 | l &= ~CONF_SOSSI_RESET_R; | ||
612 | omap_writel(l, MOD_CONF_CTRL_1); | ||
613 | |||
614 | clk_enable(sossi.fck); | ||
615 | l = omap_readl(ARM_IDLECT2); | ||
616 | l &= ~(1 << 8); /* DMACK_REQ */ | ||
617 | omap_writel(l, ARM_IDLECT2); | ||
618 | |||
619 | l = sossi_read_reg(SOSSI_INIT2_REG); | ||
620 | /* Enable and reset the SoSSI block */ | ||
621 | l |= (1 << 0) | (1 << 1); | ||
622 | sossi_write_reg(SOSSI_INIT2_REG, l); | ||
623 | /* Take SoSSI out of reset */ | ||
624 | l &= ~(1 << 1); | ||
625 | sossi_write_reg(SOSSI_INIT2_REG, l); | ||
626 | |||
627 | sossi_write_reg(SOSSI_ID_REG, 0); | ||
628 | l = sossi_read_reg(SOSSI_ID_REG); | ||
629 | k = sossi_read_reg(SOSSI_ID_REG); | ||
630 | |||
631 | if (l != 0x55555555 || k != 0xaaaaaaaa) { | ||
632 | dev_err(fbdev->dev, | ||
633 | "invalid SoSSI sync pattern: %08x, %08x\n", l, k); | ||
634 | r = -ENODEV; | ||
635 | goto err; | ||
636 | } | ||
637 | |||
638 | if ((r = omap_lcdc_set_dma_callback(sossi_dma_callback, NULL)) < 0) { | ||
639 | dev_err(fbdev->dev, "can't get LCDC IRQ\n"); | ||
640 | r = -ENODEV; | ||
641 | goto err; | ||
642 | } | ||
643 | |||
644 | l = sossi_read_reg(SOSSI_ID_REG); /* Component code */ | ||
645 | l = sossi_read_reg(SOSSI_ID_REG); | ||
646 | dev_info(fbdev->dev, "SoSSI version %d.%d initialized\n", | ||
647 | l >> 16, l & 0xffff); | ||
648 | |||
649 | l = sossi_read_reg(SOSSI_INIT1_REG); | ||
650 | l |= (1 << 19); /* DMA_MODE */ | ||
651 | l &= ~(1 << 31); /* REORDERING */ | ||
652 | sossi_write_reg(SOSSI_INIT1_REG, l); | ||
653 | |||
654 | if ((r = request_irq(INT_1610_SoSSI_MATCH, sossi_match_irq, | ||
655 | IRQ_TYPE_EDGE_FALLING, | ||
656 | "sossi_match", sossi.fbdev->dev)) < 0) { | ||
657 | dev_err(sossi.fbdev->dev, "can't get SoSSI match IRQ\n"); | ||
658 | goto err; | ||
659 | } | ||
660 | |||
661 | clk_disable(sossi.fck); | ||
662 | return 0; | ||
663 | |||
664 | err: | ||
665 | clk_disable(sossi.fck); | ||
666 | clk_put(sossi.fck); | ||
667 | return r; | ||
668 | } | ||
669 | |||
670 | static void sossi_cleanup(void) | ||
671 | { | ||
672 | omap_lcdc_free_dma_callback(); | ||
673 | clk_put(sossi.fck); | ||
674 | iounmap(sossi.base); | ||
675 | } | ||
676 | |||
677 | struct lcd_ctrl_extif omap1_ext_if = { | ||
678 | .init = sossi_init, | ||
679 | .cleanup = sossi_cleanup, | ||
680 | .get_clk_info = sossi_get_clk_info, | ||
681 | .convert_timings = sossi_convert_timings, | ||
682 | .set_timings = sossi_set_timings, | ||
683 | .set_bits_per_cycle = sossi_set_bits_per_cycle, | ||
684 | .setup_tearsync = sossi_setup_tearsync, | ||
685 | .enable_tearsync = sossi_enable_tearsync, | ||
686 | .write_command = sossi_write_command, | ||
687 | .read_data = sossi_read_data, | ||
688 | .write_data = sossi_write_data, | ||
689 | .transfer_area = sossi_transfer_area, | ||
690 | |||
691 | .max_transmit_size = SOSSI_MAX_XMIT_BYTES, | ||
692 | }; | ||
693 | |||