diff options
Diffstat (limited to 'drivers/video/fbdev/da8xx-fb.c')
-rw-r--r-- | drivers/video/fbdev/da8xx-fb.c | 1659 |
1 files changed, 1659 insertions, 0 deletions
diff --git a/drivers/video/fbdev/da8xx-fb.c b/drivers/video/fbdev/da8xx-fb.c new file mode 100644 index 000000000000..6b23508ff0a5 --- /dev/null +++ b/drivers/video/fbdev/da8xx-fb.c | |||
@@ -0,0 +1,1659 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008-2009 MontaVista Software Inc. | ||
3 | * Copyright (C) 2008-2009 Texas Instruments Inc | ||
4 | * | ||
5 | * Based on the LCD driver for TI Avalanche processors written by | ||
6 | * Ajay Singh and Shalom Hai. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option)any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/fb.h> | ||
25 | #include <linux/dma-mapping.h> | ||
26 | #include <linux/device.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/uaccess.h> | ||
29 | #include <linux/pm_runtime.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/wait.h> | ||
32 | #include <linux/clk.h> | ||
33 | #include <linux/cpufreq.h> | ||
34 | #include <linux/console.h> | ||
35 | #include <linux/spinlock.h> | ||
36 | #include <linux/slab.h> | ||
37 | #include <linux/delay.h> | ||
38 | #include <linux/lcm.h> | ||
39 | #include <video/da8xx-fb.h> | ||
40 | #include <asm/div64.h> | ||
41 | |||
42 | #define DRIVER_NAME "da8xx_lcdc" | ||
43 | |||
44 | #define LCD_VERSION_1 1 | ||
45 | #define LCD_VERSION_2 2 | ||
46 | |||
47 | /* LCD Status Register */ | ||
48 | #define LCD_END_OF_FRAME1 BIT(9) | ||
49 | #define LCD_END_OF_FRAME0 BIT(8) | ||
50 | #define LCD_PL_LOAD_DONE BIT(6) | ||
51 | #define LCD_FIFO_UNDERFLOW BIT(5) | ||
52 | #define LCD_SYNC_LOST BIT(2) | ||
53 | #define LCD_FRAME_DONE BIT(0) | ||
54 | |||
55 | /* LCD DMA Control Register */ | ||
56 | #define LCD_DMA_BURST_SIZE(x) ((x) << 4) | ||
57 | #define LCD_DMA_BURST_1 0x0 | ||
58 | #define LCD_DMA_BURST_2 0x1 | ||
59 | #define LCD_DMA_BURST_4 0x2 | ||
60 | #define LCD_DMA_BURST_8 0x3 | ||
61 | #define LCD_DMA_BURST_16 0x4 | ||
62 | #define LCD_V1_END_OF_FRAME_INT_ENA BIT(2) | ||
63 | #define LCD_V2_END_OF_FRAME0_INT_ENA BIT(8) | ||
64 | #define LCD_V2_END_OF_FRAME1_INT_ENA BIT(9) | ||
65 | #define LCD_DUAL_FRAME_BUFFER_ENABLE BIT(0) | ||
66 | |||
67 | /* LCD Control Register */ | ||
68 | #define LCD_CLK_DIVISOR(x) ((x) << 8) | ||
69 | #define LCD_RASTER_MODE 0x01 | ||
70 | |||
71 | /* LCD Raster Control Register */ | ||
72 | #define LCD_PALETTE_LOAD_MODE(x) ((x) << 20) | ||
73 | #define PALETTE_AND_DATA 0x00 | ||
74 | #define PALETTE_ONLY 0x01 | ||
75 | #define DATA_ONLY 0x02 | ||
76 | |||
77 | #define LCD_MONO_8BIT_MODE BIT(9) | ||
78 | #define LCD_RASTER_ORDER BIT(8) | ||
79 | #define LCD_TFT_MODE BIT(7) | ||
80 | #define LCD_V1_UNDERFLOW_INT_ENA BIT(6) | ||
81 | #define LCD_V2_UNDERFLOW_INT_ENA BIT(5) | ||
82 | #define LCD_V1_PL_INT_ENA BIT(4) | ||
83 | #define LCD_V2_PL_INT_ENA BIT(6) | ||
84 | #define LCD_MONOCHROME_MODE BIT(1) | ||
85 | #define LCD_RASTER_ENABLE BIT(0) | ||
86 | #define LCD_TFT_ALT_ENABLE BIT(23) | ||
87 | #define LCD_STN_565_ENABLE BIT(24) | ||
88 | #define LCD_V2_DMA_CLK_EN BIT(2) | ||
89 | #define LCD_V2_LIDD_CLK_EN BIT(1) | ||
90 | #define LCD_V2_CORE_CLK_EN BIT(0) | ||
91 | #define LCD_V2_LPP_B10 26 | ||
92 | #define LCD_V2_TFT_24BPP_MODE BIT(25) | ||
93 | #define LCD_V2_TFT_24BPP_UNPACK BIT(26) | ||
94 | |||
95 | /* LCD Raster Timing 2 Register */ | ||
96 | #define LCD_AC_BIAS_TRANSITIONS_PER_INT(x) ((x) << 16) | ||
97 | #define LCD_AC_BIAS_FREQUENCY(x) ((x) << 8) | ||
98 | #define LCD_SYNC_CTRL BIT(25) | ||
99 | #define LCD_SYNC_EDGE BIT(24) | ||
100 | #define LCD_INVERT_PIXEL_CLOCK BIT(22) | ||
101 | #define LCD_INVERT_LINE_CLOCK BIT(21) | ||
102 | #define LCD_INVERT_FRAME_CLOCK BIT(20) | ||
103 | |||
104 | /* LCD Block */ | ||
105 | #define LCD_PID_REG 0x0 | ||
106 | #define LCD_CTRL_REG 0x4 | ||
107 | #define LCD_STAT_REG 0x8 | ||
108 | #define LCD_RASTER_CTRL_REG 0x28 | ||
109 | #define LCD_RASTER_TIMING_0_REG 0x2C | ||
110 | #define LCD_RASTER_TIMING_1_REG 0x30 | ||
111 | #define LCD_RASTER_TIMING_2_REG 0x34 | ||
112 | #define LCD_DMA_CTRL_REG 0x40 | ||
113 | #define LCD_DMA_FRM_BUF_BASE_ADDR_0_REG 0x44 | ||
114 | #define LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG 0x48 | ||
115 | #define LCD_DMA_FRM_BUF_BASE_ADDR_1_REG 0x4C | ||
116 | #define LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG 0x50 | ||
117 | |||
118 | /* Interrupt Registers available only in Version 2 */ | ||
119 | #define LCD_RAW_STAT_REG 0x58 | ||
120 | #define LCD_MASKED_STAT_REG 0x5c | ||
121 | #define LCD_INT_ENABLE_SET_REG 0x60 | ||
122 | #define LCD_INT_ENABLE_CLR_REG 0x64 | ||
123 | #define LCD_END_OF_INT_IND_REG 0x68 | ||
124 | |||
125 | /* Clock registers available only on Version 2 */ | ||
126 | #define LCD_CLK_ENABLE_REG 0x6c | ||
127 | #define LCD_CLK_RESET_REG 0x70 | ||
128 | #define LCD_CLK_MAIN_RESET BIT(3) | ||
129 | |||
130 | #define LCD_NUM_BUFFERS 2 | ||
131 | |||
132 | #define PALETTE_SIZE 256 | ||
133 | |||
134 | #define CLK_MIN_DIV 2 | ||
135 | #define CLK_MAX_DIV 255 | ||
136 | |||
137 | static void __iomem *da8xx_fb_reg_base; | ||
138 | static unsigned int lcd_revision; | ||
139 | static irq_handler_t lcdc_irq_handler; | ||
140 | static wait_queue_head_t frame_done_wq; | ||
141 | static int frame_done_flag; | ||
142 | |||
143 | static unsigned int lcdc_read(unsigned int addr) | ||
144 | { | ||
145 | return (unsigned int)__raw_readl(da8xx_fb_reg_base + (addr)); | ||
146 | } | ||
147 | |||
148 | static void lcdc_write(unsigned int val, unsigned int addr) | ||
149 | { | ||
150 | __raw_writel(val, da8xx_fb_reg_base + (addr)); | ||
151 | } | ||
152 | |||
153 | struct da8xx_fb_par { | ||
154 | struct device *dev; | ||
155 | resource_size_t p_palette_base; | ||
156 | unsigned char *v_palette_base; | ||
157 | dma_addr_t vram_phys; | ||
158 | unsigned long vram_size; | ||
159 | void *vram_virt; | ||
160 | unsigned int dma_start; | ||
161 | unsigned int dma_end; | ||
162 | struct clk *lcdc_clk; | ||
163 | int irq; | ||
164 | unsigned int palette_sz; | ||
165 | int blank; | ||
166 | wait_queue_head_t vsync_wait; | ||
167 | int vsync_flag; | ||
168 | int vsync_timeout; | ||
169 | spinlock_t lock_for_chan_update; | ||
170 | |||
171 | /* | ||
172 | * LCDC has 2 ping pong DMA channels, channel 0 | ||
173 | * and channel 1. | ||
174 | */ | ||
175 | unsigned int which_dma_channel_done; | ||
176 | #ifdef CONFIG_CPU_FREQ | ||
177 | struct notifier_block freq_transition; | ||
178 | #endif | ||
179 | unsigned int lcdc_clk_rate; | ||
180 | void (*panel_power_ctrl)(int); | ||
181 | u32 pseudo_palette[16]; | ||
182 | struct fb_videomode mode; | ||
183 | struct lcd_ctrl_config cfg; | ||
184 | }; | ||
185 | |||
186 | static struct fb_var_screeninfo da8xx_fb_var; | ||
187 | |||
188 | static struct fb_fix_screeninfo da8xx_fb_fix = { | ||
189 | .id = "DA8xx FB Drv", | ||
190 | .type = FB_TYPE_PACKED_PIXELS, | ||
191 | .type_aux = 0, | ||
192 | .visual = FB_VISUAL_PSEUDOCOLOR, | ||
193 | .xpanstep = 0, | ||
194 | .ypanstep = 1, | ||
195 | .ywrapstep = 0, | ||
196 | .accel = FB_ACCEL_NONE | ||
197 | }; | ||
198 | |||
199 | static struct fb_videomode known_lcd_panels[] = { | ||
200 | /* Sharp LCD035Q3DG01 */ | ||
201 | [0] = { | ||
202 | .name = "Sharp_LCD035Q3DG01", | ||
203 | .xres = 320, | ||
204 | .yres = 240, | ||
205 | .pixclock = KHZ2PICOS(4607), | ||
206 | .left_margin = 6, | ||
207 | .right_margin = 8, | ||
208 | .upper_margin = 2, | ||
209 | .lower_margin = 2, | ||
210 | .hsync_len = 0, | ||
211 | .vsync_len = 0, | ||
212 | .sync = FB_SYNC_CLK_INVERT | | ||
213 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
214 | }, | ||
215 | /* Sharp LK043T1DG01 */ | ||
216 | [1] = { | ||
217 | .name = "Sharp_LK043T1DG01", | ||
218 | .xres = 480, | ||
219 | .yres = 272, | ||
220 | .pixclock = KHZ2PICOS(7833), | ||
221 | .left_margin = 2, | ||
222 | .right_margin = 2, | ||
223 | .upper_margin = 2, | ||
224 | .lower_margin = 2, | ||
225 | .hsync_len = 41, | ||
226 | .vsync_len = 10, | ||
227 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
228 | .flag = 0, | ||
229 | }, | ||
230 | [2] = { | ||
231 | /* Hitachi SP10Q010 */ | ||
232 | .name = "SP10Q010", | ||
233 | .xres = 320, | ||
234 | .yres = 240, | ||
235 | .pixclock = KHZ2PICOS(7833), | ||
236 | .left_margin = 10, | ||
237 | .right_margin = 10, | ||
238 | .upper_margin = 10, | ||
239 | .lower_margin = 10, | ||
240 | .hsync_len = 10, | ||
241 | .vsync_len = 10, | ||
242 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
243 | .flag = 0, | ||
244 | }, | ||
245 | }; | ||
246 | |||
247 | static bool da8xx_fb_is_raster_enabled(void) | ||
248 | { | ||
249 | return !!(lcdc_read(LCD_RASTER_CTRL_REG) & LCD_RASTER_ENABLE); | ||
250 | } | ||
251 | |||
252 | /* Enable the Raster Engine of the LCD Controller */ | ||
253 | static void lcd_enable_raster(void) | ||
254 | { | ||
255 | u32 reg; | ||
256 | |||
257 | /* Put LCDC in reset for several cycles */ | ||
258 | if (lcd_revision == LCD_VERSION_2) | ||
259 | /* Write 1 to reset LCDC */ | ||
260 | lcdc_write(LCD_CLK_MAIN_RESET, LCD_CLK_RESET_REG); | ||
261 | mdelay(1); | ||
262 | |||
263 | /* Bring LCDC out of reset */ | ||
264 | if (lcd_revision == LCD_VERSION_2) | ||
265 | lcdc_write(0, LCD_CLK_RESET_REG); | ||
266 | mdelay(1); | ||
267 | |||
268 | /* Above reset sequence doesnot reset register context */ | ||
269 | reg = lcdc_read(LCD_RASTER_CTRL_REG); | ||
270 | if (!(reg & LCD_RASTER_ENABLE)) | ||
271 | lcdc_write(reg | LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); | ||
272 | } | ||
273 | |||
274 | /* Disable the Raster Engine of the LCD Controller */ | ||
275 | static void lcd_disable_raster(enum da8xx_frame_complete wait_for_frame_done) | ||
276 | { | ||
277 | u32 reg; | ||
278 | int ret; | ||
279 | |||
280 | reg = lcdc_read(LCD_RASTER_CTRL_REG); | ||
281 | if (reg & LCD_RASTER_ENABLE) | ||
282 | lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); | ||
283 | else | ||
284 | /* return if already disabled */ | ||
285 | return; | ||
286 | |||
287 | if ((wait_for_frame_done == DA8XX_FRAME_WAIT) && | ||
288 | (lcd_revision == LCD_VERSION_2)) { | ||
289 | frame_done_flag = 0; | ||
290 | ret = wait_event_interruptible_timeout(frame_done_wq, | ||
291 | frame_done_flag != 0, | ||
292 | msecs_to_jiffies(50)); | ||
293 | if (ret == 0) | ||
294 | pr_err("LCD Controller timed out\n"); | ||
295 | } | ||
296 | } | ||
297 | |||
298 | static void lcd_blit(int load_mode, struct da8xx_fb_par *par) | ||
299 | { | ||
300 | u32 start; | ||
301 | u32 end; | ||
302 | u32 reg_ras; | ||
303 | u32 reg_dma; | ||
304 | u32 reg_int; | ||
305 | |||
306 | /* init reg to clear PLM (loading mode) fields */ | ||
307 | reg_ras = lcdc_read(LCD_RASTER_CTRL_REG); | ||
308 | reg_ras &= ~(3 << 20); | ||
309 | |||
310 | reg_dma = lcdc_read(LCD_DMA_CTRL_REG); | ||
311 | |||
312 | if (load_mode == LOAD_DATA) { | ||
313 | start = par->dma_start; | ||
314 | end = par->dma_end; | ||
315 | |||
316 | reg_ras |= LCD_PALETTE_LOAD_MODE(DATA_ONLY); | ||
317 | if (lcd_revision == LCD_VERSION_1) { | ||
318 | reg_dma |= LCD_V1_END_OF_FRAME_INT_ENA; | ||
319 | } else { | ||
320 | reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) | | ||
321 | LCD_V2_END_OF_FRAME0_INT_ENA | | ||
322 | LCD_V2_END_OF_FRAME1_INT_ENA | | ||
323 | LCD_FRAME_DONE | LCD_SYNC_LOST; | ||
324 | lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG); | ||
325 | } | ||
326 | reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE; | ||
327 | |||
328 | lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); | ||
329 | lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); | ||
330 | lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_1_REG); | ||
331 | lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG); | ||
332 | } else if (load_mode == LOAD_PALETTE) { | ||
333 | start = par->p_palette_base; | ||
334 | end = start + par->palette_sz - 1; | ||
335 | |||
336 | reg_ras |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY); | ||
337 | |||
338 | if (lcd_revision == LCD_VERSION_1) { | ||
339 | reg_ras |= LCD_V1_PL_INT_ENA; | ||
340 | } else { | ||
341 | reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) | | ||
342 | LCD_V2_PL_INT_ENA; | ||
343 | lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG); | ||
344 | } | ||
345 | |||
346 | lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); | ||
347 | lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); | ||
348 | } | ||
349 | |||
350 | lcdc_write(reg_dma, LCD_DMA_CTRL_REG); | ||
351 | lcdc_write(reg_ras, LCD_RASTER_CTRL_REG); | ||
352 | |||
353 | /* | ||
354 | * The Raster enable bit must be set after all other control fields are | ||
355 | * set. | ||
356 | */ | ||
357 | lcd_enable_raster(); | ||
358 | } | ||
359 | |||
360 | /* Configure the Burst Size and fifo threhold of DMA */ | ||
361 | static int lcd_cfg_dma(int burst_size, int fifo_th) | ||
362 | { | ||
363 | u32 reg; | ||
364 | |||
365 | reg = lcdc_read(LCD_DMA_CTRL_REG) & 0x00000001; | ||
366 | switch (burst_size) { | ||
367 | case 1: | ||
368 | reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_1); | ||
369 | break; | ||
370 | case 2: | ||
371 | reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_2); | ||
372 | break; | ||
373 | case 4: | ||
374 | reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_4); | ||
375 | break; | ||
376 | case 8: | ||
377 | reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_8); | ||
378 | break; | ||
379 | case 16: | ||
380 | default: | ||
381 | reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_16); | ||
382 | break; | ||
383 | } | ||
384 | |||
385 | reg |= (fifo_th << 8); | ||
386 | |||
387 | lcdc_write(reg, LCD_DMA_CTRL_REG); | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | static void lcd_cfg_ac_bias(int period, int transitions_per_int) | ||
393 | { | ||
394 | u32 reg; | ||
395 | |||
396 | /* Set the AC Bias Period and Number of Transisitons per Interrupt */ | ||
397 | reg = lcdc_read(LCD_RASTER_TIMING_2_REG) & 0xFFF00000; | ||
398 | reg |= LCD_AC_BIAS_FREQUENCY(period) | | ||
399 | LCD_AC_BIAS_TRANSITIONS_PER_INT(transitions_per_int); | ||
400 | lcdc_write(reg, LCD_RASTER_TIMING_2_REG); | ||
401 | } | ||
402 | |||
403 | static void lcd_cfg_horizontal_sync(int back_porch, int pulse_width, | ||
404 | int front_porch) | ||
405 | { | ||
406 | u32 reg; | ||
407 | |||
408 | reg = lcdc_read(LCD_RASTER_TIMING_0_REG) & 0xf; | ||
409 | reg |= (((back_porch-1) & 0xff) << 24) | ||
410 | | (((front_porch-1) & 0xff) << 16) | ||
411 | | (((pulse_width-1) & 0x3f) << 10); | ||
412 | lcdc_write(reg, LCD_RASTER_TIMING_0_REG); | ||
413 | |||
414 | /* | ||
415 | * LCDC Version 2 adds some extra bits that increase the allowable | ||
416 | * size of the horizontal timing registers. | ||
417 | * remember that the registers use 0 to represent 1 so all values | ||
418 | * that get set into register need to be decremented by 1 | ||
419 | */ | ||
420 | if (lcd_revision == LCD_VERSION_2) { | ||
421 | /* Mask off the bits we want to change */ | ||
422 | reg = lcdc_read(LCD_RASTER_TIMING_2_REG) & ~0x780000ff; | ||
423 | reg |= ((front_porch-1) & 0x300) >> 8; | ||
424 | reg |= ((back_porch-1) & 0x300) >> 4; | ||
425 | reg |= ((pulse_width-1) & 0x3c0) << 21; | ||
426 | lcdc_write(reg, LCD_RASTER_TIMING_2_REG); | ||
427 | } | ||
428 | } | ||
429 | |||
430 | static void lcd_cfg_vertical_sync(int back_porch, int pulse_width, | ||
431 | int front_porch) | ||
432 | { | ||
433 | u32 reg; | ||
434 | |||
435 | reg = lcdc_read(LCD_RASTER_TIMING_1_REG) & 0x3ff; | ||
436 | reg |= ((back_porch & 0xff) << 24) | ||
437 | | ((front_porch & 0xff) << 16) | ||
438 | | (((pulse_width-1) & 0x3f) << 10); | ||
439 | lcdc_write(reg, LCD_RASTER_TIMING_1_REG); | ||
440 | } | ||
441 | |||
442 | static int lcd_cfg_display(const struct lcd_ctrl_config *cfg, | ||
443 | struct fb_videomode *panel) | ||
444 | { | ||
445 | u32 reg; | ||
446 | u32 reg_int; | ||
447 | |||
448 | reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(LCD_TFT_MODE | | ||
449 | LCD_MONO_8BIT_MODE | | ||
450 | LCD_MONOCHROME_MODE); | ||
451 | |||
452 | switch (cfg->panel_shade) { | ||
453 | case MONOCHROME: | ||
454 | reg |= LCD_MONOCHROME_MODE; | ||
455 | if (cfg->mono_8bit_mode) | ||
456 | reg |= LCD_MONO_8BIT_MODE; | ||
457 | break; | ||
458 | case COLOR_ACTIVE: | ||
459 | reg |= LCD_TFT_MODE; | ||
460 | if (cfg->tft_alt_mode) | ||
461 | reg |= LCD_TFT_ALT_ENABLE; | ||
462 | break; | ||
463 | |||
464 | case COLOR_PASSIVE: | ||
465 | /* AC bias applicable only for Pasive panels */ | ||
466 | lcd_cfg_ac_bias(cfg->ac_bias, cfg->ac_bias_intrpt); | ||
467 | if (cfg->bpp == 12 && cfg->stn_565_mode) | ||
468 | reg |= LCD_STN_565_ENABLE; | ||
469 | break; | ||
470 | |||
471 | default: | ||
472 | return -EINVAL; | ||
473 | } | ||
474 | |||
475 | /* enable additional interrupts here */ | ||
476 | if (lcd_revision == LCD_VERSION_1) { | ||
477 | reg |= LCD_V1_UNDERFLOW_INT_ENA; | ||
478 | } else { | ||
479 | reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) | | ||
480 | LCD_V2_UNDERFLOW_INT_ENA; | ||
481 | lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG); | ||
482 | } | ||
483 | |||
484 | lcdc_write(reg, LCD_RASTER_CTRL_REG); | ||
485 | |||
486 | reg = lcdc_read(LCD_RASTER_TIMING_2_REG); | ||
487 | |||
488 | reg |= LCD_SYNC_CTRL; | ||
489 | |||
490 | if (cfg->sync_edge) | ||
491 | reg |= LCD_SYNC_EDGE; | ||
492 | else | ||
493 | reg &= ~LCD_SYNC_EDGE; | ||
494 | |||
495 | if ((panel->sync & FB_SYNC_HOR_HIGH_ACT) == 0) | ||
496 | reg |= LCD_INVERT_LINE_CLOCK; | ||
497 | else | ||
498 | reg &= ~LCD_INVERT_LINE_CLOCK; | ||
499 | |||
500 | if ((panel->sync & FB_SYNC_VERT_HIGH_ACT) == 0) | ||
501 | reg |= LCD_INVERT_FRAME_CLOCK; | ||
502 | else | ||
503 | reg &= ~LCD_INVERT_FRAME_CLOCK; | ||
504 | |||
505 | lcdc_write(reg, LCD_RASTER_TIMING_2_REG); | ||
506 | |||
507 | return 0; | ||
508 | } | ||
509 | |||
510 | static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height, | ||
511 | u32 bpp, u32 raster_order) | ||
512 | { | ||
513 | u32 reg; | ||
514 | |||
515 | if (bpp > 16 && lcd_revision == LCD_VERSION_1) | ||
516 | return -EINVAL; | ||
517 | |||
518 | /* Set the Panel Width */ | ||
519 | /* Pixels per line = (PPL + 1)*16 */ | ||
520 | if (lcd_revision == LCD_VERSION_1) { | ||
521 | /* | ||
522 | * 0x3F in bits 4..9 gives max horizontal resolution = 1024 | ||
523 | * pixels. | ||
524 | */ | ||
525 | width &= 0x3f0; | ||
526 | } else { | ||
527 | /* | ||
528 | * 0x7F in bits 4..10 gives max horizontal resolution = 2048 | ||
529 | * pixels. | ||
530 | */ | ||
531 | width &= 0x7f0; | ||
532 | } | ||
533 | |||
534 | reg = lcdc_read(LCD_RASTER_TIMING_0_REG); | ||
535 | reg &= 0xfffffc00; | ||
536 | if (lcd_revision == LCD_VERSION_1) { | ||
537 | reg |= ((width >> 4) - 1) << 4; | ||
538 | } else { | ||
539 | width = (width >> 4) - 1; | ||
540 | reg |= ((width & 0x3f) << 4) | ((width & 0x40) >> 3); | ||
541 | } | ||
542 | lcdc_write(reg, LCD_RASTER_TIMING_0_REG); | ||
543 | |||
544 | /* Set the Panel Height */ | ||
545 | /* Set bits 9:0 of Lines Per Pixel */ | ||
546 | reg = lcdc_read(LCD_RASTER_TIMING_1_REG); | ||
547 | reg = ((height - 1) & 0x3ff) | (reg & 0xfffffc00); | ||
548 | lcdc_write(reg, LCD_RASTER_TIMING_1_REG); | ||
549 | |||
550 | /* Set bit 10 of Lines Per Pixel */ | ||
551 | if (lcd_revision == LCD_VERSION_2) { | ||
552 | reg = lcdc_read(LCD_RASTER_TIMING_2_REG); | ||
553 | reg |= ((height - 1) & 0x400) << 16; | ||
554 | lcdc_write(reg, LCD_RASTER_TIMING_2_REG); | ||
555 | } | ||
556 | |||
557 | /* Set the Raster Order of the Frame Buffer */ | ||
558 | reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(1 << 8); | ||
559 | if (raster_order) | ||
560 | reg |= LCD_RASTER_ORDER; | ||
561 | |||
562 | par->palette_sz = 16 * 2; | ||
563 | |||
564 | switch (bpp) { | ||
565 | case 1: | ||
566 | case 2: | ||
567 | case 4: | ||
568 | case 16: | ||
569 | break; | ||
570 | case 24: | ||
571 | reg |= LCD_V2_TFT_24BPP_MODE; | ||
572 | break; | ||
573 | case 32: | ||
574 | reg |= LCD_V2_TFT_24BPP_MODE; | ||
575 | reg |= LCD_V2_TFT_24BPP_UNPACK; | ||
576 | break; | ||
577 | case 8: | ||
578 | par->palette_sz = 256 * 2; | ||
579 | break; | ||
580 | |||
581 | default: | ||
582 | return -EINVAL; | ||
583 | } | ||
584 | |||
585 | lcdc_write(reg, LCD_RASTER_CTRL_REG); | ||
586 | |||
587 | return 0; | ||
588 | } | ||
589 | |||
590 | #define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16) | ||
591 | static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, | ||
592 | unsigned blue, unsigned transp, | ||
593 | struct fb_info *info) | ||
594 | { | ||
595 | struct da8xx_fb_par *par = info->par; | ||
596 | unsigned short *palette = (unsigned short *) par->v_palette_base; | ||
597 | u_short pal; | ||
598 | int update_hw = 0; | ||
599 | |||
600 | if (regno > 255) | ||
601 | return 1; | ||
602 | |||
603 | if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) | ||
604 | return 1; | ||
605 | |||
606 | if (info->var.bits_per_pixel > 16 && lcd_revision == LCD_VERSION_1) | ||
607 | return -EINVAL; | ||
608 | |||
609 | switch (info->fix.visual) { | ||
610 | case FB_VISUAL_TRUECOLOR: | ||
611 | red = CNVT_TOHW(red, info->var.red.length); | ||
612 | green = CNVT_TOHW(green, info->var.green.length); | ||
613 | blue = CNVT_TOHW(blue, info->var.blue.length); | ||
614 | break; | ||
615 | case FB_VISUAL_PSEUDOCOLOR: | ||
616 | switch (info->var.bits_per_pixel) { | ||
617 | case 4: | ||
618 | if (regno > 15) | ||
619 | return -EINVAL; | ||
620 | |||
621 | if (info->var.grayscale) { | ||
622 | pal = regno; | ||
623 | } else { | ||
624 | red >>= 4; | ||
625 | green >>= 8; | ||
626 | blue >>= 12; | ||
627 | |||
628 | pal = red & 0x0f00; | ||
629 | pal |= green & 0x00f0; | ||
630 | pal |= blue & 0x000f; | ||
631 | } | ||
632 | if (regno == 0) | ||
633 | pal |= 0x2000; | ||
634 | palette[regno] = pal; | ||
635 | break; | ||
636 | |||
637 | case 8: | ||
638 | red >>= 4; | ||
639 | green >>= 8; | ||
640 | blue >>= 12; | ||
641 | |||
642 | pal = (red & 0x0f00); | ||
643 | pal |= (green & 0x00f0); | ||
644 | pal |= (blue & 0x000f); | ||
645 | |||
646 | if (palette[regno] != pal) { | ||
647 | update_hw = 1; | ||
648 | palette[regno] = pal; | ||
649 | } | ||
650 | break; | ||
651 | } | ||
652 | break; | ||
653 | } | ||
654 | |||
655 | /* Truecolor has hardware independent palette */ | ||
656 | if (info->fix.visual == FB_VISUAL_TRUECOLOR) { | ||
657 | u32 v; | ||
658 | |||
659 | if (regno > 15) | ||
660 | return -EINVAL; | ||
661 | |||
662 | v = (red << info->var.red.offset) | | ||
663 | (green << info->var.green.offset) | | ||
664 | (blue << info->var.blue.offset); | ||
665 | |||
666 | ((u32 *) (info->pseudo_palette))[regno] = v; | ||
667 | if (palette[0] != 0x4000) { | ||
668 | update_hw = 1; | ||
669 | palette[0] = 0x4000; | ||
670 | } | ||
671 | } | ||
672 | |||
673 | /* Update the palette in the h/w as needed. */ | ||
674 | if (update_hw) | ||
675 | lcd_blit(LOAD_PALETTE, par); | ||
676 | |||
677 | return 0; | ||
678 | } | ||
679 | #undef CNVT_TOHW | ||
680 | |||
681 | static void da8xx_fb_lcd_reset(void) | ||
682 | { | ||
683 | /* DMA has to be disabled */ | ||
684 | lcdc_write(0, LCD_DMA_CTRL_REG); | ||
685 | lcdc_write(0, LCD_RASTER_CTRL_REG); | ||
686 | |||
687 | if (lcd_revision == LCD_VERSION_2) { | ||
688 | lcdc_write(0, LCD_INT_ENABLE_SET_REG); | ||
689 | /* Write 1 to reset */ | ||
690 | lcdc_write(LCD_CLK_MAIN_RESET, LCD_CLK_RESET_REG); | ||
691 | lcdc_write(0, LCD_CLK_RESET_REG); | ||
692 | } | ||
693 | } | ||
694 | |||
695 | static int da8xx_fb_config_clk_divider(struct da8xx_fb_par *par, | ||
696 | unsigned lcdc_clk_div, | ||
697 | unsigned lcdc_clk_rate) | ||
698 | { | ||
699 | int ret; | ||
700 | |||
701 | if (par->lcdc_clk_rate != lcdc_clk_rate) { | ||
702 | ret = clk_set_rate(par->lcdc_clk, lcdc_clk_rate); | ||
703 | if (IS_ERR_VALUE(ret)) { | ||
704 | dev_err(par->dev, | ||
705 | "unable to set clock rate at %u\n", | ||
706 | lcdc_clk_rate); | ||
707 | return ret; | ||
708 | } | ||
709 | par->lcdc_clk_rate = clk_get_rate(par->lcdc_clk); | ||
710 | } | ||
711 | |||
712 | /* Configure the LCD clock divisor. */ | ||
713 | lcdc_write(LCD_CLK_DIVISOR(lcdc_clk_div) | | ||
714 | (LCD_RASTER_MODE & 0x1), LCD_CTRL_REG); | ||
715 | |||
716 | if (lcd_revision == LCD_VERSION_2) | ||
717 | lcdc_write(LCD_V2_DMA_CLK_EN | LCD_V2_LIDD_CLK_EN | | ||
718 | LCD_V2_CORE_CLK_EN, LCD_CLK_ENABLE_REG); | ||
719 | |||
720 | return 0; | ||
721 | } | ||
722 | |||
723 | static unsigned int da8xx_fb_calc_clk_divider(struct da8xx_fb_par *par, | ||
724 | unsigned pixclock, | ||
725 | unsigned *lcdc_clk_rate) | ||
726 | { | ||
727 | unsigned lcdc_clk_div; | ||
728 | |||
729 | pixclock = PICOS2KHZ(pixclock) * 1000; | ||
730 | |||
731 | *lcdc_clk_rate = par->lcdc_clk_rate; | ||
732 | |||
733 | if (pixclock < (*lcdc_clk_rate / CLK_MAX_DIV)) { | ||
734 | *lcdc_clk_rate = clk_round_rate(par->lcdc_clk, | ||
735 | pixclock * CLK_MAX_DIV); | ||
736 | lcdc_clk_div = CLK_MAX_DIV; | ||
737 | } else if (pixclock > (*lcdc_clk_rate / CLK_MIN_DIV)) { | ||
738 | *lcdc_clk_rate = clk_round_rate(par->lcdc_clk, | ||
739 | pixclock * CLK_MIN_DIV); | ||
740 | lcdc_clk_div = CLK_MIN_DIV; | ||
741 | } else { | ||
742 | lcdc_clk_div = *lcdc_clk_rate / pixclock; | ||
743 | } | ||
744 | |||
745 | return lcdc_clk_div; | ||
746 | } | ||
747 | |||
748 | static int da8xx_fb_calc_config_clk_divider(struct da8xx_fb_par *par, | ||
749 | struct fb_videomode *mode) | ||
750 | { | ||
751 | unsigned lcdc_clk_rate; | ||
752 | unsigned lcdc_clk_div = da8xx_fb_calc_clk_divider(par, mode->pixclock, | ||
753 | &lcdc_clk_rate); | ||
754 | |||
755 | return da8xx_fb_config_clk_divider(par, lcdc_clk_div, lcdc_clk_rate); | ||
756 | } | ||
757 | |||
758 | static unsigned da8xx_fb_round_clk(struct da8xx_fb_par *par, | ||
759 | unsigned pixclock) | ||
760 | { | ||
761 | unsigned lcdc_clk_div, lcdc_clk_rate; | ||
762 | |||
763 | lcdc_clk_div = da8xx_fb_calc_clk_divider(par, pixclock, &lcdc_clk_rate); | ||
764 | return KHZ2PICOS(lcdc_clk_rate / (1000 * lcdc_clk_div)); | ||
765 | } | ||
766 | |||
767 | static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, | ||
768 | struct fb_videomode *panel) | ||
769 | { | ||
770 | u32 bpp; | ||
771 | int ret = 0; | ||
772 | |||
773 | ret = da8xx_fb_calc_config_clk_divider(par, panel); | ||
774 | if (IS_ERR_VALUE(ret)) { | ||
775 | dev_err(par->dev, "unable to configure clock\n"); | ||
776 | return ret; | ||
777 | } | ||
778 | |||
779 | if (panel->sync & FB_SYNC_CLK_INVERT) | ||
780 | lcdc_write((lcdc_read(LCD_RASTER_TIMING_2_REG) | | ||
781 | LCD_INVERT_PIXEL_CLOCK), LCD_RASTER_TIMING_2_REG); | ||
782 | else | ||
783 | lcdc_write((lcdc_read(LCD_RASTER_TIMING_2_REG) & | ||
784 | ~LCD_INVERT_PIXEL_CLOCK), LCD_RASTER_TIMING_2_REG); | ||
785 | |||
786 | /* Configure the DMA burst size and fifo threshold. */ | ||
787 | ret = lcd_cfg_dma(cfg->dma_burst_sz, cfg->fifo_th); | ||
788 | if (ret < 0) | ||
789 | return ret; | ||
790 | |||
791 | /* Configure the vertical and horizontal sync properties. */ | ||
792 | lcd_cfg_vertical_sync(panel->upper_margin, panel->vsync_len, | ||
793 | panel->lower_margin); | ||
794 | lcd_cfg_horizontal_sync(panel->left_margin, panel->hsync_len, | ||
795 | panel->right_margin); | ||
796 | |||
797 | /* Configure for disply */ | ||
798 | ret = lcd_cfg_display(cfg, panel); | ||
799 | if (ret < 0) | ||
800 | return ret; | ||
801 | |||
802 | bpp = cfg->bpp; | ||
803 | |||
804 | if (bpp == 12) | ||
805 | bpp = 16; | ||
806 | ret = lcd_cfg_frame_buffer(par, (unsigned int)panel->xres, | ||
807 | (unsigned int)panel->yres, bpp, | ||
808 | cfg->raster_order); | ||
809 | if (ret < 0) | ||
810 | return ret; | ||
811 | |||
812 | /* Configure FDD */ | ||
813 | lcdc_write((lcdc_read(LCD_RASTER_CTRL_REG) & 0xfff00fff) | | ||
814 | (cfg->fdd << 12), LCD_RASTER_CTRL_REG); | ||
815 | |||
816 | return 0; | ||
817 | } | ||
818 | |||
819 | /* IRQ handler for version 2 of LCDC */ | ||
820 | static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg) | ||
821 | { | ||
822 | struct da8xx_fb_par *par = arg; | ||
823 | u32 stat = lcdc_read(LCD_MASKED_STAT_REG); | ||
824 | |||
825 | if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { | ||
826 | lcd_disable_raster(DA8XX_FRAME_NOWAIT); | ||
827 | lcdc_write(stat, LCD_MASKED_STAT_REG); | ||
828 | lcd_enable_raster(); | ||
829 | } else if (stat & LCD_PL_LOAD_DONE) { | ||
830 | /* | ||
831 | * Must disable raster before changing state of any control bit. | ||
832 | * And also must be disabled before clearing the PL loading | ||
833 | * interrupt via the following write to the status register. If | ||
834 | * this is done after then one gets multiple PL done interrupts. | ||
835 | */ | ||
836 | lcd_disable_raster(DA8XX_FRAME_NOWAIT); | ||
837 | |||
838 | lcdc_write(stat, LCD_MASKED_STAT_REG); | ||
839 | |||
840 | /* Disable PL completion interrupt */ | ||
841 | lcdc_write(LCD_V2_PL_INT_ENA, LCD_INT_ENABLE_CLR_REG); | ||
842 | |||
843 | /* Setup and start data loading mode */ | ||
844 | lcd_blit(LOAD_DATA, par); | ||
845 | } else { | ||
846 | lcdc_write(stat, LCD_MASKED_STAT_REG); | ||
847 | |||
848 | if (stat & LCD_END_OF_FRAME0) { | ||
849 | par->which_dma_channel_done = 0; | ||
850 | lcdc_write(par->dma_start, | ||
851 | LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); | ||
852 | lcdc_write(par->dma_end, | ||
853 | LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); | ||
854 | par->vsync_flag = 1; | ||
855 | wake_up_interruptible(&par->vsync_wait); | ||
856 | } | ||
857 | |||
858 | if (stat & LCD_END_OF_FRAME1) { | ||
859 | par->which_dma_channel_done = 1; | ||
860 | lcdc_write(par->dma_start, | ||
861 | LCD_DMA_FRM_BUF_BASE_ADDR_1_REG); | ||
862 | lcdc_write(par->dma_end, | ||
863 | LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG); | ||
864 | par->vsync_flag = 1; | ||
865 | wake_up_interruptible(&par->vsync_wait); | ||
866 | } | ||
867 | |||
868 | /* Set only when controller is disabled and at the end of | ||
869 | * active frame | ||
870 | */ | ||
871 | if (stat & BIT(0)) { | ||
872 | frame_done_flag = 1; | ||
873 | wake_up_interruptible(&frame_done_wq); | ||
874 | } | ||
875 | } | ||
876 | |||
877 | lcdc_write(0, LCD_END_OF_INT_IND_REG); | ||
878 | return IRQ_HANDLED; | ||
879 | } | ||
880 | |||
881 | /* IRQ handler for version 1 LCDC */ | ||
882 | static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg) | ||
883 | { | ||
884 | struct da8xx_fb_par *par = arg; | ||
885 | u32 stat = lcdc_read(LCD_STAT_REG); | ||
886 | u32 reg_ras; | ||
887 | |||
888 | if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { | ||
889 | lcd_disable_raster(DA8XX_FRAME_NOWAIT); | ||
890 | lcdc_write(stat, LCD_STAT_REG); | ||
891 | lcd_enable_raster(); | ||
892 | } else if (stat & LCD_PL_LOAD_DONE) { | ||
893 | /* | ||
894 | * Must disable raster before changing state of any control bit. | ||
895 | * And also must be disabled before clearing the PL loading | ||
896 | * interrupt via the following write to the status register. If | ||
897 | * this is done after then one gets multiple PL done interrupts. | ||
898 | */ | ||
899 | lcd_disable_raster(DA8XX_FRAME_NOWAIT); | ||
900 | |||
901 | lcdc_write(stat, LCD_STAT_REG); | ||
902 | |||
903 | /* Disable PL completion inerrupt */ | ||
904 | reg_ras = lcdc_read(LCD_RASTER_CTRL_REG); | ||
905 | reg_ras &= ~LCD_V1_PL_INT_ENA; | ||
906 | lcdc_write(reg_ras, LCD_RASTER_CTRL_REG); | ||
907 | |||
908 | /* Setup and start data loading mode */ | ||
909 | lcd_blit(LOAD_DATA, par); | ||
910 | } else { | ||
911 | lcdc_write(stat, LCD_STAT_REG); | ||
912 | |||
913 | if (stat & LCD_END_OF_FRAME0) { | ||
914 | par->which_dma_channel_done = 0; | ||
915 | lcdc_write(par->dma_start, | ||
916 | LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); | ||
917 | lcdc_write(par->dma_end, | ||
918 | LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); | ||
919 | par->vsync_flag = 1; | ||
920 | wake_up_interruptible(&par->vsync_wait); | ||
921 | } | ||
922 | |||
923 | if (stat & LCD_END_OF_FRAME1) { | ||
924 | par->which_dma_channel_done = 1; | ||
925 | lcdc_write(par->dma_start, | ||
926 | LCD_DMA_FRM_BUF_BASE_ADDR_1_REG); | ||
927 | lcdc_write(par->dma_end, | ||
928 | LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG); | ||
929 | par->vsync_flag = 1; | ||
930 | wake_up_interruptible(&par->vsync_wait); | ||
931 | } | ||
932 | } | ||
933 | |||
934 | return IRQ_HANDLED; | ||
935 | } | ||
936 | |||
937 | static int fb_check_var(struct fb_var_screeninfo *var, | ||
938 | struct fb_info *info) | ||
939 | { | ||
940 | int err = 0; | ||
941 | struct da8xx_fb_par *par = info->par; | ||
942 | int bpp = var->bits_per_pixel >> 3; | ||
943 | unsigned long line_size = var->xres_virtual * bpp; | ||
944 | |||
945 | if (var->bits_per_pixel > 16 && lcd_revision == LCD_VERSION_1) | ||
946 | return -EINVAL; | ||
947 | |||
948 | switch (var->bits_per_pixel) { | ||
949 | case 1: | ||
950 | case 8: | ||
951 | var->red.offset = 0; | ||
952 | var->red.length = 8; | ||
953 | var->green.offset = 0; | ||
954 | var->green.length = 8; | ||
955 | var->blue.offset = 0; | ||
956 | var->blue.length = 8; | ||
957 | var->transp.offset = 0; | ||
958 | var->transp.length = 0; | ||
959 | var->nonstd = 0; | ||
960 | break; | ||
961 | case 4: | ||
962 | var->red.offset = 0; | ||
963 | var->red.length = 4; | ||
964 | var->green.offset = 0; | ||
965 | var->green.length = 4; | ||
966 | var->blue.offset = 0; | ||
967 | var->blue.length = 4; | ||
968 | var->transp.offset = 0; | ||
969 | var->transp.length = 0; | ||
970 | var->nonstd = FB_NONSTD_REV_PIX_IN_B; | ||
971 | break; | ||
972 | case 16: /* RGB 565 */ | ||
973 | var->red.offset = 11; | ||
974 | var->red.length = 5; | ||
975 | var->green.offset = 5; | ||
976 | var->green.length = 6; | ||
977 | var->blue.offset = 0; | ||
978 | var->blue.length = 5; | ||
979 | var->transp.offset = 0; | ||
980 | var->transp.length = 0; | ||
981 | var->nonstd = 0; | ||
982 | break; | ||
983 | case 24: | ||
984 | var->red.offset = 16; | ||
985 | var->red.length = 8; | ||
986 | var->green.offset = 8; | ||
987 | var->green.length = 8; | ||
988 | var->blue.offset = 0; | ||
989 | var->blue.length = 8; | ||
990 | var->nonstd = 0; | ||
991 | break; | ||
992 | case 32: | ||
993 | var->transp.offset = 24; | ||
994 | var->transp.length = 8; | ||
995 | var->red.offset = 16; | ||
996 | var->red.length = 8; | ||
997 | var->green.offset = 8; | ||
998 | var->green.length = 8; | ||
999 | var->blue.offset = 0; | ||
1000 | var->blue.length = 8; | ||
1001 | var->nonstd = 0; | ||
1002 | break; | ||
1003 | default: | ||
1004 | err = -EINVAL; | ||
1005 | } | ||
1006 | |||
1007 | var->red.msb_right = 0; | ||
1008 | var->green.msb_right = 0; | ||
1009 | var->blue.msb_right = 0; | ||
1010 | var->transp.msb_right = 0; | ||
1011 | |||
1012 | if (line_size * var->yres_virtual > par->vram_size) | ||
1013 | var->yres_virtual = par->vram_size / line_size; | ||
1014 | |||
1015 | if (var->yres > var->yres_virtual) | ||
1016 | var->yres = var->yres_virtual; | ||
1017 | |||
1018 | if (var->xres > var->xres_virtual) | ||
1019 | var->xres = var->xres_virtual; | ||
1020 | |||
1021 | if (var->xres + var->xoffset > var->xres_virtual) | ||
1022 | var->xoffset = var->xres_virtual - var->xres; | ||
1023 | if (var->yres + var->yoffset > var->yres_virtual) | ||
1024 | var->yoffset = var->yres_virtual - var->yres; | ||
1025 | |||
1026 | var->pixclock = da8xx_fb_round_clk(par, var->pixclock); | ||
1027 | |||
1028 | return err; | ||
1029 | } | ||
1030 | |||
1031 | #ifdef CONFIG_CPU_FREQ | ||
1032 | static int lcd_da8xx_cpufreq_transition(struct notifier_block *nb, | ||
1033 | unsigned long val, void *data) | ||
1034 | { | ||
1035 | struct da8xx_fb_par *par; | ||
1036 | |||
1037 | par = container_of(nb, struct da8xx_fb_par, freq_transition); | ||
1038 | if (val == CPUFREQ_POSTCHANGE) { | ||
1039 | if (par->lcdc_clk_rate != clk_get_rate(par->lcdc_clk)) { | ||
1040 | par->lcdc_clk_rate = clk_get_rate(par->lcdc_clk); | ||
1041 | lcd_disable_raster(DA8XX_FRAME_WAIT); | ||
1042 | da8xx_fb_calc_config_clk_divider(par, &par->mode); | ||
1043 | if (par->blank == FB_BLANK_UNBLANK) | ||
1044 | lcd_enable_raster(); | ||
1045 | } | ||
1046 | } | ||
1047 | |||
1048 | return 0; | ||
1049 | } | ||
1050 | |||
1051 | static int lcd_da8xx_cpufreq_register(struct da8xx_fb_par *par) | ||
1052 | { | ||
1053 | par->freq_transition.notifier_call = lcd_da8xx_cpufreq_transition; | ||
1054 | |||
1055 | return cpufreq_register_notifier(&par->freq_transition, | ||
1056 | CPUFREQ_TRANSITION_NOTIFIER); | ||
1057 | } | ||
1058 | |||
1059 | static void lcd_da8xx_cpufreq_deregister(struct da8xx_fb_par *par) | ||
1060 | { | ||
1061 | cpufreq_unregister_notifier(&par->freq_transition, | ||
1062 | CPUFREQ_TRANSITION_NOTIFIER); | ||
1063 | } | ||
1064 | #endif | ||
1065 | |||
1066 | static int fb_remove(struct platform_device *dev) | ||
1067 | { | ||
1068 | struct fb_info *info = dev_get_drvdata(&dev->dev); | ||
1069 | |||
1070 | if (info) { | ||
1071 | struct da8xx_fb_par *par = info->par; | ||
1072 | |||
1073 | #ifdef CONFIG_CPU_FREQ | ||
1074 | lcd_da8xx_cpufreq_deregister(par); | ||
1075 | #endif | ||
1076 | if (par->panel_power_ctrl) | ||
1077 | par->panel_power_ctrl(0); | ||
1078 | |||
1079 | lcd_disable_raster(DA8XX_FRAME_WAIT); | ||
1080 | lcdc_write(0, LCD_RASTER_CTRL_REG); | ||
1081 | |||
1082 | /* disable DMA */ | ||
1083 | lcdc_write(0, LCD_DMA_CTRL_REG); | ||
1084 | |||
1085 | unregister_framebuffer(info); | ||
1086 | fb_dealloc_cmap(&info->cmap); | ||
1087 | dma_free_coherent(NULL, PALETTE_SIZE, par->v_palette_base, | ||
1088 | par->p_palette_base); | ||
1089 | dma_free_coherent(NULL, par->vram_size, par->vram_virt, | ||
1090 | par->vram_phys); | ||
1091 | pm_runtime_put_sync(&dev->dev); | ||
1092 | pm_runtime_disable(&dev->dev); | ||
1093 | framebuffer_release(info); | ||
1094 | |||
1095 | } | ||
1096 | return 0; | ||
1097 | } | ||
1098 | |||
1099 | /* | ||
1100 | * Function to wait for vertical sync which for this LCD peripheral | ||
1101 | * translates into waiting for the current raster frame to complete. | ||
1102 | */ | ||
1103 | static int fb_wait_for_vsync(struct fb_info *info) | ||
1104 | { | ||
1105 | struct da8xx_fb_par *par = info->par; | ||
1106 | int ret; | ||
1107 | |||
1108 | /* | ||
1109 | * Set flag to 0 and wait for isr to set to 1. It would seem there is a | ||
1110 | * race condition here where the ISR could have occurred just before or | ||
1111 | * just after this set. But since we are just coarsely waiting for | ||
1112 | * a frame to complete then that's OK. i.e. if the frame completed | ||
1113 | * just before this code executed then we have to wait another full | ||
1114 | * frame time but there is no way to avoid such a situation. On the | ||
1115 | * other hand if the frame completed just after then we don't need | ||
1116 | * to wait long at all. Either way we are guaranteed to return to the | ||
1117 | * user immediately after a frame completion which is all that is | ||
1118 | * required. | ||
1119 | */ | ||
1120 | par->vsync_flag = 0; | ||
1121 | ret = wait_event_interruptible_timeout(par->vsync_wait, | ||
1122 | par->vsync_flag != 0, | ||
1123 | par->vsync_timeout); | ||
1124 | if (ret < 0) | ||
1125 | return ret; | ||
1126 | if (ret == 0) | ||
1127 | return -ETIMEDOUT; | ||
1128 | |||
1129 | return 0; | ||
1130 | } | ||
1131 | |||
1132 | static int fb_ioctl(struct fb_info *info, unsigned int cmd, | ||
1133 | unsigned long arg) | ||
1134 | { | ||
1135 | struct lcd_sync_arg sync_arg; | ||
1136 | |||
1137 | switch (cmd) { | ||
1138 | case FBIOGET_CONTRAST: | ||
1139 | case FBIOPUT_CONTRAST: | ||
1140 | case FBIGET_BRIGHTNESS: | ||
1141 | case FBIPUT_BRIGHTNESS: | ||
1142 | case FBIGET_COLOR: | ||
1143 | case FBIPUT_COLOR: | ||
1144 | return -ENOTTY; | ||
1145 | case FBIPUT_HSYNC: | ||
1146 | if (copy_from_user(&sync_arg, (char *)arg, | ||
1147 | sizeof(struct lcd_sync_arg))) | ||
1148 | return -EFAULT; | ||
1149 | lcd_cfg_horizontal_sync(sync_arg.back_porch, | ||
1150 | sync_arg.pulse_width, | ||
1151 | sync_arg.front_porch); | ||
1152 | break; | ||
1153 | case FBIPUT_VSYNC: | ||
1154 | if (copy_from_user(&sync_arg, (char *)arg, | ||
1155 | sizeof(struct lcd_sync_arg))) | ||
1156 | return -EFAULT; | ||
1157 | lcd_cfg_vertical_sync(sync_arg.back_porch, | ||
1158 | sync_arg.pulse_width, | ||
1159 | sync_arg.front_porch); | ||
1160 | break; | ||
1161 | case FBIO_WAITFORVSYNC: | ||
1162 | return fb_wait_for_vsync(info); | ||
1163 | default: | ||
1164 | return -EINVAL; | ||
1165 | } | ||
1166 | return 0; | ||
1167 | } | ||
1168 | |||
1169 | static int cfb_blank(int blank, struct fb_info *info) | ||
1170 | { | ||
1171 | struct da8xx_fb_par *par = info->par; | ||
1172 | int ret = 0; | ||
1173 | |||
1174 | if (par->blank == blank) | ||
1175 | return 0; | ||
1176 | |||
1177 | par->blank = blank; | ||
1178 | switch (blank) { | ||
1179 | case FB_BLANK_UNBLANK: | ||
1180 | lcd_enable_raster(); | ||
1181 | |||
1182 | if (par->panel_power_ctrl) | ||
1183 | par->panel_power_ctrl(1); | ||
1184 | break; | ||
1185 | case FB_BLANK_NORMAL: | ||
1186 | case FB_BLANK_VSYNC_SUSPEND: | ||
1187 | case FB_BLANK_HSYNC_SUSPEND: | ||
1188 | case FB_BLANK_POWERDOWN: | ||
1189 | if (par->panel_power_ctrl) | ||
1190 | par->panel_power_ctrl(0); | ||
1191 | |||
1192 | lcd_disable_raster(DA8XX_FRAME_WAIT); | ||
1193 | break; | ||
1194 | default: | ||
1195 | ret = -EINVAL; | ||
1196 | } | ||
1197 | |||
1198 | return ret; | ||
1199 | } | ||
1200 | |||
1201 | /* | ||
1202 | * Set new x,y offsets in the virtual display for the visible area and switch | ||
1203 | * to the new mode. | ||
1204 | */ | ||
1205 | static int da8xx_pan_display(struct fb_var_screeninfo *var, | ||
1206 | struct fb_info *fbi) | ||
1207 | { | ||
1208 | int ret = 0; | ||
1209 | struct fb_var_screeninfo new_var; | ||
1210 | struct da8xx_fb_par *par = fbi->par; | ||
1211 | struct fb_fix_screeninfo *fix = &fbi->fix; | ||
1212 | unsigned int end; | ||
1213 | unsigned int start; | ||
1214 | unsigned long irq_flags; | ||
1215 | |||
1216 | if (var->xoffset != fbi->var.xoffset || | ||
1217 | var->yoffset != fbi->var.yoffset) { | ||
1218 | memcpy(&new_var, &fbi->var, sizeof(new_var)); | ||
1219 | new_var.xoffset = var->xoffset; | ||
1220 | new_var.yoffset = var->yoffset; | ||
1221 | if (fb_check_var(&new_var, fbi)) | ||
1222 | ret = -EINVAL; | ||
1223 | else { | ||
1224 | memcpy(&fbi->var, &new_var, sizeof(new_var)); | ||
1225 | |||
1226 | start = fix->smem_start + | ||
1227 | new_var.yoffset * fix->line_length + | ||
1228 | new_var.xoffset * fbi->var.bits_per_pixel / 8; | ||
1229 | end = start + fbi->var.yres * fix->line_length - 1; | ||
1230 | par->dma_start = start; | ||
1231 | par->dma_end = end; | ||
1232 | spin_lock_irqsave(&par->lock_for_chan_update, | ||
1233 | irq_flags); | ||
1234 | if (par->which_dma_channel_done == 0) { | ||
1235 | lcdc_write(par->dma_start, | ||
1236 | LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); | ||
1237 | lcdc_write(par->dma_end, | ||
1238 | LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); | ||
1239 | } else if (par->which_dma_channel_done == 1) { | ||
1240 | lcdc_write(par->dma_start, | ||
1241 | LCD_DMA_FRM_BUF_BASE_ADDR_1_REG); | ||
1242 | lcdc_write(par->dma_end, | ||
1243 | LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG); | ||
1244 | } | ||
1245 | spin_unlock_irqrestore(&par->lock_for_chan_update, | ||
1246 | irq_flags); | ||
1247 | } | ||
1248 | } | ||
1249 | |||
1250 | return ret; | ||
1251 | } | ||
1252 | |||
1253 | static int da8xxfb_set_par(struct fb_info *info) | ||
1254 | { | ||
1255 | struct da8xx_fb_par *par = info->par; | ||
1256 | int ret; | ||
1257 | bool raster = da8xx_fb_is_raster_enabled(); | ||
1258 | |||
1259 | if (raster) | ||
1260 | lcd_disable_raster(DA8XX_FRAME_WAIT); | ||
1261 | |||
1262 | fb_var_to_videomode(&par->mode, &info->var); | ||
1263 | |||
1264 | par->cfg.bpp = info->var.bits_per_pixel; | ||
1265 | |||
1266 | info->fix.visual = (par->cfg.bpp <= 8) ? | ||
1267 | FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; | ||
1268 | info->fix.line_length = (par->mode.xres * par->cfg.bpp) / 8; | ||
1269 | |||
1270 | ret = lcd_init(par, &par->cfg, &par->mode); | ||
1271 | if (ret < 0) { | ||
1272 | dev_err(par->dev, "lcd init failed\n"); | ||
1273 | return ret; | ||
1274 | } | ||
1275 | |||
1276 | par->dma_start = info->fix.smem_start + | ||
1277 | info->var.yoffset * info->fix.line_length + | ||
1278 | info->var.xoffset * info->var.bits_per_pixel / 8; | ||
1279 | par->dma_end = par->dma_start + | ||
1280 | info->var.yres * info->fix.line_length - 1; | ||
1281 | |||
1282 | lcdc_write(par->dma_start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); | ||
1283 | lcdc_write(par->dma_end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); | ||
1284 | lcdc_write(par->dma_start, LCD_DMA_FRM_BUF_BASE_ADDR_1_REG); | ||
1285 | lcdc_write(par->dma_end, LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG); | ||
1286 | |||
1287 | if (raster) | ||
1288 | lcd_enable_raster(); | ||
1289 | |||
1290 | return 0; | ||
1291 | } | ||
1292 | |||
1293 | static struct fb_ops da8xx_fb_ops = { | ||
1294 | .owner = THIS_MODULE, | ||
1295 | .fb_check_var = fb_check_var, | ||
1296 | .fb_set_par = da8xxfb_set_par, | ||
1297 | .fb_setcolreg = fb_setcolreg, | ||
1298 | .fb_pan_display = da8xx_pan_display, | ||
1299 | .fb_ioctl = fb_ioctl, | ||
1300 | .fb_fillrect = cfb_fillrect, | ||
1301 | .fb_copyarea = cfb_copyarea, | ||
1302 | .fb_imageblit = cfb_imageblit, | ||
1303 | .fb_blank = cfb_blank, | ||
1304 | }; | ||
1305 | |||
1306 | static struct fb_videomode *da8xx_fb_get_videomode(struct platform_device *dev) | ||
1307 | { | ||
1308 | struct da8xx_lcdc_platform_data *fb_pdata = dev_get_platdata(&dev->dev); | ||
1309 | struct fb_videomode *lcdc_info; | ||
1310 | int i; | ||
1311 | |||
1312 | for (i = 0, lcdc_info = known_lcd_panels; | ||
1313 | i < ARRAY_SIZE(known_lcd_panels); i++, lcdc_info++) { | ||
1314 | if (strcmp(fb_pdata->type, lcdc_info->name) == 0) | ||
1315 | break; | ||
1316 | } | ||
1317 | |||
1318 | if (i == ARRAY_SIZE(known_lcd_panels)) { | ||
1319 | dev_err(&dev->dev, "no panel found\n"); | ||
1320 | return NULL; | ||
1321 | } | ||
1322 | dev_info(&dev->dev, "found %s panel\n", lcdc_info->name); | ||
1323 | |||
1324 | return lcdc_info; | ||
1325 | } | ||
1326 | |||
1327 | static int fb_probe(struct platform_device *device) | ||
1328 | { | ||
1329 | struct da8xx_lcdc_platform_data *fb_pdata = | ||
1330 | dev_get_platdata(&device->dev); | ||
1331 | static struct resource *lcdc_regs; | ||
1332 | struct lcd_ctrl_config *lcd_cfg; | ||
1333 | struct fb_videomode *lcdc_info; | ||
1334 | struct fb_info *da8xx_fb_info; | ||
1335 | struct da8xx_fb_par *par; | ||
1336 | struct clk *tmp_lcdc_clk; | ||
1337 | int ret; | ||
1338 | unsigned long ulcm; | ||
1339 | |||
1340 | if (fb_pdata == NULL) { | ||
1341 | dev_err(&device->dev, "Can not get platform data\n"); | ||
1342 | return -ENOENT; | ||
1343 | } | ||
1344 | |||
1345 | lcdc_info = da8xx_fb_get_videomode(device); | ||
1346 | if (lcdc_info == NULL) | ||
1347 | return -ENODEV; | ||
1348 | |||
1349 | lcdc_regs = platform_get_resource(device, IORESOURCE_MEM, 0); | ||
1350 | da8xx_fb_reg_base = devm_ioremap_resource(&device->dev, lcdc_regs); | ||
1351 | if (IS_ERR(da8xx_fb_reg_base)) | ||
1352 | return PTR_ERR(da8xx_fb_reg_base); | ||
1353 | |||
1354 | tmp_lcdc_clk = devm_clk_get(&device->dev, "fck"); | ||
1355 | if (IS_ERR(tmp_lcdc_clk)) { | ||
1356 | dev_err(&device->dev, "Can not get device clock\n"); | ||
1357 | return PTR_ERR(tmp_lcdc_clk); | ||
1358 | } | ||
1359 | |||
1360 | pm_runtime_enable(&device->dev); | ||
1361 | pm_runtime_get_sync(&device->dev); | ||
1362 | |||
1363 | /* Determine LCD IP Version */ | ||
1364 | switch (lcdc_read(LCD_PID_REG)) { | ||
1365 | case 0x4C100102: | ||
1366 | lcd_revision = LCD_VERSION_1; | ||
1367 | break; | ||
1368 | case 0x4F200800: | ||
1369 | case 0x4F201000: | ||
1370 | lcd_revision = LCD_VERSION_2; | ||
1371 | break; | ||
1372 | default: | ||
1373 | dev_warn(&device->dev, "Unknown PID Reg value 0x%x, " | ||
1374 | "defaulting to LCD revision 1\n", | ||
1375 | lcdc_read(LCD_PID_REG)); | ||
1376 | lcd_revision = LCD_VERSION_1; | ||
1377 | break; | ||
1378 | } | ||
1379 | |||
1380 | lcd_cfg = (struct lcd_ctrl_config *)fb_pdata->controller_data; | ||
1381 | |||
1382 | if (!lcd_cfg) { | ||
1383 | ret = -EINVAL; | ||
1384 | goto err_pm_runtime_disable; | ||
1385 | } | ||
1386 | |||
1387 | da8xx_fb_info = framebuffer_alloc(sizeof(struct da8xx_fb_par), | ||
1388 | &device->dev); | ||
1389 | if (!da8xx_fb_info) { | ||
1390 | dev_dbg(&device->dev, "Memory allocation failed for fb_info\n"); | ||
1391 | ret = -ENOMEM; | ||
1392 | goto err_pm_runtime_disable; | ||
1393 | } | ||
1394 | |||
1395 | par = da8xx_fb_info->par; | ||
1396 | par->dev = &device->dev; | ||
1397 | par->lcdc_clk = tmp_lcdc_clk; | ||
1398 | par->lcdc_clk_rate = clk_get_rate(par->lcdc_clk); | ||
1399 | if (fb_pdata->panel_power_ctrl) { | ||
1400 | par->panel_power_ctrl = fb_pdata->panel_power_ctrl; | ||
1401 | par->panel_power_ctrl(1); | ||
1402 | } | ||
1403 | |||
1404 | fb_videomode_to_var(&da8xx_fb_var, lcdc_info); | ||
1405 | par->cfg = *lcd_cfg; | ||
1406 | |||
1407 | da8xx_fb_lcd_reset(); | ||
1408 | |||
1409 | /* allocate frame buffer */ | ||
1410 | par->vram_size = lcdc_info->xres * lcdc_info->yres * lcd_cfg->bpp; | ||
1411 | ulcm = lcm((lcdc_info->xres * lcd_cfg->bpp)/8, PAGE_SIZE); | ||
1412 | par->vram_size = roundup(par->vram_size/8, ulcm); | ||
1413 | par->vram_size = par->vram_size * LCD_NUM_BUFFERS; | ||
1414 | |||
1415 | par->vram_virt = dma_alloc_coherent(NULL, | ||
1416 | par->vram_size, | ||
1417 | (resource_size_t *) &par->vram_phys, | ||
1418 | GFP_KERNEL | GFP_DMA); | ||
1419 | if (!par->vram_virt) { | ||
1420 | dev_err(&device->dev, | ||
1421 | "GLCD: kmalloc for frame buffer failed\n"); | ||
1422 | ret = -EINVAL; | ||
1423 | goto err_release_fb; | ||
1424 | } | ||
1425 | |||
1426 | da8xx_fb_info->screen_base = (char __iomem *) par->vram_virt; | ||
1427 | da8xx_fb_fix.smem_start = par->vram_phys; | ||
1428 | da8xx_fb_fix.smem_len = par->vram_size; | ||
1429 | da8xx_fb_fix.line_length = (lcdc_info->xres * lcd_cfg->bpp) / 8; | ||
1430 | |||
1431 | par->dma_start = par->vram_phys; | ||
1432 | par->dma_end = par->dma_start + lcdc_info->yres * | ||
1433 | da8xx_fb_fix.line_length - 1; | ||
1434 | |||
1435 | /* allocate palette buffer */ | ||
1436 | par->v_palette_base = dma_alloc_coherent(NULL, | ||
1437 | PALETTE_SIZE, | ||
1438 | (resource_size_t *) | ||
1439 | &par->p_palette_base, | ||
1440 | GFP_KERNEL | GFP_DMA); | ||
1441 | if (!par->v_palette_base) { | ||
1442 | dev_err(&device->dev, | ||
1443 | "GLCD: kmalloc for palette buffer failed\n"); | ||
1444 | ret = -EINVAL; | ||
1445 | goto err_release_fb_mem; | ||
1446 | } | ||
1447 | memset(par->v_palette_base, 0, PALETTE_SIZE); | ||
1448 | |||
1449 | par->irq = platform_get_irq(device, 0); | ||
1450 | if (par->irq < 0) { | ||
1451 | ret = -ENOENT; | ||
1452 | goto err_release_pl_mem; | ||
1453 | } | ||
1454 | |||
1455 | da8xx_fb_var.grayscale = | ||
1456 | lcd_cfg->panel_shade == MONOCHROME ? 1 : 0; | ||
1457 | da8xx_fb_var.bits_per_pixel = lcd_cfg->bpp; | ||
1458 | |||
1459 | /* Initialize fbinfo */ | ||
1460 | da8xx_fb_info->flags = FBINFO_FLAG_DEFAULT; | ||
1461 | da8xx_fb_info->fix = da8xx_fb_fix; | ||
1462 | da8xx_fb_info->var = da8xx_fb_var; | ||
1463 | da8xx_fb_info->fbops = &da8xx_fb_ops; | ||
1464 | da8xx_fb_info->pseudo_palette = par->pseudo_palette; | ||
1465 | da8xx_fb_info->fix.visual = (da8xx_fb_info->var.bits_per_pixel <= 8) ? | ||
1466 | FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; | ||
1467 | |||
1468 | ret = fb_alloc_cmap(&da8xx_fb_info->cmap, PALETTE_SIZE, 0); | ||
1469 | if (ret) | ||
1470 | goto err_release_pl_mem; | ||
1471 | da8xx_fb_info->cmap.len = par->palette_sz; | ||
1472 | |||
1473 | /* initialize var_screeninfo */ | ||
1474 | da8xx_fb_var.activate = FB_ACTIVATE_FORCE; | ||
1475 | fb_set_var(da8xx_fb_info, &da8xx_fb_var); | ||
1476 | |||
1477 | dev_set_drvdata(&device->dev, da8xx_fb_info); | ||
1478 | |||
1479 | /* initialize the vsync wait queue */ | ||
1480 | init_waitqueue_head(&par->vsync_wait); | ||
1481 | par->vsync_timeout = HZ / 5; | ||
1482 | par->which_dma_channel_done = -1; | ||
1483 | spin_lock_init(&par->lock_for_chan_update); | ||
1484 | |||
1485 | /* Register the Frame Buffer */ | ||
1486 | if (register_framebuffer(da8xx_fb_info) < 0) { | ||
1487 | dev_err(&device->dev, | ||
1488 | "GLCD: Frame Buffer Registration Failed!\n"); | ||
1489 | ret = -EINVAL; | ||
1490 | goto err_dealloc_cmap; | ||
1491 | } | ||
1492 | |||
1493 | #ifdef CONFIG_CPU_FREQ | ||
1494 | ret = lcd_da8xx_cpufreq_register(par); | ||
1495 | if (ret) { | ||
1496 | dev_err(&device->dev, "failed to register cpufreq\n"); | ||
1497 | goto err_cpu_freq; | ||
1498 | } | ||
1499 | #endif | ||
1500 | |||
1501 | if (lcd_revision == LCD_VERSION_1) | ||
1502 | lcdc_irq_handler = lcdc_irq_handler_rev01; | ||
1503 | else { | ||
1504 | init_waitqueue_head(&frame_done_wq); | ||
1505 | lcdc_irq_handler = lcdc_irq_handler_rev02; | ||
1506 | } | ||
1507 | |||
1508 | ret = devm_request_irq(&device->dev, par->irq, lcdc_irq_handler, 0, | ||
1509 | DRIVER_NAME, par); | ||
1510 | if (ret) | ||
1511 | goto irq_freq; | ||
1512 | return 0; | ||
1513 | |||
1514 | irq_freq: | ||
1515 | #ifdef CONFIG_CPU_FREQ | ||
1516 | lcd_da8xx_cpufreq_deregister(par); | ||
1517 | err_cpu_freq: | ||
1518 | #endif | ||
1519 | unregister_framebuffer(da8xx_fb_info); | ||
1520 | |||
1521 | err_dealloc_cmap: | ||
1522 | fb_dealloc_cmap(&da8xx_fb_info->cmap); | ||
1523 | |||
1524 | err_release_pl_mem: | ||
1525 | dma_free_coherent(NULL, PALETTE_SIZE, par->v_palette_base, | ||
1526 | par->p_palette_base); | ||
1527 | |||
1528 | err_release_fb_mem: | ||
1529 | dma_free_coherent(NULL, par->vram_size, par->vram_virt, par->vram_phys); | ||
1530 | |||
1531 | err_release_fb: | ||
1532 | framebuffer_release(da8xx_fb_info); | ||
1533 | |||
1534 | err_pm_runtime_disable: | ||
1535 | pm_runtime_put_sync(&device->dev); | ||
1536 | pm_runtime_disable(&device->dev); | ||
1537 | |||
1538 | return ret; | ||
1539 | } | ||
1540 | |||
1541 | #ifdef CONFIG_PM_SLEEP | ||
1542 | static struct lcdc_context { | ||
1543 | u32 clk_enable; | ||
1544 | u32 ctrl; | ||
1545 | u32 dma_ctrl; | ||
1546 | u32 raster_timing_0; | ||
1547 | u32 raster_timing_1; | ||
1548 | u32 raster_timing_2; | ||
1549 | u32 int_enable_set; | ||
1550 | u32 dma_frm_buf_base_addr_0; | ||
1551 | u32 dma_frm_buf_ceiling_addr_0; | ||
1552 | u32 dma_frm_buf_base_addr_1; | ||
1553 | u32 dma_frm_buf_ceiling_addr_1; | ||
1554 | u32 raster_ctrl; | ||
1555 | } reg_context; | ||
1556 | |||
1557 | static void lcd_context_save(void) | ||
1558 | { | ||
1559 | if (lcd_revision == LCD_VERSION_2) { | ||
1560 | reg_context.clk_enable = lcdc_read(LCD_CLK_ENABLE_REG); | ||
1561 | reg_context.int_enable_set = lcdc_read(LCD_INT_ENABLE_SET_REG); | ||
1562 | } | ||
1563 | |||
1564 | reg_context.ctrl = lcdc_read(LCD_CTRL_REG); | ||
1565 | reg_context.dma_ctrl = lcdc_read(LCD_DMA_CTRL_REG); | ||
1566 | reg_context.raster_timing_0 = lcdc_read(LCD_RASTER_TIMING_0_REG); | ||
1567 | reg_context.raster_timing_1 = lcdc_read(LCD_RASTER_TIMING_1_REG); | ||
1568 | reg_context.raster_timing_2 = lcdc_read(LCD_RASTER_TIMING_2_REG); | ||
1569 | reg_context.dma_frm_buf_base_addr_0 = | ||
1570 | lcdc_read(LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); | ||
1571 | reg_context.dma_frm_buf_ceiling_addr_0 = | ||
1572 | lcdc_read(LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); | ||
1573 | reg_context.dma_frm_buf_base_addr_1 = | ||
1574 | lcdc_read(LCD_DMA_FRM_BUF_BASE_ADDR_1_REG); | ||
1575 | reg_context.dma_frm_buf_ceiling_addr_1 = | ||
1576 | lcdc_read(LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG); | ||
1577 | reg_context.raster_ctrl = lcdc_read(LCD_RASTER_CTRL_REG); | ||
1578 | return; | ||
1579 | } | ||
1580 | |||
1581 | static void lcd_context_restore(void) | ||
1582 | { | ||
1583 | if (lcd_revision == LCD_VERSION_2) { | ||
1584 | lcdc_write(reg_context.clk_enable, LCD_CLK_ENABLE_REG); | ||
1585 | lcdc_write(reg_context.int_enable_set, LCD_INT_ENABLE_SET_REG); | ||
1586 | } | ||
1587 | |||
1588 | lcdc_write(reg_context.ctrl, LCD_CTRL_REG); | ||
1589 | lcdc_write(reg_context.dma_ctrl, LCD_DMA_CTRL_REG); | ||
1590 | lcdc_write(reg_context.raster_timing_0, LCD_RASTER_TIMING_0_REG); | ||
1591 | lcdc_write(reg_context.raster_timing_1, LCD_RASTER_TIMING_1_REG); | ||
1592 | lcdc_write(reg_context.raster_timing_2, LCD_RASTER_TIMING_2_REG); | ||
1593 | lcdc_write(reg_context.dma_frm_buf_base_addr_0, | ||
1594 | LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); | ||
1595 | lcdc_write(reg_context.dma_frm_buf_ceiling_addr_0, | ||
1596 | LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); | ||
1597 | lcdc_write(reg_context.dma_frm_buf_base_addr_1, | ||
1598 | LCD_DMA_FRM_BUF_BASE_ADDR_1_REG); | ||
1599 | lcdc_write(reg_context.dma_frm_buf_ceiling_addr_1, | ||
1600 | LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG); | ||
1601 | lcdc_write(reg_context.raster_ctrl, LCD_RASTER_CTRL_REG); | ||
1602 | return; | ||
1603 | } | ||
1604 | |||
1605 | static int fb_suspend(struct device *dev) | ||
1606 | { | ||
1607 | struct fb_info *info = dev_get_drvdata(dev); | ||
1608 | struct da8xx_fb_par *par = info->par; | ||
1609 | |||
1610 | console_lock(); | ||
1611 | if (par->panel_power_ctrl) | ||
1612 | par->panel_power_ctrl(0); | ||
1613 | |||
1614 | fb_set_suspend(info, 1); | ||
1615 | lcd_disable_raster(DA8XX_FRAME_WAIT); | ||
1616 | lcd_context_save(); | ||
1617 | pm_runtime_put_sync(dev); | ||
1618 | console_unlock(); | ||
1619 | |||
1620 | return 0; | ||
1621 | } | ||
1622 | static int fb_resume(struct device *dev) | ||
1623 | { | ||
1624 | struct fb_info *info = dev_get_drvdata(dev); | ||
1625 | struct da8xx_fb_par *par = info->par; | ||
1626 | |||
1627 | console_lock(); | ||
1628 | pm_runtime_get_sync(dev); | ||
1629 | lcd_context_restore(); | ||
1630 | if (par->blank == FB_BLANK_UNBLANK) { | ||
1631 | lcd_enable_raster(); | ||
1632 | |||
1633 | if (par->panel_power_ctrl) | ||
1634 | par->panel_power_ctrl(1); | ||
1635 | } | ||
1636 | |||
1637 | fb_set_suspend(info, 0); | ||
1638 | console_unlock(); | ||
1639 | |||
1640 | return 0; | ||
1641 | } | ||
1642 | #endif | ||
1643 | |||
1644 | static SIMPLE_DEV_PM_OPS(fb_pm_ops, fb_suspend, fb_resume); | ||
1645 | |||
1646 | static struct platform_driver da8xx_fb_driver = { | ||
1647 | .probe = fb_probe, | ||
1648 | .remove = fb_remove, | ||
1649 | .driver = { | ||
1650 | .name = DRIVER_NAME, | ||
1651 | .owner = THIS_MODULE, | ||
1652 | .pm = &fb_pm_ops, | ||
1653 | }, | ||
1654 | }; | ||
1655 | module_platform_driver(da8xx_fb_driver); | ||
1656 | |||
1657 | MODULE_DESCRIPTION("Framebuffer driver for TI da8xx/omap-l1xx"); | ||
1658 | MODULE_AUTHOR("Texas Instruments"); | ||
1659 | MODULE_LICENSE("GPL"); | ||